mirror of
https://github.com/discourse/discourse.git
synced 2025-01-22 13:43:17 +08:00
FEATURE: setting allowing tl0/anonymous flag illegal content (#30785)
The new site setting `allow_anonymous_and_tl0_to_flag_illegal` allows tl0 users to flag illegal content. In addition, anonymous users are instructed on how to flag illegal content by sending emails. Also `email_address_to_report_illegal_content` setting is added. If not provided, then the site contact email is used.
This commit is contained in:
parent
d3a7b99699
commit
029bd6feda
|
@ -42,6 +42,7 @@
|
|||
<input
|
||||
id="radio_{{this.flag.name_key}}"
|
||||
{{on "click" (fn this.changePostActionType this.flag)}}
|
||||
checked={{this.selected}}
|
||||
type="radio"
|
||||
name="post_action_type_index"
|
||||
/>
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
import Component from "@glimmer/component";
|
||||
import { service } from "@ember/service";
|
||||
import { htmlSafe } from "@ember/template";
|
||||
import { isEmpty } from "@ember/utils";
|
||||
import DModal from "discourse/components/d-modal";
|
||||
import { getAbsoluteURL } from "discourse/lib/get-url";
|
||||
import { i18n } from "discourse-i18n";
|
||||
|
||||
export default class AnonymousFlagModal extends Component {
|
||||
@service siteSettings;
|
||||
|
||||
get description() {
|
||||
return i18n("anonymous_flagging.description", {
|
||||
email: this.#email,
|
||||
topic_title: this.args.model.flagModel.topic.title,
|
||||
url: getAbsoluteURL(this.args.model.flagModel.url),
|
||||
});
|
||||
}
|
||||
|
||||
get #email() {
|
||||
if (isEmpty(this.siteSettings.email_address_to_report_illegal_content)) {
|
||||
return this.siteSettings.contact_email;
|
||||
}
|
||||
return this.siteSettings.email_address_to_report_illegal_content;
|
||||
}
|
||||
|
||||
<template>
|
||||
<DModal
|
||||
@title={{i18n "anonymous_flagging.title"}}
|
||||
@closeModal={{@closeModal}}
|
||||
@bodyClass="anonymous-flag-modal__body"
|
||||
class="anonymous-flag-modal"
|
||||
>
|
||||
<:body>
|
||||
{{htmlSafe this.description}}
|
||||
</:body>
|
||||
</DModal>
|
||||
</template>
|
||||
}
|
|
@ -29,6 +29,10 @@ export default class Flag extends Component {
|
|||
this.adminTools
|
||||
?.checkSpammer(this.args.model.flagModel.user_id)
|
||||
.then((result) => (this.spammerDetails = result));
|
||||
|
||||
if (this.flagsAvailable.length === 1) {
|
||||
this.selected = this.flagsAvailable[0];
|
||||
}
|
||||
}
|
||||
|
||||
get flagActions() {
|
||||
|
|
|
@ -6,9 +6,21 @@ import concatClass from "discourse/helpers/concat-class";
|
|||
import DiscourseURL from "discourse/lib/url";
|
||||
|
||||
export default class PostMenuFlagButton extends Component {
|
||||
static shouldRender(args) {
|
||||
static shouldRender(args, helper) {
|
||||
const { reviewable_id, canFlag, hidden } = args.post;
|
||||
return reviewable_id || (canFlag && !hidden);
|
||||
return (
|
||||
reviewable_id ||
|
||||
(canFlag && !hidden) ||
|
||||
(helper.siteSettings
|
||||
.allow_tl0_and_anonymous_users_to_flag_illegal_content &&
|
||||
!helper.currentUser)
|
||||
);
|
||||
}
|
||||
|
||||
get title() {
|
||||
return this.args.post.currentUser
|
||||
? "post.controls.flag"
|
||||
: "post.controls.anonymous_flag";
|
||||
}
|
||||
|
||||
@action
|
||||
|
@ -36,7 +48,7 @@ export default class PostMenuFlagButton extends Component {
|
|||
@action={{@buttonActions.showFlags}}
|
||||
@icon="flag"
|
||||
@label={{if @showLabel "post.controls.flag_action"}}
|
||||
@title="post.controls.flag"
|
||||
@title={{this.title}}
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
@ -3,6 +3,7 @@ import { cancel, schedule } from "@ember/runloop";
|
|||
import { service } from "@ember/service";
|
||||
import { isEmpty } from "@ember/utils";
|
||||
import AddPmParticipants from "discourse/components/modal/add-pm-participants";
|
||||
import AnonymousFlagModal from "discourse/components/modal/anonymous-flag";
|
||||
import ChangeOwnerModal from "discourse/components/modal/change-owner";
|
||||
import ChangeTimestampModal from "discourse/components/modal/change-timestamp";
|
||||
import EditSlowModeModal from "discourse/components/modal/edit-slow-mode";
|
||||
|
@ -27,6 +28,7 @@ const SCROLL_DELAY = 500;
|
|||
export default class TopicRoute extends DiscourseRoute {
|
||||
@service composer;
|
||||
@service screenTrack;
|
||||
@service currentUser;
|
||||
@service modal;
|
||||
@service router;
|
||||
|
||||
|
@ -104,7 +106,7 @@ export default class TopicRoute extends DiscourseRoute {
|
|||
|
||||
@action
|
||||
showFlags(model) {
|
||||
this.modal.show(FlagModal, {
|
||||
this.modal.show(this.currentUser ? FlagModal : AnonymousFlagModal, {
|
||||
model: {
|
||||
flagTarget: new PostFlag(),
|
||||
flagModel: model,
|
||||
|
|
|
@ -211,20 +211,30 @@ registerButton("flag-count", (attrs) => {
|
|||
};
|
||||
});
|
||||
|
||||
registerButton("flag", (attrs) => {
|
||||
if (attrs.reviewableId || (attrs.canFlag && !attrs.hidden)) {
|
||||
let button = {
|
||||
action: "showFlags",
|
||||
title: "post.controls.flag",
|
||||
icon: "flag",
|
||||
className: "create-flag",
|
||||
};
|
||||
if (attrs.reviewableId) {
|
||||
button.before = "flag-count";
|
||||
registerButton(
|
||||
"flag",
|
||||
(attrs, _state, siteSettings, _postMenuSettings, currentUser) => {
|
||||
if (
|
||||
attrs.reviewableId ||
|
||||
(attrs.canFlag && !attrs.hidden) ||
|
||||
(siteSettings.allow_tl0_and_anonymous_users_to_flag_illegal_content &&
|
||||
!currentUser)
|
||||
) {
|
||||
const button = {
|
||||
action: "showFlags",
|
||||
title: currentUser
|
||||
? "post.controls.flag"
|
||||
: "post.controls.anonymous_flag",
|
||||
icon: "flag",
|
||||
className: "create-flag",
|
||||
};
|
||||
if (attrs.reviewableId) {
|
||||
button.before = "flag-count";
|
||||
}
|
||||
return button;
|
||||
}
|
||||
return button;
|
||||
}
|
||||
});
|
||||
);
|
||||
|
||||
registerButton("edit", (attrs) => {
|
||||
if (attrs.canEdit) {
|
||||
|
|
|
@ -3894,6 +3894,7 @@ en:
|
|||
edit_anonymous: "Sorry, but you need to be logged in to edit this post."
|
||||
flag_action: "Flag"
|
||||
flag: "privately flag this post for attention or send a personal message about it"
|
||||
anonymous_flag: "send an email to staff to flag this post"
|
||||
delete_action: "Delete post"
|
||||
delete: "delete this post"
|
||||
undelete_action: "Undelete post"
|
||||
|
@ -4211,6 +4212,10 @@ en:
|
|||
none: "no subcategories"
|
||||
colors_disabled: "You can’t select colors because you have a category style of none."
|
||||
|
||||
anonymous_flagging:
|
||||
title: "Report illegal content"
|
||||
description: "To report illegal content, please contact <a href='mailto:%{email}?subject=Illegal content: %{topic_title}&body=This post %{url} contains illegal content.'>%{email}</a>"
|
||||
|
||||
flagging:
|
||||
title: "Thanks for keeping our community civil!"
|
||||
action: "Flag Post"
|
||||
|
|
|
@ -364,6 +364,8 @@ en:
|
|||
slow_down_crawler_user_agent_cannot_be_popular_browsers: "You cannot add any of the following values to the setting: %{values}."
|
||||
strip_image_metadata_cannot_be_disabled_if_composer_media_optimization_image_enabled: "You cannot disable strip image metadata if 'composer media optimization image enabled' is enabled. Disable 'composer media optimization image enabled' before disabling strip image metadata."
|
||||
twitter_summary_large_image_no_svg: "Twitter summary images used for twitter:image metadata cannot be an .svg image."
|
||||
tl0_and_anonymous_flag: "Either 'site contact email' or 'email address to report illegal content' must be provided for anonymous users."
|
||||
|
||||
conflicting_google_user_id: 'The Google Account ID for this account has changed; staff intervention is required for security reasons. Please contact staff and point them to <br><a href="https://meta.discourse.org/t/76575">https://meta.discourse.org/t/76575</a>'
|
||||
onebox:
|
||||
invalid_address: "Sorry, we were unable to generate a preview for this web page, because the server '%{hostname}' could not be found. Instead of a preview, only a link will appear in your post. :cry:"
|
||||
|
@ -2307,6 +2309,8 @@ en:
|
|||
reviewable_default_visibility: "Don't show reviewable items unless they meet this priority"
|
||||
reviewable_low_priority_threshold: "The priority filter hides reviewable items that don't meet this score unless the '(any)' filter is used."
|
||||
high_trust_flaggers_auto_hide_posts: "New user posts are automatically hidden after being flagged as spam by a TL3+ user"
|
||||
allow_tl0_and_anonymous_users_to_flag_illegal_content: "Anonymous users will see information that they have to e-mail administrators to report illegal content."
|
||||
email_address_to_report_illegal_content: "If left blank the default site admin email will be used."
|
||||
cooldown_hours_until_reflag: "How much time users will have to wait until they are able to reflag a post"
|
||||
slow_mode_prevents_editing: "Does 'Slow Mode' prevent editing, after editing_grace_period?"
|
||||
|
||||
|
|
|
@ -54,6 +54,7 @@ required:
|
|||
default: ""
|
||||
type: email
|
||||
area: "about|notifications|legal"
|
||||
client: true
|
||||
contact_url:
|
||||
default: ""
|
||||
area: "about|legal"
|
||||
|
@ -1938,6 +1939,14 @@ trust:
|
|||
allow_any: false
|
||||
refresh: true
|
||||
area: "group_permissions"
|
||||
allow_tl0_and_anonymous_users_to_flag_illegal_content:
|
||||
default: false
|
||||
area: "flags"
|
||||
client: true
|
||||
email_address_to_report_illegal_content:
|
||||
default: ""
|
||||
area: "flags"
|
||||
client: true
|
||||
min_trust_to_post_links:
|
||||
default: 0
|
||||
enum: "TrustLevelSetting"
|
||||
|
|
|
@ -94,6 +94,10 @@ module PostGuardian
|
|||
post.topic.private_message?
|
||||
)
|
||||
) ||
|
||||
(
|
||||
action_key == :illegal &&
|
||||
SiteSetting.allow_tl0_and_anonymous_users_to_flag_illegal_content
|
||||
) ||
|
||||
# not a flagging action, and haven't done it already
|
||||
not(is_flag || already_taken_this_action) &&
|
||||
# nothing except flagging on archived topics
|
||||
|
|
|
@ -267,6 +267,16 @@ module SiteSettings::Validations
|
|||
validate_error :twitter_summary_large_image_no_svg
|
||||
end
|
||||
|
||||
def validate_allow_tl0_and_anonymous_users_to_flag_illegal_content(new_val)
|
||||
return if new_val == "f"
|
||||
if SiteSetting.contact_email.present? ||
|
||||
SiteSetting.email_address_to_report_illegal_content.present?
|
||||
return
|
||||
end
|
||||
|
||||
validate_error :tl0_and_anonymous_flag
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def validate_bucket_setting(setting_name, upload_bucket, backup_bucket)
|
||||
|
|
|
@ -163,6 +163,16 @@ RSpec.describe Guardian do
|
|||
Flag.reset_flag_settings!
|
||||
end
|
||||
|
||||
it "return true for illegal if tl0 and allow_tl0_and_anonymous_users_to_flag_illegal_content" do
|
||||
SiteSetting.flag_post_allowed_groups = ""
|
||||
user.trust_level = TrustLevel[0]
|
||||
expect(Guardian.new(user).post_can_act?(post, :illegal)).to be false
|
||||
|
||||
SiteSetting.email_address_to_report_illegal_content = "illegal@example.com"
|
||||
SiteSetting.allow_tl0_and_anonymous_users_to_flag_illegal_content = true
|
||||
expect(Guardian.new(user).post_can_act?(post, :illegal)).to be true
|
||||
end
|
||||
|
||||
it "works as expected for silenced users" do
|
||||
UserSilencer.silence(user, admin)
|
||||
|
||||
|
|
|
@ -474,4 +474,19 @@ RSpec.describe SiteSettings::Validations do
|
|||
expect { validations.validate_twitter_summary_large_image(nil) }.not_to raise_error
|
||||
end
|
||||
end
|
||||
|
||||
describe "#validate_allow_tl0_and_anonymous_users_to_flag_illegal_content" do
|
||||
it "does not allow to enable when no contact email is provided" do
|
||||
expect {
|
||||
validations.validate_allow_tl0_and_anonymous_users_to_flag_illegal_content("t")
|
||||
}.to raise_error(
|
||||
Discourse::InvalidParameters,
|
||||
I18n.t("errors.site_settings.tl0_and_anonymous_flag"),
|
||||
)
|
||||
SiteSetting.contact_email = "illegal@example.com"
|
||||
expect {
|
||||
validations.validate_allow_tl0_and_anonymous_users_to_flag_illegal_content("t")
|
||||
}.not_to raise_error
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -71,6 +71,8 @@ RSpec.describe Admin::SiteSettingsController do
|
|||
expect(response.status).to eq(200)
|
||||
expect(response.parsed_body["site_settings"].map { |s| s["setting"] }).to match_array(
|
||||
%w[
|
||||
allow_tl0_and_anonymous_users_to_flag_illegal_content
|
||||
email_address_to_report_illegal_content
|
||||
silence_new_user_sensitivity
|
||||
num_users_to_silence_new_user
|
||||
flag_sockpuppets
|
||||
|
|
|
@ -164,6 +164,8 @@ describe "Admin Flags Page", type: :system do
|
|||
admin_flags_page.click_tab("settings")
|
||||
expect(page.all(".setting-label h3").map(&:text).map(&:downcase)).to eq(
|
||||
[
|
||||
"allow tl0 and anonymous users to flag illegal content",
|
||||
"email address to report illegal content",
|
||||
"silence new user sensitivity",
|
||||
"num users to silence new user",
|
||||
"flag sockpuppets",
|
||||
|
|
|
@ -2,21 +2,23 @@
|
|||
|
||||
describe "Flagging post", type: :system do
|
||||
fab!(:current_user) { Fabricate(:admin) }
|
||||
fab!(:first_post) { Fabricate(:post) }
|
||||
fab!(:post_to_flag) { Fabricate(:post, topic: first_post.topic) }
|
||||
fab!(:category)
|
||||
fab!(:topic) { Fabricate(:topic, category: category) }
|
||||
fab!(:first_post) { Fabricate(:post, topic: topic) }
|
||||
fab!(:post_to_flag) { Fabricate(:post, topic: topic) }
|
||||
|
||||
let(:topic_page) { PageObjects::Pages::Topic.new }
|
||||
let(:flag_modal) { PageObjects::Modals::Flag.new }
|
||||
|
||||
before { sign_in(current_user) }
|
||||
|
||||
describe "Using Take Action" do
|
||||
before { sign_in(current_user) }
|
||||
|
||||
it "can select the default action to hide the post, agree with other flags, and reach the flag threshold" do
|
||||
other_flag = Fabricate(:flag_post_action, post: post_to_flag, user: Fabricate(:moderator))
|
||||
other_flag_reviewable =
|
||||
Fabricate(:reviewable_flagged_post, target: post_to_flag, created_by: other_flag.user)
|
||||
expect(other_flag.reload.agreed_at).to be_nil
|
||||
topic_page.visit_topic(post_to_flag.topic)
|
||||
topic_page.visit_topic(topic)
|
||||
topic_page.expand_post_actions(post_to_flag)
|
||||
topic_page.click_post_action_button(post_to_flag, :flag)
|
||||
flag_modal.choose_type(:off_topic)
|
||||
|
@ -34,8 +36,10 @@ describe "Flagging post", type: :system do
|
|||
end
|
||||
|
||||
describe "As Illegal" do
|
||||
before { sign_in(current_user) }
|
||||
|
||||
it do
|
||||
topic_page.visit_topic(post_to_flag.topic)
|
||||
topic_page.visit_topic(topic)
|
||||
topic_page.expand_post_actions(post_to_flag)
|
||||
topic_page.click_post_action_button(post_to_flag, :flag)
|
||||
flag_modal.choose_type(:illegal)
|
||||
|
@ -50,4 +54,63 @@ describe "Flagging post", type: :system do
|
|||
expect(page).to have_content(I18n.t("js.post.actions.by_you.illegal"))
|
||||
end
|
||||
end
|
||||
|
||||
context "when tl0" do
|
||||
fab!(:tl0_user) { Fabricate(:user, trust_level: TrustLevel[0]) }
|
||||
before { sign_in(tl0_user) }
|
||||
|
||||
it "does not allow to mark posts as illegal" do
|
||||
topic_page.visit_topic(topic)
|
||||
topic_page.expand_post_actions(post_to_flag)
|
||||
expect(topic_page).to have_no_flag_button
|
||||
end
|
||||
|
||||
it "allows to mark posts as illegal when allow_tl0_and_anonymous_users_to_flag_illegal_content setting is enabled" do
|
||||
SiteSetting.email_address_to_report_illegal_content = "illegal@example.com"
|
||||
SiteSetting.allow_tl0_and_anonymous_users_to_flag_illegal_content = true
|
||||
topic_page.visit_topic(topic).open_flag_topic_modal
|
||||
expect(flag_modal).to have_choices(I18n.t("js.flagging.formatted_name.illegal"))
|
||||
end
|
||||
end
|
||||
|
||||
context "when anonymous" do
|
||||
let(:anonymous_flag_modal) { PageObjects::Modals::AnonymousFlag.new }
|
||||
|
||||
it "does not allow to mark posts as illegal" do
|
||||
topic_page.visit_topic(topic)
|
||||
expect(topic_page).to have_no_post_more_actions(post_to_flag)
|
||||
end
|
||||
|
||||
it "allows to mark posts as illegal when allow_tl0_and_anonymous_users_to_flag_illegal_content setting is enabled" do
|
||||
SiteSetting.contact_email = "contact@example.com"
|
||||
SiteSetting.allow_tl0_and_anonymous_users_to_flag_illegal_content = true
|
||||
|
||||
topic_page.visit_topic(topic, post_number: post_to_flag.post_number)
|
||||
topic_page.expand_post_actions(post_to_flag)
|
||||
topic_page.find_post_action_button(post_to_flag, :flag).click
|
||||
|
||||
expect(anonymous_flag_modal.body).to have_content(
|
||||
ActionView::Base.full_sanitizer.sanitize(
|
||||
I18n.t(
|
||||
"js.anonymous_flagging.description",
|
||||
{ email: "contact@example.com", topic_title: topic.title, url: current_url },
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
SiteSetting.email_address_to_report_illegal_content = "illegal@example.com"
|
||||
topic_page.visit_topic(topic)
|
||||
topic_page.expand_post_actions(post_to_flag)
|
||||
topic_page.find_post_action_button(post_to_flag, :flag).click
|
||||
|
||||
expect(anonymous_flag_modal.body).to have_content(
|
||||
ActionView::Base.full_sanitizer.sanitize(
|
||||
I18n.t(
|
||||
"js.anonymous_flagging.description",
|
||||
{ email: "illegal@example.com", topic_title: topic.title, url: current_url },
|
||||
),
|
||||
),
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
9
spec/system/page_objects/modals/anonoymous_flag.rb
Normal file
9
spec/system/page_objects/modals/anonoymous_flag.rb
Normal file
|
@ -0,0 +1,9 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module PageObjects
|
||||
module Modals
|
||||
class AnonymousFlag < PageObjects::Modals::Base
|
||||
BODY_SELECTOR = ".anonymous-flag-modal__body"
|
||||
end
|
||||
end
|
||||
end
|
|
@ -78,6 +78,10 @@ module PageObjects
|
|||
".topic-post:not(.staged) #post_#{post_number}"
|
||||
end
|
||||
|
||||
def has_no_post_more_actions?(post)
|
||||
within_post(post) { has_no_css?(".show-more-actions") }
|
||||
end
|
||||
|
||||
def has_post_more_actions?(post)
|
||||
within_post(post) { has_css?(".show-more-actions") }
|
||||
end
|
||||
|
@ -300,6 +304,10 @@ module PageObjects
|
|||
find(".modal.convert-to-public-topic")
|
||||
end
|
||||
|
||||
def has_no_flag_button?
|
||||
has_no_css?(".post-action-menu__flag.create-flag")
|
||||
end
|
||||
|
||||
def open_flag_topic_modal
|
||||
expect(page).to have_css(".flag-topic", wait: Capybara.default_max_wait_time * 3)
|
||||
find(".flag-topic").click
|
||||
|
|
Loading…
Reference in New Issue
Block a user