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.

issue_comment.go 9.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387
  1. // Copyright 2015 The Gogs 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. "time"
  8. "code.gitea.io/gitea/models"
  9. "code.gitea.io/gitea/modules/context"
  10. "code.gitea.io/gitea/modules/notification"
  11. api "code.gitea.io/sdk/gitea"
  12. )
  13. // ListIssueComments list all the comments of an issue
  14. func ListIssueComments(ctx *context.APIContext) {
  15. // swagger:operation GET /repos/{owner}/{repo}/issues/{index}/comments issue issueGetComments
  16. // ---
  17. // summary: List all comments on an issue
  18. // produces:
  19. // - application/json
  20. // parameters:
  21. // - name: owner
  22. // in: path
  23. // description: owner of the repo
  24. // type: string
  25. // required: true
  26. // - name: repo
  27. // in: path
  28. // description: name of the repo
  29. // type: string
  30. // required: true
  31. // - name: index
  32. // in: path
  33. // description: index of the issue
  34. // type: integer
  35. // format: int64
  36. // required: true
  37. // - name: since
  38. // in: query
  39. // description: if provided, only comments updated since the specified time are returned.
  40. // type: string
  41. // responses:
  42. // "200":
  43. // "$ref": "#/responses/CommentList"
  44. var since time.Time
  45. if len(ctx.Query("since")) > 0 {
  46. since, _ = time.Parse(time.RFC3339, ctx.Query("since"))
  47. }
  48. // comments,err:=models.GetCommentsByIssueIDSince(, since)
  49. issue, err := models.GetIssueByIndex(ctx.Repo.Repository.ID, ctx.ParamsInt64(":index"))
  50. if err != nil {
  51. ctx.Error(500, "GetRawIssueByIndex", err)
  52. return
  53. }
  54. comments, err := models.FindComments(models.FindCommentsOptions{
  55. IssueID: issue.ID,
  56. Since: since.Unix(),
  57. Type: models.CommentTypeComment,
  58. })
  59. if err != nil {
  60. ctx.Error(500, "GetCommentsByIssueIDSince", err)
  61. return
  62. }
  63. apiComments := make([]*api.Comment, len(comments))
  64. if err = models.CommentList(comments).LoadPosters(); err != nil {
  65. ctx.Error(500, "LoadPosters", err)
  66. return
  67. }
  68. for i := range comments {
  69. apiComments[i] = comments[i].APIFormat()
  70. }
  71. ctx.JSON(200, &apiComments)
  72. }
  73. // ListRepoIssueComments returns all issue-comments for a repo
  74. func ListRepoIssueComments(ctx *context.APIContext) {
  75. // swagger:operation GET /repos/{owner}/{repo}/issues/comments issue issueGetRepoComments
  76. // ---
  77. // summary: List all comments in a repository
  78. // produces:
  79. // - application/json
  80. // parameters:
  81. // - name: owner
  82. // in: path
  83. // description: owner of the repo
  84. // type: string
  85. // required: true
  86. // - name: repo
  87. // in: path
  88. // description: name of the repo
  89. // type: string
  90. // required: true
  91. // - name: since
  92. // in: query
  93. // description: if provided, only comments updated since the provided time are returned.
  94. // type: string
  95. // responses:
  96. // "200":
  97. // "$ref": "#/responses/CommentList"
  98. var since time.Time
  99. if len(ctx.Query("since")) > 0 {
  100. since, _ = time.Parse(time.RFC3339, ctx.Query("since"))
  101. }
  102. comments, err := models.FindComments(models.FindCommentsOptions{
  103. RepoID: ctx.Repo.Repository.ID,
  104. Since: since.Unix(),
  105. Type: models.CommentTypeComment,
  106. })
  107. if err != nil {
  108. ctx.Error(500, "GetCommentsByRepoIDSince", err)
  109. return
  110. }
  111. if err = models.CommentList(comments).LoadPosters(); err != nil {
  112. ctx.Error(500, "LoadPosters", err)
  113. return
  114. }
  115. apiComments := make([]*api.Comment, len(comments))
  116. for i := range comments {
  117. apiComments[i] = comments[i].APIFormat()
  118. }
  119. ctx.JSON(200, &apiComments)
  120. }
  121. // CreateIssueComment create a comment for an issue
  122. func CreateIssueComment(ctx *context.APIContext, form api.CreateIssueCommentOption) {
  123. // swagger:operation POST /repos/{owner}/{repo}/issues/{index}/comments issue issueCreateComment
  124. // ---
  125. // summary: Add a comment to an issue
  126. // consumes:
  127. // - application/json
  128. // produces:
  129. // - application/json
  130. // parameters:
  131. // - name: owner
  132. // in: path
  133. // description: owner of the repo
  134. // type: string
  135. // required: true
  136. // - name: repo
  137. // in: path
  138. // description: name of the repo
  139. // type: string
  140. // required: true
  141. // - name: index
  142. // in: path
  143. // description: index of the issue
  144. // type: integer
  145. // format: int64
  146. // required: true
  147. // - name: body
  148. // in: body
  149. // schema:
  150. // "$ref": "#/definitions/CreateIssueCommentOption"
  151. // responses:
  152. // "201":
  153. // "$ref": "#/responses/Comment"
  154. issue, err := models.GetIssueByIndex(ctx.Repo.Repository.ID, ctx.ParamsInt64(":index"))
  155. if err != nil {
  156. ctx.Error(500, "GetIssueByIndex", err)
  157. return
  158. }
  159. if issue.IsLocked && !ctx.Repo.CanWrite(models.UnitTypeIssues) && !ctx.User.IsAdmin {
  160. ctx.Error(403, "CreateIssueComment", errors.New(ctx.Tr("repo.issues.comment_on_locked")))
  161. return
  162. }
  163. comment, err := models.CreateIssueComment(ctx.User, ctx.Repo.Repository, issue, form.Body, nil)
  164. if err != nil {
  165. ctx.Error(500, "CreateIssueComment", err)
  166. return
  167. }
  168. notification.NotifyCreateIssueComment(ctx.User, ctx.Repo.Repository, issue, comment)
  169. ctx.JSON(201, comment.APIFormat())
  170. }
  171. // EditIssueComment modify a comment of an issue
  172. func EditIssueComment(ctx *context.APIContext, form api.EditIssueCommentOption) {
  173. // swagger:operation PATCH /repos/{owner}/{repo}/issues/comments/{id} issue issueEditComment
  174. // ---
  175. // summary: Edit a comment
  176. // consumes:
  177. // - application/json
  178. // produces:
  179. // - application/json
  180. // parameters:
  181. // - name: owner
  182. // in: path
  183. // description: owner of the repo
  184. // type: string
  185. // required: true
  186. // - name: repo
  187. // in: path
  188. // description: name of the repo
  189. // type: string
  190. // required: true
  191. // - name: id
  192. // in: path
  193. // description: id of the comment to edit
  194. // type: integer
  195. // format: int64
  196. // required: true
  197. // - name: body
  198. // in: body
  199. // schema:
  200. // "$ref": "#/definitions/EditIssueCommentOption"
  201. // responses:
  202. // "200":
  203. // "$ref": "#/responses/Comment"
  204. editIssueComment(ctx, form)
  205. }
  206. // EditIssueCommentDeprecated modify a comment of an issue
  207. func EditIssueCommentDeprecated(ctx *context.APIContext, form api.EditIssueCommentOption) {
  208. // swagger:operation PATCH /repos/{owner}/{repo}/issues/{index}/comments/{id} issue issueEditCommentDeprecated
  209. // ---
  210. // summary: Edit a comment
  211. // deprecated: true
  212. // consumes:
  213. // - application/json
  214. // produces:
  215. // - application/json
  216. // parameters:
  217. // - name: owner
  218. // in: path
  219. // description: owner of the repo
  220. // type: string
  221. // required: true
  222. // - name: repo
  223. // in: path
  224. // description: name of the repo
  225. // type: string
  226. // required: true
  227. // - name: index
  228. // in: path
  229. // description: this parameter is ignored
  230. // type: integer
  231. // required: true
  232. // - name: id
  233. // in: path
  234. // description: id of the comment to edit
  235. // type: integer
  236. // format: int64
  237. // required: true
  238. // - name: body
  239. // in: body
  240. // schema:
  241. // "$ref": "#/definitions/EditIssueCommentOption"
  242. // responses:
  243. // "200":
  244. // "$ref": "#/responses/Comment"
  245. editIssueComment(ctx, form)
  246. }
  247. func editIssueComment(ctx *context.APIContext, form api.EditIssueCommentOption) {
  248. comment, err := models.GetCommentByID(ctx.ParamsInt64(":id"))
  249. if err != nil {
  250. if models.IsErrCommentNotExist(err) {
  251. ctx.NotFound(err)
  252. } else {
  253. ctx.Error(500, "GetCommentByID", err)
  254. }
  255. return
  256. }
  257. if !ctx.IsSigned || (ctx.User.ID != comment.PosterID && !ctx.Repo.IsAdmin()) {
  258. ctx.Status(403)
  259. return
  260. } else if comment.Type != models.CommentTypeComment {
  261. ctx.Status(204)
  262. return
  263. }
  264. oldContent := comment.Content
  265. comment.Content = form.Body
  266. if err := models.UpdateComment(ctx.User, comment, oldContent); err != nil {
  267. ctx.Error(500, "UpdateComment", err)
  268. return
  269. }
  270. notification.NotifyUpdateComment(ctx.User, comment, oldContent)
  271. ctx.JSON(200, comment.APIFormat())
  272. }
  273. // DeleteIssueComment delete a comment from an issue
  274. func DeleteIssueComment(ctx *context.APIContext) {
  275. // swagger:operation DELETE /repos/{owner}/{repo}/issues/comments/{id} issue issueDeleteComment
  276. // ---
  277. // summary: Delete a comment
  278. // parameters:
  279. // - name: owner
  280. // in: path
  281. // description: owner of the repo
  282. // type: string
  283. // required: true
  284. // - name: repo
  285. // in: path
  286. // description: name of the repo
  287. // type: string
  288. // required: true
  289. // - name: id
  290. // in: path
  291. // description: id of comment to delete
  292. // type: integer
  293. // format: int64
  294. // required: true
  295. // responses:
  296. // "204":
  297. // "$ref": "#/responses/empty"
  298. deleteIssueComment(ctx)
  299. }
  300. // DeleteIssueCommentDeprecated delete a comment from an issue
  301. func DeleteIssueCommentDeprecated(ctx *context.APIContext) {
  302. // swagger:operation DELETE /repos/{owner}/{repo}/issues/{index}/comments/{id} issue issueDeleteCommentDeprecated
  303. // ---
  304. // summary: Delete a comment
  305. // deprecated: true
  306. // parameters:
  307. // - name: owner
  308. // in: path
  309. // description: owner of the repo
  310. // type: string
  311. // required: true
  312. // - name: repo
  313. // in: path
  314. // description: name of the repo
  315. // type: string
  316. // required: true
  317. // - name: index
  318. // in: path
  319. // description: this parameter is ignored
  320. // type: integer
  321. // required: true
  322. // - name: id
  323. // in: path
  324. // description: id of comment to delete
  325. // type: integer
  326. // format: int64
  327. // required: true
  328. // responses:
  329. // "204":
  330. // "$ref": "#/responses/empty"
  331. deleteIssueComment(ctx)
  332. }
  333. func deleteIssueComment(ctx *context.APIContext) {
  334. comment, err := models.GetCommentByID(ctx.ParamsInt64(":id"))
  335. if err != nil {
  336. if models.IsErrCommentNotExist(err) {
  337. ctx.NotFound(err)
  338. } else {
  339. ctx.Error(500, "GetCommentByID", err)
  340. }
  341. return
  342. }
  343. if !ctx.IsSigned || (ctx.User.ID != comment.PosterID && !ctx.Repo.IsAdmin()) {
  344. ctx.Status(403)
  345. return
  346. } else if comment.Type != models.CommentTypeComment {
  347. ctx.Status(204)
  348. return
  349. }
  350. if err = models.DeleteComment(ctx.User, comment); err != nil {
  351. ctx.Error(500, "DeleteCommentByID", err)
  352. return
  353. }
  354. notification.NotifyDeleteComment(ctx.User, comment)
  355. ctx.Status(204)
  356. }