gitea源码

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. // Copyright 2016 The Gitea Authors. All rights reserved.
  2. // SPDX-License-Identifier: MIT
  3. package user
  4. import (
  5. "errors"
  6. "net/http"
  7. access_model "code.gitea.io/gitea/models/perm/access"
  8. repo_model "code.gitea.io/gitea/models/repo"
  9. user_model "code.gitea.io/gitea/models/user"
  10. api "code.gitea.io/gitea/modules/structs"
  11. "code.gitea.io/gitea/routers/api/v1/utils"
  12. "code.gitea.io/gitea/services/context"
  13. "code.gitea.io/gitea/services/convert"
  14. )
  15. // getWatchedRepos returns the repos that the user with the specified userID is watching
  16. func getWatchedRepos(ctx *context.APIContext, user *user_model.User, private bool) ([]*api.Repository, int64, error) {
  17. watchedRepos, total, err := repo_model.GetWatchedRepos(ctx, &repo_model.WatchedReposOptions{
  18. ListOptions: utils.GetListOptions(ctx),
  19. WatcherID: user.ID,
  20. IncludePrivate: private,
  21. })
  22. if err != nil {
  23. return nil, 0, err
  24. }
  25. repos := make([]*api.Repository, len(watchedRepos))
  26. for i, watched := range watchedRepos {
  27. permission, err := access_model.GetUserRepoPermission(ctx, watched, user)
  28. if err != nil {
  29. return nil, 0, err
  30. }
  31. repos[i] = convert.ToRepo(ctx, watched, permission)
  32. }
  33. return repos, total, nil
  34. }
  35. // GetWatchedRepos returns the repos that the user specified in ctx is watching
  36. func GetWatchedRepos(ctx *context.APIContext) {
  37. // swagger:operation GET /users/{username}/subscriptions user userListSubscriptions
  38. // ---
  39. // summary: List the repositories watched by a user
  40. // produces:
  41. // - application/json
  42. // parameters:
  43. // - name: username
  44. // type: string
  45. // in: path
  46. // description: username of the user whose watched repos are to be listed
  47. // required: true
  48. // - name: page
  49. // in: query
  50. // description: page number of results to return (1-based)
  51. // type: integer
  52. // - name: limit
  53. // in: query
  54. // description: page size of results
  55. // type: integer
  56. // responses:
  57. // "200":
  58. // "$ref": "#/responses/RepositoryList"
  59. // "404":
  60. // "$ref": "#/responses/notFound"
  61. private := ctx.ContextUser.ID == ctx.Doer.ID
  62. repos, total, err := getWatchedRepos(ctx, ctx.ContextUser, private)
  63. if err != nil {
  64. ctx.APIErrorInternal(err)
  65. }
  66. ctx.SetTotalCountHeader(total)
  67. ctx.JSON(http.StatusOK, &repos)
  68. }
  69. // GetMyWatchedRepos returns the repos that the authenticated user is watching
  70. func GetMyWatchedRepos(ctx *context.APIContext) {
  71. // swagger:operation GET /user/subscriptions user userCurrentListSubscriptions
  72. // ---
  73. // summary: List repositories watched by the authenticated user
  74. // produces:
  75. // - application/json
  76. // parameters:
  77. // - name: page
  78. // in: query
  79. // description: page number of results to return (1-based)
  80. // type: integer
  81. // - name: limit
  82. // in: query
  83. // description: page size of results
  84. // type: integer
  85. // responses:
  86. // "200":
  87. // "$ref": "#/responses/RepositoryList"
  88. repos, total, err := getWatchedRepos(ctx, ctx.Doer, true)
  89. if err != nil {
  90. ctx.APIErrorInternal(err)
  91. }
  92. ctx.SetTotalCountHeader(total)
  93. ctx.JSON(http.StatusOK, &repos)
  94. }
  95. // IsWatching returns whether the authenticated user is watching the repo
  96. // specified in ctx
  97. func IsWatching(ctx *context.APIContext) {
  98. // swagger:operation GET /repos/{owner}/{repo}/subscription repository userCurrentCheckSubscription
  99. // ---
  100. // summary: Check if the current user is watching a repo
  101. // parameters:
  102. // - name: owner
  103. // in: path
  104. // description: owner of the repo
  105. // type: string
  106. // required: true
  107. // - name: repo
  108. // in: path
  109. // description: name of the repo
  110. // type: string
  111. // required: true
  112. // responses:
  113. // "200":
  114. // "$ref": "#/responses/WatchInfo"
  115. // "404":
  116. // description: User is not watching this repo or repo do not exist
  117. if repo_model.IsWatching(ctx, ctx.Doer.ID, ctx.Repo.Repository.ID) {
  118. ctx.JSON(http.StatusOK, api.WatchInfo{
  119. Subscribed: true,
  120. Ignored: false,
  121. Reason: nil,
  122. CreatedAt: ctx.Repo.Repository.CreatedUnix.AsTime(),
  123. URL: subscriptionURL(ctx.Repo.Repository),
  124. RepositoryURL: ctx.Repo.Repository.APIURL(),
  125. })
  126. } else {
  127. ctx.APIErrorNotFound()
  128. }
  129. }
  130. // Watch the repo specified in ctx, as the authenticated user
  131. func Watch(ctx *context.APIContext) {
  132. // swagger:operation PUT /repos/{owner}/{repo}/subscription repository userCurrentPutSubscription
  133. // ---
  134. // summary: Watch a repo
  135. // parameters:
  136. // - name: owner
  137. // in: path
  138. // description: owner of the repo
  139. // type: string
  140. // required: true
  141. // - name: repo
  142. // in: path
  143. // description: name of the repo
  144. // type: string
  145. // required: true
  146. // responses:
  147. // "200":
  148. // "$ref": "#/responses/WatchInfo"
  149. // "403":
  150. // "$ref": "#/responses/forbidden"
  151. // "404":
  152. // "$ref": "#/responses/notFound"
  153. err := repo_model.WatchRepo(ctx, ctx.Doer, ctx.Repo.Repository, true)
  154. if err != nil {
  155. if errors.Is(err, user_model.ErrBlockedUser) {
  156. ctx.APIError(http.StatusForbidden, err)
  157. } else {
  158. ctx.APIErrorInternal(err)
  159. }
  160. return
  161. }
  162. ctx.JSON(http.StatusOK, api.WatchInfo{
  163. Subscribed: true,
  164. Ignored: false,
  165. Reason: nil,
  166. CreatedAt: ctx.Repo.Repository.CreatedUnix.AsTime(),
  167. URL: subscriptionURL(ctx.Repo.Repository),
  168. RepositoryURL: ctx.Repo.Repository.APIURL(),
  169. })
  170. }
  171. // Unwatch the repo specified in ctx, as the authenticated user
  172. func Unwatch(ctx *context.APIContext) {
  173. // swagger:operation DELETE /repos/{owner}/{repo}/subscription repository userCurrentDeleteSubscription
  174. // ---
  175. // summary: Unwatch a repo
  176. // parameters:
  177. // - name: owner
  178. // in: path
  179. // description: owner of the repo
  180. // type: string
  181. // required: true
  182. // - name: repo
  183. // in: path
  184. // description: name of the repo
  185. // type: string
  186. // required: true
  187. // responses:
  188. // "204":
  189. // "$ref": "#/responses/empty"
  190. // "404":
  191. // "$ref": "#/responses/notFound"
  192. err := repo_model.WatchRepo(ctx, ctx.Doer, ctx.Repo.Repository, false)
  193. if err != nil {
  194. ctx.APIErrorInternal(err)
  195. return
  196. }
  197. ctx.Status(http.StatusNoContent)
  198. }
  199. // subscriptionURL returns the URL of the subscription API endpoint of a repo
  200. func subscriptionURL(repo *repo_model.Repository) string {
  201. return repo.APIURL() + "/subscription"
  202. }