Changes
11 changed files (+397/-423)
-
-
@@ -1186,6 +1186,9 @@ type IssuesOptions struct {// prioritize issues from this repo PriorityRepoID int64 IsArchived util.OptionalBool Org *Organization // issues permission scope Team *Team // issues permission scope User *user_model.User // issues permission scope } // sortIssuesSession sort an issues-related session based on the provided
-
@@ -1337,6 +1340,44 @@ func (opts *IssuesOptions) setupSession(sess *xorm.Session) {From("milestone"). Where(builder.In("name", opts.IncludeMilestones))) } if opts.User != nil { sess.And( issuePullAccessibleRepoCond("issue.repo_id", opts.User.ID, opts.Org, opts.Team, opts.IsPull.IsTrue()), ) } } // issuePullAccessibleRepoCond userID must not be zero, this condition require join repository table func issuePullAccessibleRepoCond(repoIDstr string, userID int64, org *Organization, team *Team, isPull bool) builder.Cond { var cond = builder.NewCond() var unitType = unit.TypeIssues if isPull { unitType = unit.TypePullRequests } if org != nil { if team != nil { cond = cond.And(teamUnitsRepoCond(repoIDstr, userID, org.ID, team.ID, unitType)) // special team member repos } else { cond = cond.And( builder.Or( userOrgUnitRepoCond(repoIDstr, userID, org.ID, unitType), // team member repos userOrgPublicUnitRepoCond(userID, org.ID), // user org public non-member repos, TODO: check repo has issues ), ) } } else { cond = cond.And( builder.Or( userOwnedRepoCond(userID), // owned repos userCollaborationRepoCond(repoIDstr, userID), // collaboration repos userAssignedRepoCond(repoIDstr, userID), // user has been assigned accessible public repos userMentionedRepoCond(repoIDstr, userID), // user has been mentioned accessible public repos userCreateIssueRepoCond(repoIDstr, userID, isPull), // user has created issue/pr accessible public repos ), ) } return cond } func applyReposCondition(sess *xorm.Session, repoIDs []int64) *xorm.Session {
-
@@ -1646,15 +1687,16 @@ func getIssueStatsChunk(opts *IssueStatsOptions, issueIDs []int64) (*IssueStats,// UserIssueStatsOptions contains parameters accepted by GetUserIssueStats. type UserIssueStatsOptions struct { UserID int64 RepoIDs []int64 UserRepoIDs []int64 FilterMode int IsPull bool IsClosed bool IssueIDs []int64 IsArchived util.OptionalBool LabelIDs []int64 UserID int64 RepoIDs []int64 FilterMode int IsPull bool IsClosed bool IssueIDs []int64 IsArchived util.OptionalBool LabelIDs []int64 Org *Organization Team *Team } // GetUserIssueStats returns issue statistic information for dashboard by given conditions.
-
@@ -1671,28 +1713,34 @@ func GetUserIssueStats(opts UserIssueStatsOptions) (*IssueStats, error) {cond = cond.And(builder.In("issue.id", opts.IssueIDs)) } if opts.UserID > 0 { cond = cond.And(issuePullAccessibleRepoCond("issue.repo_id", opts.UserID, opts.Org, opts.Team, opts.IsPull)) } sess := func(cond builder.Cond) *xorm.Session { s := db.GetEngine(db.DefaultContext).Where(cond) if len(opts.LabelIDs) > 0 { s.Join("INNER", "issue_label", "issue_label.issue_id = issue.id"). In("issue_label.label_id", opts.LabelIDs) } if opts.IsArchived != util.OptionalBoolNone { s.Join("INNER", "repository", "issue.repo_id = repository.id"). And(builder.Eq{"repository.is_archived": opts.IsArchived.IsTrue()}) if opts.UserID > 0 || opts.IsArchived != util.OptionalBoolNone { s.Join("INNER", "repository", "issue.repo_id = repository.id") if opts.IsArchived != util.OptionalBoolNone { s.And(builder.Eq{"repository.is_archived": opts.IsArchived.IsTrue()}) } } return s } switch opts.FilterMode { case FilterModeAll: stats.OpenCount, err = applyReposCondition(sess(cond), opts.UserRepoIDs). stats.OpenCount, err = sess(cond). And("issue.is_closed = ?", false). Count(new(Issue)) if err != nil { return nil, err } stats.ClosedCount, err = applyReposCondition(sess(cond), opts.UserRepoIDs). stats.ClosedCount, err = sess(cond). And("issue.is_closed = ?", true). Count(new(Issue)) if err != nil {
-
@@ -1768,7 +1816,7 @@ func GetUserIssueStats(opts UserIssueStatsOptions) (*IssueStats, error) {return nil, err } stats.YourRepositoriesCount, err = applyReposCondition(sess(cond), opts.UserRepoIDs).Count(new(Issue)) stats.YourRepositoriesCount, err = sess(cond).Count(new(Issue)) if err != nil { return nil, err }
-
-
-
@@ -25,6 +25,9 @@ const (func (issues IssueList) getRepoIDs() []int64 { repoIDs := make(map[int64]struct{}, len(issues)) for _, issue := range issues { if issue.Repo != nil { continue } if _, ok := repoIDs[issue.RepoID]; !ok { repoIDs[issue.RepoID] = struct{}{} }
-
@@ -56,8 +59,12 @@ func (issues IssueList) loadRepositories(e db.Engine) ([]*repo_model.Repository,} for _, issue := range issues { issue.Repo = repoMaps[issue.RepoID] if issue.PullRequest != nil { if issue.Repo == nil { issue.Repo = repoMaps[issue.RepoID] } else { repoMaps[issue.RepoID] = issue.Repo } if issue.PullRequest != nil && issue.PullRequest.BaseRepo == nil { issue.PullRequest.BaseRepo = issue.Repo } }
-
-
-
@@ -206,52 +206,52 @@ func TestGetUserIssueStats(t *testing.T) {FilterMode: FilterModeAll, }, IssueStats{ YourRepositoriesCount: 0, AssignCount: 1, CreateCount: 1, OpenCount: 0, ClosedCount: 0, YourRepositoriesCount: 1, // 6 AssignCount: 1, // 6 CreateCount: 1, // 6 OpenCount: 1, // 6 ClosedCount: 1, // 1 }, }, { UserIssueStatsOptions{ UserID: 1, FilterMode: FilterModeAssign, RepoIDs: []int64{1}, FilterMode: FilterModeAll, IsClosed: true, }, IssueStats{ YourRepositoriesCount: 0, AssignCount: 2, CreateCount: 2, OpenCount: 2, ClosedCount: 0, YourRepositoriesCount: 1, // 6 AssignCount: 0, CreateCount: 0, OpenCount: 1, // 6 ClosedCount: 1, // 1 }, }, { UserIssueStatsOptions{ UserID: 1, FilterMode: FilterModeCreate, FilterMode: FilterModeAssign, }, IssueStats{ YourRepositoriesCount: 0, AssignCount: 2, CreateCount: 2, OpenCount: 2, YourRepositoriesCount: 1, // 6 AssignCount: 1, // 6 CreateCount: 1, // 6 OpenCount: 1, // 6 ClosedCount: 0, }, }, { UserIssueStatsOptions{ UserID: 2, UserRepoIDs: []int64{1, 2}, FilterMode: FilterModeAll, IsClosed: true, UserID: 1, FilterMode: FilterModeCreate, }, IssueStats{ YourRepositoriesCount: 2, AssignCount: 0, CreateCount: 2, OpenCount: 2, ClosedCount: 2, YourRepositoriesCount: 1, // 6 AssignCount: 1, // 6 CreateCount: 1, // 6 OpenCount: 1, // 6 ClosedCount: 0, }, }, {
-
@@ -260,9 +260,10 @@ func TestGetUserIssueStats(t *testing.T) {FilterMode: FilterModeMention, }, IssueStats{ YourRepositoriesCount: 0, AssignCount: 2, CreateCount: 2, YourRepositoriesCount: 1, // 6 AssignCount: 1, // 6 CreateCount: 1, // 6 MentionCount: 0, OpenCount: 0, ClosedCount: 0, },
-
@@ -274,19 +275,21 @@ func TestGetUserIssueStats(t *testing.T) {IssueIDs: []int64{1}, }, IssueStats{ YourRepositoriesCount: 0, AssignCount: 1, CreateCount: 1, OpenCount: 1, YourRepositoriesCount: 1, // 1 AssignCount: 1, // 1 CreateCount: 1, // 1 OpenCount: 1, // 1 ClosedCount: 0, }, }, } { stats, err := GetUserIssueStats(test.Opts) if !assert.NoError(t, err) { continue } assert.Equal(t, test.ExpectedIssueStats, *stats) t.Run(fmt.Sprintf("%#v", test.Opts), func(t *testing.T) { stats, err := GetUserIssueStats(test.Opts) if !assert.NoError(t, err) { return } assert.Equal(t, test.ExpectedIssueStats, *stats) }) } }
-
-
-
@@ -731,15 +731,6 @@ func CountUserRepositories(userID int64, private bool) int64 {return countRepositories(userID, private) } // GetUserMirrorRepositories returns a list of mirror repositories of given user. func GetUserMirrorRepositories(userID int64) ([]*Repository, error) { repos := make([]*Repository, 0, 10) return repos, db.GetEngine(db.DefaultContext). Where("owner_id = ?", userID). And("is_mirror = ?", true). Find(&repos) } func getRepositoryCount(e db.Engine, ownerID int64) (int64, error) { return e.Count(&Repository{OwnerID: ownerID}) }
-
@@ -766,25 +757,3 @@ func GetPublicRepositoryCount(u *user_model.User) (int64, error) {func GetPrivateRepositoryCount(u *user_model.User) (int64, error) { return getPrivateRepositoryCount(db.GetEngine(db.DefaultContext), u) } // IterateRepository iterate repositories func IterateRepository(f func(repo *Repository) error) error { var start int batchSize := setting.Database.IterateBufferSize for { repos := make([]*Repository, 0, batchSize) if err := db.GetEngine(db.DefaultContext).Limit(batchSize, start).Find(&repos); err != nil { return err } if len(repos) == 0 { return nil } start += len(repos) for _, repo := range repos { if err := f(repo); err != nil { return err } } } }
-
-
models/repo/repo_list.go (new)
-
@@ -0,0 +1,46 @@// Copyright 2021 The Gitea Authors. All rights reserved. // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE file. package repo import ( "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/modules/setting" ) // GetUserMirrorRepositories returns a list of mirror repositories of given user. func GetUserMirrorRepositories(userID int64) ([]*Repository, error) { repos := make([]*Repository, 0, 10) return repos, db.GetEngine(db.DefaultContext). Where("owner_id = ?", userID). And("is_mirror = ?", true). Find(&repos) } // IterateRepository iterate repositories func IterateRepository(f func(repo *Repository) error) error { var start int batchSize := setting.Database.IterateBufferSize for { repos := make([]*Repository, 0, batchSize) if err := db.GetEngine(db.DefaultContext).Limit(batchSize, start).Find(&repos); err != nil { return err } if len(repos) == 0 { return nil } start += len(repos) for _, repo := range repos { if err := f(repo); err != nil { return err } } } } // FindReposMapByIDs find repos as map func FindReposMapByIDs(repoIDs []int64, res map[int64]*Repository) error { return db.GetEngine(db.DefaultContext).In("id", repoIDs).Find(&res) }
-
-
-
@@ -11,6 +11,7 @@ import ("code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/perm" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unit" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/util"
-
@@ -145,6 +146,188 @@ type SearchRepoOptions struct {LowerNames []string } // SearchOrderBy is used to sort the result type SearchOrderBy string func (s SearchOrderBy) String() string { return string(s) } // Strings for sorting result const ( SearchOrderByAlphabetically SearchOrderBy = "name ASC" SearchOrderByAlphabeticallyReverse SearchOrderBy = "name DESC" SearchOrderByLeastUpdated SearchOrderBy = "updated_unix ASC" SearchOrderByRecentUpdated SearchOrderBy = "updated_unix DESC" SearchOrderByOldest SearchOrderBy = "created_unix ASC" SearchOrderByNewest SearchOrderBy = "created_unix DESC" SearchOrderBySize SearchOrderBy = "size ASC" SearchOrderBySizeReverse SearchOrderBy = "size DESC" SearchOrderByID SearchOrderBy = "id ASC" SearchOrderByIDReverse SearchOrderBy = "id DESC" SearchOrderByStars SearchOrderBy = "num_stars ASC" SearchOrderByStarsReverse SearchOrderBy = "num_stars DESC" SearchOrderByForks SearchOrderBy = "num_forks ASC" SearchOrderByForksReverse SearchOrderBy = "num_forks DESC" ) // userOwnedRepoCond returns user ownered repositories func userOwnedRepoCond(userID int64) builder.Cond { return builder.Eq{ "repository.owner_id": userID, } } // userAssignedRepoCond return user as assignee repositories list func userAssignedRepoCond(id string, userID int64) builder.Cond { return builder.And( builder.Eq{ "repository.is_private": false, }, builder.In(id, builder.Select("issue.repo_id").From("issue_assignees"). InnerJoin("issue", "issue.id = issue_assignees.issue_id"). Where(builder.Eq{ "issue_assignees.assignee_id": userID, }), ), ) } // userCreateIssueRepoCond return user created issues repositories list func userCreateIssueRepoCond(id string, userID int64, isPull bool) builder.Cond { return builder.And( builder.Eq{ "repository.is_private": false, }, builder.In(id, builder.Select("issue.repo_id").From("issue"). Where(builder.Eq{ "issue.poster_id": userID, "issue.is_pull": isPull, }), ), ) } // userMentionedRepoCond return user metinoed repositories list func userMentionedRepoCond(id string, userID int64) builder.Cond { return builder.And( builder.Eq{ "repository.is_private": false, }, builder.In(id, builder.Select("issue.repo_id").From("issue_user"). InnerJoin("issue", "issue.id = issue_user.issue_id"). Where(builder.Eq{ "issue_user.is_mentioned": true, "issue_user.uid": userID, }), ), ) } // teamUnitsRepoCond returns query condition for those repo id in the special org team with special units access func teamUnitsRepoCond(id string, userID, orgID, teamID int64, units ...unit.Type) builder.Cond { return builder.In(id, builder.Select("repo_id").From("team_repo").Where( builder.Eq{ "team_id": teamID, }.And( builder.In( "team_id", builder.Select("team_id").From("team_user").Where( builder.Eq{ "uid": userID, }, ), )).And( builder.In( "team_id", builder.Select("team_id").From("team_unit").Where( builder.Eq{ "org_id": orgID, }.And( builder.In("type", units), ), ), ), ), )) } // userCollaborationRepoCond returns user as collabrators repositories list func userCollaborationRepoCond(idStr string, userID int64) builder.Cond { return builder.In(idStr, builder.Select("repo_id"). From("`access`"). Where(builder.And( builder.Eq{"user_id": userID}, builder.Gt{"mode": int(perm.AccessModeNone)}, )), ) } // userOrgTeamRepoCond selects repos that the given user has access to through team membership func userOrgTeamRepoCond(idStr string, userID int64) builder.Cond { return builder.In(idStr, userOrgTeamRepoBuilder(userID)) } // userOrgTeamRepoBuilder returns repo ids where user's teams can access. func userOrgTeamRepoBuilder(userID int64) *builder.Builder { return builder.Select("`team_repo`.repo_id"). From("team_repo"). Join("INNER", "team_user", "`team_user`.team_id = `team_repo`.team_id"). Where(builder.Eq{"`team_user`.uid": userID}) } // userOrgTeamUnitRepoBuilder returns repo ids where user's teams can access the special unit. func userOrgTeamUnitRepoBuilder(userID int64, unitType unit.Type) *builder.Builder { return userOrgTeamRepoBuilder(userID). Join("INNER", "team_unit", "`team_unit`.team_id = `team_repo`.team_id"). Where(builder.Eq{"`team_unit`.`type`": unitType}) } // userOrgUnitRepoCond selects repos that the given user has access to through org and the special unit func userOrgUnitRepoCond(idStr string, userID, orgID int64, unitType unit.Type) builder.Cond { return builder.In(idStr, userOrgTeamUnitRepoBuilder(userID, unitType). And(builder.Eq{"org_id": orgID}), ) } // userOrgPublicRepoCond returns the condition that one user could access all public repositories in organizations func userOrgPublicRepoCond(userID int64) builder.Cond { return builder.And( builder.Eq{"`repository`.is_private": false}, builder.In("`repository`.owner_id", builder.Select("`org_user`.org_id"). From("org_user"). Where(builder.Eq{"`org_user`.uid": userID}), ), ) } // userOrgPublicRepoCondPrivate returns the condition that one user could access all public repositories in private organizations func userOrgPublicRepoCondPrivate(userID int64) builder.Cond { return builder.And( builder.Eq{"`repository`.is_private": false}, builder.In("`repository`.owner_id", builder.Select("`org_user`.org_id"). From("org_user"). Join("INNER", "`user`", "`user`.id = `org_user`.org_id"). Where(builder.Eq{ "`org_user`.uid": userID, "`user`.`type`": user_model.UserTypeOrganization, "`user`.visibility": structs.VisibleTypePrivate, }), ), ) } // userOrgPublicUnitRepoCond returns the condition that one user could access all public repositories in the special organization func userOrgPublicUnitRepoCond(userID, orgID int64) builder.Cond { return userOrgPublicRepoCond(userID). And(builder.Eq{"`repository`.owner_id": orgID}) } // SearchRepositoryCondition creates a query condition according search repository options func SearchRepositoryCondition(opts *SearchRepoOptions) builder.Cond { cond := builder.NewCond()
-
@@ -198,27 +381,12 @@ func SearchRepositoryCondition(opts *SearchRepoOptions) builder.Cond {// 2. But we can see because of: builder.Or( // A. We have access builder.In("`repository`.id", builder.Select("`access`.repo_id"). From("access"). Where(builder.Eq{"`access`.user_id": opts.OwnerID})), userCollaborationRepoCond("`repository`.id", opts.OwnerID), // B. We are in a team for builder.In("`repository`.id", builder.Select("`team_repo`.repo_id"). From("team_repo"). Where(builder.Eq{"`team_user`.uid": opts.OwnerID}). Join("INNER", "team_user", "`team_user`.team_id = `team_repo`.team_id")), // C. Public repositories in private organizations that we are member of builder.And( builder.Eq{"`repository`.is_private": false}, builder.In("`repository`.owner_id", builder.Select("`org_user`.org_id"). From("org_user"). Join("INNER", "`user`", "`user`.id = `org_user`.org_id"). Where(builder.Eq{ "`org_user`.uid": opts.OwnerID, "`user`.type": user_model.UserTypeOrganization, "`user`.visibility": structs.VisibleTypePrivate, })))), userOrgTeamRepoCond("`repository`.id", opts.OwnerID), // C. Public repositories in organizations that we are member of userOrgPublicRepoCondPrivate(opts.OwnerID), ), ) if !opts.Private { collaborateCond = collaborateCond.And(builder.Expr("owner_id NOT IN (SELECT org_id FROM org_user WHERE org_user.uid = ? AND org_user.is_public = ?)", opts.OwnerID, false))
-
@@ -389,24 +557,14 @@ func accessibleRepositoryCondition(user *user_model.User) builder.Cond {if user != nil { cond = cond.Or( // 2. Be able to see all repositories that we have access to builder.In("`repository`.id", builder.Select("repo_id"). From("`access`"). Where(builder.And( builder.Eq{"user_id": user.ID}, builder.Gt{"mode": int(perm.AccessModeNone)}))), userCollaborationRepoCond("`repository`.id", user.ID), // 3. Repositories that we directly own builder.Eq{"`repository`.owner_id": user.ID}, // 4. Be able to see all repositories that we are in a team builder.In("`repository`.id", builder.Select("`team_repo`.repo_id"). From("team_repo"). Where(builder.Eq{"`team_user`.uid": user.ID}). Join("INNER", "team_user", "`team_user`.team_id = `team_repo`.team_id")), userOrgTeamRepoCond("`repository`.id", user.ID), // 5. Be able to see all public repos in private organizations that we are an org_user of builder.And(builder.Eq{"`repository`.is_private": false}, builder.In("`repository`.owner_id", builder.Select("`org_user`.org_id"). From("org_user"). Where(builder.Eq{"`org_user`.uid": user.ID})))) userOrgPublicRepoCond(user.ID), ) } return cond
-
-
-
@@ -400,26 +400,6 @@ func HasAccess(userID int64, repo *repo_model.Repository) (bool, error) {return hasAccess(db.DefaultContext, userID, repo) } // FilterOutRepoIdsWithoutUnitAccess filter out repos where user has no access to repositories func FilterOutRepoIdsWithoutUnitAccess(u *user_model.User, repoIDs []int64, units ...unit.Type) ([]int64, error) { i := 0 for _, rID := range repoIDs { repo, err := repo_model.GetRepositoryByID(rID) if err != nil { return nil, err } perm, err := GetUserRepoPermission(repo, u) if err != nil { return nil, err } if perm.CanReadAny(units...) { repoIDs[i] = rID i++ } } return repoIDs[:i], nil } // GetRepoReaders returns all users that have explicit read access or higher to the repository. func GetRepoReaders(repo *repo_model.Repository) (_ []*user_model.User, err error) { return getUsersWithAccessMode(db.DefaultContext, repo, perm_model.AccessModeRead)
-
-
-
@@ -15,7 +15,6 @@ import (asymkey_model "code.gitea.io/gitea/models/asymkey" "code.gitea.io/gitea/models/db" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unit" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/structs"
-
@@ -30,109 +29,6 @@ func GetOrganizationCount(ctx context.Context, u *user_model.User) (int64, errorCount(new(OrgUser)) } // GetRepositoryIDs returns repositories IDs where user owned and has unittypes // Caller shall check that units is not globally disabled func GetRepositoryIDs(u *user_model.User, units ...unit.Type) ([]int64, error) { var ids []int64 sess := db.GetEngine(db.DefaultContext).Table("repository").Cols("repository.id") if len(units) > 0 { sess = sess.Join("INNER", "repo_unit", "repository.id = repo_unit.repo_id") sess = sess.In("repo_unit.type", units) } return ids, sess.Where("owner_id = ?", u.ID).Find(&ids) } // GetActiveRepositoryIDs returns non-archived repositories IDs where user owned and has unittypes // Caller shall check that units is not globally disabled func GetActiveRepositoryIDs(u *user_model.User, units ...unit.Type) ([]int64, error) { var ids []int64 sess := db.GetEngine(db.DefaultContext).Table("repository").Cols("repository.id") if len(units) > 0 { sess = sess.Join("INNER", "repo_unit", "repository.id = repo_unit.repo_id") sess = sess.In("repo_unit.type", units) } sess.Where(builder.Eq{"is_archived": false}) return ids, sess.Where("owner_id = ?", u.ID).GroupBy("repository.id").Find(&ids) } // GetOrgRepositoryIDs returns repositories IDs where user's team owned and has unittypes // Caller shall check that units is not globally disabled func GetOrgRepositoryIDs(u *user_model.User, units ...unit.Type) ([]int64, error) { var ids []int64 if err := db.GetEngine(db.DefaultContext).Table("repository"). Cols("repository.id"). Join("INNER", "team_user", "repository.owner_id = team_user.org_id"). Join("INNER", "team_repo", "(? != ? and repository.is_private != ?) OR (team_user.team_id = team_repo.team_id AND repository.id = team_repo.repo_id)", true, u.IsRestricted, true). Where("team_user.uid = ?", u.ID). GroupBy("repository.id").Find(&ids); err != nil { return nil, err } if len(units) > 0 { return FilterOutRepoIdsWithoutUnitAccess(u, ids, units...) } return ids, nil } // GetActiveOrgRepositoryIDs returns non-archived repositories IDs where user's team owned and has unittypes // Caller shall check that units is not globally disabled func GetActiveOrgRepositoryIDs(u *user_model.User, units ...unit.Type) ([]int64, error) { var ids []int64 if err := db.GetEngine(db.DefaultContext).Table("repository"). Cols("repository.id"). Join("INNER", "team_user", "repository.owner_id = team_user.org_id"). Join("INNER", "team_repo", "(? != ? and repository.is_private != ?) OR (team_user.team_id = team_repo.team_id AND repository.id = team_repo.repo_id)", true, u.IsRestricted, true). Where("team_user.uid = ?", u.ID). Where(builder.Eq{"is_archived": false}). GroupBy("repository.id").Find(&ids); err != nil { return nil, err } if len(units) > 0 { return FilterOutRepoIdsWithoutUnitAccess(u, ids, units...) } return ids, nil } // GetAccessRepoIDs returns all repositories IDs where user's or user is a team member organizations // Caller shall check that units is not globally disabled func GetAccessRepoIDs(u *user_model.User, units ...unit.Type) ([]int64, error) { ids, err := GetRepositoryIDs(u, units...) if err != nil { return nil, err } ids2, err := GetOrgRepositoryIDs(u, units...) if err != nil { return nil, err } return append(ids, ids2...), nil } // GetActiveAccessRepoIDs returns all non-archived repositories IDs where user's or user is a team member organizations // Caller shall check that units is not globally disabled func GetActiveAccessRepoIDs(u *user_model.User, units ...unit.Type) ([]int64, error) { ids, err := GetActiveRepositoryIDs(u, units...) if err != nil { return nil, err } ids2, err := GetActiveOrgRepositoryIDs(u, units...) if err != nil { return nil, err } return append(ids, ids2...), nil } // deleteBeans deletes all given beans, beans should contain delete conditions. func deleteBeans(e db.Engine, beans ...interface{}) (err error) { for i := range beans {
-
-
-
@@ -98,25 +98,3 @@ func testIsUserOrgOwner(t *testing.T, uid, orgID int64, expected bool) {assert.NoError(t, err) assert.Equal(t, expected, is) } func TestGetOrgRepositoryIDs(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) user4 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}).(*user_model.User) user5 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 5}).(*user_model.User) accessibleRepos, err := GetOrgRepositoryIDs(user2) assert.NoError(t, err) // User 2's team has access to private repos 3, 5, repo 32 is a public repo of the organization assert.Equal(t, []int64{3, 5, 23, 24, 32}, accessibleRepos) accessibleRepos, err = GetOrgRepositoryIDs(user4) assert.NoError(t, err) // User 4's team has access to private repo 3, repo 32 is a public repo of the organization assert.Equal(t, []int64{3, 32}, accessibleRepos) accessibleRepos, err = GetOrgRepositoryIDs(user5) assert.NoError(t, err) // User 5's team has no access to any repo assert.Len(t, accessibleRepos, 0) }
-
-
-
@@ -403,27 +403,26 @@ func buildIssueOverview(ctx *context.Context, unitType unit.Type) {// - Count Issues by repo // -------------------------------------------------------------------------- isPullList := unitType == unit.TypePullRequests opts := &models.IssuesOptions{ IsPull: util.OptionalBoolOf(isPullList), SortType: sortType, IsArchived: util.OptionalBoolFalse, } // Get repository IDs where User/Org/Team has access. var team *models.Team var org *models.Organization if ctx.Org != nil { org = ctx.Org.Organization team = ctx.Org.Team } userRepoIDs, err := getActiveUserRepoIDs(ctxUser, team, unitType) if err != nil { ctx.ServerError("userRepoIDs", err) return isPullList := unitType == unit.TypePullRequests opts := &models.IssuesOptions{ IsPull: util.OptionalBoolOf(isPullList), SortType: sortType, IsArchived: util.OptionalBoolFalse, Org: org, Team: team, User: ctx.User, } switch filterMode { case models.FilterModeAll: opts.RepoIDs = userRepoIDs case models.FilterModeAssign: opts.AssigneeID = ctx.User.ID case models.FilterModeCreate:
-
@@ -434,10 +433,6 @@ func buildIssueOverview(ctx *context.Context, unitType unit.Type) {opts.ReviewRequestedID = ctx.User.ID } if ctxUser.IsOrganization() { opts.RepoIDs = userRepoIDs } // keyword holds the search term entered into the search field. keyword := strings.Trim(ctx.FormString("q"), " ") ctx.Data["Keyword"] = keyword
-
@@ -524,27 +519,25 @@ func buildIssueOverview(ctx *context.Context, unitType unit.Type) {// ---------------------------------- // showReposMap maps repository IDs to their Repository pointers. showReposMap, err := repoIDMap(ctxUser, issueCountByRepo, unitType) showReposMap, err := loadRepoByIDs(ctxUser, issueCountByRepo, unitType) if err != nil { if repo_model.IsErrRepoNotExist(err) { ctx.NotFound("GetRepositoryByID", err) return } ctx.ServerError("repoIDMap", err) ctx.ServerError("loadRepoByIDs", err) return } // a RepositoryList showRepos := models.RepositoryListOfMap(showReposMap) sort.Sort(showRepos) if err = showRepos.LoadAttributes(); err != nil { ctx.ServerError("LoadAttributes", err) return } // maps pull request IDs to their CommitStatus. Will be posted to ctx.Data. for _, issue := range issues { issue.Repo = showReposMap[issue.RepoID] if issue.Repo == nil { issue.Repo = showReposMap[issue.RepoID] } } commitStatus, err := pull_service.GetIssuesLastCommitStatus(issues)
-
@@ -556,86 +549,39 @@ func buildIssueOverview(ctx *context.Context, unitType unit.Type) {// ------------------------------- // Fill stats to post to ctx.Data. // ------------------------------- userIssueStatsOpts := models.UserIssueStatsOptions{ UserID: ctx.User.ID, UserRepoIDs: userRepoIDs, FilterMode: filterMode, IsPull: isPullList, IsClosed: isShowClosed, IsArchived: util.OptionalBoolFalse, LabelIDs: opts.LabelIDs, } if len(repoIDs) > 0 { userIssueStatsOpts.UserRepoIDs = repoIDs } if ctxUser.IsOrganization() { userIssueStatsOpts.RepoIDs = userRepoIDs } userIssueStats, err := models.GetUserIssueStats(userIssueStatsOpts) if err != nil { ctx.ServerError("GetUserIssueStats User", err) return } var shownIssueStats *models.IssueStats var issueStats *models.IssueStats if !forceEmpty { statsOpts := models.UserIssueStatsOptions{ UserID: ctx.User.ID, UserRepoIDs: userRepoIDs, FilterMode: filterMode, IsPull: isPullList, IsClosed: isShowClosed, IssueIDs: issueIDsFromSearch, IsArchived: util.OptionalBoolFalse, LabelIDs: opts.LabelIDs, UserID: ctx.User.ID, FilterMode: filterMode, IsPull: isPullList, IsClosed: isShowClosed, IssueIDs: issueIDsFromSearch, IsArchived: util.OptionalBoolFalse, LabelIDs: opts.LabelIDs, Org: org, Team: team, } if len(repoIDs) > 0 { statsOpts.RepoIDs = repoIDs } else if ctxUser.IsOrganization() { statsOpts.RepoIDs = userRepoIDs } shownIssueStats, err = models.GetUserIssueStats(statsOpts) issueStats, err = models.GetUserIssueStats(statsOpts) if err != nil { ctx.ServerError("GetUserIssueStats Shown", err) return } } else { shownIssueStats = &models.IssueStats{} } var allIssueStats *models.IssueStats if !forceEmpty { allIssueStatsOpts := models.UserIssueStatsOptions{ UserID: ctx.User.ID, UserRepoIDs: userRepoIDs, FilterMode: filterMode, IsPull: isPullList, IsClosed: isShowClosed, IssueIDs: issueIDsFromSearch, IsArchived: util.OptionalBoolFalse, LabelIDs: opts.LabelIDs, } if ctxUser.IsOrganization() { allIssueStatsOpts.RepoIDs = userRepoIDs } allIssueStats, err = models.GetUserIssueStats(allIssueStatsOpts) if err != nil { ctx.ServerError("GetUserIssueStats All", err) return } } else { allIssueStats = &models.IssueStats{} issueStats = &models.IssueStats{} } // Will be posted to ctx.Data. var shownIssues int if !isShowClosed { shownIssues = int(shownIssueStats.OpenCount) ctx.Data["TotalIssueCount"] = int(allIssueStats.OpenCount) shownIssues = int(issueStats.OpenCount) ctx.Data["TotalIssueCount"] = shownIssues } else { shownIssues = int(shownIssueStats.ClosedCount) ctx.Data["TotalIssueCount"] = int(allIssueStats.ClosedCount) shownIssues = int(issueStats.ClosedCount) ctx.Data["TotalIssueCount"] = shownIssues } ctx.Data["IsShowClosed"] = isShowClosed
-
@@ -671,8 +617,7 @@ func buildIssueOverview(ctx *context.Context, unitType unit.Type) {ctx.Data["CommitStatus"] = commitStatus ctx.Data["Repos"] = showRepos ctx.Data["Counts"] = issueCountByRepo ctx.Data["IssueStats"] = userIssueStats ctx.Data["ShownIssueStats"] = shownIssueStats ctx.Data["IssueStats"] = issueStats ctx.Data["ViewType"] = viewType ctx.Data["SortType"] = sortType ctx.Data["RepoIDs"] = repoIDs
-
@@ -730,56 +675,6 @@ func getRepoIDs(reposQuery string) []int64 {return repoIDs } func getActiveUserRepoIDs(ctxUser *user_model.User, team *models.Team, unitType unit.Type) ([]int64, error) { var userRepoIDs []int64 var err error if ctxUser.IsOrganization() { userRepoIDs, err = getActiveTeamOrOrgRepoIds(ctxUser, team, unitType) if err != nil { return nil, fmt.Errorf("orgRepoIds: %v", err) } } else { userRepoIDs, err = models.GetActiveAccessRepoIDs(ctxUser, unitType) if err != nil { return nil, fmt.Errorf("ctxUser.GetAccessRepoIDs: %v", err) } } if len(userRepoIDs) == 0 { userRepoIDs = []int64{-1} } return userRepoIDs, nil } // getActiveTeamOrOrgRepoIds gets RepoIDs for ctxUser as Organization. // Should be called if and only if ctxUser.IsOrganization == true. func getActiveTeamOrOrgRepoIds(ctxUser *user_model.User, team *models.Team, unitType unit.Type) ([]int64, error) { var orgRepoIDs []int64 var err error var env models.AccessibleReposEnvironment if team != nil { env = models.OrgFromUser(ctxUser).AccessibleTeamReposEnv(team) } else { env, err = models.OrgFromUser(ctxUser).AccessibleReposEnv(ctxUser.ID) if err != nil { return nil, fmt.Errorf("AccessibleReposEnv: %v", err) } } orgRepoIDs, err = env.RepoIDs(1, ctxUser.NumRepos) if err != nil { return nil, fmt.Errorf("env.RepoIDs: %v", err) } orgRepoIDs, err = models.FilterOutRepoIdsWithoutUnitAccess(ctxUser, orgRepoIDs, unitType) if err != nil { return nil, fmt.Errorf("FilterOutRepoIdsWithoutUnitAccess: %v", err) } return orgRepoIDs, nil } func issueIDsFromSearch(ctxUser *user_model.User, keyword string, opts *models.IssuesOptions) ([]int64, error) { if len(keyword) == 0 { return []int64{}, nil
-
@@ -797,33 +692,27 @@ func issueIDsFromSearch(ctxUser *user_model.User, keyword string, opts *models.Ireturn issueIDsFromSearch, nil } func repoIDMap(ctxUser *user_model.User, issueCountByRepo map[int64]int64, unitType unit.Type) (map[int64]*repo_model.Repository, error) { repoByID := make(map[int64]*repo_model.Repository, len(issueCountByRepo)) func loadRepoByIDs(ctxUser *user_model.User, issueCountByRepo map[int64]int64, unitType unit.Type) (map[int64]*repo_model.Repository, error) { var totalRes = make(map[int64]*repo_model.Repository, len(issueCountByRepo)) var repoIDs = make([]int64, 0, 500) for id := range issueCountByRepo { if id <= 0 { continue } if _, ok := repoByID[id]; !ok { repo, err := repo_model.GetRepositoryByID(id) if repo_model.IsErrRepoNotExist(err) { repoIDs = append(repoIDs, id) if len(repoIDs) == 500 { if err := repo_model.FindReposMapByIDs(repoIDs, totalRes); err != nil { return nil, err } else if err != nil { return nil, fmt.Errorf("GetRepositoryByID: [%d]%v", id, err) } repoByID[id] = repo repoIDs = repoIDs[:0] } repo := repoByID[id] // Check if user has access to given repository. perm, err := models.GetUserRepoPermission(repo, ctxUser) if err != nil { return nil, fmt.Errorf("GetUserRepoPermission: [%d]%v", id, err) } if !perm.CanRead(unitType) { log.Debug("User created Issues in Repository which they no longer have access to: [%d]", id) } if len(repoIDs) > 0 { if err := repo_model.FindReposMapByIDs(repoIDs, totalRes); err != nil { return nil, err } } return repoByID, nil return totalRes, nil } // ShowSSHKeys output all the ssh keys of user by uid
-
-
-
@@ -61,11 +61,11 @@<div class="ui compact tiny menu"> <a class="item{{if not .IsShowClosed}} active{{end}}" href="{{.Link}}?type={{$.ViewType}}&repos=[{{range $.RepoIDs}}{{.}}%2C{{end}}]&sort={{$.SortType}}&state=open&q={{$.Keyword}}"> {{svg "octicon-issue-opened" 16 "mr-3"}} {{.i18n.Tr "repo.issues.open_tab" .ShownIssueStats.OpenCount}} {{.i18n.Tr "repo.issues.open_tab" .IssueStats.OpenCount}} </a> <a class="item{{if .IsShowClosed}} active{{end}}" href="{{.Link}}?type={{$.ViewType}}&repos=[{{range $.RepoIDs}}{{.}}%2C{{end}}]&sort={{$.SortType}}&state=closed&q={{$.Keyword}}"> {{svg "octicon-issue-closed" 16 "mr-3"}} {{.i18n.Tr "repo.issues.close_tab" .ShownIssueStats.ClosedCount}} {{.i18n.Tr "repo.issues.close_tab" .IssueStats.ClosedCount}} </a> </div> </div>
-