FEATURE: Admins can flag posts so they can review them later. (#12311)
Staff can send a post to the review queue by clicking the "Flag Post" button next to "Take Action...". Clicking it flags the post using the "Notify moderators" score type and hides it. A custom message will be sent to the user.
This commit is contained in:
parent
0902e56162
commit
8fcad73b36
|
@ -12,7 +12,10 @@ export default Component.extend({
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.element.querySelector("#radio_" + nameKey).checked = "true";
|
const selector = this.element.querySelector("#radio_" + nameKey);
|
||||||
|
if (selector) {
|
||||||
|
selector.checked = "true";
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@observes("nameKey")
|
@observes("nameKey")
|
||||||
|
|
|
@ -266,6 +266,17 @@ export default Controller.extend(ModalFunctionality, {
|
||||||
this.set("model.hidden", true);
|
this.set("model.hidden", true);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
flagForReview() {
|
||||||
|
const notifyModeratorsID = 7;
|
||||||
|
const notifyModerators = this.flagsAvailable.find(
|
||||||
|
(f) => f.id === notifyModeratorsID
|
||||||
|
);
|
||||||
|
this.set("selected", notifyModerators);
|
||||||
|
|
||||||
|
this.send("createFlag", { queue_for_review: true });
|
||||||
|
this.set("model.hidden", true);
|
||||||
|
},
|
||||||
|
|
||||||
changePostActionType(action) {
|
changePostActionType(action) {
|
||||||
this.set("selected", action);
|
this.set("selected", action);
|
||||||
},
|
},
|
||||||
|
|
|
@ -53,6 +53,7 @@ export default RestModel.extend({
|
||||||
message: opts.message,
|
message: opts.message,
|
||||||
is_warning: opts.isWarning,
|
is_warning: opts.isWarning,
|
||||||
take_action: opts.takeAction,
|
take_action: opts.takeAction,
|
||||||
|
queue_for_review: opts.queue_for_review,
|
||||||
flag_topic: this.flagTopic ? true : false,
|
flag_topic: this.flagTopic ? true : false,
|
||||||
},
|
},
|
||||||
returnXHR: true,
|
returnXHR: true,
|
||||||
|
|
|
@ -40,6 +40,13 @@
|
||||||
performAction=(action "takeAction")
|
performAction=(action "takeAction")
|
||||||
reviewableUpdating=submitDisabled
|
reviewableUpdating=submitDisabled
|
||||||
}}
|
}}
|
||||||
|
|
||||||
|
{{d-button
|
||||||
|
class="btn-danger"
|
||||||
|
action=(action "flagForReview")
|
||||||
|
icon="exclamation-triangle"
|
||||||
|
label="flagging.flag_for_review"
|
||||||
|
}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
{{#if showDeleteSpammer}}
|
{{#if showDeleteSpammer}}
|
||||||
|
|
|
@ -16,7 +16,8 @@ class PostActionsController < ApplicationController
|
||||||
is_warning: params[:is_warning],
|
is_warning: params[:is_warning],
|
||||||
message: params[:message],
|
message: params[:message],
|
||||||
take_action: params[:take_action] == 'true',
|
take_action: params[:take_action] == 'true',
|
||||||
flag_topic: params[:flag_topic] == 'true'
|
flag_topic: params[:flag_topic] == 'true',
|
||||||
|
queue_for_review: params[:queue_for_review] == 'true'
|
||||||
)
|
)
|
||||||
result = creator.perform
|
result = creator.perform
|
||||||
|
|
||||||
|
|
|
@ -522,7 +522,7 @@ class Post < ActiveRecord::Base
|
||||||
(topic.present? && (topic.private_message? || topic.category&.read_restricted))
|
(topic.present? && (topic.private_message? || topic.category&.read_restricted))
|
||||||
end
|
end
|
||||||
|
|
||||||
def hide!(post_action_type_id, reason = nil)
|
def hide!(post_action_type_id, reason = nil, custom_message: nil)
|
||||||
return if hidden?
|
return if hidden?
|
||||||
|
|
||||||
reason ||= hidden_at ?
|
reason ||= hidden_at ?
|
||||||
|
@ -554,11 +554,16 @@ class Post < ActiveRecord::Base
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message = custom_message
|
||||||
|
if message.nil?
|
||||||
|
message = hiding_again ? :post_hidden_again : :post_hidden
|
||||||
|
end
|
||||||
|
|
||||||
Jobs.enqueue_in(
|
Jobs.enqueue_in(
|
||||||
5.seconds,
|
5.seconds,
|
||||||
:send_system_message,
|
:send_system_message,
|
||||||
user_id: user.id,
|
user_id: user.id,
|
||||||
message_type: hiding_again ? :post_hidden_again : :post_hidden,
|
message_type: message,
|
||||||
message_options: options
|
message_options: options
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
|
@ -3246,6 +3246,7 @@ en:
|
||||||
notify_action: "Message"
|
notify_action: "Message"
|
||||||
official_warning: "Official Warning"
|
official_warning: "Official Warning"
|
||||||
delete_spammer: "Delete Spammer"
|
delete_spammer: "Delete Spammer"
|
||||||
|
flag_for_review: "Flag Post"
|
||||||
|
|
||||||
# keys ending with _MF use message format, see https://meta.discourse.org/t/message-format-support-for-localization/7035 for details
|
# keys ending with _MF use message format, see https://meta.discourse.org/t/message-format-support-for-localization/7035 for details
|
||||||
delete_confirm_MF: "You are about to delete {POSTS, plural, one {<b>#</b> post} other {<b>#</b> posts}} and {TOPICS, plural, one {<b>#</b> topic} other {<b>#</b> topics}} from this user, remove their account, block signups from their IP address <b>{ip_address}</b>, and add their email address <b>{email}</b> to a permanent block list. Are you sure this user is really a spammer?"
|
delete_confirm_MF: "You are about to delete {POSTS, plural, one {<b>#</b> post} other {<b>#</b> posts}} and {TOPICS, plural, one {<b>#</b> topic} other {<b>#</b> topics}} from this user, remove their account, block signups from their IP address <b>{ip_address}</b>, and add their email address <b>{email}</b> to a permanent block list. Are you sure this user is really a spammer?"
|
||||||
|
|
|
@ -2820,6 +2820,20 @@ en:
|
||||||
The community flagged this post and now it is hidden. **Because this post has been hidden more than once, your post will now remain hidden until it is handled by a staff member.**
|
The community flagged this post and now it is hidden. **Because this post has been hidden more than once, your post will now remain hidden until it is handled by a staff member.**
|
||||||
|
|
||||||
For additional guidance, please refer to our [community guidelines](%{base_url}/guidelines).
|
For additional guidance, please refer to our [community guidelines](%{base_url}/guidelines).
|
||||||
|
|
||||||
|
queued_by_staff:
|
||||||
|
title: "Post Needs Approval"
|
||||||
|
subject_template: "Post hidden by staff, awaiting approval"
|
||||||
|
text_body_template: |
|
||||||
|
Hello,
|
||||||
|
|
||||||
|
This is an automated message from %{site_name} to let you know that your post was hidden.
|
||||||
|
|
||||||
|
<%{base_url}%{url}>
|
||||||
|
|
||||||
|
Your post will remain hidden until a staff member reviews it.
|
||||||
|
|
||||||
|
For additional guidance, please refer to our [community guidelines](%{base_url}/guidelines).
|
||||||
|
|
||||||
flags_disagreed:
|
flags_disagreed:
|
||||||
title: "Flagged post restored by staff"
|
title: "Flagged post restored by staff"
|
||||||
|
@ -4907,6 +4921,7 @@ en:
|
||||||
email_spam: "This email was flagged as spam by the header defined in `email_in_spam_header`."
|
email_spam: "This email was flagged as spam by the header defined in `email_in_spam_header`."
|
||||||
suspect_user: "This new user entered profile information without reading any topics or posts, which strongly suggests they may be a spammer. See `approve_suspect_users`."
|
suspect_user: "This new user entered profile information without reading any topics or posts, which strongly suggests they may be a spammer. See `approve_suspect_users`."
|
||||||
contains_media: "This post includes embedded media. See `review_media_unless_trust_level`."
|
contains_media: "This post includes embedded media. See `review_media_unless_trust_level`."
|
||||||
|
queued_by_staff: "A staff member thinks this post needs review. It'll remain hidden until then."
|
||||||
|
|
||||||
actions:
|
actions:
|
||||||
agree:
|
agree:
|
||||||
|
|
|
@ -39,6 +39,7 @@ class PostActionCreator
|
||||||
take_action: false,
|
take_action: false,
|
||||||
flag_topic: false,
|
flag_topic: false,
|
||||||
created_at: nil,
|
created_at: nil,
|
||||||
|
queue_for_review: false,
|
||||||
reason: nil
|
reason: nil
|
||||||
)
|
)
|
||||||
@created_by = created_by
|
@created_by = created_by
|
||||||
|
@ -54,7 +55,13 @@ class PostActionCreator
|
||||||
@message = message
|
@message = message
|
||||||
@flag_topic = flag_topic
|
@flag_topic = flag_topic
|
||||||
@meta_post = nil
|
@meta_post = nil
|
||||||
|
|
||||||
@reason = reason
|
@reason = reason
|
||||||
|
@queue_for_review = queue_for_review
|
||||||
|
|
||||||
|
if reason.nil? && @queue_for_review
|
||||||
|
@reason = 'queued_by_staff'
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def post_can_act?
|
def post_can_act?
|
||||||
|
@ -71,7 +78,7 @@ class PostActionCreator
|
||||||
def perform
|
def perform
|
||||||
result = CreateResult.new
|
result = CreateResult.new
|
||||||
|
|
||||||
unless post_can_act?
|
if !post_can_act? || (@queue_for_review && !guardian.is_staff?)
|
||||||
result.forbidden = true
|
result.forbidden = true
|
||||||
result.add_error(I18n.t("invalid_access"))
|
result.add_error(I18n.t("invalid_access"))
|
||||||
return result
|
return result
|
||||||
|
@ -186,7 +193,20 @@ private
|
||||||
def auto_hide_if_needed
|
def auto_hide_if_needed
|
||||||
return if @post.hidden?
|
return if @post.hidden?
|
||||||
return if !@created_by.staff? && @post.user&.staff?
|
return if !@created_by.staff? && @post.user&.staff?
|
||||||
return unless PostActionType.auto_action_flag_types.include?(@post_action_name)
|
|
||||||
|
not_auto_action_flag_type = !PostActionType.auto_action_flag_types.include?(@post_action_name)
|
||||||
|
return if not_auto_action_flag_type && !@queue_for_review
|
||||||
|
|
||||||
|
if @queue_for_review
|
||||||
|
@post.topic.update_status('visible', false, @created_by) if @post.is_first_post?
|
||||||
|
|
||||||
|
@post.hide!(
|
||||||
|
@post_action_type_id,
|
||||||
|
Post.hidden_reasons[:flag_threshold_reached],
|
||||||
|
custom_message: :queued_by_staff
|
||||||
|
)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
if trusted_spam_flagger?
|
if trusted_spam_flagger?
|
||||||
@post.hide!(@post_action_type_id, Post.hidden_reasons[:flagged_by_tl3_user])
|
@post.hide!(@post_action_type_id, Post.hidden_reasons[:flagged_by_tl3_user])
|
||||||
|
@ -312,6 +332,7 @@ private
|
||||||
targets_topic: @targets_topic
|
targets_topic: @targets_topic
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
result.reviewable_score = result.reviewable.add_score(
|
result.reviewable_score = result.reviewable.add_score(
|
||||||
@created_by,
|
@created_by,
|
||||||
@post_action_type_id,
|
@post_action_type_id,
|
||||||
|
|
|
@ -219,4 +219,43 @@ describe PostActionCreator do
|
||||||
expect(reviewable.reload).to be_approved
|
expect(reviewable.reload).to be_approved
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context "queue_for_review" do
|
||||||
|
fab!(:admin) { Fabricate(:admin) }
|
||||||
|
|
||||||
|
it 'fails if the user is not a staff member' do
|
||||||
|
creator = PostActionCreator.new(
|
||||||
|
user, post,
|
||||||
|
PostActionType.types[:notify_moderators], queue_for_review: true
|
||||||
|
)
|
||||||
|
result = creator.perform
|
||||||
|
|
||||||
|
expect(result.success?).to eq(false)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'creates a new reviewable and hides the post' do
|
||||||
|
result = build_creator.perform
|
||||||
|
|
||||||
|
expect(result.success?).to eq(true)
|
||||||
|
|
||||||
|
score = result.reviewable.reviewable_scores.last
|
||||||
|
expect(score.reason).to eq('queued_by_staff')
|
||||||
|
expect(post.reload.hidden?).to eq(true)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'hides the topic even if it has replies' do
|
||||||
|
Fabricate(:post, topic: post.topic)
|
||||||
|
|
||||||
|
result = build_creator.perform
|
||||||
|
|
||||||
|
expect(post.topic.reload.visible?).to eq(false)
|
||||||
|
end
|
||||||
|
|
||||||
|
def build_creator
|
||||||
|
PostActionCreator.new(
|
||||||
|
admin, post,
|
||||||
|
PostActionType.types[:notify_moderators], queue_for_review: true
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue