FEATURE: Silence watched word (#13160)

FEATURE: Silence watched word (#13160)

This is a new type of watched word to replace auto_silence_first_post_ regex site setting.

diff --git a/app/models/watched_word.rb b/app/models/watched_word.rb
index 6c9c0e0..1a84b7f 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 0c9ac70..f1e4ddb 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 a5c6b13..aa28560 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 3a66d38..84c2faa 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 9b72719..1dc38fc 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 68a0ce0..1e7f64f 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

GitHub sha: 571ee453

This commit appears in #13160 which was approved by eviltrout. It was merged by nbianca.