From 963b9fd1571d8518b5cd5e95f0103521c6e72a97 Mon Sep 17 00:00:00 2001 From: Krzysztof Kotlarek Date: Wed, 29 May 2024 14:39:58 +1000 Subject: [PATCH] FEATURE: admin can disable flags (#27171) UI for admins to disable system flags. --- .../addon/components/admin-flag-item.gjs | 43 +++++++++++++++++++ .../admin/addon/components/admin-flags.gjs | 26 +++++++++++ .../admin/addon/routes/admin-route-map.js | 8 ++++ .../addon/templates/config-flags-index.hbs | 1 + .../addon/templates/flags-index.hbs ./config | 1 + .../discourse/app/components/modal/flag.js | 2 +- .../app/lib/sidebar/admin-nav-map.js | 6 +++ .../discourse/tests/fixtures/site-fixtures.js | 9 ++++ .../stylesheets/common/admin/admin_base.scss | 1 + .../stylesheets/common/admin/flags.scss | 11 +++++ app/controllers/admin/admin_controller.rb | 2 + .../admin/config/flags_controller.rb | 21 +++++++++ app/controllers/admin/staff_controller.rb | 2 + app/models/flag.rb | 1 + app/models/post_action_type.rb | 22 +++++++++- app/models/reviewable_score.rb | 2 +- .../post_action_type_serializer.rb | 15 ++++++- app/serializers/toggle_flag.rb | 40 +++++++++++++++++ config/locales/client.en.yml | 7 +++ config/routes.rb | 5 +++ db/fixtures/003_flags.rb | 10 +++++ .../20240527055057_add_score_type_to_flags.rb | 7 +++ lib/guardian/flag_guardian.rb | 4 ++ lib/guardian/post_guardian.rb | 2 + spec/lib/guardian/flag_guardian_spec.rb | 11 ++++- spec/lib/guardian_spec.rb | 9 ++++ .../api/schemas/json/site_response.json | 12 +++++- spec/services/toggle_flag_spec.rb | 33 ++++++++++++++ spec/system/admin_flags_spec.rb | 29 +++++++++++++ spec/system/page_objects/pages/admin_flags.rb | 11 +++++ spec/system/page_objects/pages/topic.rb | 4 ++ 31 files changed, 350 insertions(+), 7 deletions(-) create mode 100644 app/assets/javascripts/admin/addon/components/admin-flag-item.gjs create mode 100644 app/assets/javascripts/admin/addon/components/admin-flags.gjs create mode 100644 app/assets/javascripts/admin/addon/templates/config-flags-index.hbs create mode 100644 app/assets/javascripts/admin/addon/templates/flags-index.hbs ./config create mode 100644 app/assets/stylesheets/common/admin/flags.scss create mode 100644 app/controllers/admin/config/flags_controller.rb create mode 100644 app/serializers/toggle_flag.rb create mode 100644 db/migrate/20240527055057_add_score_type_to_flags.rb create mode 100644 spec/services/toggle_flag_spec.rb create mode 100644 spec/system/admin_flags_spec.rb create mode 100644 spec/system/page_objects/pages/admin_flags.rb diff --git a/app/assets/javascripts/admin/addon/components/admin-flag-item.gjs b/app/assets/javascripts/admin/addon/components/admin-flag-item.gjs new file mode 100644 index 00000000000..09a1f639b8e --- /dev/null +++ b/app/assets/javascripts/admin/addon/components/admin-flag-item.gjs @@ -0,0 +1,43 @@ +import Component from "@glimmer/component"; +import { tracked } from "@glimmer/tracking"; +import { fn } from "@ember/helper"; +import { on } from "@ember/modifier"; +import { action } from "@ember/object"; +import { htmlSafe } from "@ember/template"; +import DToggleSwitch from "discourse/components/d-toggle-switch"; +import { ajax } from "discourse/lib/ajax"; +import { popupAjaxError } from "discourse/lib/ajax-error"; + +export default class AdminFlagItem extends Component { + @tracked enabled = this.args.flag.enabled; + + @action + toggleFlagEnabled(flag) { + this.enabled = !this.enabled; + + return ajax(`/admin/config/flags/${flag.id}/toggle`, { + type: "PUT", + }).catch((error) => { + this.enabled = !this.enabled; + return popupAjaxError(error); + }); + } + + +} diff --git a/app/assets/javascripts/admin/addon/components/admin-flags.gjs b/app/assets/javascripts/admin/addon/components/admin-flags.gjs new file mode 100644 index 00000000000..226eaf9aae9 --- /dev/null +++ b/app/assets/javascripts/admin/addon/components/admin-flags.gjs @@ -0,0 +1,26 @@ +import Component from "@glimmer/component"; +import { inject as service } from "@ember/service"; +import i18n from "discourse-common/helpers/i18n"; +import AdminFlagItem from "admin/components/admin-flag-item"; + +export default class AdminFlags extends Component { + @service site; + flags = this.site.flagTypes; + + +} diff --git a/app/assets/javascripts/admin/addon/routes/admin-route-map.js b/app/assets/javascripts/admin/addon/routes/admin-route-map.js index 94be1effbed..4691fbe0b4d 100644 --- a/app/assets/javascripts/admin/addon/routes/admin-route-map.js +++ b/app/assets/javascripts/admin/addon/routes/admin-route-map.js @@ -209,6 +209,14 @@ export default function () { } ); + this.route( + "adminConfigFlags", + { path: "/config/flags", resetNamespace: true }, + function () { + this.route("index", { path: "/" }); + } + ); + this.route( "adminPlugins", { path: "/plugins", resetNamespace: true }, diff --git a/app/assets/javascripts/admin/addon/templates/config-flags-index.hbs b/app/assets/javascripts/admin/addon/templates/config-flags-index.hbs new file mode 100644 index 00000000000..a67eca6e56b --- /dev/null +++ b/app/assets/javascripts/admin/addon/templates/config-flags-index.hbs @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/assets/javascripts/admin/addon/templates/flags-index.hbs ./config b/app/assets/javascripts/admin/addon/templates/flags-index.hbs ./config new file mode 100644 index 00000000000..587c5fd41ed --- /dev/null +++ b/app/assets/javascripts/admin/addon/templates/flags-index.hbs ./config @@ -0,0 +1 @@ + diff --git a/app/assets/javascripts/discourse/app/components/modal/flag.js b/app/assets/javascripts/discourse/app/components/modal/flag.js index 6d43147e792..95b26ec3535 100644 --- a/app/assets/javascripts/discourse/app/components/modal/flag.js +++ b/app/assets/javascripts/discourse/app/components/modal/flag.js @@ -85,7 +85,7 @@ export default class Flag extends Component { } get flagsAvailable() { - return this.args.model.flagTarget.flagsAvailable(this); + return this.args.model.flagTarget.flagsAvailable(this).filterBy("enabled"); } get staffFlagsAvailable() { diff --git a/app/assets/javascripts/discourse/app/lib/sidebar/admin-nav-map.js b/app/assets/javascripts/discourse/app/lib/sidebar/admin-nav-map.js index c0dd6f4e70e..c78cdd5854a 100644 --- a/app/assets/javascripts/discourse/app/lib/sidebar/admin-nav-map.js +++ b/app/assets/javascripts/discourse/app/lib/sidebar/admin-nav-map.js @@ -110,6 +110,12 @@ export const ADMIN_NAV_MAP = [ label: "admin.community.sidebar_link.legal", icon: "gavel", }, + { + name: "admin_moderation_flags", + route: "adminConfigFlags", + label: "admin.community.sidebar_link.moderation_flags", + icon: "flag", + }, ], }, { diff --git a/app/assets/javascripts/discourse/tests/fixtures/site-fixtures.js b/app/assets/javascripts/discourse/tests/fixtures/site-fixtures.js index d11a3655f3e..004a9e1e4fe 100644 --- a/app/assets/javascripts/discourse/tests/fixtures/site-fixtures.js +++ b/app/assets/javascripts/discourse/tests/fixtures/site-fixtures.js @@ -590,6 +590,7 @@ export default { icon: null, id: 3, is_custom_flag: false, + enabled: true }, { name_key: "inappropriate", @@ -602,6 +603,7 @@ export default { icon: null, id: 4, is_custom_flag: false, + enabled: true }, { name_key: "vote", @@ -612,6 +614,7 @@ export default { icon: null, id: 5, is_custom_flag: false, + enabled: true }, { name_key: "spam", @@ -623,6 +626,7 @@ export default { icon: null, id: 8, is_custom_flag: false, + enabled: true }, { name_key: "notify_user", @@ -635,6 +639,7 @@ export default { icon: null, id: 6, is_custom_flag: true, + enabled: true }, { name_key: "notify_moderators", @@ -646,6 +651,7 @@ export default { icon: null, id: 7, is_custom_flag: true, + enabled: true }, ], topic_flag_types: [ @@ -658,6 +664,7 @@ export default { icon: null, id: 4, is_custom_flag: false, + enabled: true }, { name_key: "spam", @@ -668,6 +675,7 @@ export default { icon: null, id: 8, is_custom_flag: false, + enabled: true }, { name_key: "notify_moderators", @@ -678,6 +686,7 @@ export default { icon: null, id: 7, is_custom_flag: true, + enabled: true }, ], archetypes: [ diff --git a/app/assets/stylesheets/common/admin/admin_base.scss b/app/assets/stylesheets/common/admin/admin_base.scss index 08ccc0d491f..f1498ef60d3 100644 --- a/app/assets/stylesheets/common/admin/admin_base.scss +++ b/app/assets/stylesheets/common/admin/admin_base.scss @@ -1056,6 +1056,7 @@ a.inline-editable-field { @import "common/admin/penalty"; @import "common/admin/badges"; @import "common/admin/emails"; +@import "common/admin/flags"; @import "common/admin/json_schema_editor"; @import "common/admin/schema_field"; @import "common/admin/staff_logs"; diff --git a/app/assets/stylesheets/common/admin/flags.scss b/app/assets/stylesheets/common/admin/flags.scss new file mode 100644 index 00000000000..1adf148b8a4 --- /dev/null +++ b/app/assets/stylesheets/common/admin/flags.scss @@ -0,0 +1,11 @@ +.admin-flag-item { + &__name { + font-weight: bold; + color: var(--tertiary); + padding-bottom: 0; + margin-bottom: 0; + } + &__description { + margin-top: 0.5em; + } +} diff --git a/app/controllers/admin/admin_controller.rb b/app/controllers/admin/admin_controller.rb index 2220a511e77..2595961acf9 100644 --- a/app/controllers/admin/admin_controller.rb +++ b/app/controllers/admin/admin_controller.rb @@ -1,6 +1,8 @@ # frozen_string_literal: true class Admin::AdminController < ApplicationController + include WithServiceHelper + requires_login before_action :ensure_admin diff --git a/app/controllers/admin/config/flags_controller.rb b/app/controllers/admin/config/flags_controller.rb new file mode 100644 index 00000000000..7eb69d50fff --- /dev/null +++ b/app/controllers/admin/config/flags_controller.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +class Admin::Config::FlagsController < Admin::AdminController + def toggle + with_service(ToggleFlag) do + on_success do + Discourse.request_refresh! + render(json: success_json) + end + on_failure { render(json: failed_json, status: 422) } + on_model_not_found(:message) { raise Discourse::NotFound } + on_failed_policy(:invalid_access) { raise Discourse::InvalidAccess } + on_failed_contract do |contract| + render(json: failed_json.merge(errors: contract.errors.full_messages), status: 400) + end + end + end + + def index + end +end diff --git a/app/controllers/admin/staff_controller.rb b/app/controllers/admin/staff_controller.rb index 01d18fc92c4..39205fdff34 100644 --- a/app/controllers/admin/staff_controller.rb +++ b/app/controllers/admin/staff_controller.rb @@ -1,6 +1,8 @@ # frozen_string_literal: true class Admin::StaffController < ApplicationController + include WithServiceHelper + requires_login before_action :ensure_staff end diff --git a/app/models/flag.rb b/app/models/flag.rb index 5085d0246a2..1312dfbf3d6 100644 --- a/app/models/flag.rb +++ b/app/models/flag.rb @@ -62,4 +62,5 @@ end # enabled :boolean default(TRUE), not null # created_at :datetime not null # updated_at :datetime not null +# score_type :boolean default(FALSE), not null # diff --git a/app/models/post_action_type.rb b/app/models/post_action_type.rb index 2becdad1207..611a011c4df 100644 --- a/app/models/post_action_type.rb +++ b/app/models/post_action_type.rb @@ -37,6 +37,7 @@ class PostActionType < ActiveRecord::Base @all_flags = nil @flag_settings = FlagSettings.new ReviewableScore.reload_types + PostActionType.new.expire_cache end def overridden_by_plugin_or_skipped_db? @@ -67,7 +68,18 @@ class PostActionType < ActiveRecord::Base def flag_types return flag_settings.flag_types if overridden_by_plugin_or_skipped_db? - flag_enum(all_flags) + + # Once replace_flag API is fully deprecated, then we can drop respond_to. It is needed right now for migration to be evaluated. + # TODO (krisk) + flag_enum(all_flags.reject { |flag| flag.respond_to?(:score_type) && flag.score_type }) + end + + def score_types + return flag_settings.flag_types if overridden_by_plugin_or_skipped_db? + + # Once replace_flag API is fully deprecated, then we can drop respond_to. It is needed right now for migration to be evaluated. + # TODO (krisk) + flag_enum(all_flags.filter { |flag| flag.respond_to?(:score_type) && flag.score_type }) end # flags resulting in mod notifications @@ -88,6 +100,14 @@ class PostActionType < ActiveRecord::Base end end + def disabled_flag_types + flag_enum(all_flags.reject(&:enabled)) + end + + def enabled_flag_types + flag_enum(all_flags.filter(&:enabled)) + end + def custom_types return flag_settings.custom_types if overridden_by_plugin_or_skipped_db? flag_enum(all_flags.select(&:custom_type)) diff --git a/app/models/reviewable_score.rb b/app/models/reviewable_score.rb index 774a5385333..af34a428ed3 100644 --- a/app/models/reviewable_score.rb +++ b/app/models/reviewable_score.rb @@ -11,7 +11,7 @@ class ReviewableScore < ActiveRecord::Base # To keep things simple the types correspond to `PostActionType` for backwards # compatibility, but we can add extra reasons for scores. def self.types - @types ||= PostActionType.flag_types.merge(needs_approval: 9) + @types ||= PostActionType.flag_types.merge(PostActionType.score_types) end # When extending post action flags, we need to call this method in order to diff --git a/app/serializers/post_action_type_serializer.rb b/app/serializers/post_action_type_serializer.rb index 7f42c654e9a..ea2684180ef 100644 --- a/app/serializers/post_action_type_serializer.rb +++ b/app/serializers/post_action_type_serializer.rb @@ -1,7 +1,16 @@ # frozen_string_literal: true class PostActionTypeSerializer < ApplicationSerializer - attributes(:id, :name_key, :name, :description, :short_description, :is_flag, :is_custom_flag) + attributes( + :id, + :name_key, + :name, + :description, + :short_description, + :is_flag, + :is_custom_flag, + :enabled, + ) include ConfigurableUrls @@ -29,6 +38,10 @@ class PostActionTypeSerializer < ApplicationSerializer PostActionType.types[object.id].to_s end + def enabled + !!PostActionType.enabled_flag_types[object.id] + end + protected def i18n(field, default: nil, vars: nil) diff --git a/app/serializers/toggle_flag.rb b/app/serializers/toggle_flag.rb new file mode 100644 index 00000000000..b30839f649a --- /dev/null +++ b/app/serializers/toggle_flag.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true + +class ToggleFlag + include Service::Base + + contract + model :flag + policy :invalid_access + + transaction do + step :toggle + step :log + end + + class Contract + attribute :flag_id, :integer + validates :flag_id, presence: true + end + + private + + def fetch_flag(flag_id:) + Flag.find(flag_id) + end + + def invalid_access(guardian:) + guardian.can_toggle_flag? + end + + def toggle(flag:) + flag.update!(enabled: !flag.enabled) + end + + def log(guardian:, flag:) + StaffActionLogger.new(guardian.user).log_custom( + "toggle_flag", + { flag: flag.name, enabled: flag.enabled }, + ) + end +end diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index 1e84567389d..10911dbfabd 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -5023,6 +5023,10 @@ en: label: Category include_subcategories: label: "Include Subcategories" + flags: + title: "Moderation Flags" + description: "Description" + enabled: "Enabled?" groups: new: @@ -5362,6 +5366,8 @@ en: user_fields: "User Fields" watched_words: "Watched Words" legal: "Legal" + moderation_flags: "Moderation Flags" + appearance: title: "Appearance" @@ -6080,6 +6086,7 @@ en: create_watched_word_group: "create watched word group" update_watched_word_group: "update watched word group" delete_watched_word_group: "delete watched word group" + toggle_flag: "toggle flag" 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/config/routes.rb b/config/routes.rb index 13e3909b573..dcfd3f54b85 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -393,6 +393,11 @@ Discourse::Application.routes.draw do post "preview" => "badges#preview" end end + namespace :config, constraints: StaffConstraint.new do + resources :flags, only: %i[index] do + put "toggle" + end + end end # admin namespace get "email/unsubscribe/:key" => "email#unsubscribe", :as => "email_unsubscribe" diff --git a/db/fixtures/003_flags.rb b/db/fixtures/003_flags.rb index 2e5aa43d1a3..3e8fef259c8 100644 --- a/db/fixtures/003_flags.rb +++ b/db/fixtures/003_flags.rb @@ -54,3 +54,13 @@ Flag.seed do |s| s.custom_type = true s.applies_to = %w[Post Topic Chat::Message] end +Flag.seed do |s| + s.id = 9 + s.name = "needs_approval" + s.position = 6 + s.notify_type = false + s.auto_action_type = false + s.custom_type = false + s.score_type = true + s.applies_to = %w[] +end diff --git a/db/migrate/20240527055057_add_score_type_to_flags.rb b/db/migrate/20240527055057_add_score_type_to_flags.rb new file mode 100644 index 00000000000..14942163dc3 --- /dev/null +++ b/db/migrate/20240527055057_add_score_type_to_flags.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +class AddScoreTypeToFlags < ActiveRecord::Migration[7.0] + def change + add_column(:flags, :score_type, :boolean, default: false, null: false) + end +end diff --git a/lib/guardian/flag_guardian.rb b/lib/guardian/flag_guardian.rb index 302f84b9a74..72df18ff822 100644 --- a/lib/guardian/flag_guardian.rb +++ b/lib/guardian/flag_guardian.rb @@ -4,4 +4,8 @@ module FlagGuardian def can_edit_flag?(flag) @user.admin? && !flag.system? && !flag.used? end + + def can_toggle_flag? + @user.admin? + end end diff --git a/lib/guardian/post_guardian.rb b/lib/guardian/post_guardian.rb index 809efcf74de..30eea751784 100644 --- a/lib/guardian/post_guardian.rb +++ b/lib/guardian/post_guardian.rb @@ -56,6 +56,8 @@ module PostGuardian # post made by staff, but we don't allow staff flags return false if is_flag && (!SiteSetting.allow_flagging_staff?) && post&.user&.staff? + return false if is_flag && PostActionType.disabled_flag_types.keys.include?(action_key) + if action_key == :notify_user && !@user.in_any_groups?(SiteSetting.personal_message_enabled_groups_map) # The modifier below is used to add additional permissions for notifying users. diff --git a/spec/lib/guardian/flag_guardian_spec.rb b/spec/lib/guardian/flag_guardian_spec.rb index f41e5708049..951af910582 100644 --- a/spec/lib/guardian/flag_guardian_spec.rb +++ b/spec/lib/guardian/flag_guardian_spec.rb @@ -3,13 +3,15 @@ RSpec.describe FlagGuardian do fab!(:user) fab!(:admin) + fab!(:moderator) after(:each) { Flag.reset_flag_settings! } describe "#can_edit_flag?" do - it "returns true for admin and false for regular user" do + it "returns true for admin and false for moderator and regular user" do flag = Fabricate(:flag) expect(Guardian.new(admin).can_edit_flag?(flag)).to eq(true) + expect(Guardian.new(moderator).can_edit_flag?(flag)).to eq(false) expect(Guardian.new(user).can_edit_flag?(flag)).to eq(false) flag.destroy! end @@ -32,4 +34,11 @@ RSpec.describe FlagGuardian do flag.destroy! end end + + describe "#can_toggle_flag?" do + it "returns true for admin and false for regular user" do + expect(Guardian.new(admin).can_toggle_flag?).to eq(true) + expect(Guardian.new(user).can_toggle_flag?).to eq(false) + end + end end diff --git a/spec/lib/guardian_spec.rb b/spec/lib/guardian_spec.rb index 1e580813c93..a2e82ed15d5 100644 --- a/spec/lib/guardian_spec.rb +++ b/spec/lib/guardian_spec.rb @@ -154,6 +154,15 @@ RSpec.describe Guardian do expect(Guardian.new(admin).post_can_act?(post, :notify_user)).to be_truthy end + it "returns false if flag is disabled" do + expect(Guardian.new(admin).post_can_act?(post, :spam)).to be true + Flag.where(name: "spam").update!(enabled: false) + expect(Guardian.new(admin).post_can_act?(post, :spam)).to be false + Flag.where(name: "spam").update!(enabled: true) + ensure + Flag.reset_flag_settings! + end + it "works as expected for silenced users" do UserSilencer.silence(user, admin) diff --git a/spec/requests/api/schemas/json/site_response.json b/spec/requests/api/schemas/json/site_response.json index 487955e158d..62b7deeb72a 100644 --- a/spec/requests/api/schemas/json/site_response.json +++ b/spec/requests/api/schemas/json/site_response.json @@ -353,6 +353,9 @@ }, "is_custom_flag": { "type": "boolean" + }, + "enabled": { + "type": "boolean" } }, "required": [ @@ -362,7 +365,8 @@ "description", "short_description", "is_flag", - "is_custom_flag" + "is_custom_flag", + "enabled" ] } }, @@ -393,6 +397,9 @@ }, "is_custom_flag": { "type": "boolean" + }, + "enabled": { + "type": "boolean" } }, "required": [ @@ -402,7 +409,8 @@ "description", "short_description", "is_flag", - "is_custom_flag" + "is_custom_flag", + "enabled" ] } }, diff --git a/spec/services/toggle_flag_spec.rb b/spec/services/toggle_flag_spec.rb new file mode 100644 index 00000000000..2af4c4b5a9f --- /dev/null +++ b/spec/services/toggle_flag_spec.rb @@ -0,0 +1,33 @@ +# frozen_string_literal: true + +RSpec.describe(ToggleFlag) do + subject(:result) { described_class.call(flag_id: flag.id, guardian: current_user.guardian) } + + let(:flag) { Flag.system.last } + + context "when user is not allowed to perform the action" do + fab!(:current_user) { Fabricate(:user) } + + it { is_expected.to fail_a_policy(:invalid_access) } + end + + context "when user is allowed to perform the action" do + fab!(:current_user) { Fabricate(:admin) } + + it "sets the service result as successful" do + expect(result).to be_a_success + end + + it "toggles the flag" do + expect(result[:flag].enabled).to be false + end + + it "logs the action" do + expect { result }.to change { UserHistory.count }.by(1) + expect(UserHistory.last).to have_attributes( + custom_type: "toggle_flag", + details: "flag: #{result[:flag].name}\nenabled: #{result[:flag].enabled}", + ) + end + end +end diff --git a/spec/system/admin_flags_spec.rb b/spec/system/admin_flags_spec.rb new file mode 100644 index 00000000000..fc6888725ad --- /dev/null +++ b/spec/system/admin_flags_spec.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +describe "Admin Flags Page", type: :system do + fab!(:admin) + fab!(:topic) + fab!(:post) { Fabricate(:post, topic: topic) } + + let(:topic_page) { PageObjects::Pages::Topic.new } + let(:admin_flags_page) { PageObjects::Pages::AdminFlags.new } + + before { sign_in(admin) } + + it "allows admin to disable flags" do + topic_page.visit_topic(post.topic) + topic_page.open_flag_topic_modal + expect(all(".flag-action-type-details strong").map(&:text)).to eq( + ["Something Else", "It's Inappropriate", "It's Spam", "It's Illegal"], + ) + + visit "/admin/config/flags" + admin_flags_page.toggle("spam") + + topic_page.visit_topic(post.topic) + topic_page.open_flag_topic_modal + expect(all(".flag-action-type-details strong").map(&:text)).to eq( + ["Something Else", "It's Inappropriate", "It's Illegal"], + ) + end +end diff --git a/spec/system/page_objects/pages/admin_flags.rb b/spec/system/page_objects/pages/admin_flags.rb new file mode 100644 index 00000000000..72748128918 --- /dev/null +++ b/spec/system/page_objects/pages/admin_flags.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +module PageObjects + module Pages + class AdminFlags < PageObjects::Pages::Base + def toggle(key) + PageObjects::Components::DToggleSwitch.new(".admin-flag-item__toggle.#{key}").toggle + end + end + end +end diff --git a/spec/system/page_objects/pages/topic.rb b/spec/system/page_objects/pages/topic.rb index 2aa42d909b7..36f83589942 100644 --- a/spec/system/page_objects/pages/topic.rb +++ b/spec/system/page_objects/pages/topic.rb @@ -244,6 +244,10 @@ module PageObjects find(".modal.convert-to-public-topic") end + def open_flag_topic_modal + find(".flag-topic").click + end + private def within_post(post)