FIX: limit the number of custom flags to 50 (#28221)

Admin can create up to 50 custom flags. It is limited for performance reasons.

When the limit is reached "Add button" is disabled and backend is protected by guardian.
This commit is contained in:
Krzysztof Kotlarek 2024-08-06 10:50:12 +10:00 committed by GitHub
parent 2e8273dcb4
commit fc2259d1c8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 52 additions and 3 deletions

View File

@ -4,6 +4,7 @@ import { action } from "@ember/object";
import { service } from "@ember/service"; import { service } from "@ember/service";
import { ajax } from "discourse/lib/ajax"; import { ajax } from "discourse/lib/ajax";
import { popupAjaxError } from "discourse/lib/ajax-error"; import { popupAjaxError } from "discourse/lib/ajax-error";
import { SYSTEM_FLAG_IDS } from "discourse/lib/constants";
import i18n from "discourse-common/helpers/i18n"; import i18n from "discourse-common/helpers/i18n";
import { bind } from "discourse-common/utils/decorators"; import { bind } from "discourse-common/utils/decorators";
import AdminConfigHeader from "admin/components/admin-config-header"; import AdminConfigHeader from "admin/components/admin-config-header";
@ -11,8 +12,17 @@ import AdminFlagItem from "admin/components/admin-flag-item";
export default class AdminConfigAreasFlags extends Component { export default class AdminConfigAreasFlags extends Component {
@service site; @service site;
@service siteSettings;
@tracked flags = this.site.flagTypes; @tracked flags = this.site.flagTypes;
get addFlagButtonDisabled() {
return (
this.flags.filter(
(flag) => !Object.values(SYSTEM_FLAG_IDS).includes(flag.id)
).length >= this.siteSettings.custom_flags_limit
);
}
@bind @bind
isFirstFlag(flag) { isFirstFlag(flag) {
return this.flags.indexOf(flag) === 1; return this.flags.indexOf(flag) === 1;
@ -68,6 +78,7 @@ export default class AdminConfigAreasFlags extends Component {
@primaryActionCssClass="admin-flags__header-add-flag" @primaryActionCssClass="admin-flags__header-add-flag"
@primaryActionIcon="plus" @primaryActionIcon="plus"
@primaryActionLabel="admin.config_areas.flags.add" @primaryActionLabel="admin.config_areas.flags.add"
@primaryActionDisabled={{this.addFlagButtonDisabled}}
/> />
<table class="admin-flags__items grid"> <table class="admin-flags__items grid">
<thead> <thead>

View File

@ -20,6 +20,7 @@ export default class AdminFlagItem extends Component {
"btn-icon-text" "btn-icon-text"
@primaryActionCssClass @primaryActionCssClass
}} }}
@disabled={{@primaryActionDisabled}}
> >
{{dIcon @primaryActionIcon}} {{dIcon @primaryActionIcon}}
{{i18n @primaryActionLabel}} {{i18n @primaryActionLabel}}

View File

@ -10,6 +10,7 @@ class Flag < ActiveRecord::Base
MAX_DESCRIPTION_LENGTH = 1000 MAX_DESCRIPTION_LENGTH = 1000
scope :enabled, -> { where(enabled: true) } scope :enabled, -> { where(enabled: true) }
scope :system, -> { where("id < 1000") } scope :system, -> { where("id < 1000") }
scope :custom, -> { where("id >= 1000") }
before_save :set_position before_save :set_position
before_save :set_name_key before_save :set_name_key

View File

@ -2434,6 +2434,10 @@ developer:
type: group_list type: group_list
hidden: true hidden: true
allow_any: false allow_any: false
custom_flags_limit:
default: 50
hidden: true
client: true
navigation: navigation:
navigation_menu: navigation_menu:

View File

@ -6,7 +6,7 @@ module FlagGuardian
end end
def can_create_flag? def can_create_flag?
@user.admin? @user.admin? && Flag.custom.count < SiteSetting.custom_flags_limit
end end
def can_toggle_flag? def can_toggle_flag?

View File

@ -6,6 +6,19 @@ RSpec.describe FlagGuardian do
fab!(:moderator) fab!(:moderator)
after(:each) { Flag.reset_flag_settings! } after(:each) { Flag.reset_flag_settings! }
describe "#can_create_flag?" do
it "returns true for admin and when custom flags limit is not reached" do
SiteSetting.custom_flags_limit = 1
expect(Guardian.new(admin).can_create_flag?).to eq(true)
expect(Guardian.new(user).can_create_flag?).to eq(false)
Fabricate(:flag)
expect(Guardian.new(admin).can_create_flag?).to eq(false)
expect(Guardian.new(user).can_create_flag?).to eq(false)
end
end
describe "#can_edit_flag?" do describe "#can_edit_flag?" do
it "returns true for admin and false for moderator and regular user" do it "returns true for admin and false for moderator and regular user" do

View File

@ -9,7 +9,10 @@ describe "Admin Flags Page", type: :system do
let(:admin_flag_form_page) { PageObjects::Pages::AdminFlagForm.new } let(:admin_flag_form_page) { PageObjects::Pages::AdminFlagForm.new }
let(:flag_modal) { PageObjects::Modals::Flag.new } let(:flag_modal) { PageObjects::Modals::Flag.new }
before { sign_in(admin) } before do
sign_in(admin)
SiteSetting.custom_flags_limit = 1
end
it "allows admin to disable, change order, create, update and delete flags" do it "allows admin to disable, change order, create, update and delete flags" do
# disable # disable
@ -69,7 +72,11 @@ describe "Admin Flags Page", type: :system do
"Something Else", "Something Else",
) )
admin_flags_page.visit.click_add_flag admin_flags_page.visit
expect(admin_flags_page).to have_add_flag_button_enabled
admin_flags_page.click_add_flag
admin_flag_form_page admin_flag_form_page
.fill_in_name("Vulgar") .fill_in_name("Vulgar")
.fill_in_description("New flag description") .fill_in_description("New flag description")
@ -87,6 +94,8 @@ describe "Admin Flags Page", type: :system do
"Vulgar", "Vulgar",
) )
expect(admin_flags_page).to have_add_flag_button_disabled
topic_page.visit_topic(post.topic).open_flag_topic_modal topic_page.visit_topic(post.topic).open_flag_topic_modal
expect(flag_modal).to have_choices( expect(flag_modal).to have_choices(
@ -126,6 +135,8 @@ describe "Admin Flags Page", type: :system do
expect(admin_flags_page).to have_no_flag("tasteless") expect(admin_flags_page).to have_no_flag("tasteless")
expect(admin_flags_page).to have_add_flag_button_enabled
topic_page.visit_topic(post.topic).open_flag_topic_modal topic_page.visit_topic(post.topic).open_flag_topic_modal
expect(flag_modal).to have_choices( expect(flag_modal).to have_choices(

View File

@ -47,6 +47,14 @@ module PageObjects
all(".admin-flag-item__name").map(&:text) == flags all(".admin-flag-item__name").map(&:text) == flags
end end
def has_add_flag_button_enabled?
has_css?(".admin-flags__header-add-flag:not([disabled])")
end
def has_add_flag_button_disabled?
has_no_css?(".admin-flags__header-add-flag[disabled]")
end
def has_flag?(flag) def has_flag?(flag)
has_css?(".admin-flag-item.#{flag}") has_css?(".admin-flag-item.#{flag}")
end end