diff --git a/app/assets/javascripts/admin/models/site_setting.js b/app/assets/javascripts/admin/models/site_setting.js index 5e0ac79c1..5768208ad 100644 --- a/app/assets/javascripts/admin/models/site_setting.js +++ b/app/assets/javascripts/admin/models/site_setting.js @@ -78,7 +78,16 @@ Discourse.SiteSetting = Discourse.Model.extend({ }).then(function() { setting.set('originalValue', setting.get('value')); }); - } + }, + + validValues: function() { + var vals; + vals = Em.A(); + this.get("valid_values").each(function(v){ + vals.addObject({ name: v, value: v }); + }); + return vals; + }.property('valid_values') }); Discourse.SiteSetting.reopenClass({ diff --git a/app/assets/javascripts/admin/templates/site_settings/setting_enum.js.handlebars b/app/assets/javascripts/admin/templates/site_settings/setting_enum.js.handlebars new file mode 100644 index 000000000..a3d7920eb --- /dev/null +++ b/app/assets/javascripts/admin/templates/site_settings/setting_enum.js.handlebars @@ -0,0 +1,19 @@ +{{#with view.content}} +
+

{{unbound setting}}

+
+
+ {{combobox valueAttribute="value" content=validValues value=value}} +
{{unbound description}}
+
+ {{#if dirty}} +
+ + +
+ {{else}} + {{#if overridden}} + + {{/if}} + {{/if}} +{{/with}} \ No newline at end of file diff --git a/app/assets/javascripts/admin/views/site_setting_view.js b/app/assets/javascripts/admin/views/site_setting_view.js index 8a6dc7e28..140714aa2 100644 --- a/app/assets/javascripts/admin/views/site_setting_view.js +++ b/app/assets/javascripts/admin/views/site_setting_view.js @@ -12,7 +12,10 @@ Discourse.SiteSettingView = Discourse.View.extend({ templateName: function() { // If we're editing a boolean, return a different template - if (this.get('content.type') === 'bool') return 'admin/templates/site_settings/setting_bool' + if (this.get('content.type') === 'bool') return 'admin/templates/site_settings/setting_bool'; + + // If we're editing an enum field, show a dropdown + if (this.get('content.type') === 'enum' ) return 'admin/templates/site_settings/setting_enum'; // Default to string editor return 'admin/templates/site_settings/setting_string'; diff --git a/app/models/locale_site_setting.rb b/app/models/locale_site_setting.rb new file mode 100644 index 000000000..904a7fba5 --- /dev/null +++ b/app/models/locale_site_setting.rb @@ -0,0 +1,21 @@ +class LocaleSiteSetting + + def self.valid_value?(val) + supported_locales.include?(val) + end + + def self.all_values + supported_locales + end + + + private + + @lock = Mutex.new + + def self.supported_locales + @lock.synchronize do + @supported_locales ||= Dir.glob( File.join(Rails.root, 'config', 'locales', 'client.*.yml') ).map {|x| x.split('.')[-2]} + end + end +end diff --git a/app/models/site_setting.rb b/app/models/site_setting.rb index c31fd0cd6..acdf6ff46 100644 --- a/app/models/site_setting.rb +++ b/app/models/site_setting.rb @@ -203,7 +203,7 @@ class SiteSetting < ActiveRecord::Base setting(:title_fancy_entities, true) # The default locale for the site - setting(:default_locale, 'en') + setting(:default_locale, 'en', enum: 'LocaleSiteSetting') client_setting(:educate_until_posts, 2) diff --git a/lib/site_setting_extension.rb b/lib/site_setting_extension.rb index 60aff615d..f7ad6913e 100644 --- a/lib/site_setting_extension.rb +++ b/lib/site_setting_extension.rb @@ -3,7 +3,7 @@ require_dependency 'enum' module SiteSettingExtension def types - @types ||= Enum.new(:string, :time, :fixnum, :float, :bool, :null) + @types ||= Enum.new(:string, :time, :fixnum, :float, :bool, :null, :enum) end def mutex @@ -19,10 +19,15 @@ module SiteSettingExtension @defaults ||= {} end - def setting(name, default = nil) + def enums + @enums ||= {} + end + + def setting(name, default = nil, opts = {}) mutex.synchronize do self.defaults[name] = default current_value = current.has_key?(name) ? current[name] : default + enums[name] = opts[:enum] if opts[:enum] setup_methods(name, current_value) end end @@ -56,11 +61,12 @@ module SiteSettingExtension def all_settings @defaults.map do |s, v| value = send(s) + type = types[get_data_type(s, value)] {setting: s, description: description(s), default: v, - type: types[get_data_type(value)].to_s, - value: value.to_s} + type: type.to_s, + value: value.to_s}.merge( type == :enum ? {valid_values: enum_class(s).all_values} : {}) end end @@ -154,7 +160,7 @@ module SiteSettingExtension return unless table_exists? setting = SiteSetting.where(name: name).first - type = get_data_type(defaults[name]) + type = get_data_type(name, defaults[name]) if type == types[:bool] && val != true && val != false val = (val == "t" || val == "true") ? 't' : 'f' @@ -165,7 +171,11 @@ module SiteSettingExtension end if type == types[:null] && val != '' - type = get_data_type(val) + type = get_data_type(name, val) + end + + if type == types[:enum] + raise Discourse::InvalidParameters.new(:value) unless enum_class(name).valid_value?(val) end if setting @@ -182,10 +192,12 @@ module SiteSettingExtension protected - def get_data_type(val) + def get_data_type(name,val) return types[:null] if val.nil? - if String === val + if enums[name] + types[:enum] + elsif String === val types[:string] elsif Fixnum === val types[:fixnum] @@ -200,7 +212,7 @@ module SiteSettingExtension case type when types[:fixnum] value.to_i - when types[:string] + when types[:string], types[:enum] value when types[:bool] value == "t" @@ -242,6 +254,10 @@ module SiteSettingExtension super(method, *args, &block) end + def enum_class(name) + enums[name] = enums[name].constantize unless enums[name].is_a?(Class) + enums[name] + end end diff --git a/spec/controllers/admin/site_settings_controller_spec.rb b/spec/controllers/admin/site_settings_controller_spec.rb index 36d0b3982..1644ff2e3 100644 --- a/spec/controllers/admin/site_settings_controller_spec.rb +++ b/spec/controllers/admin/site_settings_controller_spec.rb @@ -26,7 +26,7 @@ describe Admin::SiteSettingsController do context 'update' do it 'requires a value parameter' do - lambda { xhr :put, :update, id: 'test_setting' }.should raise_error(ActionController::ParameterMissing) + lambda { xhr :put, :update, id: 'test_setting' }.should raise_error(ActionController::ParameterMissing) end it 'sets the value when the param is present' do diff --git a/spec/models/locale_site_setting_spec.rb b/spec/models/locale_site_setting_spec.rb new file mode 100644 index 000000000..c7114fb98 --- /dev/null +++ b/spec/models/locale_site_setting_spec.rb @@ -0,0 +1,21 @@ +require 'spec_helper' + +describe LocaleSiteSetting do + + describe 'valid_value?' do + it 'returns true for a locale that we have translations for' do + expect(LocaleSiteSetting.valid_value?('en')).to eq(true) + end + + it 'returns false for a locale that we do not have translations for' do + expect(LocaleSiteSetting.valid_value?('swedish-chef')).to eq(false) + end + end + + describe 'all_values' do + it 'returns all the locales that we have translations for' do + expect(LocaleSiteSetting.all_values.sort).to eq(Dir.glob( File.join(Rails.root, 'config', 'locales', 'client.*.yml') ).map {|x| x.split('.')[-2]}.sort) + end + end + +end diff --git a/spec/models/site_setting_spec.rb b/spec/models/site_setting_spec.rb index 31584f82b..62b6f3901 100644 --- a/spec/models/site_setting_spec.rb +++ b/spec/models/site_setting_spec.rb @@ -114,6 +114,35 @@ describe SiteSetting do end end + describe 'enum setting' do + before :all do + @enum_class = Class.new + SiteSetting.setting(:test_enum, 'en', enum: @enum_class) + SiteSetting.refresh! + end + + it 'should have the correct default' do + expect(SiteSetting.test_enum).to eq('en') + end + + context 'when overridden' do + after :each do + SiteSetting.remove_override!(:test_enum) + end + + it 'stores valid values' do + @enum_class.expects(:valid_value?).with('fr').returns(true) + SiteSetting.test_enum = 'fr' + expect(SiteSetting.test_enum).to eq('fr') + end + + it 'rejects invalid values' do + @enum_class.expects(:valid_value?).with('gg').returns(false) + expect { SiteSetting.test_enum = 'gg' }.to raise_error(Discourse::InvalidParameters) + end + end + end + describe 'call_discourse_hub?' do it 'should be true when enforce_global_nicknames is true and discourse_org_access_key is set' do SiteSetting.enforce_global_nicknames = true