Can't revert due to incompatibility of new site setting types.
Revert "Revert "FEATURE: Site settings defaults per locale""
This reverts commit 439fe8ba24
.
This commit is contained in:
parent
439fe8ba24
commit
3f24ed2b3e
|
@ -64,16 +64,16 @@ export default Ember.Component.extend(BufferedContent, {
|
|||
}.on("willDestroyElement"),
|
||||
|
||||
_save() {
|
||||
const self = this,
|
||||
setting = this.get('buffered');
|
||||
SiteSetting.update(setting.get('setting'), setting.get('value')).then(function() {
|
||||
self.set('validationMessage', null);
|
||||
self.commitBuffer();
|
||||
}).catch(function(e) {
|
||||
const setting = this.get('buffered'),
|
||||
action = SiteSetting.update(setting.get('setting'), setting.get('value'));
|
||||
action.then(() => {
|
||||
this.set('validationMessage', null);
|
||||
this.commitBuffer();
|
||||
}).catch((e) => {
|
||||
if (e.jqXHR.responseJSON && e.jqXHR.responseJSON.errors) {
|
||||
self.set('validationMessage', e.jqXHR.responseJSON.errors[0]);
|
||||
this.set('validationMessage', e.jqXHR.responseJSON.errors[0]);
|
||||
} else {
|
||||
self.set('validationMessage', I18n.t('generic_error'));
|
||||
this.set('validationMessage', I18n.t('generic_error'));
|
||||
}
|
||||
});
|
||||
},
|
||||
|
|
|
@ -48,7 +48,7 @@ SiteSetting.reopenClass({
|
|||
update(key, value) {
|
||||
const data = {};
|
||||
data[key] = value;
|
||||
return ajax("/admin/site_settings/" + key, { type: 'PUT', data });
|
||||
return ajax(`/admin/site_settings/${key}`, { type: 'PUT', data });
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
class Admin::SiteSettingsController < Admin::AdminController
|
||||
rescue_from Discourse::InvalidParameters do |e|
|
||||
render_json_error e.message, status: 422
|
||||
end
|
||||
|
||||
def index
|
||||
render_json_dump(site_settings: SiteSetting.all_settings, diags: SiteSetting.diags)
|
||||
|
@ -9,15 +12,17 @@ class Admin::SiteSettingsController < Admin::AdminController
|
|||
id = params[:id]
|
||||
value = params[id]
|
||||
value.strip! if value.is_a?(String)
|
||||
begin
|
||||
# note, as of Ruby 2.3 symbols are GC'd so this is considered safe
|
||||
if SiteSetting.hidden_settings.include?(id.to_sym)
|
||||
raise Discourse::InvalidParameters, "You are not allowed to change hidden settings"
|
||||
end
|
||||
SiteSetting.set_and_log(id, value, current_user)
|
||||
render nothing: true
|
||||
rescue Discourse::InvalidParameters => e
|
||||
render json: { errors: [e.message] }, status: 422
|
||||
raise_access_hidden_setting(id)
|
||||
SiteSetting.set_and_log(id, value, current_user)
|
||||
render nothing: true
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def raise_access_hidden_setting(id)
|
||||
# note, as of Ruby 2.3 symbols are GC'd so this is considered safe
|
||||
if SiteSetting.hidden_settings.include?(id.to_sym)
|
||||
raise Discourse::InvalidParameters, "You are not allowed to change hidden settings"
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -14,11 +14,7 @@ class SiteSetting < ActiveRecord::Base
|
|||
|
||||
def self.load_settings(file)
|
||||
SiteSettings::YamlLoader.new(file).load do |category, name, default, opts|
|
||||
if opts.delete(:client)
|
||||
client_setting(name, default, opts.merge(category: category))
|
||||
else
|
||||
setting(name, default, opts.merge(category: category))
|
||||
end
|
||||
setting(name, default, opts.merge(category: category))
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -31,6 +27,11 @@ class SiteSetting < ActiveRecord::Base
|
|||
end
|
||||
end
|
||||
|
||||
# `current` hash is not populated everytime when load a site setting
|
||||
# in order to support locale default. Instead, we simply `refresh!` once.
|
||||
# This should only affects the spec in which you should populate `current`
|
||||
refresh!
|
||||
|
||||
client_settings << :available_locales
|
||||
|
||||
def self.available_locales
|
||||
|
|
|
@ -59,6 +59,9 @@ Discourse::Application.configure do
|
|||
end
|
||||
|
||||
config.after_initialize do
|
||||
SiteSetting.defaults.set_regardless_of_locale(:port, 3000)
|
||||
SiteSetting.refresh!
|
||||
|
||||
if ENV['BULLET']
|
||||
Bullet.enable = true
|
||||
Bullet.rails_logger = true
|
||||
|
|
|
@ -46,4 +46,22 @@ Discourse::Application.configure do
|
|||
config.logger = Logger.new(nil)
|
||||
config.log_level = :fatal
|
||||
end
|
||||
|
||||
config.after_initialize do
|
||||
SiteSetting.defaults.tap do |s|
|
||||
s.set_regardless_of_locale(:s3_upload_bucket, 'bucket')
|
||||
s.set_regardless_of_locale(:min_post_length, 5)
|
||||
s.set_regardless_of_locale(:min_first_post_length, 5)
|
||||
s.set_regardless_of_locale(:min_private_message_post_length, 10)
|
||||
s.set_regardless_of_locale(:crawl_images, false)
|
||||
s.set_regardless_of_locale(:download_remote_images_to_local, false)
|
||||
s.set_regardless_of_locale(:unique_posts_mins, 0)
|
||||
s.set_regardless_of_locale(:queue_jobs, false)
|
||||
# disable plugins
|
||||
if ENV['LOAD_PLUGINS'] == '1'
|
||||
s.set_regardless_of_locale(:discourse_narrative_bot_enabled, false)
|
||||
end
|
||||
end
|
||||
SiteSetting.refresh!
|
||||
end
|
||||
end
|
||||
|
|
|
@ -12,6 +12,9 @@
|
|||
# shadowed_by_global - "Shadow" a site setting with a GlobalSetting. If the GlobalSetting
|
||||
# exists it will be used instead of the setting and the setting will be hidden.
|
||||
# Useful for things like API keys on multisite.
|
||||
# locale_default - A hash which overrides according to `SiteSetting.default_locale`.
|
||||
# The key should be as the same as possible value of default_locale.
|
||||
#
|
||||
#
|
||||
# type: email - Must be a valid email address.
|
||||
# type: username - Must match the username of an existing user.
|
||||
|
@ -68,11 +71,6 @@ required:
|
|||
default: ''
|
||||
|
||||
basic:
|
||||
default_locale:
|
||||
default: 'en'
|
||||
enum: 'LocaleSiteSetting'
|
||||
refresh: true
|
||||
shadowed_by_global: true
|
||||
allow_user_locale:
|
||||
client: true
|
||||
default: false
|
||||
|
@ -432,21 +430,24 @@ posting:
|
|||
min_post_length:
|
||||
client: true
|
||||
min: 1
|
||||
default:
|
||||
test: 5
|
||||
default: 20
|
||||
default: 20
|
||||
locale_default:
|
||||
zh_CN: 8
|
||||
zh_TW: 8
|
||||
min_first_post_length:
|
||||
client: true
|
||||
min: 1
|
||||
default:
|
||||
test: 5
|
||||
default: 20
|
||||
default: 20
|
||||
locale_default:
|
||||
zh_CN: 8
|
||||
zh_TW: 8
|
||||
min_private_message_post_length:
|
||||
client: true
|
||||
min: 1
|
||||
default:
|
||||
test: 5
|
||||
default: 10
|
||||
default: 10
|
||||
locale_default:
|
||||
zh_CN: 3
|
||||
zh_TW: 3
|
||||
max_post_length:
|
||||
client: true
|
||||
default: 32000
|
||||
|
@ -454,17 +455,32 @@ posting:
|
|||
topic_featured_link_enabled:
|
||||
client: true
|
||||
default: true
|
||||
body_min_entropy: 7
|
||||
body_min_entropy:
|
||||
default: 7
|
||||
locale_default:
|
||||
zh_CN: 3
|
||||
zh_TW: 3
|
||||
min_topic_title_length:
|
||||
client: true
|
||||
default: 15
|
||||
locale_default:
|
||||
zh_CN: 6
|
||||
zh_TW: 6
|
||||
max_topic_title_length:
|
||||
client: true
|
||||
default: 255
|
||||
max: 255
|
||||
title_min_entropy: 10
|
||||
title_min_entropy:
|
||||
default: 10
|
||||
locale_default:
|
||||
zh_CN: 3
|
||||
zh_TW: 3
|
||||
allow_uppercase_posts: false
|
||||
title_prettify: true
|
||||
title_prettify:
|
||||
default: true
|
||||
locale_default:
|
||||
zh_CN: false
|
||||
zh_TW: false
|
||||
title_fancy_entities: true
|
||||
min_private_message_title_length:
|
||||
client: true
|
||||
|
@ -478,9 +494,15 @@ posting:
|
|||
min_title_similar_length:
|
||||
client: true
|
||||
default: 10
|
||||
locale_default:
|
||||
zh_CN: 4
|
||||
zh_TW: 4
|
||||
min_body_similar_length:
|
||||
client: true
|
||||
default: 15
|
||||
locale_default:
|
||||
zh_CN: 5
|
||||
zh_TW: 5
|
||||
enable_private_messages:
|
||||
default: true
|
||||
client: true
|
||||
|
@ -524,7 +546,11 @@ posting:
|
|||
newuser_max_attachments:
|
||||
client: true
|
||||
default: 0
|
||||
post_excerpt_maxlength: 300
|
||||
post_excerpt_maxlength:
|
||||
default: 300
|
||||
locale_default:
|
||||
zh_CN: 120
|
||||
zh_TW: 120
|
||||
show_pinned_excerpt_mobile:
|
||||
client: true
|
||||
default: true
|
||||
|
@ -603,7 +629,11 @@ email:
|
|||
client: true
|
||||
private_email_time_window_seconds: 20
|
||||
email_posts_context: 5
|
||||
digest_min_excerpt_length: 100
|
||||
digest_min_excerpt_length:
|
||||
default: 100
|
||||
locale_default:
|
||||
zh_CN: 50
|
||||
zh_TW: 50
|
||||
digest_topics:
|
||||
default: 5
|
||||
min: 1
|
||||
|
@ -726,9 +756,7 @@ files:
|
|||
refresh: true
|
||||
type: list
|
||||
crawl_images:
|
||||
default:
|
||||
test: false
|
||||
default: true
|
||||
default: true
|
||||
max_image_width:
|
||||
client: true
|
||||
default: 690
|
||||
|
@ -736,9 +764,7 @@ files:
|
|||
client: true
|
||||
default: 500
|
||||
download_remote_images_to_local:
|
||||
default:
|
||||
test: false
|
||||
default: true
|
||||
default: true
|
||||
download_remote_images_threshold: 10
|
||||
download_remote_images_max_days_old:
|
||||
default: 30
|
||||
|
@ -908,7 +934,11 @@ security:
|
|||
|
||||
onebox:
|
||||
enable_flash_video_onebox: false
|
||||
post_onebox_maxlength: 500
|
||||
post_onebox_maxlength:
|
||||
default: 500
|
||||
locale_default:
|
||||
zh_CN: 200
|
||||
zh_TW: 200
|
||||
onebox_domains_blacklist:
|
||||
default: ''
|
||||
type: list
|
||||
|
@ -954,10 +984,7 @@ spam:
|
|||
auto_block_first_post_regex: ""
|
||||
|
||||
rate_limits:
|
||||
unique_posts_mins:
|
||||
default:
|
||||
test: 0
|
||||
default: 5
|
||||
unique_posts_mins: 5
|
||||
rate_limit_create_topic: 15
|
||||
rate_limit_create_post: 5
|
||||
rate_limit_new_user_create_topic: 120
|
||||
|
@ -995,28 +1022,20 @@ rate_limits:
|
|||
|
||||
developer:
|
||||
force_hostname:
|
||||
hidden:
|
||||
development: false
|
||||
default: true
|
||||
hidden: true
|
||||
default: ''
|
||||
port:
|
||||
hidden:
|
||||
development: false
|
||||
default: true
|
||||
default:
|
||||
development: 3000
|
||||
default: ''
|
||||
hidden: true
|
||||
default: ''
|
||||
queue_jobs:
|
||||
hidden:
|
||||
development: false
|
||||
default: true
|
||||
default:
|
||||
test: false
|
||||
default: true
|
||||
hidden: true
|
||||
default: true
|
||||
enable_long_polling:
|
||||
client: true
|
||||
default: true
|
||||
long_polling_interval: 25000
|
||||
long_polling_interval:
|
||||
default: 25000
|
||||
max: 25000
|
||||
long_polling_base_url:
|
||||
client: true
|
||||
default: '/'
|
||||
|
@ -1144,12 +1163,19 @@ search:
|
|||
min_search_term_length:
|
||||
client: true
|
||||
default: 3
|
||||
locale_default:
|
||||
zh_CN: 2
|
||||
zh_TW: 2
|
||||
|
||||
search_tokenize_chinese_japanese_korean: false
|
||||
search_prefer_recent_posts: false
|
||||
search_recent_posts_size: 100000
|
||||
search_recent_posts_size:
|
||||
default: 100000
|
||||
max: 100000
|
||||
log_search_queries: true
|
||||
search_query_log_max_size: 1000000
|
||||
search_query_log_max_size:
|
||||
default: 1000000
|
||||
max: 1000000
|
||||
|
||||
uncategorized:
|
||||
version_checks:
|
||||
|
@ -1166,6 +1192,9 @@ uncategorized:
|
|||
slug_generation_method:
|
||||
default: 'ascii'
|
||||
enum: 'SlugSetting'
|
||||
locale_default:
|
||||
zh_CN: 'none'
|
||||
zh_TW: 'none'
|
||||
|
||||
permalink_normalizations:
|
||||
default: ''
|
||||
|
@ -1306,6 +1335,9 @@ uncategorized:
|
|||
read_time_word_count:
|
||||
default: 500
|
||||
client: true
|
||||
locale_default:
|
||||
zh_CN: 350
|
||||
zh_TW: 350
|
||||
|
||||
topic_page_title_includes_category: true
|
||||
|
||||
|
@ -1323,7 +1355,7 @@ user_preferences:
|
|||
default_email_mailing_list_mode: false
|
||||
default_email_mailing_list_mode_frequency:
|
||||
enum: 'MailingListModeSiteSetting'
|
||||
default: 0
|
||||
default: 1
|
||||
disable_mailing_list_mode:
|
||||
default: false
|
||||
client: true
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
class CorrectDefaultEmailMailingListModeFrequency < ActiveRecord::Migration
|
||||
def up
|
||||
execute "UPDATE site_settings SET value = '1' WHERE value = '0' AND name = 'default_email_mailing_list_mode_frequency';"
|
||||
end
|
||||
|
||||
def down
|
||||
end
|
||||
end
|
|
@ -84,6 +84,8 @@ module Discourse
|
|||
# Cross site request forgery
|
||||
class CSRF < StandardError; end
|
||||
|
||||
class Deprecation < StandardError; end
|
||||
|
||||
def self.filters
|
||||
@filters ||= [:latest, :unread, :new, :read, :posted, :bookmarks]
|
||||
end
|
||||
|
|
|
@ -1,14 +1,16 @@
|
|||
require_dependency 'enum'
|
||||
require_dependency 'site_settings/deprecated_settings'
|
||||
require_dependency 'site_settings/type_supervisor'
|
||||
require_dependency 'site_settings/defaults_provider'
|
||||
require_dependency 'site_settings/db_provider'
|
||||
require 'site_setting_validations'
|
||||
|
||||
module SiteSettingExtension
|
||||
include SiteSettingValidations
|
||||
include SiteSettings::DeprecatedSettings
|
||||
extend Forwardable
|
||||
|
||||
# For plugins, so they can tell if a feature is supported
|
||||
def supported_types
|
||||
[:email, :username, :list, :enum]
|
||||
end
|
||||
def_delegator :defaults, :site_locale, :default_locale
|
||||
def_delegator :defaults, :site_locale=, :default_locale=
|
||||
def_delegator :defaults, :has_setting?
|
||||
def_delegators 'SiteSettings::TypeSupervisor', :types, :supported_types
|
||||
|
||||
# part 1 of refactor, centralizing the dependency here
|
||||
def provider=(val)
|
||||
|
@ -20,22 +22,6 @@ module SiteSettingExtension
|
|||
@provider ||= SiteSettings::DbProvider.new(SiteSetting)
|
||||
end
|
||||
|
||||
def types
|
||||
@types ||= Enum.new(string: 1,
|
||||
time: 2,
|
||||
integer: 3,
|
||||
float: 4,
|
||||
bool: 5,
|
||||
null: 6,
|
||||
enum: 7,
|
||||
list: 8,
|
||||
url_list: 9,
|
||||
host_list: 10,
|
||||
category_list: 11,
|
||||
value_list: 12,
|
||||
regex: 13)
|
||||
end
|
||||
|
||||
def mutex
|
||||
@mutex ||= Mutex.new
|
||||
end
|
||||
|
@ -46,25 +32,17 @@ module SiteSettingExtension
|
|||
end
|
||||
|
||||
def defaults
|
||||
@defaults ||= {}
|
||||
@defaults ||= SiteSettings::DefaultsProvider.new(self)
|
||||
end
|
||||
|
||||
def type_supervisor
|
||||
@type_supervisor ||= SiteSettings::TypeSupervisor.new(defaults)
|
||||
end
|
||||
|
||||
def categories
|
||||
@categories ||= {}
|
||||
end
|
||||
|
||||
def enums
|
||||
@enums ||= {}
|
||||
end
|
||||
|
||||
def static_types
|
||||
@static_types ||= {}
|
||||
end
|
||||
|
||||
def choices
|
||||
@choices ||= {}
|
||||
end
|
||||
|
||||
def shadowed_settings
|
||||
@shadowed_settings ||= []
|
||||
end
|
||||
|
@ -85,34 +63,14 @@ module SiteSettingExtension
|
|||
@previews ||= {}
|
||||
end
|
||||
|
||||
def validators
|
||||
@validators ||= {}
|
||||
end
|
||||
|
||||
def setting(name_arg, default = nil, opts = {})
|
||||
name = name_arg.to_sym
|
||||
mutex.synchronize do
|
||||
self.defaults[name] = default
|
||||
defaults.load_setting(name,
|
||||
default,
|
||||
opts.extract!(*SiteSettings::DefaultsProvider::CONSUMED_OPTS))
|
||||
|
||||
categories[name] = opts[:category] || :uncategorized
|
||||
current_value = current.has_key?(name) ? current[name] : default
|
||||
|
||||
if enum = opts[:enum]
|
||||
enums[name] = enum.is_a?(String) ? enum.constantize : enum
|
||||
opts[:type] ||= :enum
|
||||
end
|
||||
|
||||
if new_choices = opts[:choices]
|
||||
|
||||
new_choices = eval(new_choices) if new_choices.is_a?(String)
|
||||
|
||||
choices.has_key?(name) ?
|
||||
choices[name].concat(new_choices) :
|
||||
choices[name] = new_choices
|
||||
end
|
||||
|
||||
if type = opts[:type]
|
||||
static_types[name.to_sym] = type.to_sym
|
||||
end
|
||||
|
||||
if opts[:hidden]
|
||||
hidden_settings << name
|
||||
|
@ -124,7 +82,6 @@ module SiteSettingExtension
|
|||
unless val.nil? || (val == ''.freeze)
|
||||
hidden_settings << name
|
||||
shadowed_settings << name
|
||||
current_value = val
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -132,31 +89,24 @@ module SiteSettingExtension
|
|||
refresh_settings << name
|
||||
end
|
||||
|
||||
if opts[:client]
|
||||
client_settings << name.to_sym
|
||||
end
|
||||
|
||||
if opts[:preview]
|
||||
previews[name] = opts[:preview]
|
||||
end
|
||||
|
||||
opts[:validator] = opts[:validator].try(:constantize)
|
||||
type = opts[:type] || get_data_type(name, defaults[name])
|
||||
type_supervisor.load_setting(name,
|
||||
opts.extract!(*SiteSettings::TypeSupervisor::CONSUMED_OPTS))
|
||||
|
||||
if validator_type = opts[:validator] || validator_for(type)
|
||||
validators[name] = { class: validator_type, opts: opts }
|
||||
end
|
||||
|
||||
current[name] = current_value
|
||||
setup_methods(name)
|
||||
end
|
||||
end
|
||||
|
||||
# just like a setting, except that it is available in javascript via DiscourseSession
|
||||
def client_setting(name, default = nil, opts = {})
|
||||
setting(name, default, opts)
|
||||
client_settings << name.to_sym
|
||||
end
|
||||
|
||||
def settings_hash
|
||||
result = {}
|
||||
@defaults.each do |s, _|
|
||||
defaults.each_key do |s|
|
||||
result[s] = send(s).to_s
|
||||
end
|
||||
result
|
||||
|
@ -174,32 +124,21 @@ module SiteSettingExtension
|
|||
|
||||
# Retrieve all settings
|
||||
def all_settings(include_hidden = false)
|
||||
@defaults
|
||||
.reject { |s, _| hidden_settings.include?(s) && !include_hidden }
|
||||
defaults
|
||||
.reject { |s, _| !include_hidden && hidden_settings.include?(s) }
|
||||
.map do |s, v|
|
||||
value = send(s)
|
||||
type = types[get_data_type(s, value)]
|
||||
opts = {
|
||||
setting: s,
|
||||
description: description(s),
|
||||
default: v.to_s,
|
||||
type: type.to_s,
|
||||
value: value.to_s,
|
||||
category: categories[s],
|
||||
preview: previews[s]
|
||||
}
|
||||
value = send(s)
|
||||
opts = {
|
||||
setting: s,
|
||||
description: description(s),
|
||||
default: defaults[s].to_s,
|
||||
value: value.to_s,
|
||||
category: categories[s],
|
||||
preview: previews[s]
|
||||
}.merge(type_supervisor.type_hash(s))
|
||||
|
||||
if type == :enum && enum_class(s)
|
||||
opts.merge!(valid_values: enum_class(s).values, translate_names: enum_class(s).translate_names?)
|
||||
elsif type == :enum
|
||||
opts.merge!(valid_values: choices[s].map { |c| { name: c, value: c } }, translate_names: false)
|
||||
end
|
||||
|
||||
opts[:textarea] = true if static_types[s] == :textarea
|
||||
|
||||
opts[:choices] = choices[s] if choices.has_key? s
|
||||
opts
|
||||
end
|
||||
opts
|
||||
end.unshift(defaults.locale_setting_hash)
|
||||
end
|
||||
|
||||
def description(setting)
|
||||
|
@ -217,22 +156,22 @@ module SiteSettingExtension
|
|||
def refresh!
|
||||
mutex.synchronize do
|
||||
ensure_listen_for_changes
|
||||
old = current
|
||||
|
||||
new_hash = Hash[*(provider.all.map { |s|
|
||||
[s.name.intern, convert(s.value, s.data_type, s.name)]
|
||||
new_hash = Hash[*(defaults.db_all.map { |s|
|
||||
[s.name.to_sym, type_supervisor.to_rb_value(s.name, s.value, s.data_type)]
|
||||
}.to_a.flatten)]
|
||||
|
||||
# add defaults, cause they are cached
|
||||
new_hash = defaults.merge(new_hash)
|
||||
defaults_view = defaults.all
|
||||
|
||||
# add locale default and defaults based on default_locale, cause they are cached
|
||||
new_hash = defaults_view.merge(new_hash)
|
||||
|
||||
# add shadowed
|
||||
shadowed_settings.each { |ss| new_hash[ss] = GlobalSetting.send(ss) }
|
||||
|
||||
changes, deletions = diff_hash(new_hash, old)
|
||||
|
||||
changes, deletions = diff_hash(new_hash, current)
|
||||
changes.each { |name, val| current[name] = val }
|
||||
deletions.each { |name, val| current[name] = defaults[name] }
|
||||
deletions.each { |name, _| current[name] = defaults_view[name] }
|
||||
|
||||
clear_cache!
|
||||
end
|
||||
|
@ -282,44 +221,9 @@ module SiteSettingExtension
|
|||
end
|
||||
|
||||
def add_override!(name, val)
|
||||
type = get_data_type(name, defaults[name.to_sym])
|
||||
|
||||
val = val.to_s if type == types[:string]
|
||||
|
||||
if type == types[:bool] && val != true && val != false
|
||||
val = (val == "t" || val == "true") ? 't' : 'f'
|
||||
end
|
||||
|
||||
if type == types[:integer] && !val.is_a?(Integer)
|
||||
val = val.to_i
|
||||
end
|
||||
|
||||
if type == types[:null] && val != ''
|
||||
type = get_data_type(name, val)
|
||||
end
|
||||
|
||||
if type == types[:enum]
|
||||
val = val.to_i if defaults[name.to_sym].is_a?(Integer)
|
||||
if enum_class(name)
|
||||
raise Discourse::InvalidParameters.new(:value) unless enum_class(name).valid_value?(val)
|
||||
else
|
||||
raise Discourse::InvalidParameters.new(:value) unless choices[name].include?(val)
|
||||
end
|
||||
end
|
||||
|
||||
if v = validators[name]
|
||||
validator = v[:class].new(v[:opts])
|
||||
unless validator.valid_value?(val)
|
||||
raise Discourse::InvalidParameters.new(validator.error_message)
|
||||
end
|
||||
end
|
||||
|
||||
if self.respond_to? "validate_#{name}"
|
||||
send("validate_#{name}", val)
|
||||
end
|
||||
|
||||
val, type = type_supervisor.to_db_value(name, val)
|
||||
provider.save(name, val, type)
|
||||
current[name] = convert(val, type, name)
|
||||
current[name] = type_supervisor.to_rb_value(name, val)
|
||||
notify_clients!(name) if client_settings.include? name
|
||||
clear_cache!
|
||||
end
|
||||
|
@ -332,26 +236,10 @@ module SiteSettingExtension
|
|||
MessageBus.publish('/client_settings', name: name, value: self.send(name))
|
||||
end
|
||||
|
||||
def has_setting?(name)
|
||||
defaults.has_key?(name.to_sym) || defaults.has_key?("#{name}?".to_sym)
|
||||
end
|
||||
|
||||
def requires_refresh?(name)
|
||||
refresh_settings.include?(name.to_sym)
|
||||
end
|
||||
|
||||
def is_valid_data?(name, value)
|
||||
valid = true
|
||||
type = get_data_type(name, defaults[name.to_sym])
|
||||
|
||||
if type == types[:integer]
|
||||
# validate integer
|
||||
valid = false unless value.to_i.is_a?(Integer)
|
||||
end
|
||||
|
||||
valid
|
||||
end
|
||||
|
||||
def filter_value(name, value)
|
||||
if %w[disabled_image_download_domains onebox_domains_blacklist exclude_rel_nofollow_domains email_domains_blacklist email_domains_whitelist white_listed_spam_host_domains].include? name
|
||||
domain_array = []
|
||||
|
@ -362,7 +250,7 @@ module SiteSettingExtension
|
|||
end
|
||||
|
||||
def set(name, value)
|
||||
if has_setting?(name) && is_valid_data?(name, value)
|
||||
if has_setting?(name)
|
||||
value = filter_value(name, value)
|
||||
self.send("#{name}=", value)
|
||||
Discourse.request_refresh! if requires_refresh?(name)
|
||||
|
@ -399,90 +287,11 @@ module SiteSettingExtension
|
|||
[changes, deletions]
|
||||
end
|
||||
|
||||
def get_data_type(name, val)
|
||||
return types[:null] if val.nil?
|
||||
|
||||
# Some types are just for validations like email.
|
||||
# Only consider it valid if includes in `types`
|
||||
if static_type = static_types[name.to_sym]
|
||||
return types[static_type] if types.keys.include?(static_type)
|
||||
end
|
||||
|
||||
case val
|
||||
when String
|
||||
types[:string]
|
||||
when Integer
|
||||
types[:integer]
|
||||
when Float
|
||||
types[:float]
|
||||
when TrueClass, FalseClass
|
||||
types[:bool]
|
||||
else
|
||||
raise ArgumentError.new :val
|
||||
end
|
||||
end
|
||||
|
||||
def convert(value, type, name)
|
||||
case type
|
||||
when types[:float]
|
||||
value.to_f
|
||||
when types[:integer]
|
||||
value.to_i
|
||||
when types[:bool]
|
||||
value == true || value == "t" || value == "true"
|
||||
when types[:null]
|
||||
nil
|
||||
when types[:enum]
|
||||
defaults[name.to_sym].is_a?(Integer) ? value.to_i : value
|
||||
else
|
||||
return value if types[type]
|
||||
# Otherwise it's a type error
|
||||
raise ArgumentError.new :type
|
||||
end
|
||||
end
|
||||
|
||||
def validator_for(type_name)
|
||||
@validator_mapping ||= {
|
||||
'email' => EmailSettingValidator,
|
||||
'username' => UsernameSettingValidator,
|
||||
types[:integer] => IntegerSettingValidator,
|
||||
types[:string] => StringSettingValidator,
|
||||
'list' => StringSettingValidator,
|
||||
'enum' => StringSettingValidator,
|
||||
'regex' => RegexSettingValidator
|
||||
}
|
||||
@validator_mapping[type_name]
|
||||
end
|
||||
|
||||
DEPRECATED_SETTINGS = [
|
||||
['use_https', 'force_https', '1.7']
|
||||
]
|
||||
|
||||
def setup_deprecated_methods
|
||||
DEPRECATED_SETTINGS.each do |old_setting, new_setting, version|
|
||||
define_singleton_method old_setting do
|
||||
logger.warn("`SiteSetting.#{old_setting}` has been deprecated and will be removed in the #{version} Release. Please use `SiteSetting.#{new_setting}` instead")
|
||||
self.public_send new_setting
|
||||
end
|
||||
|
||||
define_singleton_method "#{old_setting}?" do
|
||||
logger.warn("`SiteSetting.#{old_setting}?` has been deprecated and will be removed in the #{version} Release. Please use `SiteSetting.#{new_setting}?` instead")
|
||||
self.public_send "#{new_setting}?"
|
||||
end
|
||||
|
||||
define_singleton_method "#{old_setting}=" do |val|
|
||||
logger.warn("`SiteSetting.#{old_setting}=` has been deprecated and will be removed in the #{version} Release. Please use `SiteSetting.#{new_setting}=` instead")
|
||||
self.public_send "#{new_setting}=", val
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def setup_methods(name)
|
||||
clean_name = name.to_s.sub("?", "").to_sym
|
||||
|
||||
define_singleton_method clean_name do
|
||||
c = @containers[provider.current_site]
|
||||
if c
|
||||
if (c = @containers[provider.current_site])
|
||||
c[name]
|
||||
else
|
||||
refresh!
|
||||
|
@ -499,10 +308,6 @@ module SiteSettingExtension
|
|||
end
|
||||
end
|
||||
|
||||
def enum_class(name)
|
||||
enums[name]
|
||||
end
|
||||
|
||||
def get_hostname(url)
|
||||
unless (URI.parse(url).scheme rescue nil).nil?
|
||||
url = "http://#{url}" if URI.parse(url).scheme.nil?
|
||||
|
|
|
@ -0,0 +1,126 @@
|
|||
module SiteSettings; end
|
||||
|
||||
# A cache for providing default value based on site locale
|
||||
class SiteSettings::DefaultsProvider
|
||||
include Enumerable
|
||||
|
||||
CONSUMED_OPTS = %i[default locale_default].freeze
|
||||
DEFAULT_LOCALE_KEY = :default_locale
|
||||
DEFAULT_LOCALE = 'en'.freeze
|
||||
DEFAULT_CATEGORY = 'required'.freeze
|
||||
|
||||
def initialize(site_setting)
|
||||
@site_setting = site_setting
|
||||
@site_setting.refresh_settings << DEFAULT_LOCALE_KEY
|
||||
|
||||
@cached = {}
|
||||
@defaults = {}
|
||||
@defaults[DEFAULT_LOCALE.to_sym] = {}
|
||||
@site_locale = nil
|
||||
refresh_site_locale!
|
||||
end
|
||||
|
||||
def load_setting(name_arg, value, opts = {})
|
||||
name = name_arg.to_sym
|
||||
@defaults[DEFAULT_LOCALE.to_sym][name] = value
|
||||
|
||||
if (locale_default = opts[:locale_default])
|
||||
locale_default.each do |locale, v|
|
||||
locale = locale.to_sym
|
||||
@defaults[locale] ||= {}
|
||||
@defaults[locale][name] = v
|
||||
end
|
||||
end
|
||||
refresh_cache!
|
||||
end
|
||||
|
||||
def db_all
|
||||
@site_setting.provider.all.delete_if { |s| s.name.to_sym == DEFAULT_LOCALE_KEY }
|
||||
end
|
||||
|
||||
def all
|
||||
@cached
|
||||
end
|
||||
|
||||
def get(name)
|
||||
@cached[name.to_sym]
|
||||
end
|
||||
|
||||
# Used to override site settings in dev/test env
|
||||
def set_regardless_of_locale(name, value)
|
||||
name = name.to_sym
|
||||
if @site_setting.has_setting?(name)
|
||||
@defaults.each { |_, hash| hash.delete(name) }
|
||||
@defaults[DEFAULT_LOCALE.to_sym][name] = value
|
||||
value, type = @site_setting.type_supervisor.to_db_value(name, value)
|
||||
@cached[name] = @site_setting.type_supervisor.to_rb_value(name, value, type)
|
||||
else
|
||||
raise ArgumentError.new("No setting named '#{name}' exists")
|
||||
end
|
||||
end
|
||||
|
||||
alias [] get
|
||||
|
||||
attr_reader :site_locale
|
||||
|
||||
def site_locale=(val)
|
||||
val = val.to_s
|
||||
raise Discourse::InvalidParameters.new(:value) unless LocaleSiteSetting.valid_value?(val)
|
||||
|
||||
if val != @site_locale
|
||||
@site_setting.provider.save(DEFAULT_LOCALE_KEY, val, SiteSetting.types[:string])
|
||||
refresh_site_locale!
|
||||
@site_setting.refresh!
|
||||
Discourse.request_refresh!
|
||||
end
|
||||
|
||||
@site_locale
|
||||
end
|
||||
|
||||
def each
|
||||
@cached.each { |k, v| yield k.to_sym, v }
|
||||
end
|
||||
|
||||
def locale_setting_hash
|
||||
{
|
||||
setting: DEFAULT_LOCALE_KEY,
|
||||
default: DEFAULT_LOCALE,
|
||||
category: DEFAULT_CATEGORY,
|
||||
description: @site_setting.description(DEFAULT_LOCALE_KEY),
|
||||
type: SiteSetting.types[SiteSetting.types[:enum]],
|
||||
preview: nil,
|
||||
value: @site_locale,
|
||||
valid_values: LocaleSiteSetting.values,
|
||||
translate_names: LocaleSiteSetting.translate_names?
|
||||
}
|
||||
end
|
||||
|
||||
def refresh_site_locale!
|
||||
if GlobalSetting.respond_to?(DEFAULT_LOCALE_KEY) &&
|
||||
(global_val = GlobalSetting.send(DEFAULT_LOCALE_KEY)) &&
|
||||
!global_val.blank?
|
||||
@site_locale = global_val
|
||||
elsif (db_val = @site_setting.provider.find(DEFAULT_LOCALE_KEY))
|
||||
@site_locale = db_val.value.to_s
|
||||
else
|
||||
@site_locale = DEFAULT_LOCALE
|
||||
end
|
||||
refresh_cache!
|
||||
@site_locale
|
||||
end
|
||||
|
||||
def has_setting?(name)
|
||||
has_key?(name.to_sym) || has_key?("#{name.to_s}?".to_sym)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def has_key?(key)
|
||||
@cached.key?(key) || key == DEFAULT_LOCALE_KEY
|
||||
end
|
||||
|
||||
def refresh_cache!
|
||||
@cached = @defaults[DEFAULT_LOCALE.to_sym].merge(@defaults.fetch(@site_locale.to_sym, {}))
|
||||
end
|
||||
|
||||
end
|
|
@ -0,0 +1,26 @@
|
|||
module SiteSettings; end
|
||||
|
||||
module SiteSettings::DeprecatedSettings
|
||||
DEPRECATED_SETTINGS = [
|
||||
%w[use_https force_https 1.7]
|
||||
]
|
||||
|
||||
def setup_deprecated_methods
|
||||
DEPRECATED_SETTINGS.each do |old_setting, new_setting, version|
|
||||
define_singleton_method old_setting do
|
||||
logger.warn("`SiteSetting.#{old_setting}` has been deprecated and will be removed in the #{version} Release. Please use `SiteSetting.#{new_setting}` instead")
|
||||
self.public_send new_setting
|
||||
end
|
||||
|
||||
define_singleton_method "#{old_setting}?" do
|
||||
logger.warn("`SiteSetting.#{old_setting}?` has been deprecated and will be removed in the #{version} Release. Please use `SiteSetting.#{new_setting}?` instead")
|
||||
self.public_send "#{new_setting}?"
|
||||
end
|
||||
|
||||
define_singleton_method "#{old_setting}=" do |val|
|
||||
logger.warn("`SiteSetting.#{old_setting}=` has been deprecated and will be removed in the #{version} Release. Please use `SiteSetting.#{new_setting}=` instead")
|
||||
self.public_send "#{new_setting}=", val
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -10,7 +10,7 @@ class SiteSettings::LocalProcessProvider
|
|||
@settings[current_site] ||= {}
|
||||
end
|
||||
|
||||
def initialize()
|
||||
def initialize
|
||||
@settings = {}
|
||||
self.current_site = "test"
|
||||
end
|
||||
|
|
|
@ -0,0 +1,210 @@
|
|||
require_dependency 'site_settings/validations'
|
||||
require_dependency 'enum'
|
||||
|
||||
module SiteSettings; end
|
||||
|
||||
class SiteSettings::TypeSupervisor
|
||||
include SiteSettings::Validations
|
||||
|
||||
CONSUMED_OPTS = %i[enum choices type validator min max regex hidden regex_error].freeze
|
||||
VALIDATOR_OPTS = %i[min max regex hidden regex_error].freeze
|
||||
|
||||
# For plugins, so they can tell if a feature is supported
|
||||
SUPPORTED_TYPES = %i[email username list enum].freeze
|
||||
|
||||
def self.types
|
||||
@types ||= Enum.new(string: 1,
|
||||
time: 2,
|
||||
integer: 3,
|
||||
float: 4,
|
||||
bool: 5,
|
||||
null: 6,
|
||||
enum: 7,
|
||||
list: 8,
|
||||
url_list: 9,
|
||||
host_list: 10,
|
||||
category_list: 11,
|
||||
value_list: 12,
|
||||
regex: 13,
|
||||
email: 14,
|
||||
username: 15)
|
||||
end
|
||||
|
||||
def self.parse_value_type(val)
|
||||
case val
|
||||
when NilClass
|
||||
self.types[:null]
|
||||
when String
|
||||
self.types[:string]
|
||||
when Integer
|
||||
self.types[:integer]
|
||||
when Float
|
||||
self.types[:float]
|
||||
when TrueClass, FalseClass
|
||||
self.types[:bool]
|
||||
else
|
||||
raise ArgumentError.new :val
|
||||
end
|
||||
end
|
||||
|
||||
def self.supported_types
|
||||
SUPPORTED_TYPES
|
||||
end
|
||||
|
||||
def initialize(defaults_provider)
|
||||
@defaults_provider = defaults_provider
|
||||
@enums = {}
|
||||
@static_types = {}
|
||||
@choices = {}
|
||||
@validators = {}
|
||||
@types = {}
|
||||
end
|
||||
|
||||
def load_setting(name_arg, opts = {})
|
||||
name = name_arg.to_sym
|
||||
|
||||
if (enum = opts[:enum])
|
||||
@enums[name] = enum.is_a?(String) ? enum.constantize : enum
|
||||
opts[:type] ||= :enum
|
||||
end
|
||||
|
||||
if (new_choices = opts[:choices])
|
||||
new_choices = eval(new_choices) if new_choices.is_a?(String)
|
||||
|
||||
if @choices.has_key?(name)
|
||||
@choices[name].concat(new_choices)
|
||||
else
|
||||
@choices[name] = new_choices
|
||||
end
|
||||
end
|
||||
|
||||
if (type = opts[:type])
|
||||
@static_types[name] = type.to_sym
|
||||
end
|
||||
@types[name] = get_data_type(name, @defaults_provider[name])
|
||||
|
||||
opts[:validator] = opts[:validator].try(:constantize)
|
||||
if (validator_type = (opts[:validator] || validator_for(@types[name])))
|
||||
@validators[name] = { class: validator_type, opts: opts.slice(*VALIDATOR_OPTS) }
|
||||
end
|
||||
end
|
||||
|
||||
def to_rb_value(name, value, override_type = nil)
|
||||
name = name.to_sym
|
||||
type = @types[name] = (override_type || @types[name] || get_data_type(name, value))
|
||||
|
||||
case type
|
||||
when self.class.types[:float]
|
||||
value.to_f
|
||||
when self.class.types[:integer]
|
||||
value.to_i
|
||||
when self.class.types[:bool]
|
||||
value == true || value == 't' || value == 'true'
|
||||
when self.class.types[:null]
|
||||
nil
|
||||
when self.class.types[:enum]
|
||||
@defaults_provider[name].is_a?(Integer) ? value.to_i : value.to_s
|
||||
when self.class.types[:string]
|
||||
value.to_s
|
||||
else
|
||||
return value if self.class.types[type]
|
||||
# Otherwise it's a type error
|
||||
raise ArgumentError.new :type
|
||||
end
|
||||
end
|
||||
|
||||
def to_db_value(name, value)
|
||||
val, type = normalize_input(name, value)
|
||||
validate_value(name, type, val)
|
||||
[val, type]
|
||||
end
|
||||
|
||||
def type_hash(name)
|
||||
name = name.to_sym
|
||||
type = self.class.types[@types[name]]
|
||||
|
||||
result = { type: type.to_s }
|
||||
|
||||
if type == :enum
|
||||
if (klass = enum_class(name))
|
||||
result.merge!(valid_values: klass.values, translate_names: klass.translate_names?)
|
||||
else
|
||||
result.merge!(valid_values: @choices[name].map { |c| { name: c, value: c } }, translate_names: false)
|
||||
end
|
||||
end
|
||||
|
||||
result[:choices] = @choices[name] if @choices.has_key? name
|
||||
result
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def normalize_input(name, val)
|
||||
name = name.to_sym
|
||||
type = @types[name] || self.class.parse_value_type(val)
|
||||
|
||||
if type == self.class.types[:bool]
|
||||
val = (val == true || val == 't' || val == 'true') ? 't' : 'f'
|
||||
elsif type == self.class.types[:integer] && !val.is_a?(Integer)
|
||||
val = val.to_i
|
||||
elsif type == self.class.types[:null] && val != ''
|
||||
type = get_data_type(name, val)
|
||||
elsif type == self.class.types[:enum]
|
||||
val = @defaults_provider[name].is_a?(Integer) ? val.to_i : val.to_s
|
||||
end
|
||||
|
||||
[val, type]
|
||||
end
|
||||
|
||||
def validate_value(name, type, val)
|
||||
if type == self.class.types[:enum]
|
||||
if enum_class(name)
|
||||
raise Discourse::InvalidParameters.new(:value) unless enum_class(name).valid_value?(val)
|
||||
else
|
||||
raise Discourse::InvalidParameters.new(:value) unless @choices[name].include?(val)
|
||||
end
|
||||
end
|
||||
|
||||
if (v = @validators[name])
|
||||
validator = v[:class].new(v[:opts])
|
||||
unless validator.valid_value?(val)
|
||||
raise Discourse::InvalidParameters, "#{name.to_s}: #{validator.error_message}"
|
||||
end
|
||||
end
|
||||
|
||||
validate_method = "validate_#{name}"
|
||||
if self.respond_to? validate_method
|
||||
send(validate_method, val)
|
||||
end
|
||||
end
|
||||
|
||||
def get_data_type(name, val)
|
||||
# Some types are just for validations like email.
|
||||
# Only consider it valid if includes in `types`
|
||||
if (static_type = @static_types[name.to_sym])
|
||||
return self.class.types[static_type] if self.class.types.keys.include?(static_type)
|
||||
end
|
||||
|
||||
self.class.parse_value_type(val)
|
||||
end
|
||||
|
||||
def enum_class(name)
|
||||
@enums[name]
|
||||
end
|
||||
|
||||
def validator_for(type_name)
|
||||
case type_name
|
||||
when self.class.types[:email]
|
||||
EmailSettingValidator
|
||||
when self.class.types[:username]
|
||||
UsernameSettingValidator
|
||||
when self.class.types[:integer]
|
||||
IntegerSettingValidator
|
||||
when self.class.types[:regex]
|
||||
RegexSettingValidator
|
||||
when self.class.types[:string], self.class.types[:list], self.class.types[:enum]
|
||||
StringSettingValidator
|
||||
else nil
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,6 +1,6 @@
|
|||
module SiteSettings; end
|
||||
|
||||
module SiteSettingValidations
|
||||
|
||||
module SiteSettings::Validations
|
||||
def validate_error(key)
|
||||
raise Discourse::InvalidParameters.new(I18n.t("errors.site_settings.#{key}"))
|
||||
end
|
|
@ -1,32 +1,26 @@
|
|||
module SiteSettings; end
|
||||
|
||||
class SiteSettings::YamlLoader
|
||||
|
||||
def initialize(file)
|
||||
@file = file
|
||||
end
|
||||
|
||||
def env_val(value)
|
||||
if value.is_a?(Hash)
|
||||
value.has_key?(Rails.env) ? value[Rails.env] : value['default']
|
||||
else
|
||||
value
|
||||
end
|
||||
end
|
||||
|
||||
def load
|
||||
yaml = YAML.load_file(@file)
|
||||
yaml.each_key do |category|
|
||||
yaml[category].each do |setting_name, hash|
|
||||
if hash.is_a?(Hash)
|
||||
# Get default value for the site setting:
|
||||
value = env_val(hash.delete('default'))
|
||||
|
||||
if hash.key?('hidden')
|
||||
hash['hidden'] = env_val(hash.delete('hidden'))
|
||||
value = hash.delete('default')
|
||||
if value.is_a?(Hash)
|
||||
raise Discourse::Deprecation, "Site setting per env is no longer supported. Error setting: #{setting_name}"
|
||||
end
|
||||
|
||||
yield category, setting_name, value, hash.symbolize_keys!
|
||||
if hash['hidden']&.is_a?(Hash)
|
||||
raise Discourse::Deprecation, "Hidden site setting per env is no longer supported. Error setting: #{setting_name}"
|
||||
end
|
||||
|
||||
yield category, setting_name, value, hash.deep_symbolize_keys!
|
||||
else
|
||||
# Simplest case. site_setting_name: 'default value'
|
||||
yield category, setting_name, hash, {}
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
plugins:
|
||||
discourse_narrative_bot_enabled:
|
||||
default:
|
||||
default: true
|
||||
test: false
|
||||
default: true
|
||||
client: true
|
||||
disable_discourse_narrative_bot_welcome_post:
|
||||
default: false
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
require 'benchmark/ips'
|
||||
require File.expand_path('../../../../config/environment', __FILE__)
|
||||
|
||||
# Put pre conditions here
|
||||
# Used db but it's OK in the most cases
|
||||
|
||||
# build the cache
|
||||
SiteSetting.title = SecureRandom.hex
|
||||
SiteSetting.default_locale = SiteSetting.default_locale == 'en' ? 'zh_CN' : 'en'
|
||||
SiteSetting.refresh!
|
||||
|
||||
tests = [
|
||||
["current cache", lambda do
|
||||
SiteSetting.title
|
||||
SiteSetting.enable_sso
|
||||
end
|
||||
],
|
||||
["change default locale with current cache refreshed", lambda do
|
||||
SiteSetting.default_locale = SiteSetting.default_locale == 'en' ? 'zh_CN' : 'en'
|
||||
end
|
||||
],
|
||||
["change site setting", lambda do
|
||||
SiteSetting.title = SecureRandom.hex
|
||||
end
|
||||
],
|
||||
]
|
||||
|
||||
Benchmark.ips do |x|
|
||||
tests.each do |test, proc|
|
||||
x.report(test, proc)
|
||||
end
|
||||
end
|
||||
|
||||
# 2017-08-02 - Erick's Site Setting change
|
||||
|
||||
# Before
|
||||
# Calculating -------------------------------------
|
||||
# current cache 167.518k (±12.1%) i/s - 822.983k in 5.000478s
|
||||
# change default locale with current cache refreshed
|
||||
# 174.173 (±16.7%) i/s - 845.000 in 5.015281s
|
||||
# change site setting 132.956 (±16.5%) i/s - 663.000 in 5.124766s
|
||||
|
||||
# After
|
||||
# Calculating -------------------------------------
|
||||
# current cache 167.170k (±12.2%) i/s - 824.688k in 5.022784s
|
||||
# change default locale with current cache refreshed
|
||||
# 79.876 (±16.3%) i/s - 392.000 in 5.067448s
|
||||
# change site setting 129.085 (±13.2%) i/s - 636.000 in 5.032536s
|
|
@ -0,0 +1,32 @@
|
|||
require 'ruby-prof'
|
||||
|
||||
def profile(&blk)
|
||||
result = RubyProf.profile(&blk)
|
||||
printer = RubyProf::GraphHtmlPrinter.new(result)
|
||||
printer.print(STDOUT)
|
||||
end
|
||||
profile { '' } # loading profiler dependency
|
||||
|
||||
require File.expand_path('../../../../config/environment', __FILE__)
|
||||
|
||||
# warming up
|
||||
SiteSetting.title
|
||||
SiteSetting.enable_sso
|
||||
SiteSetting.default_locale = SiteSetting.default_locale == 'en' ? 'zh_CN' : 'en'
|
||||
SiteSetting.title = SecureRandom.hex
|
||||
|
||||
profile do
|
||||
SiteSetting.title
|
||||
end
|
||||
|
||||
profile do
|
||||
SiteSetting.enable_sso
|
||||
end
|
||||
|
||||
profile do
|
||||
SiteSetting.default_locale = SiteSetting.default_locale == 'en' ? 'zh_CN' : 'en'
|
||||
end
|
||||
|
||||
profile do
|
||||
SiteSetting.title = SecureRandom.hex
|
||||
end
|
|
@ -64,7 +64,7 @@ describe SiteSettingExtension do
|
|||
expect(settings.hello).to eq(99)
|
||||
end
|
||||
|
||||
it "Publishes changes cross sites" do
|
||||
it "publishes changes cross sites" do
|
||||
settings.setting(:hello, 1)
|
||||
settings2.setting(:hello, 1)
|
||||
|
||||
|
@ -143,7 +143,7 @@ describe SiteSettingExtension do
|
|||
|
||||
it "should publish changes to clients" do
|
||||
settings.setting("test_setting", 100)
|
||||
settings.client_setting("test_setting")
|
||||
settings.setting("test_setting", nil, client: true)
|
||||
|
||||
messages = MessageBus.track_publish do
|
||||
settings.test_setting = 88
|
||||
|
@ -155,8 +155,11 @@ describe SiteSettingExtension do
|
|||
end
|
||||
|
||||
describe "remove_override" do
|
||||
it "correctly nukes overrides" do
|
||||
before do
|
||||
settings.setting(:test_override, "test")
|
||||
settings.refresh!
|
||||
end
|
||||
it "correctly nukes overrides" do
|
||||
settings.test_override = "bla"
|
||||
settings.remove_override!(:test_override)
|
||||
expect(settings.test_override).to eq("test")
|
||||
|
@ -263,6 +266,7 @@ describe SiteSettingExtension 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
|
||||
|
||||
|
@ -272,7 +276,7 @@ describe SiteSettingExtension do
|
|||
|
||||
class TestEnumClass
|
||||
def self.valid_value?(v)
|
||||
true
|
||||
self.values.include?(v)
|
||||
end
|
||||
def self.values
|
||||
['en']
|
||||
|
@ -299,6 +303,10 @@ describe SiteSettingExtension 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)
|
||||
|
@ -384,6 +392,14 @@ describe SiteSettingExtension do
|
|||
end
|
||||
end
|
||||
|
||||
describe ".set_and_log" do
|
||||
it "raises an error when set for an invalid setting name" do
|
||||
expect {
|
||||
settings.set_and_log("provider", "haxxed")
|
||||
}.to raise_error(ArgumentError)
|
||||
end
|
||||
end
|
||||
|
||||
describe "filter domain name" do
|
||||
before do
|
||||
settings.setting(:white_listed_spam_host_domains, "www.example.com")
|
||||
|
@ -503,4 +519,62 @@ describe SiteSettingExtension do
|
|||
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 do
|
||||
settings.remove_override!(:test_override)
|
||||
end
|
||||
|
||||
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(Rails.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
|
||||
|
||||
end
|
||||
|
|
|
@ -0,0 +1,268 @@
|
|||
require 'rails_helper'
|
||||
require_dependency 'site_settings/defaults_provider'
|
||||
|
||||
describe SiteSettings::DefaultsProvider do
|
||||
|
||||
let :provider_local do
|
||||
SiteSettings::LocalProcessProvider.new
|
||||
end
|
||||
|
||||
def new_settings(provider)
|
||||
Class.new do
|
||||
extend SiteSettingExtension
|
||||
self.provider = provider
|
||||
end
|
||||
end
|
||||
|
||||
let :settings do
|
||||
new_settings(provider_local)
|
||||
end
|
||||
|
||||
describe 'inserts default_locale into refresh' do
|
||||
it 'when initialize' do
|
||||
expect(settings.refresh_settings.include?(SiteSettings::DefaultsProvider::DEFAULT_LOCALE_KEY)).to be_truthy
|
||||
end
|
||||
end
|
||||
|
||||
describe '.db_all' do
|
||||
it 'collects values from db except default locale' do
|
||||
settings.provider.save(SiteSettings::DefaultsProvider::DEFAULT_LOCALE_KEY,
|
||||
'en',
|
||||
SiteSetting.types[:string])
|
||||
expect(settings.defaults.db_all).to eq([])
|
||||
end
|
||||
|
||||
it 'can collect values from db' do
|
||||
settings.provider.save('try_a', 1, SiteSetting.types[:integer])
|
||||
settings.provider.save('try_b', 2, SiteSetting.types[:integer])
|
||||
expect(settings.defaults.db_all.count).to eq 2
|
||||
end
|
||||
end
|
||||
|
||||
describe 'expose default cache according to locale' do
|
||||
before(:each) do
|
||||
settings.setting(:test_override, 'default', locale_default: { zh_CN: 'cn' })
|
||||
settings.setting(:test_default, 'test', regex: '^\S+$')
|
||||
settings.refresh!
|
||||
end
|
||||
|
||||
describe '.all' do
|
||||
it 'returns all values according to the current locale' do
|
||||
expect(settings.defaults.all).to eq(test_override: 'default', test_default: 'test')
|
||||
settings.defaults.site_locale = 'zh_CN'
|
||||
settings.defaults.refresh_site_locale!
|
||||
expect(settings.defaults.all).to eq(test_override: 'cn', test_default: 'test')
|
||||
end
|
||||
end
|
||||
|
||||
describe '.get' do
|
||||
it 'returns the default value to a site setting' do
|
||||
expect(settings.defaults.get(:test_override)).to eq 'default'
|
||||
end
|
||||
|
||||
it 'accepts a string as the parameters' do
|
||||
expect(settings.defaults.get('test_override')).to eq 'default'
|
||||
end
|
||||
|
||||
it 'returns the default value according to current locale' do
|
||||
expect(settings.defaults.get(:test_override)).to eq 'default'
|
||||
settings.defaults.site_locale = 'zh_CN'
|
||||
expect(settings.defaults.get(:test_override)).to eq 'cn'
|
||||
end
|
||||
end
|
||||
|
||||
describe '.set_regardless_of_locale' do
|
||||
let(:val) { 'env_overriden' }
|
||||
|
||||
it 'sets the default value to a site setting regardless the locale' do
|
||||
settings.defaults.set_regardless_of_locale(:test_override, val)
|
||||
expect(settings.defaults.get(:test_override)).to eq val
|
||||
settings.defaults.site_locale = 'zh_CN'
|
||||
expect(settings.defaults.get(:test_override)).to eq val
|
||||
end
|
||||
|
||||
it 'handles the string' do
|
||||
settings.defaults.set_regardless_of_locale('test_override', val)
|
||||
expect(settings.defaults.get(:test_override)).to eq val
|
||||
end
|
||||
|
||||
it 'converts the data type' do
|
||||
settings.defaults.set_regardless_of_locale(:test_override, 1)
|
||||
expect(settings.defaults.get(:test_override)).to eq '1'
|
||||
end
|
||||
|
||||
it 'raises when the setting does not exists' do
|
||||
expect {
|
||||
settings.defaults.set_regardless_of_locale(:not_exist, 1)
|
||||
}.to raise_error(ArgumentError)
|
||||
end
|
||||
|
||||
it 'raises when the value is not valid' do
|
||||
expect {
|
||||
settings.defaults.set_regardless_of_locale(:test_default, 'regex will fail')
|
||||
}.to raise_error(Discourse::InvalidParameters)
|
||||
end
|
||||
end
|
||||
|
||||
describe '.each' do
|
||||
it 'yields the pair of site settings' do
|
||||
expect { |b| settings.defaults.each(&b) }.to yield_successive_args([:test_override, 'default'], [:test_default, 'test'])
|
||||
settings.defaults.site_locale = 'zh_CN'
|
||||
expect { |b| settings.defaults.each(&b) }.to yield_successive_args([:test_override, 'cn'], [:test_default, 'test'])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '.site_locale' do
|
||||
it 'returns the current site locale' do
|
||||
expect(settings.defaults.site_locale).to eq 'en'
|
||||
end
|
||||
|
||||
context 'when locale is set in the db' do
|
||||
let(:db_val) { 'zr' }
|
||||
let(:global_val) { 'gr' }
|
||||
|
||||
before do
|
||||
settings.provider.save(SiteSettings::DefaultsProvider::DEFAULT_LOCALE_KEY,
|
||||
db_val,
|
||||
SiteSetting.types[:string])
|
||||
settings.defaults.refresh_site_locale!
|
||||
end
|
||||
|
||||
it 'should load from database' do
|
||||
expect(settings.defaults.site_locale).to eq db_val
|
||||
end
|
||||
|
||||
it 'prioritizes GlobalSetting than value from db' do
|
||||
GlobalSetting.stubs(:default_locale).returns(global_val)
|
||||
settings.defaults.refresh_site_locale!
|
||||
expect(settings.defaults.site_locale).to eq global_val
|
||||
end
|
||||
|
||||
it 'ignores blank GlobalSetting' do
|
||||
GlobalSetting.stubs(:default_locale).returns('')
|
||||
settings.defaults.refresh_site_locale!
|
||||
expect(settings.defaults.site_locale).to eq db_val
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
describe '.site_locale=' do
|
||||
it 'changes and store the current site locale' do
|
||||
settings.defaults.site_locale = 'zh_CN'
|
||||
expect(settings.defaults.site_locale).to eq 'zh_CN'
|
||||
end
|
||||
|
||||
it 'changes and store the current site locale' do
|
||||
expect { settings.defaults.site_locale = 'random' }.to raise_error(Discourse::InvalidParameters)
|
||||
expect(settings.defaults.site_locale).to eq 'en'
|
||||
end
|
||||
|
||||
it "don't change when it's shadowed" do
|
||||
GlobalSetting.stubs(:default_locale).returns('shadowed')
|
||||
settings.defaults.site_locale = 'zh_CN'
|
||||
expect(settings.defaults.site_locale).to eq 'shadowed'
|
||||
end
|
||||
|
||||
it 'refresh_site_locale! when called' do
|
||||
settings.defaults.expects(:refresh_site_locale!)
|
||||
settings.defaults.site_locale = 'zh_CN'
|
||||
end
|
||||
|
||||
it 'refreshes the client when changed' do
|
||||
Discourse.expects(:request_refresh!).once
|
||||
settings.defaults.site_locale = 'zh_CN'
|
||||
end
|
||||
|
||||
it "doesn't refresh the client when changed" do
|
||||
Discourse.expects(:request_refresh!).never
|
||||
settings.defaults.site_locale = 'en'
|
||||
end
|
||||
end
|
||||
|
||||
describe '.locale_setting_hash' do
|
||||
it 'returns the hash for client display' do
|
||||
result = settings.defaults.locale_setting_hash
|
||||
|
||||
expect(result[:setting]).to eq(SiteSettings::DefaultsProvider::DEFAULT_LOCALE_KEY)
|
||||
expect(result[:default]).to eq(SiteSettings::DefaultsProvider::DEFAULT_LOCALE)
|
||||
expect(result[:type]).to eq(SiteSetting.types[SiteSetting.types[:enum]])
|
||||
expect(result[:preview]).to be_nil
|
||||
expect(result[:value]).to eq(SiteSettings::DefaultsProvider::DEFAULT_LOCALE)
|
||||
expect(result[:category]).to eq(SiteSettings::DefaultsProvider::DEFAULT_CATEGORY)
|
||||
expect(result[:valid_values]).to eq(LocaleSiteSetting.values)
|
||||
expect(result[:translate_names]).to eq(LocaleSiteSetting.translate_names?)
|
||||
expect(result[:description]).not_to be_nil
|
||||
end
|
||||
end
|
||||
|
||||
describe '.load_setting' do
|
||||
it 'adds a setting to the cache' do
|
||||
settings.defaults.load_setting('new_a', 1)
|
||||
expect(settings.defaults[:new_a]).to eq 1
|
||||
end
|
||||
|
||||
it 'takes care of locale default' do
|
||||
settings.defaults.load_setting(:new_b, 1, locale_default: { zh_CN: 2, zh_TW: 2 })
|
||||
expect(settings.defaults[:new_b]).to eq 1
|
||||
end
|
||||
end
|
||||
|
||||
describe '.refresh_site_locale!' do
|
||||
it 'loads the change to locale' do
|
||||
expect(settings.defaults.site_locale).to eq 'en'
|
||||
settings.provider.save(SiteSettings::DefaultsProvider::DEFAULT_LOCALE_KEY,
|
||||
'zh_CN',
|
||||
SiteSetting.types[:string])
|
||||
settings.defaults.refresh_site_locale!
|
||||
expect(settings.defaults.site_locale).to eq 'zh_CN'
|
||||
end
|
||||
|
||||
it 'loads from GlobalSettings' do
|
||||
expect(settings.defaults.site_locale).to eq 'en'
|
||||
GlobalSetting.stubs(:default_locale).returns('fr')
|
||||
settings.defaults.refresh_site_locale!
|
||||
expect(settings.defaults.site_locale).to eq 'fr'
|
||||
end
|
||||
|
||||
it 'prioritized GlobalSettings than db' do
|
||||
expect(settings.defaults.site_locale).to eq 'en'
|
||||
settings.provider.save(SiteSettings::DefaultsProvider::DEFAULT_LOCALE_KEY,
|
||||
'zh_CN',
|
||||
SiteSetting.types[:string])
|
||||
GlobalSetting.stubs(:default_locale).returns('fr')
|
||||
settings.defaults.refresh_site_locale!
|
||||
expect(settings.defaults.site_locale).to eq 'fr'
|
||||
end
|
||||
end
|
||||
|
||||
describe '.has_setting?' do
|
||||
before do
|
||||
settings.setting(:r, 1)
|
||||
settings.setting(:question?, 1)
|
||||
end
|
||||
|
||||
it "returns true when it's present in the cache" do
|
||||
expect(settings.defaults.has_setting?(:r)).to be_truthy
|
||||
end
|
||||
|
||||
it '"responds when the arg is string' do
|
||||
expect(settings.defaults.has_setting?('r')).to be_truthy
|
||||
end
|
||||
|
||||
it 'default_locale always exists' do
|
||||
expect(settings.defaults.has_setting?(SiteSettings::DefaultsProvider::DEFAULT_LOCALE_KEY)).to be_truthy
|
||||
end
|
||||
|
||||
it 'returns false when the key is not exist' do
|
||||
expect(settings.defaults.has_setting?('no_key')).to be_falsey
|
||||
end
|
||||
|
||||
it 'checks name with question mark' do
|
||||
expect(settings.defaults.has_setting?(:question)).to be_truthy
|
||||
expect(settings.defaults.has_setting?('question')).to be_truthy
|
||||
end
|
||||
end
|
||||
|
||||
end
|
|
@ -0,0 +1,341 @@
|
|||
require 'rails_helper'
|
||||
require_dependency 'site_settings/type_supervisor'
|
||||
|
||||
describe SiteSettings::TypeSupervisor do
|
||||
let :provider_local do
|
||||
SiteSettings::LocalProcessProvider.new
|
||||
end
|
||||
|
||||
def new_settings(provider)
|
||||
Class.new do
|
||||
extend SiteSettingExtension
|
||||
self.provider = provider
|
||||
end
|
||||
end
|
||||
|
||||
let :settings do
|
||||
new_settings(provider_local)
|
||||
end
|
||||
|
||||
subject { SiteSettings::TypeSupervisor }
|
||||
|
||||
describe 'constants' do
|
||||
it 'validator opts are the subset of consumed opts' do
|
||||
expect(Set.new(SiteSettings::TypeSupervisor::CONSUMED_OPTS).superset?(
|
||||
Set.new(SiteSettings::TypeSupervisor::VALIDATOR_OPTS))).to be_truthy
|
||||
end
|
||||
end
|
||||
|
||||
describe '#types' do
|
||||
context "verify enum sequence" do
|
||||
it "'string' should be at 1st position" do
|
||||
expect(SiteSettings::TypeSupervisor.types[:string]).to eq(1)
|
||||
end
|
||||
it "'time' should be at 2nd position" do
|
||||
expect(SiteSettings::TypeSupervisor.types[:time]).to eq(2)
|
||||
end
|
||||
it "'integer' should be at 3rd position" do
|
||||
expect(SiteSettings::TypeSupervisor.types[:integer]).to eq(3)
|
||||
end
|
||||
it "'float' should be at 4th position" do
|
||||
expect(SiteSettings::TypeSupervisor.types[:float]).to eq(4)
|
||||
end
|
||||
it "'bool' should be at 5th position" do
|
||||
expect(SiteSettings::TypeSupervisor.types[:bool]).to eq(5)
|
||||
end
|
||||
it "'null' should be at 6th position" do
|
||||
expect(SiteSettings::TypeSupervisor.types[:null]).to eq(6)
|
||||
end
|
||||
it "'enum' should be at 7th position" do
|
||||
expect(SiteSettings::TypeSupervisor.types[:enum]).to eq(7)
|
||||
end
|
||||
it "'list' should be at 8th position" do
|
||||
expect(SiteSettings::TypeSupervisor.types[:list]).to eq(8)
|
||||
end
|
||||
it "'url_list' should be at 9th position" do
|
||||
expect(SiteSettings::TypeSupervisor.types[:url_list]).to eq(9)
|
||||
end
|
||||
it "'host_list' should be at 10th position" do
|
||||
expect(SiteSettings::TypeSupervisor.types[:host_list]).to eq(10)
|
||||
end
|
||||
it "'category_list' should be at 11th position" do
|
||||
expect(SiteSettings::TypeSupervisor.types[:category_list]).to eq(11)
|
||||
end
|
||||
it "'value_list' should be at 12th position" do
|
||||
expect(SiteSettings::TypeSupervisor.types[:value_list]).to eq(12)
|
||||
end
|
||||
it "'regex' should be at 13th position" do
|
||||
expect(SiteSettings::TypeSupervisor.types[:regex]).to eq(13)
|
||||
end
|
||||
it "'email' should be at 14th position" do
|
||||
expect(SiteSettings::TypeSupervisor.types[:email]).to eq(14)
|
||||
end
|
||||
it "'username' should be at 15th position" do
|
||||
expect(SiteSettings::TypeSupervisor.types[:username]).to eq(15)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#parse_value_type' do
|
||||
it 'returns :null type when the value is nil' do
|
||||
expect(subject.parse_value_type(nil)).to eq(SiteSetting.types[:null])
|
||||
end
|
||||
|
||||
it 'returns :integer type when the value is int' do
|
||||
expect(subject.parse_value_type(2)).to eq(SiteSetting.types[:integer])
|
||||
end
|
||||
|
||||
it 'returns :integer type when the value is large int' do
|
||||
expect(subject.parse_value_type(99999999999999999999999999999999999)).to eq(SiteSetting.types[:integer])
|
||||
end
|
||||
|
||||
it 'returns :float type when the value is float' do
|
||||
expect(subject.parse_value_type(1.23)).to eq(SiteSetting.types[:float])
|
||||
end
|
||||
|
||||
it 'returns :bool type when the value is true' do
|
||||
expect(subject.parse_value_type(true)).to eq(SiteSetting.types[:bool])
|
||||
end
|
||||
|
||||
it 'returns :bool type when the value is false' do
|
||||
expect(subject.parse_value_type(false)).to eq(SiteSetting.types[:bool])
|
||||
end
|
||||
|
||||
it 'raises when the value is not listed' do
|
||||
expect {
|
||||
subject.parse_value_type(Object.new)
|
||||
}.to raise_error ArgumentError
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
context 'with different data types' 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
|
||||
|
||||
class TestSmallThanTenValidator
|
||||
def initialize(opts)
|
||||
end
|
||||
def valid_value?(v)
|
||||
v < 10
|
||||
end
|
||||
def error_message
|
||||
''
|
||||
end
|
||||
end
|
||||
|
||||
before do
|
||||
settings.setting(:type_null, nil)
|
||||
settings.setting(:type_int, 1)
|
||||
settings.setting(:type_true, true)
|
||||
settings.setting(:type_false, false)
|
||||
settings.setting(:type_float, 2.3232)
|
||||
settings.setting(:type_string, 'string')
|
||||
settings.setting(:type_enum_default_string, '2', type: 'enum', choices: ['2'])
|
||||
settings.setting(:type_enum_class, 'en', enum: 'TestEnumClass')
|
||||
settings.setting(:type_validator, 5, validator: 'TestSmallThanTenValidator')
|
||||
settings.setting(:type_mock_validate_method, 'no_value')
|
||||
settings.setting(:type_custom, 'custom', type: 'list')
|
||||
settings.refresh!
|
||||
end
|
||||
|
||||
describe '.to_db_value' do
|
||||
let(:true_val) { 't' }
|
||||
let(:false_val) { 'f' }
|
||||
|
||||
it 'returns nil value' do
|
||||
expect(settings.type_supervisor.to_db_value(:type_null, nil)).to eq [nil, SiteSetting.types[:null]]
|
||||
end
|
||||
|
||||
it 'gives a second chance to guess even told :null type' do
|
||||
expect(settings.type_supervisor.to_db_value(:type_null, 1)).to eq [1, SiteSetting.types[:integer]]
|
||||
end
|
||||
|
||||
it 'writes `t` or `f` given the possible bool value' do
|
||||
expect(settings.type_supervisor.to_db_value(:type_true, true)).to eq [true_val, SiteSetting.types[:bool]]
|
||||
expect(settings.type_supervisor.to_db_value(:type_true, 't')).to eq [true_val, SiteSetting.types[:bool]]
|
||||
expect(settings.type_supervisor.to_db_value(:type_true, 'true')).to eq [true_val, SiteSetting.types[:bool]]
|
||||
expect(settings.type_supervisor.to_db_value(:type_true, false)).to eq [false_val, SiteSetting.types[:bool]]
|
||||
end
|
||||
|
||||
it 'writes `f` if given not `true` value' do
|
||||
expect(settings.type_supervisor.to_db_value(:type_true, '')).to eq [false_val, SiteSetting.types[:bool]]
|
||||
expect(settings.type_supervisor.to_db_value(:type_true, nil)).to eq [false_val, SiteSetting.types[:bool]]
|
||||
end
|
||||
|
||||
it 'returns floats value' do
|
||||
expect(settings.type_supervisor.to_db_value(:type_float, 1.2)).to eq [1.2, SiteSetting.types[:float]]
|
||||
expect(settings.type_supervisor.to_db_value(:type_float, 1)).to eq [1.0, SiteSetting.types[:float]]
|
||||
end
|
||||
|
||||
it 'returns string value' do
|
||||
expect(settings.type_supervisor.to_db_value(:type_string, 'a')).to eq ['a', SiteSetting.types[:string]]
|
||||
end
|
||||
|
||||
it 'returns enum value with string default' do
|
||||
expect(settings.type_supervisor.to_db_value(:type_enum_default_string, 2)).to eq ['2', SiteSetting.types[:enum]]
|
||||
expect(settings.type_supervisor.to_db_value(:type_enum_default_string, '2')).to eq ['2', SiteSetting.types[:enum]]
|
||||
end
|
||||
|
||||
it 'raises when it does not in the enum choices' do
|
||||
expect {
|
||||
settings.type_supervisor.to_db_value(:type_enum_default_string, 'random')
|
||||
}.to raise_error Discourse::InvalidParameters
|
||||
end
|
||||
|
||||
it 'returns enum value for the given enum class' do
|
||||
expect(settings.type_supervisor.to_db_value(:type_enum_class, 'en')).to eq ['en', SiteSetting.types[:enum]]
|
||||
end
|
||||
|
||||
it 'raises when it does not in the enum class' do
|
||||
expect {
|
||||
settings.type_supervisor.to_db_value(:type_enum_class, 'random')
|
||||
}.to raise_error Discourse::InvalidParameters
|
||||
end
|
||||
|
||||
it 'validates value by validator' do
|
||||
expect(settings.type_supervisor.to_db_value(:type_validator, 1)).to eq [1, SiteSetting.types[:integer]]
|
||||
end
|
||||
|
||||
it 'raises when the validator says so' do
|
||||
expect {
|
||||
settings.type_supervisor.to_db_value(:type_validator, 11)
|
||||
}.to raise_error Discourse::InvalidParameters
|
||||
end
|
||||
|
||||
it 'tries invoke validate methods' do
|
||||
settings.type_supervisor.expects(:validate_type_mock_validate_method).with('no')
|
||||
settings.type_supervisor.to_db_value(:type_mock_validate_method, 'no')
|
||||
end
|
||||
end
|
||||
|
||||
describe '.to_rb_value' do
|
||||
let(:true_val) { 't' }
|
||||
let(:false_val) { 'f' }
|
||||
|
||||
it 'the type can be overriden by a parameter' do
|
||||
expect(settings.type_supervisor.to_rb_value(:type_null, '1', SiteSetting.types[:integer])).to eq(1)
|
||||
end
|
||||
|
||||
it 'returns nil value' do
|
||||
expect(settings.type_supervisor.to_rb_value(:type_null, '1')).to eq nil
|
||||
expect(settings.type_supervisor.to_rb_value(:type_null, 1)).to eq nil
|
||||
expect(settings.type_supervisor.to_rb_value(:type_null, 'null')).to eq nil
|
||||
expect(settings.type_supervisor.to_rb_value(:type_null, 'nil')).to eq nil
|
||||
end
|
||||
|
||||
it 'returns true when it is true or `t` or `true`' do
|
||||
expect(settings.type_supervisor.to_rb_value(:type_true, true)).to eq true
|
||||
expect(settings.type_supervisor.to_rb_value(:type_true, 't')).to eq true
|
||||
expect(settings.type_supervisor.to_rb_value(:type_true, 'true')).to eq true
|
||||
end
|
||||
|
||||
it 'returns false if not one of `true` value' do
|
||||
expect(settings.type_supervisor.to_rb_value(:type_true, 'tr')).to eq false
|
||||
expect(settings.type_supervisor.to_rb_value(:type_true, '')).to eq false
|
||||
expect(settings.type_supervisor.to_rb_value(:type_true, nil)).to eq false
|
||||
expect(settings.type_supervisor.to_rb_value(:type_true, false)).to eq false
|
||||
expect(settings.type_supervisor.to_rb_value(:type_true, 'f')).to eq false
|
||||
expect(settings.type_supervisor.to_rb_value(:type_true, 'false')).to eq false
|
||||
end
|
||||
|
||||
it 'returns float value' do
|
||||
expect(settings.type_supervisor.to_rb_value(:type_float, 1.2)).to eq 1.2
|
||||
expect(settings.type_supervisor.to_rb_value(:type_float, 1)).to eq 1.0
|
||||
expect(settings.type_supervisor.to_rb_value(:type_float, '2.2')).to eq 2.2
|
||||
expect(settings.type_supervisor.to_rb_value(:type_float, '2')).to eq 2
|
||||
end
|
||||
|
||||
it 'returns string value' do
|
||||
expect(settings.type_supervisor.to_rb_value(:type_string, 'a')).to eq 'a'
|
||||
expect(settings.type_supervisor.to_rb_value(:type_string, 2)).to eq '2'
|
||||
end
|
||||
|
||||
it 'returns value with string default' do
|
||||
expect(settings.type_supervisor.to_rb_value(:type_enum_default_string, 2)).to eq '2'
|
||||
expect(settings.type_supervisor.to_rb_value(:type_enum_default_string, '2')).to eq '2'
|
||||
end
|
||||
|
||||
it 'returns value with a custom type' do
|
||||
expect(settings.type_supervisor.to_rb_value(:type_custom, 2)).to eq 2
|
||||
expect(settings.type_supervisor.to_rb_value(:type_custom, '2|3')).to eq '2|3'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '.type_hash' do
|
||||
class TestEnumClass2
|
||||
def self.valid_value?(v)
|
||||
self.values.include?(v)
|
||||
end
|
||||
def self.values
|
||||
['a', 'b']
|
||||
end
|
||||
def self.translate_names?
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
before do
|
||||
settings.setting(:type_null, nil)
|
||||
settings.setting(:type_int, 1)
|
||||
settings.setting(:type_true, true)
|
||||
settings.setting(:type_float, 2.3232)
|
||||
settings.setting(:type_string, 'string')
|
||||
settings.setting(:type_url_list, 'string', type: 'url_list')
|
||||
settings.setting(:type_enum_choices, '2', type: 'enum', choices: ['1', '2'])
|
||||
settings.setting(:type_enum_class, 'a', enum: 'TestEnumClass2')
|
||||
settings.setting(:type_list, 'a', type: 'list', choices: ['a', 'b'])
|
||||
settings.refresh!
|
||||
end
|
||||
|
||||
it 'returns null type' do
|
||||
expect(settings.type_supervisor.type_hash(:type_null)[:type]).to eq 'null'
|
||||
end
|
||||
it 'returns int type' do
|
||||
expect(settings.type_supervisor.type_hash(:type_int)[:type]).to eq 'integer'
|
||||
end
|
||||
it 'returns bool type' do
|
||||
expect(settings.type_supervisor.type_hash(:type_true)[:type]).to eq 'bool'
|
||||
end
|
||||
it 'returns float type' do
|
||||
expect(settings.type_supervisor.type_hash(:type_float)[:type]).to eq 'float'
|
||||
end
|
||||
it 'returns string type' do
|
||||
expect(settings.type_supervisor.type_hash(:type_string)[:type]).to eq 'string'
|
||||
end
|
||||
it 'returns url_list type' do
|
||||
expect(settings.type_supervisor.type_hash(:type_url_list)[:type]).to eq 'url_list'
|
||||
end
|
||||
it 'returns enum type' do
|
||||
expect(settings.type_supervisor.type_hash(:type_enum_choices)[:type]).to eq 'enum'
|
||||
end
|
||||
|
||||
it 'returns list choices' do
|
||||
expect(settings.type_supervisor.type_hash(:type_list)[:choices]).to eq ['a', 'b']
|
||||
end
|
||||
|
||||
it 'returns enum choices' do
|
||||
hash = settings.type_supervisor.type_hash(:type_enum_choices)
|
||||
expect(hash[:valid_values]).to eq [{ name: '1', value: '1' }, { name: '2', value: '2' }]
|
||||
expect(hash[:translate_names]).to eq false
|
||||
end
|
||||
|
||||
it 'returns enum class' do
|
||||
hash = settings.type_supervisor.type_hash(:type_enum_class)
|
||||
expect(hash[:valid_values]).to eq ['a', 'b']
|
||||
expect(hash[:translate_names]).to eq false
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
|
@ -8,26 +8,18 @@ describe SiteSettings::YamlLoader do
|
|||
|
||||
def load_yaml(file_arg)
|
||||
SiteSettings::YamlLoader.new(file_arg).load do |category, name, default, opts|
|
||||
if opts.delete(:client)
|
||||
client_setting(category, name, default, opts)
|
||||
else
|
||||
setting(category, name, default, opts)
|
||||
end
|
||||
setting(category, name, default, opts)
|
||||
end
|
||||
end
|
||||
|
||||
def setting(category, name, default = nil, opts = {})
|
||||
@settings ||= []
|
||||
@client_settings ||= []
|
||||
@settings << name
|
||||
@categories ||= []
|
||||
@categories << category
|
||||
@categories.uniq!
|
||||
end
|
||||
|
||||
def client_setting(category, name, default = nil)
|
||||
@client_settings ||= []
|
||||
@client_settings << name
|
||||
setting(category, name, default)
|
||||
@client_settings << name if opts.has_key?(:client)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -36,7 +28,9 @@ describe SiteSettings::YamlLoader do
|
|||
let(:client) { "#{Rails.root}/spec/fixtures/site_settings/client.yml" }
|
||||
let(:enum) { "#{Rails.root}/spec/fixtures/site_settings/enum.yml" }
|
||||
let(:enum_client) { "#{Rails.root}/spec/fixtures/site_settings/enum_client.yml" }
|
||||
let(:env) { "#{Rails.root}/spec/fixtures/site_settings/env.yml" }
|
||||
let(:deprecated_env) { "#{Rails.root}/spec/fixtures/site_settings/deprecated_env.yml" }
|
||||
let(:deprecated_hidden) { "#{Rails.root}/spec/fixtures/site_settings/deprecated_hidden.yml" }
|
||||
let(:locale_default) { "#{Rails.root}/spec/fixtures/site_settings/locale_default.yml" }
|
||||
|
||||
it "loads simple settings" do
|
||||
receiver.expects(:setting).with('category1', 'title', 'My Site', {}).once
|
||||
|
@ -57,9 +51,9 @@ describe SiteSettings::YamlLoader do
|
|||
end
|
||||
|
||||
it "can load client settings" do
|
||||
receiver.expects(:client_setting).with('category1', 'title', 'Discourse', {})
|
||||
receiver.expects(:client_setting).with('category2', 'tos_url', '', {})
|
||||
receiver.expects(:client_setting).with('category2', 'must_approve_users', false, {})
|
||||
receiver.expects(:setting).with('category1', 'title', 'Discourse', client: true)
|
||||
receiver.expects(:setting).with('category2', 'tos_url', '', client: true)
|
||||
receiver.expects(:setting).with('category2', 'must_approve_users', false, client: true)
|
||||
receiver.load_yaml(client)
|
||||
end
|
||||
|
||||
|
@ -69,15 +63,22 @@ describe SiteSettings::YamlLoader do
|
|||
end
|
||||
|
||||
it "can load enum client settings" do
|
||||
receiver.expects(:client_setting).with do |category, name, default, opts|
|
||||
category == ('basics') && name == ('default_locale') && default == ('en') && opts[:enum] == ('LocaleSiteSetting')
|
||||
receiver.expects(:setting).with do |category, name, default, opts|
|
||||
category == ('basics') && name == ('default_locale') && default == ('en') && opts[:enum] == ('LocaleSiteSetting') && opts[:client] == true
|
||||
end
|
||||
receiver.load_yaml(enum_client)
|
||||
end
|
||||
|
||||
it "can load settings based on environment" do
|
||||
receiver.expects(:setting).with('misc', 'port', '', {})
|
||||
receiver.expects(:client_setting).with('misc', 'crawl_images', false, {})
|
||||
receiver.load_yaml(env)
|
||||
it "raises deprecation when load settings based on environment" do
|
||||
expect { receiver.load_yaml(deprecated_env) }.to raise_error(Discourse::Deprecation)
|
||||
end
|
||||
|
||||
it "raises deprecation when hidden property is based on environment" do
|
||||
expect { receiver.load_yaml(deprecated_hidden) }.to raise_error(Discourse::Deprecation)
|
||||
end
|
||||
|
||||
it "can load settings with locale default" do
|
||||
receiver.expects(:setting).with('search', 'min_search_term_length', 3, min: 2, client: true, locale_default: { zh_CN: 2, zh_TW: 2 })
|
||||
receiver.load_yaml(locale_default)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -27,6 +27,7 @@ describe Admin::SiteSettingsController do
|
|||
|
||||
before do
|
||||
SiteSetting.setting(:test_setting, "default")
|
||||
SiteSetting.refresh!
|
||||
end
|
||||
|
||||
it 'sets the value when the param is present' do
|
||||
|
@ -49,6 +50,7 @@ describe Admin::SiteSettingsController do
|
|||
|
||||
it 'does not allow changing of hidden settings' do
|
||||
SiteSetting.setting(:hidden_setting, "hidden", hidden: true)
|
||||
SiteSetting.refresh!
|
||||
result = xhr :put, :update, id: 'hidden_setting', hidden_setting: 'not allowed'
|
||||
expect(SiteSetting.hidden_setting).to eq("hidden")
|
||||
expect(result.status).to eq(422)
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
developer:
|
||||
force_hostname:
|
||||
hidden:
|
||||
development: false
|
||||
default: true
|
||||
default: ''
|
|
@ -0,0 +1,8 @@
|
|||
search:
|
||||
min_search_term_length:
|
||||
client: true
|
||||
default: 3
|
||||
locale_default:
|
||||
zh_CN: 2
|
||||
zh_TW: 2
|
||||
min: 2
|
|
@ -80,8 +80,8 @@ Spork.prefork do
|
|||
# and pretend they are default.
|
||||
# There are a bunch of settings that are seeded, they must be loaded as defaults
|
||||
SiteSetting.current.each do |k, v|
|
||||
# skip setting defauls for settings that are in unloaded plugins
|
||||
SiteSetting.defaults[k] = v if SiteSetting.respond_to? k
|
||||
# skip setting defaults for settings that are in unloaded plugins
|
||||
SiteSetting.defaults.set_regardless_of_locale(k, v) if SiteSetting.respond_to? k
|
||||
end
|
||||
|
||||
require_dependency 'site_settings/local_process_provider'
|
||||
|
@ -119,6 +119,7 @@ Spork.prefork do
|
|||
SiteSetting.provider.all.each do |setting|
|
||||
SiteSetting.remove_override!(setting.name)
|
||||
end
|
||||
SiteSetting.defaults.site_locale = SiteSettings::DefaultsProvider::DEFAULT_LOCALE
|
||||
|
||||
# very expensive IO operations
|
||||
SiteSetting.automatically_download_gravatars = false
|
||||
|
|
Loading…
Reference in New Issue