FEATURE: Notify responders of post removal (#15049)
- Notify users whose posts were cascade deleted due to a flagged post
This commit is contained in:
parent
9105163882
commit
8c7cc426b7
|
@ -1498,6 +1498,7 @@ en:
|
|||
tl2_post_edit_time_limit: "A tl2+ author can edit their post for (n) minutes after posting. Set to 0 for forever."
|
||||
edit_history_visible_to_public: "Allow everyone to see previous versions of an edited post. When disabled, only staff members can view."
|
||||
delete_removed_posts_after: "Posts removed by the author will be automatically deleted after (n) hours. If set to 0, posts will be deleted immediately."
|
||||
notify_users_after_responses_deleted_on_flagged_post: "When a post is flagged and then removed, all users that responded to the post and had their responses removed will be notified."
|
||||
max_image_width: "Maximum thumbnail width of images in a post"
|
||||
max_image_height: "Maximum thumbnail height of images in a post"
|
||||
responsive_post_image_sizes: "Resize lightbox preview images to allow for high DPI screens of the following pixel ratios. Remove all values to disable responsive images."
|
||||
|
@ -2791,6 +2792,11 @@ en:
|
|||
inappropriate: "Your post was flagged as **inappropriate**: the community feels it is offensive, abusive, or a violation of [our community guidelines](%{base_path}/guidelines)."
|
||||
spam: "Your post was flagged as **spam**: the community feels it is an advertisement, something that is overly promotional in nature instead of being useful or relevant to the topic as expected."
|
||||
notify_moderators: "Your post was flagged **for moderator attention**: the community feels something about the post requires manual intervention by a staff member."
|
||||
responder:
|
||||
off_topic: "The post was flagged as **off-topic**: the community feels it is not a good fit for the topic, as currently defined by the title and the first post."
|
||||
inappropriate: "The post was flagged as **inappropriate**: the community feels it is offensive, abusive, or a violation of [our community guidelines](%{base_path}/guidelines)."
|
||||
spam: "The post was flagged as **spam**: the community feels it is an advertisement, something that is overly promotional in nature instead of being useful or relevant to the topic as expected."
|
||||
notify_moderators: "The post was flagged **for moderator attention**: the community feels something about the post requires manual intervention by a staff member."
|
||||
|
||||
flags_dispositions:
|
||||
agreed: "Thanks for letting us know. We agree there is an issue and we're looking into it."
|
||||
|
@ -2889,6 +2895,24 @@ en:
|
|||
|
||||
Please review our [community guidelines](%{base_url}/guidelines) for details.
|
||||
|
||||
flags_agreed_and_post_deleted_for_responders:
|
||||
title: "Reply removed from flagged post by staff"
|
||||
subject_template: "Reply removed from flagged post by staff"
|
||||
text_body_template: |
|
||||
Hello,
|
||||
|
||||
This is an automated message from %{site_name} to let you know that a [post](%{base_url}%{url}) you replied to was removed.
|
||||
|
||||
%{flag_reason}
|
||||
|
||||
This post was flagged by the community and a staff member opted to remove it.
|
||||
|
||||
``` markdown
|
||||
%{flagged_post_raw_content}
|
||||
```
|
||||
|
||||
For more details on the reason for removal, please review our [community guidelines](%{base_url}/guidelines).
|
||||
|
||||
usage_tips:
|
||||
text_body_template: |
|
||||
For a few quick tips on getting started as a new user, [check out this blog post](https://blog.discourse.org/2016/12/discourse-new-user-tips-and-tricks/).
|
||||
|
|
|
@ -828,6 +828,8 @@ posting:
|
|||
delete_removed_posts_after:
|
||||
client: true
|
||||
default: 24
|
||||
notify_users_after_responses_deleted_on_flagged_post:
|
||||
default: false
|
||||
traditional_markdown_linebreaks:
|
||||
client: true
|
||||
default: false
|
||||
|
|
|
@ -43,7 +43,10 @@ class PostDestroyer
|
|||
reply_ids = post.reply_ids(Guardian.new(performed_by), only_replies_to_single_post: false)
|
||||
replies = Post.where(id: reply_ids.map { |r| r[:id] })
|
||||
PostDestroyer.new(performed_by, post, reviewable: reviewable).destroy
|
||||
replies.each { |reply| PostDestroyer.new(performed_by, reply, defer_flags: defer_reply_flags).destroy }
|
||||
|
||||
options = { defer_flags: defer_reply_flags }
|
||||
options.merge!({ reviewable: reviewable, notify_responders: true, parent_post: post }) if SiteSetting.notify_users_after_responses_deleted_on_flagged_post
|
||||
replies.each { |reply| PostDestroyer.new(performed_by, reply, options).destroy }
|
||||
end
|
||||
|
||||
def initialize(user, post, opts = {})
|
||||
|
@ -179,7 +182,7 @@ class PostDestroyer
|
|||
|
||||
DB.after_commit do
|
||||
if @opts[:reviewable]
|
||||
notify_deletion(@opts[:reviewable])
|
||||
notify_deletion(@opts[:reviewable], { notify_responders: @opts[:notify_responders], parent_post: @opts[:parent_post] })
|
||||
elsif reviewable = @post.reviewable_flag
|
||||
@opts[:defer_flags] ? ignore(reviewable) : agree(reviewable)
|
||||
end
|
||||
|
@ -315,21 +318,23 @@ class PostDestroyer
|
|||
reviewable.transition_to(:ignored, @user)
|
||||
end
|
||||
|
||||
def notify_deletion(reviewable)
|
||||
def notify_deletion(reviewable, options = {})
|
||||
return if @post.user.blank?
|
||||
|
||||
allowed_user = @user.human? && @user.staff?
|
||||
return unless allowed_user && rs = reviewable.reviewable_scores.order('created_at DESC').first
|
||||
|
||||
notify_responders = options[:notify_responders]
|
||||
|
||||
Jobs.enqueue(
|
||||
:send_system_message,
|
||||
user_id: @post.user_id,
|
||||
message_type: :flags_agreed_and_post_deleted,
|
||||
message_type: notify_responders ? :flags_agreed_and_post_deleted_for_responders : :flags_agreed_and_post_deleted,
|
||||
message_options: {
|
||||
flagged_post_raw_content: @post.raw,
|
||||
url: @post.url,
|
||||
flagged_post_raw_content: notify_responders ? options[:parent_post].raw : @post.raw,
|
||||
url: notify_responders ? options[:parent_post].url : @post.url,
|
||||
flag_reason: I18n.t(
|
||||
"flag_reasons.#{PostActionType.types[rs.reviewable_score_type]}",
|
||||
"flag_reasons#{".responder" if notify_responders}.#{PostActionType.types[rs.reviewable_score_type]}",
|
||||
locale: SiteSetting.default_locale,
|
||||
base_path: Discourse.base_path
|
||||
)
|
||||
|
|
|
@ -57,6 +57,9 @@ Fabricator(:reviewable_flagged_post) do
|
|||
topic
|
||||
target_type 'Post'
|
||||
target { Fabricate(:post) }
|
||||
reviewable_scores { |p| [
|
||||
Fabricate.build(:reviewable_score, reviewable_id: p[:id]),
|
||||
]}
|
||||
end
|
||||
|
||||
Fabricator(:reviewable_user) do
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
Fabricator(:reviewable_score) do
|
||||
reviewable { Fabricate(:reviewable) }
|
||||
user { Fabricate(:user) }
|
||||
reviewable_score_type { 4 }
|
||||
status { 1 }
|
||||
score { 11.0 }
|
||||
reviewed_by { Fabricate(:user) }
|
||||
end
|
|
@ -283,16 +283,27 @@ RSpec.describe ReviewableFlaggedPost, type: :model do
|
|||
end
|
||||
|
||||
describe "#perform_delete_and_agree_replies" do
|
||||
it 'ignore flagged replies' do
|
||||
flagged_post = Fabricate(:reviewable_flagged_post)
|
||||
reply = create_reply(flagged_post.target)
|
||||
flagged_post.target.update(reply_count: 1)
|
||||
flagged_reply = Fabricate(:reviewable_flagged_post, target: reply)
|
||||
let(:flagged_post) { Fabricate(:reviewable_flagged_post) }
|
||||
let!(:reply) { create_reply(flagged_post.target) }
|
||||
|
||||
before do
|
||||
flagged_post.target.update(reply_count: 1)
|
||||
end
|
||||
|
||||
it 'ignore flagged replies' do
|
||||
flagged_reply = Fabricate(:reviewable_flagged_post, target: reply)
|
||||
flagged_post.perform(moderator, :delete_and_agree_replies)
|
||||
|
||||
expect(flagged_reply.reload.status).to eq(Reviewable.statuses[:ignored])
|
||||
end
|
||||
|
||||
it 'notifies users that responded to flagged post' do
|
||||
SiteSetting.notify_users_after_responses_deleted_on_flagged_post = true
|
||||
flagged_post.perform(moderator, :delete_and_agree_replies)
|
||||
|
||||
expect(Jobs::SendSystemMessage.jobs.size).to eq(2)
|
||||
expect(Jobs::SendSystemMessage.jobs.last["args"].first["message_type"]).to eq("flags_agreed_and_post_deleted_for_responders")
|
||||
end
|
||||
end
|
||||
|
||||
describe "#perform_disagree_and_restore" do
|
||||
|
|
|
@ -4,28 +4,20 @@ require 'rails_helper'
|
|||
|
||||
describe TopicViewPostsSerializer do
|
||||
|
||||
let(:user) { Fabricate(:user) }
|
||||
let(:post) { Fabricate(:post) }
|
||||
let(:topic) { post.topic }
|
||||
let!(:reviewable) { Fabricate(:reviewable_flagged_post,
|
||||
created_by: user,
|
||||
target: post,
|
||||
topic: topic,
|
||||
reviewable_scores: [
|
||||
Fabricate(:reviewable_score, reviewable_score_type: 0, status: ReviewableScore.statuses[:pending]),
|
||||
Fabricate(:reviewable_score, reviewable_score_type: 0, status: ReviewableScore.statuses[:ignored])
|
||||
]
|
||||
)}
|
||||
|
||||
it 'should return the right attributes' do
|
||||
|
||||
user = Fabricate(:user)
|
||||
post = Fabricate(:post)
|
||||
topic = post.topic
|
||||
|
||||
reviewable = Fabricate(:reviewable_flagged_post, created_by: user, target: post, topic: topic)
|
||||
|
||||
ReviewableScore.create!(
|
||||
reviewable_id: reviewable.id,
|
||||
user_id: user.id,
|
||||
reviewable_score_type: 0,
|
||||
status: ReviewableScore.statuses[:pending]
|
||||
)
|
||||
|
||||
ReviewableScore.create!(
|
||||
reviewable_id: reviewable.id,
|
||||
user_id: user.id,
|
||||
reviewable_score_type: 0,
|
||||
status: ReviewableScore.statuses[:ignored]
|
||||
)
|
||||
|
||||
topic_view = TopicView.new(topic, user, post_ids: [post.id])
|
||||
|
||||
serializer = TopicViewPostsSerializer.new(
|
||||
|
|
Loading…
Reference in New Issue