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.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323
  1. // Copyright 2016 The Gogs Authors. All rights reserved.
  2. // Copyright 2018 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 repo
  6. import (
  7. "net/http"
  8. "code.gitea.io/gitea/models"
  9. "code.gitea.io/gitea/modules/context"
  10. "code.gitea.io/gitea/modules/convert"
  11. api "code.gitea.io/gitea/modules/structs"
  12. issue_service "code.gitea.io/gitea/services/issue"
  13. )
  14. // ListIssueLabels list all the labels of an issue
  15. func ListIssueLabels(ctx *context.APIContext) {
  16. // swagger:operation GET /repos/{owner}/{repo}/issues/{index}/labels issue issueGetLabels
  17. // ---
  18. // summary: Get an issue's labels
  19. // produces:
  20. // - application/json
  21. // parameters:
  22. // - name: owner
  23. // in: path
  24. // description: owner of the repo
  25. // type: string
  26. // required: true
  27. // - name: repo
  28. // in: path
  29. // description: name of the repo
  30. // type: string
  31. // required: true
  32. // - name: index
  33. // in: path
  34. // description: index of the issue
  35. // type: integer
  36. // format: int64
  37. // required: true
  38. // responses:
  39. // "200":
  40. // "$ref": "#/responses/LabelList"
  41. // "404":
  42. // "$ref": "#/responses/notFound"
  43. issue, err := models.GetIssueByIndex(ctx.Repo.Repository.ID, ctx.ParamsInt64(":index"))
  44. if err != nil {
  45. if models.IsErrIssueNotExist(err) {
  46. ctx.NotFound()
  47. } else {
  48. ctx.Error(http.StatusInternalServerError, "GetIssueByIndex", err)
  49. }
  50. return
  51. }
  52. if err := issue.LoadAttributes(); err != nil {
  53. ctx.Error(http.StatusInternalServerError, "LoadAttributes", err)
  54. return
  55. }
  56. ctx.JSON(http.StatusOK, convert.ToLabelList(issue.Labels))
  57. }
  58. // AddIssueLabels add labels for an issue
  59. func AddIssueLabels(ctx *context.APIContext, form api.IssueLabelsOption) {
  60. // swagger:operation POST /repos/{owner}/{repo}/issues/{index}/labels issue issueAddLabel
  61. // ---
  62. // summary: Add a label to an issue
  63. // consumes:
  64. // - application/json
  65. // produces:
  66. // - application/json
  67. // parameters:
  68. // - name: owner
  69. // in: path
  70. // description: owner of the repo
  71. // type: string
  72. // required: true
  73. // - name: repo
  74. // in: path
  75. // description: name of the repo
  76. // type: string
  77. // required: true
  78. // - name: index
  79. // in: path
  80. // description: index of the issue
  81. // type: integer
  82. // format: int64
  83. // required: true
  84. // - name: body
  85. // in: body
  86. // schema:
  87. // "$ref": "#/definitions/IssueLabelsOption"
  88. // responses:
  89. // "200":
  90. // "$ref": "#/responses/LabelList"
  91. // "403":
  92. // "$ref": "#/responses/forbidden"
  93. issue, labels, err := prepareForReplaceOrAdd(ctx, form)
  94. if err != nil {
  95. return
  96. }
  97. if err = issue_service.AddLabels(issue, ctx.User, labels); err != nil {
  98. ctx.Error(http.StatusInternalServerError, "AddLabels", err)
  99. return
  100. }
  101. labels, err = models.GetLabelsByIssueID(issue.ID)
  102. if err != nil {
  103. ctx.Error(http.StatusInternalServerError, "GetLabelsByIssueID", err)
  104. return
  105. }
  106. ctx.JSON(http.StatusOK, convert.ToLabelList(labels))
  107. }
  108. // DeleteIssueLabel delete a label for an issue
  109. func DeleteIssueLabel(ctx *context.APIContext) {
  110. // swagger:operation DELETE /repos/{owner}/{repo}/issues/{index}/labels/{id} issue issueRemoveLabel
  111. // ---
  112. // summary: Remove a label from an issue
  113. // produces:
  114. // - application/json
  115. // parameters:
  116. // - name: owner
  117. // in: path
  118. // description: owner of the repo
  119. // type: string
  120. // required: true
  121. // - name: repo
  122. // in: path
  123. // description: name of the repo
  124. // type: string
  125. // required: true
  126. // - name: index
  127. // in: path
  128. // description: index of the issue
  129. // type: integer
  130. // format: int64
  131. // required: true
  132. // - name: id
  133. // in: path
  134. // description: id of the label to remove
  135. // type: integer
  136. // format: int64
  137. // required: true
  138. // responses:
  139. // "204":
  140. // "$ref": "#/responses/empty"
  141. // "403":
  142. // "$ref": "#/responses/forbidden"
  143. // "422":
  144. // "$ref": "#/responses/validationError"
  145. issue, err := models.GetIssueByIndex(ctx.Repo.Repository.ID, ctx.ParamsInt64(":index"))
  146. if err != nil {
  147. if models.IsErrIssueNotExist(err) {
  148. ctx.NotFound()
  149. } else {
  150. ctx.Error(http.StatusInternalServerError, "GetIssueByIndex", err)
  151. }
  152. return
  153. }
  154. if !ctx.Repo.CanWriteIssuesOrPulls(issue.IsPull) {
  155. ctx.Status(http.StatusForbidden)
  156. return
  157. }
  158. label, err := models.GetLabelInRepoByID(ctx.Repo.Repository.ID, ctx.ParamsInt64(":id"))
  159. if err != nil {
  160. if models.IsErrLabelNotExist(err) {
  161. ctx.Error(http.StatusUnprocessableEntity, "", err)
  162. } else {
  163. ctx.Error(http.StatusInternalServerError, "GetLabelInRepoByID", err)
  164. }
  165. return
  166. }
  167. if err := issue_service.RemoveLabel(issue, ctx.User, label); err != nil {
  168. ctx.Error(http.StatusInternalServerError, "DeleteIssueLabel", err)
  169. return
  170. }
  171. ctx.Status(http.StatusNoContent)
  172. }
  173. // ReplaceIssueLabels replace labels for an issue
  174. func ReplaceIssueLabels(ctx *context.APIContext, form api.IssueLabelsOption) {
  175. // swagger:operation PUT /repos/{owner}/{repo}/issues/{index}/labels issue issueReplaceLabels
  176. // ---
  177. // summary: Replace an issue's labels
  178. // consumes:
  179. // - application/json
  180. // produces:
  181. // - application/json
  182. // parameters:
  183. // - name: owner
  184. // in: path
  185. // description: owner of the repo
  186. // type: string
  187. // required: true
  188. // - name: repo
  189. // in: path
  190. // description: name of the repo
  191. // type: string
  192. // required: true
  193. // - name: index
  194. // in: path
  195. // description: index of the issue
  196. // type: integer
  197. // format: int64
  198. // required: true
  199. // - name: body
  200. // in: body
  201. // schema:
  202. // "$ref": "#/definitions/IssueLabelsOption"
  203. // responses:
  204. // "200":
  205. // "$ref": "#/responses/LabelList"
  206. // "403":
  207. // "$ref": "#/responses/forbidden"
  208. issue, labels, err := prepareForReplaceOrAdd(ctx, form)
  209. if err != nil {
  210. return
  211. }
  212. if err := issue_service.ReplaceLabels(issue, ctx.User, labels); err != nil {
  213. ctx.Error(http.StatusInternalServerError, "ReplaceLabels", err)
  214. return
  215. }
  216. labels, err = models.GetLabelsByIssueID(issue.ID)
  217. if err != nil {
  218. ctx.Error(http.StatusInternalServerError, "GetLabelsByIssueID", err)
  219. return
  220. }
  221. ctx.JSON(http.StatusOK, convert.ToLabelList(labels))
  222. }
  223. // ClearIssueLabels delete all the labels for an issue
  224. func ClearIssueLabels(ctx *context.APIContext) {
  225. // swagger:operation DELETE /repos/{owner}/{repo}/issues/{index}/labels issue issueClearLabels
  226. // ---
  227. // summary: Remove all labels from an issue
  228. // produces:
  229. // - application/json
  230. // parameters:
  231. // - name: owner
  232. // in: path
  233. // description: owner of the repo
  234. // type: string
  235. // required: true
  236. // - name: repo
  237. // in: path
  238. // description: name of the repo
  239. // type: string
  240. // required: true
  241. // - name: index
  242. // in: path
  243. // description: index of the issue
  244. // type: integer
  245. // format: int64
  246. // required: true
  247. // responses:
  248. // "204":
  249. // "$ref": "#/responses/empty"
  250. // "403":
  251. // "$ref": "#/responses/forbidden"
  252. issue, err := models.GetIssueByIndex(ctx.Repo.Repository.ID, ctx.ParamsInt64(":index"))
  253. if err != nil {
  254. if models.IsErrIssueNotExist(err) {
  255. ctx.NotFound()
  256. } else {
  257. ctx.Error(http.StatusInternalServerError, "GetIssueByIndex", err)
  258. }
  259. return
  260. }
  261. if !ctx.Repo.CanWriteIssuesOrPulls(issue.IsPull) {
  262. ctx.Status(http.StatusForbidden)
  263. return
  264. }
  265. if err := issue_service.ClearLabels(issue, ctx.User); err != nil {
  266. ctx.Error(http.StatusInternalServerError, "ClearLabels", err)
  267. return
  268. }
  269. ctx.Status(http.StatusNoContent)
  270. }
  271. func prepareForReplaceOrAdd(ctx *context.APIContext, form api.IssueLabelsOption) (issue *models.Issue, labels []*models.Label, err error) {
  272. issue, err = models.GetIssueByIndex(ctx.Repo.Repository.ID, ctx.ParamsInt64(":index"))
  273. if err != nil {
  274. if models.IsErrIssueNotExist(err) {
  275. ctx.NotFound()
  276. } else {
  277. ctx.Error(http.StatusInternalServerError, "GetIssueByIndex", err)
  278. }
  279. return
  280. }
  281. labels, err = models.GetLabelsInRepoByIDs(ctx.Repo.Repository.ID, form.Labels)
  282. if err != nil {
  283. ctx.Error(http.StatusInternalServerError, "GetLabelsInRepoByIDs", err)
  284. return
  285. }
  286. if !ctx.Repo.CanWriteIssuesOrPulls(issue.IsPull) {
  287. ctx.Status(http.StatusForbidden)
  288. return
  289. }
  290. return
  291. }