You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

team.go 12 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493
  1. // Copyright 2016 The Gogs Authors. All rights reserved.
  2. // Copyright 2019 The Gitea Authors. All rights reserved.
  3. // Use of this source code is governed by a MIT-style
  4. // license that can be found in the LICENSE file.
  5. package org
  6. import (
  7. api "code.gitea.io/sdk/gitea"
  8. "code.gitea.io/gitea/models"
  9. "code.gitea.io/gitea/modules/context"
  10. "code.gitea.io/gitea/routers/api/v1/convert"
  11. "code.gitea.io/gitea/routers/api/v1/user"
  12. )
  13. // ListTeams list all the teams of an organization
  14. func ListTeams(ctx *context.APIContext) {
  15. // swagger:operation GET /orgs/{org}/teams organization orgListTeams
  16. // ---
  17. // summary: List an organization's teams
  18. // produces:
  19. // - application/json
  20. // parameters:
  21. // - name: org
  22. // in: path
  23. // description: name of the organization
  24. // type: string
  25. // required: true
  26. // responses:
  27. // "200":
  28. // "$ref": "#/responses/TeamList"
  29. org := ctx.Org.Organization
  30. if err := org.GetTeams(); err != nil {
  31. ctx.Error(500, "GetTeams", err)
  32. return
  33. }
  34. apiTeams := make([]*api.Team, len(org.Teams))
  35. for i := range org.Teams {
  36. apiTeams[i] = convert.ToTeam(org.Teams[i])
  37. }
  38. ctx.JSON(200, apiTeams)
  39. }
  40. // ListUserTeams list all the teams a user belongs to
  41. func ListUserTeams(ctx *context.APIContext) {
  42. // swagger:operation GET /user/teams user userListTeams
  43. // ---
  44. // summary: List all the teams a user belongs to
  45. // produces:
  46. // - application/json
  47. // responses:
  48. // "200":
  49. // "$ref": "#/responses/TeamList"
  50. teams, err := models.GetUserTeams(ctx.User.ID)
  51. if err != nil {
  52. ctx.Error(500, "GetUserTeams", err)
  53. return
  54. }
  55. cache := make(map[int64]*api.Organization)
  56. apiTeams := make([]*api.Team, len(teams))
  57. for i := range teams {
  58. apiOrg, ok := cache[teams[i].OrgID]
  59. if !ok {
  60. org, err := models.GetUserByID(teams[i].OrgID)
  61. if err != nil {
  62. ctx.Error(500, "GetUserByID", err)
  63. return
  64. }
  65. apiOrg = convert.ToOrganization(org)
  66. cache[teams[i].OrgID] = apiOrg
  67. }
  68. apiTeams[i] = convert.ToTeam(teams[i])
  69. apiTeams[i].Organization = apiOrg
  70. }
  71. ctx.JSON(200, apiTeams)
  72. }
  73. // GetTeam api for get a team
  74. func GetTeam(ctx *context.APIContext) {
  75. // swagger:operation GET /teams/{id} organization orgGetTeam
  76. // ---
  77. // summary: Get a team
  78. // produces:
  79. // - application/json
  80. // parameters:
  81. // - name: id
  82. // in: path
  83. // description: id of the team to get
  84. // type: integer
  85. // format: int64
  86. // required: true
  87. // responses:
  88. // "200":
  89. // "$ref": "#/responses/Team"
  90. ctx.JSON(200, convert.ToTeam(ctx.Org.Team))
  91. }
  92. // CreateTeam api for create a team
  93. func CreateTeam(ctx *context.APIContext, form api.CreateTeamOption) {
  94. // swagger:operation POST /orgs/{org}/teams organization orgCreateTeam
  95. // ---
  96. // summary: Create a team
  97. // consumes:
  98. // - application/json
  99. // produces:
  100. // - application/json
  101. // parameters:
  102. // - name: org
  103. // in: path
  104. // description: name of the organization
  105. // type: string
  106. // required: true
  107. // - name: body
  108. // in: body
  109. // schema:
  110. // "$ref": "#/definitions/CreateTeamOption"
  111. // responses:
  112. // "201":
  113. // "$ref": "#/responses/Team"
  114. team := &models.Team{
  115. OrgID: ctx.Org.Organization.ID,
  116. Name: form.Name,
  117. Description: form.Description,
  118. Authorize: models.ParseAccessMode(form.Permission),
  119. }
  120. unitTypes := models.FindUnitTypes(form.Units...)
  121. if team.Authorize < models.AccessModeOwner {
  122. var units = make([]*models.TeamUnit, 0, len(form.Units))
  123. for _, tp := range unitTypes {
  124. units = append(units, &models.TeamUnit{
  125. OrgID: ctx.Org.Organization.ID,
  126. Type: tp,
  127. })
  128. }
  129. team.Units = units
  130. }
  131. if err := models.NewTeam(team); err != nil {
  132. if models.IsErrTeamAlreadyExist(err) {
  133. ctx.Error(422, "", err)
  134. } else {
  135. ctx.Error(500, "NewTeam", err)
  136. }
  137. return
  138. }
  139. ctx.JSON(201, convert.ToTeam(team))
  140. }
  141. // EditTeam api for edit a team
  142. func EditTeam(ctx *context.APIContext, form api.EditTeamOption) {
  143. // swagger:operation PATCH /teams/{id} organization orgEditTeam
  144. // ---
  145. // summary: Edit a team
  146. // consumes:
  147. // - application/json
  148. // produces:
  149. // - application/json
  150. // parameters:
  151. // - name: id
  152. // in: path
  153. // description: id of the team to edit
  154. // type: integer
  155. // required: true
  156. // - name: body
  157. // in: body
  158. // schema:
  159. // "$ref": "#/definitions/EditTeamOption"
  160. // responses:
  161. // "200":
  162. // "$ref": "#/responses/Team"
  163. team := ctx.Org.Team
  164. team.Name = form.Name
  165. team.Description = form.Description
  166. team.Authorize = models.ParseAccessMode(form.Permission)
  167. unitTypes := models.FindUnitTypes(form.Units...)
  168. if team.Authorize < models.AccessModeOwner {
  169. var units = make([]*models.TeamUnit, 0, len(form.Units))
  170. for _, tp := range unitTypes {
  171. units = append(units, &models.TeamUnit{
  172. OrgID: ctx.Org.Organization.ID,
  173. Type: tp,
  174. })
  175. }
  176. team.Units = units
  177. }
  178. if err := models.UpdateTeam(team, true); err != nil {
  179. ctx.Error(500, "EditTeam", err)
  180. return
  181. }
  182. ctx.JSON(200, convert.ToTeam(team))
  183. }
  184. // DeleteTeam api for delete a team
  185. func DeleteTeam(ctx *context.APIContext) {
  186. // swagger:operation DELETE /teams/{id} organization orgDeleteTeam
  187. // ---
  188. // summary: Delete a team
  189. // parameters:
  190. // - name: id
  191. // in: path
  192. // description: id of the team to delete
  193. // type: integer
  194. // format: int64
  195. // required: true
  196. // responses:
  197. // "204":
  198. // description: team deleted
  199. if err := models.DeleteTeam(ctx.Org.Team); err != nil {
  200. ctx.Error(500, "DeleteTeam", err)
  201. return
  202. }
  203. ctx.Status(204)
  204. }
  205. // GetTeamMembers api for get a team's members
  206. func GetTeamMembers(ctx *context.APIContext) {
  207. // swagger:operation GET /teams/{id}/members organization orgListTeamMembers
  208. // ---
  209. // summary: List a team's members
  210. // produces:
  211. // - application/json
  212. // parameters:
  213. // - name: id
  214. // in: path
  215. // description: id of the team
  216. // type: integer
  217. // format: int64
  218. // required: true
  219. // responses:
  220. // "200":
  221. // "$ref": "#/responses/UserList"
  222. isMember, err := models.IsOrganizationMember(ctx.Org.Team.OrgID, ctx.User.ID)
  223. if err != nil {
  224. ctx.Error(500, "IsOrganizationMember", err)
  225. return
  226. } else if !isMember {
  227. ctx.Status(404)
  228. return
  229. }
  230. team := ctx.Org.Team
  231. if err := team.GetMembers(); err != nil {
  232. ctx.Error(500, "GetTeamMembers", err)
  233. return
  234. }
  235. members := make([]*api.User, len(team.Members))
  236. for i, member := range team.Members {
  237. members[i] = member.APIFormat()
  238. }
  239. ctx.JSON(200, members)
  240. }
  241. // GetTeamMember api for get a particular member of team
  242. func GetTeamMember(ctx *context.APIContext) {
  243. // swagger:operation GET /teams/{id}/members/{username} organization orgListTeamMember
  244. // ---
  245. // summary: List a particular member of team
  246. // produces:
  247. // - application/json
  248. // parameters:
  249. // - name: id
  250. // in: path
  251. // description: id of the team
  252. // type: integer
  253. // format: int64
  254. // required: true
  255. // - name: username
  256. // in: path
  257. // description: username of the member to list
  258. // type: string
  259. // required: true
  260. // responses:
  261. // "200":
  262. // "$ref": "#/responses/User"
  263. u := user.GetUserByParams(ctx)
  264. if ctx.Written() {
  265. return
  266. }
  267. ctx.JSON(200, u.APIFormat())
  268. }
  269. // AddTeamMember api for add a member to a team
  270. func AddTeamMember(ctx *context.APIContext) {
  271. // swagger:operation PUT /teams/{id}/members/{username} organization orgAddTeamMember
  272. // ---
  273. // summary: Add a team member
  274. // produces:
  275. // - application/json
  276. // parameters:
  277. // - name: id
  278. // in: path
  279. // description: id of the team
  280. // type: integer
  281. // format: int64
  282. // required: true
  283. // - name: username
  284. // in: path
  285. // description: username of the user to add
  286. // type: string
  287. // required: true
  288. // responses:
  289. // "204":
  290. // "$ref": "#/responses/empty"
  291. u := user.GetUserByParams(ctx)
  292. if ctx.Written() {
  293. return
  294. }
  295. if err := ctx.Org.Team.AddMember(u.ID); err != nil {
  296. ctx.Error(500, "AddMember", err)
  297. return
  298. }
  299. ctx.Status(204)
  300. }
  301. // RemoveTeamMember api for remove one member from a team
  302. func RemoveTeamMember(ctx *context.APIContext) {
  303. // swagger:operation DELETE /teams/{id}/members/{username} organization orgRemoveTeamMember
  304. // ---
  305. // summary: Remove a team member
  306. // produces:
  307. // - application/json
  308. // parameters:
  309. // - name: id
  310. // in: path
  311. // description: id of the team
  312. // type: integer
  313. // format: int64
  314. // required: true
  315. // - name: username
  316. // in: path
  317. // description: username of the user to remove
  318. // type: string
  319. // required: true
  320. // responses:
  321. // "204":
  322. // "$ref": "#/responses/empty"
  323. u := user.GetUserByParams(ctx)
  324. if ctx.Written() {
  325. return
  326. }
  327. if err := ctx.Org.Team.RemoveMember(u.ID); err != nil {
  328. ctx.Error(500, "RemoveMember", err)
  329. return
  330. }
  331. ctx.Status(204)
  332. }
  333. // GetTeamRepos api for get a team's repos
  334. func GetTeamRepos(ctx *context.APIContext) {
  335. // swagger:operation GET /teams/{id}/repos organization orgListTeamRepos
  336. // ---
  337. // summary: List a team's repos
  338. // produces:
  339. // - application/json
  340. // parameters:
  341. // - name: id
  342. // in: path
  343. // description: id of the team
  344. // type: integer
  345. // format: int64
  346. // required: true
  347. // responses:
  348. // "200":
  349. // "$ref": "#/responses/RepositoryList"
  350. team := ctx.Org.Team
  351. if err := team.GetRepositories(); err != nil {
  352. ctx.Error(500, "GetTeamRepos", err)
  353. }
  354. repos := make([]*api.Repository, len(team.Repos))
  355. for i, repo := range team.Repos {
  356. access, err := models.AccessLevel(ctx.User, repo)
  357. if err != nil {
  358. ctx.Error(500, "GetTeamRepos", err)
  359. return
  360. }
  361. repos[i] = repo.APIFormat(access)
  362. }
  363. ctx.JSON(200, repos)
  364. }
  365. // getRepositoryByParams get repository by a team's organization ID and repo name
  366. func getRepositoryByParams(ctx *context.APIContext) *models.Repository {
  367. repo, err := models.GetRepositoryByName(ctx.Org.Team.OrgID, ctx.Params(":reponame"))
  368. if err != nil {
  369. if models.IsErrRepoNotExist(err) {
  370. ctx.Status(404)
  371. } else {
  372. ctx.Error(500, "GetRepositoryByName", err)
  373. }
  374. return nil
  375. }
  376. return repo
  377. }
  378. // AddTeamRepository api for adding a repository to a team
  379. func AddTeamRepository(ctx *context.APIContext) {
  380. // swagger:operation PUT /teams/{id}/repos/{org}/{repo} organization orgAddTeamRepository
  381. // ---
  382. // summary: Add a repository to a team
  383. // produces:
  384. // - application/json
  385. // parameters:
  386. // - name: id
  387. // in: path
  388. // description: id of the team
  389. // type: integer
  390. // format: int64
  391. // required: true
  392. // - name: org
  393. // in: path
  394. // description: organization that owns the repo to add
  395. // type: string
  396. // required: true
  397. // - name: repo
  398. // in: path
  399. // description: name of the repo to add
  400. // type: string
  401. // required: true
  402. // responses:
  403. // "204":
  404. // "$ref": "#/responses/empty"
  405. repo := getRepositoryByParams(ctx)
  406. if ctx.Written() {
  407. return
  408. }
  409. if access, err := models.AccessLevel(ctx.User, repo); err != nil {
  410. ctx.Error(500, "AccessLevel", err)
  411. return
  412. } else if access < models.AccessModeAdmin {
  413. ctx.Error(403, "", "Must have admin-level access to the repository")
  414. return
  415. }
  416. if err := ctx.Org.Team.AddRepository(repo); err != nil {
  417. ctx.Error(500, "AddRepository", err)
  418. return
  419. }
  420. ctx.Status(204)
  421. }
  422. // RemoveTeamRepository api for removing a repository from a team
  423. func RemoveTeamRepository(ctx *context.APIContext) {
  424. // swagger:operation DELETE /teams/{id}/repos/{org}/{repo} organization orgRemoveTeamRepository
  425. // ---
  426. // summary: Remove a repository from a team
  427. // description: This does not delete the repository, it only removes the
  428. // repository from the team.
  429. // produces:
  430. // - application/json
  431. // parameters:
  432. // - name: id
  433. // in: path
  434. // description: id of the team
  435. // type: integer
  436. // format: int64
  437. // required: true
  438. // - name: org
  439. // in: path
  440. // description: organization that owns the repo to remove
  441. // type: string
  442. // required: true
  443. // - name: repo
  444. // in: path
  445. // description: name of the repo to remove
  446. // type: string
  447. // required: true
  448. // responses:
  449. // "204":
  450. // "$ref": "#/responses/empty"
  451. repo := getRepositoryByParams(ctx)
  452. if ctx.Written() {
  453. return
  454. }
  455. if access, err := models.AccessLevel(ctx.User, repo); err != nil {
  456. ctx.Error(500, "AccessLevel", err)
  457. return
  458. } else if access < models.AccessModeAdmin {
  459. ctx.Error(403, "", "Must have admin-level access to the repository")
  460. return
  461. }
  462. if err := ctx.Org.Team.RemoveRepository(repo.ID); err != nil {
  463. ctx.Error(500, "RemoveRepository", err)
  464. return
  465. }
  466. ctx.Status(204)
  467. }