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.

pull_review.go 4.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. // Copyright 2018 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. "fmt"
  7. "code.gitea.io/gitea/models"
  8. "code.gitea.io/gitea/modules/auth"
  9. "code.gitea.io/gitea/modules/context"
  10. "code.gitea.io/gitea/modules/log"
  11. pull_service "code.gitea.io/gitea/services/pull"
  12. )
  13. // CreateCodeComment will create a code comment including an pending review if required
  14. func CreateCodeComment(ctx *context.Context, form auth.CodeCommentForm) {
  15. issue := GetActionIssue(ctx)
  16. if !issue.IsPull {
  17. return
  18. }
  19. if ctx.Written() {
  20. return
  21. }
  22. if ctx.HasError() {
  23. ctx.Flash.Error(ctx.Data["ErrorMsg"].(string))
  24. ctx.Redirect(fmt.Sprintf("%s/pulls/%d/files", ctx.Repo.RepoLink, issue.Index))
  25. return
  26. }
  27. signedLine := form.Line
  28. if form.Side == "previous" {
  29. signedLine *= -1
  30. }
  31. comment, err := pull_service.CreateCodeComment(
  32. ctx.User,
  33. ctx.Repo.GitRepo,
  34. issue,
  35. signedLine,
  36. form.Content,
  37. form.TreePath,
  38. form.IsReview,
  39. form.Reply,
  40. form.LatestCommitID,
  41. )
  42. if err != nil {
  43. ctx.ServerError("CreateCodeComment", err)
  44. return
  45. }
  46. if comment == nil {
  47. log.Trace("Comment not created: %-v #%d[%d]", ctx.Repo.Repository, issue.Index, issue.ID)
  48. ctx.Redirect(fmt.Sprintf("%s/pulls/%d/files", ctx.Repo.RepoLink, issue.Index))
  49. return
  50. }
  51. log.Trace("Comment created: %-v #%d[%d] Comment[%d]", ctx.Repo.Repository, issue.Index, issue.ID, comment.ID)
  52. ctx.Redirect(comment.HTMLURL())
  53. }
  54. // UpdateResolveConversation add or remove an Conversation resolved mark
  55. func UpdateResolveConversation(ctx *context.Context) {
  56. action := ctx.Query("action")
  57. commentID := ctx.QueryInt64("comment_id")
  58. comment, err := models.GetCommentByID(commentID)
  59. if err != nil {
  60. ctx.ServerError("GetIssueByID", err)
  61. return
  62. }
  63. if err = comment.LoadIssue(); err != nil {
  64. ctx.ServerError("comment.LoadIssue", err)
  65. return
  66. }
  67. var permResult bool
  68. if permResult, err = models.CanMarkConversation(comment.Issue, ctx.User); err != nil {
  69. ctx.ServerError("CanMarkConversation", err)
  70. return
  71. }
  72. if !permResult {
  73. ctx.Error(403)
  74. return
  75. }
  76. if !comment.Issue.IsPull {
  77. ctx.Error(400)
  78. return
  79. }
  80. if action == "Resolve" || action == "UnResolve" {
  81. err = models.MarkConversation(comment, ctx.User, action == "Resolve")
  82. if err != nil {
  83. ctx.ServerError("MarkConversation", err)
  84. return
  85. }
  86. } else {
  87. ctx.Error(400)
  88. return
  89. }
  90. ctx.JSON(200, map[string]interface{}{
  91. "ok": true,
  92. })
  93. }
  94. // SubmitReview creates a review out of the existing pending review or creates a new one if no pending review exist
  95. func SubmitReview(ctx *context.Context, form auth.SubmitReviewForm) {
  96. issue := GetActionIssue(ctx)
  97. if !issue.IsPull {
  98. return
  99. }
  100. if ctx.Written() {
  101. return
  102. }
  103. if ctx.HasError() {
  104. ctx.Flash.Error(ctx.Data["ErrorMsg"].(string))
  105. ctx.Redirect(fmt.Sprintf("%s/pulls/%d/files", ctx.Repo.RepoLink, issue.Index))
  106. return
  107. }
  108. reviewType := form.ReviewType()
  109. switch reviewType {
  110. case models.ReviewTypeUnknown:
  111. ctx.ServerError("ReviewType", fmt.Errorf("unknown ReviewType: %s", form.Type))
  112. return
  113. // can not approve/reject your own PR
  114. case models.ReviewTypeApprove, models.ReviewTypeReject:
  115. if issue.IsPoster(ctx.User.ID) {
  116. var translated string
  117. if reviewType == models.ReviewTypeApprove {
  118. translated = ctx.Tr("repo.issues.review.self.approval")
  119. } else {
  120. translated = ctx.Tr("repo.issues.review.self.rejection")
  121. }
  122. ctx.Flash.Error(translated)
  123. ctx.Redirect(fmt.Sprintf("%s/pulls/%d/files", ctx.Repo.RepoLink, issue.Index))
  124. return
  125. }
  126. }
  127. _, comm, err := pull_service.SubmitReview(ctx.User, ctx.Repo.GitRepo, issue, reviewType, form.Content, form.CommitID)
  128. if err != nil {
  129. if models.IsContentEmptyErr(err) {
  130. ctx.Flash.Error(ctx.Tr("repo.issues.review.content.empty"))
  131. ctx.Redirect(fmt.Sprintf("%s/pulls/%d/files", ctx.Repo.RepoLink, issue.Index))
  132. } else {
  133. ctx.ServerError("SubmitReview", err)
  134. }
  135. return
  136. }
  137. ctx.Redirect(fmt.Sprintf("%s/pulls/%d#%s", ctx.Repo.RepoLink, issue.Index, comm.HashTag()))
  138. }