本站源代码
Nie możesz wybrać więcej, niż 25 tematów Tematy muszą się zaczynać od litery lub cyfry, mogą zawierać myślniki ('-') i mogą mieć do 35 znaków.

590 lines
15KB

  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. "strings"
  8. "code.gitea.io/gitea/models"
  9. "code.gitea.io/gitea/modules/context"
  10. "code.gitea.io/gitea/modules/log"
  11. api "code.gitea.io/gitea/modules/structs"
  12. "code.gitea.io/gitea/routers/api/v1/convert"
  13. "code.gitea.io/gitea/routers/api/v1/user"
  14. )
  15. // ListTeams list all the teams of an organization
  16. func ListTeams(ctx *context.APIContext) {
  17. // swagger:operation GET /orgs/{org}/teams organization orgListTeams
  18. // ---
  19. // summary: List an organization's teams
  20. // produces:
  21. // - application/json
  22. // parameters:
  23. // - name: org
  24. // in: path
  25. // description: name of the organization
  26. // type: string
  27. // required: true
  28. // responses:
  29. // "200":
  30. // "$ref": "#/responses/TeamList"
  31. org := ctx.Org.Organization
  32. if err := org.GetTeams(); err != nil {
  33. ctx.Error(500, "GetTeams", err)
  34. return
  35. }
  36. apiTeams := make([]*api.Team, len(org.Teams))
  37. for i := range org.Teams {
  38. if err := org.Teams[i].GetUnits(); err != nil {
  39. ctx.Error(500, "GetUnits", err)
  40. return
  41. }
  42. apiTeams[i] = convert.ToTeam(org.Teams[i])
  43. }
  44. ctx.JSON(200, apiTeams)
  45. }
  46. // ListUserTeams list all the teams a user belongs to
  47. func ListUserTeams(ctx *context.APIContext) {
  48. // swagger:operation GET /user/teams user userListTeams
  49. // ---
  50. // summary: List all the teams a user belongs to
  51. // produces:
  52. // - application/json
  53. // responses:
  54. // "200":
  55. // "$ref": "#/responses/TeamList"
  56. teams, err := models.GetUserTeams(ctx.User.ID)
  57. if err != nil {
  58. ctx.Error(500, "GetUserTeams", err)
  59. return
  60. }
  61. cache := make(map[int64]*api.Organization)
  62. apiTeams := make([]*api.Team, len(teams))
  63. for i := range teams {
  64. apiOrg, ok := cache[teams[i].OrgID]
  65. if !ok {
  66. org, err := models.GetUserByID(teams[i].OrgID)
  67. if err != nil {
  68. ctx.Error(500, "GetUserByID", err)
  69. return
  70. }
  71. apiOrg = convert.ToOrganization(org)
  72. cache[teams[i].OrgID] = apiOrg
  73. }
  74. apiTeams[i] = convert.ToTeam(teams[i])
  75. apiTeams[i].Organization = apiOrg
  76. }
  77. ctx.JSON(200, apiTeams)
  78. }
  79. // GetTeam api for get a team
  80. func GetTeam(ctx *context.APIContext) {
  81. // swagger:operation GET /teams/{id} organization orgGetTeam
  82. // ---
  83. // summary: Get a team
  84. // produces:
  85. // - application/json
  86. // parameters:
  87. // - name: id
  88. // in: path
  89. // description: id of the team to get
  90. // type: integer
  91. // format: int64
  92. // required: true
  93. // responses:
  94. // "200":
  95. // "$ref": "#/responses/Team"
  96. ctx.JSON(200, convert.ToTeam(ctx.Org.Team))
  97. }
  98. // CreateTeam api for create a team
  99. func CreateTeam(ctx *context.APIContext, form api.CreateTeamOption) {
  100. // swagger:operation POST /orgs/{org}/teams organization orgCreateTeam
  101. // ---
  102. // summary: Create a team
  103. // consumes:
  104. // - application/json
  105. // produces:
  106. // - application/json
  107. // parameters:
  108. // - name: org
  109. // in: path
  110. // description: name of the organization
  111. // type: string
  112. // required: true
  113. // - name: body
  114. // in: body
  115. // schema:
  116. // "$ref": "#/definitions/CreateTeamOption"
  117. // responses:
  118. // "201":
  119. // "$ref": "#/responses/Team"
  120. team := &models.Team{
  121. OrgID: ctx.Org.Organization.ID,
  122. Name: form.Name,
  123. Description: form.Description,
  124. Authorize: models.ParseAccessMode(form.Permission),
  125. }
  126. unitTypes := models.FindUnitTypes(form.Units...)
  127. if team.Authorize < models.AccessModeOwner {
  128. var units = make([]*models.TeamUnit, 0, len(form.Units))
  129. for _, tp := range unitTypes {
  130. units = append(units, &models.TeamUnit{
  131. OrgID: ctx.Org.Organization.ID,
  132. Type: tp,
  133. })
  134. }
  135. team.Units = units
  136. }
  137. if err := models.NewTeam(team); err != nil {
  138. if models.IsErrTeamAlreadyExist(err) {
  139. ctx.Error(422, "", err)
  140. } else {
  141. ctx.Error(500, "NewTeam", err)
  142. }
  143. return
  144. }
  145. ctx.JSON(201, convert.ToTeam(team))
  146. }
  147. // EditTeam api for edit a team
  148. func EditTeam(ctx *context.APIContext, form api.EditTeamOption) {
  149. // swagger:operation PATCH /teams/{id} organization orgEditTeam
  150. // ---
  151. // summary: Edit a team
  152. // consumes:
  153. // - application/json
  154. // produces:
  155. // - application/json
  156. // parameters:
  157. // - name: id
  158. // in: path
  159. // description: id of the team to edit
  160. // type: integer
  161. // required: true
  162. // - name: body
  163. // in: body
  164. // schema:
  165. // "$ref": "#/definitions/EditTeamOption"
  166. // responses:
  167. // "200":
  168. // "$ref": "#/responses/Team"
  169. team := ctx.Org.Team
  170. team.Name = form.Name
  171. team.Description = form.Description
  172. team.Authorize = models.ParseAccessMode(form.Permission)
  173. unitTypes := models.FindUnitTypes(form.Units...)
  174. if team.Authorize < models.AccessModeOwner {
  175. var units = make([]*models.TeamUnit, 0, len(form.Units))
  176. for _, tp := range unitTypes {
  177. units = append(units, &models.TeamUnit{
  178. OrgID: ctx.Org.Team.OrgID,
  179. Type: tp,
  180. })
  181. }
  182. team.Units = units
  183. }
  184. if err := models.UpdateTeam(team, true); err != nil {
  185. ctx.Error(500, "EditTeam", err)
  186. return
  187. }
  188. ctx.JSON(200, convert.ToTeam(team))
  189. }
  190. // DeleteTeam api for delete a team
  191. func DeleteTeam(ctx *context.APIContext) {
  192. // swagger:operation DELETE /teams/{id} organization orgDeleteTeam
  193. // ---
  194. // summary: Delete a team
  195. // parameters:
  196. // - name: id
  197. // in: path
  198. // description: id of the team to delete
  199. // type: integer
  200. // format: int64
  201. // required: true
  202. // responses:
  203. // "204":
  204. // description: team deleted
  205. if err := models.DeleteTeam(ctx.Org.Team); err != nil {
  206. ctx.Error(500, "DeleteTeam", err)
  207. return
  208. }
  209. ctx.Status(204)
  210. }
  211. // GetTeamMembers api for get a team's members
  212. func GetTeamMembers(ctx *context.APIContext) {
  213. // swagger:operation GET /teams/{id}/members organization orgListTeamMembers
  214. // ---
  215. // summary: List a team's members
  216. // produces:
  217. // - application/json
  218. // parameters:
  219. // - name: id
  220. // in: path
  221. // description: id of the team
  222. // type: integer
  223. // format: int64
  224. // required: true
  225. // responses:
  226. // "200":
  227. // "$ref": "#/responses/UserList"
  228. isMember, err := models.IsOrganizationMember(ctx.Org.Team.OrgID, ctx.User.ID)
  229. if err != nil {
  230. ctx.Error(500, "IsOrganizationMember", err)
  231. return
  232. } else if !isMember {
  233. ctx.NotFound()
  234. return
  235. }
  236. team := ctx.Org.Team
  237. if err := team.GetMembers(); err != nil {
  238. ctx.Error(500, "GetTeamMembers", err)
  239. return
  240. }
  241. members := make([]*api.User, len(team.Members))
  242. for i, member := range team.Members {
  243. members[i] = convert.ToUser(member, ctx.IsSigned, ctx.User.IsAdmin)
  244. }
  245. ctx.JSON(200, members)
  246. }
  247. // GetTeamMember api for get a particular member of team
  248. func GetTeamMember(ctx *context.APIContext) {
  249. // swagger:operation GET /teams/{id}/members/{username} organization orgListTeamMember
  250. // ---
  251. // summary: List a particular member of team
  252. // produces:
  253. // - application/json
  254. // parameters:
  255. // - name: id
  256. // in: path
  257. // description: id of the team
  258. // type: integer
  259. // format: int64
  260. // required: true
  261. // - name: username
  262. // in: path
  263. // description: username of the member to list
  264. // type: string
  265. // required: true
  266. // responses:
  267. // "200":
  268. // "$ref": "#/responses/User"
  269. u := user.GetUserByParams(ctx)
  270. if ctx.Written() {
  271. return
  272. }
  273. teamID := ctx.ParamsInt64("teamid")
  274. isTeamMember, err := models.IsUserInTeams(u.ID, []int64{teamID})
  275. if err != nil {
  276. ctx.Error(500, "IsUserInTeams", err)
  277. return
  278. } else if !isTeamMember {
  279. ctx.NotFound()
  280. return
  281. }
  282. ctx.JSON(200, convert.ToUser(u, ctx.IsSigned, ctx.User.IsAdmin))
  283. }
  284. // AddTeamMember api for add a member to a team
  285. func AddTeamMember(ctx *context.APIContext) {
  286. // swagger:operation PUT /teams/{id}/members/{username} organization orgAddTeamMember
  287. // ---
  288. // summary: Add a team member
  289. // produces:
  290. // - application/json
  291. // parameters:
  292. // - name: id
  293. // in: path
  294. // description: id of the team
  295. // type: integer
  296. // format: int64
  297. // required: true
  298. // - name: username
  299. // in: path
  300. // description: username of the user to add
  301. // type: string
  302. // required: true
  303. // responses:
  304. // "204":
  305. // "$ref": "#/responses/empty"
  306. u := user.GetUserByParams(ctx)
  307. if ctx.Written() {
  308. return
  309. }
  310. if err := ctx.Org.Team.AddMember(u.ID); err != nil {
  311. ctx.Error(500, "AddMember", err)
  312. return
  313. }
  314. ctx.Status(204)
  315. }
  316. // RemoveTeamMember api for remove one member from a team
  317. func RemoveTeamMember(ctx *context.APIContext) {
  318. // swagger:operation DELETE /teams/{id}/members/{username} organization orgRemoveTeamMember
  319. // ---
  320. // summary: Remove a team member
  321. // produces:
  322. // - application/json
  323. // parameters:
  324. // - name: id
  325. // in: path
  326. // description: id of the team
  327. // type: integer
  328. // format: int64
  329. // required: true
  330. // - name: username
  331. // in: path
  332. // description: username of the user to remove
  333. // type: string
  334. // required: true
  335. // responses:
  336. // "204":
  337. // "$ref": "#/responses/empty"
  338. u := user.GetUserByParams(ctx)
  339. if ctx.Written() {
  340. return
  341. }
  342. if err := ctx.Org.Team.RemoveMember(u.ID); err != nil {
  343. ctx.Error(500, "RemoveMember", err)
  344. return
  345. }
  346. ctx.Status(204)
  347. }
  348. // GetTeamRepos api for get a team's repos
  349. func GetTeamRepos(ctx *context.APIContext) {
  350. // swagger:operation GET /teams/{id}/repos organization orgListTeamRepos
  351. // ---
  352. // summary: List a team's repos
  353. // produces:
  354. // - application/json
  355. // parameters:
  356. // - name: id
  357. // in: path
  358. // description: id of the team
  359. // type: integer
  360. // format: int64
  361. // required: true
  362. // responses:
  363. // "200":
  364. // "$ref": "#/responses/RepositoryList"
  365. team := ctx.Org.Team
  366. if err := team.GetRepositories(); err != nil {
  367. ctx.Error(500, "GetTeamRepos", err)
  368. }
  369. repos := make([]*api.Repository, len(team.Repos))
  370. for i, repo := range team.Repos {
  371. access, err := models.AccessLevel(ctx.User, repo)
  372. if err != nil {
  373. ctx.Error(500, "GetTeamRepos", err)
  374. return
  375. }
  376. repos[i] = repo.APIFormat(access)
  377. }
  378. ctx.JSON(200, repos)
  379. }
  380. // getRepositoryByParams get repository by a team's organization ID and repo name
  381. func getRepositoryByParams(ctx *context.APIContext) *models.Repository {
  382. repo, err := models.GetRepositoryByName(ctx.Org.Team.OrgID, ctx.Params(":reponame"))
  383. if err != nil {
  384. if models.IsErrRepoNotExist(err) {
  385. ctx.NotFound()
  386. } else {
  387. ctx.Error(500, "GetRepositoryByName", err)
  388. }
  389. return nil
  390. }
  391. return repo
  392. }
  393. // AddTeamRepository api for adding a repository to a team
  394. func AddTeamRepository(ctx *context.APIContext) {
  395. // swagger:operation PUT /teams/{id}/repos/{org}/{repo} organization orgAddTeamRepository
  396. // ---
  397. // summary: Add a repository to a team
  398. // produces:
  399. // - application/json
  400. // parameters:
  401. // - name: id
  402. // in: path
  403. // description: id of the team
  404. // type: integer
  405. // format: int64
  406. // required: true
  407. // - name: org
  408. // in: path
  409. // description: organization that owns the repo to add
  410. // type: string
  411. // required: true
  412. // - name: repo
  413. // in: path
  414. // description: name of the repo to add
  415. // type: string
  416. // required: true
  417. // responses:
  418. // "204":
  419. // "$ref": "#/responses/empty"
  420. repo := getRepositoryByParams(ctx)
  421. if ctx.Written() {
  422. return
  423. }
  424. if access, err := models.AccessLevel(ctx.User, repo); err != nil {
  425. ctx.Error(500, "AccessLevel", err)
  426. return
  427. } else if access < models.AccessModeAdmin {
  428. ctx.Error(403, "", "Must have admin-level access to the repository")
  429. return
  430. }
  431. if err := ctx.Org.Team.AddRepository(repo); err != nil {
  432. ctx.Error(500, "AddRepository", err)
  433. return
  434. }
  435. ctx.Status(204)
  436. }
  437. // RemoveTeamRepository api for removing a repository from a team
  438. func RemoveTeamRepository(ctx *context.APIContext) {
  439. // swagger:operation DELETE /teams/{id}/repos/{org}/{repo} organization orgRemoveTeamRepository
  440. // ---
  441. // summary: Remove a repository from a team
  442. // description: This does not delete the repository, it only removes the
  443. // repository from the team.
  444. // produces:
  445. // - application/json
  446. // parameters:
  447. // - name: id
  448. // in: path
  449. // description: id of the team
  450. // type: integer
  451. // format: int64
  452. // required: true
  453. // - name: org
  454. // in: path
  455. // description: organization that owns the repo to remove
  456. // type: string
  457. // required: true
  458. // - name: repo
  459. // in: path
  460. // description: name of the repo to remove
  461. // type: string
  462. // required: true
  463. // responses:
  464. // "204":
  465. // "$ref": "#/responses/empty"
  466. repo := getRepositoryByParams(ctx)
  467. if ctx.Written() {
  468. return
  469. }
  470. if access, err := models.AccessLevel(ctx.User, repo); err != nil {
  471. ctx.Error(500, "AccessLevel", err)
  472. return
  473. } else if access < models.AccessModeAdmin {
  474. ctx.Error(403, "", "Must have admin-level access to the repository")
  475. return
  476. }
  477. if err := ctx.Org.Team.RemoveRepository(repo.ID); err != nil {
  478. ctx.Error(500, "RemoveRepository", err)
  479. return
  480. }
  481. ctx.Status(204)
  482. }
  483. // SearchTeam api for searching teams
  484. func SearchTeam(ctx *context.APIContext) {
  485. // swagger:operation GET /orgs/{org}/teams/search organization teamSearch
  486. // ---
  487. // summary: Search for teams within an organization
  488. // produces:
  489. // - application/json
  490. // parameters:
  491. // - name: org
  492. // in: path
  493. // description: name of the organization
  494. // type: string
  495. // required: true
  496. // - name: q
  497. // in: query
  498. // description: keywords to search
  499. // type: string
  500. // - name: include_desc
  501. // in: query
  502. // description: include search within team description (defaults to true)
  503. // type: boolean
  504. // - name: limit
  505. // in: query
  506. // description: limit size of results
  507. // type: integer
  508. // - name: page
  509. // in: query
  510. // description: page number of results to return (1-based)
  511. // type: integer
  512. // responses:
  513. // "200":
  514. // description: "SearchResults of a successful search"
  515. // schema:
  516. // type: object
  517. // properties:
  518. // ok:
  519. // type: boolean
  520. // data:
  521. // type: array
  522. // items:
  523. // "$ref": "#/definitions/Team"
  524. opts := &models.SearchTeamOptions{
  525. UserID: ctx.User.ID,
  526. Keyword: strings.TrimSpace(ctx.Query("q")),
  527. OrgID: ctx.Org.Organization.ID,
  528. IncludeDesc: (ctx.Query("include_desc") == "" || ctx.QueryBool("include_desc")),
  529. PageSize: ctx.QueryInt("limit"),
  530. Page: ctx.QueryInt("page"),
  531. }
  532. teams, _, err := models.SearchTeam(opts)
  533. if err != nil {
  534. log.Error("SearchTeam failed: %v", err)
  535. ctx.JSON(500, map[string]interface{}{
  536. "ok": false,
  537. "error": "SearchTeam internal failure",
  538. })
  539. return
  540. }
  541. apiTeams := make([]*api.Team, len(teams))
  542. for i := range teams {
  543. if err := teams[i].GetUnits(); err != nil {
  544. log.Error("Team GetUnits failed: %v", err)
  545. ctx.JSON(500, map[string]interface{}{
  546. "ok": false,
  547. "error": "SearchTeam failed to get units",
  548. })
  549. return
  550. }
  551. apiTeams[i] = convert.ToTeam(teams[i])
  552. }
  553. ctx.JSON(200, map[string]interface{}{
  554. "ok": true,
  555. "data": apiTeams,
  556. })
  557. }
上海开阖软件有限公司 沪ICP备12045867号-1