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 10KB

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