You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

issue_reaction.go 11 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415
  1. // Copyright 2019 The Gitea Authors. All rights reserved.
  2. // Use of this source code is governed by a MIT-style
  3. // license that can be found in the LICENSE file.
  4. package repo
  5. import (
  6. "errors"
  7. "net/http"
  8. "code.gitea.io/gitea/models"
  9. "code.gitea.io/gitea/modules/context"
  10. api "code.gitea.io/gitea/modules/structs"
  11. )
  12. // GetIssueCommentReactions list reactions of a issue comment
  13. func GetIssueCommentReactions(ctx *context.APIContext) {
  14. // swagger:operation GET /repos/{owner}/{repo}/issues/comments/{id}/reactions issue issueGetCommentReactions
  15. // ---
  16. // summary: Get a list reactions of a issue comment
  17. // consumes:
  18. // - application/json
  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: id
  33. // in: path
  34. // description: id of the comment to edit
  35. // type: integer
  36. // format: int64
  37. // required: true
  38. // responses:
  39. // "200":
  40. // "$ref": "#/responses/ReactionResponseList"
  41. // "403":
  42. // "$ref": "#/responses/forbidden"
  43. comment, err := models.GetCommentByID(ctx.ParamsInt64(":id"))
  44. if err != nil {
  45. if models.IsErrCommentNotExist(err) {
  46. ctx.NotFound(err)
  47. } else {
  48. ctx.Error(http.StatusInternalServerError, "GetCommentByID", err)
  49. }
  50. return
  51. }
  52. if !ctx.Repo.CanRead(models.UnitTypeIssues) && !ctx.User.IsAdmin {
  53. ctx.Error(http.StatusForbidden, "GetIssueCommentReactions", errors.New("no permission to get reactions"))
  54. return
  55. }
  56. reactions, err := models.FindCommentReactions(comment)
  57. if err != nil {
  58. ctx.Error(http.StatusInternalServerError, "FindIssueReactions", err)
  59. return
  60. }
  61. _, err = reactions.LoadUsers()
  62. if err != nil {
  63. ctx.Error(http.StatusInternalServerError, "ReactionList.LoadUsers()", err)
  64. return
  65. }
  66. var result []api.ReactionResponse
  67. for _, r := range reactions {
  68. result = append(result, api.ReactionResponse{
  69. User: r.User.APIFormat(),
  70. Reaction: r.Type,
  71. Created: r.CreatedUnix.AsTime(),
  72. })
  73. }
  74. ctx.JSON(http.StatusOK, result)
  75. }
  76. // PostIssueCommentReaction add a reaction to a comment of a issue
  77. func PostIssueCommentReaction(ctx *context.APIContext, form api.EditReactionOption) {
  78. // swagger:operation POST /repos/{owner}/{repo}/issues/comments/{id}/reactions issue issuePostCommentReaction
  79. // ---
  80. // summary: Add a reaction to a comment of a issue comment
  81. // consumes:
  82. // - application/json
  83. // produces:
  84. // - application/json
  85. // parameters:
  86. // - name: owner
  87. // in: path
  88. // description: owner of the repo
  89. // type: string
  90. // required: true
  91. // - name: repo
  92. // in: path
  93. // description: name of the repo
  94. // type: string
  95. // required: true
  96. // - name: id
  97. // in: path
  98. // description: id of the comment to edit
  99. // type: integer
  100. // format: int64
  101. // required: true
  102. // - name: content
  103. // in: body
  104. // schema:
  105. // "$ref": "#/definitions/EditReactionOption"
  106. // responses:
  107. // "201":
  108. // "$ref": "#/responses/ReactionResponse"
  109. // "403":
  110. // "$ref": "#/responses/forbidden"
  111. changeIssueCommentReaction(ctx, form, true)
  112. }
  113. // DeleteIssueCommentReaction list reactions of a issue comment
  114. func DeleteIssueCommentReaction(ctx *context.APIContext, form api.EditReactionOption) {
  115. // swagger:operation DELETE /repos/{owner}/{repo}/issues/comments/{id}/reactions issue issueDeleteCommentReaction
  116. // ---
  117. // summary: Remove a reaction from a comment of a issue comment
  118. // consumes:
  119. // - application/json
  120. // produces:
  121. // - application/json
  122. // parameters:
  123. // - name: owner
  124. // in: path
  125. // description: owner of the repo
  126. // type: string
  127. // required: true
  128. // - name: repo
  129. // in: path
  130. // description: name of the repo
  131. // type: string
  132. // required: true
  133. // - name: id
  134. // in: path
  135. // description: id of the comment to edit
  136. // type: integer
  137. // format: int64
  138. // required: true
  139. // - name: content
  140. // in: body
  141. // schema:
  142. // "$ref": "#/definitions/EditReactionOption"
  143. // responses:
  144. // "200":
  145. // "$ref": "#/responses/empty"
  146. // "403":
  147. // "$ref": "#/responses/forbidden"
  148. changeIssueCommentReaction(ctx, form, false)
  149. }
  150. func changeIssueCommentReaction(ctx *context.APIContext, form api.EditReactionOption, isCreateType bool) {
  151. comment, err := models.GetCommentByID(ctx.ParamsInt64(":id"))
  152. if err != nil {
  153. if models.IsErrCommentNotExist(err) {
  154. ctx.NotFound(err)
  155. } else {
  156. ctx.Error(http.StatusInternalServerError, "GetCommentByID", err)
  157. }
  158. return
  159. }
  160. err = comment.LoadIssue()
  161. if err != nil {
  162. ctx.Error(http.StatusInternalServerError, "comment.LoadIssue() failed", err)
  163. }
  164. if comment.Issue.IsLocked && !ctx.Repo.CanWrite(models.UnitTypeIssues) && !ctx.User.IsAdmin {
  165. ctx.Error(http.StatusForbidden, "ChangeIssueCommentReaction", errors.New("no permission to change reaction"))
  166. return
  167. }
  168. if isCreateType {
  169. // PostIssueCommentReaction part
  170. reaction, err := models.CreateCommentReaction(ctx.User, comment.Issue, comment, form.Reaction)
  171. if err != nil {
  172. if models.IsErrForbiddenIssueReaction(err) {
  173. ctx.Error(http.StatusForbidden, err.Error(), err)
  174. } else {
  175. ctx.Error(http.StatusInternalServerError, "CreateCommentReaction", err)
  176. }
  177. return
  178. }
  179. _, err = reaction.LoadUser()
  180. if err != nil {
  181. ctx.Error(http.StatusInternalServerError, "Reaction.LoadUser()", err)
  182. return
  183. }
  184. ctx.JSON(http.StatusCreated, api.ReactionResponse{
  185. User: reaction.User.APIFormat(),
  186. Reaction: reaction.Type,
  187. Created: reaction.CreatedUnix.AsTime(),
  188. })
  189. } else {
  190. // DeleteIssueCommentReaction part
  191. err = models.DeleteCommentReaction(ctx.User, comment.Issue, comment, form.Reaction)
  192. if err != nil {
  193. ctx.Error(http.StatusInternalServerError, "DeleteCommentReaction", err)
  194. return
  195. }
  196. //ToDo respond 204
  197. ctx.Status(http.StatusOK)
  198. }
  199. }
  200. // GetIssueReactions list reactions of a issue comment
  201. func GetIssueReactions(ctx *context.APIContext) {
  202. // swagger:operation GET /repos/{owner}/{repo}/issues/{index}/reactions issue issueGetIssueReactions
  203. // ---
  204. // summary: Get a list reactions of a issue
  205. // consumes:
  206. // - application/json
  207. // produces:
  208. // - application/json
  209. // parameters:
  210. // - name: owner
  211. // in: path
  212. // description: owner of the repo
  213. // type: string
  214. // required: true
  215. // - name: repo
  216. // in: path
  217. // description: name of the repo
  218. // type: string
  219. // required: true
  220. // - name: index
  221. // in: path
  222. // description: index of the issue
  223. // type: integer
  224. // format: int64
  225. // required: true
  226. // responses:
  227. // "200":
  228. // "$ref": "#/responses/ReactionResponseList"
  229. // "403":
  230. // "$ref": "#/responses/forbidden"
  231. issue, err := models.GetIssueWithAttrsByIndex(ctx.Repo.Repository.ID, ctx.ParamsInt64(":index"))
  232. if err != nil {
  233. if models.IsErrIssueNotExist(err) {
  234. ctx.NotFound()
  235. } else {
  236. ctx.Error(http.StatusInternalServerError, "GetIssueByIndex", err)
  237. }
  238. return
  239. }
  240. if !ctx.Repo.CanRead(models.UnitTypeIssues) && !ctx.User.IsAdmin {
  241. ctx.Error(http.StatusForbidden, "GetIssueReactions", errors.New("no permission to get reactions"))
  242. return
  243. }
  244. reactions, err := models.FindIssueReactions(issue)
  245. if err != nil {
  246. ctx.Error(http.StatusInternalServerError, "FindIssueReactions", err)
  247. return
  248. }
  249. _, err = reactions.LoadUsers()
  250. if err != nil {
  251. ctx.Error(http.StatusInternalServerError, "ReactionList.LoadUsers()", err)
  252. return
  253. }
  254. var result []api.ReactionResponse
  255. for _, r := range reactions {
  256. result = append(result, api.ReactionResponse{
  257. User: r.User.APIFormat(),
  258. Reaction: r.Type,
  259. Created: r.CreatedUnix.AsTime(),
  260. })
  261. }
  262. ctx.JSON(http.StatusOK, result)
  263. }
  264. // PostIssueReaction add a reaction to a comment of a issue
  265. func PostIssueReaction(ctx *context.APIContext, form api.EditReactionOption) {
  266. // swagger:operation POST /repos/{owner}/{repo}/issues/{index}/reactions issue issuePostIssueReaction
  267. // ---
  268. // summary: Add a reaction to a comment of a issue
  269. // consumes:
  270. // - application/json
  271. // produces:
  272. // - application/json
  273. // parameters:
  274. // - name: owner
  275. // in: path
  276. // description: owner of the repo
  277. // type: string
  278. // required: true
  279. // - name: repo
  280. // in: path
  281. // description: name of the repo
  282. // type: string
  283. // required: true
  284. // - name: index
  285. // in: path
  286. // description: index of the issue
  287. // type: integer
  288. // format: int64
  289. // required: true
  290. // - name: content
  291. // in: body
  292. // schema:
  293. // "$ref": "#/definitions/EditReactionOption"
  294. // responses:
  295. // "201":
  296. // "$ref": "#/responses/ReactionResponse"
  297. // "403":
  298. // "$ref": "#/responses/forbidden"
  299. changeIssueReaction(ctx, form, true)
  300. }
  301. // DeleteIssueReaction list reactions of a issue comment
  302. func DeleteIssueReaction(ctx *context.APIContext, form api.EditReactionOption) {
  303. // swagger:operation DELETE /repos/{owner}/{repo}/issues/{index}/reactions issue issueDeleteIssueReaction
  304. // ---
  305. // summary: Remove a reaction from a comment of a issue
  306. // consumes:
  307. // - application/json
  308. // produces:
  309. // - application/json
  310. // parameters:
  311. // - name: owner
  312. // in: path
  313. // description: owner of the repo
  314. // type: string
  315. // required: true
  316. // - name: repo
  317. // in: path
  318. // description: name of the repo
  319. // type: string
  320. // required: true
  321. // - name: index
  322. // in: path
  323. // description: index of the issue
  324. // type: integer
  325. // format: int64
  326. // required: true
  327. // - name: content
  328. // in: body
  329. // schema:
  330. // "$ref": "#/definitions/EditReactionOption"
  331. // responses:
  332. // "200":
  333. // "$ref": "#/responses/empty"
  334. // "403":
  335. // "$ref": "#/responses/forbidden"
  336. changeIssueReaction(ctx, form, false)
  337. }
  338. func changeIssueReaction(ctx *context.APIContext, form api.EditReactionOption, isCreateType bool) {
  339. issue, err := models.GetIssueWithAttrsByIndex(ctx.Repo.Repository.ID, ctx.ParamsInt64(":index"))
  340. if err != nil {
  341. if models.IsErrIssueNotExist(err) {
  342. ctx.NotFound()
  343. } else {
  344. ctx.Error(http.StatusInternalServerError, "GetIssueByIndex", err)
  345. }
  346. return
  347. }
  348. if issue.IsLocked && !ctx.Repo.CanWrite(models.UnitTypeIssues) && !ctx.User.IsAdmin {
  349. ctx.Error(http.StatusForbidden, "ChangeIssueCommentReaction", errors.New("no permission to change reaction"))
  350. return
  351. }
  352. if isCreateType {
  353. // PostIssueReaction part
  354. reaction, err := models.CreateIssueReaction(ctx.User, issue, form.Reaction)
  355. if err != nil {
  356. if models.IsErrForbiddenIssueReaction(err) {
  357. ctx.Error(http.StatusForbidden, err.Error(), err)
  358. } else {
  359. ctx.Error(http.StatusInternalServerError, "CreateCommentReaction", err)
  360. }
  361. return
  362. }
  363. _, err = reaction.LoadUser()
  364. if err != nil {
  365. ctx.Error(http.StatusInternalServerError, "Reaction.LoadUser()", err)
  366. return
  367. }
  368. ctx.JSON(http.StatusCreated, api.ReactionResponse{
  369. User: reaction.User.APIFormat(),
  370. Reaction: reaction.Type,
  371. Created: reaction.CreatedUnix.AsTime(),
  372. })
  373. } else {
  374. // DeleteIssueReaction part
  375. err = models.DeleteIssueReaction(ctx.User, issue, form.Reaction)
  376. if err != nil {
  377. ctx.Error(http.StatusInternalServerError, "DeleteIssueReaction", err)
  378. return
  379. }
  380. //ToDo respond 204
  381. ctx.Status(http.StatusOK)
  382. }
  383. }