Skip to content

Commit 1223c6c

Browse files
authored
Merge branch 'main' into lunny/remove_unnecessary_repo_branch
2 parents 032b43d + 55a69ae commit 1223c6c

20 files changed

+149
-39
lines changed

cmd/admin_user_create.go

Lines changed: 37 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"context"
88
"errors"
99
"fmt"
10+
"strings"
1011

1112
auth_model "code.gitea.io/gitea/models/auth"
1213
"code.gitea.io/gitea/models/db"
@@ -66,6 +67,16 @@ var microcmdUserCreate = &cli.Command{
6667
Name: "access-token",
6768
Usage: "Generate access token for the user",
6869
},
70+
&cli.StringFlag{
71+
Name: "access-token-name",
72+
Usage: `Name of the generated access token`,
73+
Value: "gitea-admin",
74+
},
75+
&cli.StringFlag{
76+
Name: "access-token-scopes",
77+
Usage: `Scopes of the generated access token, comma separated. Examples: "all", "public-only,read:issue", "write:repository,write:user"`,
78+
Value: "all",
79+
},
6980
&cli.BoolFlag{
7081
Name: "restricted",
7182
Usage: "Make a restricted user account",
@@ -187,23 +198,40 @@ func runCreateUser(c *cli.Context) error {
187198
IsRestricted: restricted,
188199
}
189200

201+
var accessTokenName string
202+
var accessTokenScope auth_model.AccessTokenScope
203+
if c.IsSet("access-token") {
204+
accessTokenName = strings.TrimSpace(c.String("access-token-name"))
205+
if accessTokenName == "" {
206+
return errors.New("access-token-name cannot be empty")
207+
}
208+
var err error
209+
accessTokenScope, err = auth_model.AccessTokenScope(c.String("access-token-scopes")).Normalize()
210+
if err != nil {
211+
return fmt.Errorf("invalid access token scope provided: %w", err)
212+
}
213+
if !accessTokenScope.HasPermissionScope() {
214+
return errors.New("access token does not have any permission")
215+
}
216+
} else if c.IsSet("access-token-name") || c.IsSet("access-token-scopes") {
217+
return errors.New("access-token-name and access-token-scopes flags are only valid when access-token flag is set")
218+
}
219+
220+
// arguments should be prepared before creating the user & access token, in case there is anything wrong
221+
222+
// create the user
190223
if err := user_model.CreateUser(ctx, u, &user_model.Meta{}, overwriteDefault); err != nil {
191224
return fmt.Errorf("CreateUser: %w", err)
192225
}
226+
fmt.Printf("New user '%s' has been successfully created!\n", username)
193227

194-
if c.Bool("access-token") {
195-
t := &auth_model.AccessToken{
196-
Name: "gitea-admin",
197-
UID: u.ID,
198-
}
199-
228+
// create the access token
229+
if accessTokenScope != "" {
230+
t := &auth_model.AccessToken{Name: accessTokenName, UID: u.ID, Scope: accessTokenScope}
200231
if err := auth_model.NewAccessToken(ctx, t); err != nil {
201232
return err
202233
}
203-
204234
fmt.Printf("Access token was successfully created... %s\n", t.Token)
205235
}
206-
207-
fmt.Printf("New user '%s' has been successfully created!\n", username)
208236
return nil
209237
}

cmd/admin_user_create_test.go

Lines changed: 58 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"strings"
99
"testing"
1010

11+
auth_model "code.gitea.io/gitea/models/auth"
1112
"code.gitea.io/gitea/models/db"
1213
"code.gitea.io/gitea/models/unittest"
1314
user_model "code.gitea.io/gitea/models/user"
@@ -22,6 +23,7 @@ func TestAdminUserCreate(t *testing.T) {
2223
reset := func() {
2324
require.NoError(t, db.TruncateBeans(db.DefaultContext, &user_model.User{}))
2425
require.NoError(t, db.TruncateBeans(db.DefaultContext, &user_model.EmailAddress{}))
26+
require.NoError(t, db.TruncateBeans(db.DefaultContext, &auth_model.AccessToken{}))
2527
}
2628

2729
t.Run("MustChangePassword", func(t *testing.T) {
@@ -48,11 +50,11 @@ func TestAdminUserCreate(t *testing.T) {
4850
assert.Equal(t, check{IsAdmin: false, MustChangePassword: false}, createCheck("u5", "--must-change-password=false"))
4951
})
5052

51-
t.Run("UserType", func(t *testing.T) {
52-
createUser := func(name, args string) error {
53-
return app.Run(strings.Fields(fmt.Sprintf("./gitea admin user create --username %s --email %[email protected] %s", name, name, args)))
54-
}
53+
createUser := func(name, args string) error {
54+
return app.Run(strings.Fields(fmt.Sprintf("./gitea admin user create --username %s --email %[email protected] %s", name, name, args)))
55+
}
5556

57+
t.Run("UserType", func(t *testing.T) {
5658
reset()
5759
assert.ErrorContains(t, createUser("u", "--user-type invalid"), "invalid user type")
5860
assert.ErrorContains(t, createUser("u", "--user-type bot --password 123"), "can only be set for individual users")
@@ -63,4 +65,56 @@ func TestAdminUserCreate(t *testing.T) {
6365
assert.Equal(t, user_model.UserTypeBot, u.Type)
6466
assert.Empty(t, u.Passwd)
6567
})
68+
69+
t.Run("AccessToken", func(t *testing.T) {
70+
// no generated access token
71+
reset()
72+
assert.NoError(t, createUser("u", "--random-password"))
73+
assert.Equal(t, 1, unittest.GetCount(t, &user_model.User{}))
74+
assert.Equal(t, 0, unittest.GetCount(t, &auth_model.AccessToken{}))
75+
76+
// using "--access-token" only means "all" access
77+
reset()
78+
assert.NoError(t, createUser("u", "--random-password --access-token"))
79+
assert.Equal(t, 1, unittest.GetCount(t, &user_model.User{}))
80+
assert.Equal(t, 1, unittest.GetCount(t, &auth_model.AccessToken{}))
81+
accessToken := unittest.AssertExistsAndLoadBean(t, &auth_model.AccessToken{Name: "gitea-admin"})
82+
hasScopes, err := accessToken.Scope.HasScope(auth_model.AccessTokenScopeWriteAdmin, auth_model.AccessTokenScopeWriteRepository)
83+
assert.NoError(t, err)
84+
assert.True(t, hasScopes)
85+
86+
// using "--access-token" with name & scopes
87+
reset()
88+
assert.NoError(t, createUser("u", "--random-password --access-token --access-token-name new-token-name --access-token-scopes read:issue,read:user"))
89+
assert.Equal(t, 1, unittest.GetCount(t, &user_model.User{}))
90+
assert.Equal(t, 1, unittest.GetCount(t, &auth_model.AccessToken{}))
91+
accessToken = unittest.AssertExistsAndLoadBean(t, &auth_model.AccessToken{Name: "new-token-name"})
92+
hasScopes, err = accessToken.Scope.HasScope(auth_model.AccessTokenScopeReadIssue, auth_model.AccessTokenScopeReadUser)
93+
assert.NoError(t, err)
94+
assert.True(t, hasScopes)
95+
hasScopes, err = accessToken.Scope.HasScope(auth_model.AccessTokenScopeWriteAdmin, auth_model.AccessTokenScopeWriteRepository)
96+
assert.NoError(t, err)
97+
assert.False(t, hasScopes)
98+
99+
// using "--access-token-name" without "--access-token"
100+
reset()
101+
err = createUser("u", "--random-password --access-token-name new-token-name")
102+
assert.Equal(t, 0, unittest.GetCount(t, &user_model.User{}))
103+
assert.Equal(t, 0, unittest.GetCount(t, &auth_model.AccessToken{}))
104+
assert.ErrorContains(t, err, "access-token-name and access-token-scopes flags are only valid when access-token flag is set")
105+
106+
// using "--access-token-scopes" without "--access-token"
107+
reset()
108+
err = createUser("u", "--random-password --access-token-scopes read:issue")
109+
assert.Equal(t, 0, unittest.GetCount(t, &user_model.User{}))
110+
assert.Equal(t, 0, unittest.GetCount(t, &auth_model.AccessToken{}))
111+
assert.ErrorContains(t, err, "access-token-name and access-token-scopes flags are only valid when access-token flag is set")
112+
113+
// empty permission
114+
reset()
115+
err = createUser("u", "--random-password --access-token --access-token-scopes public-only")
116+
assert.Equal(t, 0, unittest.GetCount(t, &user_model.User{}))
117+
assert.Equal(t, 0, unittest.GetCount(t, &auth_model.AccessToken{}))
118+
assert.ErrorContains(t, err, "access token does not have any permission")
119+
})
66120
}

cmd/admin_user_generate_access_token.go

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,16 +34,16 @@ var microcmdUserGenerateAccessToken = &cli.Command{
3434
},
3535
&cli.StringFlag{
3636
Name: "scopes",
37-
Value: "",
38-
Usage: "Comma separated list of scopes to apply to access token",
37+
Value: "all",
38+
Usage: `Comma separated list of scopes to apply to access token, examples: "all", "public-only,read:issue", "write:repository,write:user"`,
3939
},
4040
},
4141
Action: runGenerateAccessToken,
4242
}
4343

4444
func runGenerateAccessToken(c *cli.Context) error {
4545
if !c.IsSet("username") {
46-
return errors.New("You must provide a username to generate a token for")
46+
return errors.New("you must provide a username to generate a token for")
4747
}
4848

4949
ctx, cancel := installSignals()
@@ -77,6 +77,9 @@ func runGenerateAccessToken(c *cli.Context) error {
7777
if err != nil {
7878
return fmt.Errorf("invalid access token scope provided: %w", err)
7979
}
80+
if !accessTokenScope.HasPermissionScope() {
81+
return errors.New("access token does not have any permission")
82+
}
8083
t.Scope = accessTokenScope
8184

8285
// create the token

models/auth/access_token_scope.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,10 @@ func (s AccessTokenScope) Normalize() (AccessTokenScope, error) {
295295
return bitmap.toScope(), nil
296296
}
297297

298+
func (s AccessTokenScope) HasPermissionScope() bool {
299+
return s != "" && s != AccessTokenScopePublicOnly
300+
}
301+
298302
// PublicOnly checks if this token scope is limited to public resources
299303
func (s AccessTokenScope) PublicOnly() (bool, error) {
300304
bitmap, err := s.parse()

models/user/avatar.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,9 @@ func GenerateRandomAvatar(ctx context.Context, u *User) error {
6161

6262
// AvatarLinkWithSize returns a link to the user's avatar with size. size <= 0 means default size
6363
func (u *User) AvatarLinkWithSize(ctx context.Context, size int) string {
64-
if u.IsGhost() || u.IsGiteaActions() {
64+
// ghost user was deleted, Gitea actions is a bot user, 0 means the user should be a virtual user
65+
// which comes from git configure information
66+
if u.IsGhost() || u.IsGiteaActions() || u.ID <= 0 {
6567
return avatars.DefaultAvatarLink()
6668
}
6769

options/locale/locale_cs-CZ.ini

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -718,8 +718,6 @@ public_profile=Veřejný profil
718718
biography_placeholder=Řekněte nám něco o sobě! (Můžete použít Markdown)
719719
location_placeholder=Sdílejte svou přibližnou polohu s ostatními
720720
profile_desc=Nastavte, jak bude váš profil zobrazen ostatním uživatelům. Vaše hlavní e-mailová adresa bude použita pro oznámení, obnovení hesla a operace Git.
721-
password_username_disabled=Nemáte oprávnění měnit jejich uživatelské jméno. Pro více informací kontaktujte svého administrátora.
722-
password_full_name_disabled=Nemáte oprávnění měnit jejich celé jméno. Pro více informací kontaktujte správce webu.
723721
full_name=Celé jméno
724722
website=Web
725723
location=Místo

options/locale/locale_de-DE.ini

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -724,8 +724,6 @@ public_profile=Öffentliches Profil
724724
biography_placeholder=Erzähle uns ein wenig über Dich selbst! (Du kannst Markdown verwenden)
725725
location_placeholder=Teile Deinen ungefähren Standort mit anderen
726726
profile_desc=Lege fest, wie dein Profil anderen Benutzern angezeigt wird. Deine primäre E-Mail-Adresse wird für Benachrichtigungen, Passwort-Wiederherstellung und webbasierte Git-Operationen verwendet.
727-
password_username_disabled=Du bist nicht berechtigt, den Benutzernamen zu ändern. Bitte kontaktiere Deinen Seitenadministrator für weitere Details.
728-
password_full_name_disabled=Du bist nicht berechtigt, den vollständigen Namen zu ändern. Bitte kontaktiere Deinen Seitenadministrator für weitere Details.
729727
full_name=Vollständiger Name
730728
website=Webseite
731729
location=Standort

options/locale/locale_en-US.ini

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2733,6 +2733,7 @@ branch.restore_success = Branch "%s" has been restored.
27332733
branch.restore_failed = Failed to restore branch "%s".
27342734
branch.protected_deletion_failed = Branch "%s" is protected. It cannot be deleted.
27352735
branch.default_deletion_failed = Branch "%s" is the default branch. It cannot be deleted.
2736+
branch.default_branch_not_exist = Default branch "%s" does not exist.
27362737
branch.restore = Restore Branch "%s"
27372738
branch.download = Download Branch "%s"
27382739
branch.rename = Rename Branch "%s"

options/locale/locale_fr-FR.ini

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -730,8 +730,6 @@ public_profile=Profil public
730730
biography_placeholder=Parlez-nous un peu de vous ! (Vous pouvez utiliser Markdown)
731731
location_placeholder=Partagez votre position approximative avec d'autres personnes
732732
profile_desc=Contrôlez comment votre profil est affiché aux autres utilisateurs. Votre adresse courriel principale sera utilisée pour les notifications, la récupération de mot de passe et les opérations Git basées sur le Web.
733-
password_username_disabled=Vous n’êtes pas autorisé à modifier leur nom d’utilisateur. Veuillez contacter l’administrateur de votre site pour plus de détails.
734-
password_full_name_disabled=Vous n’êtes pas autorisé à modifier leur nom complet. Veuillez contacter l’administrateur du site pour plus de détails.
735733
full_name=Nom complet
736734
website=Site Web
737735
location=Localisation
@@ -1546,6 +1544,8 @@ issues.filter_project=Projet
15461544
issues.filter_project_all=Tous les projets
15471545
issues.filter_project_none=Aucun projet
15481546
issues.filter_assignee=Assigné
1547+
issues.filter_assignee_no_assignee=Non-assigné
1548+
issues.filter_assignee_any_assignee=Assigné
15491549
issues.filter_poster=Auteur
15501550
issues.filter_user_placeholder=Rechercher des utilisateurs
15511551
issues.filter_user_no_select=Tous les utilisateurs

options/locale/locale_ga-IE.ini

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -730,8 +730,6 @@ public_profile=Próifíl Phoiblí
730730
biography_placeholder=Inis dúinn beagán fút féin! (Is féidir leat Markdown a úsáid)
731731
location_placeholder=Comhroinn do shuíomh thart le daoine eile
732732
profile_desc=Rialú conas a thaispeánfar do phróifíl d'úsáideoirí eile. Úsáidfear do phríomhsheoladh ríomhphoist le haghaidh fógraí, aisghabháil pasfhocail agus oibríochtaí Git gréasán-bhunaithe.
733-
password_username_disabled=Níl cead agat a n-ainm úsáideora a athrú. Déan teagmháil le do riarthóir suímh le haghaidh tuilleadh sonraí.
734-
password_full_name_disabled=Níl cead agat a n-ainm iomlán a athrú. Déan teagmháil le do riarthóir suímh le haghaidh tuilleadh sonraí.
735733
full_name=Ainm Iomlán
736734
website=Láithreán Gréasáin
737735
location=Suíomh

0 commit comments

Comments
 (0)