From 7ec2037f5f7deecfbf59a206a33bf3cc9a8cc0cc Mon Sep 17 00:00:00 2001 From: Azareal Date: Wed, 15 Jan 2020 14:16:10 +1000 Subject: [PATCH] Delete likes on replies / topics properly when their parent is deleted. --- common/reply.go | 33 +++++++++++++++++++++++++++++++-- common/topic.go | 10 ++++++++-- common/user.go | 29 +++++++++++++++++++++++------ routes/reply.go | 4 ++-- 4 files changed, 64 insertions(+), 12 deletions(-) diff --git a/common/reply.go b/common/reply.go index ae094c55..1ee072ab 100644 --- a/common/reply.go +++ b/common/reply.go @@ -63,6 +63,9 @@ type ReplyStmts struct { delete *sql.Stmt addLikesToReply *sql.Stmt removeRepliesFromTopic *sql.Stmt + deleteLikesForReply *sql.Stmt + deleteActivity *sql.Stmt + deleteActivitySubs *sql.Stmt updateTopicReplies *sql.Stmt updateTopicReplies2 *sql.Stmt @@ -79,6 +82,9 @@ func init() { delete: acc.Delete(re).Where("rid=?").Prepare(), addLikesToReply: acc.Update(re).Set("likeCount=likeCount+?").Where("rid=?").Prepare(), removeRepliesFromTopic: acc.Update("topics").Set("postCount=postCount-?").Where("tid=?").Prepare(), + deleteLikesForReply: acc.Delete("likes").Where("targetItem=? AND targetType='replies'").Prepare(), + deleteActivity: acc.Delete("activity_stream").Where("elementID=? AND elementType='post'").Prepare(), + deleteActivitySubs: acc.Delete("activity_subscriptions").Where("targetID=? AND targetType='post'").Prepare(), // TODO: Optimise this to avoid firing an update if it's not the last reply in a topic. We will need to set lastReplyID properly in other places and in the patcher first so we can use it here. updateTopicReplies: acc.RawPrepare("UPDATE topics t INNER JOIN replies r ON t.tid = r.tid SET t.lastReplyBy = r.createdBy, t.lastReplyAt = r.createdAt, t.lastReplyID = r.rid WHERE t.tid = ?"), @@ -114,9 +120,20 @@ func (r *Reply) Like(uid int) (err error) { } // TODO: Refresh topic list? -// TODO: Remove alerts. +// TODO: Restructure alerts so we can delete the "x replied to topic" ones too. func (r *Reply) Delete() error { - _, err := replyStmts.delete.Exec(r.ID) + creator, err := Users.Get(r.CreatedBy) + if err == nil { + wcount := WordCount(r.Content) + err = creator.DecreasePostStats(wcount, false) + if err != nil { + return err + } + } else if err != ErrNoRows { + return err + } + + _, err = replyStmts.delete.Exec(r.ID) if err != nil { return err } @@ -135,6 +152,18 @@ func (r *Reply) Delete() error { tc.Remove(r.ParentID) } _ = Rstore.GetCache().Remove(r.ID) + if err != nil { + return err + } + _, err = replyStmts.deleteLikesForReply.Exec(r.ID) + if err != nil { + return err + } + _, err = replyStmts.deleteActivitySubs.Exec(r.ID) + if err != nil { + return err + } + _, err = replyStmts.deleteActivity.Exec(r.ID) return err } diff --git a/common/topic.go b/common/topic.go index 5742d973..8979dcea 100644 --- a/common/topic.go +++ b/common/topic.go @@ -197,6 +197,7 @@ type TopicStmts struct { createLike *sql.Stmt addLikesToTopic *sql.Stmt delete *sql.Stmt + deleteLikesForTopic *sql.Stmt deleteActivity *sql.Stmt deleteActivitySubs *sql.Stmt edit *sql.Stmt @@ -226,6 +227,7 @@ func init() { createLike: acc.Insert("likes").Columns("weight, targetItem, targetType, sentBy, createdAt").Fields("?,?,?,?,UTC_TIMESTAMP()").Prepare(), addLikesToTopic: acc.Update(t).Set("likeCount=likeCount+?").Where("tid = ?").Prepare(), delete: acc.Delete(t).Where("tid = ?").Prepare(), + deleteLikesForTopic: acc.Delete("likes").Where("targetItem=? AND targetType='topics'").Prepare(), deleteActivity: acc.Delete("activity_stream").Where("elementID=? AND elementType='topic'").Prepare(), deleteActivitySubs: acc.Delete("activity_subscriptions").Where("targetID=? AND targetType='topic'").Prepare(), edit: acc.Update(t).Set("title=?,content=?,parsed_content=?").Where("tid=?").Prepare(), // TODO: Only run the content update bits on non-polls, does this matter? @@ -328,10 +330,10 @@ func (t *Topic) Unlike(uid int) error { // TODO: Use a transaction here func (t *Topic) Delete() error { - topicCreator, err := Users.Get(t.CreatedBy) + creator, err := Users.Get(t.CreatedBy) if err == nil { wcount := WordCount(t.Content) - err = topicCreator.DecreasePostStats(wcount, true) + err = creator.DecreasePostStats(wcount, true) if err != nil { return err } @@ -349,6 +351,10 @@ func (t *Topic) Delete() error { if err != nil && err != ErrNoRows { return err } + _, err = topicStmts.deleteLikesForTopic.Exec(t.ID) + if err != nil { + return err + } _, err = topicStmts.deleteActivitySubs.Exec(t.ID) if err != nil { return err diff --git a/common/user.go b/common/user.go index 41ea9961..b295d41e 100644 --- a/common/user.go +++ b/common/user.go @@ -146,9 +146,9 @@ type UserStmts struct { scheduleAvatarResize *sql.Stmt - deletePosts *sql.Stmt + deletePosts *sql.Stmt deleteProfilePosts *sql.Stmt - deleteReplyPosts *sql.Stmt + deleteReplyPosts *sql.Stmt } var userStmts UserStmts @@ -186,9 +186,9 @@ func init() { scheduleAvatarResize: acc.Insert("users_avatar_queue").Columns("uid").Fields("?").Prepare(), - deletePosts: acc.Select("topics").Columns("tid,parentID").Where("createdBy=?").Prepare(), + deletePosts: acc.Select("topics").Columns("tid,parentID").Where("createdBy=?").Prepare(), deleteProfilePosts: acc.Select("users_replies").Columns("rid").Where("createdBy=?").Prepare(), - deleteReplyPosts: acc.Select("replies").Columns("rid,tid").Where("createdBy=?").Prepare(), + deleteReplyPosts: acc.Select("replies").Columns("rid,tid").Where("createdBy=?").Prepare(), } return acc.FirstError() }) @@ -346,6 +346,10 @@ func (u *User) DeletePosts() error { } updatedForums[parentID] = updatedForums[parentID] + 1 + _, err = topicStmts.deleteLikesForTopic.Exec(tid) + if err != nil { + return err + } _, err = topicStmts.deleteActivitySubs.Exec(tid) if err != nil { return err @@ -401,7 +405,7 @@ func (u *User) DeletePosts() error { rc := Rstore.GetCache() for rows.Next() { var rid, tid int - err := rows.Scan(&rid,&tid) + err := rows.Scan(&rid, &tid) if err != nil { return err } @@ -426,7 +430,20 @@ func (u *User) DeletePosts() error { if err != nil { return err } - // TODO: Remove alerts. + + _, err = replyStmts.deleteLikesForReply.Exec(rid) + if err != nil { + return err + } + _, err = replyStmts.deleteActivitySubs.Exec(rid) + if err != nil { + return err + } + _, err = replyStmts.deleteActivity.Exec(rid) + if err != nil { + return err + } + // TODO: Restructure alerts so we can delete the "x replied to topic" ones too. } return rows.Err() } diff --git a/routes/reply.go b/routes/reply.go index 6dd35237..2757c87b 100644 --- a/routes/reply.go +++ b/routes/reply.go @@ -327,7 +327,7 @@ func ReplyDeleteSubmit(w http.ResponseWriter, r *http.Request, user c.User, srid } // ? - What happens if an error fires after a redirect...? - replyCreator, err := c.Users.Get(reply.CreatedBy) + /*replyCreator, err := c.Users.Get(reply.CreatedBy) if err == nil { err = replyCreator.DecreasePostStats(c.WordCount(reply.Content), false) if err != nil { @@ -335,7 +335,7 @@ func ReplyDeleteSubmit(w http.ResponseWriter, r *http.Request, user c.User, srid } } else if err != sql.ErrNoRows { return c.InternalErrorJSQ(err, w, r, js) - } + }*/ err = c.ModLogs.Create("delete", reply.ParentID, "reply", user.GetIP(), user.ID) if err != nil {