From 644e6c7f46fdefcc64f5b6dc48c9043aaa363798 Mon Sep 17 00:00:00 2001
From: Krzysztof Kotlarek <kotlarek.krzysztof@gmail.com>
Date: Tue, 22 Oct 2024 10:56:31 +1100
Subject: [PATCH] FEATURE: auto_action_type field for flags (#29306)

Allow admins to specify if the flag should be `auto_action_type`. If yes, then when an admin flags a post,  it is automatically actioned.

Meta: https://meta.discourse.org/t/allow-creation-of-custom-flags-which-auto-hide-content-similar-to-spam-and-inapproriate/329894
---
 .../addon/components/admin-flags-form.gjs     | 27 ++++++++++++++++++-
 app/serializers/flag_serializer.rb            |  3 ++-
 app/services/flags/create_flag.rb             |  1 +
 app/services/flags/update_flag.rb             |  1 +
 config/locales/client.en.yml                  |  2 ++
 .../api/schemas/json/site_response.json       | 12 +++++++--
 spec/services/flags/create_flag_spec.rb       |  6 ++++-
 spec/services/flags/update_flag_spec.rb       | 14 +++++++++-
 8 files changed, 60 insertions(+), 6 deletions(-)

diff --git a/app/assets/javascripts/admin/addon/components/admin-flags-form.gjs b/app/assets/javascripts/admin/addon/components/admin-flags-form.gjs
index fa9a0b0d341..4395ac21116 100644
--- a/app/assets/javascripts/admin/addon/components/admin-flags-form.gjs
+++ b/app/assets/javascripts/admin/addon/components/admin-flags-form.gjs
@@ -30,11 +30,13 @@ export default class AdminFlagsForm extends Component {
         appliesTo: this.args.flag.applies_to,
         requireMessage: this.args.flag.require_message,
         enabled: this.args.flag.enabled,
+        autoActionType: this.args.flag.auto_action_type,
       };
     } else {
       return {
         enabled: true,
         requireMessage: false,
+        autoActionType: false,
       };
     }
   }
@@ -68,7 +70,14 @@ export default class AdminFlagsForm extends Component {
   }
 
   @action
-  save({ name, description, appliesTo, requireMessage, enabled }) {
+  save({
+    name,
+    description,
+    appliesTo,
+    requireMessage,
+    enabled,
+    autoActionType,
+  }) {
     const createOrUpdate = this.isUpdate ? this.update : this.create;
     const data = {
       name,
@@ -76,6 +85,7 @@ export default class AdminFlagsForm extends Component {
       enabled,
       applies_to: appliesTo,
       require_message: requireMessage,
+      auto_action_type: autoActionType,
     };
     createOrUpdate(data);
   }
@@ -107,6 +117,7 @@ export default class AdminFlagsForm extends Component {
       this.args.flag.applies_to = response.flag.applies_to;
       this.args.flag.require_message = response.flag.require_message;
       this.args.flag.enabled = response.flag.enabled;
+      this.args.flag.auto_action_type = response.flag.auto_action_type;
       this.router.transitionTo("adminConfig.flags");
     } catch (error) {
       popupAjaxError(error);
@@ -183,6 +194,20 @@ export default class AdminFlagsForm extends Component {
                 >
                   <field.Checkbox />
                 </checkboxGroup.Field>
+
+                <checkboxGroup.Field
+                  @name="autoActionType"
+                  @title={{i18n
+                    "admin.config_areas.flags.form.auto_action_type"
+                  }}
+                  as |field|
+                >
+                  <field.Checkbox>
+                    {{i18n
+                      "admin.config_areas.flags.form.auto_action_type_description"
+                    }}
+                  </field.Checkbox>
+                </checkboxGroup.Field>
               </form.CheckboxGroup>
 
               <form.Alert @icon="info-circle">
diff --git a/app/serializers/flag_serializer.rb b/app/serializers/flag_serializer.rb
index b7e4e927e3e..bc072927c3b 100644
--- a/app/serializers/flag_serializer.rb
+++ b/app/serializers/flag_serializer.rb
@@ -12,7 +12,8 @@ class FlagSerializer < ApplicationSerializer
              :enabled,
              :is_flag,
              :applies_to,
-             :is_used
+             :is_used,
+             :auto_action_type
 
   def i18n_prefix
     "#{@options[:target] || "post_action"}_types.#{object.name_key}"
diff --git a/app/services/flags/create_flag.rb b/app/services/flags/create_flag.rb
index 8a0f1e85931..b0d1b385dbc 100644
--- a/app/services/flags/create_flag.rb
+++ b/app/services/flags/create_flag.rb
@@ -10,6 +10,7 @@ class Flags::CreateFlag
     attribute :require_message, :boolean
     attribute :enabled, :boolean
     attribute :applies_to
+    attribute :auto_action_type, :boolean
 
     validates :name, presence: true
     validates :description, presence: true
diff --git a/app/services/flags/update_flag.rb b/app/services/flags/update_flag.rb
index a32312aaaad..1a52d3d8925 100644
--- a/app/services/flags/update_flag.rb
+++ b/app/services/flags/update_flag.rb
@@ -10,6 +10,7 @@ class Flags::UpdateFlag
     attribute :require_message, :boolean
     attribute :enabled, :boolean
     attribute :applies_to
+    attribute :auto_action_type, :boolean
 
     validates :id, presence: true
     validates :name, presence: true
diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml
index dc046bb6c28..28dc31fdea8 100644
--- a/config/locales/client.en.yml
+++ b/config/locales/client.en.yml
@@ -5679,6 +5679,8 @@ en:
             non_deletable: "You cannot delete this flag because it is a system flag or has already been used in the review system, however you can still disable it."
             require_message: "Prompt users to provide additional reasons"
             require_message_description: "When this flag is selected, a text field will be displayed for the user to provide additional detail about why they are flagging the content"
+            auto_action_type: "Auto action type"
+            auto_action_type_description: "When a post is flagged by a staff member it is automatically hidden"
           more_options:
             title: "More options"
             move_up: "Move up"
diff --git a/spec/requests/api/schemas/json/site_response.json b/spec/requests/api/schemas/json/site_response.json
index 44cf69df471..a91ea86bb52 100644
--- a/spec/requests/api/schemas/json/site_response.json
+++ b/spec/requests/api/schemas/json/site_response.json
@@ -368,6 +368,9 @@
             },
             "position": {
               "type": "integer"
+            },
+            "auto_action_type": {
+              "type": "boolean"
             }
           },
           "required": [
@@ -380,7 +383,8 @@
             "require_message",
             "enabled",
             "applies_to",
-            "is_used"
+            "is_used",
+            "auto_action_type"
           ]
         }
     },
@@ -423,6 +427,9 @@
             },
             "position": {
               "type": "integer"
+            },
+            "auto_action_type": {
+              "type": "boolean"
             }
           },
           "required": [
@@ -435,7 +442,8 @@
             "require_message",
             "enabled",
             "applies_to",
-            "is_used"
+            "is_used",
+            "auto_action_type"
           ]
         }
     },
diff --git a/spec/services/flags/create_flag_spec.rb b/spec/services/flags/create_flag_spec.rb
index 0ba2858ef17..4906ecbcefc 100644
--- a/spec/services/flags/create_flag_spec.rb
+++ b/spec/services/flags/create_flag_spec.rb
@@ -14,13 +14,16 @@ RSpec.describe(Flags::CreateFlag) do
 
     fab!(:current_user) { Fabricate(:admin) }
 
-    let(:params) { { name:, description:, applies_to:, require_message:, enabled: } }
+    let(:params) do
+      { name:, description:, applies_to:, require_message:, enabled:, auto_action_type: }
+    end
     let(:dependencies) { { guardian: current_user.guardian } }
     let(:name) { "custom flag name" }
     let(:description) { "custom flag description" }
     let(:applies_to) { ["Topic"] }
     let(:enabled) { true }
     let(:require_message) { true }
+    let(:auto_action_type) { true }
 
     context "when user is not allowed to perform the action" do
       fab!(:current_user) { Fabricate(:user) }
@@ -62,6 +65,7 @@ RSpec.describe(Flags::CreateFlag) do
           require_message: true,
           enabled: true,
           notify_type: true,
+          auto_action_type: true,
         )
       end
 
diff --git a/spec/services/flags/update_flag_spec.rb b/spec/services/flags/update_flag_spec.rb
index 17fcde871a0..70b216727c2 100644
--- a/spec/services/flags/update_flag_spec.rb
+++ b/spec/services/flags/update_flag_spec.rb
@@ -16,7 +16,17 @@ RSpec.describe(Flags::UpdateFlag) do
     fab!(:current_user) { Fabricate(:admin) }
 
     let(:flag) { Fabricate(:flag) }
-    let(:params) { { id: flag_id, name:, description:, applies_to:, require_message:, enabled: } }
+    let(:params) do
+      {
+        id: flag_id,
+        name:,
+        description:,
+        applies_to:,
+        require_message:,
+        enabled:,
+        auto_action_type:,
+      }
+    end
     let(:dependencies) { { guardian: current_user.guardian } }
     let(:flag_id) { flag.id }
     let(:name) { "edited custom flag name" }
@@ -24,6 +34,7 @@ RSpec.describe(Flags::UpdateFlag) do
     let(:applies_to) { ["Topic"] }
     let(:require_message) { true }
     let(:enabled) { false }
+    let(:auto_action_type) { true }
 
     context "when contract is invalid" do
       let(:name) { nil }
@@ -72,6 +83,7 @@ RSpec.describe(Flags::UpdateFlag) do
           applies_to: ["Topic"],
           require_message: true,
           enabled: false,
+          auto_action_type: true,
         )
       end