Skip to content

Commit dfdc3ea

Browse files
authored
Merge branch 'main' into optimize-filetree-icons-match
2 parents 9ce6848 + a4df01b commit dfdc3ea

File tree

30 files changed

+353
-173
lines changed

30 files changed

+353
-173
lines changed

cmd/admin_auth_ldap.go

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,34 @@ var (
127127
&cli.UintFlag{
128128
Name: "page-size",
129129
Usage: "Search page size.",
130+
},
131+
&cli.BoolFlag{
132+
Name: "enable-groups",
133+
Usage: "Enable LDAP groups",
134+
},
135+
&cli.StringFlag{
136+
Name: "group-search-base-dn",
137+
Usage: "The LDAP base DN at which group accounts will be searched for",
138+
},
139+
&cli.StringFlag{
140+
Name: "group-member-attribute",
141+
Usage: "Group attribute containing list of users",
142+
},
143+
&cli.StringFlag{
144+
Name: "group-user-attribute",
145+
Usage: "User attribute listed in group",
146+
},
147+
&cli.StringFlag{
148+
Name: "group-filter",
149+
Usage: "Verify group membership in LDAP",
150+
},
151+
&cli.StringFlag{
152+
Name: "group-team-map",
153+
Usage: "Map LDAP groups to Organization teams",
154+
},
155+
&cli.BoolFlag{
156+
Name: "group-team-map-removal",
157+
Usage: "Remove users from synchronized teams if user does not belong to corresponding LDAP group",
130158
})
131159

132160
ldapSimpleAuthCLIFlags = append(commonLdapCLIFlags,
@@ -273,6 +301,27 @@ func parseLdapConfig(c *cli.Context, config *ldap.Source) error {
273301
if c.IsSet("skip-local-2fa") {
274302
config.SkipLocalTwoFA = c.Bool("skip-local-2fa")
275303
}
304+
if c.IsSet("enable-groups") {
305+
config.GroupsEnabled = c.Bool("enable-groups")
306+
}
307+
if c.IsSet("group-search-base-dn") {
308+
config.GroupDN = c.String("group-search-base-dn")
309+
}
310+
if c.IsSet("group-member-attribute") {
311+
config.GroupMemberUID = c.String("group-member-attribute")
312+
}
313+
if c.IsSet("group-user-attribute") {
314+
config.UserUID = c.String("group-user-attribute")
315+
}
316+
if c.IsSet("group-filter") {
317+
config.GroupFilter = c.String("group-filter")
318+
}
319+
if c.IsSet("group-team-map") {
320+
config.GroupTeamMap = c.String("group-team-map")
321+
}
322+
if c.IsSet("group-team-map-removal") {
323+
config.GroupTeamMapRemoval = c.Bool("group-team-map-removal")
324+
}
276325
return nil
277326
}
278327

cmd/admin_auth_ldap_test.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,13 @@ func TestAddLdapBindDn(t *testing.T) {
5151
"--attributes-in-bind",
5252
"--synchronize-users",
5353
"--page-size", "99",
54+
"--enable-groups",
55+
"--group-search-base-dn", "ou=group,dc=full-domain-bind,dc=org",
56+
"--group-member-attribute", "memberUid",
57+
"--group-user-attribute", "uid",
58+
"--group-filter", "(|(cn=gitea_users)(cn=admins))",
59+
"--group-team-map", `{"cn=my-group,cn=groups,dc=example,dc=org": {"MyGiteaOrganization": ["MyGiteaTeam1", "MyGiteaTeam2"]}}`,
60+
"--group-team-map-removal",
5461
},
5562
source: &auth.Source{
5663
Type: auth.LDAP,
@@ -78,6 +85,13 @@ func TestAddLdapBindDn(t *testing.T) {
7885
AdminFilter: "(memberOf=cn=admin-group,ou=example,dc=full-domain-bind,dc=org)",
7986
RestrictedFilter: "(memberOf=cn=restricted-group,ou=example,dc=full-domain-bind,dc=org)",
8087
Enabled: true,
88+
GroupsEnabled: true,
89+
GroupDN: "ou=group,dc=full-domain-bind,dc=org",
90+
GroupMemberUID: "memberUid",
91+
UserUID: "uid",
92+
GroupFilter: "(|(cn=gitea_users)(cn=admins))",
93+
GroupTeamMap: `{"cn=my-group,cn=groups,dc=example,dc=org": {"MyGiteaOrganization": ["MyGiteaTeam1", "MyGiteaTeam2"]}}`,
94+
GroupTeamMapRemoval: true,
8195
},
8296
},
8397
},
@@ -510,6 +524,13 @@ func TestUpdateLdapBindDn(t *testing.T) {
510524
"--bind-password", "secret-bind-full",
511525
"--synchronize-users",
512526
"--page-size", "99",
527+
"--enable-groups",
528+
"--group-search-base-dn", "ou=group,dc=full-domain-bind,dc=org",
529+
"--group-member-attribute", "memberUid",
530+
"--group-user-attribute", "uid",
531+
"--group-filter", "(|(cn=gitea_users)(cn=admins))",
532+
"--group-team-map", `{"cn=my-group,cn=groups,dc=example,dc=org": {"MyGiteaOrganization": ["MyGiteaTeam1", "MyGiteaTeam2"]}}`,
533+
"--group-team-map-removal",
513534
},
514535
id: 23,
515536
existingAuthSource: &auth.Source{
@@ -545,6 +566,13 @@ func TestUpdateLdapBindDn(t *testing.T) {
545566
AdminFilter: "(memberOf=cn=admin-group,ou=example,dc=full-domain-bind,dc=org)",
546567
RestrictedFilter: "(memberOf=cn=restricted-group,ou=example,dc=full-domain-bind,dc=org)",
547568
Enabled: true,
569+
GroupsEnabled: true,
570+
GroupDN: "ou=group,dc=full-domain-bind,dc=org",
571+
GroupMemberUID: "memberUid",
572+
UserUID: "uid",
573+
GroupFilter: "(|(cn=gitea_users)(cn=admins))",
574+
GroupTeamMap: `{"cn=my-group,cn=groups,dc=example,dc=org": {"MyGiteaOrganization": ["MyGiteaTeam1", "MyGiteaTeam2"]}}`,
575+
GroupTeamMapRemoval: true,
548576
},
549577
},
550578
},

models/activities/action.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,10 @@ func (a *Action) TableIndices() []*schemas.Index {
172172
cuIndex := schemas.NewIndex("c_u", schemas.IndexType)
173173
cuIndex.AddColumn("user_id", "is_deleted")
174174

175-
indices := []*schemas.Index{actUserIndex, repoIndex, cudIndex, cuIndex}
175+
actUserUserIndex := schemas.NewIndex("au_c_u", schemas.IndexType)
176+
actUserUserIndex.AddColumn("act_user_id", "created_unix", "user_id")
177+
178+
indices := []*schemas.Index{actUserIndex, repoIndex, cudIndex, cuIndex, actUserUserIndex}
176179

177180
return indices
178181
}
@@ -442,6 +445,7 @@ type GetFeedsOptions struct {
442445
OnlyPerformedBy bool // only actions performed by requested user
443446
IncludeDeleted bool // include deleted actions
444447
Date string // the day we want activity for: YYYY-MM-DD
448+
DontCount bool // do counting in GetFeeds
445449
}
446450

447451
// ActivityReadable return whether doer can read activities of user

models/activities/action_list.go

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,11 @@ func GetFeeds(ctx context.Context, opts GetFeedsOptions) (ActionList, int64, err
243243
sess := db.GetEngine(ctx).Where(cond)
244244
sess = db.SetSessionPagination(sess, &opts)
245245

246-
count, err = sess.Desc("`action`.created_unix").FindAndCount(&actions)
246+
if opts.DontCount {
247+
err = sess.Desc("`action`.created_unix").Find(&actions)
248+
} else {
249+
count, err = sess.Desc("`action`.created_unix").FindAndCount(&actions)
250+
}
247251
if err != nil {
248252
return nil, 0, fmt.Errorf("FindAndCount: %w", err)
249253
}
@@ -257,11 +261,13 @@ func GetFeeds(ctx context.Context, opts GetFeedsOptions) (ActionList, int64, err
257261
return nil, 0, fmt.Errorf("Find(actionsIDs): %w", err)
258262
}
259263

260-
count, err = db.GetEngine(ctx).Where(cond).
261-
Table("action").
262-
Cols("`action`.id").Count()
263-
if err != nil {
264-
return nil, 0, fmt.Errorf("Count: %w", err)
264+
if !opts.DontCount {
265+
count, err = db.GetEngine(ctx).Where(cond).
266+
Table("action").
267+
Cols("`action`.id").Count()
268+
if err != nil {
269+
return nil, 0, fmt.Errorf("Count: %w", err)
270+
}
265271
}
266272

267273
if err := db.GetEngine(ctx).In("`action`.id", actionIDs).Desc("`action`.created_unix").Find(&actions); err != nil {
@@ -275,3 +281,9 @@ func GetFeeds(ctx context.Context, opts GetFeedsOptions) (ActionList, int64, err
275281

276282
return actions, count, nil
277283
}
284+
285+
func CountUserFeeds(ctx context.Context, userID int64) (int64, error) {
286+
return db.GetEngine(ctx).Where("user_id = ?", userID).
287+
And("is_deleted = ?", false).
288+
Count(&Action{})
289+
}

models/migrations/migrations.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,7 @@ func prepareMigrationTasks() []*migration {
377377
newMigration(314, "Update OwnerID as zero for repository level action tables", v1_24.UpdateOwnerIDOfRepoLevelActionsTables),
378378
newMigration(315, "Add Ephemeral to ActionRunner", v1_24.AddEphemeralToActionRunner),
379379
newMigration(316, "Add description for secrets and variables", v1_24.AddDescriptionForSecretsAndVariables),
380+
newMigration(317, "Add new index for action for heatmap", v1_24.AddNewIndexForUserDashboard),
380381
}
381382
return preparedMigrations
382383
}

models/migrations/v1_24/v317.go

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
// Copyright 2025 The Gitea Authors. All rights reserved.
2+
// SPDX-License-Identifier: MIT
3+
4+
package v1_24 //nolint
5+
6+
import (
7+
"code.gitea.io/gitea/modules/timeutil"
8+
9+
"xorm.io/xorm"
10+
"xorm.io/xorm/schemas"
11+
)
12+
13+
type improveActionTableIndicesAction struct {
14+
ID int64 `xorm:"pk autoincr"`
15+
UserID int64 `xorm:"INDEX"` // Receiver user id.
16+
OpType int
17+
ActUserID int64 // Action user id.
18+
RepoID int64
19+
CommentID int64 `xorm:"INDEX"`
20+
IsDeleted bool `xorm:"NOT NULL DEFAULT false"`
21+
RefName string
22+
IsPrivate bool `xorm:"NOT NULL DEFAULT false"`
23+
Content string `xorm:"TEXT"`
24+
CreatedUnix timeutil.TimeStamp `xorm:"created"`
25+
}
26+
27+
// TableName sets the name of this table
28+
func (*improveActionTableIndicesAction) TableName() string {
29+
return "action"
30+
}
31+
32+
// TableIndices implements xorm's TableIndices interface
33+
func (a *improveActionTableIndicesAction) TableIndices() []*schemas.Index {
34+
repoIndex := schemas.NewIndex("r_u_d", schemas.IndexType)
35+
repoIndex.AddColumn("repo_id", "user_id", "is_deleted")
36+
37+
actUserIndex := schemas.NewIndex("au_r_c_u_d", schemas.IndexType)
38+
actUserIndex.AddColumn("act_user_id", "repo_id", "created_unix", "user_id", "is_deleted")
39+
40+
cudIndex := schemas.NewIndex("c_u_d", schemas.IndexType)
41+
cudIndex.AddColumn("created_unix", "user_id", "is_deleted")
42+
43+
cuIndex := schemas.NewIndex("c_u", schemas.IndexType)
44+
cuIndex.AddColumn("user_id", "is_deleted")
45+
46+
actUserUserIndex := schemas.NewIndex("au_c_u", schemas.IndexType)
47+
actUserUserIndex.AddColumn("act_user_id", "created_unix", "user_id")
48+
49+
indices := []*schemas.Index{actUserIndex, repoIndex, cudIndex, cuIndex, actUserUserIndex}
50+
51+
return indices
52+
}
53+
54+
func AddNewIndexForUserDashboard(x *xorm.Engine) error {
55+
return x.Sync(new(improveActionTableIndicesAction))
56+
}

models/repo/repo.go

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -215,12 +215,24 @@ func init() {
215215
db.RegisterModel(new(Repository))
216216
}
217217

218-
func (repo *Repository) GetName() string {
219-
return repo.Name
218+
func RelativePath(ownerName, repoName string) string {
219+
return strings.ToLower(ownerName) + "/" + strings.ToLower(repoName) + ".git"
220220
}
221221

222-
func (repo *Repository) GetOwnerName() string {
223-
return repo.OwnerName
222+
// RelativePath should be an unix style path like username/reponame.git
223+
func (repo *Repository) RelativePath() string {
224+
return RelativePath(repo.OwnerName, repo.Name)
225+
}
226+
227+
type StorageRepo string
228+
229+
// RelativePath should be an unix style path like username/reponame.git
230+
func (sr StorageRepo) RelativePath() string {
231+
return string(sr)
232+
}
233+
234+
func (repo *Repository) WikiStorageRepo() StorageRepo {
235+
return StorageRepo(strings.ToLower(repo.OwnerName) + "/" + strings.ToLower(repo.Name) + ".wiki.git")
224236
}
225237

226238
// SanitizedOriginalURL returns a sanitized OriginalURL

modules/gitrepo/branch.go

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -44,24 +44,12 @@ func GetDefaultBranch(ctx context.Context, repo Repository) (string, error) {
4444
return git.GetDefaultBranch(ctx, repoPath(repo))
4545
}
4646

47-
func GetWikiDefaultBranch(ctx context.Context, repo Repository) (string, error) {
48-
return git.GetDefaultBranch(ctx, wikiPath(repo))
49-
}
50-
5147
// IsReferenceExist returns true if given reference exists in the repository.
5248
func IsReferenceExist(ctx context.Context, repo Repository, name string) bool {
5349
return git.IsReferenceExist(ctx, repoPath(repo), name)
5450
}
5551

56-
func IsWikiReferenceExist(ctx context.Context, repo Repository, name string) bool {
57-
return git.IsReferenceExist(ctx, wikiPath(repo), name)
58-
}
59-
6052
// IsBranchExist returns true if given branch exists in the repository.
6153
func IsBranchExist(ctx context.Context, repo Repository, name string) bool {
6254
return IsReferenceExist(ctx, repo, git.BranchPrefix+name)
6355
}
64-
65-
func IsWikiBranchExist(ctx context.Context, repo Repository, name string) bool {
66-
return IsWikiReferenceExist(ctx, repo, git.BranchPrefix+name)
67-
}

modules/gitrepo/gitrepo.go

Lines changed: 7 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -8,40 +8,29 @@ import (
88
"fmt"
99
"io"
1010
"path/filepath"
11-
"strings"
1211

1312
"code.gitea.io/gitea/modules/git"
1413
"code.gitea.io/gitea/modules/reqctx"
1514
"code.gitea.io/gitea/modules/setting"
1615
"code.gitea.io/gitea/modules/util"
1716
)
1817

18+
// Repository represents a git repository which stored in a disk
1919
type Repository interface {
20-
GetName() string
21-
GetOwnerName() string
22-
}
23-
24-
func absPath(owner, name string) string {
25-
return filepath.Join(setting.RepoRootPath, strings.ToLower(owner), strings.ToLower(name)+".git")
20+
RelativePath() string // We don't assume how the directory structure of the repository is, so we only need the relative path
2621
}
2722

23+
// RelativePath should be an unix style path like username/reponame.git
24+
// This method should change it according to the current OS.
2825
func repoPath(repo Repository) string {
29-
return absPath(repo.GetOwnerName(), repo.GetName())
30-
}
31-
32-
func wikiPath(repo Repository) string {
33-
return filepath.Join(setting.RepoRootPath, strings.ToLower(repo.GetOwnerName()), strings.ToLower(repo.GetName())+".wiki.git")
26+
return filepath.Join(setting.RepoRootPath, filepath.FromSlash(repo.RelativePath()))
3427
}
3528

3629
// OpenRepository opens the repository at the given relative path with the provided context.
3730
func OpenRepository(ctx context.Context, repo Repository) (*git.Repository, error) {
3831
return git.OpenRepository(ctx, repoPath(repo))
3932
}
4033

41-
func OpenWikiRepository(ctx context.Context, repo Repository) (*git.Repository, error) {
42-
return git.OpenRepository(ctx, wikiPath(repo))
43-
}
44-
4534
// contextKey is a value for use with context.WithValue.
4635
type contextKey struct {
4736
repoPath string
@@ -86,9 +75,8 @@ func DeleteRepository(ctx context.Context, repo Repository) error {
8675
}
8776

8877
// RenameRepository renames a repository's name on disk
89-
func RenameRepository(ctx context.Context, repo Repository, newName string) error {
90-
newRepoPath := absPath(repo.GetOwnerName(), newName)
91-
if err := util.Rename(repoPath(repo), newRepoPath); err != nil {
78+
func RenameRepository(ctx context.Context, repo, newRepo Repository) error {
79+
if err := util.Rename(repoPath(repo), repoPath(newRepo)); err != nil {
9280
return fmt.Errorf("rename repository directory: %w", err)
9381
}
9482
return nil

modules/gitrepo/hooks.go

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -106,16 +106,11 @@ done
106106
return hookNames, hookTpls, giteaHookTpls
107107
}
108108

109-
// CreateDelegateHooksForRepo creates all the hooks scripts for the repo
110-
func CreateDelegateHooksForRepo(_ context.Context, repo Repository) (err error) {
109+
// CreateDelegateHooks creates all the hooks scripts for the repo
110+
func CreateDelegateHooks(_ context.Context, repo Repository) (err error) {
111111
return createDelegateHooks(filepath.Join(repoPath(repo), "hooks"))
112112
}
113113

114-
// CreateDelegateHooksForWiki creates all the hooks scripts for the wiki repo
115-
func CreateDelegateHooksForWiki(_ context.Context, repo Repository) (err error) {
116-
return createDelegateHooks(filepath.Join(wikiPath(repo), "hooks"))
117-
}
118-
119114
func createDelegateHooks(hookDir string) (err error) {
120115
hookNames, hookTpls, giteaHookTpls := getHookTemplates()
121116

@@ -178,16 +173,11 @@ func ensureExecutable(filename string) error {
178173
return os.Chmod(filename, mode)
179174
}
180175

181-
// CheckDelegateHooksForRepo checks the hooks scripts for the repo
182-
func CheckDelegateHooksForRepo(_ context.Context, repo Repository) ([]string, error) {
176+
// CheckDelegateHooks checks the hooks scripts for the repo
177+
func CheckDelegateHooks(_ context.Context, repo Repository) ([]string, error) {
183178
return checkDelegateHooks(filepath.Join(repoPath(repo), "hooks"))
184179
}
185180

186-
// CheckDelegateHooksForWiki checks the hooks scripts for the repo
187-
func CheckDelegateHooksForWiki(_ context.Context, repo Repository) ([]string, error) {
188-
return checkDelegateHooks(filepath.Join(wikiPath(repo), "hooks"))
189-
}
190-
191181
func checkDelegateHooks(hookDir string) ([]string, error) {
192182
hookNames, hookTpls, giteaHookTpls := getHookTemplates()
193183

0 commit comments

Comments
 (0)