2019-04-30 08:27:42 +08:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
2022-07-28 10:27:38 +08:00
|
|
|
RSpec.describe PostDestroyer do
|
2019-01-04 01:03:01 +08:00
|
|
|
before { UserActionManager.enable }
|
2013-05-14 09:59:55 +08:00
|
|
|
|
2024-01-25 14:28:26 +08:00
|
|
|
fab!(:moderator) { Fabricate(:moderator, refresh_auto_groups: true) }
|
2024-03-26 11:41:12 +08:00
|
|
|
fab!(:admin)
|
2024-01-25 14:28:26 +08:00
|
|
|
fab!(:coding_horror) { Fabricate(:coding_horror, refresh_auto_groups: true) }
|
2013-07-22 13:06:53 +08:00
|
|
|
let(:post) { create_post }
|
2013-03-20 02:15:08 +08:00
|
|
|
|
2014-09-26 01:51:00 +08:00
|
|
|
describe "destroy_old_hidden_posts" do
|
|
|
|
it "destroys posts that have been hidden for 30 days" do
|
|
|
|
now = Time.now
|
|
|
|
|
|
|
|
freeze_time(now - 60.days)
|
|
|
|
topic = post.topic
|
|
|
|
reply1 = create_post(topic: topic)
|
|
|
|
|
|
|
|
freeze_time(now - 40.days)
|
|
|
|
reply2 = create_post(topic: topic)
|
2019-01-04 01:03:01 +08:00
|
|
|
reply2.hide!(PostActionType.types[:off_topic])
|
2014-09-26 01:51:00 +08:00
|
|
|
|
|
|
|
freeze_time(now - 20.days)
|
|
|
|
reply3 = create_post(topic: topic)
|
2019-01-04 01:03:01 +08:00
|
|
|
reply3.hide!(PostActionType.types[:off_topic])
|
2014-09-26 01:51:00 +08:00
|
|
|
|
|
|
|
freeze_time(now - 10.days)
|
|
|
|
reply4 = create_post(topic: topic)
|
|
|
|
|
|
|
|
freeze_time(now)
|
|
|
|
PostDestroyer.destroy_old_hidden_posts
|
|
|
|
|
|
|
|
reply1.reload
|
|
|
|
reply2.reload
|
|
|
|
reply3.reload
|
|
|
|
reply4.reload
|
|
|
|
|
2015-01-10 00:34:37 +08:00
|
|
|
expect(reply1.deleted_at).to eq(nil)
|
|
|
|
expect(reply2.deleted_at).not_to eq(nil)
|
|
|
|
expect(reply3.deleted_at).to eq(nil)
|
|
|
|
expect(reply4.deleted_at).to eq(nil)
|
2014-09-26 01:51:00 +08:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2013-07-22 15:48:24 +08:00
|
|
|
describe "destroy_old_stubs" do
|
2019-05-07 21:25:52 +08:00
|
|
|
it "destroys stubs for deleted by user topics" do
|
|
|
|
SiteSetting.delete_removed_posts_after = 24
|
|
|
|
|
|
|
|
PostDestroyer.new(post.user, post).destroy
|
|
|
|
post.update_column(:updated_at, 2.days.ago)
|
|
|
|
|
|
|
|
PostDestroyer.destroy_stubs
|
|
|
|
expect(post.reload.deleted_at).not_to eq(nil)
|
|
|
|
end
|
|
|
|
|
2013-07-22 15:48:24 +08:00
|
|
|
it "destroys stubs for deleted by user posts" do
|
2017-07-07 14:09:14 +08:00
|
|
|
SiteSetting.delete_removed_posts_after = 24
|
2013-07-23 14:11:44 +08:00
|
|
|
topic = post.topic
|
|
|
|
reply1 = create_post(topic: topic)
|
|
|
|
reply2 = create_post(topic: topic)
|
|
|
|
reply3 = create_post(topic: topic)
|
2013-07-22 15:48:24 +08:00
|
|
|
|
|
|
|
PostDestroyer.new(reply1.user, reply1).destroy
|
|
|
|
PostDestroyer.new(reply2.user, reply2).destroy
|
|
|
|
|
|
|
|
reply2.update_column(:updated_at, 2.days.ago)
|
|
|
|
|
|
|
|
PostDestroyer.destroy_stubs
|
|
|
|
|
|
|
|
reply1.reload
|
|
|
|
reply2.reload
|
|
|
|
reply3.reload
|
|
|
|
|
2015-01-10 00:34:37 +08:00
|
|
|
expect(reply1.deleted_at).to eq(nil)
|
|
|
|
expect(reply2.deleted_at).not_to eq(nil)
|
|
|
|
expect(reply3.deleted_at).to eq(nil)
|
2013-07-22 15:48:24 +08:00
|
|
|
|
2013-07-23 14:11:44 +08:00
|
|
|
# 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
|
2015-01-10 00:34:37 +08:00
|
|
|
expect(reply1.deleted_at).to eq(nil)
|
2013-07-23 14:11:44 +08:00
|
|
|
|
|
|
|
# flag the post, it should not nuke the stub anymore
|
|
|
|
topic.recover!
|
2021-12-16 01:41:14 +08:00
|
|
|
reviewable = PostActionCreator.spam(coding_horror, reply1).reviewable
|
2013-07-23 14:11:44 +08:00
|
|
|
|
|
|
|
PostDestroyer.destroy_stubs
|
|
|
|
|
|
|
|
reply1.reload
|
2015-01-10 00:34:37 +08:00
|
|
|
expect(reply1.deleted_at).to eq(nil)
|
2013-07-23 14:11:44 +08:00
|
|
|
|
2019-01-04 01:03:01 +08:00
|
|
|
# ignore the flag, we should be able to delete the stub
|
2023-03-02 23:40:53 +08:00
|
|
|
reviewable.perform(Discourse.system_user, :ignore_and_do_nothing)
|
2018-08-10 02:54:23 +08:00
|
|
|
PostDestroyer.destroy_stubs
|
|
|
|
|
|
|
|
reply1.reload
|
|
|
|
expect(reply1.deleted_at).to_not eq(nil)
|
2013-07-22 15:48:24 +08:00
|
|
|
end
|
2013-08-03 01:35:42 +08:00
|
|
|
|
|
|
|
it "uses the delete_removed_posts_after site setting" do
|
|
|
|
topic = post.topic
|
|
|
|
reply1 = create_post(topic: topic)
|
|
|
|
reply2 = create_post(topic: topic)
|
|
|
|
|
|
|
|
PostDestroyer.new(reply1.user, reply1).destroy
|
|
|
|
PostDestroyer.new(reply2.user, reply2).destroy
|
|
|
|
|
2017-07-07 14:09:14 +08:00
|
|
|
SiteSetting.delete_removed_posts_after = 1
|
2013-08-03 01:35:42 +08:00
|
|
|
|
|
|
|
reply2.update_column(:updated_at, 70.minutes.ago)
|
|
|
|
|
|
|
|
PostDestroyer.destroy_stubs
|
|
|
|
|
|
|
|
reply1.reload
|
|
|
|
reply2.reload
|
|
|
|
|
2015-01-10 00:34:37 +08:00
|
|
|
expect(reply1.deleted_at).to eq(nil)
|
|
|
|
expect(reply2.deleted_at).not_to eq(nil)
|
2013-08-03 01:35:42 +08:00
|
|
|
|
2017-07-07 14:09:14 +08:00
|
|
|
SiteSetting.delete_removed_posts_after = 72
|
2013-08-03 01:35:42 +08:00
|
|
|
|
|
|
|
reply1.update_column(:updated_at, 2.days.ago)
|
|
|
|
|
|
|
|
PostDestroyer.destroy_stubs
|
|
|
|
|
2015-01-10 00:34:37 +08:00
|
|
|
expect(reply1.reload.deleted_at).to eq(nil)
|
2013-08-03 01:35:42 +08:00
|
|
|
|
2017-07-07 14:09:14 +08:00
|
|
|
SiteSetting.delete_removed_posts_after = 47
|
2013-08-03 01:35:42 +08:00
|
|
|
|
|
|
|
PostDestroyer.destroy_stubs
|
|
|
|
|
2015-01-10 00:34:37 +08:00
|
|
|
expect(reply1.reload.deleted_at).not_to eq(nil)
|
2013-08-03 01:35:42 +08:00
|
|
|
end
|
2014-10-07 04:29:20 +08:00
|
|
|
|
|
|
|
it "deletes posts immediately if delete_removed_posts_after is 0" do
|
|
|
|
topic = post.topic
|
|
|
|
reply1 = create_post(topic: topic)
|
|
|
|
|
2017-07-07 14:09:14 +08:00
|
|
|
SiteSetting.delete_removed_posts_after = 0
|
2014-10-07 04:29:20 +08:00
|
|
|
|
|
|
|
PostDestroyer.new(reply1.user, reply1).destroy
|
|
|
|
|
2015-01-10 00:34:37 +08:00
|
|
|
expect(reply1.reload.deleted_at).not_to eq(nil)
|
2014-10-07 04:29:20 +08:00
|
|
|
end
|
2013-07-22 15:48:24 +08:00
|
|
|
end
|
|
|
|
|
2015-09-19 00:48:43 +08:00
|
|
|
describe "recovery and user actions" do
|
|
|
|
it "recreates user actions" do
|
|
|
|
reply = create_post(topic: post.topic)
|
|
|
|
author = reply.user
|
|
|
|
|
|
|
|
post_action =
|
|
|
|
author.user_actions.where(action_type: UserAction::REPLY, target_post_id: reply.id).first
|
|
|
|
expect(post_action).to be_present
|
|
|
|
|
|
|
|
PostDestroyer.new(moderator, reply).destroy
|
|
|
|
|
|
|
|
# User Action is removed
|
|
|
|
post_action =
|
|
|
|
author.user_actions.where(action_type: UserAction::REPLY, target_post_id: reply.id).first
|
|
|
|
expect(post_action).to be_blank
|
|
|
|
|
|
|
|
PostDestroyer.new(moderator, reply).recover
|
|
|
|
|
|
|
|
# On recovery, the user action is recreated
|
|
|
|
post_action =
|
|
|
|
author.user_actions.where(action_type: UserAction::REPLY, target_post_id: reply.id).first
|
|
|
|
expect(post_action).to be_present
|
|
|
|
end
|
2016-06-13 11:25:06 +08:00
|
|
|
|
2020-02-06 16:19:04 +08:00
|
|
|
it "works with topics and posts with no user" do
|
|
|
|
post = Fabricate(:post)
|
|
|
|
UserDestroyer.new(Discourse.system_user).destroy(post.user, delete_posts: true)
|
|
|
|
|
2021-07-23 14:39:49 +08:00
|
|
|
expect { PostDestroyer.new(admin, post.reload).recover }.to change { post.reload.user_id }.to(
|
2020-02-06 16:19:04 +08:00
|
|
|
Discourse.system_user.id,
|
|
|
|
).and change { post.topic.user_id }.to(Discourse.system_user.id)
|
|
|
|
end
|
|
|
|
|
2022-02-25 08:20:54 +08:00
|
|
|
it "bypassed validation when updating users" do
|
|
|
|
post = create_post
|
|
|
|
|
|
|
|
# ensure user would fail validations
|
|
|
|
UserEmail.where(user_id: post.user_id).delete_all
|
|
|
|
|
|
|
|
PostDestroyer.new(admin, post.reload).destroy
|
|
|
|
PostDestroyer.new(admin, post.reload, force_destroy: true).destroy
|
|
|
|
|
|
|
|
expect(Post.with_deleted.find_by(id: post.id)).to eq(nil)
|
|
|
|
end
|
|
|
|
|
2016-06-13 11:25:06 +08:00
|
|
|
describe "post_count recovery" do
|
|
|
|
before do
|
|
|
|
post
|
|
|
|
@user = post.user
|
2017-11-10 07:05:53 +08:00
|
|
|
@reply = create_post(topic: post.topic, user: @user)
|
2016-06-13 11:25:06 +08:00
|
|
|
expect(@user.user_stat.post_count).to eq(1)
|
|
|
|
end
|
|
|
|
|
2019-03-29 21:36:29 +08:00
|
|
|
it "Recovers the post correctly" do
|
|
|
|
PostDestroyer.new(admin, post).destroy
|
|
|
|
|
|
|
|
post.reload
|
|
|
|
PostDestroyer.new(admin, post).recover
|
|
|
|
recovered_topic = post.reload.topic
|
|
|
|
|
|
|
|
expect(recovered_topic.deleted_at).to be_nil
|
|
|
|
expect(recovered_topic.deleted_by_id).to be_nil
|
|
|
|
end
|
|
|
|
|
2022-07-28 00:14:14 +08:00
|
|
|
context "with recover" do
|
2019-04-11 01:10:21 +08:00
|
|
|
it "doesn't raise an error when the raw doesn't change" do
|
|
|
|
PostRevisor.new(@reply).revise!(
|
|
|
|
@user,
|
|
|
|
{ edit_reason: "made a change" },
|
|
|
|
force_new_version: true,
|
|
|
|
)
|
|
|
|
PostDestroyer.new(@user, @reply.reload).recover
|
|
|
|
end
|
|
|
|
|
2019-04-12 04:21:00 +08:00
|
|
|
it "won't recover a non user-deleted post" do
|
|
|
|
PostRevisor.new(@reply).revise!(
|
|
|
|
admin,
|
|
|
|
{ raw: "this is a change to the post" },
|
|
|
|
force_new_version: true,
|
|
|
|
)
|
|
|
|
PostDestroyer.new(@user, @reply.reload).recover
|
|
|
|
expect(@reply.reload.raw).to eq("this is a change to the post")
|
|
|
|
end
|
|
|
|
|
2016-06-13 11:25:06 +08:00
|
|
|
it "should increment the user's post count" do
|
2017-11-10 07:05:53 +08:00
|
|
|
PostDestroyer.new(@user, @reply).destroy
|
|
|
|
expect(@user.user_stat.topic_count).to eq(1)
|
2016-06-13 11:25:06 +08:00
|
|
|
expect(@user.user_stat.post_count).to eq(1)
|
|
|
|
|
2017-11-10 07:05:53 +08:00
|
|
|
PostDestroyer.new(@user, @reply.reload).recover
|
|
|
|
expect(@user.user_stat.topic_count).to eq(1)
|
2016-06-13 11:25:06 +08:00
|
|
|
expect(@user.reload.user_stat.post_count).to eq(1)
|
2017-11-10 07:05:53 +08:00
|
|
|
|
|
|
|
expect(
|
|
|
|
UserAction.where(
|
|
|
|
target_topic_id: post.topic_id,
|
|
|
|
action_type: UserAction::NEW_TOPIC,
|
|
|
|
).count,
|
|
|
|
).to eq(1)
|
|
|
|
expect(
|
|
|
|
UserAction.where(target_topic_id: post.topic_id, action_type: UserAction::REPLY).count,
|
|
|
|
).to eq(1)
|
2016-06-13 11:25:06 +08:00
|
|
|
end
|
2021-06-16 06:30:40 +08:00
|
|
|
|
|
|
|
it "runs the SyncTopicUserBookmarked for the topic that the post is in so topic_users.bookmarked is correct" do
|
|
|
|
PostDestroyer.new(@user, @reply).destroy
|
|
|
|
expect_enqueued_with(
|
|
|
|
job: :sync_topic_user_bookmarked,
|
|
|
|
args: {
|
|
|
|
topic_id: @reply.topic_id,
|
|
|
|
},
|
|
|
|
) { PostDestroyer.new(@user, @reply.reload).recover }
|
|
|
|
end
|
2016-06-13 11:25:06 +08:00
|
|
|
end
|
|
|
|
|
2022-07-28 00:14:14 +08:00
|
|
|
context "when recovered by admin" do
|
2020-07-16 22:15:01 +08:00
|
|
|
it "should set user_deleted to false" do
|
|
|
|
PostDestroyer.new(@user, @reply).destroy
|
|
|
|
expect(@reply.reload.user_deleted).to eq(true)
|
|
|
|
|
|
|
|
PostDestroyer.new(admin, @reply).recover
|
|
|
|
expect(@reply.reload.user_deleted).to eq(false)
|
|
|
|
end
|
|
|
|
|
2016-06-13 11:25:06 +08:00
|
|
|
it "should increment the user's post count" do
|
2017-11-10 07:05:53 +08:00
|
|
|
PostDestroyer.new(moderator, @reply).destroy
|
|
|
|
expect(@user.reload.user_stat.topic_count).to eq(1)
|
|
|
|
expect(@user.user_stat.post_count).to eq(0)
|
|
|
|
|
|
|
|
PostDestroyer.new(admin, @reply).recover
|
|
|
|
expect(@user.reload.user_stat.topic_count).to eq(1)
|
|
|
|
expect(@user.user_stat.post_count).to eq(1)
|
|
|
|
|
2016-06-13 11:25:06 +08:00
|
|
|
PostDestroyer.new(moderator, post).destroy
|
2017-11-10 07:05:53 +08:00
|
|
|
expect(@user.reload.user_stat.topic_count).to eq(0)
|
2016-06-13 11:25:06 +08:00
|
|
|
expect(@user.user_stat.post_count).to eq(0)
|
|
|
|
|
|
|
|
PostDestroyer.new(admin, post).recover
|
2017-11-10 07:05:53 +08:00
|
|
|
expect(@user.reload.user_stat.topic_count).to eq(1)
|
|
|
|
expect(@user.user_stat.post_count).to eq(1)
|
|
|
|
|
|
|
|
expect(
|
|
|
|
UserAction.where(
|
|
|
|
target_topic_id: post.topic_id,
|
|
|
|
action_type: UserAction::NEW_TOPIC,
|
|
|
|
).count,
|
|
|
|
).to eq(1)
|
|
|
|
expect(
|
|
|
|
UserAction.where(target_topic_id: post.topic_id, action_type: UserAction::REPLY).count,
|
|
|
|
).to eq(1)
|
2016-06-13 11:25:06 +08:00
|
|
|
end
|
2020-07-22 09:57:16 +08:00
|
|
|
|
2022-07-28 00:14:14 +08:00
|
|
|
context "when recovered by user with access to moderate topic category" do
|
2020-07-22 09:57:16 +08:00
|
|
|
fab!(:review_user) { Fabricate(:user) }
|
|
|
|
|
|
|
|
before do
|
|
|
|
SiteSetting.enable_category_group_moderation = true
|
|
|
|
review_group = Fabricate(:group)
|
2024-09-04 09:38:46 +08:00
|
|
|
review_category = Fabricate(:category)
|
|
|
|
Fabricate(:category_moderation_group, category: review_category, group: review_group)
|
2020-07-22 09:57:16 +08:00
|
|
|
@reply.topic.update!(category: review_category)
|
|
|
|
review_group.users << review_user
|
|
|
|
end
|
|
|
|
|
|
|
|
context "when the post has a Reviewable record" do
|
|
|
|
before do
|
|
|
|
ReviewableFlaggedPost.needs_review!(target: @reply, created_by: Fabricate(:user))
|
|
|
|
end
|
|
|
|
|
2020-07-28 10:06:15 +08:00
|
|
|
def changes_deleted_at_to_nil
|
2020-07-22 09:57:16 +08:00
|
|
|
PostDestroyer.new(Discourse.system_user, @reply).destroy
|
|
|
|
@reply.reload
|
|
|
|
expect(@reply.user_deleted).to eq(false)
|
|
|
|
expect(@reply.deleted_at).not_to eq(nil)
|
|
|
|
|
|
|
|
PostDestroyer.new(review_user, @reply).recover
|
|
|
|
@reply.reload
|
|
|
|
expect(@reply.deleted_at).to eq(nil)
|
|
|
|
end
|
2020-07-28 10:06:15 +08:00
|
|
|
|
|
|
|
it "changes deleted_at to nil" do
|
|
|
|
changes_deleted_at_to_nil
|
|
|
|
end
|
|
|
|
|
|
|
|
context "when the topic is deleted" do
|
|
|
|
before { @reply.topic.trash! }
|
|
|
|
it "changes deleted_at to nil" do
|
|
|
|
changes_deleted_at_to_nil
|
|
|
|
end
|
|
|
|
end
|
2020-07-22 09:57:16 +08:00
|
|
|
end
|
|
|
|
end
|
2016-06-13 11:25:06 +08:00
|
|
|
end
|
|
|
|
end
|
2015-09-19 00:48:43 +08:00
|
|
|
end
|
|
|
|
|
2018-10-02 23:25:08 +08:00
|
|
|
describe "recovery and post actions" do
|
2021-12-16 01:41:14 +08:00
|
|
|
fab!(:codinghorror) { coding_horror }
|
2019-01-04 01:03:01 +08:00
|
|
|
let!(:like) { PostActionCreator.like(codinghorror, post).post_action }
|
|
|
|
let!(:another_like) { PostActionCreator.like(moderator, post).post_action }
|
2018-10-02 23:25:08 +08:00
|
|
|
|
|
|
|
it "restores public post actions" do
|
|
|
|
PostDestroyer.new(moderator, post).destroy
|
|
|
|
expect(PostAction.exists?(id: like.id)).to eq(false)
|
|
|
|
|
|
|
|
PostDestroyer.new(moderator, post).recover
|
|
|
|
expect(PostAction.exists?(id: like.id)).to eq(true)
|
|
|
|
end
|
|
|
|
|
|
|
|
it "does not recover previously-deleted actions" do
|
2019-01-04 01:03:01 +08:00
|
|
|
PostActionDestroyer.destroy(codinghorror, post, :like)
|
2018-10-02 23:25:08 +08:00
|
|
|
expect(PostAction.exists?(id: like.id)).to eq(false)
|
|
|
|
|
|
|
|
PostDestroyer.new(moderator, post).destroy
|
|
|
|
PostDestroyer.new(moderator, post).recover
|
|
|
|
expect(PostAction.exists?(id: another_like.id)).to eq(true)
|
|
|
|
expect(PostAction.exists?(id: like.id)).to eq(false)
|
|
|
|
end
|
|
|
|
|
|
|
|
it "updates post like count" do
|
|
|
|
PostDestroyer.new(moderator, post).destroy
|
|
|
|
PostDestroyer.new(moderator, post).recover
|
|
|
|
post.reload
|
|
|
|
expect(post.like_count).to eq(2)
|
|
|
|
expect(post.custom_fields["deleted_public_actions"]).to be_nil
|
|
|
|
end
|
2020-08-12 08:16:26 +08:00
|
|
|
|
|
|
|
it "unmarks the matching incoming email for imap sync" do
|
|
|
|
SiteSetting.enable_imap = true
|
|
|
|
incoming =
|
|
|
|
Fabricate(:incoming_email, imap_sync: true, post: post, topic: post.topic, imap_uid: 99)
|
|
|
|
PostDestroyer.new(moderator, post).recover
|
|
|
|
incoming.reload
|
|
|
|
expect(incoming.imap_sync).to eq(false)
|
|
|
|
end
|
2018-10-02 23:25:08 +08:00
|
|
|
end
|
|
|
|
|
2013-03-20 02:15:08 +08:00
|
|
|
describe "basic destroying" do
|
2013-09-06 23:50:05 +08:00
|
|
|
it "as the creator of the post, doesn't delete the post" do
|
2016-09-05 15:58:04 +08:00
|
|
|
begin
|
|
|
|
post2 = create_post
|
2017-11-03 04:43:09 +08:00
|
|
|
user_stat = post2.user.user_stat
|
2016-09-05 15:58:04 +08:00
|
|
|
|
|
|
|
called = 0
|
2023-11-29 13:38:07 +08:00
|
|
|
topic_destroyed = ->(topic, user) do
|
2016-09-05 15:58:04 +08:00
|
|
|
expect(topic).to eq(post2.topic)
|
|
|
|
expect(user).to eq(post2.user)
|
|
|
|
called += 1
|
2023-11-29 13:38:07 +08:00
|
|
|
end
|
2013-09-06 23:50:05 +08:00
|
|
|
|
2016-09-05 15:58:04 +08:00
|
|
|
DiscourseEvent.on(:topic_destroyed, &topic_destroyed)
|
2013-09-06 23:50:05 +08:00
|
|
|
|
2016-09-05 15:58:04 +08:00
|
|
|
@orig = post2.cooked
|
2017-11-03 03:33:40 +08:00
|
|
|
# Guardian.new(post2.user).can_delete_post?(post2) == false
|
2016-09-05 15:58:04 +08:00
|
|
|
PostDestroyer.new(post2.user, post2).destroy
|
|
|
|
post2.reload
|
2013-09-06 23:50:05 +08:00
|
|
|
|
2016-09-05 15:58:04 +08:00
|
|
|
expect(post2.deleted_at).to be_blank
|
|
|
|
expect(post2.deleted_by).to be_blank
|
|
|
|
expect(post2.user_deleted).to eq(true)
|
2021-05-25 10:04:10 +08:00
|
|
|
expect(post2.raw).to eq(I18n.t("js.topic.deleted_by_author_simple"))
|
2016-09-05 15:58:04 +08:00
|
|
|
expect(post2.version).to eq(2)
|
|
|
|
expect(called).to eq(1)
|
2017-11-10 07:05:53 +08:00
|
|
|
expect(user_stat.reload.post_count).to eq(0)
|
|
|
|
expect(user_stat.reload.topic_count).to eq(1)
|
2016-06-29 10:00:07 +08:00
|
|
|
|
2016-09-05 15:58:04 +08:00
|
|
|
called = 0
|
2023-11-29 13:38:07 +08:00
|
|
|
topic_recovered = ->(topic, user) do
|
2016-09-05 15:58:04 +08:00
|
|
|
expect(topic).to eq(post2.topic)
|
|
|
|
expect(user).to eq(post2.user)
|
|
|
|
called += 1
|
2023-11-29 13:38:07 +08:00
|
|
|
end
|
2016-09-05 15:58:04 +08:00
|
|
|
|
|
|
|
DiscourseEvent.on(:topic_recovered, &topic_recovered)
|
|
|
|
|
|
|
|
# lets try to recover
|
|
|
|
PostDestroyer.new(post2.user, post2).recover
|
|
|
|
post2.reload
|
|
|
|
expect(post2.version).to eq(3)
|
|
|
|
expect(post2.user_deleted).to eq(false)
|
|
|
|
expect(post2.cooked).to eq(@orig)
|
|
|
|
expect(called).to eq(1)
|
2017-11-10 07:05:53 +08:00
|
|
|
expect(user_stat.reload.post_count).to eq(0)
|
|
|
|
expect(user_stat.reload.topic_count).to eq(1)
|
2016-09-05 15:58:04 +08:00
|
|
|
ensure
|
|
|
|
DiscourseEvent.off(:topic_destroyed, &topic_destroyed)
|
|
|
|
DiscourseEvent.off(:topic_recovered, &topic_recovered)
|
|
|
|
end
|
2013-03-20 02:15:08 +08:00
|
|
|
end
|
|
|
|
|
2019-06-20 23:23:49 +08:00
|
|
|
it "maintains history when a user destroys a hidden post" do
|
|
|
|
post.hide!(PostActionType.types[:inappropriate])
|
|
|
|
PostDestroyer.new(post.user, post).destroy
|
|
|
|
expect(post.revisions[0].modifications["raw"]).to be_present
|
|
|
|
end
|
|
|
|
|
2017-11-03 03:33:40 +08:00
|
|
|
it "when topic is destroyed, it updates user_stats correctly" do
|
2018-07-14 00:15:59 +08:00
|
|
|
SiteSetting.min_topic_title_length = 5
|
|
|
|
post.topic.update_column(:title, "xyz")
|
|
|
|
|
2017-11-03 03:33:40 +08:00
|
|
|
user1 = post.user
|
|
|
|
user2 = Fabricate(:user)
|
|
|
|
reply = create_post(topic_id: post.topic_id, user: user2)
|
|
|
|
reply2 = create_post(topic_id: post.topic_id, user: user1)
|
|
|
|
expect(user1.user_stat.topic_count).to eq(1)
|
2017-11-10 07:05:53 +08:00
|
|
|
expect(user1.user_stat.post_count).to eq(1)
|
2017-11-03 03:33:40 +08:00
|
|
|
expect(user2.user_stat.topic_count).to eq(0)
|
|
|
|
expect(user2.user_stat.post_count).to eq(1)
|
2018-07-14 00:15:59 +08:00
|
|
|
|
2021-07-23 14:39:49 +08:00
|
|
|
PostDestroyer.new(admin, post).destroy
|
2017-11-03 03:33:40 +08:00
|
|
|
user1.reload
|
|
|
|
user2.reload
|
|
|
|
expect(user1.user_stat.topic_count).to eq(0)
|
|
|
|
expect(user1.user_stat.post_count).to eq(0)
|
|
|
|
expect(user2.user_stat.topic_count).to eq(0)
|
|
|
|
expect(user2.user_stat.post_count).to eq(0)
|
|
|
|
end
|
|
|
|
|
2022-02-16 09:49:11 +08:00
|
|
|
it "does not update post_count or topic_count to a negative number" do
|
|
|
|
user1 = post.user
|
|
|
|
reply2 = create_post(topic_id: post.topic_id, user: user1)
|
|
|
|
expect(user1.user_stat.topic_count).to eq(1)
|
|
|
|
expect(user1.user_stat.post_count).to eq(1)
|
|
|
|
|
|
|
|
user1.user_stat.update!(topic_count: 0)
|
|
|
|
user1.user_stat.update!(post_count: 0)
|
|
|
|
|
|
|
|
PostDestroyer.new(admin, post).destroy
|
|
|
|
user1.reload
|
|
|
|
expect(user1.user_stat.topic_count).to eq(0)
|
|
|
|
expect(user1.user_stat.post_count).to eq(0)
|
|
|
|
end
|
|
|
|
|
2021-03-11 22:34:54 +08:00
|
|
|
it "deletes the published page associated with the topic" do
|
|
|
|
slug = "my-published-page"
|
|
|
|
publish_result = PublishedPage.publish!(admin, post.topic, slug)
|
|
|
|
pp = publish_result.last
|
|
|
|
expect(publish_result.first).to eq(true)
|
|
|
|
|
|
|
|
PostDestroyer.new(admin, post).destroy
|
|
|
|
|
|
|
|
expect(PublishedPage.find_by(id: pp.id)).to be_nil
|
|
|
|
end
|
|
|
|
|
2017-06-16 11:27:51 +08:00
|
|
|
it "accepts a delete_removed_posts_after option" do
|
|
|
|
SiteSetting.delete_removed_posts_after = 0
|
|
|
|
|
2019-03-30 00:10:05 +08:00
|
|
|
post.update!(post_number: 2)
|
|
|
|
|
2017-06-16 11:27:51 +08:00
|
|
|
PostDestroyer.new(post.user, post, delete_removed_posts_after: 1).destroy
|
|
|
|
|
|
|
|
post.reload
|
|
|
|
|
|
|
|
expect(post.deleted_at).to eq(nil)
|
|
|
|
expect(post.user_deleted).to eq(true)
|
|
|
|
|
2021-05-25 10:04:10 +08:00
|
|
|
expect(post.raw).to eq(I18n.t("js.post.deleted_by_author_simple"))
|
2017-06-16 11:27:51 +08:00
|
|
|
end
|
|
|
|
|
2021-06-16 06:30:40 +08:00
|
|
|
it "runs the SyncTopicUserBookmarked for the topic that the post is in so topic_users.bookmarked is correct" do
|
|
|
|
post2 = create_post
|
|
|
|
PostDestroyer.new(post2.user, post2).destroy
|
|
|
|
expect_job_enqueued(job: :sync_topic_user_bookmarked, args: { topic_id: post2.topic_id })
|
|
|
|
end
|
|
|
|
|
2021-11-08 09:33:41 +08:00
|
|
|
it "skips post revise validations when post is marked for deletion by the author" do
|
|
|
|
SiteSetting.min_first_post_length = 100
|
|
|
|
post =
|
|
|
|
create_post(
|
|
|
|
raw: "this is a long post what passes the min_first_post_length validation " * 3,
|
|
|
|
)
|
|
|
|
PostDestroyer.new(post.user, post).destroy
|
|
|
|
post.reload
|
|
|
|
expect(post.errors).to be_blank
|
|
|
|
expect(post.revisions.count).to eq(1)
|
|
|
|
expect(post.raw).to eq(I18n.t("js.topic.deleted_by_author_simple"))
|
|
|
|
expect(post.user_deleted).to eq(true)
|
|
|
|
expect(post.topic.closed).to eq(true)
|
|
|
|
end
|
|
|
|
|
2013-03-20 02:15:08 +08:00
|
|
|
context "as a moderator" do
|
|
|
|
it "deletes the post" do
|
2015-09-19 00:48:43 +08:00
|
|
|
author = post.user
|
2017-11-10 07:05:53 +08:00
|
|
|
reply = create_post(topic_id: post.topic_id, user: author)
|
2015-09-19 00:48:43 +08:00
|
|
|
|
|
|
|
post_count = author.post_count
|
|
|
|
history_count = UserHistory.count
|
|
|
|
|
2017-11-10 07:05:53 +08:00
|
|
|
PostDestroyer.new(moderator, reply).destroy
|
2015-09-19 00:48:43 +08:00
|
|
|
|
2017-11-10 07:05:53 +08:00
|
|
|
expect(reply.deleted_at).to be_present
|
|
|
|
expect(reply.deleted_by).to eq(moderator)
|
2014-10-01 23:40:13 +08:00
|
|
|
|
2015-09-19 00:48:43 +08:00
|
|
|
author.reload
|
|
|
|
expect(author.post_count).to eq(post_count - 1)
|
|
|
|
expect(UserHistory.count).to eq(history_count + 1)
|
2014-10-01 23:40:13 +08:00
|
|
|
end
|
2014-08-15 03:21:10 +08:00
|
|
|
end
|
2013-05-03 15:56:23 +08:00
|
|
|
|
2022-07-28 00:14:14 +08:00
|
|
|
context "when deleted by user with access to moderate topic category" do
|
2020-07-22 09:57:16 +08:00
|
|
|
fab!(:review_user) { Fabricate(:user) }
|
|
|
|
|
|
|
|
before do
|
|
|
|
SiteSetting.enable_category_group_moderation = true
|
|
|
|
review_group = Fabricate(:group)
|
2024-09-04 09:38:46 +08:00
|
|
|
review_category = Fabricate(:category)
|
|
|
|
Fabricate(:category_moderation_group, category: review_category, group: review_group)
|
2020-07-22 09:57:16 +08:00
|
|
|
post.topic.update!(category: review_category)
|
|
|
|
review_group.users << review_user
|
|
|
|
end
|
|
|
|
|
|
|
|
context "when the post has a reviewable" do
|
|
|
|
it "deletes the post" do
|
|
|
|
author = post.user
|
|
|
|
reply = create_post(topic_id: post.topic_id, user: author)
|
|
|
|
ReviewableFlaggedPost.needs_review!(target: reply, created_by: Fabricate(:user))
|
|
|
|
|
|
|
|
post_count = author.post_count
|
|
|
|
history_count = UserHistory.count
|
|
|
|
|
|
|
|
PostDestroyer.new(review_user, reply).destroy
|
|
|
|
|
|
|
|
expect(reply.deleted_at).to be_present
|
|
|
|
expect(reply.deleted_by).to eq(review_user)
|
|
|
|
|
|
|
|
author.reload
|
|
|
|
expect(author.post_count).to eq(post_count - 1)
|
|
|
|
expect(UserHistory.count).to eq(history_count + 1)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2014-08-15 03:21:10 +08:00
|
|
|
context "as an admin" do
|
2013-05-03 15:56:23 +08:00
|
|
|
it "deletes the post" do
|
2014-08-15 03:21:10 +08:00
|
|
|
PostDestroyer.new(admin, post).destroy
|
2015-01-10 00:34:37 +08:00
|
|
|
expect(post.deleted_at).to be_present
|
|
|
|
expect(post.deleted_by).to eq(admin)
|
2013-05-03 15:56:23 +08:00
|
|
|
end
|
2014-08-15 03:21:10 +08:00
|
|
|
|
2017-11-10 07:05:53 +08:00
|
|
|
it "updates the user's topic_count for first post" do
|
2014-08-15 03:21:10 +08:00
|
|
|
author = post.user
|
|
|
|
expect {
|
|
|
|
PostDestroyer.new(admin, post).destroy
|
|
|
|
author.reload
|
2017-11-10 07:05:53 +08:00
|
|
|
}.to change { author.topic_count }.by(-1)
|
|
|
|
expect(author.user_stat.post_count).to eq(0)
|
|
|
|
end
|
|
|
|
|
|
|
|
it "updates the user's post_count for reply" do
|
|
|
|
author = post.user
|
|
|
|
reply = create_post(topic: post.topic, user: author)
|
|
|
|
expect {
|
|
|
|
PostDestroyer.new(admin, reply).destroy
|
|
|
|
author.reload
|
2014-08-15 03:21:10 +08:00
|
|
|
}.to change { author.post_count }.by(-1)
|
2017-11-10 07:05:53 +08:00
|
|
|
expect(author.user_stat.topic_count).to eq(1)
|
2014-08-15 03:21:10 +08:00
|
|
|
end
|
2017-11-03 05:11:08 +08:00
|
|
|
|
|
|
|
it "doesn't count whispers" do
|
|
|
|
user_stat = admin.user_stat
|
|
|
|
whisper =
|
|
|
|
PostCreator.new(
|
|
|
|
admin,
|
|
|
|
topic_id: post.topic.id,
|
|
|
|
reply_to_post_number: 1,
|
|
|
|
post_type: Post.types[:whisper],
|
|
|
|
raw: "this is a whispered reply",
|
|
|
|
).create
|
|
|
|
expect(user_stat.reload.post_count).to eq(0)
|
|
|
|
expect { PostDestroyer.new(admin, whisper).destroy }.to_not change {
|
|
|
|
user_stat.reload.post_count
|
|
|
|
}
|
|
|
|
end
|
2013-05-03 15:56:23 +08:00
|
|
|
end
|
2013-03-20 02:15:08 +08:00
|
|
|
end
|
|
|
|
|
2022-07-28 00:14:14 +08:00
|
|
|
describe "private message" do
|
2019-05-07 11:12:20 +08:00
|
|
|
fab!(:author) { Fabricate(:user) }
|
|
|
|
fab!(:private_message) { Fabricate(:private_message_topic, user: author) }
|
|
|
|
fab!(:first_post) { Fabricate(:post, topic: private_message, user: author) }
|
|
|
|
fab!(:second_post) { Fabricate(:post, topic: private_message, user: author, post_number: 2) }
|
2018-07-04 10:50:51 +08:00
|
|
|
|
|
|
|
it "doesn't update post_count for a reply" do
|
|
|
|
expect {
|
|
|
|
PostDestroyer.new(admin, second_post).destroy
|
|
|
|
author.reload
|
|
|
|
}.to_not change { author.post_count }
|
|
|
|
|
|
|
|
expect { PostDestroyer.new(admin, second_post).recover }.to_not change { author.post_count }
|
|
|
|
end
|
|
|
|
|
|
|
|
it "doesn't update topic_count for first post" do
|
|
|
|
expect {
|
|
|
|
PostDestroyer.new(admin, first_post).destroy
|
|
|
|
author.reload
|
|
|
|
}.to_not change { author.topic_count }
|
|
|
|
expect(author.post_count).to eq(0) # also unchanged
|
|
|
|
end
|
2018-10-05 16:53:59 +08:00
|
|
|
|
|
|
|
it "triggers the extensibility events" do
|
|
|
|
events = DiscourseEvent.track_events { PostDestroyer.new(admin, first_post).destroy }.last(2)
|
|
|
|
|
|
|
|
expect(events[0][:event_name]).to eq(:post_destroyed)
|
|
|
|
expect(events[0][:params].first).to eq(first_post)
|
|
|
|
|
|
|
|
expect(events[1][:event_name]).to eq(:topic_destroyed)
|
|
|
|
expect(events[1][:params].first).to eq(first_post.topic)
|
|
|
|
end
|
2020-09-02 08:10:42 +08:00
|
|
|
|
|
|
|
it "should not log a personal message view" do
|
|
|
|
SiteSetting.log_personal_messages_views = true
|
|
|
|
Fabricate(:topic_web_hook)
|
|
|
|
StaffActionLogger.any_instance.expects(:log_check_personal_message).never
|
|
|
|
PostDestroyer.new(admin, first_post).destroy
|
|
|
|
end
|
2018-07-04 10:50:51 +08:00
|
|
|
end
|
|
|
|
|
2021-07-23 14:50:28 +08:00
|
|
|
describe "deleting a post directly after a whisper" do
|
2022-12-17 00:42:51 +08:00
|
|
|
before { SiteSetting.whispers_allowed_groups = "#{Group::AUTO_GROUPS[:staff]}" }
|
2021-07-23 14:50:28 +08:00
|
|
|
|
|
|
|
it "should not set Topic#last_post_user_id to a whisperer" do
|
|
|
|
post_1 = create_post(topic: post.topic, user: moderator)
|
2022-06-30 08:18:12 +08:00
|
|
|
create_post(topic: post.topic, user: Fabricate(:user), post_type: Post.types[:whisper])
|
2021-07-23 14:50:28 +08:00
|
|
|
whisper_2 =
|
|
|
|
create_post(topic: post.topic, user: Fabricate(:user), post_type: Post.types[:whisper])
|
|
|
|
|
|
|
|
PostDestroyer.new(admin, whisper_2).destroy
|
|
|
|
|
|
|
|
expect(post.topic.reload.last_post_user_id).to eq(post_1.user.id)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2022-07-28 00:14:14 +08:00
|
|
|
describe "deleting the second post in a topic" do
|
2023-12-13 11:50:13 +08:00
|
|
|
fab!(:user) { Fabricate(:user, refresh_auto_groups: true) }
|
2013-07-22 13:06:53 +08:00
|
|
|
let!(:post) { create_post(user: user) }
|
2018-07-14 00:15:59 +08:00
|
|
|
let(:topic) { post.topic }
|
2021-12-16 01:41:14 +08:00
|
|
|
fab!(:second_user) { coding_horror }
|
2013-07-22 13:06:53 +08:00
|
|
|
let!(:second_post) { create_post(topic: topic, user: second_user) }
|
2013-03-20 02:15:08 +08:00
|
|
|
|
|
|
|
before do
|
|
|
|
PostDestroyer.new(moderator, second_post).destroy
|
2018-07-14 00:15:59 +08:00
|
|
|
topic.reload
|
2013-03-20 02:15:08 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
it "resets the last_poster_id back to the OP" do
|
2015-01-10 00:34:37 +08:00
|
|
|
expect(topic.last_post_user_id).to eq(user.id)
|
2013-03-20 02:15:08 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
it "resets the last_posted_at back to the OP" do
|
2015-01-10 00:34:37 +08:00
|
|
|
expect(topic.last_posted_at.to_i).to eq(post.created_at.to_i)
|
2013-03-20 02:15:08 +08:00
|
|
|
end
|
|
|
|
|
2018-07-14 00:15:59 +08:00
|
|
|
it "resets the highest_post_number" do
|
|
|
|
expect(topic.highest_post_number).to eq(post.post_number)
|
|
|
|
end
|
|
|
|
|
2022-07-28 00:14:14 +08:00
|
|
|
context "with topic_user" do
|
2014-05-06 21:41:59 +08:00
|
|
|
let(:topic_user) { second_user.topic_users.find_by(topic_id: topic.id) }
|
2013-03-20 02:15:08 +08:00
|
|
|
|
|
|
|
it "clears the posted flag for the second user" do
|
2015-01-10 00:34:37 +08:00
|
|
|
expect(topic_user.posted?).to eq(false)
|
2013-03-20 02:15:08 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
it "sets the second user's last_read_post_number back to 1" do
|
2015-01-10 00:34:37 +08:00
|
|
|
expect(topic_user.last_read_post_number).to eq(1)
|
2013-03-20 02:15:08 +08:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2022-07-28 00:14:14 +08:00
|
|
|
describe "deleting a post belonging to a deleted topic" do
|
2013-07-23 23:50:58 +08:00
|
|
|
let!(:topic) { post.topic }
|
2017-11-03 04:43:09 +08:00
|
|
|
let(:author) { post.user }
|
2013-07-23 23:50:58 +08:00
|
|
|
|
|
|
|
before do
|
|
|
|
topic.trash!(admin)
|
|
|
|
post.reload
|
|
|
|
end
|
|
|
|
|
|
|
|
context "as a moderator" do
|
|
|
|
before { PostDestroyer.new(moderator, post).destroy }
|
|
|
|
|
|
|
|
it "deletes the post" do
|
2015-01-10 00:34:37 +08:00
|
|
|
expect(post.deleted_at).to be_present
|
|
|
|
expect(post.deleted_by).to eq(moderator)
|
2017-11-03 04:43:09 +08:00
|
|
|
expect(author.user_stat.post_count).to eq(0)
|
2013-07-23 23:50:58 +08:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context "as an admin" do
|
2023-06-21 22:00:19 +08:00
|
|
|
subject(:destroyer) { PostDestroyer.new(admin, post).destroy }
|
2013-07-23 23:50:58 +08:00
|
|
|
|
|
|
|
it "deletes the post" do
|
2023-06-21 22:00:19 +08:00
|
|
|
destroyer
|
2015-01-10 00:34:37 +08:00
|
|
|
expect(post.deleted_at).to be_present
|
|
|
|
expect(post.deleted_by).to eq(admin)
|
2013-07-23 23:50:58 +08:00
|
|
|
end
|
2014-10-01 23:40:13 +08:00
|
|
|
|
|
|
|
it "creates a new user history entry" do
|
2023-06-21 22:00:19 +08:00
|
|
|
expect { destroyer }.to change { UserHistory.count }.by(1)
|
2017-11-03 04:43:09 +08:00
|
|
|
end
|
2018-10-05 16:53:59 +08:00
|
|
|
|
|
|
|
it "triggers a extensibility event" do
|
2023-06-21 22:00:19 +08:00
|
|
|
events = DiscourseEvent.track_events { destroyer }
|
2018-10-05 16:53:59 +08:00
|
|
|
|
|
|
|
expect(events[0][:event_name]).to eq(:post_destroyed)
|
|
|
|
expect(events[0][:params].first).to eq(post)
|
|
|
|
end
|
2017-11-03 04:43:09 +08:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2022-07-28 00:14:14 +08:00
|
|
|
describe "deleting a reply belonging to a deleted topic" do
|
2017-11-03 04:43:09 +08:00
|
|
|
let!(:topic) { post.topic }
|
|
|
|
let!(:reply) { create_post(topic_id: topic.id, user: post.user) }
|
|
|
|
let(:author) { reply.user }
|
|
|
|
|
|
|
|
before do
|
|
|
|
topic.trash!(admin)
|
|
|
|
post.reload
|
|
|
|
reply.reload
|
|
|
|
end
|
|
|
|
|
|
|
|
context "as a moderator" do
|
2023-06-21 22:00:19 +08:00
|
|
|
subject(:destroyer) { PostDestroyer.new(moderator, reply).destroy }
|
2017-11-03 04:43:09 +08:00
|
|
|
|
|
|
|
it "deletes the reply" do
|
2023-06-21 22:00:19 +08:00
|
|
|
destroyer
|
2017-11-03 04:43:09 +08:00
|
|
|
expect(reply.deleted_at).to be_present
|
|
|
|
expect(reply.deleted_by).to eq(moderator)
|
|
|
|
end
|
|
|
|
|
|
|
|
it "doesn't decrement post_count again" do
|
2023-06-21 22:00:19 +08:00
|
|
|
expect { destroyer }.to_not change { author.user_stat.post_count }
|
2017-11-03 04:43:09 +08:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context "as an admin" do
|
2023-06-21 22:00:19 +08:00
|
|
|
subject(:destroyer) { PostDestroyer.new(admin, reply).destroy }
|
2017-11-03 04:43:09 +08:00
|
|
|
|
|
|
|
it "deletes the post" do
|
2023-06-21 22:00:19 +08:00
|
|
|
destroyer
|
2017-11-03 04:43:09 +08:00
|
|
|
expect(reply.deleted_at).to be_present
|
|
|
|
expect(reply.deleted_by).to eq(admin)
|
|
|
|
end
|
|
|
|
|
|
|
|
it "doesn't decrement post_count again" do
|
2023-06-21 22:00:19 +08:00
|
|
|
expect { destroyer }.to_not change { author.user_stat.post_count }
|
2017-11-03 04:43:09 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
it "creates a new user history entry" do
|
2023-06-21 22:00:19 +08:00
|
|
|
expect { destroyer }.to change { UserHistory.count }.by(1)
|
2014-10-01 23:40:13 +08:00
|
|
|
end
|
2013-07-23 23:50:58 +08:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2018-11-22 22:08:37 +08:00
|
|
|
it "deletes a post belonging to a non-existent topic" do
|
|
|
|
DB.exec("DELETE FROM topics WHERE id = ?", post.topic_id)
|
|
|
|
post.reload
|
|
|
|
|
|
|
|
PostDestroyer.new(admin, post).destroy
|
|
|
|
|
|
|
|
expect(post.deleted_at).to be_present
|
|
|
|
expect(post.deleted_by).to eq(admin)
|
|
|
|
end
|
|
|
|
|
2013-03-20 02:15:08 +08:00
|
|
|
describe "after delete" do
|
2021-12-16 01:41:14 +08:00
|
|
|
fab!(:coding_horror) { coding_horror }
|
2019-05-07 11:12:20 +08:00
|
|
|
fab!(:post) { Fabricate(:post, raw: "Hello @CodingHorror") }
|
2013-03-20 02:15:08 +08:00
|
|
|
|
|
|
|
it "should feature the users again (in case they've changed)" do
|
2020-07-24 17:16:52 +08:00
|
|
|
expect_enqueued_with(job: :feature_topic_users, args: { topic_id: post.topic_id }) do
|
|
|
|
PostDestroyer.new(moderator, post).destroy
|
|
|
|
end
|
2013-03-20 02:15:08 +08:00
|
|
|
end
|
|
|
|
|
2020-08-12 08:16:26 +08:00
|
|
|
describe "incoming email and imap sync" do
|
|
|
|
fab!(:incoming) { Fabricate(:incoming_email, post: post, topic: post.topic) }
|
|
|
|
|
|
|
|
it "does nothing if imap not enabled" do
|
|
|
|
IncomingEmail.expects(:find_by).never
|
|
|
|
PostDestroyer.new(moderator, post).destroy
|
|
|
|
end
|
|
|
|
|
|
|
|
it "does nothing if the incoming email has no imap_uid" do
|
|
|
|
SiteSetting.enable_imap = true
|
|
|
|
PostDestroyer.new(moderator, post).destroy
|
|
|
|
expect(incoming.reload.imap_sync).to eq(false)
|
|
|
|
end
|
|
|
|
|
|
|
|
it "sets imap_sync to true for the matching incoming" do
|
|
|
|
SiteSetting.enable_imap = true
|
|
|
|
incoming.update(imap_uid: 999)
|
|
|
|
PostDestroyer.new(moderator, post).destroy
|
|
|
|
expect(incoming.reload.imap_sync).to eq(true)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2022-07-28 00:14:14 +08:00
|
|
|
context "with a reply" do
|
2019-05-07 11:12:20 +08:00
|
|
|
fab!(:reply) { Fabricate(:basic_reply, user: coding_horror, topic: post.topic) }
|
2020-01-18 00:24:49 +08:00
|
|
|
let!(:post_reply) { PostReply.create(post_id: post.id, reply_post_id: reply.id) }
|
2013-03-20 02:15:08 +08:00
|
|
|
|
|
|
|
it "changes the post count of the topic" do
|
|
|
|
post.reload
|
2015-01-10 00:34:37 +08:00
|
|
|
expect {
|
2013-03-20 02:15:08 +08:00
|
|
|
PostDestroyer.new(moderator, reply).destroy
|
|
|
|
post.topic.reload
|
2015-01-10 00:34:37 +08:00
|
|
|
}.to change(post.topic, :posts_count).by(-1)
|
2013-03-20 02:15:08 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
it "lowers the reply_count when the reply is deleted" do
|
|
|
|
expect { PostDestroyer.new(moderator, reply).destroy }.to change(
|
2015-01-10 00:34:37 +08:00
|
|
|
post.post_replies,
|
|
|
|
:count,
|
|
|
|
).by(-1)
|
2013-03-20 02:15:08 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
it "should increase the post_number when there are deletion gaps" do
|
|
|
|
PostDestroyer.new(moderator, reply).destroy
|
|
|
|
p = Fabricate(:post, user: post.user, topic: post.topic)
|
2015-01-10 00:34:37 +08:00
|
|
|
expect(p.post_number).to eq(3)
|
2013-03-20 02:15:08 +08:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2022-07-28 00:14:14 +08:00
|
|
|
describe "@mentions" do
|
2013-03-20 02:15:08 +08:00
|
|
|
it "removes notifications when deleted" do
|
2019-03-14 22:47:38 +08:00
|
|
|
Jobs.run_immediately!
|
2014-03-18 12:22:39 +08:00
|
|
|
user = Fabricate(:evil_trout)
|
|
|
|
post = create_post(raw: "Hello @eviltrout")
|
2021-07-23 14:39:49 +08:00
|
|
|
expect { PostDestroyer.new(moderator, post).destroy }.to change(
|
2015-01-10 00:34:37 +08:00
|
|
|
user.notifications,
|
|
|
|
:count,
|
|
|
|
).by(-1)
|
2013-03-20 02:15:08 +08:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2013-06-06 04:00:45 +08:00
|
|
|
describe "post actions" do
|
|
|
|
let(:second_post) { Fabricate(:post, topic_id: post.topic_id) }
|
2019-01-04 01:03:01 +08:00
|
|
|
let(:flag_result) { PostActionCreator.off_topic(moderator, second_post) }
|
|
|
|
let!(:flag) { flag_result.post_action }
|
2013-03-20 02:15:08 +08:00
|
|
|
|
2018-11-30 01:14:18 +08:00
|
|
|
before { Jobs::SendSystemMessage.clear }
|
2018-07-25 05:17:47 +08:00
|
|
|
|
2018-07-25 07:25:00 +08:00
|
|
|
it "should delete public post actions and agree with flags" do
|
2019-01-21 22:51:09 +08:00
|
|
|
url = second_post.url
|
2018-11-28 12:51:11 +08:00
|
|
|
PostDestroyer.new(moderator, second_post).destroy
|
2013-06-06 04:00:45 +08:00
|
|
|
|
2014-07-29 01:17:37 +08:00
|
|
|
off_topic = PostAction.find_by(id: flag.id)
|
2015-01-10 00:34:37 +08:00
|
|
|
expect(off_topic).not_to eq(nil)
|
|
|
|
expect(off_topic.agreed_at).not_to eq(nil)
|
2014-07-29 01:17:37 +08:00
|
|
|
|
2013-06-06 04:00:45 +08:00
|
|
|
second_post.reload
|
2015-01-10 00:34:37 +08:00
|
|
|
expect(second_post.off_topic_count).to eq(1)
|
2018-07-25 05:17:47 +08:00
|
|
|
|
2019-01-21 14:57:23 +08:00
|
|
|
jobs = Jobs::SendSystemMessage.jobs
|
|
|
|
expect(jobs.size).to eq(1)
|
|
|
|
|
|
|
|
Jobs::SendSystemMessage.new.execute(jobs[0]["args"][0].with_indifferent_access)
|
|
|
|
|
2019-01-21 22:51:09 +08:00
|
|
|
expect(Post.last.raw).to eq(
|
|
|
|
I18n.t(
|
|
|
|
"system_messages.flags_agreed_and_post_deleted.text_body_template",
|
|
|
|
flagged_post_raw_content: second_post.raw,
|
|
|
|
url: url,
|
|
|
|
flag_reason:
|
|
|
|
I18n.t(
|
|
|
|
"flag_reasons.#{PostActionType.flag_types[off_topic.post_action_type_id]}",
|
|
|
|
locale: SiteSetting.default_locale,
|
|
|
|
base_path: Discourse.base_path,
|
|
|
|
),
|
|
|
|
site_name: SiteSetting.title,
|
|
|
|
base_url: Discourse.base_url,
|
|
|
|
).strip,
|
|
|
|
)
|
2013-03-20 02:15:08 +08:00
|
|
|
end
|
2018-07-25 07:25:00 +08:00
|
|
|
|
|
|
|
it "should not send the flags_agreed_and_post_deleted message if it was deleted by system" do
|
2019-01-04 01:03:01 +08:00
|
|
|
expect(ReviewableFlaggedPost.pending.count).to eq(1)
|
2018-11-28 12:51:11 +08:00
|
|
|
PostDestroyer.new(Discourse.system_user, second_post).destroy
|
2018-11-30 01:14:18 +08:00
|
|
|
expect(Jobs::SendSystemMessage.jobs.size).to eq(0)
|
2019-01-04 01:03:01 +08:00
|
|
|
expect(ReviewableFlaggedPost.pending.count).to eq(0)
|
2018-07-25 07:25:00 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
it "should not send the flags_agreed_and_post_deleted message if it was deleted by author" do
|
|
|
|
SiteSetting.delete_removed_posts_after = 0
|
2019-01-04 01:03:01 +08:00
|
|
|
expect(ReviewableFlaggedPost.pending.count).to eq(1)
|
2018-11-28 12:51:11 +08:00
|
|
|
PostDestroyer.new(second_post.user, second_post).destroy
|
2018-11-30 01:14:18 +08:00
|
|
|
expect(Jobs::SendSystemMessage.jobs.size).to eq(0)
|
2019-01-04 01:03:01 +08:00
|
|
|
expect(ReviewableFlaggedPost.pending.count).to eq(0)
|
2018-07-25 07:25:00 +08:00
|
|
|
end
|
2018-07-27 03:12:12 +08:00
|
|
|
|
2019-01-04 01:03:01 +08:00
|
|
|
it "should not send the flags_agreed_and_post_deleted message if flags were ignored" do
|
|
|
|
expect(ReviewableFlaggedPost.pending.count).to eq(1)
|
2023-03-02 23:40:53 +08:00
|
|
|
flag_result.reviewable.perform(moderator, :ignore_and_do_nothing)
|
2018-07-27 03:12:12 +08:00
|
|
|
second_post.reload
|
2019-01-04 01:03:01 +08:00
|
|
|
expect(ReviewableFlaggedPost.pending.count).to eq(0)
|
2018-11-30 01:14:18 +08:00
|
|
|
|
2018-11-28 12:51:11 +08:00
|
|
|
PostDestroyer.new(moderator, second_post).destroy
|
2018-11-30 01:14:18 +08:00
|
|
|
expect(Jobs::SendSystemMessage.jobs.size).to eq(0)
|
|
|
|
end
|
|
|
|
|
|
|
|
it "should not send the flags_agreed_and_post_deleted message if defer_flags is true" do
|
2019-01-04 01:03:01 +08:00
|
|
|
expect(ReviewableFlaggedPost.pending.count).to eq(1)
|
2018-11-30 01:14:18 +08:00
|
|
|
PostDestroyer.new(moderator, second_post, defer_flags: true).destroy
|
|
|
|
expect(Jobs::SendSystemMessage.jobs.size).to eq(0)
|
2019-01-04 01:03:01 +08:00
|
|
|
expect(ReviewableFlaggedPost.pending.count).to eq(0)
|
2018-07-27 03:12:12 +08:00
|
|
|
end
|
2024-12-04 11:46:52 +08:00
|
|
|
|
|
|
|
context "when custom flags" do
|
|
|
|
fab!(:custom_flag) { Fabricate(:flag, name: "custom flag", notify_type: true) }
|
|
|
|
let(:third_post) { Fabricate(:post, topic_id: post.topic_id) }
|
|
|
|
|
|
|
|
it "should send message to user with correct translation" do
|
|
|
|
PostActionCreator.new(
|
|
|
|
moderator,
|
|
|
|
third_post,
|
|
|
|
custom_flag.id,
|
|
|
|
is_warning: false,
|
|
|
|
flag_topic: true,
|
|
|
|
).perform
|
|
|
|
PostDestroyer.new(moderator, third_post, { reviewable: Reviewable.last }).destroy
|
|
|
|
jobs = Jobs::SendSystemMessage.jobs
|
|
|
|
expect(jobs.size).to eq(1)
|
|
|
|
|
|
|
|
Jobs::SendSystemMessage.new.execute(jobs[0]["args"][0].with_indifferent_access)
|
|
|
|
|
|
|
|
expect(Post.last.raw).to match("custom flag")
|
|
|
|
custom_flag.destroy!
|
|
|
|
end
|
|
|
|
end
|
2013-03-20 02:15:08 +08:00
|
|
|
end
|
|
|
|
|
2014-06-04 23:41:11 +08:00
|
|
|
describe "user actions" do
|
2021-12-16 01:41:14 +08:00
|
|
|
let(:codinghorror) { coding_horror }
|
2014-06-04 23:41:11 +08:00
|
|
|
let(:second_post) { Fabricate(:post, topic_id: post.topic_id) }
|
|
|
|
|
|
|
|
def create_user_action(action_type)
|
|
|
|
UserAction.log_action!(
|
|
|
|
action_type: action_type,
|
|
|
|
user_id: codinghorror.id,
|
|
|
|
acting_user_id: codinghorror.id,
|
|
|
|
target_topic_id: second_post.topic_id,
|
|
|
|
target_post_id: second_post.id,
|
|
|
|
)
|
|
|
|
end
|
|
|
|
|
|
|
|
it "should delete the user actions" do
|
|
|
|
like = create_user_action(UserAction::LIKE)
|
|
|
|
|
|
|
|
PostDestroyer.new(moderator, second_post).destroy
|
|
|
|
|
2014-09-26 01:51:00 +08:00
|
|
|
expect(UserAction.find_by(id: like.id)).to be_nil
|
2014-06-04 23:41:11 +08:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2013-06-14 01:41:45 +08:00
|
|
|
describe "topic links" do
|
2019-05-07 11:12:20 +08:00
|
|
|
fab!(:first_post) { Fabricate(:post) }
|
2013-06-14 01:41:45 +08:00
|
|
|
let!(:topic) { first_post.topic }
|
|
|
|
let!(:second_post) { Fabricate(:post_with_external_links, topic: topic) }
|
|
|
|
|
|
|
|
before { TopicLink.extract_from(second_post) }
|
|
|
|
|
|
|
|
it "should destroy the topic links when moderator destroys the post" do
|
|
|
|
PostDestroyer.new(moderator, second_post.reload).destroy
|
|
|
|
expect(topic.topic_links.count).to eq(0)
|
|
|
|
end
|
|
|
|
|
|
|
|
it "should destroy the topic links when the user destroys the post" do
|
|
|
|
PostDestroyer.new(second_post.user, second_post.reload).destroy
|
|
|
|
expect(topic.topic_links.count).to eq(0)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2021-06-02 02:02:53 +08:00
|
|
|
describe "internal links" do
|
2023-11-10 06:47:59 +08:00
|
|
|
fab!(:topic)
|
2021-06-02 02:02:53 +08:00
|
|
|
let!(:second_post) { Fabricate(:post, topic: topic) }
|
|
|
|
fab!(:other_topic) { Fabricate(:topic) }
|
|
|
|
let!(:other_post) { Fabricate(:post, topic: other_topic) }
|
2024-01-18 14:08:40 +08:00
|
|
|
fab!(:user) { Fabricate(:user, refresh_auto_groups: true) }
|
2021-06-02 02:02:53 +08:00
|
|
|
let!(:base_url) { URI.parse(Discourse.base_url) }
|
|
|
|
let!(:guardian) { Guardian.new }
|
|
|
|
let!(:url) do
|
|
|
|
"http://#{base_url.host}/t/#{other_topic.slug}/#{other_topic.id}/#{other_post.post_number}"
|
2023-01-09 19:18:21 +08:00
|
|
|
end
|
2021-06-02 02:02:53 +08:00
|
|
|
|
|
|
|
it "should destroy internal links when user deletes own post" do
|
|
|
|
new_post = Post.create!(user: user, topic: topic, raw: "Link to other topic:\n\n#{url}\n")
|
|
|
|
TopicLink.extract_from(new_post)
|
|
|
|
|
|
|
|
link_counts = TopicLink.counts_for(guardian, other_topic.reload, [other_post])
|
|
|
|
expect(link_counts.count).to eq(1)
|
|
|
|
|
|
|
|
PostDestroyer.new(user, new_post).destroy
|
|
|
|
|
|
|
|
updated_link_counts = TopicLink.counts_for(guardian, other_topic.reload, [other_post])
|
|
|
|
expect(updated_link_counts.count).to eq(0)
|
|
|
|
end
|
|
|
|
|
|
|
|
it "should destroy internal links when moderator deletes post" do
|
2022-02-07 11:23:34 +08:00
|
|
|
new_post = create_post(user: user, topic: topic, raw: "Link to other topic:\n\n#{url}\n")
|
2021-06-02 02:02:53 +08:00
|
|
|
TopicLink.extract_from(new_post)
|
|
|
|
link_counts = TopicLink.counts_for(guardian, other_topic.reload, [other_post])
|
|
|
|
expect(link_counts.count).to eq(1)
|
|
|
|
|
|
|
|
PostDestroyer.new(moderator, new_post).destroy
|
|
|
|
TopicLink.extract_from(new_post)
|
|
|
|
updated_link_counts = TopicLink.counts_for(guardian, other_topic, [other_post])
|
|
|
|
|
|
|
|
expect(updated_link_counts.count).to eq(0)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2021-12-09 01:12:24 +08:00
|
|
|
describe ".delete_with_replies" do
|
|
|
|
subject(:delete_with_replies) do
|
|
|
|
PostDestroyer.delete_with_replies(reporter, post, defer_reply_flags: defer_reply_flags)
|
2023-01-09 19:18:21 +08:00
|
|
|
end
|
2021-12-09 01:12:24 +08:00
|
|
|
|
2023-11-10 06:47:59 +08:00
|
|
|
fab!(:post)
|
2021-12-09 01:12:24 +08:00
|
|
|
let(:reporter) { Discourse.system_user }
|
|
|
|
let(:reply) { Fabricate(:post, topic: post.topic) }
|
|
|
|
let(:reviewable_reply) { PostActionCreator.off_topic(reporter, reply).reviewable }
|
2019-11-28 04:19:44 +08:00
|
|
|
|
|
|
|
before do
|
|
|
|
post.update(replies: [reply])
|
|
|
|
PostActionCreator.off_topic(reporter, post)
|
2021-12-09 01:12:24 +08:00
|
|
|
reviewable_reply
|
2019-11-28 04:19:44 +08:00
|
|
|
end
|
|
|
|
|
2021-12-09 01:12:24 +08:00
|
|
|
context "when deferring reply flags" do
|
|
|
|
let(:defer_reply_flags) { true }
|
2019-11-28 04:19:44 +08:00
|
|
|
|
2021-12-09 01:12:24 +08:00
|
|
|
it "ignores flagged replies" do
|
|
|
|
delete_with_replies
|
|
|
|
expect(reviewable_reply.reload).to be_ignored
|
|
|
|
end
|
2019-11-28 04:19:44 +08:00
|
|
|
end
|
|
|
|
|
2021-12-09 01:12:24 +08:00
|
|
|
context "when not deferring reply flags" do
|
|
|
|
let(:defer_reply_flags) { false }
|
2019-11-28 04:19:44 +08:00
|
|
|
|
2021-12-09 01:12:24 +08:00
|
|
|
it "approves flagged replies" do
|
|
|
|
delete_with_replies
|
|
|
|
expect(reviewable_reply.reload).to be_approved
|
|
|
|
end
|
2019-11-28 04:19:44 +08:00
|
|
|
end
|
|
|
|
end
|
2019-12-10 03:15:47 +08:00
|
|
|
|
|
|
|
describe "featured topics for user_profiles" do
|
2023-11-10 06:47:59 +08:00
|
|
|
fab!(:user)
|
2019-12-10 03:15:47 +08:00
|
|
|
|
|
|
|
it "clears the user_profiles featured_topic column" do
|
|
|
|
user.user_profile.update(featured_topic: post.topic)
|
|
|
|
PostDestroyer.new(admin, post).destroy
|
|
|
|
expect(user.user_profile.reload.featured_topic).to eq(nil)
|
|
|
|
end
|
|
|
|
end
|
2020-11-10 12:40:48 +08:00
|
|
|
|
|
|
|
describe "permanent destroy" do
|
2023-11-10 06:47:59 +08:00
|
|
|
fab!(:private_message_topic)
|
2020-11-10 12:40:48 +08:00
|
|
|
fab!(:private_post) { Fabricate(:private_message_post, topic: private_message_topic) }
|
2020-11-17 04:40:36 +08:00
|
|
|
fab!(:post_action) { Fabricate(:post_action, post: private_post) }
|
2020-11-10 12:40:48 +08:00
|
|
|
fab!(:reply) { Fabricate(:private_message_post, topic: private_message_topic) }
|
2021-03-25 09:34:53 +08:00
|
|
|
fab!(:post_revision) { Fabricate(:post_revision, post: private_post) }
|
|
|
|
fab!(:upload1) { Fabricate(:upload_s3, created_at: 5.hours.ago) }
|
2022-06-09 07:24:30 +08:00
|
|
|
fab!(:upload_reference) { UploadReference.create(target: private_post, upload: upload1) }
|
2021-02-02 05:57:31 +08:00
|
|
|
|
2020-11-10 12:40:48 +08:00
|
|
|
it "destroys the post and topic if deleting first post" do
|
|
|
|
PostDestroyer.new(reply.user, reply, permanent: true).destroy
|
|
|
|
expect { reply.reload }.to raise_error(ActiveRecord::RecordNotFound)
|
|
|
|
expect(private_message_topic.reload.persisted?).to be true
|
|
|
|
|
|
|
|
PostDestroyer.new(private_post.user, private_post, permanent: true).destroy
|
|
|
|
expect { private_post.reload }.to raise_error(ActiveRecord::RecordNotFound)
|
|
|
|
expect { private_message_topic.reload }.to raise_error(ActiveRecord::RecordNotFound)
|
2020-11-17 04:40:36 +08:00
|
|
|
expect { post_action.reload }.to raise_error(ActiveRecord::RecordNotFound)
|
2021-03-25 09:34:53 +08:00
|
|
|
expect { post_revision.reload }.to raise_error(ActiveRecord::RecordNotFound)
|
2022-06-09 07:24:30 +08:00
|
|
|
expect { upload_reference.reload }.to raise_error(ActiveRecord::RecordNotFound)
|
2021-03-25 09:34:53 +08:00
|
|
|
|
|
|
|
Jobs::CleanUpUploads.new.reset_last_cleanup!
|
|
|
|
SiteSetting.clean_orphan_uploads_grace_period_hours = 1
|
|
|
|
Jobs::CleanUpUploads.new.execute({})
|
|
|
|
expect { upload1.reload }.to raise_error(ActiveRecord::RecordNotFound)
|
2020-11-10 12:40:48 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
it "soft delete if not creator of post or not private message" do
|
|
|
|
PostDestroyer.new(moderator, reply, permanent: true).destroy
|
|
|
|
expect(reply.deleted_at).not_to eq(nil)
|
|
|
|
|
|
|
|
PostDestroyer.new(post.user, post, permanent: true).destroy
|
|
|
|
expect(post.user_deleted).to be true
|
2021-03-25 09:34:53 +08:00
|
|
|
|
|
|
|
expect(post_revision.reload.persisted?).to be true
|
2020-11-10 12:40:48 +08:00
|
|
|
end
|
2021-02-02 05:57:31 +08:00
|
|
|
|
2023-01-27 22:15:33 +08:00
|
|
|
it "destroys the post when force_destroy is true for soft deleted topics" do
|
|
|
|
post = Fabricate(:post)
|
|
|
|
topic = post.topic
|
|
|
|
|
|
|
|
PostDestroyer.new(moderator, post).destroy
|
|
|
|
post = Post.with_deleted.find_by(id: post.id)
|
|
|
|
expect(post).not_to eq(nil)
|
|
|
|
|
|
|
|
PostDestroyer.new(moderator, post, force_destroy: true).destroy
|
|
|
|
post = Post.with_deleted.find_by(id: post.id)
|
|
|
|
expect(post).to eq(nil)
|
|
|
|
|
|
|
|
topic = Topic.with_deleted.find_by(id: topic.id)
|
|
|
|
expect(topic).to eq(nil)
|
|
|
|
end
|
|
|
|
|
|
|
|
it "destroys the post when force_destroy is true for regular posts" do
|
2021-02-02 05:57:31 +08:00
|
|
|
PostDestroyer.new(moderator, reply, force_destroy: true).destroy
|
|
|
|
expect { reply.reload }.to raise_error(ActiveRecord::RecordNotFound)
|
|
|
|
|
|
|
|
regular_post = Fabricate(:post)
|
2023-01-27 22:15:33 +08:00
|
|
|
topic = regular_post.topic
|
|
|
|
|
2021-02-02 05:57:31 +08:00
|
|
|
PostDestroyer.new(moderator, regular_post, force_destroy: true).destroy
|
|
|
|
expect { regular_post.reload }.to raise_error(ActiveRecord::RecordNotFound)
|
2023-01-27 22:15:33 +08:00
|
|
|
expect { topic.reload }.to raise_error(ActiveRecord::RecordNotFound)
|
2021-02-02 05:57:31 +08:00
|
|
|
end
|
2024-09-24 17:26:31 +08:00
|
|
|
|
|
|
|
it "destroys the post when force_destroy is true for posts by deleted users" do
|
|
|
|
regular_post = Fabricate(:post, post_number: 2)
|
|
|
|
UserDestroyer.new(admin).destroy(regular_post.user, delete_posts: true)
|
|
|
|
regular_post.reload
|
|
|
|
|
|
|
|
PostDestroyer.new(moderator, regular_post, force_destroy: true).destroy
|
|
|
|
expect { regular_post.reload }.to raise_error(ActiveRecord::RecordNotFound)
|
|
|
|
end
|
2020-11-10 12:40:48 +08:00
|
|
|
end
|
2022-06-28 05:21:05 +08:00
|
|
|
|
|
|
|
describe "publishes messages to subscribers" do
|
|
|
|
# timestamps are rounded because postgres truncates the timestamp. that would cause the comparison if we compared
|
|
|
|
# these timestamps with the one read from the database
|
|
|
|
fab!(:first_post) { Fabricate(:post, created_at: 10.days.ago.round) }
|
2023-11-10 06:47:59 +08:00
|
|
|
fab!(:walter_white)
|
2022-06-28 05:21:05 +08:00
|
|
|
let!(:topic) { first_post.topic }
|
|
|
|
let!(:reply) do
|
|
|
|
Fabricate(:post, topic: topic, created_at: 5.days.ago.round, user: coding_horror)
|
2023-01-09 19:18:21 +08:00
|
|
|
end
|
2022-06-28 05:21:05 +08:00
|
|
|
let!(:expendable_reply) do
|
|
|
|
Fabricate(:post, topic: topic, created_at: 2.days.ago.round, user: walter_white)
|
2023-01-09 19:18:21 +08:00
|
|
|
end
|
2022-06-28 05:21:05 +08:00
|
|
|
|
|
|
|
it "when a post is destroyed publishes updated topic stats" do
|
|
|
|
expect(topic.reload.posts_count).to eq(3)
|
|
|
|
|
|
|
|
messages =
|
|
|
|
MessageBus.track_publish("/topic/#{topic.id}") do
|
|
|
|
PostDestroyer.new(moderator, expendable_reply, force_destroy: true).destroy
|
|
|
|
end
|
|
|
|
|
|
|
|
expect { expendable_reply.reload }.to raise_error(ActiveRecord::RecordNotFound)
|
|
|
|
|
|
|
|
stats_message = messages.select { |msg| msg.data[:type] == :stats }.first
|
|
|
|
expect(stats_message).to be_present
|
|
|
|
expect(stats_message.data[:posts_count]).to eq(2)
|
|
|
|
expect(stats_message.data[:last_posted_at]).to eq(reply.created_at.as_json)
|
|
|
|
expect(stats_message.data[:last_poster]).to eq(
|
|
|
|
BasicUserSerializer.new(reply.user, root: false).as_json,
|
|
|
|
)
|
|
|
|
end
|
|
|
|
|
|
|
|
it "when a post is deleted publishes updated topic stats" do
|
|
|
|
expect(topic.reload.posts_count).to eq(3)
|
|
|
|
|
|
|
|
messages =
|
|
|
|
MessageBus.track_publish("/topic/#{topic.id}") do
|
|
|
|
PostDestroyer.new(moderator, expendable_reply).destroy
|
|
|
|
end
|
|
|
|
|
|
|
|
expect(expendable_reply.reload.deleted_at).not_to eq(nil)
|
|
|
|
|
|
|
|
stats_message = messages.select { |msg| msg.data[:type] == :stats }.first
|
|
|
|
expect(stats_message).to be_present
|
|
|
|
expect(stats_message.data[:posts_count]).to eq(2)
|
|
|
|
expect(stats_message.data[:last_posted_at]).to eq(reply.created_at.as_json)
|
|
|
|
expect(stats_message.data[:last_poster]).to eq(
|
|
|
|
BasicUserSerializer.new(reply.user, root: false).as_json,
|
|
|
|
)
|
|
|
|
end
|
|
|
|
|
|
|
|
it "when a post is recovered publishes update topic stats" do
|
|
|
|
expect(topic.reload.posts_count).to eq(3)
|
|
|
|
|
|
|
|
PostDestroyer.new(moderator, expendable_reply).destroy
|
|
|
|
expect(topic.reload.posts_count).to eq(2)
|
|
|
|
|
|
|
|
expendable_reply.reload
|
|
|
|
|
|
|
|
messages =
|
|
|
|
MessageBus.track_publish("/topic/#{topic.id}") do
|
|
|
|
PostDestroyer.new(admin, expendable_reply).recover
|
|
|
|
end
|
|
|
|
|
|
|
|
expect(topic.reload.posts_count).to eq(3)
|
|
|
|
|
|
|
|
stats_message = messages.select { |msg| msg.data[:type] == :stats }.first
|
|
|
|
expect(stats_message).to be_present
|
|
|
|
expect(stats_message.data[:posts_count]).to eq(3)
|
|
|
|
expect(stats_message.data[:last_posted_at]).to eq(expendable_reply.created_at.as_json)
|
|
|
|
expect(stats_message.data[:last_poster]).to eq(
|
|
|
|
BasicUserSerializer.new(expendable_reply.user, root: false).as_json,
|
|
|
|
)
|
|
|
|
end
|
|
|
|
end
|
2023-01-18 07:13:45 +08:00
|
|
|
|
|
|
|
describe "mailing_list_mode emails on recovery" do
|
2023-11-10 06:47:59 +08:00
|
|
|
fab!(:topic)
|
2023-01-18 07:13:45 +08:00
|
|
|
fab!(:post_1) { Fabricate(:post, topic: topic) }
|
|
|
|
fab!(:post_2) { Fabricate(:post, topic: topic) }
|
|
|
|
|
|
|
|
it "enqueues the notify_mailing_list_subscribers_job for the post" do
|
|
|
|
PostDestroyer.new(admin, post_2).destroy
|
|
|
|
post_2.reload
|
|
|
|
expect_enqueued_with(job: :notify_mailing_list_subscribers, args: { post_id: post_2.id }) do
|
|
|
|
PostDestroyer.new(admin, post_2).recover
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
it "enqueues the notify_mailing_list_subscribers_job for the op" do
|
|
|
|
PostDestroyer.new(admin, post_1).destroy
|
|
|
|
post_1.reload
|
|
|
|
expect_enqueued_with(job: :notify_mailing_list_subscribers, args: { post_id: post_1.id }) do
|
|
|
|
PostDestroyer.new(admin, post_1).recover
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2013-03-20 02:15:08 +08:00
|
|
|
end
|