From 571ee4537a3ed1ccc02bfae0462d1b409f18cbba Mon Sep 17 00:00:00 2001 From: Bianca Nenciu Date: Thu, 27 May 2021 19:19:58 +0300 Subject: [PATCH] FEATURE: Silence watched word (#13160) This is a new type of watched word to replace auto_silence_first_post_ regex site setting. --- app/models/watched_word.rb | 1 + app/services/word_watcher.rb | 4 ++++ config/locales/client.en.yml | 2 ++ config/locales/server.en.yml | 1 + lib/new_post_manager.rb | 8 ++++++-- spec/requests/posts_controller_spec.rb | 22 ++++++++++++++++++++++ 6 files changed, 36 insertions(+), 2 deletions(-) diff --git a/app/models/watched_word.rb b/app/models/watched_word.rb index 6c9c0e07a3b..1a84b7fd5dc 100644 --- a/app/models/watched_word.rb +++ b/app/models/watched_word.rb @@ -10,6 +10,7 @@ class WatchedWord < ActiveRecord::Base flag: 4, replace: 5, tag: 6, + silence: 7 ) end diff --git a/app/services/word_watcher.rb b/app/services/word_watcher.rb index 0c9ac7076e7..f1e4ddbf5b9 100644 --- a/app/services/word_watcher.rb +++ b/app/services/word_watcher.rb @@ -88,6 +88,10 @@ class WordWatcher word_matches_for_action?(:block, all_matches: true) end + def should_silence? + word_matches_for_action?(:silence) + end + def word_matches_for_action?(action, all_matches: false) regexp = self.class.word_matcher_regexp(action) if regexp diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index a5c6b13662e..aa285607380 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -4708,6 +4708,7 @@ en: flag: "Flag" replace: "Replace" tag: "Tag" + silence: "Silence" action_descriptions: block: "Prevent posts containing these words from being posted. The user will see an error message when they try to submit their post." censor: "Allow posts containing these words, but replace them with characters that hide the censored words." @@ -4715,6 +4716,7 @@ en: flag: "Allow posts containing these words, but flag them as inappropriate so moderators can review them." replace: "Replace words in posts with other words or links" tag: "Automatically tag topics based on first post" + silence: "First posts of users containing these words will require approval by staff before they can be seen and the user will be automatically silenced." form: label: "Has word or phrase" placeholder: "Enter word or phrase (* is a wildcard)" diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml index 3a66d38b500..84c2faa36eb 100644 --- a/config/locales/server.en.yml +++ b/config/locales/server.en.yml @@ -2562,6 +2562,7 @@ en: other: "Automatically deactivated after %{count} days of inactivity" activated_by_staff: "Activated by staff" new_user_typed_too_fast: "New user typed too fast" + content_matches_auto_silence_regex: "Content matches auto silence regex" content_matches_auto_block_regex: "Content matches auto block regex" username: short: "must be at least %{min} characters" diff --git a/lib/new_post_manager.rb b/lib/new_post_manager.rb index 9b72719232b..1dc38fcc7f7 100644 --- a/lib/new_post_manager.rb +++ b/lib/new_post_manager.rb @@ -54,6 +54,10 @@ class NewPostManager manager.user.trust_level <= SiteSetting.auto_silence_fast_typers_max_trust_level end + def self.auto_silence?(manager) + is_first_post?(manager) && WordWatcher.new("#{manager.args[:title]} #{manager.args[:raw]}").should_silence? + end + def self.matches_auto_silence_regex?(manager) args = manager.args @@ -102,7 +106,7 @@ class NewPostManager return :fast_typer if is_fast_typer?(manager) - return :auto_silence_regex if matches_auto_silence_regex?(manager) + return :auto_silence_regex if auto_silence?(manager) || matches_auto_silence_regex?(manager) return :staged if SiteSetting.approve_unless_staged? && user.staged? @@ -168,7 +172,7 @@ class NewPostManager I18n.with_locale(SiteSetting.default_locale) do if is_fast_typer?(manager) UserSilencer.silence(manager.user, Discourse.system_user, keep_posts: true, reason: I18n.t("user.new_user_typed_too_fast")) - elsif matches_auto_silence_regex?(manager) + elsif auto_silence?(manager) || matches_auto_silence_regex?(manager) UserSilencer.silence(manager.user, Discourse.system_user, keep_posts: true, reason: I18n.t("user.content_matches_auto_silence_regex")) elsif reason == :email_spam && is_first_post?(manager) UserSilencer.silence(manager.user, Discourse.system_user, keep_posts: true, reason: I18n.t("user.email_in_spam_header")) diff --git a/spec/requests/posts_controller_spec.rb b/spec/requests/posts_controller_spec.rb index 68a0ce008e9..1e7f64f4731 100644 --- a/spec/requests/posts_controller_spec.rb +++ b/spec/requests/posts_controller_spec.rb @@ -907,6 +907,28 @@ describe PostsController do expect(user).to be_silenced end + it 'silences correctly based on silence watched words' do + SiteSetting.watched_words_regular_expressions = true + WatchedWord.create!(action: WatchedWord.actions[:silence], word: 'I love candy') + WatchedWord.create!(action: WatchedWord.actions[:silence], word: 'i eat s[1-5]') + + post "/posts.json", params: { + raw: 'this is the test content', + title: 'when I eat s3 sometimes when not looking' + } + + expect(response.status).to eq(200) + parsed = response.parsed_body + + expect(parsed["action"]).to eq("enqueued") + reviewable = ReviewableQueuedPost.find_by(created_by: user) + score = reviewable.reviewable_scores.first + expect(score.reason).to eq('auto_silence_regex') + + user.reload + expect(user).to be_silenced + end + it "can send a message to a group" do group = Group.create(name: 'test_group', messageable_level: Group::ALIAS_LEVELS[:nobody]) user1 = user