mirror of
				https://gitee.com/gitea/gitea
				synced 2025-11-04 00:20:25 +08:00 
			
		
		
		
	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>
			
			
This commit is contained in:
		@@ -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").
 | 
			
		||||
 
 | 
			
		||||
@@ -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)
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -150,6 +150,9 @@ type swaggerParameterBodies struct {
 | 
			
		||||
	// in:body
 | 
			
		||||
	SubmitPullReviewOptions api.SubmitPullReviewOptions
 | 
			
		||||
 | 
			
		||||
	// in:body
 | 
			
		||||
	DismissPullReviewOptions api.DismissPullReviewOptions
 | 
			
		||||
 | 
			
		||||
	// in:body
 | 
			
		||||
	MigrateRepoOptions api.MigrateRepoOptions
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user