mirror of
https://github.com/go-gitea/gitea.git
synced 2025-08-20 10:14:04 +00:00
Fix deleting code comment bug
This commit is contained in:
parent
3531e9dbfd
commit
000d87efe1
@ -1122,21 +1122,21 @@ func UpdateComment(ctx context.Context, c *Comment, contentVersion int, doer *us
|
|||||||
}
|
}
|
||||||
|
|
||||||
// DeleteComment deletes the comment
|
// DeleteComment deletes the comment
|
||||||
func DeleteComment(ctx context.Context, comment *Comment) error {
|
func DeleteComment(ctx context.Context, comment *Comment) (*Comment, error) {
|
||||||
e := db.GetEngine(ctx)
|
e := db.GetEngine(ctx)
|
||||||
if _, err := e.ID(comment.ID).NoAutoCondition().Delete(comment); err != nil {
|
if _, err := e.ID(comment.ID).NoAutoCondition().Delete(comment); err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := db.DeleteByBean(ctx, &ContentHistory{
|
if _, err := db.DeleteByBean(ctx, &ContentHistory{
|
||||||
CommentID: comment.ID,
|
CommentID: comment.ID,
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if comment.Type.CountedAsConversation() {
|
if comment.Type.CountedAsConversation() {
|
||||||
if err := UpdateIssueNumComments(ctx, comment.IssueID); err != nil {
|
if err := UpdateIssueNumComments(ctx, comment.IssueID); err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if _, err := e.Table("action").
|
if _, err := e.Table("action").
|
||||||
@ -1144,14 +1144,44 @@ func DeleteComment(ctx context.Context, comment *Comment) error {
|
|||||||
Update(map[string]any{
|
Update(map[string]any{
|
||||||
"is_deleted": true,
|
"is_deleted": true,
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return err
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var deletedReviewComment *Comment
|
||||||
|
|
||||||
|
// delete review & review comment if the code comment is the last comment of the review
|
||||||
|
if comment.Type == CommentTypeCode && comment.ReviewID > 0 {
|
||||||
|
res, err := db.GetEngine(ctx).ID(comment.ReviewID).
|
||||||
|
Where("NOT EXISTS (SELECT 1 FROM comment WHERE review_id = ? AND `type` = ?)", comment.ReviewID, CommentTypeCode).
|
||||||
|
Delete(new(Review))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if res > 0 {
|
||||||
|
var reviewComment Comment
|
||||||
|
has, err := db.GetEngine(ctx).Where("review_id = ?", comment.ReviewID).
|
||||||
|
And("type = ?", CommentTypeReview).Get(&reviewComment)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if has && reviewComment.Content == "" {
|
||||||
|
if _, err := db.GetEngine(ctx).ID(reviewComment.ID).Delete(new(Comment)); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
deletedReviewComment = &reviewComment
|
||||||
|
}
|
||||||
|
comment.ReviewID = 0 // reset review ID to 0 for the notification
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := comment.neuterCrossReferences(ctx); err != nil {
|
if err := comment.neuterCrossReferences(ctx); err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return DeleteReaction(ctx, &ReactionOptions{CommentID: comment.ID})
|
if err := DeleteReaction(ctx, &ReactionOptions{CommentID: comment.ID}); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return deletedReviewComment, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateCommentsMigrationsByType updates comments' migrations information via given git service type and original id and poster id
|
// UpdateCommentsMigrationsByType updates comments' migrations information via given git service type and original id and poster id
|
||||||
|
@ -124,3 +124,18 @@ func Test_UpdateIssueNumComments(t *testing.T) {
|
|||||||
issue2 = unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 2})
|
issue2 = unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 2})
|
||||||
assert.Equal(t, 1, issue2.NumComments)
|
assert.Equal(t, 1, issue2.NumComments)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Test_DeleteCommentWithReview(t *testing.T) {
|
||||||
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
|
||||||
|
comment := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{ID: 7})
|
||||||
|
assert.Equal(t, int64(10), comment.ReviewID)
|
||||||
|
review := unittest.AssertExistsAndLoadBean(t, &issues_model.Review{ID: comment.ReviewID})
|
||||||
|
|
||||||
|
// FIXME: the test fixtures needs a review type comment to be created
|
||||||
|
|
||||||
|
// since this is the last comment of the review, it should be deleted when the comment is deleted
|
||||||
|
assert.NoError(t, issues_model.DeleteComment(db.DefaultContext, comment))
|
||||||
|
|
||||||
|
unittest.AssertNotExistsBean(t, &issues_model.Review{ID: review.ID})
|
||||||
|
}
|
||||||
|
@ -721,12 +721,12 @@ func deleteIssueComment(ctx *context.APIContext) {
|
|||||||
if !ctx.IsSigned || (ctx.Doer.ID != comment.PosterID && !ctx.Repo.CanWriteIssuesOrPulls(comment.Issue.IsPull)) {
|
if !ctx.IsSigned || (ctx.Doer.ID != comment.PosterID && !ctx.Repo.CanWriteIssuesOrPulls(comment.Issue.IsPull)) {
|
||||||
ctx.Status(http.StatusForbidden)
|
ctx.Status(http.StatusForbidden)
|
||||||
return
|
return
|
||||||
} else if comment.Type != issues_model.CommentTypeComment {
|
} else if comment.Type != issues_model.CommentTypeComment && comment.Type == issues_model.CommentTypeCode {
|
||||||
ctx.Status(http.StatusNoContent)
|
ctx.Status(http.StatusNoContent)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = issue_service.DeleteComment(ctx, ctx.Doer, comment); err != nil {
|
if _, err = issue_service.DeleteComment(ctx, ctx.Doer, comment); err != nil {
|
||||||
ctx.APIErrorInternal(err)
|
ctx.APIErrorInternal(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -325,12 +325,18 @@ func DeleteComment(ctx *context.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = issue_service.DeleteComment(ctx, ctx.Doer, comment); err != nil {
|
deletedReviewComment, err := issue_service.DeleteComment(ctx, ctx.Doer, comment)
|
||||||
|
if err != nil {
|
||||||
ctx.ServerError("DeleteComment", err)
|
ctx.ServerError("DeleteComment", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.Status(http.StatusOK)
|
res := map[string]any{}
|
||||||
|
if deletedReviewComment != nil {
|
||||||
|
res["deletedReviewCommentHashTag"] = deletedReviewComment.HashTag()
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.JSON(http.StatusOK, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ChangeCommentReaction create a reaction for comment
|
// ChangeCommentReaction create a reaction for comment
|
||||||
|
@ -15,6 +15,8 @@ import (
|
|||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
"code.gitea.io/gitea/modules/gitrepo"
|
"code.gitea.io/gitea/modules/gitrepo"
|
||||||
"code.gitea.io/gitea/modules/json"
|
"code.gitea.io/gitea/modules/json"
|
||||||
|
"code.gitea.io/gitea/modules/log"
|
||||||
|
"code.gitea.io/gitea/modules/storage"
|
||||||
"code.gitea.io/gitea/modules/timeutil"
|
"code.gitea.io/gitea/modules/timeutil"
|
||||||
git_service "code.gitea.io/gitea/services/git"
|
git_service "code.gitea.io/gitea/services/git"
|
||||||
notify_service "code.gitea.io/gitea/services/notify"
|
notify_service "code.gitea.io/gitea/services/notify"
|
||||||
@ -131,17 +133,40 @@ func UpdateComment(ctx context.Context, c *issues_model.Comment, contentVersion
|
|||||||
}
|
}
|
||||||
|
|
||||||
// DeleteComment deletes the comment
|
// DeleteComment deletes the comment
|
||||||
func DeleteComment(ctx context.Context, doer *user_model.User, comment *issues_model.Comment) error {
|
func DeleteComment(ctx context.Context, doer *user_model.User, comment *issues_model.Comment) (*issues_model.Comment, error) {
|
||||||
err := db.WithTx(ctx, func(ctx context.Context) error {
|
deletedReviewComment, err := db.WithTx2(ctx, func(ctx context.Context) (*issues_model.Comment, error) {
|
||||||
return issues_model.DeleteComment(ctx, comment)
|
if err := comment.LoadAttachments(ctx); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
deletedReviewComment, err := issues_model.DeleteComment(ctx, comment)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// delete comment attachments
|
||||||
|
if _, err := repo_model.DeleteAttachments(ctx, comment.Attachments, true); err != nil {
|
||||||
|
return nil, fmt.Errorf("delete attachments: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, attachment := range comment.Attachments {
|
||||||
|
if err := storage.Attachments.Delete(repo_model.AttachmentRelativePath(attachment.UUID)); err != nil {
|
||||||
|
// Even delete files failed, but the attachments has been removed from database, so we
|
||||||
|
// should not return error but only record the error on logs.
|
||||||
|
// users have to delete this attachments manually or we should have a
|
||||||
|
// synchronize between database attachment table and attachment storage
|
||||||
|
log.Error("delete attachment[uuid: %s] failed: %v", attachment.UUID, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return deletedReviewComment, nil
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
notify_service.DeleteComment(ctx, doer, comment)
|
notify_service.DeleteComment(ctx, doer, comment)
|
||||||
|
|
||||||
return nil
|
return deletedReviewComment, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// LoadCommentPushCommits Load push commits
|
// LoadCommentPushCommits Load push commits
|
||||||
|
@ -117,7 +117,7 @@ func deleteUser(ctx context.Context, u *user_model.User, purge bool) (err error)
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, comment := range comments {
|
for _, comment := range comments {
|
||||||
if err = issues_model.DeleteComment(ctx, comment); err != nil {
|
if _, err = issues_model.DeleteComment(ctx, comment); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -150,6 +150,12 @@ export function initRepoIssueCommentDelete() {
|
|||||||
counter.textContent = String(num);
|
counter.textContent = String(num);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const json: Record<string, any> = await response.json();
|
||||||
|
if (json.errorMessage) throw new Error(json.errorMessage);
|
||||||
|
|
||||||
|
if (json.deletedReviewCommentHashTag) {
|
||||||
|
document.querySelector(`#${json.deletedReviewCommentHashTag}`)?.remove();
|
||||||
|
}
|
||||||
document.querySelector(`#${deleteButton.getAttribute('data-comment-id')}`)?.remove();
|
document.querySelector(`#${deleteButton.getAttribute('data-comment-id')}`)?.remove();
|
||||||
|
|
||||||
if (conversationHolder && !conversationHolder.querySelector('.comment')) {
|
if (conversationHolder && !conversationHolder.querySelector('.comment')) {
|
||||||
|
Loading…
Reference in New Issue
Block a user