mirror of
https://gh.wpcy.net/https://github.com/discourse/discourse.git
synced 2026-05-04 17:02:35 +08:00
When a site setting has `depends_behavior: hidden`, it is shown or hidden based on whether its parent setting is enabled. Until now that decision was made on the server, so toggling the parent in the admin UI required saving and reloading the page for dependent settings to appear or disappear. The server no longer excludes hidden-by-dependency settings from the `/admin/site_settings` payload; it just serializes `depends_behavior` alongside `depends_on` and lets the client decide. A new `site-setting-store` service tracks every loaded setting by name and exposes `isSettingVisible(setting, activeFilter)`, the single source of truth for the following rule: - On first load, children of a disabled parent are not rendered. - Enabling the parent (checkbox or reset-to-default) reveals them reactively; a `revealed` latch on the model keeps them visible for the rest of the session. - Disabling the parent again after reveal leaves the children mounted and switches them to a disabled state (no re-hide jank). - Searching by exact setting name still surfaces an unrevealed child (in a disabled state), so deep links like `?filter=topic_voting_tl0_vote_limit` work even when the parent is off. Visibility is enforced at the iteration layer (category controller and `admin-filtered-site-settings`) using the shared helper, so the filter recomputes whenever `revealed` flips on a tracked `SiteSetting`. Ref - t/181881 --------- Co-authored-by: Martin Brennan <martin@discourse.org>
2076 lines
66 KiB
Ruby
2076 lines
66 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
RSpec.describe SiteSettingExtension do
|
|
# We disable message bus here to avoid a large amount
|
|
# of unneeded messaging, tests are careful to call refresh
|
|
# when they need to.
|
|
#
|
|
# DistributedCache used by locale handler can under certain
|
|
# cases take a tiny bit to stabilize.
|
|
#
|
|
# TODO: refactor SiteSettingExtension not to rely on statics in
|
|
# DefaultsProvider
|
|
#
|
|
before { MessageBus.off }
|
|
|
|
after { MessageBus.on }
|
|
|
|
describe "#types" do
|
|
context "when verifying enum sequence" do
|
|
before { @types = SiteSetting.types }
|
|
|
|
it "'string' should be at 1st position" do
|
|
expect(@types[:string]).to eq(1)
|
|
end
|
|
|
|
it "'value_list' should be at 12th position" do
|
|
expect(@types[:value_list]).to eq(12)
|
|
end
|
|
end
|
|
end
|
|
|
|
let :provider_local do
|
|
SiteSettings::LocalProcessProvider.new
|
|
end
|
|
|
|
let :settings do
|
|
new_settings(provider_local)
|
|
end
|
|
|
|
let :settings2 do
|
|
new_settings(provider_local)
|
|
end
|
|
|
|
it "does not leak state cause changes are not linked" do
|
|
t1 =
|
|
Thread.new do
|
|
5.times do
|
|
settings = new_settings(SiteSettings::LocalProcessProvider.new)
|
|
settings.setting(:title, "test")
|
|
settings.title = "title1"
|
|
expect(settings.title).to eq "title1"
|
|
end
|
|
end
|
|
|
|
t2 =
|
|
Thread.new do
|
|
5.times do
|
|
settings = new_settings(SiteSettings::LocalProcessProvider.new)
|
|
settings.setting(:title, "test")
|
|
settings.title = "title2"
|
|
expect(settings.title).to eq "title2"
|
|
end
|
|
end
|
|
|
|
t1.join
|
|
t2.join
|
|
end
|
|
|
|
describe ".refresh!" do
|
|
it "ensures that the right MessageBus subscription has been set up" do
|
|
settings.expects(:ensure_listen_for_changes).once
|
|
settings.refresh!
|
|
end
|
|
|
|
it "will reset to default if provider vanishes" do
|
|
settings.setting(:hello, 1)
|
|
settings.hello = 100
|
|
expect(settings.hello).to eq(100)
|
|
|
|
settings.provider.clear
|
|
settings.refresh!
|
|
|
|
expect(settings.hello).to eq(1)
|
|
end
|
|
|
|
it "will set to new value if provider changes" do
|
|
settings.setting(:hello, 1)
|
|
settings.hello = 100
|
|
expect(settings.hello).to eq(100)
|
|
|
|
settings.provider.save(:hello, 99, SiteSetting.types[:integer])
|
|
settings.refresh!
|
|
|
|
expect(settings.hello).to eq(99)
|
|
end
|
|
|
|
it "picks up changes from provider on refresh across processes" do
|
|
settings.setting(:hello, 1)
|
|
settings2.setting(:hello, 1)
|
|
|
|
settings.hello = 100
|
|
|
|
settings2.refresh!
|
|
expect(settings2.hello).to eq(100)
|
|
|
|
settings.hello = 99
|
|
|
|
settings2.refresh!
|
|
expect(settings2.hello).to eq(99)
|
|
end
|
|
|
|
it "does not override types in the type supervisor" do
|
|
settings.setting(:foo, "bar")
|
|
settings.provider.save(:foo, "bar", SiteSetting.types[:enum])
|
|
settings.refresh!
|
|
expect(settings.foo).to eq("bar")
|
|
|
|
settings.foo = "baz"
|
|
expect(settings.foo).to eq("baz")
|
|
end
|
|
|
|
it "clears the cache for site setting uploads" do
|
|
settings.setting(:upload_type, "", type: :upload)
|
|
upload = Fabricate(:upload)
|
|
settings.upload_type = upload
|
|
|
|
expect(settings.upload_type).to eq(upload)
|
|
expect(settings.send(:uploads)[:upload_type]).to eq(upload)
|
|
|
|
upload2 = Fabricate(:upload)
|
|
settings.provider.save(:upload_type, upload2.id, SiteSetting.types[:upload])
|
|
|
|
expect do settings.refresh! end.to change { settings.send(:uploads)[:upload_type] }.from(
|
|
upload,
|
|
).to(nil)
|
|
|
|
expect(settings.upload_type).to eq(upload2)
|
|
end
|
|
|
|
it "refreshes the client_settings_json cache" do
|
|
upload = Fabricate(:upload)
|
|
settings.setting(:upload_type, upload.id.to_s, type: :upload, client: true)
|
|
settings.setting(:string_type, "haha", client: true)
|
|
settings.refresh!
|
|
|
|
expect(settings.client_settings_json).to eq(
|
|
%Q|{"default_locale":"#{SiteSetting.default_locale}","upload_type":"#{upload.url}","string_type":"haha"}|,
|
|
)
|
|
|
|
upload.update!(url: "a_new_url")
|
|
settings.string_type = "changed"
|
|
settings.refresh!
|
|
|
|
expect(settings.client_settings_json).to eq(
|
|
%Q|{"default_locale":"#{SiteSetting.default_locale}","upload_type":"a_new_url","string_type":"changed"}|,
|
|
)
|
|
end
|
|
|
|
context "when the provider value equals the YAML default" do
|
|
it "does not mark a normal setting as modified from default" do
|
|
settings.setting(:hello, 1)
|
|
settings.provider.save(:hello, 1, SiteSetting.types[:integer])
|
|
settings.refresh!
|
|
|
|
expect(settings.setting_modified_from_default?(:hello)).to eq(false)
|
|
end
|
|
|
|
it "still marks an upcoming change setting as modified from default so admins can opt out" do
|
|
settings.setting(
|
|
:upcoming_change_opt_out_flag,
|
|
false,
|
|
upcoming_change: {
|
|
status: :experimental,
|
|
impact: "feature,staff",
|
|
},
|
|
)
|
|
UpcomingChanges.stubs(:settings_provider).returns(settings)
|
|
|
|
settings.provider.save(:upcoming_change_opt_out_flag, false, SiteSetting.types[:bool])
|
|
settings.refresh!
|
|
|
|
expect(settings.setting_modified_from_default?(:upcoming_change_opt_out_flag)).to eq(true)
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "DiscourseEvent" do
|
|
before do
|
|
settings.setting(:test_setting, 1)
|
|
settings.refresh!
|
|
end
|
|
|
|
it "triggers events correctly" do
|
|
settings.setting(:test_setting, 1)
|
|
settings.refresh!
|
|
|
|
override_events = DiscourseEvent.track_events { settings.test_setting = 2 }
|
|
no_change_events = DiscourseEvent.track_events { settings.test_setting = 2 }
|
|
default_events = DiscourseEvent.track_events { settings.test_setting = 1 }
|
|
|
|
expect(override_events.map { |e| e[:event_name] }).to contain_exactly(:site_setting_changed)
|
|
expect(no_change_events.map { |e| e[:event_name] }).to be_empty
|
|
expect(default_events.map { |e| e[:event_name] }).to contain_exactly(:site_setting_changed)
|
|
|
|
changed_event_1 = override_events.find { |e| e[:event_name] == :site_setting_changed }
|
|
changed_event_2 = default_events.find { |e| e[:event_name] == :site_setting_changed }
|
|
|
|
expect(changed_event_1[:params]).to eq([:test_setting, 1, 2])
|
|
expect(changed_event_2[:params]).to eq([:test_setting, 2, 1])
|
|
end
|
|
end
|
|
|
|
describe "int setting" do
|
|
before do
|
|
settings.setting(:test_setting, 77)
|
|
settings.refresh!
|
|
end
|
|
|
|
it "should have a key in all_settings" do
|
|
expect(settings.all_settings.detect { |s| s[:setting] == :test_setting }).to be_present
|
|
end
|
|
|
|
it "should have the correct desc" do
|
|
I18n.backend.store_translations(
|
|
:en,
|
|
site_settings: {
|
|
test_setting: "test description <a href='%{base_path}/admin'>/admin</a>",
|
|
},
|
|
)
|
|
expect(settings.description(:test_setting)).to eq(
|
|
"test description <a href='/admin'>/admin</a>",
|
|
)
|
|
|
|
Discourse.stubs(:base_path).returns("/forum")
|
|
expect(settings.description(:test_setting)).to eq(
|
|
"test description <a href='/forum/admin'>/admin</a>",
|
|
)
|
|
end
|
|
|
|
it "should have the correct default" do
|
|
expect(settings.test_setting).to eq(77)
|
|
end
|
|
|
|
context "when overridden" do
|
|
after :each do
|
|
settings.remove_override!(:test_setting)
|
|
end
|
|
|
|
it "should have the correct override" do
|
|
settings.test_setting = 100
|
|
expect(settings.test_setting).to eq(100)
|
|
end
|
|
|
|
it "should coerce correct string to int" do
|
|
settings.test_setting = "101"
|
|
expect(settings.test_setting).to eq(101)
|
|
end
|
|
|
|
it "should coerce incorrect string to 0" do
|
|
settings.test_setting = "pie"
|
|
expect(settings.test_setting).to eq(0)
|
|
end
|
|
|
|
it "should not set default when reset" do
|
|
settings.test_setting = 100
|
|
settings.setting(:test_setting, 77)
|
|
settings.refresh!
|
|
expect(settings.test_setting).not_to eq(77)
|
|
end
|
|
|
|
it "can be overridden with set" do
|
|
settings.set("test_setting", 12)
|
|
expect(settings.test_setting).to eq(12)
|
|
end
|
|
|
|
it "should publish changes to clients" do
|
|
settings.setting("test_setting", 100)
|
|
settings.setting("test_setting", nil, client: true)
|
|
|
|
message = MessageBus.track_publish("/client_settings") { settings.test_setting = 88 }.first
|
|
|
|
expect(message).to be_present
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "remove_override" do
|
|
fab!(:upload)
|
|
|
|
before do
|
|
settings.setting(:test_override, "test")
|
|
settings.setting(:image_list_test, "", type: :uploaded_image_list)
|
|
settings.refresh!
|
|
end
|
|
it "correctly nukes overrides" do
|
|
settings.test_override = "bla"
|
|
settings.remove_override!(:test_override)
|
|
expect(settings.test_override).to eq("test")
|
|
end
|
|
|
|
it "correctly nukes overrides for image list type setting" do
|
|
settings.image_list_test = "#{upload.id}"
|
|
settings.remove_override!(:image_list_test)
|
|
expect(settings.image_list_test).to be_empty
|
|
end
|
|
end
|
|
|
|
describe "string setting" do
|
|
before do
|
|
settings.setting(:test_str, "str")
|
|
settings.refresh!
|
|
end
|
|
|
|
it "should have the correct default" do
|
|
expect(settings.test_str).to eq("str")
|
|
end
|
|
|
|
context "when overridden" do
|
|
after :each do
|
|
settings.remove_override!(:test_str)
|
|
end
|
|
|
|
it "should coerce int to string" do
|
|
settings.test_str = 100
|
|
expect(settings.test_str).to eq("100")
|
|
end
|
|
|
|
it "can be overridden with set" do
|
|
settings.set("test_str", "hi")
|
|
expect(settings.test_str).to eq("hi")
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "string setting with regex" do
|
|
it "Supports custom validation errors" do
|
|
I18n.backend.store_translations(:en, { oops: "oops" })
|
|
|
|
settings.setting(:test_str, "bob", regex: "hi", regex_error: "oops")
|
|
settings.refresh!
|
|
|
|
begin
|
|
settings.test_str = "a"
|
|
rescue Discourse::InvalidParameters => e
|
|
message = e.message
|
|
end
|
|
|
|
expect(message).to match(/oops/)
|
|
end
|
|
end
|
|
|
|
describe "bool setting" do
|
|
before do
|
|
settings.setting(:test_hello?, false)
|
|
settings.refresh!
|
|
end
|
|
|
|
it "should have the correct default" do
|
|
expect(settings.test_hello?).to eq(false)
|
|
end
|
|
|
|
context "when overridden" do
|
|
after { settings.remove_override!(:test_hello?) }
|
|
|
|
it "should have the correct override" do
|
|
settings.test_hello = true
|
|
expect(settings.test_hello?).to eq(true)
|
|
end
|
|
|
|
it "should coerce true strings to true" do
|
|
settings.test_hello = "true"
|
|
expect(settings.test_hello?).to be(true)
|
|
end
|
|
|
|
it "should coerce all other strings to false" do
|
|
settings.test_hello = "f"
|
|
expect(settings.test_hello?).to be(false)
|
|
end
|
|
|
|
it "should not set default when reset" do
|
|
settings.test_hello = true
|
|
settings.setting(:test_hello?, false)
|
|
settings.refresh!
|
|
expect(settings.test_hello?).not_to eq(false)
|
|
end
|
|
|
|
it "can be overridden with set" do
|
|
settings.set("test_hello", true)
|
|
expect(settings.test_hello?).to eq(true)
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "int enum" do
|
|
class TestIntEnumClass
|
|
def self.valid_value?(v)
|
|
true
|
|
end
|
|
|
|
def self.values
|
|
[1, 2, 3]
|
|
end
|
|
end
|
|
|
|
it "should coerce correctly" do
|
|
settings.setting(:test_int_enum, 1, enum: TestIntEnumClass)
|
|
settings.test_int_enum = "2"
|
|
settings.refresh!
|
|
expect(settings.defaults[:test_int_enum]).to eq(1)
|
|
expect(settings.test_int_enum).to eq(2)
|
|
end
|
|
end
|
|
|
|
describe "enum setting" do
|
|
class TestEnumClass
|
|
def self.valid_value?(v)
|
|
self.values.include?(v)
|
|
end
|
|
|
|
def self.values
|
|
["en"]
|
|
end
|
|
|
|
def self.translate_names?
|
|
false
|
|
end
|
|
end
|
|
|
|
let(:test_enum_class) { TestEnumClass }
|
|
|
|
before do
|
|
settings.setting(:test_enum, "en", enum: test_enum_class)
|
|
settings.refresh!
|
|
end
|
|
|
|
it "should have the correct default" do
|
|
expect(settings.test_enum).to eq("en")
|
|
end
|
|
|
|
it "should not hose all_settings" do
|
|
expect(settings.all_settings.detect { |s| s[:setting] == :test_enum }).to be_present
|
|
end
|
|
|
|
it "should report error when being set other values" do
|
|
expect { settings.test_enum = "not_in_enum" }.to raise_error(Discourse::InvalidParameters)
|
|
end
|
|
|
|
context "when overridden" do
|
|
after :each do
|
|
settings.remove_override!(:validated_setting)
|
|
end
|
|
|
|
it "stores valid values" do
|
|
test_enum_class.expects(:valid_value?).with("fr").returns(true)
|
|
settings.test_enum = "fr"
|
|
expect(settings.test_enum).to eq("fr")
|
|
end
|
|
|
|
it "rejects invalid values" do
|
|
test_enum_class.expects(:valid_value?).with("gg").returns(false)
|
|
expect { settings.test_enum = "gg" }.to raise_error(Discourse::InvalidParameters)
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "a setting with a category" do
|
|
before do
|
|
settings.setting(:test_setting, 88, category: :tests)
|
|
settings.refresh!
|
|
end
|
|
|
|
it "should return the category in all_settings" do
|
|
expect(settings.all_settings.find { |s| s[:setting] == :test_setting }[:category]).to eq(
|
|
:tests,
|
|
)
|
|
end
|
|
|
|
context "when overridden" do
|
|
after :each do
|
|
settings.remove_override!(:test_setting)
|
|
end
|
|
|
|
it "should have the correct override" do
|
|
settings.test_setting = 101
|
|
expect(settings.test_setting).to eq(101)
|
|
end
|
|
|
|
it "should still have the correct category" do
|
|
settings.test_setting = 102
|
|
expect(settings.all_settings.find { |s| s[:setting] == :test_setting }[:category]).to eq(
|
|
:tests,
|
|
)
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "a setting with an area" do
|
|
before do
|
|
settings.setting(:test_setting, 88, area: "flags")
|
|
settings.setting(:test_setting2, 89, area: "flags")
|
|
settings.setting(:test_setting4, 90)
|
|
settings.refresh!
|
|
end
|
|
|
|
it "should allow to filter by area" do
|
|
expect(settings.all_settings(filter_area: "flags").map { |s| s[:setting].to_sym }).to eq(
|
|
%i[default_locale test_setting test_setting2],
|
|
)
|
|
end
|
|
|
|
it "raised an error when area is invalid" do
|
|
expect {
|
|
settings.setting(:test_setting, 89, area: "invalid")
|
|
settings.refresh!
|
|
}.to raise_error(Discourse::InvalidParameters)
|
|
end
|
|
|
|
it "allows plugin to register valid areas" do
|
|
plugin = Plugin::Instance.new nil, "/tmp/test.rb"
|
|
plugin.register_site_setting_area("plugin_area")
|
|
settings.setting(:test_plugin_setting, 88, area: "plugin_area")
|
|
expect(
|
|
settings
|
|
.all_settings(filter_area: "plugin_area", include_locale_setting: false)
|
|
.map { |s| s[:setting].to_sym },
|
|
).to eq(%i[test_plugin_setting])
|
|
end
|
|
end
|
|
|
|
describe "setting with a validator" do
|
|
before do
|
|
settings.setting(:validated_setting, "info@example.com", type: "email")
|
|
settings.refresh!
|
|
end
|
|
|
|
after :each do
|
|
settings.remove_override!(:validated_setting)
|
|
end
|
|
|
|
it "stores valid values" do
|
|
EmailSettingValidator.any_instance.expects(:valid_value?).returns(true)
|
|
settings.validated_setting = "success@example.com"
|
|
expect(settings.validated_setting).to eq("success@example.com")
|
|
end
|
|
|
|
it "rejects invalid values" do
|
|
expect {
|
|
EmailSettingValidator.any_instance.expects(:valid_value?).returns(false)
|
|
settings.validated_setting = "nope"
|
|
}.to raise_error(Discourse::InvalidParameters)
|
|
expect(settings.validated_setting).to eq("info@example.com")
|
|
end
|
|
|
|
it "allows blank values" do
|
|
settings.validated_setting = ""
|
|
expect(settings.validated_setting).to eq("")
|
|
end
|
|
end
|
|
|
|
describe "datetime setting" do
|
|
before do
|
|
settings.setting(:datetime_setting, "2024-01-01T00:00:00Z", type: "datetime")
|
|
settings.refresh!
|
|
end
|
|
|
|
after :each do
|
|
settings.remove_override!(:datetime_setting)
|
|
end
|
|
|
|
it "stores valid datetime values" do
|
|
settings.datetime_setting = "2024-12-29T15:30:00Z"
|
|
expect(settings.datetime_setting).to eq("2024-12-29T15:30:00Z")
|
|
end
|
|
|
|
it "stores valid datetime values with timezone offset" do
|
|
settings.datetime_setting = "2024-12-29T15:30:00+05:30"
|
|
expect(settings.datetime_setting).to eq("2024-12-29T15:30:00+05:30")
|
|
end
|
|
|
|
it "stores valid datetime values with milliseconds" do
|
|
settings.datetime_setting = "2024-12-29T15:30:00.123Z"
|
|
expect(settings.datetime_setting).to eq("2024-12-29T15:30:00.123Z")
|
|
end
|
|
|
|
it "rejects date-only strings" do
|
|
expect { settings.datetime_setting = "2024-12-29" }.to raise_error(
|
|
Discourse::InvalidParameters,
|
|
)
|
|
end
|
|
|
|
it "rejects datetime without timezone" do
|
|
expect { settings.datetime_setting = "2024-12-29T15:30:00" }.to raise_error(
|
|
Discourse::InvalidParameters,
|
|
)
|
|
end
|
|
|
|
it "rejects invalid datetime strings" do
|
|
expect { settings.datetime_setting = "not a datetime" }.to raise_error(
|
|
Discourse::InvalidParameters,
|
|
)
|
|
expect { settings.datetime_setting = "2024-13-01T15:30:00Z" }.to raise_error(
|
|
Discourse::InvalidParameters,
|
|
)
|
|
end
|
|
|
|
it "allows blank values" do
|
|
settings.datetime_setting = ""
|
|
expect(settings.datetime_setting).to eq("")
|
|
end
|
|
end
|
|
|
|
describe "set for an invalid setting name" do
|
|
it "raises an error" do
|
|
settings.setting(:test_setting, 77)
|
|
settings.refresh!
|
|
expect { settings.set("provider", "haxxed") }.to raise_error(Discourse::InvalidParameters)
|
|
end
|
|
end
|
|
|
|
describe ".get" do
|
|
before do
|
|
settings.setting(:title, "Discourse v1")
|
|
settings.refresh!
|
|
end
|
|
|
|
it "works correctly" do
|
|
expect { settings.get("frogs_in_africa") }.to raise_error(Discourse::InvalidParameters)
|
|
|
|
expect(settings.get(:title)).to eq("Discourse v1")
|
|
expect(settings.get("title")).to eq("Discourse v1")
|
|
end
|
|
end
|
|
|
|
describe ".set_and_log" do
|
|
before do
|
|
settings.setting(:s3_secret_access_key, "old_secret_key", secret: true)
|
|
settings.setting(:title, "Discourse v1")
|
|
settings.refresh!
|
|
end
|
|
|
|
it "raises an error when set for an invalid setting name" do
|
|
expect { settings.set_and_log("provider", "haxxed") }.to raise_error(
|
|
Discourse::InvalidParameters,
|
|
)
|
|
end
|
|
|
|
it "scrubs secret setting values from logs" do
|
|
settings.set_and_log("s3_secret_access_key", "new_secret_key")
|
|
expect(UserHistory.last.previous_value).to eq("[FILTERED]")
|
|
expect(UserHistory.last.new_value).to eq("[FILTERED]")
|
|
end
|
|
|
|
it "works" do
|
|
settings.set_and_log("title", "Discourse v2")
|
|
expect(settings.title).to eq("Discourse v2")
|
|
expect(UserHistory.last.previous_value).to eq("Discourse v1")
|
|
expect(UserHistory.last.new_value).to eq("Discourse v2")
|
|
end
|
|
|
|
it "does not create an entry in the staff action logs when new value is the same" do
|
|
expect { settings.set_and_log("title", "Discourse v1") }.not_to change { UserHistory.count }
|
|
end
|
|
|
|
context "when a detailed message is provided" do
|
|
let(:message) { "We really need to do this, see https://meta.discourse.org/t/123" }
|
|
|
|
it "adds the detailed message to the user history record" do
|
|
expect {
|
|
settings.set_and_log("title", "Discourse v2", Discourse.system_user, message)
|
|
}.to change { UserHistory.last.try(:details) }.to(message)
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "filter domain name" do
|
|
before do
|
|
settings.setting(:allowed_spam_host_domains, "www.example.com")
|
|
settings.refresh!
|
|
end
|
|
|
|
it "filters domain" do
|
|
settings.set("allowed_spam_host_domains", "http://www.discourse.org/")
|
|
expect(settings.allowed_spam_host_domains).to eq("www.discourse.org")
|
|
end
|
|
|
|
it "returns invalid domain as is, without throwing exception" do
|
|
settings.set("allowed_spam_host_domains", "test!url")
|
|
expect(settings.allowed_spam_host_domains).to eq("test!url")
|
|
end
|
|
end
|
|
|
|
describe "dependent settings" do
|
|
context "when a dependent setting depends_behavior is not set" do
|
|
before do
|
|
settings.setting(:cool_thing_image, nil, depends_on: [:enable_cool_thing])
|
|
settings.refresh!
|
|
end
|
|
|
|
it "is present in all_settings" do
|
|
expect(settings.all_settings.find { |s| s[:setting] == :cool_thing_image }).not_to be_blank
|
|
end
|
|
end
|
|
|
|
context "when a dependent setting depends_behavior is hidden" do
|
|
before do
|
|
settings.setting(
|
|
:cool_thing_image,
|
|
nil,
|
|
depends_on: [:enable_cool_thing],
|
|
depends_behavior: :hidden,
|
|
)
|
|
settings.refresh!
|
|
end
|
|
|
|
context "when the depends_on setting is an upcoming change" do
|
|
context "when the upcoming change is enabled by an admin" do
|
|
before do
|
|
settings.setting(
|
|
:enable_cool_thing,
|
|
true,
|
|
upcoming_change: {
|
|
status: :alpha,
|
|
impact: "feature,staff",
|
|
},
|
|
)
|
|
settings.refresh!
|
|
allow(UpcomingChanges).to receive(:enabled?).with(:enable_cool_thing).and_return(true)
|
|
end
|
|
|
|
it "is present in all_settings" do
|
|
expect(
|
|
settings.all_settings.find { |s| s[:setting] == :cool_thing_image },
|
|
).not_to be_blank
|
|
end
|
|
end
|
|
|
|
context "when the upcoming change is automatically enabled because of the promotion status" do
|
|
before do
|
|
settings.setting(
|
|
:enable_cool_thing,
|
|
true,
|
|
upcoming_change: {
|
|
status: :alpha,
|
|
impact: "feature,staff",
|
|
},
|
|
)
|
|
settings.refresh!
|
|
allow(UpcomingChanges).to receive(:enabled?).with(:enable_cool_thing).and_return(true)
|
|
end
|
|
|
|
it "is present in all_settings" do
|
|
expect(
|
|
settings.all_settings.find { |s| s[:setting] == :cool_thing_image },
|
|
).not_to be_blank
|
|
end
|
|
end
|
|
end
|
|
|
|
context "when the depends_on setting is true" do
|
|
before do
|
|
settings.setting(:enable_cool_thing, true)
|
|
settings.refresh!
|
|
end
|
|
|
|
it "is present in all_settings" do
|
|
expect(
|
|
settings.all_settings.find { |s| s[:setting] == :cool_thing_image },
|
|
).not_to be_blank
|
|
end
|
|
|
|
it "serializes depends_on and the matching humanized names" do
|
|
setting = settings.all_settings.find { |s| s[:setting] == :cool_thing_image }
|
|
expect(setting[:depends_on]).to eq([:enable_cool_thing])
|
|
expect(setting[:depends_on_humanized_names]).to eq(["Enable cool thing"])
|
|
end
|
|
end
|
|
|
|
context "when the depends_on setting is false" do
|
|
before do
|
|
settings.setting(:enable_cool_thing, false)
|
|
settings.refresh!
|
|
end
|
|
|
|
it "is still present in all_settings so the UI can reactively hide/disable it" do
|
|
setting = settings.all_settings.find { |s| s[:setting] == :cool_thing_image }
|
|
expect(setting).not_to be_blank
|
|
expect(setting[:depends_on]).to eq([:enable_cool_thing])
|
|
expect(setting[:depends_behavior]).to eq(:hidden)
|
|
end
|
|
end
|
|
|
|
context "when the depends_on setting does not exist" do
|
|
before do
|
|
settings.setting(
|
|
:orphan_setting,
|
|
nil,
|
|
depends_on: [:nonexistent_setting],
|
|
depends_behavior: :hidden,
|
|
)
|
|
settings.refresh!
|
|
end
|
|
|
|
it "is still present in all_settings (visibility handled client-side)" do
|
|
expect(settings.all_settings.find { |s| s[:setting] == :orphan_setting }).not_to be_blank
|
|
end
|
|
end
|
|
|
|
context "when the setting is also explicitly hidden" do
|
|
before do
|
|
settings.setting(:enable_cool_thing, true)
|
|
settings.refresh!
|
|
end
|
|
|
|
it "remains hidden even when depends_on settings are true" do
|
|
settings.setting(
|
|
:hidden_cool_thing_image,
|
|
nil,
|
|
hidden: true,
|
|
depends_on: [:enable_cool_thing],
|
|
depends_behavior: :hidden,
|
|
)
|
|
settings.refresh!
|
|
|
|
expect(settings.hidden_settings).to include(:hidden_cool_thing_image)
|
|
expect(
|
|
settings.all_settings.find { |s| s[:setting] == :hidden_cool_thing_image },
|
|
).to be_blank
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "hidden" do
|
|
before do
|
|
settings.setting(:other_setting, "Blah")
|
|
settings.setting(:superman_identity, "Clark Kent", hidden: true)
|
|
settings.refresh!
|
|
end
|
|
|
|
after { DiscoursePluginRegistry.reset! }
|
|
|
|
it "is in the `hidden_settings` collection" do
|
|
expect(settings.hidden_settings.include?(:superman_identity)).to eq(true)
|
|
end
|
|
|
|
it "can be retrieved" do
|
|
expect(settings.superman_identity).to eq("Clark Kent")
|
|
end
|
|
|
|
it "is not present in all_settings by default" do
|
|
expect(settings.all_settings.find { |s| s[:setting] == :superman_identity }).to be_blank
|
|
end
|
|
|
|
it "is present in all_settings when we ask for hidden" do
|
|
expect(
|
|
settings.all_settings(include_hidden: true).find { |s| s[:setting] == :superman_identity },
|
|
).to be_present
|
|
end
|
|
|
|
it "does not call the hidden_site_settings plugin modifier in a loop" do
|
|
called = 0
|
|
plugin = Plugin::Instance.new
|
|
plugin.register_modifier(:hidden_site_settings) do |defaults|
|
|
called += 1
|
|
defaults + [:other_setting]
|
|
end
|
|
settings.all_settings(include_hidden: true)
|
|
expect(called).to eq(1)
|
|
end
|
|
|
|
it "calls the site_setting_result modifier for each setting" do
|
|
plugin = Plugin::Instance.new
|
|
plugin.register_modifier(:site_setting_result) do |opts|
|
|
opts[:custom_attribute] = "test_value" if opts[:setting] == :other_setting
|
|
opts
|
|
end
|
|
|
|
result = settings.all_settings
|
|
other_setting = result.find { |s| s[:setting] == :other_setting }
|
|
|
|
expect(other_setting[:custom_attribute]).to eq("test_value")
|
|
end
|
|
end
|
|
|
|
describe "global override" do
|
|
context "with default_locale" do
|
|
it "supports adding a default locale via a global" do
|
|
global_setting :default_locale, "zh_CN"
|
|
settings.default_locale = "en"
|
|
expect(settings.default_locale).to eq("zh_CN")
|
|
end
|
|
end
|
|
|
|
context "without global setting" do
|
|
before do
|
|
settings.setting(:trout_api_key, "evil")
|
|
settings.refresh!
|
|
end
|
|
|
|
it "should not add the key to the shadowed_settings collection" do
|
|
expect(settings.shadowed_settings.include?(:trout_api_key)).to eq(false)
|
|
end
|
|
|
|
it "can return the default value" do
|
|
expect(settings.trout_api_key).to eq("evil")
|
|
end
|
|
|
|
it "can overwrite the default" do
|
|
settings.trout_api_key = "tophat"
|
|
settings.refresh!
|
|
expect(settings.trout_api_key).to eq("tophat")
|
|
end
|
|
end
|
|
|
|
context "with blank global setting" do
|
|
before do
|
|
GlobalSetting.stubs(:nada).returns("")
|
|
settings.setting(:nada, "nothing")
|
|
settings.refresh!
|
|
end
|
|
|
|
it "should return default cause nothing is set" do
|
|
expect(settings.nada).to eq("nothing")
|
|
end
|
|
end
|
|
|
|
context "with a false override" do
|
|
before do
|
|
GlobalSetting.stubs(:bool).returns(false)
|
|
settings.setting(:bool, true)
|
|
settings.refresh!
|
|
end
|
|
|
|
it "should return default cause nothing is set" do
|
|
expect(settings.bool).to eq(false)
|
|
end
|
|
|
|
it "should not trigger any message bus work if you try to set it" do
|
|
m =
|
|
MessageBus.track_publish("/site_settings") do
|
|
settings.bool = true
|
|
expect(settings.bool).to eq(false)
|
|
end
|
|
expect(m.length).to eq(0)
|
|
end
|
|
end
|
|
|
|
context "with global setting" do
|
|
before do
|
|
GlobalSetting.stubs(:trout_api_key).returns("purringcat")
|
|
settings.setting(:trout_api_key, "evil")
|
|
settings.refresh!
|
|
end
|
|
|
|
it "should return the global setting instead of default" do
|
|
expect(settings.trout_api_key).to eq("purringcat")
|
|
end
|
|
|
|
it "should return the global setting after a refresh" do
|
|
settings.refresh!
|
|
expect(settings.trout_api_key).to eq("purringcat")
|
|
end
|
|
|
|
it "should add the key to the hidden_settings collection" do
|
|
expect(settings.hidden_settings.include?(:trout_api_key)).to eq(true)
|
|
|
|
["", nil].each_with_index do |setting, index|
|
|
GlobalSetting.stubs(:"trout_api_key_#{index}").returns(setting)
|
|
settings.setting(:"trout_api_key_#{index}", "evil")
|
|
settings.refresh!
|
|
expect(settings.hidden_settings.include?(:"trout_api_key_#{index}")).to eq(false)
|
|
end
|
|
end
|
|
|
|
it "should add the key to the shadowed_settings collection" do
|
|
expect(settings.shadowed_settings.include?(:trout_api_key)).to eq(true)
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "secret" do
|
|
before do
|
|
settings.setting(:superman_identity, "Clark Kent", secret: true)
|
|
settings.refresh!
|
|
end
|
|
|
|
it "is in the `secret_settings` collection" do
|
|
expect(settings.secret_settings.include?(:superman_identity)).to eq(true)
|
|
end
|
|
|
|
it "can be retrieved" do
|
|
expect(settings.superman_identity).to eq("Clark Kent")
|
|
end
|
|
|
|
it "is present in all_settings by default" do
|
|
secret_setting = settings.all_settings.find { |s| s[:setting] == :superman_identity }
|
|
expect(secret_setting).to be_present
|
|
expect(secret_setting[:secret]).to eq(true)
|
|
end
|
|
end
|
|
|
|
describe "locale default overrides are respected" do
|
|
before do
|
|
settings.setting(:test_override, "default", locale_default: { zh_CN: "cn" })
|
|
settings.refresh!
|
|
end
|
|
|
|
after { settings.remove_override!(:test_override) }
|
|
|
|
it "ensures the default cache expired after overriding the default_locale" do
|
|
expect(settings.test_override).to eq("default")
|
|
settings.default_locale = "zh_CN"
|
|
expect(settings.test_override).to eq("cn")
|
|
end
|
|
|
|
it "returns the saved setting even locale default exists" do
|
|
expect(settings.test_override).to eq("default")
|
|
settings.default_locale = "zh_CN"
|
|
settings.test_override = "saved"
|
|
expect(settings.test_override).to eq("saved")
|
|
end
|
|
end
|
|
|
|
describe ".requires_refresh?" do
|
|
it "always refresh default_locale always require refresh" do
|
|
expect(settings.requires_refresh?(:default_locale)).to be_truthy
|
|
end
|
|
end
|
|
|
|
describe ".default_locale" do
|
|
it "is always loaded" do
|
|
expect(settings.default_locale).to eq("en")
|
|
end
|
|
end
|
|
|
|
describe ".default_locale=" do
|
|
it "can be changed" do
|
|
settings.default_locale = "zh_CN"
|
|
expect(settings.default_locale).to eq "zh_CN"
|
|
end
|
|
|
|
it "refresh!" do
|
|
settings.expects(:refresh!)
|
|
settings.default_locale = "zh_CN"
|
|
end
|
|
|
|
it "expires the cache" do
|
|
settings.default_locale = "zh_CN"
|
|
expect(Discourse.cache.exist?(SiteSettingExtension.client_settings_cache_key)).to be_falsey
|
|
end
|
|
|
|
it "refreshes the client" do
|
|
Discourse.expects(:request_refresh!)
|
|
settings.default_locale = "zh_CN"
|
|
end
|
|
end
|
|
|
|
describe "get_hostname" do
|
|
it "properly extracts the hostname" do
|
|
# consider testing this through a public interface, this tests implementation details
|
|
expect(settings.send(:get_hostname, "discourse.org")).to eq("discourse.org")
|
|
expect(settings.send(:get_hostname, "@discourse.org")).to eq("discourse.org")
|
|
expect(settings.send(:get_hostname, "https://discourse.org")).to eq("discourse.org")
|
|
end
|
|
end
|
|
|
|
describe ".all_settings" do
|
|
describe "non-configurable plugin exclusion" do
|
|
it "includes plugin site settings when the plugin is configurable" do
|
|
SiteSetting::SAMPLE_TEST_PLUGIN.stubs(:configurable?).returns(true)
|
|
|
|
expect(SiteSetting.all_settings.map { |s| s[:setting] }).to include(:plugin_setting)
|
|
end
|
|
|
|
it "excludes plugin site settings when the plugin is not configurable" do
|
|
SiteSetting::SAMPLE_TEST_PLUGIN.stubs(:configurable?).returns(false)
|
|
|
|
expect(SiteSetting.all_settings.map { |s| s[:setting] }).not_to include(:plugin_setting)
|
|
end
|
|
end
|
|
|
|
describe "uploads settings" do
|
|
it "should return the right values" do
|
|
negative_upload_id = [(Upload.minimum(:id) || 0) - 1, -10].min
|
|
system_upload = Fabricate(:upload, id: negative_upload_id)
|
|
settings.setting(:logo, system_upload.id, type: :upload)
|
|
settings.refresh!
|
|
setting = settings.all_settings.last
|
|
|
|
expect(setting[:value]).to eq(system_upload.url)
|
|
expect(setting[:default]).to eq(system_upload.url)
|
|
|
|
upload = Fabricate(:upload)
|
|
settings.logo = upload
|
|
settings.refresh!
|
|
setting = settings.all_settings.last
|
|
|
|
expect(setting[:value]).to eq(upload.url)
|
|
expect(setting[:default]).to eq(system_upload.url)
|
|
end
|
|
end
|
|
|
|
describe "objects settings with uploads" do
|
|
it "should hydrate upload IDs to URLs" do
|
|
upload1 = Fabricate(:upload)
|
|
upload2 = Fabricate(:upload)
|
|
upload3 = Fabricate(:upload)
|
|
|
|
schema = {
|
|
name: "section",
|
|
properties: {
|
|
title: {
|
|
type: "string",
|
|
},
|
|
image: {
|
|
type: "upload",
|
|
},
|
|
links: {
|
|
type: "objects",
|
|
schema: {
|
|
name: "link",
|
|
properties: {
|
|
link_image: {
|
|
type: "upload",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
settings.setting(:test_objects_with_uploads, "[]", type: :objects, schema: schema)
|
|
settings.test_objects_with_uploads = [
|
|
{
|
|
"title" => "Section 1",
|
|
"image" => upload1.id,
|
|
"links" => [{ "link_image" => upload3.id }],
|
|
},
|
|
{ "title" => "Section 2", "image" => upload2.id },
|
|
].to_json
|
|
settings.refresh!
|
|
|
|
setting = settings.all_settings.last
|
|
value = JSON.parse(setting[:value])
|
|
|
|
expect(value[0]["image"]).to eq(upload1.url)
|
|
expect(value[1]["image"]).to eq(upload2.url)
|
|
expect(value[0]["title"]).to eq("Section 1")
|
|
expect(value[1]["title"]).to eq("Section 2")
|
|
expect(value[0]["links"][0]["link_image"]).to eq(upload3.url)
|
|
end
|
|
|
|
it "should batch uploads query" do
|
|
upload1 = Fabricate(:upload)
|
|
upload2 = Fabricate(:upload)
|
|
upload3 = Fabricate(:upload)
|
|
|
|
schema = {
|
|
name: "section",
|
|
properties: {
|
|
title: {
|
|
type: "string",
|
|
},
|
|
image: {
|
|
type: "upload",
|
|
},
|
|
},
|
|
}
|
|
|
|
settings.setting(:test_objects_with_uploads, "[]", type: :objects, schema: schema)
|
|
settings.test_objects_with_uploads = [
|
|
{ "title" => "Section 1", "image" => upload1.id },
|
|
{ "title" => "Section 2", "image" => upload2.id },
|
|
{ "title" => "Section 3", "image" => upload3.id },
|
|
].to_json
|
|
settings.refresh!
|
|
|
|
queries =
|
|
track_sql_queries do
|
|
setting = settings.all_settings.last
|
|
JSON.parse(setting[:value])
|
|
end
|
|
|
|
upload_queries = queries.select { |q| q.include?("SELECT") && q.include?("uploads") }
|
|
expect(upload_queries.length).to eq(1)
|
|
end
|
|
end
|
|
|
|
context "with the filter_allowed_hidden argument" do
|
|
it "includes the specified hidden settings only if include_hidden is true" do
|
|
result =
|
|
SiteSetting
|
|
.all_settings(include_hidden: true, filter_allowed_hidden: [:about_banner_image])
|
|
.map { |ss| ss[:setting] }
|
|
|
|
expect(result).to include(:about_banner_image)
|
|
expect(result).not_to include(:community_owner)
|
|
|
|
result =
|
|
SiteSetting
|
|
.all_settings(include_hidden: false, filter_allowed_hidden: [:about_banner_image])
|
|
.map { |ss| ss[:setting] }
|
|
|
|
expect(result).not_to include(:about_banner_image)
|
|
expect(result).not_to include(:community_owner)
|
|
|
|
result =
|
|
SiteSetting
|
|
.all_settings(include_hidden: true, filter_allowed_hidden: [:community_owner])
|
|
.map { |ss| ss[:setting] }
|
|
|
|
expect(result).not_to include(:about_banner_image)
|
|
expect(result).to include(:community_owner)
|
|
|
|
result =
|
|
SiteSetting
|
|
.all_settings(
|
|
include_hidden: true,
|
|
filter_allowed_hidden: %i[about_banner_image community_owner],
|
|
)
|
|
.map { |ss| ss[:setting] }
|
|
|
|
expect(result).to include(:about_banner_image)
|
|
expect(result).to include(:community_owner)
|
|
end
|
|
end
|
|
end
|
|
|
|
describe ".client_settings_json_uncached" do
|
|
it "should return the right json value" do
|
|
upload = Fabricate(:upload)
|
|
settings.setting(:upload_type, upload.id.to_s, type: :upload, client: true)
|
|
settings.setting(:string_type, "haha", client: true)
|
|
settings.refresh!
|
|
|
|
expect(settings.client_settings_json_uncached).to eq(
|
|
%Q|{"default_locale":"#{SiteSetting.default_locale}","upload_type":"#{upload.url}","string_type":"haha"}|,
|
|
)
|
|
end
|
|
|
|
it "settings with html type are not sanitized" do
|
|
settings.setting(:with_html, "<script></script>rest", type: :html, client: true)
|
|
|
|
client_settings = JSON.parse settings.client_settings_json_uncached
|
|
|
|
expect(client_settings["with_html"]).to eq("<script></script>rest")
|
|
end
|
|
|
|
it "does not include themeable site settings" do
|
|
SiteSetting.refresh!
|
|
expect(SiteSetting.client_settings_json_uncached).not_to include("enable_welcome_banner")
|
|
expect(SiteSetting.client_settings_json_uncached).not_to include("search_experience")
|
|
end
|
|
|
|
context "when error occurs" do
|
|
it "re-raises the exception instead of returning nil" do
|
|
settings.setting(:test_setting, "value", client: true)
|
|
settings.refresh!
|
|
|
|
allow(settings).to receive(:public_send).with(:default_locale).and_return(
|
|
SiteSetting.default_locale,
|
|
)
|
|
allow(settings).to receive(:public_send).with(:test_setting).and_raise(
|
|
PG::ConnectionBad,
|
|
"connection lost",
|
|
)
|
|
|
|
expect { settings.client_settings_json_uncached }.to raise_error(
|
|
PG::ConnectionBad,
|
|
/connection lost/,
|
|
)
|
|
end
|
|
end
|
|
end
|
|
|
|
describe ".client_settings_json" do
|
|
it "returns valid JSON when successful" do
|
|
settings.setting(:test_setting, "value", client: true)
|
|
settings.refresh!
|
|
|
|
result = settings.client_settings_json
|
|
expect { JSON.parse(result) }.not_to raise_error
|
|
parsed = JSON.parse(result)
|
|
expect(parsed["test_setting"]).to eq("value")
|
|
end
|
|
|
|
context "when error occurs" do
|
|
it "returns empty string without caching the error" do
|
|
settings.setting(:test_setting, "value", client: true)
|
|
settings.refresh!
|
|
|
|
allow(settings).to receive(:client_settings_json_uncached).and_raise(
|
|
PG::ConnectionBad,
|
|
"connection lost",
|
|
)
|
|
|
|
result = settings.client_settings_json
|
|
expect(result).to eq("")
|
|
end
|
|
|
|
it "does not cache the error and retries on next call" do
|
|
settings.setting(:test_setting, "value", client: true)
|
|
settings.refresh!
|
|
|
|
cache_key = SiteSettingExtension.client_settings_cache_key
|
|
|
|
call_count = 0
|
|
allow(settings).to receive(:client_settings_json_uncached) do
|
|
call_count += 1
|
|
if call_count == 1
|
|
raise PG::ConnectionBad, "connection lost"
|
|
else
|
|
'{"default_locale":"en","test_setting":"value"}'
|
|
end
|
|
end
|
|
|
|
# First call fails
|
|
result1 = settings.client_settings_json
|
|
expect(result1).to eq("")
|
|
# Verify error was NOT cached in Redis
|
|
expect(Discourse.cache.exist?(cache_key)).to be_falsey
|
|
|
|
# Second call should retry (not use cached error) and succeed
|
|
result2 = settings.client_settings_json
|
|
expect(result2).to eq('{"default_locale":"en","test_setting":"value"}')
|
|
expect(call_count).to eq(2) # Both calls executed, error was not cached
|
|
|
|
# Verify success was cached in Redis
|
|
expect(Discourse.cache.exist?(cache_key)).to be_truthy
|
|
expect(Discourse.cache.read(cache_key)).to eq(
|
|
'{"default_locale":"en","test_setting":"value"}',
|
|
)
|
|
end
|
|
end
|
|
end
|
|
|
|
describe ".setup_methods" do
|
|
describe "for uploads site settings" do
|
|
fab!(:upload)
|
|
fab!(:upload2, :upload)
|
|
|
|
it "should return the upload record" do
|
|
settings.setting(:some_upload, upload.id.to_s, type: :upload)
|
|
|
|
expect(settings.some_upload).to eq(upload)
|
|
|
|
# Ensure that we cache the upload record
|
|
expect(settings.some_upload.object_id).to eq(settings.some_upload.object_id)
|
|
|
|
settings.some_upload = upload2
|
|
|
|
expect(settings.some_upload).to eq(upload2)
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "mandatory_values for group list settings" do
|
|
it "adds mandatory values" do
|
|
expect(SiteSetting.embedded_media_post_allowed_groups).to eq("1|2|10")
|
|
|
|
SiteSetting.embedded_media_post_allowed_groups = 14
|
|
expect(SiteSetting.embedded_media_post_allowed_groups).to eq("1|2|14")
|
|
|
|
SiteSetting.embedded_media_post_allowed_groups = ""
|
|
expect(SiteSetting.embedded_media_post_allowed_groups).to eq("1|2")
|
|
|
|
test_provider = SiteSetting.provider
|
|
SiteSetting.provider = SiteSettings::DbProvider.new(SiteSetting)
|
|
SiteSetting.embedded_media_post_allowed_groups = "13|14"
|
|
expect(SiteSetting.embedded_media_post_allowed_groups).to eq("1|2|13|14")
|
|
expect(SiteSetting.find_by(name: "embedded_media_post_allowed_groups").value).to eq(
|
|
"1|2|13|14",
|
|
)
|
|
ensure
|
|
SiteSetting.find_by(name: "embedded_media_post_allowed_groups").destroy
|
|
SiteSetting.provider = test_provider
|
|
end
|
|
end
|
|
|
|
describe "disallowed_groups for group list settings" do
|
|
it "strips disallowed groups when setting a value" do
|
|
SiteSetting.whispers_allowed_groups = "0|1|2"
|
|
expect(SiteSetting.whispers_allowed_groups).to eq("1|2")
|
|
|
|
SiteSetting.whispers_allowed_groups = "0"
|
|
expect(SiteSetting.whispers_allowed_groups).to eq("")
|
|
|
|
SiteSetting.whispers_allowed_groups = "1|0|2|0"
|
|
expect(SiteSetting.whispers_allowed_groups).to eq("1|2")
|
|
end
|
|
|
|
it "is included in all_settings output" do
|
|
setting = SiteSetting.all_settings.find { |s| s[:setting] == :whispers_allowed_groups }
|
|
expect(setting[:disallowed_groups]).to eq("0")
|
|
end
|
|
end
|
|
|
|
describe "requires_confirmation settings" do
|
|
it "returns 'simple' for settings that require confirmation with 'simple' type" do
|
|
expect(
|
|
SiteSetting.all_settings.find { |s| s[:setting] == :min_password_length }[
|
|
:requires_confirmation
|
|
],
|
|
).to eq("simple")
|
|
end
|
|
|
|
it "returns nil for settings that do not require confirmation" do
|
|
expect(
|
|
SiteSetting.all_settings.find { |s| s[:setting] == :display_local_time_in_user_card }[
|
|
:requires_confirmation
|
|
],
|
|
).to eq(nil)
|
|
end
|
|
end
|
|
|
|
describe "site setting groups" do
|
|
before do
|
|
SiteSettingGroup.create!(
|
|
name: "enable_upload_debug_mode",
|
|
group_ids: "#{Group::AUTO_GROUPS[:trust_level_0]}|#{Group::AUTO_GROUPS[:trust_level_1]}",
|
|
)
|
|
end
|
|
|
|
it "returns the correct group for a setting" do
|
|
SiteSetting.refresh!
|
|
expect(SiteSetting.site_setting_group_ids[:enable_upload_debug_mode]).to eq([10, 11])
|
|
end
|
|
end
|
|
|
|
describe "site setting singleton methods" do
|
|
describe "for an upcoming change site setting" do
|
|
let(:setting_name) { :enable_upload_debug_mode }
|
|
let(:default_value) { SiteSetting.defaults[setting_name] }
|
|
|
|
before do
|
|
mock_upcoming_change_metadata(
|
|
{
|
|
enable_upload_debug_mode: {
|
|
impact: "other,developers",
|
|
status: :beta,
|
|
impact_type: "other",
|
|
impact_role: "developers",
|
|
},
|
|
},
|
|
)
|
|
SiteSetting.send(:setup_methods, setting_name)
|
|
SiteSetting.refresh!
|
|
end
|
|
|
|
after do
|
|
SiteSetting.remove_override!(setting_name)
|
|
SiteSetting.refresh!
|
|
end
|
|
|
|
it "returns the stored value when it differs from the default" do
|
|
SiteSetting.public_send("#{setting_name}=", !default_value)
|
|
expect(SiteSetting.public_send(setting_name)).to eq(!default_value)
|
|
end
|
|
|
|
it "returns true when the setting meets the promotion status" do
|
|
SiteSetting.promote_upcoming_changes_on_status = :beta
|
|
expect(SiteSetting.public_send(setting_name)).to eq(true)
|
|
end
|
|
|
|
it "returns false when admins have changed the setting to false even if the promotion status is met" do
|
|
SiteSetting.public_send("#{setting_name}=", false)
|
|
expect(SiteSetting.public_send(setting_name)).to eq(false)
|
|
|
|
SiteSetting.promote_upcoming_changes_on_status = :beta
|
|
expect(SiteSetting.public_send(setting_name)).to eq(false)
|
|
end
|
|
|
|
it "returns the default when the setting does not meet the promotion status" do
|
|
SiteSetting.promote_upcoming_changes_on_status = :stable
|
|
expect(SiteSetting.public_send(setting_name)).to eq(default_value)
|
|
end
|
|
|
|
context "when the upcoming change is permanent" do
|
|
before do
|
|
mock_upcoming_change_metadata(
|
|
{
|
|
enable_upload_debug_mode: {
|
|
impact: "other,developers",
|
|
status: :permanent,
|
|
impact_type: "other",
|
|
impact_role: "developers",
|
|
},
|
|
},
|
|
)
|
|
end
|
|
|
|
it "returns true" do
|
|
expect(SiteSetting.public_send(setting_name)).to eq(true)
|
|
end
|
|
|
|
it "return true even if the setting value is false in the database" do
|
|
SiteSetting.public_send("#{setting_name}=", false)
|
|
expect(SiteSetting.public_send(setting_name)).to eq(true)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "#notify_clients!" do
|
|
context "when the site setting is an upcoming change" do
|
|
before do
|
|
mock_upcoming_change_metadata(
|
|
{
|
|
enable_upload_debug_mode: {
|
|
impact: "other,developers",
|
|
status: :experimental,
|
|
impact_type: "other",
|
|
impact_role: "developers",
|
|
},
|
|
some_other_upcoming_setting: {
|
|
impact: "feature,staff",
|
|
status: :alpha,
|
|
impact_type: "feature",
|
|
impact_role: "staff",
|
|
},
|
|
},
|
|
)
|
|
SiteSetting.send(:setup_methods, :enable_upload_debug_mode)
|
|
SiteSetting.refresh!
|
|
end
|
|
|
|
after { SiteSetting.refresh! }
|
|
|
|
context "with site setting groups assigned" do
|
|
before do
|
|
SiteSettingGroup.create!(
|
|
name: "enable_upload_debug_mode",
|
|
group_ids:
|
|
"#{Group::AUTO_GROUPS[:trust_level_0]}|#{Group::AUTO_GROUPS[:trust_level_1]}",
|
|
)
|
|
SiteSetting.refresh!
|
|
end
|
|
|
|
after { SiteSetting.refresh! }
|
|
|
|
it "does not publish to MessageBus for the client settings channel" do
|
|
messages =
|
|
MessageBus.track_publish(SiteSettingExtension::CLIENT_SETTINGS_CHANNEL) do
|
|
SiteSetting.notify_clients!(:enable_upload_debug_mode)
|
|
end
|
|
|
|
expect(messages.length).to eq(0)
|
|
end
|
|
end
|
|
|
|
context "without site setting groups assigned" do
|
|
it "publishes to MessageBus with the setting name and value" do
|
|
messages =
|
|
MessageBus.track_publish(SiteSettingExtension::CLIENT_SETTINGS_CHANNEL) do
|
|
SiteSetting.notify_clients!(:enable_upload_debug_mode)
|
|
end
|
|
|
|
expect(messages.length).to eq(1)
|
|
expect(messages.first.data[:name]).to eq(:enable_upload_debug_mode)
|
|
expect(messages.first.data[:value]).to eq(SiteSetting.enable_upload_debug_mode)
|
|
end
|
|
end
|
|
end
|
|
|
|
context "when the site setting is not an upcoming change" do
|
|
it "publishes to MessageBus with the setting name and value" do
|
|
messages =
|
|
MessageBus.track_publish(SiteSettingExtension::CLIENT_SETTINGS_CHANNEL) do
|
|
SiteSetting.notify_clients!(:title)
|
|
end
|
|
|
|
expect(messages.length).to eq(1)
|
|
expect(messages.first.data[:name]).to eq(:title)
|
|
expect(messages.first.data[:value]).to eq(SiteSetting.title)
|
|
end
|
|
|
|
it "includes scoped_to parameter when provided" do
|
|
messages =
|
|
MessageBus.track_publish(SiteSettingExtension::CLIENT_SETTINGS_CHANNEL) do
|
|
SiteSetting.notify_clients!(:title, { theme_id: 123 })
|
|
end
|
|
|
|
expect(messages.length).to eq(1)
|
|
expect(messages.first.data[:scoped_to]).to eq({ theme_id: 123 })
|
|
end
|
|
end
|
|
|
|
context "with default_locale setting" do
|
|
it "uses the custom getter for default_locale" do
|
|
messages =
|
|
MessageBus.track_publish(SiteSettingExtension::CLIENT_SETTINGS_CHANNEL) do
|
|
SiteSetting.notify_clients!(:default_locale)
|
|
end
|
|
|
|
expect(messages.length).to eq(1)
|
|
expect(messages.first.data[:name]).to eq(:default_locale)
|
|
expect(messages.first.data[:value]).to eq(SiteSetting.default_locale)
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "themeable settings" do
|
|
fab!(:theme_1, :theme)
|
|
fab!(:theme_2, :theme)
|
|
fab!(:tss_1) do
|
|
Fabricate(
|
|
:theme_site_setting_with_service,
|
|
name: "enable_welcome_banner",
|
|
value: false,
|
|
theme: theme_1,
|
|
)
|
|
end
|
|
fab!(:tss_2) do
|
|
Fabricate(
|
|
:theme_site_setting_with_service,
|
|
name: "search_experience",
|
|
value: "search_field",
|
|
theme: theme_2,
|
|
)
|
|
end
|
|
|
|
it "has the site setting default values when there are no theme site settings for the theme" do
|
|
SiteSetting.refresh!
|
|
expect(SiteSetting.theme_site_settings[theme_1.id][:search_experience]).to eq("search_icon")
|
|
expect(SiteSetting.theme_site_settings[theme_2.id][:enable_welcome_banner]).to eq(true)
|
|
end
|
|
|
|
it "returns true for settings that are themeable" do
|
|
expect(SiteSetting.themeable[:enable_welcome_banner]).to eq(true)
|
|
end
|
|
|
|
it "returns false for settings that are not themeable" do
|
|
expect(SiteSetting.themeable[:title]).to eq(false)
|
|
end
|
|
|
|
it "caches the theme site setting values on a per theme basis" do
|
|
SiteSetting.refresh!
|
|
expect(SiteSetting.theme_site_settings[theme_1.id][:enable_welcome_banner]).to eq(false)
|
|
expect(SiteSetting.theme_site_settings[theme_2.id][:search_experience]).to eq("search_field")
|
|
end
|
|
|
|
it "overrides the site setting value with the theme site setting" do
|
|
SiteSetting.create!(
|
|
name: "enable_welcome_banner",
|
|
data_type: SiteSettings::TypeSupervisor.types[:bool],
|
|
value: "t",
|
|
)
|
|
SiteSetting.create!(
|
|
name: "search_experience",
|
|
data_type: SiteSettings::TypeSupervisor.types[:enum],
|
|
value: SiteSetting.type_supervisor.to_db_value(:search_experience, "search_icon"),
|
|
)
|
|
SiteSetting.refresh!
|
|
expect(SiteSetting.enable_welcome_banner(theme_id: theme_1.id)).to eq(false)
|
|
expect(SiteSetting.enable_welcome_banner(theme_id: theme_2.id)).to eq(true)
|
|
expect(SiteSetting.search_experience(theme_id: theme_1.id)).to eq("search_icon")
|
|
expect(SiteSetting.search_experience(theme_id: theme_2.id)).to eq("search_field")
|
|
end
|
|
|
|
it "publishes the right MessageBus message when a theme site setting is updated" do
|
|
settings_tss_instance_1 = new_settings(provider_local)
|
|
settings_tss_instance_1.load_settings(File.join(Rails.root, "config", "site_settings.yml"))
|
|
settings_tss_instance_1.refresh!
|
|
|
|
expect(settings_tss_instance_1.enable_welcome_banner(theme_id: theme_1.id)).to eq(false)
|
|
|
|
tss_1.update!(value: true)
|
|
|
|
messages =
|
|
MessageBus.track_publish(described_class::SITE_SETTINGS_CHANNEL) do
|
|
settings_tss_instance_1.change_themeable_site_setting(
|
|
theme_1.id,
|
|
:enable_welcome_banner,
|
|
true,
|
|
)
|
|
end
|
|
|
|
expect(messages.length).to eq(1)
|
|
|
|
message = messages.first
|
|
|
|
expect(message.data[:process]).to eq(settings_tss_instance_1.process_id)
|
|
end
|
|
|
|
describe ".theme_site_settings_json_uncached" do
|
|
it "returns the correct JSON" do
|
|
SiteSetting.refresh!
|
|
expect(SiteSetting.theme_site_settings_json_uncached(theme_1.id)).to eq(
|
|
%Q|{"enable_welcome_banner":false,"search_experience":"search_icon"}|,
|
|
)
|
|
end
|
|
|
|
it "returns default JSON when the theme_id is null" do
|
|
SiteSetting.refresh!
|
|
expect(SiteSetting.theme_site_settings_json_uncached(nil)).to eq(
|
|
%Q|{"enable_welcome_banner":true,"search_experience":"search_icon"}|,
|
|
)
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "_map extension for list settings" do
|
|
it "handles splitting group_list settings" do
|
|
SiteSetting.personal_message_enabled_groups = "1|2"
|
|
expect(SiteSetting.personal_message_enabled_groups_map).to eq([1, 2])
|
|
end
|
|
|
|
it "handles splitting category_list settings" do
|
|
SiteSetting.digest_suppress_categories = "3|4"
|
|
expect(SiteSetting.digest_suppress_categories_map).to eq([3, 4])
|
|
end
|
|
|
|
it "handles splitting compact list settings" do
|
|
SiteSetting.markdown_linkify_tlds = "com|net"
|
|
expect(SiteSetting.markdown_linkify_tlds_map).to eq(%w[com net])
|
|
end
|
|
|
|
it "handles splitting simple list settings" do
|
|
SiteSetting.ga_universal_auto_link_domains = "test.com|xy.com"
|
|
expect(SiteSetting.ga_universal_auto_link_domains_map).to eq(%w[test.com xy.com])
|
|
end
|
|
|
|
it "handles splitting list settings with no type" do
|
|
SiteSetting.post_menu = "read|like"
|
|
expect(SiteSetting.post_menu_map).to eq(%w[read like])
|
|
end
|
|
|
|
it "does not handle splitting secret list settings" do
|
|
SiteSetting.discourse_connect_provider_secrets = "test|secret1\ntest2|secret2"
|
|
expect(SiteSetting.respond_to?(:discourse_connect_provider_secrets_map)).to eq(false)
|
|
end
|
|
|
|
it "handles splitting emoji_list settings" do
|
|
SiteSetting.emoji_deny_list = "smile|frown"
|
|
expect(SiteSetting.emoji_deny_list_map).to eq(%w[smile frown])
|
|
end
|
|
|
|
it "handles splitting tag_list settings" do
|
|
SiteSetting.digest_suppress_tags = "blah|blah2"
|
|
expect(SiteSetting.digest_suppress_tags_map).to eq(%w[blah blah2])
|
|
end
|
|
|
|
it "handles blank values for settings" do
|
|
SiteSetting.ga_universal_auto_link_domains = ""
|
|
SiteSetting.pm_tags_allowed_for_groups = ""
|
|
SiteSetting.exclude_rel_nofollow_domains = ""
|
|
|
|
expect(SiteSetting.ga_universal_auto_link_domains_map).to eq([])
|
|
expect(SiteSetting.pm_tags_allowed_for_groups_map).to eq([])
|
|
expect(SiteSetting.exclude_rel_nofollow_domains_map).to eq([])
|
|
end
|
|
end
|
|
|
|
describe "keywords" do
|
|
it "gets the list of I18n keywords for the setting" do
|
|
expect(SiteSetting.keywords(:clean_up_inactive_users_after_days)).to eq(
|
|
I18n.t("site_settings.keywords.clean_up_inactive_users_after_days").split("|"),
|
|
)
|
|
end
|
|
|
|
it "gets the current locale keywords and the english keywords for the setting" do
|
|
I18n.locale = :de
|
|
expect(SiteSetting.keywords(:clean_up_inactive_users_after_days)).to match_array(
|
|
(
|
|
I18n.t("site_settings.keywords.clean_up_inactive_users_after_days").split("|") +
|
|
I18n.t("site_settings.keywords.clean_up_inactive_users_after_days", locale: :en).split(
|
|
"|",
|
|
)
|
|
).flatten,
|
|
)
|
|
end
|
|
|
|
context "when a setting also has an alias after renaming" do
|
|
before { SiteSetting.stubs(:deprecated_setting_alias).returns("some_old_setting") }
|
|
|
|
it "is included with the keywords" do
|
|
expect(SiteSetting.keywords(:clean_up_inactive_users_after_days)).to include(
|
|
"some_old_setting",
|
|
)
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "humanized_name" do
|
|
it "returns the humanized name for a setting" do
|
|
expect(SiteSetting.humanized_name(:clean_up_inactive_users_after_days)).to eq(
|
|
"Clean up inactive users after days",
|
|
)
|
|
end
|
|
|
|
it "handles acronyms in setting names" do
|
|
expect(SiteSetting.humanized_name(:enable_linkedin_oidc_logins)).to eq(
|
|
"Enable LinkedIn OIDC logins",
|
|
)
|
|
end
|
|
|
|
it "handles mixed case in setting names" do
|
|
expect(SiteSetting.humanized_name(:opengraph_image)).to eq("OpenGraph image")
|
|
end
|
|
end
|
|
|
|
describe "logging Site Settings via the Rails Console" do
|
|
around do |example|
|
|
# Ensure Rails::Console is defined for the duration of each example.
|
|
if !Rails.const_defined?(:Console)
|
|
Rails.const_set("Console", Module.new)
|
|
example.run
|
|
Rails.send(:remove_const, "Console")
|
|
else
|
|
example.run
|
|
end
|
|
end
|
|
|
|
before do
|
|
settings.setting(:log_test, "initial")
|
|
settings.refresh!
|
|
end
|
|
|
|
context "when using the direct setter" do
|
|
it "logs the change exactly once" do
|
|
logger_spy = instance_spy(StaffActionLogger)
|
|
allow(StaffActionLogger).to receive(:new).with(Discourse.system_user).and_return(logger_spy)
|
|
|
|
settings.log_test = "changed"
|
|
expect(settings.log_test).to eq("changed")
|
|
expect(logger_spy).to have_received(:log_site_setting_change).with(
|
|
:log_test,
|
|
"initial",
|
|
"changed",
|
|
{ details: "Updated via Rails console" },
|
|
).once
|
|
end
|
|
end
|
|
|
|
context "when using set_and_log" do
|
|
it "logs the change exactly once without double logging" do
|
|
logger_spy = instance_spy(StaffActionLogger)
|
|
allow(StaffActionLogger).to receive(:new).with(Discourse.system_user).and_return(logger_spy)
|
|
|
|
settings.set_and_log("log_test", "changed", Discourse.system_user)
|
|
expect(settings.log_test).to eq("changed")
|
|
expect(logger_spy).to have_received(:log_site_setting_change).with(
|
|
:log_test,
|
|
"initial",
|
|
"changed",
|
|
{ details: "Updated via Rails console" },
|
|
).once
|
|
end
|
|
end
|
|
|
|
context "for secret settings" do
|
|
before do
|
|
settings.setting(:secret_test, "old_secret", secret: true)
|
|
settings.refresh!
|
|
end
|
|
|
|
it "logs filtered values" do
|
|
logger_spy = instance_spy(StaffActionLogger)
|
|
allow(StaffActionLogger).to receive(:new).with(Discourse.system_user).and_return(logger_spy)
|
|
|
|
settings.secret_test = "new_secret"
|
|
expect(settings.secret_test).to eq("new_secret")
|
|
expect(logger_spy).to have_received(:log_site_setting_change).with(
|
|
:secret_test,
|
|
"[FILTERED]",
|
|
"[FILTERED]",
|
|
{ details: "Updated via Rails console" },
|
|
).once
|
|
end
|
|
end
|
|
|
|
context "for hidden settings" do
|
|
before do
|
|
settings.setting(:hidden_test, "old_hidden", hidden: true)
|
|
settings.refresh!
|
|
end
|
|
|
|
it "does not log the change" do
|
|
logger_spy = instance_spy(StaffActionLogger)
|
|
allow(StaffActionLogger).to receive(:new).with(Discourse.system_user).and_return(logger_spy)
|
|
|
|
settings.hidden_test = "changed"
|
|
expect(settings.hidden_test).to eq("changed")
|
|
expect(logger_spy).not_to have_received(:log_site_setting_change)
|
|
end
|
|
end
|
|
|
|
context "with plugin modifiers for log details" do
|
|
before do
|
|
settings.setting(:plugin_test, "initial")
|
|
settings.refresh!
|
|
end
|
|
|
|
it "uses the default log details when no plugin modifiers exist" do
|
|
logger_spy = instance_spy(StaffActionLogger)
|
|
allow(StaffActionLogger).to receive(:new).with(Discourse.system_user).and_return(logger_spy)
|
|
|
|
settings.plugin_test = "changed"
|
|
expect(settings.plugin_test).to eq("changed")
|
|
expect(logger_spy).to have_received(:log_site_setting_change).with(
|
|
:plugin_test,
|
|
"initial",
|
|
"changed",
|
|
{ details: "Updated via Rails console" },
|
|
).once
|
|
end
|
|
|
|
it "applies plugin modifiers to log details" do
|
|
# Allow all apply_modifier calls to pass through normally
|
|
allow(DiscoursePluginRegistry).to receive(:apply_modifier).and_call_original
|
|
|
|
# But specifically mock our target call
|
|
allow(DiscoursePluginRegistry).to receive(:apply_modifier).with(
|
|
:site_setting_log_details,
|
|
"Updated via Rails console",
|
|
).and_return("Updated via Rails console via test plugin")
|
|
|
|
logger_spy = instance_spy(StaffActionLogger)
|
|
allow(StaffActionLogger).to receive(:new).with(Discourse.system_user).and_return(logger_spy)
|
|
|
|
settings.plugin_test = "changed"
|
|
expect(settings.plugin_test).to eq("changed")
|
|
expect(logger_spy).to have_received(:log_site_setting_change).with(
|
|
:plugin_test,
|
|
"initial",
|
|
"changed",
|
|
{ details: "Updated via Rails console via test plugin" },
|
|
).once
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "upcoming_change_default_override" do
|
|
before do
|
|
settings.setting(
|
|
:increase_suggested_topics_max_days_old_default,
|
|
false,
|
|
upcoming_change: {
|
|
status: :experimental,
|
|
impact: "site_setting_default,all_members",
|
|
},
|
|
)
|
|
settings.setting(
|
|
:suggested_topics_max_days_old,
|
|
365,
|
|
upcoming_change_default_override: {
|
|
upcoming_change: "increase_suggested_topics_max_days_old_default",
|
|
new_default: 1000,
|
|
},
|
|
)
|
|
settings.setting(:promote_upcoming_changes_on_status, "stable")
|
|
UpcomingChanges.stubs(:settings_provider).returns(settings)
|
|
end
|
|
|
|
context "when the linked upcoming change is active" do
|
|
before do
|
|
settings.provider.save(
|
|
:increase_suggested_topics_max_days_old_default,
|
|
true,
|
|
SiteSetting.types[:bool],
|
|
)
|
|
settings.refresh!
|
|
end
|
|
|
|
it "returns the override default" do
|
|
expect(settings.suggested_topics_max_days_old).to eq(1000)
|
|
end
|
|
end
|
|
|
|
context "when the linked upcoming change is not active" do
|
|
it "returns the YAML default" do
|
|
expect(settings.suggested_topics_max_days_old).to eq(365)
|
|
end
|
|
end
|
|
|
|
context "when the linked upcoming change is enabled via add_override!" do
|
|
it "immediately applies the override default without needing refresh!" do
|
|
settings.add_override!(:increase_suggested_topics_max_days_old_default, true)
|
|
expect(settings.suggested_topics_max_days_old).to eq(1000)
|
|
end
|
|
|
|
it "immediately reverts the override default when disabled" do
|
|
settings.add_override!(:increase_suggested_topics_max_days_old_default, true)
|
|
expect(settings.suggested_topics_max_days_old).to eq(1000)
|
|
settings.add_override!(:increase_suggested_topics_max_days_old_default, false)
|
|
expect(settings.suggested_topics_max_days_old).to eq(365)
|
|
end
|
|
|
|
it "does not override a manually set target setting value" do
|
|
settings.add_override!(:suggested_topics_max_days_old, 730)
|
|
settings.add_override!(:increase_suggested_topics_max_days_old_default, true)
|
|
expect(settings.suggested_topics_max_days_old).to eq(730)
|
|
end
|
|
end
|
|
|
|
context "when the linked upcoming change is reset via remove_override!" do
|
|
it "immediately reverts the override default" do
|
|
settings.add_override!(:increase_suggested_topics_max_days_old_default, true)
|
|
expect(settings.suggested_topics_max_days_old).to eq(1000)
|
|
|
|
settings.remove_override!(:increase_suggested_topics_max_days_old_default)
|
|
|
|
expect(settings.increase_suggested_topics_max_days_old_default).to eq(false)
|
|
expect(settings.suggested_topics_max_days_old).to eq(365)
|
|
expect(
|
|
settings.defaults.upcoming_change_override_metadata(:suggested_topics_max_days_old),
|
|
).to be_nil
|
|
end
|
|
|
|
it "reapplies the override default when a manual opt out is removed after auto-promotion" do
|
|
settings.add_override!(:promote_upcoming_changes_on_status, "experimental")
|
|
settings.refresh!
|
|
expect(settings.suggested_topics_max_days_old).to eq(1000)
|
|
|
|
settings.add_override!(:increase_suggested_topics_max_days_old_default, false)
|
|
expect(settings.suggested_topics_max_days_old).to eq(365)
|
|
|
|
settings.remove_override!(:increase_suggested_topics_max_days_old_default)
|
|
|
|
expect(settings.increase_suggested_topics_max_days_old_default).to eq(true)
|
|
expect(settings.suggested_topics_max_days_old).to eq(1000)
|
|
end
|
|
end
|
|
|
|
context "when admin opts out of the target setting after the override is active" do
|
|
before do
|
|
settings.provider.save(
|
|
:increase_suggested_topics_max_days_old_default,
|
|
true,
|
|
SiteSetting.types[:bool],
|
|
)
|
|
settings.refresh!
|
|
end
|
|
|
|
it "preserves the admin's explicit value across refresh, even when it equals the original default" do
|
|
expect(settings.suggested_topics_max_days_old).to eq(1000)
|
|
|
|
settings.provider.save(:suggested_topics_max_days_old, 365, SiteSetting.types[:integer])
|
|
settings.refresh!
|
|
|
|
expect(settings.suggested_topics_max_days_old).to eq(365)
|
|
end
|
|
end
|
|
|
|
describe "all_settings effective default" do
|
|
context "when the linked upcoming change is active" do
|
|
before do
|
|
UpcomingChanges.stubs(:settings_provider).returns(settings)
|
|
settings.provider.save(
|
|
:increase_suggested_topics_max_days_old_default,
|
|
true,
|
|
SiteSetting.types[:bool],
|
|
)
|
|
settings.refresh!
|
|
end
|
|
|
|
it "shows the override default in all_settings" do
|
|
setting = settings.all_settings.find { |s| s[:setting] == :suggested_topics_max_days_old }
|
|
expect(setting[:default]).to eq("1000")
|
|
end
|
|
|
|
it "does not show the setting as overridden when value matches effective default" do
|
|
setting = settings.all_settings.find { |s| s[:setting] == :suggested_topics_max_days_old }
|
|
expect(setting[:value]).to eq(setting[:default])
|
|
end
|
|
end
|
|
|
|
context "when the linked upcoming change is not active" do
|
|
it "shows the original YAML default in all_settings" do
|
|
setting = settings.all_settings.find { |s| s[:setting] == :suggested_topics_max_days_old }
|
|
expect(setting[:default]).to eq("365")
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|