mirror of
https://github.com/opf/openproject.git
synced 2026-06-14 03:30:14 +00:00
Allow settings to be overridden for writable and values from plugins
This commit is contained in:
@@ -1428,6 +1428,10 @@ module Settings
|
||||
end
|
||||
|
||||
def value
|
||||
unless (override = resolve_value_override).nil?
|
||||
return cast(override)
|
||||
end
|
||||
|
||||
cast(@value)
|
||||
end
|
||||
|
||||
@@ -1444,6 +1448,8 @@ module Settings
|
||||
end
|
||||
|
||||
def writable?
|
||||
return false if value_override?
|
||||
|
||||
if writable.respond_to?(:call)
|
||||
writable.call
|
||||
else
|
||||
@@ -1567,6 +1573,38 @@ module Settings
|
||||
@all ||= {}
|
||||
end
|
||||
|
||||
# Registers a value override block for a setting. The block is called
|
||||
# whenever the setting's value or writability is evaluated.
|
||||
#
|
||||
# If the block returns a non-nil value, that value is used as the setting's
|
||||
# value and the setting becomes non-writable. If the block returns nil,
|
||||
# no override is applied.
|
||||
#
|
||||
# To override a setting with nil, return a callable: +-> { nil }+
|
||||
#
|
||||
# @param name [Symbol] The setting name to override.
|
||||
# @yield A block that returns the override value, or nil to skip.
|
||||
#
|
||||
# @example Force a setting to true when a condition is met
|
||||
# Settings::Definition.add_value_override(:capture_external_links) do
|
||||
# true if MyPlugin.active?
|
||||
# end
|
||||
def add_value_override(name, &block)
|
||||
(value_overrides[name.to_sym] ||= []) << block
|
||||
end
|
||||
|
||||
def value_overrides
|
||||
@value_overrides ||= {}
|
||||
end
|
||||
|
||||
def clear_value_overrides(name = nil)
|
||||
if name
|
||||
value_overrides.delete(name.to_sym)
|
||||
else
|
||||
@value_overrides = {}
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def file_config
|
||||
@@ -1760,6 +1798,18 @@ module Settings
|
||||
attr_accessor :serialized,
|
||||
:writable
|
||||
|
||||
def value_override?
|
||||
!resolve_value_override.nil?
|
||||
end
|
||||
|
||||
def resolve_value_override
|
||||
self.class.value_overrides[name.to_sym]&.each do |block|
|
||||
result = block.call
|
||||
return result unless result.nil?
|
||||
end
|
||||
nil
|
||||
end
|
||||
|
||||
def cast(value)
|
||||
return nil if value.nil?
|
||||
|
||||
|
||||
@@ -1053,4 +1053,149 @@ RSpec.describe Settings::Definition, :settings_reset do
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe ".add_value_override" do
|
||||
before do
|
||||
described_class.add "bogus_override_test",
|
||||
default: false,
|
||||
format: :boolean
|
||||
end
|
||||
|
||||
after do
|
||||
described_class.clear_value_overrides(:bogus_override_test)
|
||||
end
|
||||
|
||||
context "when the override block returns a non-nil value" do
|
||||
before do
|
||||
described_class.add_value_override(:bogus_override_test) do
|
||||
true
|
||||
end
|
||||
end
|
||||
|
||||
it "uses the returned value as the setting value" do
|
||||
expect(described_class[:bogus_override_test].value).to be true
|
||||
end
|
||||
|
||||
it "marks the setting as non-writable" do
|
||||
expect(described_class[:bogus_override_test]).not_to be_writable
|
||||
end
|
||||
end
|
||||
|
||||
context "when the override block returns nil" do
|
||||
before do
|
||||
described_class.add_value_override(:bogus_override_test) do
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
it "uses the original default value" do
|
||||
expect(described_class[:bogus_override_test].value).to be false
|
||||
end
|
||||
|
||||
it "keeps the setting writable" do
|
||||
expect(described_class[:bogus_override_test]).to be_writable
|
||||
end
|
||||
end
|
||||
|
||||
context "when the override block returns a callable" do
|
||||
before do
|
||||
described_class.add_value_override(:bogus_override_test) do
|
||||
-> { nil }
|
||||
end
|
||||
end
|
||||
|
||||
it "calls it to obtain the value, allowing override with nil" do
|
||||
expect(described_class[:bogus_override_test].value).to be_nil
|
||||
end
|
||||
|
||||
it "marks the setting as non-writable" do
|
||||
expect(described_class[:bogus_override_test]).not_to be_writable
|
||||
end
|
||||
end
|
||||
|
||||
context "when the override is conditional" do
|
||||
let(:condition) { true }
|
||||
|
||||
before do
|
||||
cond = condition
|
||||
described_class.add_value_override(:bogus_override_test) do
|
||||
true if cond
|
||||
end
|
||||
end
|
||||
|
||||
context "when condition is met" do
|
||||
let(:condition) { true }
|
||||
|
||||
it "overrides the value" do
|
||||
expect(described_class[:bogus_override_test].value).to be true
|
||||
end
|
||||
|
||||
it "is non-writable" do
|
||||
expect(described_class[:bogus_override_test]).not_to be_writable
|
||||
end
|
||||
end
|
||||
|
||||
context "when condition is not met" do
|
||||
let(:condition) { false }
|
||||
|
||||
it "uses the original value" do
|
||||
expect(described_class[:bogus_override_test].value).to be false
|
||||
end
|
||||
|
||||
it "remains writable" do
|
||||
expect(described_class[:bogus_override_test]).to be_writable
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "with multiple override blocks" do
|
||||
before do
|
||||
described_class.add "bogus_multi_override_test",
|
||||
default: "original",
|
||||
format: :string
|
||||
|
||||
described_class.add_value_override(:bogus_multi_override_test) do
|
||||
nil
|
||||
end
|
||||
described_class.add_value_override(:bogus_multi_override_test) do
|
||||
"from_second"
|
||||
end
|
||||
described_class.add_value_override(:bogus_multi_override_test) do
|
||||
"from_third"
|
||||
end
|
||||
end
|
||||
|
||||
after do
|
||||
described_class.clear_value_overrides(:bogus_multi_override_test)
|
||||
end
|
||||
|
||||
it "uses the first block that returns a non-nil value" do
|
||||
expect(described_class[:bogus_multi_override_test].value).to eq "from_second"
|
||||
end
|
||||
end
|
||||
|
||||
context "when the setting is already non-writable" do
|
||||
before do
|
||||
described_class.add "bogus_non_writable_test",
|
||||
default: "original",
|
||||
format: :string,
|
||||
writable: false
|
||||
described_class.add_value_override(:bogus_non_writable_test) do
|
||||
"overridden"
|
||||
end
|
||||
end
|
||||
|
||||
after do
|
||||
described_class.clear_value_overrides(:bogus_non_writable_test)
|
||||
end
|
||||
|
||||
it "overrides the value" do
|
||||
expect(described_class[:bogus_non_writable_test].value).to eq "overridden"
|
||||
end
|
||||
|
||||
it "remains non-writable" do
|
||||
expect(described_class[:bogus_non_writable_test]).not_to be_writable
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user