summaryrefslogtreecommitdiffstats
path: root/routers
diff options
context:
space:
mode:
authora1012112796 <1012112796@qq.com>2021-02-12 01:32:25 +0800
committerGitHub <noreply@github.com>2021-02-11 18:32:25 +0100
commitac701637b42d2d6bb5fe9b258f3f54959b6a505e (patch)
tree3020b45f25405036036c7d0cc0a7fc5007b5ab60 /routers
parentc69c01d2b6b08a89448b5596fd2233fa4e802ac3 (diff)
downloadgitea-ac701637b42d2d6bb5fe9b258f3f54959b6a505e.tar.gz
gitea-ac701637b42d2d6bb5fe9b258f3f54959b6a505e.zip
Add dismiss review feature (#12674)
* Add dismiss review feature refs: https://github.blog/2016-10-12-dismissing-reviews-on-pull-requests/ https://developer.github.com/v3/pulls/reviews/#dismiss-a-review-for-a-pull-request * change modal ui and error message * Add unDismissReview api Signed-off-by: a1012112796 <1012112796@qq.com> Co-authored-by: zeripath <art27@cantab.net> Co-authored-by: 6543 <6543@obermui.de>
Diffstat (limited to 'routers')
-rw-r--r--routers/api/v1/api.go2
-rw-r--r--routers/api/v1/repo/pull_review.go126
-rw-r--r--routers/api/v1/swagger/options.go3
-rw-r--r--routers/repo/issue.go2
-rw-r--r--routers/repo/pull_review.go12
-rw-r--r--routers/routes/web.go1
6 files changed, 145 insertions, 1 deletions
diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go
index 9c21107a28..85c4e4d5bf 100644
--- a/routers/api/v1/api.go
+++ b/routers/api/v1/api.go
@@ -891,6 +891,8 @@ func Routes() *web.Route {
Post(reqToken(), bind(api.SubmitPullReviewOptions{}), repo.SubmitPullReview)
m.Combo("/comments").
Get(repo.GetPullReviewComments)
+ m.Post("/dismissals", reqToken(), bind(api.DismissPullReviewOptions{}), repo.DismissPullReview)
+ m.Post("/undismissals", reqToken(), repo.UnDismissPullReview)
})
})
m.Combo("/requested_reviewers").
diff --git a/routers/api/v1/repo/pull_review.go b/routers/api/v1/repo/pull_review.go
index d39db4c660..63179aa990 100644
--- a/routers/api/v1/repo/pull_review.go
+++ b/routers/api/v1/repo/pull_review.go
@@ -757,3 +757,129 @@ func apiReviewRequest(ctx *context.APIContext, opts api.PullReviewRequestOptions
return
}
}
+
+// DismissPullReview dismiss a review for a pull request
+func DismissPullReview(ctx *context.APIContext) {
+ // swagger:operation POST /repos/{owner}/{repo}/pulls/{index}/reviews/{id}/dismissals repository repoDismissPullReview
+ // ---
+ // summary: Dismiss a review for a pull request
+ // produces:
+ // - application/json
+ // parameters:
+ // - name: owner
+ // in: path
+ // description: owner of the repo
+ // type: string
+ // required: true
+ // - name: repo
+ // in: path
+ // description: name of the repo
+ // type: string
+ // required: true
+ // - name: index
+ // in: path
+ // description: index of the pull request
+ // type: integer
+ // format: int64
+ // required: true
+ // - name: id
+ // in: path
+ // description: id of the review
+ // type: integer
+ // format: int64
+ // required: true
+ // - name: body
+ // in: body
+ // required: true
+ // schema:
+ // "$ref": "#/definitions/DismissPullReviewOptions"
+ // responses:
+ // "200":
+ // "$ref": "#/responses/PullReview"
+ // "403":
+ // "$ref": "#/responses/forbidden"
+ // "422":
+ // "$ref": "#/responses/validationError"
+ opts := web.GetForm(ctx).(*api.DismissPullReviewOptions)
+ dismissReview(ctx, opts.Message, true)
+}
+
+// UnDismissPullReview cancel to dismiss a review for a pull request
+func UnDismissPullReview(ctx *context.APIContext) {
+ // swagger:operation POST /repos/{owner}/{repo}/pulls/{index}/reviews/{id}/undismissals repository repoUnDismissPullReview
+ // ---
+ // summary: Cancel to dismiss a review for a pull request
+ // produces:
+ // - application/json
+ // parameters:
+ // - name: owner
+ // in: path
+ // description: owner of the repo
+ // type: string
+ // required: true
+ // - name: repo
+ // in: path
+ // description: name of the repo
+ // type: string
+ // required: true
+ // - name: index
+ // in: path
+ // description: index of the pull request
+ // type: integer
+ // format: int64
+ // required: true
+ // - name: id
+ // in: path
+ // description: id of the review
+ // type: integer
+ // format: int64
+ // required: true
+ // responses:
+ // "200":
+ // "$ref": "#/responses/PullReview"
+ // "403":
+ // "$ref": "#/responses/forbidden"
+ // "422":
+ // "$ref": "#/responses/validationError"
+ dismissReview(ctx, "", false)
+}
+
+func dismissReview(ctx *context.APIContext, msg string, isDismiss bool) {
+ if !ctx.Repo.IsAdmin() {
+ ctx.Error(http.StatusForbidden, "", "Must be repo admin")
+ return
+ }
+ review, pr, isWrong := prepareSingleReview(ctx)
+ if isWrong {
+ return
+ }
+
+ if review.Type != models.ReviewTypeApprove && review.Type != models.ReviewTypeReject {
+ ctx.Error(http.StatusForbidden, "", "not need to dismiss this review because it's type is not Approve or change request")
+ return
+ }
+
+ if pr.Issue.IsClosed {
+ ctx.Error(http.StatusForbidden, "", "not need to dismiss this review because this pr is closed")
+ return
+ }
+
+ _, err := pull_service.DismissReview(review.ID, msg, ctx.User, isDismiss)
+ if err != nil {
+ ctx.Error(http.StatusInternalServerError, "pull_service.DismissReview", err)
+ return
+ }
+
+ if review, err = models.GetReviewByID(review.ID); err != nil {
+ ctx.Error(http.StatusInternalServerError, "GetReviewByID", err)
+ return
+ }
+
+ // convert response
+ apiReview, err := convert.ToPullReview(review, ctx.User)
+ if err != nil {
+ ctx.Error(http.StatusInternalServerError, "convertToPullReview", err)
+ return
+ }
+ ctx.JSON(http.StatusOK, apiReview)
+}
diff --git a/routers/api/v1/swagger/options.go b/routers/api/v1/swagger/options.go
index 8919a969ec..a2dc2193a8 100644
--- a/routers/api/v1/swagger/options.go
+++ b/routers/api/v1/swagger/options.go
@@ -151,6 +151,9 @@ type swaggerParameterBodies struct {
SubmitPullReviewOptions api.SubmitPullReviewOptions
// in:body
+ DismissPullReviewOptions api.DismissPullReviewOptions
+
+ // in:body
MigrateRepoOptions api.MigrateRepoOptions
// in:body
diff --git a/routers/repo/issue.go b/routers/repo/issue.go
index 71c8f1efbb..fa1ee99771 100644
--- a/routers/repo/issue.go
+++ b/routers/repo/issue.go
@@ -1364,7 +1364,7 @@ func ViewIssue(ctx *context.Context) {
return
}
}
- } else if comment.Type == models.CommentTypeCode || comment.Type == models.CommentTypeReview {
+ } else if comment.Type == models.CommentTypeCode || comment.Type == models.CommentTypeReview || comment.Type == models.CommentTypeDismissReview {
comment.RenderedContent = string(markdown.Render([]byte(comment.Content), ctx.Repo.RepoLink,
ctx.Repo.Repository.ComposeMetas()))
if err = comment.LoadReview(); err != nil && !models.IsErrReviewNotExist(err) {
diff --git a/routers/repo/pull_review.go b/routers/repo/pull_review.go
index df49b6cfe1..89e87ccc44 100644
--- a/routers/repo/pull_review.go
+++ b/routers/repo/pull_review.go
@@ -223,3 +223,15 @@ func SubmitReview(ctx *context.Context) {
ctx.Redirect(fmt.Sprintf("%s/pulls/%d#%s", ctx.Repo.RepoLink, issue.Index, comm.HashTag()))
}
+
+// DismissReview dismissing stale review by repo admin
+func DismissReview(ctx *context.Context) {
+ form := web.GetForm(ctx).(*auth.DismissReviewForm)
+ comm, err := pull_service.DismissReview(form.ReviewID, form.Message, ctx.User, true)
+ if err != nil {
+ ctx.ServerError("pull_service.DismissReview", err)
+ return
+ }
+
+ ctx.Redirect(fmt.Sprintf("%s/pulls/%d#%s", ctx.Repo.RepoLink, comm.Issue.Index, comm.HashTag()))
+}
diff --git a/routers/routes/web.go b/routers/routes/web.go
index 9e3e690fb9..2f28e567f9 100644
--- a/routers/routes/web.go
+++ b/routers/routes/web.go
@@ -734,6 +734,7 @@ func RegisterRoutes(m *web.Route) {
m.Post("/projects", reqRepoIssuesOrPullsWriter, repo.UpdateIssueProject)
m.Post("/assignee", reqRepoIssuesOrPullsWriter, repo.UpdateIssueAssignee)
m.Post("/request_review", reqRepoIssuesOrPullsReader, repo.UpdatePullReviewRequest)
+ m.Post("/dismiss_review", reqRepoAdmin, bindIgnErr(auth.DismissReviewForm{}), repo.DismissReview)
m.Post("/status", reqRepoIssuesOrPullsWriter, repo.UpdateIssueStatus)
m.Post("/resolve_conversation", reqRepoIssuesOrPullsReader, repo.UpdateResolveConversation)
m.Post("/attachments", repo.UploadIssueAttachment)