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:
Tarek Khalil 2019-03-14 22:51:43 +00:00 committed by GitHub
parent fb8bcd7469
commit bd6d31c9ec
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 153 additions and 0 deletions

View File

@ -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

View File

@ -1823,6 +1823,10 @@ en:
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."
allow_profile_backgrounds: "Allow users to upload profile backgrounds."
@ -2829,6 +2833,18 @@ en:
%{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:
title: "Too Many Spam Flags"
subject_template: "New account on hold"

View File

@ -532,6 +532,14 @@ users:
ignore_user_enabled:
default: false
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:
enable_group_directory:

View File

@ -0,0 +1,5 @@
class AddSummarizedAtColumnToIgnoredUsersTable < ActiveRecord::Migration[5.2]
def change
add_column :ignored_users, :summarized_at, :datetime
end
end

View File

@ -0,0 +1,5 @@
Fabricator(:post_custom_field) do
post
name { sequence(:key) { |i| "key#{i}" } }
value "test value"
end

View File

@ -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