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

team.go 13KB

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