From 4d2a6c40f8b8931d14504d73e69db58632d82c3f Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Sat, 23 Jan 2021 03:03:29 +0100 Subject: [PATCH] [Backport] Fix Deadlock & Delete affected reactions on comment deletion (#14392) (#14425) * Enhance Ghost comment mitigation Settings (#14392) * refactor models.DeleteComment and delete related reactions too * use deleteComment for UserDeleteWithCommentsMaxDays in DeleteUser * Resolve Fixme & fix potential deadlock * rm refactor * make diff eaven less --- models/admin.go | 2 +- models/issue_assignees.go | 2 +- models/issue_comment.go | 4 ++++ models/issue_reaction.go | 12 ++++++++---- models/user.go | 17 +++++++++-------- 5 files changed, 23 insertions(+), 14 deletions(-) diff --git a/models/admin.go b/models/admin.go index 903e35b0c..b14f0e93f 100644 --- a/models/admin.go +++ b/models/admin.go @@ -77,7 +77,7 @@ func removeStorageWithNotice(e Engine, bucket storage.ObjectStorage, title, path if err := bucket.Delete(path); err != nil { desc := fmt.Sprintf("%s [%s]: %v", title, path, err) log.Warn(title+" [%s]: %v", path, err) - if err = createNotice(x, NoticeRepository, desc); err != nil { + if err = createNotice(e, NoticeRepository, desc); err != nil { log.Error("CreateRepositoryNotice: %v", err) } } diff --git a/models/issue_assignees.go b/models/issue_assignees.go index 05e1797c1..6716f2fc7 100644 --- a/models/issue_assignees.go +++ b/models/issue_assignees.go @@ -82,7 +82,7 @@ func isUserAssignedToIssue(e Engine, issue *Issue, user *User) (isAssigned bool, } // ClearAssigneeByUserID deletes all assignments of an user -func clearAssigneeByUserID(sess *xorm.Session, userID int64) (err error) { +func clearAssigneeByUserID(sess Engine, userID int64) (err error) { _, err = sess.Delete(&IssueAssignees{AssigneeID: userID}) return } diff --git a/models/issue_comment.go b/models/issue_comment.go index 73cbb0566..b2a21e0f5 100644 --- a/models/issue_comment.go +++ b/models/issue_comment.go @@ -1077,6 +1077,10 @@ func DeleteComment(comment *Comment, doer *User) error { return err } + if err := deleteReaction(sess, &ReactionOptions{Comment: comment}); err != nil { + return err + } + return sess.Commit() } diff --git a/models/issue_reaction.go b/models/issue_reaction.go index 50b9d6848..1f1a48399 100644 --- a/models/issue_reaction.go +++ b/models/issue_reaction.go @@ -178,11 +178,15 @@ func CreateCommentReaction(doer *User, issue *Issue, comment *Comment, content s }) } -func deleteReaction(e *xorm.Session, opts *ReactionOptions) error { +func deleteReaction(e Engine, opts *ReactionOptions) error { reaction := &Reaction{ - Type: opts.Type, - UserID: opts.Doer.ID, - IssueID: opts.Issue.ID, + Type: opts.Type, + } + if opts.Doer != nil { + reaction.UserID = opts.Doer.ID + } + if opts.Issue != nil { + reaction.IssueID = opts.Issue.ID } if opts.Comment != nil { reaction.CommentID = opts.Comment.ID diff --git a/models/user.go b/models/user.go index dc3b4142b..f35d2e5c6 100644 --- a/models/user.go +++ b/models/user.go @@ -40,7 +40,6 @@ import ( "golang.org/x/crypto/scrypt" "golang.org/x/crypto/ssh" "xorm.io/builder" - "xorm.io/xorm" ) // UserType defines the user type @@ -1020,8 +1019,7 @@ func deleteBeans(e Engine, beans ...interface{}) (err error) { return nil } -// FIXME: need some kind of mechanism to record failure. HINT: system notice -func deleteUser(e *xorm.Session, u *User) error { +func deleteUser(e Engine, u *User) error { // Note: A user owns any repository or belongs to any organization // cannot perform delete operation. @@ -1135,18 +1133,21 @@ func deleteUser(e *xorm.Session, u *User) error { return fmt.Errorf("Delete: %v", err) } - // FIXME: system notice // Note: There are something just cannot be roll back, // so just keep error logs of those operations. path := UserPath(u.Name) - if err := util.RemoveAll(path); err != nil { - return fmt.Errorf("Failed to RemoveAll %s: %v", path, err) + if err = util.RemoveAll(path); err != nil { + err = fmt.Errorf("Failed to RemoveAll %s: %v", path, err) + _ = createNotice(e, NoticeTask, fmt.Sprintf("delete user '%s': %v", u.Name, err)) + return err } if len(u.Avatar) > 0 { avatarPath := u.CustomAvatarRelativePath() - if err := storage.Avatars.Delete(avatarPath); err != nil { - return fmt.Errorf("Failed to remove %s: %v", avatarPath, err) + if err = storage.Avatars.Delete(avatarPath); err != nil { + err = fmt.Errorf("Failed to remove %s: %v", avatarPath, err) + _ = createNotice(e, NoticeTask, fmt.Sprintf("delete user '%s': %v", u.Name, err)) + return err } }