FEATURE: Add `IgnoredUsersSummary` daily job (#7144)
* FEATURE: Add `IgnoredUsersSummary` daily job ## Why? This is part of the [Ability to ignore a user feature](https://meta.discourse.org/t/ability-to-ignore-a-user/110254/8). We want to: 1. Send an automatic group PM that goes out to moderators 2. When {x} users have Ignored the same user, threshold defined by a site setting, default of 5 3. Only send this message every X days which is defined by another site setting
This commit is contained in:
parent
fb8bcd7469
commit
bd6d31c9ec
|
@ -0,0 +1,42 @@
|
||||||
|
module Jobs
|
||||||
|
class IgnoredUsersSummary < Jobs::Scheduled
|
||||||
|
every 1.day
|
||||||
|
|
||||||
|
def execute(args)
|
||||||
|
return unless SiteSetting.ignore_user_enabled
|
||||||
|
|
||||||
|
params = {
|
||||||
|
threshold: SiteSetting.ignored_users_count_message_threshold,
|
||||||
|
gap_days: SiteSetting.ignored_users_message_gap_days,
|
||||||
|
coalesced_gap_days: SiteSetting.ignored_users_message_gap_days + 1,
|
||||||
|
}
|
||||||
|
user_ids = DB.query_single(<<~SQL, params)
|
||||||
|
SELECT ignored_user_id
|
||||||
|
FROM ignored_users
|
||||||
|
WHERE COALESCE(summarized_at, CURRENT_TIMESTAMP + ':coalesced_gap_days DAYS'::INTERVAL) - ':gap_days DAYS'::INTERVAL > CURRENT_TIMESTAMP
|
||||||
|
GROUP BY ignored_user_id
|
||||||
|
HAVING COUNT(ignored_user_id) >= :threshold
|
||||||
|
SQL
|
||||||
|
|
||||||
|
User.where(id: user_ids).find_each { |user| notify_user(user) }
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def notify_user(user)
|
||||||
|
params = SystemMessage.new(user).defaults.merge(ignores_threshold: SiteSetting.ignored_users_count_message_threshold)
|
||||||
|
title = I18n.t("system_messages.ignored_users_summary.subject_template")
|
||||||
|
raw = I18n.t("system_messages.ignored_users_summary.text_body_template", params)
|
||||||
|
|
||||||
|
PostCreator.create(
|
||||||
|
Discourse.system_user,
|
||||||
|
target_group_names: Group[:moderators].name,
|
||||||
|
archetype: Archetype.private_message,
|
||||||
|
subtype: TopicSubtype.system_message,
|
||||||
|
title: title,
|
||||||
|
raw: raw,
|
||||||
|
skip_validations: true)
|
||||||
|
IgnoredUser.where(ignored_user_id: user.id).update_all(summarized_at: Time.zone.now)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -1823,6 +1823,10 @@ en:
|
||||||
|
|
||||||
ignore_user_enabled: "[Beta] Allow ignoring users."
|
ignore_user_enabled: "[Beta] Allow ignoring users."
|
||||||
|
|
||||||
|
ignored_users_count_message_threshold: "Notify moderators if a particular user is ignored by this many other users."
|
||||||
|
|
||||||
|
ignored_users_message_gap_days: "How long wait before notifying moderators again about a user who has been ignored by many others"
|
||||||
|
|
||||||
user_website_domains_whitelist: "User website will be verified against these domains. Pipe-delimited list."
|
user_website_domains_whitelist: "User website will be verified against these domains. Pipe-delimited list."
|
||||||
|
|
||||||
allow_profile_backgrounds: "Allow users to upload profile backgrounds."
|
allow_profile_backgrounds: "Allow users to upload profile backgrounds."
|
||||||
|
@ -2829,6 +2833,18 @@ en:
|
||||||
%{raw}
|
%{raw}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
ignored_users_summary:
|
||||||
|
title: "Ignored User passed threshold"
|
||||||
|
subject_template: "A user is being ignored by many other users"
|
||||||
|
text_body_template: |
|
||||||
|
Hello,
|
||||||
|
|
||||||
|
This is an automated message from %{site_name} to inform you about a potentially problematic user who has been ignored by %{ignores_threshold} users. It would be smart to review their forum activity.
|
||||||
|
|
||||||
|
Please check the [user's profile](%{base_url}/u/%{username}/summary).
|
||||||
|
|
||||||
|
For additional guidance, please refer to our [community guidelines](%{base_url}/guidelines).
|
||||||
|
|
||||||
too_many_spam_flags:
|
too_many_spam_flags:
|
||||||
title: "Too Many Spam Flags"
|
title: "Too Many Spam Flags"
|
||||||
subject_template: "New account on hold"
|
subject_template: "New account on hold"
|
||||||
|
|
|
@ -532,6 +532,14 @@ users:
|
||||||
ignore_user_enabled:
|
ignore_user_enabled:
|
||||||
default: false
|
default: false
|
||||||
client: true
|
client: true
|
||||||
|
ignored_users_count_message_threshold:
|
||||||
|
default: 5
|
||||||
|
client: true
|
||||||
|
min: 1
|
||||||
|
ignored_users_message_gap_days:
|
||||||
|
default: 365
|
||||||
|
client: true
|
||||||
|
min: 1
|
||||||
|
|
||||||
groups:
|
groups:
|
||||||
enable_group_directory:
|
enable_group_directory:
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
class AddSummarizedAtColumnToIgnoredUsersTable < ActiveRecord::Migration[5.2]
|
||||||
|
def change
|
||||||
|
add_column :ignored_users, :summarized_at, :datetime
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,5 @@
|
||||||
|
Fabricator(:post_custom_field) do
|
||||||
|
post
|
||||||
|
name { sequence(:key) { |i| "key#{i}" } }
|
||||||
|
value "test value"
|
||||||
|
end
|
|
@ -0,0 +1,77 @@
|
||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
require_dependency 'jobs/scheduled/ignored_users_summary'
|
||||||
|
|
||||||
|
describe Jobs::IgnoredUsersSummary do
|
||||||
|
before do
|
||||||
|
SiteSetting.ignore_user_enabled = true
|
||||||
|
SiteSetting.ignored_users_count_message_threshold = 1
|
||||||
|
SiteSetting.ignored_users_message_gap_days = 365
|
||||||
|
end
|
||||||
|
|
||||||
|
subject { Jobs::IgnoredUsersSummary.new.execute({}) }
|
||||||
|
|
||||||
|
context "with no ignored users" do
|
||||||
|
it "does nothing" do
|
||||||
|
subject
|
||||||
|
expect { subject }.to_not change { Post.count }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when some ignored users exist" do
|
||||||
|
let(:tarek) { Fabricate(:user, username: "tarek") }
|
||||||
|
let(:matt) { Fabricate(:user, username: "matt") }
|
||||||
|
let(:john) { Fabricate(:user, username: "john") }
|
||||||
|
|
||||||
|
before do
|
||||||
|
Fabricate(:ignored_user, user: tarek, ignored_user: matt)
|
||||||
|
Fabricate(:ignored_user, user_id: tarek.id, ignored_user_id: john.id)
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when no system message exists for the ignored users" do
|
||||||
|
context "when threshold is not hit" do
|
||||||
|
before do
|
||||||
|
SiteSetting.ignored_users_count_message_threshold = 5
|
||||||
|
end
|
||||||
|
|
||||||
|
it "does nothing" do
|
||||||
|
subject
|
||||||
|
expect { subject }.to_not change { Post.count }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when threshold is hit" do
|
||||||
|
it "creates a system message" do
|
||||||
|
subject
|
||||||
|
posts = Post.joins(:topic).where(topics: {
|
||||||
|
archetype: Archetype.private_message,
|
||||||
|
subtype: TopicSubtype.system_message
|
||||||
|
})
|
||||||
|
expect(posts.count).to eq(2)
|
||||||
|
expect(posts[0].raw).to include(matt.username)
|
||||||
|
expect(posts[1].raw).to include(john.username)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when a system message already exists for the ignored users" do
|
||||||
|
context "when threshold is not hit" do
|
||||||
|
before do
|
||||||
|
SiteSetting.ignored_users_count_message_threshold = 5
|
||||||
|
end
|
||||||
|
|
||||||
|
it "does nothing" do
|
||||||
|
subject
|
||||||
|
expect { subject }.to_not change { Post.count }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when threshold is hit" do
|
||||||
|
it "does nothing" do
|
||||||
|
subject
|
||||||
|
expect { subject }.to_not change { Post.count }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in New Issue