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.

498 lines
12 KiB

  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] = member.APIFormat()
  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. ctx.JSON(200, u.APIFormat())
  272. }
  273. // AddTeamMember api for add a member to a team
  274. func AddTeamMember(ctx *context.APIContext) {
  275. // swagger:operation PUT /teams/{id}/members/{username} organization orgAddTeamMember
  276. // ---
  277. // summary: Add a team member
  278. // produces:
  279. // - application/json
  280. // parameters:
  281. // - name: id
  282. // in: path
  283. // description: id of the team
  284. // type: integer
  285. // format: int64
  286. // required: true
  287. // - name: username
  288. // in: path
  289. // description: username of the user to add
  290. // type: string
  291. // required: true
  292. // responses:
  293. // "204":
  294. // "$ref": "#/responses/empty"
  295. u := user.GetUserByParams(ctx)
  296. if ctx.Written() {
  297. return
  298. }
  299. if err := ctx.Org.Team.AddMember(u.ID); err != nil {
  300. ctx.Error(500, "AddMember", err)
  301. return
  302. }
  303. ctx.Status(204)
  304. }
  305. // RemoveTeamMember api for remove one member from a team
  306. func RemoveTeamMember(ctx *context.APIContext) {
  307. // swagger:operation DELETE /teams/{id}/members/{username} organization orgRemoveTeamMember
  308. // ---
  309. // summary: Remove a team member
  310. // produces:
  311. // - application/json
  312. // parameters:
  313. // - name: id
  314. // in: path
  315. // description: id of the team
  316. // type: integer
  317. // format: int64
  318. // required: true
  319. // - name: username
  320. // in: path
  321. // description: username of the user to remove
  322. // type: string
  323. // required: true
  324. // responses:
  325. // "204":
  326. // "$ref": "#/responses/empty"
  327. u := user.GetUserByParams(ctx)
  328. if ctx.Written() {
  329. return
  330. }
  331. if err := ctx.Org.Team.RemoveMember(u.ID); err != nil {
  332. ctx.Error(500, "RemoveMember", err)
  333. return
  334. }
  335. ctx.Status(204)
  336. }
  337. // GetTeamRepos api for get a team's repos
  338. func GetTeamRepos(ctx *context.APIContext) {
  339. // swagger:operation GET /teams/{id}/repos organization orgListTeamRepos
  340. // ---
  341. // summary: List a team's repos
  342. // produces:
  343. // - application/json
  344. // parameters:
  345. // - name: id
  346. // in: path
  347. // description: id of the team
  348. // type: integer
  349. // format: int64
  350. // required: true
  351. // responses:
  352. // "200":
  353. // "$ref": "#/responses/RepositoryList"
  354. team := ctx.Org.Team
  355. if err := team.GetRepositories(); err != nil {
  356. ctx.Error(500, "GetTeamRepos", err)
  357. }
  358. repos := make([]*api.Repository, len(team.Repos))
  359. for i, repo := range team.Repos {
  360. access, err := models.AccessLevel(ctx.User, repo)
  361. if err != nil {
  362. ctx.Error(500, "GetTeamRepos", err)
  363. return
  364. }
  365. repos[i] = repo.APIFormat(access)
  366. }
  367. ctx.JSON(200, repos)
  368. }
  369. // getRepositoryByParams get repository by a team's organization ID and repo name
  370. func getRepositoryByParams(ctx *context.APIContext) *models.Repository {
  371. repo, err := models.GetRepositoryByName(ctx.Org.Team.OrgID, ctx.Params(":reponame"))
  372. if err != nil {
  373. if models.IsErrRepoNotExist(err) {
  374. ctx.NotFound()
  375. } else {
  376. ctx.Error(500, "GetRepositoryByName", err)
  377. }
  378. return nil
  379. }
  380. return repo
  381. }
  382. // AddTeamRepository api for adding a repository to a team
  383. func AddTeamRepository(ctx *context.APIContext) {
  384. // swagger:operation PUT /teams/{id}/repos/{org}/{repo} organization orgAddTeamRepository
  385. // ---
  386. // summary: Add a repository to a team
  387. // produces:
  388. // - application/json
  389. // parameters:
  390. // - name: id
  391. // in: path
  392. // description: id of the team
  393. // type: integer
  394. // format: int64
  395. // required: true
  396. // - name: org
  397. // in: path
  398. // description: organization that owns the repo to add
  399. // type: string
  400. // required: true
  401. // - name: repo
  402. // in: path
  403. // description: name of the repo to add
  404. // type: string
  405. // required: true
  406. // responses:
  407. // "204":
  408. // "$ref": "#/responses/empty"
  409. repo := getRepositoryByParams(ctx)
  410. if ctx.Written() {
  411. return
  412. }
  413. if access, err := models.AccessLevel(ctx.User, repo); err != nil {
  414. ctx.Error(500, "AccessLevel", err)
  415. return
  416. } else if access < models.AccessModeAdmin {
  417. ctx.Error(403, "", "Must have admin-level access to the repository")
  418. return
  419. }
  420. if err := ctx.Org.Team.AddRepository(repo); err != nil {
  421. ctx.Error(500, "AddRepository", err)
  422. return
  423. }
  424. ctx.Status(204)
  425. }
  426. // RemoveTeamRepository api for removing a repository from a team
  427. func RemoveTeamRepository(ctx *context.APIContext) {
  428. // swagger:operation DELETE /teams/{id}/repos/{org}/{repo} organization orgRemoveTeamRepository
  429. // ---
  430. // summary: Remove a repository from a team
  431. // description: This does not delete the repository, it only removes the
  432. // repository from the team.
  433. // produces:
  434. // - application/json
  435. // parameters:
  436. // - name: id
  437. // in: path
  438. // description: id of the team
  439. // type: integer
  440. // format: int64
  441. // required: true
  442. // - name: org
  443. // in: path
  444. // description: organization that owns the repo to remove
  445. // type: string
  446. // required: true
  447. // - name: repo
  448. // in: path
  449. // description: name of the repo to remove
  450. // type: string
  451. // required: true
  452. // responses:
  453. // "204":
  454. // "$ref": "#/responses/empty"
  455. repo := getRepositoryByParams(ctx)
  456. if ctx.Written() {
  457. return
  458. }
  459. if access, err := models.AccessLevel(ctx.User, repo); err != nil {
  460. ctx.Error(500, "AccessLevel", err)
  461. return
  462. } else if access < models.AccessModeAdmin {
  463. ctx.Error(403, "", "Must have admin-level access to the repository")
  464. return
  465. }
  466. if err := ctx.Org.Team.RemoveRepository(repo.ID); err != nil {
  467. ctx.Error(500, "RemoveRepository", err)
  468. return
  469. }
  470. ctx.Status(204)
  471. }