Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  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, err := repo_model.GetForks(ctx, ctx.Repo.Repository, utils.GetListOptions(ctx))
  54. if err != nil {
  55. ctx.Error(http.StatusInternalServerError, "GetForks", err)
  56. return
  57. }
  58. apiForks := make([]*api.Repository, len(forks))
  59. for i, fork := range forks {
  60. permission, err := access_model.GetUserRepoPermission(ctx, fork, ctx.Doer)
  61. if err != nil {
  62. ctx.Error(http.StatusInternalServerError, "GetUserRepoPermission", err)
  63. return
  64. }
  65. apiForks[i] = convert.ToRepo(ctx, fork, permission)
  66. }
  67. ctx.SetTotalCountHeader(int64(ctx.Repo.Repository.NumForks))
  68. ctx.JSON(http.StatusOK, apiForks)
  69. }
  70. // CreateFork create a fork of a repo
  71. func CreateFork(ctx *context.APIContext) {
  72. // swagger:operation POST /repos/{owner}/{repo}/forks repository createFork
  73. // ---
  74. // summary: Fork a repository
  75. // produces:
  76. // - application/json
  77. // parameters:
  78. // - name: owner
  79. // in: path
  80. // description: owner of the repo to fork
  81. // type: string
  82. // required: true
  83. // - name: repo
  84. // in: path
  85. // description: name of the repo to fork
  86. // type: string
  87. // required: true
  88. // - name: body
  89. // in: body
  90. // schema:
  91. // "$ref": "#/definitions/CreateForkOption"
  92. // responses:
  93. // "202":
  94. // "$ref": "#/responses/Repository"
  95. // "403":
  96. // "$ref": "#/responses/forbidden"
  97. // "404":
  98. // "$ref": "#/responses/notFound"
  99. // "409":
  100. // description: The repository with the same name already exists.
  101. // "422":
  102. // "$ref": "#/responses/validationError"
  103. form := web.GetForm(ctx).(*api.CreateForkOption)
  104. repo := ctx.Repo.Repository
  105. var forker *user_model.User // user/org that will own the fork
  106. if form.Organization == nil {
  107. forker = ctx.Doer
  108. } else {
  109. org, err := organization.GetOrgByName(ctx, *form.Organization)
  110. if err != nil {
  111. if organization.IsErrOrgNotExist(err) {
  112. ctx.Error(http.StatusUnprocessableEntity, "", err)
  113. } else {
  114. ctx.Error(http.StatusInternalServerError, "GetOrgByName", err)
  115. }
  116. return
  117. }
  118. isMember, err := org.IsOrgMember(ctx, ctx.Doer.ID)
  119. if err != nil {
  120. ctx.Error(http.StatusInternalServerError, "IsOrgMember", err)
  121. return
  122. } else if !isMember {
  123. ctx.Error(http.StatusForbidden, "isMemberNot", fmt.Sprintf("User is no Member of Organisation '%s'", org.Name))
  124. return
  125. }
  126. forker = org.AsUser()
  127. }
  128. var name string
  129. if form.Name == nil {
  130. name = repo.Name
  131. } else {
  132. name = *form.Name
  133. }
  134. fork, err := repo_service.ForkRepository(ctx, ctx.Doer, forker, repo_service.ForkRepoOptions{
  135. BaseRepo: repo,
  136. Name: name,
  137. Description: repo.Description,
  138. })
  139. if err != nil {
  140. if errors.Is(err, util.ErrAlreadyExist) || repo_model.IsErrReachLimitOfRepo(err) {
  141. ctx.Error(http.StatusConflict, "ForkRepository", err)
  142. } else if errors.Is(err, user_model.ErrBlockedUser) {
  143. ctx.Error(http.StatusForbidden, "ForkRepository", err)
  144. } else {
  145. ctx.Error(http.StatusInternalServerError, "ForkRepository", err)
  146. }
  147. return
  148. }
  149. // TODO change back to 201
  150. ctx.JSON(http.StatusAccepted, convert.ToRepo(ctx, fork, access_model.Permission{AccessMode: perm.AccessModeOwner}))
  151. }