Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit d8cd33e

Browse files
committedNov 29, 2020
List, Check, Add & delete endpoints for repository teams
1 parent e00a355 commit d8cd33e

File tree

3 files changed

+402
-0
lines changed

3 files changed

+402
-0
lines changed
 

‎routers/api/v1/api.go

+6
Original file line numberDiff line numberDiff line change
@@ -669,6 +669,12 @@ func RegisterRoutes(m *macaron.Macaron) {
669669
Put(reqAdmin(), bind(api.AddCollaboratorOption{}), repo.AddCollaborator).
670670
Delete(reqAdmin(), repo.DeleteCollaborator)
671671
}, reqToken())
672+
m.Group("/teams", func() {
673+
m.Get("", reqAnyRepoReader(), repo.ListTeams)
674+
m.Combo("/:team").Get(reqAnyRepoReader(), repo.IsTeam).
675+
Put(reqAdmin(), repo.AddTeam).
676+
Delete(reqAdmin(), repo.DeleteTeam)
677+
}, reqToken())
672678
m.Get("/raw/*", context.RepoRefForAPI(), reqRepoReader(models.UnitTypeCode), repo.GetRawFile)
673679
m.Get("/archive/*", reqRepoReader(models.UnitTypeCode), repo.GetArchive)
674680
m.Combo("/forks").Get(repo.ListForks).

‎routers/api/v1/repo/teams.go

+229
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,229 @@
1+
// Copyright 2020 The Gitea Authors. All rights reserved.
2+
// Use of this source code is governed by a MIT-style
3+
// license that can be found in the LICENSE file.
4+
5+
package repo
6+
7+
import (
8+
"fmt"
9+
"net/http"
10+
11+
"code.gitea.io/gitea/models"
12+
"code.gitea.io/gitea/modules/context"
13+
"code.gitea.io/gitea/modules/convert"
14+
api "code.gitea.io/gitea/modules/structs"
15+
)
16+
17+
// ListTeams list a repository's teams
18+
func ListTeams(ctx *context.APIContext) {
19+
// swagger:operation GET /repos/{owner}/{repo}/teams repository repoListTeams
20+
// ---
21+
// summary: List a repository's teams
22+
// produces:
23+
// - application/json
24+
// parameters:
25+
// - name: owner
26+
// in: path
27+
// description: owner of the repo
28+
// type: string
29+
// required: true
30+
// - name: repo
31+
// in: path
32+
// description: name of the repo
33+
// type: string
34+
// required: true
35+
// responses:
36+
// "200":
37+
// "$ref": "#/responses/TeamList"
38+
39+
if !ctx.Repo.Owner.IsOrganization() {
40+
ctx.Error(http.StatusMethodNotAllowed, "noOrg", "repo is not owned by an organization")
41+
return
42+
}
43+
44+
teams, err := ctx.Repo.Repository.GetRepoTeams()
45+
if err != nil {
46+
ctx.InternalServerError(err)
47+
return
48+
}
49+
50+
apiTeams := make([]*api.Team, len(teams))
51+
for i := range teams {
52+
if err := teams[i].GetUnits(); err != nil {
53+
ctx.Error(http.StatusInternalServerError, "GetUnits", err)
54+
return
55+
}
56+
57+
apiTeams[i] = convert.ToTeam(teams[i])
58+
}
59+
60+
ctx.JSON(http.StatusOK, apiTeams)
61+
}
62+
63+
// IsTeam check if a team is assigned to a repository
64+
func IsTeam(ctx *context.APIContext) {
65+
// swagger:operation GET /repos/{owner}/{repo}/teams/{team} repository repoCheckTeam
66+
// ---
67+
// summary: Check if a team is assigned to a repository
68+
// produces:
69+
// - application/json
70+
// parameters:
71+
// - name: owner
72+
// in: path
73+
// description: owner of the repo
74+
// type: string
75+
// required: true
76+
// - name: repo
77+
// in: path
78+
// description: name of the repo
79+
// type: string
80+
// required: true
81+
// - name: team
82+
// in: path
83+
// description: team name
84+
// type: string
85+
// required: true
86+
// responses:
87+
// "200":
88+
// "$ref": "#/responses/Team"
89+
// "404":
90+
// "$ref": "#/responses/notFound"
91+
// "405":
92+
// "$ref": "#/responses/error"
93+
94+
if !ctx.Repo.Owner.IsOrganization() {
95+
ctx.Error(http.StatusMethodNotAllowed, "noOrg", "repo is not owned by an organization")
96+
return
97+
}
98+
99+
team := getTeamByParam(ctx)
100+
if team == nil {
101+
return
102+
}
103+
104+
if team.HasRepository(ctx.Repo.Repository.ID) {
105+
apiTeam := convert.ToTeam(team)
106+
ctx.JSON(http.StatusOK, apiTeam)
107+
return
108+
}
109+
110+
ctx.NotFound()
111+
}
112+
113+
// AddTeam add a team to a repository
114+
func AddTeam(ctx *context.APIContext) {
115+
// swagger:operation PUT /repos/{owner}/{repo}/teams/{team} repository repoAddTeam
116+
// ---
117+
// summary: Add a team to a repository
118+
// produces:
119+
// - application/json
120+
// parameters:
121+
// - name: owner
122+
// in: path
123+
// description: owner of the repo
124+
// type: string
125+
// required: true
126+
// - name: repo
127+
// in: path
128+
// description: name of the repo
129+
// type: string
130+
// required: true
131+
// - name: team
132+
// in: path
133+
// description: team name
134+
// type: string
135+
// required: true
136+
// responses:
137+
// "204":
138+
// "$ref": "#/responses/empty"
139+
// "422":
140+
// "$ref": "#/responses/validationError"
141+
// "405":
142+
// "$ref": "#/responses/error"
143+
144+
changeRepoTeam(ctx, true)
145+
}
146+
147+
// DeleteTeam delete a team from a repository
148+
func DeleteTeam(ctx *context.APIContext) {
149+
// swagger:operation DELETE /repos/{owner}/{repo}/teams/{team} repository repoDeleteTeam
150+
// ---
151+
// summary: Delete a team from a repository
152+
// produces:
153+
// - application/json
154+
// parameters:
155+
// - name: owner
156+
// in: path
157+
// description: owner of the repo
158+
// type: string
159+
// required: true
160+
// - name: repo
161+
// in: path
162+
// description: name of the repo
163+
// type: string
164+
// required: true
165+
// - name: team
166+
// in: path
167+
// description: team name
168+
// type: string
169+
// required: true
170+
// responses:
171+
// "204":
172+
// "$ref": "#/responses/empty"
173+
// "422":
174+
// "$ref": "#/responses/validationError"
175+
// "405":
176+
// "$ref": "#/responses/error"
177+
178+
changeRepoTeam(ctx, false)
179+
}
180+
181+
func changeRepoTeam(ctx *context.APIContext, add bool) {
182+
if !ctx.Repo.Owner.IsOrganization() {
183+
ctx.Error(http.StatusMethodNotAllowed, "noOrg", "repo is not owned by an organization")
184+
}
185+
if !ctx.Repo.Owner.RepoAdminChangeTeamAccess && !ctx.Repo.IsOwner() {
186+
ctx.Error(http.StatusForbidden, "noAdmin", "user is nor repo admin nor owner")
187+
return
188+
}
189+
190+
team := getTeamByParam(ctx)
191+
if team == nil {
192+
return
193+
}
194+
195+
repoHasTeam := team.HasRepository(ctx.Repo.Repository.ID)
196+
var err error
197+
if add {
198+
if repoHasTeam {
199+
ctx.Error(http.StatusUnprocessableEntity, "alreadyAdded", fmt.Errorf("team '%s' is already added to repo", team.Name))
200+
return
201+
}
202+
err = team.AddRepository(ctx.Repo.Repository)
203+
} else {
204+
if !repoHasTeam {
205+
ctx.Error(http.StatusUnprocessableEntity, "notAdded", fmt.Errorf("team '%s' was not added to repo", team.Name))
206+
return
207+
}
208+
err = team.RemoveRepository(ctx.Repo.Repository.ID)
209+
}
210+
if err != nil {
211+
ctx.InternalServerError(err)
212+
return
213+
}
214+
215+
ctx.Status(http.StatusNoContent)
216+
}
217+
218+
func getTeamByParam(ctx *context.APIContext) *models.Team {
219+
team, err := models.GetTeam(ctx.Repo.Owner.ID, ctx.Params(":team"))
220+
if err != nil {
221+
if models.IsErrTeamNotExist(err) {
222+
ctx.Error(http.StatusNotFound, "TeamNotExit", err)
223+
return nil
224+
}
225+
ctx.InternalServerError(err)
226+
return nil
227+
}
228+
return team
229+
}

‎templates/swagger/v1_json.tmpl

+167
Original file line numberDiff line numberDiff line change
@@ -8697,6 +8697,173 @@
86978697
}
86988698
}
86998699
},
8700+
"/repos/{owner}/{repo}/teams": {
8701+
"get": {
8702+
"produces": [
8703+
"application/json"
8704+
],
8705+
"tags": [
8706+
"repository"
8707+
],
8708+
"summary": "List a repository's teams",
8709+
"operationId": "repoListTeams",
8710+
"parameters": [
8711+
{
8712+
"type": "string",
8713+
"description": "owner of the repo",
8714+
"name": "owner",
8715+
"in": "path",
8716+
"required": true
8717+
},
8718+
{
8719+
"type": "string",
8720+
"description": "name of the repo",
8721+
"name": "repo",
8722+
"in": "path",
8723+
"required": true
8724+
}
8725+
],
8726+
"responses": {
8727+
"200": {
8728+
"$ref": "#/responses/TeamList"
8729+
}
8730+
}
8731+
}
8732+
},
8733+
"/repos/{owner}/{repo}/teams/{team}": {
8734+
"get": {
8735+
"produces": [
8736+
"application/json"
8737+
],
8738+
"tags": [
8739+
"repository"
8740+
],
8741+
"summary": "Check if a team is assigned to a repository",
8742+
"operationId": "repoCheckTeam",
8743+
"parameters": [
8744+
{
8745+
"type": "string",
8746+
"description": "owner of the repo",
8747+
"name": "owner",
8748+
"in": "path",
8749+
"required": true
8750+
},
8751+
{
8752+
"type": "string",
8753+
"description": "name of the repo",
8754+
"name": "repo",
8755+
"in": "path",
8756+
"required": true
8757+
},
8758+
{
8759+
"type": "string",
8760+
"description": "team name",
8761+
"name": "team",
8762+
"in": "path",
8763+
"required": true
8764+
}
8765+
],
8766+
"responses": {
8767+
"200": {
8768+
"$ref": "#/responses/Team"
8769+
},
8770+
"404": {
8771+
"$ref": "#/responses/notFound"
8772+
},
8773+
"405": {
8774+
"$ref": "#/responses/error"
8775+
}
8776+
}
8777+
},
8778+
"put": {
8779+
"produces": [
8780+
"application/json"
8781+
],
8782+
"tags": [
8783+
"repository"
8784+
],
8785+
"summary": "Add a team to a repository",
8786+
"operationId": "repoAddTeam",
8787+
"parameters": [
8788+
{
8789+
"type": "string",
8790+
"description": "owner of the repo",
8791+
"name": "owner",
8792+
"in": "path",
8793+
"required": true
8794+
},
8795+
{
8796+
"type": "string",
8797+
"description": "name of the repo",
8798+
"name": "repo",
8799+
"in": "path",
8800+
"required": true
8801+
},
8802+
{
8803+
"type": "string",
8804+
"description": "team name",
8805+
"name": "team",
8806+
"in": "path",
8807+
"required": true
8808+
}
8809+
],
8810+
"responses": {
8811+
"204": {
8812+
"$ref": "#/responses/empty"
8813+
},
8814+
"405": {
8815+
"$ref": "#/responses/error"
8816+
},
8817+
"422": {
8818+
"$ref": "#/responses/validationError"
8819+
}
8820+
}
8821+
},
8822+
"delete": {
8823+
"produces": [
8824+
"application/json"
8825+
],
8826+
"tags": [
8827+
"repository"
8828+
],
8829+
"summary": "Delete a team from a repository",
8830+
"operationId": "repoDeleteTeam",
8831+
"parameters": [
8832+
{
8833+
"type": "string",
8834+
"description": "owner of the repo",
8835+
"name": "owner",
8836+
"in": "path",
8837+
"required": true
8838+
},
8839+
{
8840+
"type": "string",
8841+
"description": "name of the repo",
8842+
"name": "repo",
8843+
"in": "path",
8844+
"required": true
8845+
},
8846+
{
8847+
"type": "string",
8848+
"description": "team name",
8849+
"name": "team",
8850+
"in": "path",
8851+
"required": true
8852+
}
8853+
],
8854+
"responses": {
8855+
"204": {
8856+
"$ref": "#/responses/empty"
8857+
},
8858+
"405": {
8859+
"$ref": "#/responses/error"
8860+
},
8861+
"422": {
8862+
"$ref": "#/responses/validationError"
8863+
}
8864+
}
8865+
}
8866+
},
87008867
"/repos/{owner}/{repo}/times": {
87018868
"get": {
87028869
"produces": [

0 commit comments

Comments
 (0)
Please sign in to comment.