FEATURE: add staff action logs for watched words (#13574)

FEATURE: add staff action logs for watched words (#13574)

diff --git a/app/controllers/admin/watched_words_controller.rb b/app/controllers/admin/watched_words_controller.rb
index 5423c32..c2cdd25 100644
--- a/app/controllers/admin/watched_words_controller.rb
+++ b/app/controllers/admin/watched_words_controller.rb
@@ -14,6 +14,7 @@ class Admin::WatchedWordsController < Admin::AdminController
   def create
     watched_word = WatchedWord.create_or_update_word(watched_words_params)
     if watched_word.valid?
+      StaffActionLogger.new(current_user).log_watched_words_creation(watched_word)
       render json: watched_word, root: false
     else
       render_json_error(watched_word)
@@ -24,6 +25,7 @@ class Admin::WatchedWordsController < Admin::AdminController
     watched_word = WatchedWord.find_by(id: params[:id])
     raise Discourse::InvalidParameters.new(:id) unless watched_word
     watched_word.destroy!
+    StaffActionLogger.new(current_user).log_watched_words_deletion(watched_word)
     render json: success_json
   end
 
@@ -36,11 +38,14 @@ class Admin::WatchedWordsController < Admin::AdminController
       begin
         CSV.foreach(file.tempfile, encoding: "bom|utf-8") do |row|
           if row[0].present? && (!has_replacement || row[1].present?)
-            WatchedWord.create_or_update_word(
+            watched_word = WatchedWord.create_or_update_word(
               word: row[0],
               replacement: has_replacement ? row[1] : nil,
               action_key: action_key
             )
+            if watched_word.valid?
+              StaffActionLogger.new(current_user).log_watched_words_creation(watched_word)
+            end
           end
         end
 
@@ -79,7 +84,10 @@ class Admin::WatchedWordsController < Admin::AdminController
     action = WatchedWord.actions[name]
     raise Discourse::NotFound if !action
 
-    WatchedWord.where(action: action).delete_all
+    WatchedWord.where(action: action).find_each do |watched_word|
+      watched_word.destroy!
+      StaffActionLogger.new(current_user).log_watched_words_deletion(watched_word)
+    end
     WordWatcher.clear_cache!
     render json: success_json
   end
diff --git a/app/models/user_history.rb b/app/models/user_history.rb
index c84b326..a0403c7 100644
--- a/app/models/user_history.rb
+++ b/app/models/user_history.rb
@@ -114,7 +114,9 @@ class UserHistory < ActiveRecord::Base
       topic_archived: 93,
       topic_unarchived: 94,
       post_staff_note_create: 95,
-      post_staff_note_destroy: 96
+      post_staff_note_destroy: 96,
+      watched_word_create: 97,
+      watched_word_destroy: 98
     )
   end
 
@@ -205,7 +207,9 @@ class UserHistory < ActiveRecord::Base
       :topic_archived,
       :topic_unarchived,
       :post_staff_note_create,
-      :post_staff_note_destroy
+      :post_staff_note_destroy,
+      :watched_word_create,
+      :watched_word_destroy
     ]
   end
 
diff --git a/app/models/watched_word.rb b/app/models/watched_word.rb
index 9251d7d..f08f523 100644
--- a/app/models/watched_word.rb
+++ b/app/models/watched_word.rb
@@ -68,10 +68,17 @@ class WatchedWord < ActiveRecord::Base
     self.action = self.class.actions[arg.to_sym]
   end
 
+  def action_log_details
+    if replacement.present?
+      "#{word} → #{replacement}"
+    else
+      word
+    end
+  end
+
   def clear_cache
     WordWatcher.clear_cache!
   end
-
 end
 
 # == Schema Information
diff --git a/app/services/staff_action_logger.rb b/app/services/staff_action_logger.rb
index e859f42..01c4e2b 100644
--- a/app/services/staff_action_logger.rb
+++ b/app/services/staff_action_logger.rb
@@ -803,6 +803,28 @@ class StaffActionLogger
     )
   end
 
+  def log_watched_words_creation(watched_word)
+    raise Discourse::InvalidParameters.new(:watched_word) unless watched_word
+
+    UserHistory.create!(
+      action: UserHistory.actions[:watched_word_create],
+      acting_user_id: @admin.id,
+      details: watched_word.action_log_details,
+      context: WatchedWord.actions[watched_word.action]
+    )
+  end
+
+  def log_watched_words_deletion(watched_word)
+    raise Discourse::InvalidParameters.new(:watched_word) unless watched_word
+
+    UserHistory.create!(
+      action: UserHistory.actions[:watched_word_destroy],
+      acting_user_id: @admin.id,
+      details: watched_word.action_log_details,
+      context: WatchedWord.actions[watched_word.action]
+    )
+  end
+
   private
 
   def get_changes(changes)
@@ -829,5 +851,4 @@ class StaffActionLogger
   def validate_category(category)
     raise Discourse::InvalidParameters.new(:category) unless category && category.is_a?(Category)
   end
-
 end
diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml
index 6d3f72a..58e07ea 100644
--- a/config/locales/client.en.yml
+++ b/config/locales/client.en.yml
@@ -4699,6 +4699,8 @@ en:
             post_staff_note_create: "add staff note"
             post_staff_note_destroy: "destroy staff note"
             delete_group: "delete group"
+            add_watched_word: "add watched word"
+            delete_watched_word: "delete watched word"
         screened_emails:
           title: "Screened Emails"
           description: "When someone tries to create a new account, the following email addresses will be checked and the registration will be blocked, or some other action performed."
diff --git a/spec/requests/admin/watched_words_controller_spec.rb b/spec/requests/admin/watched_words_controller_spec.rb
index 417e19a..0acaea6 100644
--- a/spec/requests/admin/watched_words_controller_spec.rb
+++ b/spec/requests/admin/watched_words_controller_spec.rb
@@ -24,6 +24,7 @@ RSpec.describe Admin::WatchedWordsController do
 
       expect(response.status).to eq(200)
       expect(WatchedWord.find_by(id: watched_word.id)).to eq(nil)
+      expect(UserHistory.where(action: UserHistory.actions[:watched_word_destroy]).count).to eq(1)
     end
   end
 
@@ -47,6 +48,7 @@ RSpec.describe Admin::WatchedWordsController do
         )
 
         expect(WatchedWord.pluck(:action).uniq).to eq([WatchedWord.actions[:flag]])
+        expect(UserHistory.where(action: UserHistory.actions[:watched_word_create]).count).to eq(6)
       end
 
       it 'creates the words from the file' do
@@ -64,6 +66,7 @@ RSpec.describe Admin::WatchedWordsController do
         )
 
         expect(WatchedWord.pluck(:action).uniq).to eq([WatchedWord.actions[:tag]])
+        expect(UserHistory.where(action: UserHistory.actions[:watched_word_create]).count).to eq(2)
       end
     end
   end
@@ -129,6 +132,7 @@ RSpec.describe Admin::WatchedWordsController do
         delete "/admin/customize/watched_words/action/block.json"
         expect(response.status).to eq(200)
         expect(WatchedWord.pluck(:word)).not_to include(word.word)
+        expect(UserHistory.where(action: UserHistory.actions[:watched_word_destroy]).count).to eq(1)
       end
 
       it "doesn't delete words of multiple actions in one call" do
@@ -140,6 +144,7 @@ RSpec.describe Admin::WatchedWordsController do
         all_words = WatchedWord.pluck(:word)
         expect(all_words).to include(block_word.word)
         expect(all_words).not_to include(flag_word.word)
+        expect(UserHistory.where(action: UserHistory.actions[:watched_word_destroy]).count).to eq(1)
       end
     end
   end
diff --git a/spec/services/staff_action_logger_spec.rb b/spec/services/staff_action_logger_spec.rb
index 1c05537..d40d382 100644
--- a/spec/services/staff_action_logger_spec.rb
+++ b/spec/services/staff_action_logger_spec.rb
@@ -544,7 +544,6 @@ describe StaffActionLogger do
       expect(user_history.action).to eq(UserHistory.actions[:post_rejected])
       expect(user_history.details).to include(reviewable.payload['raw'])
     end
-
   end
 
   describe 'log_topic_closed' do
@@ -617,4 +616,43 @@ describe StaffActionLogger do
     end
   end
 
+  describe '#log_watched_words_creation' do
+    fab!(:watched_word) { Fabricate(:watched_word, action: WatchedWord.actions[:block]) }
+

[... diff too long, it was truncated ...]

GitHub sha: 1ea2880276e24e01fd4e15e054b9f8f069a19af9

This commit appears in #13574 which was approved by tgxworld. It was merged by techAPJ.