Skip to content

Commit d8cd33e

Browse files
committed
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

Lines changed: 6 additions & 0 deletions
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

Lines changed: 229 additions & 0 deletions
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+
}

0 commit comments

Comments
 (0)