diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go index 6e800fdee8..2245f9093a 100644 --- a/routers/api/v1/api.go +++ b/routers/api/v1/api.go @@ -1265,7 +1265,11 @@ func Routes() *web.Route { m.Combo(""). Get(repo.GetPullReviewComments). Post(reqToken(), bind(api.CreatePullReviewCommentOptions{}), repo.CreatePullReviewComment) - m.Get("/{comment}", commentAssignment("comment"), repo.GetPullReviewComment) + m.Group("/{comment}", func() { + m.Combo(""). + Get(repo.GetPullReviewComment). + Delete(reqToken(), repo.DeletePullReviewComment) + }, commentAssignment("comment")) }) m.Post("/dismissals", reqToken(), bind(api.DismissPullReviewOptions{}), repo.DismissPullReview) m.Post("/undismissals", reqToken(), repo.UnDismissPullReview) diff --git a/routers/api/v1/repo/issue_comment.go b/routers/api/v1/repo/issue_comment.go index 91de21db40..7cd44762e3 100644 --- a/routers/api/v1/repo/issue_comment.go +++ b/routers/api/v1/repo/issue_comment.go @@ -624,7 +624,7 @@ func DeleteIssueComment(ctx *context.APIContext) { // "404": // "$ref": "#/responses/notFound" - deleteIssueComment(ctx) + deleteIssueComment(ctx, issues_model.CommentTypeComment) } // DeleteIssueCommentDeprecated delete a comment from an issue @@ -663,16 +663,16 @@ func DeleteIssueCommentDeprecated(ctx *context.APIContext) { // "404": // "$ref": "#/responses/notFound" - deleteIssueComment(ctx) + deleteIssueComment(ctx, issues_model.CommentTypeComment) } -func deleteIssueComment(ctx *context.APIContext) { +func deleteIssueComment(ctx *context.APIContext, commentType issues_model.CommentType) { comment := ctx.Comment if !ctx.IsSigned || (ctx.Doer.ID != comment.PosterID && !ctx.Repo.CanWriteIssuesOrPulls(comment.Issue.IsPull)) { ctx.Status(http.StatusForbidden) return - } else if comment.Type != issues_model.CommentTypeComment { + } else if comment.Type != commentType { ctx.Status(http.StatusNoContent) return } diff --git a/routers/api/v1/repo/pull_review.go b/routers/api/v1/repo/pull_review.go index ad9e2c5981..ab8deab362 100644 --- a/routers/api/v1/repo/pull_review.go +++ b/routers/api/v1/repo/pull_review.go @@ -1014,6 +1014,53 @@ func UnDismissPullReview(ctx *context.APIContext) { dismissReview(ctx, "", false, false) } +// DeletePullReviewComment delete a pull review comment +func DeletePullReviewComment(ctx *context.APIContext) { + // swagger:operation DELETE /repos/{owner}/{repo}/pulls/{index}/reviews/{id}/comments/{comment} repository repoDeletePullReviewComment + // --- + // summary: Delete a pull review comment + // 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: comment + // in: path + // description: id of the comment + // type: integer + // format: int64 + // required: true + // responses: + // "204": + // "$ref": "#/responses/empty" + // "403": + // "$ref": "#/responses/forbidden" + // "404": + // "$ref": "#/responses/notFound" + + deleteIssueComment(ctx, issues_model.CommentTypeCode) +} + func dismissReview(ctx *context.APIContext, msg string, isDismiss, dismissPriors bool) { if !ctx.Repo.IsAdmin() { ctx.Error(http.StatusForbidden, "", "Must be repo admin") diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl index 1c5ef5ab29..453d8b0809 100644 --- a/templates/swagger/v1_json.tmpl +++ b/templates/swagger/v1_json.tmpl @@ -11666,6 +11666,67 @@ "$ref": "#/responses/notFound" } } + }, + "delete": { + "produces": [ + "application/json" + ], + "tags": [ + "repository" + ], + "summary": "Delete a pull review comment", + "operationId": "repoDeletePullReviewComment", + "parameters": [ + { + "type": "string", + "description": "owner of the repo", + "name": "owner", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "name of the repo", + "name": "repo", + "in": "path", + "required": true + }, + { + "type": "integer", + "format": "int64", + "description": "index of the pull request", + "name": "index", + "in": "path", + "required": true + }, + { + "type": "integer", + "format": "int64", + "description": "id of the review", + "name": "id", + "in": "path", + "required": true + }, + { + "type": "integer", + "format": "int64", + "description": "id of the comment", + "name": "comment", + "in": "path", + "required": true + } + ], + "responses": { + "204": { + "$ref": "#/responses/empty" + }, + "403": { + "$ref": "#/responses/forbidden" + }, + "404": { + "$ref": "#/responses/notFound" + } + } } }, "/repos/{owner}/{repo}/pulls/{index}/reviews/{id}/dismissals": { diff --git a/tests/integration/api_pull_review_test.go b/tests/integration/api_pull_review_test.go index db44e1ade5..c66c7d752d 100644 --- a/tests/integration/api_pull_review_test.go +++ b/tests/integration/api_pull_review_test.go @@ -21,7 +21,7 @@ import ( "github.com/stretchr/testify/require" ) -func TestAPIPullReviewCreateComment(t *testing.T) { +func TestAPIPullReviewCreateDeleteComment(t *testing.T) { defer tests.PrepareTestEnv(t)() pullIssue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 3}) assert.NoError(t, pullIssue.LoadAttributes(db.DefaultContext)) @@ -47,6 +47,30 @@ func TestAPIPullReviewCreateComment(t *testing.T) { var review api.PullReview var reviewLine int64 = 1 + // cleanup + { + session := loginUser(t, "user1") + token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeAll) + + req := NewRequestf(t, http.MethodGet, "/api/v1/repos/%s/pulls/%d/reviews", repo.FullName(), pullIssue.Index).AddTokenAuth(token) + resp := MakeRequest(t, req, http.StatusOK) + var reviews []*api.PullReview + DecodeJSON(t, resp, &reviews) + for _, review := range reviews { + req := NewRequestf(t, http.MethodDelete, "/api/v1/repos/%s/pulls/%d/reviews/%d", repo.FullName(), pullIssue.Index, review.ID). + AddTokenAuth(token) + MakeRequest(t, req, http.StatusNoContent) + } + } + + requireReviewCount := func(count int) { + req := NewRequestf(t, http.MethodGet, "/api/v1/repos/%s/pulls/%d/reviews", repo.FullName(), pullIssue.Index).AddTokenAuth(token) + resp := MakeRequest(t, req, http.StatusOK) + var reviews []*api.PullReview + DecodeJSON(t, resp, &reviews) + require.EqualValues(t, count, len(reviews)) + } + { req := NewRequestWithJSON(t, http.MethodPost, fmt.Sprintf("/api/v1/repos/%s/pulls/%d/reviews", repo.FullName(), pullIssue.Index), &api.CreatePullReviewOptions{ Body: "body1", @@ -66,6 +90,7 @@ func TestAPIPullReviewCreateComment(t *testing.T) { DecodeJSON(t, resp, &getReview) require.EqualValues(t, getReview, review) } + requireReviewCount(1) newCommentBody := "first new line" var reviewComment api.PullReviewComment @@ -95,11 +120,24 @@ func TestAPIPullReviewCreateComment(t *testing.T) { assert.EqualValues(t, reviewComment, comment) } + { + req := NewRequestf(t, http.MethodDelete, "/api/v1/repos/%s/pulls/%d/reviews/%d/comments/%d", repo.FullName(), pullIssue.Index, review.ID, reviewComment.ID). + AddTokenAuth(token) + MakeRequest(t, req, http.StatusNoContent) + } + + { + req := NewRequestf(t, http.MethodGet, "/api/v1/repos/%s/pulls/%d/reviews/%d/comments/%d", repo.FullName(), pullIssue.Index, review.ID, reviewComment.ID). + AddTokenAuth(token) + MakeRequest(t, req, http.StatusNotFound) + } + { req := NewRequestf(t, http.MethodDelete, "/api/v1/repos/%s/pulls/%d/reviews/%d", repo.FullName(), pullIssue.Index, review.ID). AddTokenAuth(token) MakeRequest(t, req, http.StatusNoContent) } + requireReviewCount(0) }) } }