diff --git a/lib/post_destroyer.rb b/lib/post_destroyer.rb index 82aa4d658..68ae562a1 100644 --- a/lib/post_destroyer.rb +++ b/lib/post_destroyer.rb @@ -5,8 +5,22 @@ class PostDestroyer def self.destroy_stubs + # exclude deleted topics and posts that are actively flagged Post.where(deleted_at: nil, user_deleted: true) - .where('updated_at < ? AND post_number > 1', 1.day.ago).each do |post| + .where("NOT EXISTS ( + SELECT 1 FROM topics t + WHERE t.deleted_at IS NOT NULL AND + t.id = posts.topic_id + )") + .where("updated_at < ? AND post_number > 1", 1.day.ago) + .where("NOT EXISTS ( + SELECT 1 + FROM post_actions pa + WHERE pa.post_id = posts.id AND + pa.deleted_at IS NULL AND + pa.post_action_type_id IN (?) + )", PostActionType.notify_flag_type_ids) + .each do |post| PostDestroyer.new(Discourse.system_user, post).destroy end end @@ -39,6 +53,9 @@ class PostDestroyer # When a post is properly deleted. Well, it's still soft deleted, but it will no longer # show up in the topic def staff_destroyed + # the topic may be trashed, skip it + return unless @post.topic + Post.transaction do # Update the last post id to the previous post if it exists diff --git a/spec/components/post_destroyer_spec.rb b/spec/components/post_destroyer_spec.rb index d38c9d1fc..5a404d59b 100644 --- a/spec/components/post_destroyer_spec.rb +++ b/spec/components/post_destroyer_spec.rb @@ -13,9 +13,10 @@ describe PostDestroyer do describe 'destroy_old_stubs' do it 'destroys stubs for deleted by user posts' do Fabricate(:admin) - reply1 = create_post(topic: post.topic) - reply2 = create_post(topic: post.topic) - reply3 = create_post(topic: post.topic) + topic = post.topic + reply1 = create_post(topic: topic) + reply2 = create_post(topic: topic) + reply3 = create_post(topic: topic) PostDestroyer.new(reply1.user, reply1).destroy PostDestroyer.new(reply2.user, reply2).destroy @@ -32,6 +33,24 @@ describe PostDestroyer do reply2.deleted_at.should_not == nil reply3.deleted_at.should == nil + # if topic is deleted we should still be able to destroy stubs + + topic.trash! + reply1.update_column(:updated_at, 2.days.ago) + PostDestroyer.destroy_stubs + + reply1.reload + reply1.deleted_at.should == nil + + # flag the post, it should not nuke the stub anymore + topic.recover! + PostAction.act(Fabricate(:coding_horror), reply1, PostActionType.types[:spam]) + + PostDestroyer.destroy_stubs + + reply1.reload + reply1.deleted_at.should == nil + end end