Skip to content

Commit 5ed855d

Browse files
committed
Fix deleting code comment bug
1 parent 3e8aa52 commit 5ed855d

File tree

7 files changed

+99
-17
lines changed

7 files changed

+99
-17
lines changed

models/issues/comment.go

Lines changed: 37 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1122,36 +1122,66 @@ func UpdateComment(ctx context.Context, c *Comment, contentVersion int, doer *us
11221122
}
11231123

11241124
// DeleteComment deletes the comment
1125-
func DeleteComment(ctx context.Context, comment *Comment) error {
1125+
func DeleteComment(ctx context.Context, comment *Comment) (*Comment, error) {
11261126
e := db.GetEngine(ctx)
11271127
if _, err := e.ID(comment.ID).NoAutoCondition().Delete(comment); err != nil {
1128-
return err
1128+
return nil, err
11291129
}
11301130

11311131
if _, err := db.DeleteByBean(ctx, &ContentHistory{
11321132
CommentID: comment.ID,
11331133
}); err != nil {
1134-
return err
1134+
return nil, err
11351135
}
11361136

11371137
if comment.Type.CountedAsConversation() {
11381138
if err := UpdateIssueNumComments(ctx, comment.IssueID); err != nil {
1139-
return err
1139+
return nil, err
11401140
}
11411141
}
11421142
if _, err := e.Table("action").
11431143
Where("comment_id = ?", comment.ID).
11441144
Update(map[string]any{
11451145
"is_deleted": true,
11461146
}); err != nil {
1147-
return err
1147+
return nil, err
1148+
}
1149+
1150+
var deletedReviewComment *Comment
1151+
1152+
// delete review & review comment if the code comment is the last comment of the review
1153+
if comment.Type == CommentTypeCode && comment.ReviewID > 0 {
1154+
res, err := db.GetEngine(ctx).ID(comment.ReviewID).
1155+
Where("NOT EXISTS (SELECT 1 FROM comment WHERE review_id = ? AND `type` = ?)", comment.ReviewID, CommentTypeCode).
1156+
Delete(new(Review))
1157+
if err != nil {
1158+
return nil, err
1159+
}
1160+
if res > 0 {
1161+
var reviewComment Comment
1162+
has, err := db.GetEngine(ctx).Where("review_id = ?", comment.ReviewID).
1163+
And("type = ?", CommentTypeReview).Get(&reviewComment)
1164+
if err != nil {
1165+
return nil, err
1166+
}
1167+
if has && reviewComment.Content == "" {
1168+
if _, err := db.GetEngine(ctx).ID(reviewComment.ID).Delete(new(Comment)); err != nil {
1169+
return nil, err
1170+
}
1171+
deletedReviewComment = &reviewComment
1172+
}
1173+
comment.ReviewID = 0 // reset review ID to 0 for the notification
1174+
}
11481175
}
11491176

11501177
if err := comment.neuterCrossReferences(ctx); err != nil {
1151-
return err
1178+
return nil, err
11521179
}
11531180

1154-
return DeleteReaction(ctx, &ReactionOptions{CommentID: comment.ID})
1181+
if err := DeleteReaction(ctx, &ReactionOptions{CommentID: comment.ID}); err != nil {
1182+
return nil, err
1183+
}
1184+
return deletedReviewComment, nil
11551185
}
11561186

11571187
// UpdateCommentsMigrationsByType updates comments' migrations information via given git service type and original id and poster id

models/issues/comment_test.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,3 +124,18 @@ func Test_UpdateIssueNumComments(t *testing.T) {
124124
issue2 = unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 2})
125125
assert.Equal(t, 1, issue2.NumComments)
126126
}
127+
128+
func Test_DeleteCommentWithReview(t *testing.T) {
129+
assert.NoError(t, unittest.PrepareTestDatabase())
130+
131+
comment := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{ID: 7})
132+
assert.Equal(t, int64(10), comment.ReviewID)
133+
review := unittest.AssertExistsAndLoadBean(t, &issues_model.Review{ID: comment.ReviewID})
134+
135+
// FIXME: the test fixtures needs a review type comment to be created
136+
137+
// since this is the last comment of the review, it should be deleted when the comment is deleted
138+
assert.NoError(t, issues_model.DeleteComment(db.DefaultContext, comment))
139+
140+
unittest.AssertNotExistsBean(t, &issues_model.Review{ID: review.ID})
141+
}

routers/api/v1/repo/issue_comment.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -721,12 +721,12 @@ func deleteIssueComment(ctx *context.APIContext) {
721721
if !ctx.IsSigned || (ctx.Doer.ID != comment.PosterID && !ctx.Repo.CanWriteIssuesOrPulls(comment.Issue.IsPull)) {
722722
ctx.Status(http.StatusForbidden)
723723
return
724-
} else if comment.Type != issues_model.CommentTypeComment {
724+
} else if comment.Type != issues_model.CommentTypeComment && comment.Type == issues_model.CommentTypeCode {
725725
ctx.Status(http.StatusNoContent)
726726
return
727727
}
728728

729-
if err = issue_service.DeleteComment(ctx, ctx.Doer, comment); err != nil {
729+
if _, err = issue_service.DeleteComment(ctx, ctx.Doer, comment); err != nil {
730730
ctx.APIErrorInternal(err)
731731
return
732732
}

routers/web/repo/issue_comment.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -325,12 +325,18 @@ func DeleteComment(ctx *context.Context) {
325325
return
326326
}
327327

328-
if err = issue_service.DeleteComment(ctx, ctx.Doer, comment); err != nil {
328+
deletedReviewComment, err := issue_service.DeleteComment(ctx, ctx.Doer, comment)
329+
if err != nil {
329330
ctx.ServerError("DeleteComment", err)
330331
return
331332
}
332333

333-
ctx.Status(http.StatusOK)
334+
res := map[string]any{}
335+
if deletedReviewComment != nil {
336+
res["deletedReviewCommentHashTag"] = deletedReviewComment.HashTag()
337+
}
338+
339+
ctx.JSON(http.StatusOK, res)
334340
}
335341

336342
// ChangeCommentReaction create a reaction for comment

services/issue/comments.go

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ import (
1515
user_model "code.gitea.io/gitea/models/user"
1616
"code.gitea.io/gitea/modules/gitrepo"
1717
"code.gitea.io/gitea/modules/json"
18+
"code.gitea.io/gitea/modules/log"
19+
"code.gitea.io/gitea/modules/storage"
1820
"code.gitea.io/gitea/modules/timeutil"
1921
git_service "code.gitea.io/gitea/services/git"
2022
notify_service "code.gitea.io/gitea/services/notify"
@@ -131,17 +133,40 @@ func UpdateComment(ctx context.Context, c *issues_model.Comment, contentVersion
131133
}
132134

133135
// DeleteComment deletes the comment
134-
func DeleteComment(ctx context.Context, doer *user_model.User, comment *issues_model.Comment) error {
135-
err := db.WithTx(ctx, func(ctx context.Context) error {
136-
return issues_model.DeleteComment(ctx, comment)
136+
func DeleteComment(ctx context.Context, doer *user_model.User, comment *issues_model.Comment) (*issues_model.Comment, error) {
137+
deletedReviewComment, err := db.WithTx2(ctx, func(ctx context.Context) (*issues_model.Comment, error) {
138+
if err := comment.LoadAttachments(ctx); err != nil {
139+
return nil, err
140+
}
141+
142+
deletedReviewComment, err := issues_model.DeleteComment(ctx, comment)
143+
if err != nil {
144+
return nil, err
145+
}
146+
147+
// delete comment attachments
148+
if _, err := repo_model.DeleteAttachments(ctx, comment.Attachments, true); err != nil {
149+
return nil, fmt.Errorf("delete attachments: %w", err)
150+
}
151+
152+
for _, attachment := range comment.Attachments {
153+
if err := storage.Attachments.Delete(repo_model.AttachmentRelativePath(attachment.UUID)); err != nil {
154+
// Even delete files failed, but the attachments has been removed from database, so we
155+
// should not return error but only record the error on logs.
156+
// users have to delete this attachments manually or we should have a
157+
// synchronize between database attachment table and attachment storage
158+
log.Error("delete attachment[uuid: %s] failed: %v", attachment.UUID, err)
159+
}
160+
}
161+
return deletedReviewComment, nil
137162
})
138163
if err != nil {
139-
return err
164+
return nil, err
140165
}
141166

142167
notify_service.DeleteComment(ctx, doer, comment)
143168

144-
return nil
169+
return deletedReviewComment, nil
145170
}
146171

147172
// LoadCommentPushCommits Load push commits

services/user/delete.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ func deleteUser(ctx context.Context, u *user_model.User, purge bool) (err error)
117117
}
118118

119119
for _, comment := range comments {
120-
if err = issues_model.DeleteComment(ctx, comment); err != nil {
120+
if _, err = issues_model.DeleteComment(ctx, comment); err != nil {
121121
return err
122122
}
123123
}

web_src/js/features/repo-issue.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,12 @@ export function initRepoIssueCommentDelete() {
150150
counter.textContent = String(num);
151151
}
152152

153+
const json: Record<string, any> = await response.json();
154+
if (json.errorMessage) throw new Error(json.errorMessage);
155+
156+
if (json.deletedReviewCommentHashTag) {
157+
document.querySelector(`#${json.deletedReviewCommentHashTag}`)?.remove();
158+
}
153159
document.querySelector(`#${deleteButton.getAttribute('data-comment-id')}`)?.remove();
154160

155161
if (conversationHolder && !conversationHolder.querySelector('.comment')) {

0 commit comments

Comments
 (0)