From 9c318a17f576887736e97c7bc2971d2ad7579a33 Mon Sep 17 00:00:00 2001 From: zeripath Date: Wed, 2 Feb 2022 08:40:04 +0000 Subject: [PATCH] Add `GetUserTeams` (#18499) (#18531) Backport #18499 * Correct use `UserID` in `SearchTeams` - Use `UserID` in the `SearchTeams` function, currently it was useless to pass such information. Now it does a INNER statement to `team_user` which obtains UserID -> TeamID data. - Make OrgID optional. - Resolves #18484 * Seperate searching specific user * Add condition back * Use correct struct type Co-authored-by: Gusted Co-authored-by: 6543 <6543@obermui.de> Co-authored-by: Lunny Xiao Co-authored-by: wxiaoguang Co-authored-by: techknowlogick --- models/org_team.go | 61 +++++++++++++++++++++++++++---- models/org_team_test.go | 4 +- modules/repository/create_test.go | 2 +- routers/api/v1/org/team.go | 11 +++--- routers/web/org/teams.go | 2 +- 5 files changed, 62 insertions(+), 18 deletions(-) diff --git a/models/org_team.go b/models/org_team.go index bce4afb061..17f95bb5b0 100644 --- a/models/org_team.go +++ b/models/org_team.go @@ -49,22 +49,67 @@ func init() { db.RegisterModel(new(TeamUnit)) } -// SearchTeamOptions holds the search options -type SearchTeamOptions struct { +// SearchOrgTeamOptions holds the search options +type SearchOrgTeamOptions struct { db.ListOptions - UserID int64 Keyword string OrgID int64 IncludeDesc bool } +// GetUserTeamOptions holds the search options. +type GetUserTeamOptions struct { + db.ListOptions + UserID int64 +} + // SearchMembersOptions holds the search options type SearchMembersOptions struct { db.ListOptions } -// SearchTeam search for teams. Caller is responsible to check permissions. -func SearchTeam(opts *SearchTeamOptions) ([]*Team, int64, error) { +// GetUserTeams search for org teams. Caller is responsible to check permissions. +func GetUserTeams(opts *GetUserTeamOptions) ([]*Team, int64, error) { + if opts.Page <= 0 { + opts.Page = 1 + } + if opts.PageSize == 0 { + // Default limit + opts.PageSize = 10 + } + + sess := db.GetEngine(db.DefaultContext) + + sess = sess.Join("INNER", "team_user", "team_user.team_id = team.id"). + And("team_user.uid=?", opts.UserID) + + count, err := sess. + Count(new(Team)) + if err != nil { + return nil, 0, err + } + + if opts.PageSize == -1 { + opts.PageSize = int(count) + } else { + sess = sess.Limit(opts.PageSize, (opts.Page-1)*opts.PageSize) + } + + sess = sess.Join("INNER", "team_user", "team_user.team_id = team.id"). + And("team_user.uid=?", opts.UserID) + + teams := make([]*Team, 0, opts.PageSize) + if err = sess. + OrderBy("lower_name"). + Find(&teams); err != nil { + return nil, 0, err + } + + return teams, count, nil +} + +// SearchOrgTeams search for org teams. Caller is responsible to check permissions. +func SearchOrgTeams(opts *SearchOrgTeamOptions) ([]*Team, int64, error) { if opts.Page <= 0 { opts.Page = 1 } @@ -196,7 +241,7 @@ func (t *Team) getRepositories(e db.Engine) error { } // GetRepositories returns paginated repositories in team of organization. -func (t *Team) GetRepositories(opts *SearchTeamOptions) error { +func (t *Team) GetRepositories(opts *SearchOrgTeamOptions) error { if opts.Page == 0 { return t.getRepositories(db.GetEngine(db.DefaultContext)) } @@ -716,7 +761,7 @@ func UpdateTeam(t *Team, authChanged, includeAllChanged bool) (err error) { // DeleteTeam deletes given team. // It's caller's responsibility to assign organization ID. func DeleteTeam(t *Team) error { - if err := t.GetRepositories(&SearchTeamOptions{}); err != nil { + if err := t.GetRepositories(&SearchOrgTeamOptions{}); err != nil { return err } @@ -858,7 +903,7 @@ func AddTeamMember(team *Team, userID int64) error { } // Get team and its repositories. - if err := team.GetRepositories(&SearchTeamOptions{}); err != nil { + if err := team.GetRepositories(&SearchOrgTeamOptions{}); err != nil { return err } diff --git a/models/org_team_test.go b/models/org_team_test.go index aa62cc58e2..cf3a797991 100644 --- a/models/org_team_test.go +++ b/models/org_team_test.go @@ -46,7 +46,7 @@ func TestTeam_GetRepositories(t *testing.T) { test := func(teamID int64) { team := unittest.AssertExistsAndLoadBean(t, &Team{ID: teamID}).(*Team) - assert.NoError(t, team.GetRepositories(&SearchTeamOptions{})) + assert.NoError(t, team.GetRepositories(&SearchOrgTeamOptions{})) assert.Len(t, team.Repos, team.NumRepos) for _, repo := range team.Repos { unittest.AssertExistsAndLoadBean(t, &TeamRepo{TeamID: teamID, RepoID: repo.ID}) @@ -292,7 +292,7 @@ func TestGetTeamMembers(t *testing.T) { func TestGetUserTeams(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) test := func(userID int64) { - teams, _, err := SearchTeam(&SearchTeamOptions{UserID: userID}) + teams, _, err := GetUserTeams(&GetUserTeamOptions{UserID: userID}) assert.NoError(t, err) for _, team := range teams { unittest.AssertExistsAndLoadBean(t, &TeamUser{TeamID: team.ID, UID: userID}) diff --git a/modules/repository/create_test.go b/modules/repository/create_test.go index ed890ace43..4e232a8609 100644 --- a/modules/repository/create_test.go +++ b/modules/repository/create_test.go @@ -23,7 +23,7 @@ func TestIncludesAllRepositoriesTeams(t *testing.T) { testTeamRepositories := func(teamID int64, repoIds []int64) { team := unittest.AssertExistsAndLoadBean(t, &models.Team{ID: teamID}).(*models.Team) - assert.NoError(t, team.GetRepositories(&models.SearchTeamOptions{}), "%s: GetRepositories", team.Name) + assert.NoError(t, team.GetRepositories(&models.SearchOrgTeamOptions{}), "%s: GetRepositories", team.Name) assert.Len(t, team.Repos, team.NumRepos, "%s: len repo", team.Name) assert.Len(t, team.Repos, len(repoIds), "%s: repo count", team.Name) for i, rid := range repoIds { diff --git a/routers/api/v1/org/team.go b/routers/api/v1/org/team.go index cc7a63af33..62e6c0a6b4 100644 --- a/routers/api/v1/org/team.go +++ b/routers/api/v1/org/team.go @@ -47,7 +47,7 @@ func ListTeams(ctx *context.APIContext) { // "200": // "$ref": "#/responses/TeamList" - teams, count, err := models.SearchTeam(&models.SearchTeamOptions{ + teams, count, err := models.SearchOrgTeams(&models.SearchOrgTeamOptions{ ListOptions: utils.GetListOptions(ctx), OrgID: ctx.Org.Organization.ID, }) @@ -90,7 +90,7 @@ func ListUserTeams(ctx *context.APIContext) { // "200": // "$ref": "#/responses/TeamList" - teams, count, err := models.SearchTeam(&models.SearchTeamOptions{ + teams, count, err := models.GetUserTeams(&models.GetUserTeamOptions{ ListOptions: utils.GetListOptions(ctx), UserID: ctx.User.ID, }) @@ -533,7 +533,7 @@ func GetTeamRepos(ctx *context.APIContext) { // "$ref": "#/responses/RepositoryList" team := ctx.Org.Team - if err := team.GetRepositories(&models.SearchTeamOptions{ + if err := team.GetRepositories(&models.SearchOrgTeamOptions{ ListOptions: utils.GetListOptions(ctx), }); err != nil { ctx.Error(http.StatusInternalServerError, "GetTeamRepos", err) @@ -707,15 +707,14 @@ func SearchTeam(ctx *context.APIContext) { listOptions := utils.GetListOptions(ctx) - opts := &models.SearchTeamOptions{ - UserID: ctx.User.ID, + opts := &models.SearchOrgTeamOptions{ Keyword: ctx.FormTrim("q"), OrgID: ctx.Org.Organization.ID, IncludeDesc: ctx.FormString("include_desc") == "" || ctx.FormBool("include_desc"), ListOptions: listOptions, } - teams, maxResults, err := models.SearchTeam(opts) + teams, maxResults, err := models.SearchOrgTeams(opts) if err != nil { log.Error("SearchTeam failed: %v", err) ctx.JSON(http.StatusInternalServerError, map[string]interface{}{ diff --git a/routers/web/org/teams.go b/routers/web/org/teams.go index 732f24b22c..9b0212e569 100644 --- a/routers/web/org/teams.go +++ b/routers/web/org/teams.go @@ -319,7 +319,7 @@ func TeamRepositories(ctx *context.Context) { ctx.Data["Title"] = ctx.Org.Team.Name ctx.Data["PageIsOrgTeams"] = true ctx.Data["PageIsOrgTeamRepos"] = true - if err := ctx.Org.Team.GetRepositories(&models.SearchTeamOptions{}); err != nil { + if err := ctx.Org.Team.GetRepositories(&models.SearchOrgTeamOptions{}); err != nil { ctx.ServerError("GetRepositories", err) return }