discourse/spec/services/site_setting/update_spec.rb
Krzysztof Kotlarek d50bba3bdc
DEV: Allow SiteSetting::Update service to bulk update (#31438)
Previously, the SiteSetting::Update service allowed to update of a
single site setting. In the About controller, we were using the loop
through all settings -
https://github.com/discourse/discourse/blob/main/app/controllers/admin/config/about_controller.rb#L39

It is suboptimal because if the 3 first settings are saved and the
fourth is invalid, we will end with partially updated data.

Changing SiteSetting::Update to accept hash means that we will check
upfront if none of the settings are hidden or invalid and update all or
none.

Custom policies are used to report which settings are failing.
2025-02-24 11:09:44 +11:00

99 lines
3 KiB
Ruby
Vendored

# frozen_string_literal: true
RSpec.describe SiteSetting::Update do
describe described_class::Contract, type: :model do
it { is_expected.to validate_presence_of :settings }
end
describe ".call" do
subject(:result) { described_class.call(params:, options:, **dependencies) }
fab!(:admin)
let(:params) { { settings: } }
let(:settings) { { setting_name => new_value } }
let(:options) { { allow_changing_hidden: } }
let(:dependencies) { { guardian: } }
let(:setting_name) { :title }
let(:new_value) { "blah whatever" }
let(:guardian) { admin.guardian }
let(:allow_changing_hidden) { [] }
context "when settings is blank" do
let(:settings) { nil }
it { is_expected.to fail_a_contract }
end
context "when a non-admin user tries to change a setting" do
let(:guardian) { Guardian.new }
it { is_expected.to fail_a_policy(:current_user_is_admin) }
end
context "when the user changes a hidden setting" do
let(:setting_name) { :max_category_nesting }
let(:new_value) { 3 }
context "when allow_changing_hidden is empty array" do
it { is_expected.to fail_a_policy(:settings_are_visible) }
end
context "when allow_changing_hidden is including setting" do
let(:allow_changing_hidden) { [:max_category_nesting] }
it { is_expected.to run_successfully }
it "updates the specified setting" do
expect { result }.to change { SiteSetting.max_category_nesting }.to(3)
end
end
end
context "when a user changes a setting shadowed by a global variable" do
let(:setting_name) { :max_category_nesting }
let(:new_value) { 3 }
before { SiteSetting.stubs(:shadowed_settings).returns(Set.new([:max_category_nesting])) }
it { is_expected.to fail_a_policy(:settings_are_unshadowed_globally) }
end
context "when the user changes a visible setting" do
let(:new_value) { "hello this is title" }
it { is_expected.to run_successfully }
it "updates the specified setting" do
expect { result }.to change { SiteSetting.title }.to(new_value)
end
it "creates an entry in the staff action logs" do
expect { result }.to change {
UserHistory.where(
action: UserHistory.actions[:change_site_setting],
subject: "title",
).count
}.by(1)
end
context "when value needs cleanup" do
let(:setting_name) { :max_image_size_kb }
let(:new_value) { "8zf843" }
it "cleans up the new setting value before using it" do
expect { result }.to change { SiteSetting.max_image_size_kb }.to(8843)
end
end
end
context "when one setting is having invalid value" do
let(:settings) { { title: "hello this is title", default_categories_watching: "999999" } }
it { is_expected.to fail_a_policy(:values_are_valid) }
it "does not update valid setting" do
expect { result }.not_to change { SiteSetting.title }
end
end
end
end