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.

100 lines
2.7 KiB

  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. package repo
  5. import (
  6. "fmt"
  7. "net/http"
  8. "code.gitea.io/gitea/models"
  9. "code.gitea.io/gitea/modules/context"
  10. "code.gitea.io/gitea/modules/convert"
  11. "code.gitea.io/gitea/modules/log"
  12. api "code.gitea.io/gitea/modules/structs"
  13. repo_service "code.gitea.io/gitea/services/repository"
  14. )
  15. // Transfer transfers the ownership of a repository
  16. func Transfer(ctx *context.APIContext, opts api.TransferRepoOption) {
  17. // swagger:operation POST /repos/{owner}/{repo}/transfer repository repoTransfer
  18. // ---
  19. // summary: Transfer a repo ownership
  20. // produces:
  21. // - application/json
  22. // parameters:
  23. // - name: owner
  24. // in: path
  25. // description: owner of the repo to transfer
  26. // type: string
  27. // required: true
  28. // - name: repo
  29. // in: path
  30. // description: name of the repo to transfer
  31. // type: string
  32. // required: true
  33. // - name: body
  34. // in: body
  35. // description: "Transfer Options"
  36. // required: true
  37. // schema:
  38. // "$ref": "#/definitions/TransferRepoOption"
  39. // responses:
  40. // "202":
  41. // "$ref": "#/responses/Repository"
  42. // "403":
  43. // "$ref": "#/responses/forbidden"
  44. // "404":
  45. // "$ref": "#/responses/notFound"
  46. // "422":
  47. // "$ref": "#/responses/validationError"
  48. newOwner, err := models.GetUserByName(opts.NewOwner)
  49. if err != nil {
  50. if models.IsErrUserNotExist(err) {
  51. ctx.Error(http.StatusNotFound, "GetUserByName", err)
  52. return
  53. }
  54. ctx.InternalServerError(err)
  55. return
  56. }
  57. var teams []*models.Team
  58. if opts.TeamIDs != nil {
  59. if !newOwner.IsOrganization() {
  60. ctx.Error(http.StatusUnprocessableEntity, "repoTransfer", "Teams can only be added to organization-owned repositories")
  61. return
  62. }
  63. org := convert.ToOrganization(newOwner)
  64. for _, tID := range *opts.TeamIDs {
  65. team, err := models.GetTeamByID(tID)
  66. if err != nil {
  67. ctx.Error(http.StatusUnprocessableEntity, "team", fmt.Errorf("team %d not found", tID))
  68. return
  69. }
  70. if team.OrgID != org.ID {
  71. ctx.Error(http.StatusForbidden, "team", fmt.Errorf("team %d belongs not to org %d", tID, org.ID))
  72. return
  73. }
  74. teams = append(teams, team)
  75. }
  76. }
  77. if err = repo_service.TransferOwnership(ctx.User, newOwner, ctx.Repo.Repository, teams); err != nil {
  78. ctx.InternalServerError(err)
  79. return
  80. }
  81. newRepo, err := models.GetRepositoryByName(newOwner.ID, ctx.Repo.Repository.Name)
  82. if err != nil {
  83. ctx.InternalServerError(err)
  84. return
  85. }
  86. log.Trace("Repository transferred: %s -> %s", ctx.Repo.Repository.FullName(), newOwner.Name)
  87. ctx.JSON(http.StatusAccepted, newRepo.APIFormat(models.AccessModeAdmin))
  88. }