mirror of
https://github.com/discourse/discourse.git
synced 2024-11-27 10:25:49 +08:00
9f884cdaab
Why this change? This commit introduces an experimental `type: objects` theme setting which will allow theme developers to store a collection of objects as JSON in the database. Currently, the feature is still in development and this commit is simply setting up the ground work for us to introduce the feature in smaller pieces. What does this change do? 1. Adds a `json_value` column as `jsonb` data type to the `theme_settings` table. 2. Adds a `experimental_objects_type_for_theme_settings` site setting to determine whether `ThemeSetting` records of with the `objects` data type can be created. 3. Updates `ThemeSettingsManager` to support read/write access from the `ThemeSettings#json_value` column.
79 lines
2.3 KiB
Ruby
79 lines
2.3 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
class ThemeSettingsParser
|
|
class InvalidYaml < StandardError
|
|
end
|
|
|
|
def initialize(setting_field)
|
|
@setting_field = setting_field
|
|
@types = ThemeSetting.types
|
|
end
|
|
|
|
def extract_description(desc)
|
|
return desc if desc.is_a?(String)
|
|
|
|
if desc.is_a?(Hash)
|
|
default_locale = SiteSetting.default_locale.to_sym
|
|
fallback_locale = desc.keys.find { |key| I18n.locale_available?(key) }
|
|
locale = desc[I18n.locale] || desc[default_locale] || desc[:en] || desc[fallback_locale]
|
|
|
|
locale if locale.is_a?(String)
|
|
end
|
|
end
|
|
|
|
def create_opts(default, type, raw_opts = {})
|
|
opts = {}
|
|
opts[:description] = extract_description(raw_opts[:description])
|
|
|
|
if type == @types[:enum]
|
|
choices = raw_opts[:choices]
|
|
choices = [] unless choices.is_a?(Array)
|
|
choices << default unless choices.include?(default)
|
|
opts[:choices] = choices
|
|
end
|
|
|
|
if [@types[:integer], @types[:string], @types[:float]].include?(type)
|
|
opts[:max] = raw_opts[:max].is_a?(Numeric) ? raw_opts[:max] : Float::INFINITY
|
|
opts[:min] = raw_opts[:min].is_a?(Numeric) ? raw_opts[:min] : -Float::INFINITY
|
|
end
|
|
|
|
opts[:list_type] = raw_opts[:list_type] if raw_opts[:list_type]
|
|
|
|
opts[:textarea] = !!raw_opts[:textarea]
|
|
opts[:json_schema] = raw_opts[:json_schema]
|
|
opts[:schema] = raw_opts[:schema]
|
|
|
|
opts[:refresh] = !!raw_opts[:refresh]
|
|
|
|
opts
|
|
end
|
|
|
|
def load
|
|
return if @setting_field.value.blank?
|
|
|
|
begin
|
|
parsed = YAML.safe_load(@setting_field.value)
|
|
rescue Psych::SyntaxError, Psych::DisallowedClass => e
|
|
raise InvalidYaml.new(e.message)
|
|
end
|
|
raise InvalidYaml.new(I18n.t("themes.settings_errors.invalid_yaml")) unless parsed.is_a?(Hash)
|
|
|
|
parsed.deep_symbolize_keys!
|
|
|
|
parsed.each_pair do |setting, value|
|
|
if (type = ThemeSetting.guess_type(value)).present?
|
|
result = [setting, value, type, create_opts(value, type)]
|
|
elsif (hash = value).is_a?(Hash)
|
|
default = hash[:default]
|
|
type = hash.key?(:type) ? @types[hash[:type]&.to_sym] : ThemeSetting.guess_type(default)
|
|
|
|
result = [setting, default, type, create_opts(default, type, hash)]
|
|
else
|
|
result = [setting, value, nil, {}]
|
|
end
|
|
|
|
yield(*result)
|
|
end
|
|
end
|
|
end
|