diff --git a/plugins/discourse-narrative-bot/lib/discourse_narrative_bot/advanced_user_narrative.rb b/plugins/discourse-narrative-bot/lib/discourse_narrative_bot/advanced_user_narrative.rb index 65012aa2885..3765ed35b45 100644 --- a/plugins/discourse-narrative-bot/lib/discourse_narrative_bot/advanced_user_narrative.rb +++ b/plugins/discourse-narrative-bot/lib/discourse_narrative_bot/advanced_user_narrative.rb @@ -78,7 +78,7 @@ module DiscourseNarrativeBot prerequisite: Proc.new do SiteSetting.poll_enabled && - @user.has_trust_level?(SiteSetting.poll_minimum_trust_level_to_create) + @user.in_any_groups?(SiteSetting.poll_create_allowed_groups_map) end, next_state: :tutorial_details, next_instructions: Proc.new { I18n.t("#{I18N_KEY}.details.instructions", i18n_post_args) }, diff --git a/plugins/discourse-narrative-bot/spec/discourse_narrative_bot/advanced_user_narrative_spec.rb b/plugins/discourse-narrative-bot/spec/discourse_narrative_bot/advanced_user_narrative_spec.rb index 627242bcd58..8cc60bdd98e 100644 --- a/plugins/discourse-narrative-bot/spec/discourse_narrative_bot/advanced_user_narrative_spec.rb +++ b/plugins/discourse-narrative-bot/spec/discourse_narrative_bot/advanced_user_narrative_spec.rb @@ -29,6 +29,7 @@ RSpec.describe DiscourseNarrativeBot::AdvancedUserNarrative do stub_image_size Jobs.run_immediately! SiteSetting.discourse_narrative_bot_enabled = true + Group.refresh_automatic_groups! end describe "#notify_timeout" do @@ -620,7 +621,7 @@ RSpec.describe DiscourseNarrativeBot::AdvancedUserNarrative do end it "should create the right reply (insufficient trust level)" do - user.update(trust_level: 0) + user.change_trust_level!(TrustLevel[0]) TopicUser.change( user.id, diff --git a/plugins/poll/assets/javascripts/discourse/initializers/add-poll-ui-builder.js b/plugins/poll/assets/javascripts/discourse/initializers/add-poll-ui-builder.js index f87c15827f8..31d05413644 100644 --- a/plugins/poll/assets/javascripts/discourse/initializers/add-poll-ui-builder.js +++ b/plugins/poll/assets/javascripts/discourse/initializers/add-poll-ui-builder.js @@ -17,10 +17,7 @@ function initializePollUIBuilder(api) { return ( siteSettings.poll_enabled && (composer.model.topic?.pm_with_non_human_user || - (currentUser && - (currentUser.staff || - currentUser.trust_level >= - siteSettings.poll_minimum_trust_level_to_create))) + (currentUser && (currentUser.staff || currentUser.can_create_poll))) ); }, }); diff --git a/plugins/poll/config/locales/server.en.yml b/plugins/poll/config/locales/server.en.yml index b9a2202930a..3510c3025de 100644 --- a/plugins/poll/config/locales/server.en.yml +++ b/plugins/poll/config/locales/server.en.yml @@ -4,9 +4,12 @@ en: poll_maximum_options: "Maximum number of options allowed in a poll." poll_edit_window_mins: "Number of minutes after post creation during which polls can be edited." poll_minimum_trust_level_to_create: "Define the minimum trust level needed to create polls." + poll_create_allowed_groups: "The groups that are allowed to create polls." poll_groupable_user_fields: "A set of user field names that can be used to group and filter poll results." poll_export_data_explorer_query_id: "ID of the Data Explorer Query to use for exporting poll results (0 to disable)." poll_default_public: "When creating a new poll, enable the 'show who voted' option by default." + keywords: + poll_create_allowed_groups: "poll_minimum_trust_level_to_create" poll: poll: "poll" diff --git a/plugins/poll/config/settings.yml b/plugins/poll/config/settings.yml index 124c3ca143a..b812e7eceb7 100644 --- a/plugins/poll/config/settings.yml +++ b/plugins/poll/config/settings.yml @@ -14,6 +14,14 @@ plugins: default: 1 client: true enum: "TrustLevelSetting" + hidden: true + poll_create_allowed_groups: + default: "11" # auto group trust_level_1 + type: group_list + client: false + allow_any: false + refresh: true + validator: "AtLeastOneGroupValidator" poll_groupable_user_fields: default: "" type: list diff --git a/plugins/poll/db/post_migrate/20240122015626_fill_poll_create_allowed_groups_based_on_deprecated_setting.rb b/plugins/poll/db/post_migrate/20240122015626_fill_poll_create_allowed_groups_based_on_deprecated_setting.rb new file mode 100644 index 00000000000..d9cb6822992 --- /dev/null +++ b/plugins/poll/db/post_migrate/20240122015626_fill_poll_create_allowed_groups_based_on_deprecated_setting.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true + +class FillPollCreateAllowedGroupsBasedOnDeprecatedSetting < ActiveRecord::Migration[7.0] + def up + old_setting_trust_level = + DB.query_single( + "SELECT value FROM site_settings WHERE name = 'poll_minimum_trust_level_to_create' LIMIT 1", + ).first + + if old_setting_trust_level.present? + allowed_groups = "1#{old_setting_trust_level}" + + DB.exec( + "INSERT INTO site_settings(name, value, data_type, created_at, updated_at) + VALUES('poll_create_allowed_groups', :setting, '20', NOW(), NOW())", + setting: allowed_groups, + ) + end + end + + def down + raise ActiveRecord::IrreversibleMigration + end +end diff --git a/plugins/poll/lib/post_validator.rb b/plugins/poll/lib/post_validator.rb index db3b52b5f0f..2b57fa1a54c 100644 --- a/plugins/poll/lib/post_validator.rb +++ b/plugins/poll/lib/post_validator.rb @@ -7,13 +7,11 @@ module DiscoursePoll end def validate_post - min_trust_level = SiteSetting.poll_minimum_trust_level_to_create - if ( @post.acting_user && ( @post.acting_user.staff? || - @post.acting_user.trust_level >= TrustLevel[min_trust_level] + @post.acting_user.in_any_groups?(SiteSetting.poll_create_allowed_groups_map) ) ) || @post.topic&.pm_with_non_human_user? true diff --git a/plugins/poll/plugin.rb b/plugins/poll/plugin.rb index f79ab268934..4cb1dfa0b40 100644 --- a/plugins/poll/plugin.rb +++ b/plugins/poll/plugin.rb @@ -206,6 +206,10 @@ after_initialize do end end + add_to_serializer(:current_user, :can_create_poll) do + scope.user&.staff? || scope.user&.in_any_groups?(SiteSetting.poll_create_allowed_groups_map) + end + add_to_class(PostSerializer, :preloaded_polls) do @preloaded_polls ||= if @topic_view.present? diff --git a/plugins/poll/spec/controllers/polls_controller_spec.rb b/plugins/poll/spec/controllers/polls_controller_spec.rb index 7e8f813ccc4..d60938fe31d 100644 --- a/plugins/poll/spec/controllers/polls_controller_spec.rb +++ b/plugins/poll/spec/controllers/polls_controller_spec.rb @@ -33,6 +33,8 @@ RSpec.describe ::DiscoursePoll::PollsController do ) end + before { Group.refresh_automatic_groups! } + describe "#vote" do it "works" do channel = "/polls/#{poll.topic_id}" diff --git a/plugins/poll/spec/controllers/posts_controller_spec.rb b/plugins/poll/spec/controllers/posts_controller_spec.rb index 4dd8a4d1995..2f6da9f31d6 100644 --- a/plugins/poll/spec/controllers/posts_controller_spec.rb +++ b/plugins/poll/spec/controllers/posts_controller_spec.rb @@ -376,7 +376,7 @@ RSpec.describe PostsController do end describe "regular user with insufficient trust level" do - before { SiteSetting.poll_minimum_trust_level_to_create = 2 } + before { SiteSetting.poll_create_allowed_groups = Group::AUTO_GROUPS[:trust_level_2] } it "invalidates the post" do log_in_user(Fabricate(:user, trust_level: 1, refresh_auto_groups: true)) @@ -409,7 +409,7 @@ RSpec.describe PostsController do end describe "regular user with equal trust level" do - before { SiteSetting.poll_minimum_trust_level_to_create = 2 } + before { SiteSetting.poll_create_allowed_groups = Group::AUTO_GROUPS[:trust_level_2] } it "validates the post" do log_in_user(Fabricate(:user, trust_level: 2, refresh_auto_groups: true)) @@ -424,7 +424,7 @@ RSpec.describe PostsController do end describe "regular user with superior trust level" do - before { SiteSetting.poll_minimum_trust_level_to_create = 2 } + before { SiteSetting.poll_create_allowed_groups = Group::AUTO_GROUPS[:trust_level_2] } it "validates the post" do log_in_user(Fabricate(:user, trust_level: 3, refresh_auto_groups: true)) @@ -439,7 +439,7 @@ RSpec.describe PostsController do end describe "staff with insufficient trust level" do - before { SiteSetting.poll_minimum_trust_level_to_create = 2 } + before { SiteSetting.poll_create_allowed_groups = Group::AUTO_GROUPS[:trust_level_2] } it "validates the post" do log_in_user(Fabricate(:user, moderator: true, trust_level: 1)) @@ -454,7 +454,7 @@ RSpec.describe PostsController do end describe "staff editing posts of users with insufficient trust level" do - before { SiteSetting.poll_minimum_trust_level_to_create = 2 } + before { SiteSetting.poll_create_allowed_groups = Group::AUTO_GROUPS[:trust_level_2] } it "validates the post" do log_in_user(Fabricate(:user, trust_level: 1, refresh_auto_groups: true)) diff --git a/plugins/poll/spec/lib/new_post_manager_spec.rb b/plugins/poll/spec/lib/new_post_manager_spec.rb index fcaedfa9d7d..cc9370bcff2 100644 --- a/plugins/poll/spec/lib/new_post_manager_spec.rb +++ b/plugins/poll/spec/lib/new_post_manager_spec.rb @@ -7,7 +7,7 @@ RSpec.describe NewPostManager do let(:admin) { Fabricate(:admin, refresh_auto_groups: true) } describe "when new post containing a poll is queued for approval" do - before { SiteSetting.poll_minimum_trust_level_to_create = 0 } + before { SiteSetting.poll_create_allowed_groups = Group::AUTO_GROUPS[:trust_level_0] } let(:params) do { diff --git a/plugins/poll/spec/lib/poll_spec.rb b/plugins/poll/spec/lib/poll_spec.rb index f3ecd836766..4b15ea2060a 100644 --- a/plugins/poll/spec/lib/poll_spec.rb +++ b/plugins/poll/spec/lib/poll_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true RSpec.describe DiscoursePoll::Poll do - fab!(:user) + fab!(:user) { Fabricate(:user, refresh_auto_groups: true) } fab!(:user_2) { Fabricate(:user) } fab!(:post_with_regular_poll) { Fabricate(:post, raw: <<~RAW) } diff --git a/plugins/poll/spec/models/poll_spec.rb b/plugins/poll/spec/models/poll_spec.rb index 2afc37cc59c..b71599327a6 100644 --- a/plugins/poll/spec/models/poll_spec.rb +++ b/plugins/poll/spec/models/poll_spec.rb @@ -38,7 +38,7 @@ RSpec.describe ::DiscoursePoll::Poll do end it "author can see results when results setting is on_vote" do - author = Fabricate(:user) + author = Fabricate(:user, refresh_auto_groups: true) post = Fabricate(:post, user: author, raw: "[poll results=on_vote]\n- A\n- B\n[/poll]") poll = post.polls.first option = poll.poll_options.first @@ -60,7 +60,7 @@ RSpec.describe ::DiscoursePoll::Poll do it "only staff members can see results when results setting is staff_only" do post = Fabricate(:post, raw: "[poll results=staff_only]\n- A\n- B\n[/poll]") - user = Fabricate(:user) + user = Fabricate(:user, refresh_auto_groups: true) poll = post.polls.first option = poll.poll_options.first @@ -74,7 +74,7 @@ RSpec.describe ::DiscoursePoll::Poll do describe "when post is trashed" do it "maintains the association" do - user = Fabricate(:user) + user = Fabricate(:user, refresh_auto_groups: true) post = Fabricate(:post, raw: "[poll results=staff_only]\n- A\n- B\n[/poll]", user: user) poll = post.polls.first diff --git a/plugins/poll/test/javascripts/acceptance/poll-builder-disabled-test.js b/plugins/poll/test/javascripts/acceptance/poll-builder-disabled-test.js index 99e212ce3b2..4e75044a2bf 100644 --- a/plugins/poll/test/javascripts/acceptance/poll-builder-disabled-test.js +++ b/plugins/poll/test/javascripts/acceptance/poll-builder-disabled-test.js @@ -1,4 +1,5 @@ import { test } from "qunit"; +import { AUTO_GROUPS } from "discourse/lib/constants"; import { acceptance, exists, @@ -10,11 +11,16 @@ acceptance("Poll Builder - polls are disabled", function (needs) { needs.user(); needs.settings({ poll_enabled: false, - poll_minimum_trust_level_to_create: 2, + poll_create_allowed_groups: AUTO_GROUPS.trust_level_2, }); - test("regular user - sufficient trust level", async function (assert) { - updateCurrentUser({ moderator: false, admin: false, trust_level: 3 }); + test("regular user - sufficient permissions", async function (assert) { + updateCurrentUser({ + moderator: false, + admin: false, + trust_level: 3, + can_create_poll: true, + }); await displayPollBuilderButton(); @@ -24,8 +30,13 @@ acceptance("Poll Builder - polls are disabled", function (needs) { ); }); - test("regular user - insufficient trust level", async function (assert) { - updateCurrentUser({ moderator: false, admin: false, trust_level: 1 }); + test("regular user - insufficient permissions", async function (assert) { + updateCurrentUser({ + moderator: false, + admin: false, + trust_level: 1, + can_create_poll: false, + }); await displayPollBuilderButton(); diff --git a/plugins/poll/test/javascripts/acceptance/poll-builder-enabled-test.js b/plugins/poll/test/javascripts/acceptance/poll-builder-enabled-test.js index 66361884fe7..31955617946 100644 --- a/plugins/poll/test/javascripts/acceptance/poll-builder-enabled-test.js +++ b/plugins/poll/test/javascripts/acceptance/poll-builder-enabled-test.js @@ -1,5 +1,6 @@ import { click } from "@ember/test-helpers"; import { test } from "qunit"; +import { AUTO_GROUPS } from "discourse/lib/constants"; import { acceptance, exists, @@ -12,11 +13,16 @@ acceptance("Poll Builder - polls are enabled", function (needs) { needs.user(); needs.settings({ poll_enabled: true, - poll_minimum_trust_level_to_create: 1, + poll_create_allowed_groups: AUTO_GROUPS.trust_level_1, }); test("regular user - sufficient trust level", async function (assert) { - updateCurrentUser({ moderator: false, admin: false, trust_level: 1 }); + updateCurrentUser({ + moderator: false, + admin: false, + trust_level: 1, + can_create_poll: true, + }); await displayPollBuilderButton(); @@ -49,7 +55,12 @@ acceptance("Poll Builder - polls are enabled", function (needs) { }); test("regular user - insufficient trust level", async function (assert) { - updateCurrentUser({ moderator: false, admin: false, trust_level: 0 }); + updateCurrentUser({ + moderator: false, + admin: false, + trust_level: 0, + can_create_poll: false, + }); await displayPollBuilderButton(); diff --git a/plugins/styleguide/app/controllers/styleguide/styleguide_controller.rb b/plugins/styleguide/app/controllers/styleguide/styleguide_controller.rb index ebdab9b8f1c..48acab9e0ea 100644 --- a/plugins/styleguide/app/controllers/styleguide/styleguide_controller.rb +++ b/plugins/styleguide/app/controllers/styleguide/styleguide_controller.rb @@ -6,7 +6,9 @@ module Styleguide skip_before_action :check_xhr def index - ensure_admin if SiteSetting.styleguide_admin_only + if !current_user || !current_user.in_any_groups?(SiteSetting.styleguide_allowed_groups_map) + raise Discourse::InvalidAccess.new + end render "default/empty" end diff --git a/plugins/styleguide/config/locales/server.en.yml b/plugins/styleguide/config/locales/server.en.yml index 09e4e2e5c28..92d1d6635e2 100644 --- a/plugins/styleguide/config/locales/server.en.yml +++ b/plugins/styleguide/config/locales/server.en.yml @@ -2,3 +2,4 @@ en: site_settings: styleguide_enabled: 'Enable a "/styleguide" path to aid in styling of Discourse' styleguide_admin_only: "Limits visibility of the styleguide to admins" + styleguide_allowed_groups: "Limits visibility of the styleguide to members of the provided groups" diff --git a/plugins/styleguide/config/settings.yml b/plugins/styleguide/config/settings.yml index ee937dd3a51..6e2bc65e59f 100644 --- a/plugins/styleguide/config/settings.yml +++ b/plugins/styleguide/config/settings.yml @@ -3,3 +3,11 @@ plugins: default: false styleguide_admin_only: default: true + hidden: true + styleguide_allowed_groups: + default: "1" # auto group admins + type: group_list + client: false + allow_any: false + refresh: true + validator: "AtLeastOneGroupValidator" diff --git a/plugins/styleguide/db/post_migrate/20240122015630_fill_styleguide_admin_only_groups.rb b/plugins/styleguide/db/post_migrate/20240122015630_fill_styleguide_admin_only_groups.rb new file mode 100644 index 00000000000..b4f54ee824f --- /dev/null +++ b/plugins/styleguide/db/post_migrate/20240122015630_fill_styleguide_admin_only_groups.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true + +class FillStyleguideAdminOnlyGroups < ActiveRecord::Migration[7.0] + def up + old_setting = + DB.query_single( + "SELECT value FROM site_settings WHERE name = 'styleguide_admin_only' LIMIT 1", + ).first + + if old_setting.present? + allowed_groups = old_setting == "t" ? "1" : "14" # use admins AUTO_GROUP if true, otherwise default to TL4 + + DB.exec( + "INSERT INTO site_settings(name, value, data_type, created_at, updated_at) + VALUES('styleguide_allowed_groups', :setting, '20', NOW(), NOW())", + setting: allowed_groups, + ) + end + end + + def down + raise ActiveRecord::IrreversibleMigration + end +end diff --git a/plugins/styleguide/spec/integration/access_spec.rb b/plugins/styleguide/spec/integration/access_spec.rb index 96e5a36c399..5119c710785 100644 --- a/plugins/styleguide/spec/integration/access_spec.rb +++ b/plugins/styleguide/spec/integration/access_spec.rb @@ -1,10 +1,10 @@ # frozen_string_literal: true -RSpec.describe "SiteSetting.styleguide_admin_only" do +RSpec.describe "SiteSetting.styleguide_allowed_groups" do before { SiteSetting.styleguide_enabled = true } context "when styleguide is admin only" do - before { SiteSetting.styleguide_admin_only = true } + before { SiteSetting.styleguide_allowed_groups = Group::AUTO_GROUPS[:admins] } context "when user is admin" do before { sign_in(Fabricate(:admin)) }