gitea源码

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. // Copyright 2016 The Gogs Authors. All rights reserved.
  2. // Copyright 2020 The Gitea Authors.
  3. // SPDX-License-Identifier: MIT
  4. package repo
  5. import (
  6. "errors"
  7. "fmt"
  8. "net/http"
  9. "code.gitea.io/gitea/models/organization"
  10. "code.gitea.io/gitea/models/perm"
  11. access_model "code.gitea.io/gitea/models/perm/access"
  12. repo_model "code.gitea.io/gitea/models/repo"
  13. user_model "code.gitea.io/gitea/models/user"
  14. api "code.gitea.io/gitea/modules/structs"
  15. "code.gitea.io/gitea/modules/util"
  16. "code.gitea.io/gitea/modules/web"
  17. "code.gitea.io/gitea/routers/api/v1/utils"
  18. "code.gitea.io/gitea/services/context"
  19. "code.gitea.io/gitea/services/convert"
  20. repo_service "code.gitea.io/gitea/services/repository"
  21. )
  22. // ListForks list a repository's forks
  23. func ListForks(ctx *context.APIContext) {
  24. // swagger:operation GET /repos/{owner}/{repo}/forks repository listForks
  25. // ---
  26. // summary: List a repository's forks
  27. // produces:
  28. // - application/json
  29. // parameters:
  30. // - name: owner
  31. // in: path
  32. // description: owner of the repo
  33. // type: string
  34. // required: true
  35. // - name: repo
  36. // in: path
  37. // description: name of the repo
  38. // type: string
  39. // required: true
  40. // - name: page
  41. // in: query
  42. // description: page number of results to return (1-based)
  43. // type: integer
  44. // - name: limit
  45. // in: query
  46. // description: page size of results
  47. // type: integer
  48. // responses:
  49. // "200":
  50. // "$ref": "#/responses/RepositoryList"
  51. // "404":
  52. // "$ref": "#/responses/notFound"
  53. forks, total, err := repo_service.FindForks(ctx, ctx.Repo.Repository, ctx.Doer, utils.GetListOptions(ctx))
  54. if err != nil {
  55. ctx.APIErrorInternal(err)
  56. return
  57. }
  58. if err := repo_model.RepositoryList(forks).LoadOwners(ctx); err != nil {
  59. ctx.APIErrorInternal(err)
  60. return
  61. }
  62. if err := repo_model.RepositoryList(forks).LoadUnits(ctx); err != nil {
  63. ctx.APIErrorInternal(err)
  64. return
  65. }
  66. apiForks := make([]*api.Repository, len(forks))
  67. for i, fork := range forks {
  68. permission, err := access_model.GetUserRepoPermission(ctx, fork, ctx.Doer)
  69. if err != nil {
  70. ctx.APIErrorInternal(err)
  71. return
  72. }
  73. apiForks[i] = convert.ToRepo(ctx, fork, permission)
  74. }
  75. ctx.SetTotalCountHeader(total)
  76. ctx.JSON(http.StatusOK, apiForks)
  77. }
  78. // CreateFork create a fork of a repo
  79. func CreateFork(ctx *context.APIContext) {
  80. // swagger:operation POST /repos/{owner}/{repo}/forks repository createFork
  81. // ---
  82. // summary: Fork a repository
  83. // produces:
  84. // - application/json
  85. // parameters:
  86. // - name: owner
  87. // in: path
  88. // description: owner of the repo to fork
  89. // type: string
  90. // required: true
  91. // - name: repo
  92. // in: path
  93. // description: name of the repo to fork
  94. // type: string
  95. // required: true
  96. // - name: body
  97. // in: body
  98. // schema:
  99. // "$ref": "#/definitions/CreateForkOption"
  100. // responses:
  101. // "202":
  102. // "$ref": "#/responses/Repository"
  103. // "403":
  104. // "$ref": "#/responses/forbidden"
  105. // "404":
  106. // "$ref": "#/responses/notFound"
  107. // "409":
  108. // description: The repository with the same name already exists.
  109. // "422":
  110. // "$ref": "#/responses/validationError"
  111. form := web.GetForm(ctx).(*api.CreateForkOption)
  112. repo := ctx.Repo.Repository
  113. var forker *user_model.User // user/org that will own the fork
  114. if form.Organization == nil {
  115. forker = ctx.Doer
  116. } else {
  117. org, err := organization.GetOrgByName(ctx, *form.Organization)
  118. if err != nil {
  119. if organization.IsErrOrgNotExist(err) {
  120. ctx.APIError(http.StatusUnprocessableEntity, err)
  121. } else {
  122. ctx.APIErrorInternal(err)
  123. }
  124. return
  125. }
  126. if !ctx.Doer.IsAdmin {
  127. isMember, err := org.IsOrgMember(ctx, ctx.Doer.ID)
  128. if err != nil {
  129. ctx.APIErrorInternal(err)
  130. return
  131. } else if !isMember {
  132. ctx.APIError(http.StatusForbidden, fmt.Sprintf("User is no Member of Organisation '%s'", org.Name))
  133. return
  134. }
  135. }
  136. forker = org.AsUser()
  137. }
  138. var name string
  139. if form.Name == nil {
  140. name = repo.Name
  141. } else {
  142. name = *form.Name
  143. }
  144. fork, err := repo_service.ForkRepository(ctx, ctx.Doer, forker, repo_service.ForkRepoOptions{
  145. BaseRepo: repo,
  146. Name: name,
  147. Description: repo.Description,
  148. })
  149. if err != nil {
  150. if errors.Is(err, util.ErrAlreadyExist) || repo_model.IsErrReachLimitOfRepo(err) {
  151. ctx.APIError(http.StatusConflict, err)
  152. } else if errors.Is(err, user_model.ErrBlockedUser) {
  153. ctx.APIError(http.StatusForbidden, err)
  154. } else {
  155. ctx.APIErrorInternal(err)
  156. }
  157. return
  158. }
  159. // TODO change back to 201
  160. ctx.JSON(http.StatusAccepted, convert.ToRepo(ctx, fork, access_model.Permission{AccessMode: perm.AccessModeOwner}))
  161. }