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.

323 lines
8.0 KiB

Add Organization Wide Labels (#10814) * Add organization wide labels Implement organization wide labels similar to organization wide webhooks. This lets you create individual labels for organizations that can be used for all repos under that organization (so being able to reuse the same label across multiple repos). This makes it possible for small organizations with many repos to use labels effectively. Fixes #7406 * Add migration * remove comments * fix tests * Update options/locale/locale_en-US.ini Removed unused translation string * show org labels in issue search label filter * Use more clear var name * rename migration after merge from master * comment typo * update migration again after rebase with master * check for orgID <=0 per guillep2k review * fmt * Apply suggestions from code review Co-Authored-By: guillep2k <18600385+guillep2k@users.noreply.github.com> * remove unused code * Make sure RepoID is 0 when searching orgID per code review * more changes/code review requests * More descriptive translation var per code review * func description/delete comment when issue label deleted instead of hiding it * remove comment * only use issues in that repo when calculating number of open issues for org label on repo label page * Add integration test for IssuesSearch API with labels * remove unused function * Update models/issue_label.go Co-Authored-By: guillep2k <18600385+guillep2k@users.noreply.github.com> * Use subquery in GetLabelIDsInReposByNames * Fix tests to use correct orgID * fix more tests * IssuesSearch api now uses new BuildLabelNamesIssueIDsCondition. Add a few more tests as well * update comment for clarity * Revert previous code change now that we can use the new BuildLabelNamesIssueIDsCondition * Don't sort repos by date in IssuesSearch API After much debugging I've found a strange issue where in some cases MySQL will return a different result than other enigines if a query is sorted by a null collumn. For example with our integration test data where we don't set updated_unix in repository fixtures: SELECT `id`, `owner_id`, `owner_name`, `lower_name`, `name`, `description`, `website`, `original_service_type`, `original_url`, `default_branch`, `num_watches`, `num_stars`, `num_forks`, `num_issues`, `num_closed_issues`, `num_pulls`, `num_closed_pulls`, `num_milestones`, `num_closed_milestones`, `is_private`, `is_empty`, `is_archived`, `is_mirror`, `status`, `is_fork`, `fork_id`, `is_template`, `template_id`, `size`, `is_fsck_enabled`, `close_issues_via_commit_in_any_branch`, `topics`, `avatar`, `created_unix`, `updated_unix` FROM `repository` ORDER BY updated_unix DESC LIMIT 15 OFFSET 45 Returns different results for MySQL than other engines. However, the similar query: SELECT `id`, `owner_id`, `owner_name`, `lower_name`, `name`, `description`, `website`, `original_service_type`, `original_url`, `default_branch`, `num_watches`, `num_stars`, `num_forks`, `num_issues`, `num_closed_issues`, `num_pulls`, `num_closed_pulls`, `num_milestones`, `num_closed_milestones`, `is_private`, `is_empty`, `is_archived`, `is_mirror`, `status`, `is_fork`, `fork_id`, `is_template`, `template_id`, `size`, `is_fsck_enabled`, `close_issues_via_commit_in_any_branch`, `topics`, `avatar`, `created_unix`, `updated_unix` FROM `repository` ORDER BY updated_unix DESC LIMIT 15 OFFSET 30 Returns the same results. This causes integration tests to fail on MySQL in certain cases but would never show up in a real installation. Since this API call always returns issues based on the optionally provided repo_priority_id or the issueID itself, there is no change to results by changing the repo sorting method used to get ids earlier in the function. * linter is back! * code review * remove now unused option * Fix newline at end of files * more unused code * update to master * check for matching ids before query * Update models/issue_label.go Co-Authored-By: 6543 <6543@obermui.de> * Update models/issue_label.go * update comments * Update routers/org/setting.go Co-authored-by: Lauris BH <lauris@nix.lv> Co-authored-by: guillep2k <18600385+guillep2k@users.noreply.github.com> Co-authored-by: 6543 <6543@obermui.de>
4 years ago
Add Organization Wide Labels (#10814) * Add organization wide labels Implement organization wide labels similar to organization wide webhooks. This lets you create individual labels for organizations that can be used for all repos under that organization (so being able to reuse the same label across multiple repos). This makes it possible for small organizations with many repos to use labels effectively. Fixes #7406 * Add migration * remove comments * fix tests * Update options/locale/locale_en-US.ini Removed unused translation string * show org labels in issue search label filter * Use more clear var name * rename migration after merge from master * comment typo * update migration again after rebase with master * check for orgID <=0 per guillep2k review * fmt * Apply suggestions from code review Co-Authored-By: guillep2k <18600385+guillep2k@users.noreply.github.com> * remove unused code * Make sure RepoID is 0 when searching orgID per code review * more changes/code review requests * More descriptive translation var per code review * func description/delete comment when issue label deleted instead of hiding it * remove comment * only use issues in that repo when calculating number of open issues for org label on repo label page * Add integration test for IssuesSearch API with labels * remove unused function * Update models/issue_label.go Co-Authored-By: guillep2k <18600385+guillep2k@users.noreply.github.com> * Use subquery in GetLabelIDsInReposByNames * Fix tests to use correct orgID * fix more tests * IssuesSearch api now uses new BuildLabelNamesIssueIDsCondition. Add a few more tests as well * update comment for clarity * Revert previous code change now that we can use the new BuildLabelNamesIssueIDsCondition * Don't sort repos by date in IssuesSearch API After much debugging I've found a strange issue where in some cases MySQL will return a different result than other enigines if a query is sorted by a null collumn. For example with our integration test data where we don't set updated_unix in repository fixtures: SELECT `id`, `owner_id`, `owner_name`, `lower_name`, `name`, `description`, `website`, `original_service_type`, `original_url`, `default_branch`, `num_watches`, `num_stars`, `num_forks`, `num_issues`, `num_closed_issues`, `num_pulls`, `num_closed_pulls`, `num_milestones`, `num_closed_milestones`, `is_private`, `is_empty`, `is_archived`, `is_mirror`, `status`, `is_fork`, `fork_id`, `is_template`, `template_id`, `size`, `is_fsck_enabled`, `close_issues_via_commit_in_any_branch`, `topics`, `avatar`, `created_unix`, `updated_unix` FROM `repository` ORDER BY updated_unix DESC LIMIT 15 OFFSET 45 Returns different results for MySQL than other engines. However, the similar query: SELECT `id`, `owner_id`, `owner_name`, `lower_name`, `name`, `description`, `website`, `original_service_type`, `original_url`, `default_branch`, `num_watches`, `num_stars`, `num_forks`, `num_issues`, `num_closed_issues`, `num_pulls`, `num_closed_pulls`, `num_milestones`, `num_closed_milestones`, `is_private`, `is_empty`, `is_archived`, `is_mirror`, `status`, `is_fork`, `fork_id`, `is_template`, `template_id`, `size`, `is_fsck_enabled`, `close_issues_via_commit_in_any_branch`, `topics`, `avatar`, `created_unix`, `updated_unix` FROM `repository` ORDER BY updated_unix DESC LIMIT 15 OFFSET 30 Returns the same results. This causes integration tests to fail on MySQL in certain cases but would never show up in a real installation. Since this API call always returns issues based on the optionally provided repo_priority_id or the issueID itself, there is no change to results by changing the repo sorting method used to get ids earlier in the function. * linter is back! * code review * remove now unused option * Fix newline at end of files * more unused code * update to master * check for matching ids before query * Update models/issue_label.go Co-Authored-By: 6543 <6543@obermui.de> * Update models/issue_label.go * update comments * Update routers/org/setting.go Co-authored-by: Lauris BH <lauris@nix.lv> Co-authored-by: guillep2k <18600385+guillep2k@users.noreply.github.com> Co-authored-by: 6543 <6543@obermui.de>
4 years ago
Add Organization Wide Labels (#10814) * Add organization wide labels Implement organization wide labels similar to organization wide webhooks. This lets you create individual labels for organizations that can be used for all repos under that organization (so being able to reuse the same label across multiple repos). This makes it possible for small organizations with many repos to use labels effectively. Fixes #7406 * Add migration * remove comments * fix tests * Update options/locale/locale_en-US.ini Removed unused translation string * show org labels in issue search label filter * Use more clear var name * rename migration after merge from master * comment typo * update migration again after rebase with master * check for orgID <=0 per guillep2k review * fmt * Apply suggestions from code review Co-Authored-By: guillep2k <18600385+guillep2k@users.noreply.github.com> * remove unused code * Make sure RepoID is 0 when searching orgID per code review * more changes/code review requests * More descriptive translation var per code review * func description/delete comment when issue label deleted instead of hiding it * remove comment * only use issues in that repo when calculating number of open issues for org label on repo label page * Add integration test for IssuesSearch API with labels * remove unused function * Update models/issue_label.go Co-Authored-By: guillep2k <18600385+guillep2k@users.noreply.github.com> * Use subquery in GetLabelIDsInReposByNames * Fix tests to use correct orgID * fix more tests * IssuesSearch api now uses new BuildLabelNamesIssueIDsCondition. Add a few more tests as well * update comment for clarity * Revert previous code change now that we can use the new BuildLabelNamesIssueIDsCondition * Don't sort repos by date in IssuesSearch API After much debugging I've found a strange issue where in some cases MySQL will return a different result than other enigines if a query is sorted by a null collumn. For example with our integration test data where we don't set updated_unix in repository fixtures: SELECT `id`, `owner_id`, `owner_name`, `lower_name`, `name`, `description`, `website`, `original_service_type`, `original_url`, `default_branch`, `num_watches`, `num_stars`, `num_forks`, `num_issues`, `num_closed_issues`, `num_pulls`, `num_closed_pulls`, `num_milestones`, `num_closed_milestones`, `is_private`, `is_empty`, `is_archived`, `is_mirror`, `status`, `is_fork`, `fork_id`, `is_template`, `template_id`, `size`, `is_fsck_enabled`, `close_issues_via_commit_in_any_branch`, `topics`, `avatar`, `created_unix`, `updated_unix` FROM `repository` ORDER BY updated_unix DESC LIMIT 15 OFFSET 45 Returns different results for MySQL than other engines. However, the similar query: SELECT `id`, `owner_id`, `owner_name`, `lower_name`, `name`, `description`, `website`, `original_service_type`, `original_url`, `default_branch`, `num_watches`, `num_stars`, `num_forks`, `num_issues`, `num_closed_issues`, `num_pulls`, `num_closed_pulls`, `num_milestones`, `num_closed_milestones`, `is_private`, `is_empty`, `is_archived`, `is_mirror`, `status`, `is_fork`, `fork_id`, `is_template`, `template_id`, `size`, `is_fsck_enabled`, `close_issues_via_commit_in_any_branch`, `topics`, `avatar`, `created_unix`, `updated_unix` FROM `repository` ORDER BY updated_unix DESC LIMIT 15 OFFSET 30 Returns the same results. This causes integration tests to fail on MySQL in certain cases but would never show up in a real installation. Since this API call always returns issues based on the optionally provided repo_priority_id or the issueID itself, there is no change to results by changing the repo sorting method used to get ids earlier in the function. * linter is back! * code review * remove now unused option * Fix newline at end of files * more unused code * update to master * check for matching ids before query * Update models/issue_label.go Co-Authored-By: 6543 <6543@obermui.de> * Update models/issue_label.go * update comments * Update routers/org/setting.go Co-authored-by: Lauris BH <lauris@nix.lv> Co-authored-by: guillep2k <18600385+guillep2k@users.noreply.github.com> Co-authored-by: 6543 <6543@obermui.de>
4 years ago
Add Organization Wide Labels (#10814) * Add organization wide labels Implement organization wide labels similar to organization wide webhooks. This lets you create individual labels for organizations that can be used for all repos under that organization (so being able to reuse the same label across multiple repos). This makes it possible for small organizations with many repos to use labels effectively. Fixes #7406 * Add migration * remove comments * fix tests * Update options/locale/locale_en-US.ini Removed unused translation string * show org labels in issue search label filter * Use more clear var name * rename migration after merge from master * comment typo * update migration again after rebase with master * check for orgID <=0 per guillep2k review * fmt * Apply suggestions from code review Co-Authored-By: guillep2k <18600385+guillep2k@users.noreply.github.com> * remove unused code * Make sure RepoID is 0 when searching orgID per code review * more changes/code review requests * More descriptive translation var per code review * func description/delete comment when issue label deleted instead of hiding it * remove comment * only use issues in that repo when calculating number of open issues for org label on repo label page * Add integration test for IssuesSearch API with labels * remove unused function * Update models/issue_label.go Co-Authored-By: guillep2k <18600385+guillep2k@users.noreply.github.com> * Use subquery in GetLabelIDsInReposByNames * Fix tests to use correct orgID * fix more tests * IssuesSearch api now uses new BuildLabelNamesIssueIDsCondition. Add a few more tests as well * update comment for clarity * Revert previous code change now that we can use the new BuildLabelNamesIssueIDsCondition * Don't sort repos by date in IssuesSearch API After much debugging I've found a strange issue where in some cases MySQL will return a different result than other enigines if a query is sorted by a null collumn. For example with our integration test data where we don't set updated_unix in repository fixtures: SELECT `id`, `owner_id`, `owner_name`, `lower_name`, `name`, `description`, `website`, `original_service_type`, `original_url`, `default_branch`, `num_watches`, `num_stars`, `num_forks`, `num_issues`, `num_closed_issues`, `num_pulls`, `num_closed_pulls`, `num_milestones`, `num_closed_milestones`, `is_private`, `is_empty`, `is_archived`, `is_mirror`, `status`, `is_fork`, `fork_id`, `is_template`, `template_id`, `size`, `is_fsck_enabled`, `close_issues_via_commit_in_any_branch`, `topics`, `avatar`, `created_unix`, `updated_unix` FROM `repository` ORDER BY updated_unix DESC LIMIT 15 OFFSET 45 Returns different results for MySQL than other engines. However, the similar query: SELECT `id`, `owner_id`, `owner_name`, `lower_name`, `name`, `description`, `website`, `original_service_type`, `original_url`, `default_branch`, `num_watches`, `num_stars`, `num_forks`, `num_issues`, `num_closed_issues`, `num_pulls`, `num_closed_pulls`, `num_milestones`, `num_closed_milestones`, `is_private`, `is_empty`, `is_archived`, `is_mirror`, `status`, `is_fork`, `fork_id`, `is_template`, `template_id`, `size`, `is_fsck_enabled`, `close_issues_via_commit_in_any_branch`, `topics`, `avatar`, `created_unix`, `updated_unix` FROM `repository` ORDER BY updated_unix DESC LIMIT 15 OFFSET 30 Returns the same results. This causes integration tests to fail on MySQL in certain cases but would never show up in a real installation. Since this API call always returns issues based on the optionally provided repo_priority_id or the issueID itself, there is no change to results by changing the repo sorting method used to get ids earlier in the function. * linter is back! * code review * remove now unused option * Fix newline at end of files * more unused code * update to master * check for matching ids before query * Update models/issue_label.go Co-Authored-By: 6543 <6543@obermui.de> * Update models/issue_label.go * update comments * Update routers/org/setting.go Co-authored-by: Lauris BH <lauris@nix.lv> Co-authored-by: guillep2k <18600385+guillep2k@users.noreply.github.com> Co-authored-by: 6543 <6543@obermui.de>
4 years ago
  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.GetLabelByID(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, "GetLabelByID", 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.GetLabelsByIDs(form.Labels)
  282. if err != nil {
  283. ctx.Error(http.StatusInternalServerError, "GetLabelsByIDs", err)
  284. return
  285. }
  286. if !ctx.Repo.CanWriteIssuesOrPulls(issue.IsPull) {
  287. ctx.Status(http.StatusForbidden)
  288. return
  289. }
  290. return
  291. }