From 5ac6da3c41f628f31b2805bfc422a3abb6b76d6b Mon Sep 17 00:00:00 2001 From: Harshit Bansal Date: Thu, 17 Jan 2019 06:09:50 +0530 Subject: [PATCH] api: Add missing GET teams endpoints (#5382) * api: Add an endpoint to list a particular member of team. * models: Rename `GetUserTeams()` to `GetUserOrgTeams()` in `org_team` model. `GetUserTeams()` sounds a bit misnomer since it actually returns the teams that user belongs to in a given organization rather than all the teams across all the organization that the user has joined. * models: Add `GetUserTeams()`. Returns all the teams that a user belongs to. * api: Add an endpoint for GET '/user/teams'. A GET request to this endpoint lists all the teams that a user belongs to. --- Gopkg.lock | 4 +- models/org.go | 2 +- models/org_team.go | 20 +++++-- models/org_team_test.go | 16 +++++- routers/api/v1/api.go | 3 + routers/api/v1/org/team.go | 65 ++++++++++++++++++++++ templates/swagger/v1_json.tmpl | 52 +++++++++++++++++ vendor/code.gitea.io/sdk/gitea/hook.go | 1 + vendor/code.gitea.io/sdk/gitea/org_team.go | 7 ++- vendor/code.gitea.io/sdk/gitea/release.go | 2 +- 10 files changed, 160 insertions(+), 12 deletions(-) diff --git a/Gopkg.lock b/Gopkg.lock index 88d3567b20..17e4397b15 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -11,11 +11,11 @@ [[projects]] branch = "master" - digest = "1:aed2bc1c4026233af8ad43cab9d9464a0e3b906d3d058d2d6e814f3e1ddfa528" + digest = "1:8a559f110defa54f847a3efa2734297571d960b476699579f2008e4a37b62a1a" name = "code.gitea.io/sdk" packages = ["gitea"] pruneopts = "NUT" - revision = "d95a6e0392218961d1bdd18020290a20bd61b063" + revision = "140e9fcba7583e1c6f22eb57676bb00794ef14a8" [[projects]] digest = "1:3fcef06a1a6561955c94af6c7757a6fa37605eb653f0d06ab960e5bb80092195" diff --git a/models/org.go b/models/org.go index a98a1bd894..3f17e3641f 100644 --- a/models/org.go +++ b/models/org.go @@ -522,7 +522,7 @@ func removeOrgUser(sess *xorm.Session, orgID, userID int64) error { } // Delete member in his/her teams. - teams, err := getUserTeams(sess, org.ID, userID) + teams, err := getUserOrgTeams(sess, org.ID, userID) if err != nil { return err } diff --git a/models/org_team.go b/models/org_team.go index 34e1b4db83..2ab807b49b 100644 --- a/models/org_team.go +++ b/models/org_team.go @@ -543,7 +543,14 @@ func GetTeamMembers(teamID int64) ([]*User, error) { return getTeamMembers(x, teamID) } -func getUserTeams(e Engine, orgID, userID int64) (teams []*Team, err error) { +func getUserTeams(e Engine, userID int64) (teams []*Team, err error) { + return teams, e. + Join("INNER", "team_user", "team_user.team_id = team.id"). + Where("team_user.uid=?", userID). + Find(&teams) +} + +func getUserOrgTeams(e Engine, orgID, userID int64) (teams []*Team, err error) { return teams, e. Join("INNER", "team_user", "team_user.team_id = team.id"). Where("team.org_id = ?", orgID). @@ -561,9 +568,14 @@ func getUserRepoTeams(e Engine, orgID, userID, repoID int64) (teams []*Team, err Find(&teams) } -// GetUserTeams returns all teams that user belongs to in given organization. -func GetUserTeams(orgID, userID int64) ([]*Team, error) { - return getUserTeams(x, orgID, userID) +// GetUserOrgTeams returns all teams that user belongs to in given organization. +func GetUserOrgTeams(orgID, userID int64) ([]*Team, error) { + return getUserOrgTeams(x, orgID, userID) +} + +// GetUserTeams returns all teams that user belongs across all organizations. +func GetUserTeams(userID int64) ([]*Team, error) { + return getUserTeams(x, userID) } // AddTeamMember adds new membership of given team to given organization, diff --git a/models/org_team_test.go b/models/org_team_test.go index 87bfbb4841..a81f9c0749 100644 --- a/models/org_team_test.go +++ b/models/org_team_test.go @@ -284,9 +284,23 @@ func TestGetTeamMembers(t *testing.T) { } func TestGetUserTeams(t *testing.T) { + assert.NoError(t, PrepareTestDatabase()) + test := func(userID int64) { + teams, err := GetUserTeams(userID) + assert.NoError(t, err) + for _, team := range teams { + AssertExistsAndLoadBean(t, &TeamUser{TeamID: team.ID, UID: userID}) + } + } + test(2) + test(5) + test(NonexistentID) +} + +func TestGetUserOrgTeams(t *testing.T) { assert.NoError(t, PrepareTestDatabase()) test := func(orgID, userID int64) { - teams, err := GetUserTeams(orgID, userID) + teams, err := GetUserOrgTeams(orgID, userID) assert.NoError(t, err) for _, team := range teams { assert.EqualValues(t, orgID, team.OrgID) diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go index dcc77969f1..82c4b78de8 100644 --- a/routers/api/v1/api.go +++ b/routers/api/v1/api.go @@ -463,6 +463,8 @@ func RegisterRoutes(m *macaron.Macaron) { m.Get("/times", repo.ListMyTrackedTimes) m.Get("/subscriptions", user.GetMyWatchedRepos) + + m.Get("/teams", org.ListUserTeams) }, reqToken()) // Repositories @@ -652,6 +654,7 @@ func RegisterRoutes(m *macaron.Macaron) { m.Group("/members", func() { m.Get("", org.GetTeamMembers) m.Combo("/:username"). + Get(org.GetTeamMember). Put(reqOrgOwnership(), org.AddTeamMember). Delete(reqOrgOwnership(), org.RemoveTeamMember) }) diff --git a/routers/api/v1/org/team.go b/routers/api/v1/org/team.go index a22d25eae3..a1916db00b 100644 --- a/routers/api/v1/org/team.go +++ b/routers/api/v1/org/team.go @@ -1,4 +1,5 @@ // Copyright 2016 The Gogs Authors. All rights reserved. +// Copyright 2019 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. @@ -42,6 +43,41 @@ func ListTeams(ctx *context.APIContext) { ctx.JSON(200, apiTeams) } +// ListUserTeams list all the teams a user belongs to +func ListUserTeams(ctx *context.APIContext) { + // swagger:operation GET /user/teams user userListTeams + // --- + // summary: List all the teams a user belongs to + // produces: + // - application/json + // responses: + // "200": + // "$ref": "#/responses/TeamList" + teams, err := models.GetUserTeams(ctx.User.ID) + if err != nil { + ctx.Error(500, "GetUserTeams", err) + return + } + + cache := make(map[int64]*api.Organization) + apiTeams := make([]*api.Team, len(teams)) + for i := range teams { + apiOrg, ok := cache[teams[i].OrgID] + if !ok { + org, err := models.GetUserByID(teams[i].OrgID) + if err != nil { + ctx.Error(500, "GetUserByID", err) + return + } + apiOrg = convert.ToOrganization(org) + cache[teams[i].OrgID] = apiOrg + } + apiTeams[i] = convert.ToTeam(teams[i]) + apiTeams[i].Organization = apiOrg + } + ctx.JSON(200, apiTeams) +} + // GetTeam api for get a team func GetTeam(ctx *context.APIContext) { // swagger:operation GET /teams/{id} organization orgGetTeam @@ -221,6 +257,35 @@ func GetTeamMembers(ctx *context.APIContext) { ctx.JSON(200, members) } +// GetTeamMember api for get a particular member of team +func GetTeamMember(ctx *context.APIContext) { + // swagger:operation GET /teams/{id}/members/{username} organization orgListTeamMember + // --- + // summary: List a particular member of team + // produces: + // - application/json + // parameters: + // - name: id + // in: path + // description: id of the team + // type: integer + // format: int64 + // required: true + // - name: username + // in: path + // description: username of the member to list + // type: string + // required: true + // responses: + // "200": + // "$ref": "#/responses/User" + u := user.GetUserByParams(ctx) + if ctx.Written() { + return + } + ctx.JSON(200, u.APIFormat()) +} + // AddTeamMember api for add a member to a team func AddTeamMember(ctx *context.APIContext) { // swagger:operation PUT /teams/{id}/members/{username} organization orgAddTeamMember diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl index 52633957c3..153701d6dd 100644 --- a/templates/swagger/v1_json.tmpl +++ b/templates/swagger/v1_json.tmpl @@ -4629,6 +4629,38 @@ } }, "/teams/{id}/members/{username}": { + "get": { + "produces": [ + "application/json" + ], + "tags": [ + "organization" + ], + "summary": "List a particular member of team", + "operationId": "orgListTeamMember", + "parameters": [ + { + "type": "integer", + "format": "int64", + "description": "id of the team", + "name": "id", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "username of the member to list", + "name": "username", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "$ref": "#/responses/User" + } + } + }, "put": { "produces": [ "application/json" @@ -5418,6 +5450,23 @@ } } }, + "/user/teams": { + "get": { + "produces": [ + "application/json" + ], + "tags": [ + "user" + ], + "summary": "List all the teams a user belongs to", + "operationId": "userListTeams", + "responses": { + "200": { + "$ref": "#/responses/TeamList" + } + } + } + }, "/user/times": { "get": { "produces": [ @@ -7942,6 +7991,9 @@ "type": "string", "x-go-name": "Name" }, + "organization": { + "$ref": "#/definitions/Organization" + }, "permission": { "type": "string", "enum": [ diff --git a/vendor/code.gitea.io/sdk/gitea/hook.go b/vendor/code.gitea.io/sdk/gitea/hook.go index 80a5192d8e..ee6e2b79d5 100644 --- a/vendor/code.gitea.io/sdk/gitea/hook.go +++ b/vendor/code.gitea.io/sdk/gitea/hook.go @@ -371,6 +371,7 @@ type PushPayload struct { After string `json:"after"` CompareURL string `json:"compare_url"` Commits []*PayloadCommit `json:"commits"` + HeadCommit *PayloadCommit `json:"head_commit"` Repo *Repository `json:"repository"` Pusher *User `json:"pusher"` Sender *User `json:"sender"` diff --git a/vendor/code.gitea.io/sdk/gitea/org_team.go b/vendor/code.gitea.io/sdk/gitea/org_team.go index f3e98b932e..9de0a8d000 100644 --- a/vendor/code.gitea.io/sdk/gitea/org_team.go +++ b/vendor/code.gitea.io/sdk/gitea/org_team.go @@ -7,9 +7,10 @@ package gitea // Team represents a team in an organization type Team struct { - ID int64 `json:"id"` - Name string `json:"name"` - Description string `json:"description"` + ID int64 `json:"id"` + Name string `json:"name"` + Description string `json:"description"` + Organization *Organization `json:"organization"` // enum: none,read,write,admin,owner Permission string `json:"permission"` // enum: repo.code,repo.issues,repo.ext_issues,repo.wiki,repo.pulls,repo.releases,repo.ext_wiki diff --git a/vendor/code.gitea.io/sdk/gitea/release.go b/vendor/code.gitea.io/sdk/gitea/release.go index 396251dcac..3605d2cd4a 100644 --- a/vendor/code.gitea.io/sdk/gitea/release.go +++ b/vendor/code.gitea.io/sdk/gitea/release.go @@ -53,7 +53,7 @@ func (c *Client) GetRelease(user, repo string, id int64) (*Release, error) { type CreateReleaseOption struct { // required: true TagName string `json:"tag_name" binding:"Required"` - Target string `json:"target_commitish"` + Target string `json:"target_commitish" binding:"Required"` Title string `json:"name"` Note string `json:"body"` IsDraft bool `json:"draft"`