Add site setting category support

This commit is contained in:
Neil Lalonde 2013-11-13 14:02:47 -05:00
parent 791f5ac94e
commit 1e37abc310
14 changed files with 397 additions and 285 deletions

View File

@ -103,21 +103,25 @@ Discourse.SiteSetting = Discourse.Model.extend({
Discourse.SiteSetting.reopenClass({
/**
Retrieve all settings from the server
@method findAll
**/
findAll: function() {
var result = Em.A();
Discourse.ajax("/admin/site_settings").then(function (settings) {
return Discourse.ajax("/admin/site_settings").then(function (settings) {
// Group the results by category
var categoryNames = [],
categories = {},
result = Em.A();
_.each(settings.site_settings,function(s) {
s.originalValue = s.value;
result.pushObject(Discourse.SiteSetting.create(s));
if (!categoryNames.contains(s.category)) {
categoryNames.pushObject(s.category);
categories[s.category] = Em.A();
}
categories[s.category].pushObject(Discourse.SiteSetting.create(s));
});
result.set('diags', settings.diags);
_.each(categoryNames, function(n) {
result.pushObject({nameKey: n, name: I18n.t('admin.site_settings.categories.' + n),siteSettings: categories[n]});
});
return result;
});
},
update: function(key, value) {
@ -126,6 +130,7 @@ Discourse.SiteSetting.reopenClass({
data: { value: value }
});
}
});

View File

@ -7,7 +7,9 @@
Discourse.Route.buildRoutes(function() {
this.resource('admin', { path: '/admin' }, function() {
this.route('dashboard', { path: '/' });
this.route('site_settings', { path: '/site_settings' });
this.resource('adminSiteSettings', { path: '/site_settings' }, function() {
this.resource('adminSiteSettingsCategory', { path: 'category/:category_id'} );
});
this.resource('adminSiteContents', { path: '/site_contents' }, function() {

View File

@ -0,0 +1,18 @@
/**
Handles routes related to viewing and editing site settings within one category.
@class AdminSiteSettingCategoryRoute
@extends Discourse.Route
@namespace Discourse
@module Discourse
**/
Discourse.AdminSiteSettingsCategoryRoute = Discourse.Route.extend({
model: function(params) {
var category = this.modelFor('adminSiteSettings').find(function(siteSettingCategory) {
return siteSettingCategory.nameKey === params.category_id;
});
if (category) {
return category.siteSettings;
}
}
});

View File

@ -11,3 +11,13 @@ Discourse.AdminSiteSettingsRoute = Discourse.Route.extend({
return Discourse.SiteSetting.findAll();
}
});
/**
Handles when you click the Site Settings tab in admin, but haven't
chosen a category. It will redirect to the first category.
**/
Discourse.AdminSiteSettingsIndexRoute = Discourse.Route.extend({
model: function() {
this.transitionTo('adminSiteSettingsCategory', this.modelFor('adminSiteSettings')[0].nameKey);
}
});

View File

@ -5,7 +5,7 @@
<ul class="nav nav-pills">
<li>{{#link-to 'admin.dashboard'}}{{i18n admin.dashboard.title}}{{/link-to}}</li>
{{#if currentUser.admin}}
<li>{{#link-to 'admin.site_settings'}}{{i18n admin.site_settings.title}}{{/link-to}}</li>
<li>{{#link-to 'adminSiteSettings'}}{{i18n admin.site_settings.title}}{{/link-to}}</li>
<li>{{#link-to 'adminSiteContents'}}{{i18n admin.site_content.title}}{{/link-to}}</li>
{{/if}}
<li>{{#link-to 'adminUsersList'}}{{i18n admin.users.title}}{{/link-to}}</li>

View File

@ -8,8 +8,14 @@
<div class='controls'>
{{textField value=filter placeholderKey="type_to_filter"}}
</div>
</div>
{{collection contentBinding="filteredContent" classNames="form-horizontal settings" itemViewClass="Discourse.SiteSettingView"}}
<ul class="nav nav-pills">
{{#each category in controller}}
<li>{{#link-to 'adminSiteSettingsCategory' category.nameKey}}{{category.name}}{{/link-to}}</a></li>
{{/each}}
</ul>
<hr/>
{{ outlet }}

View File

@ -0,0 +1 @@
{{collection contentBinding="content" classNames="form-horizontal settings" itemViewClass="Discourse.SiteSettingView"}}

View File

@ -0,0 +1,3 @@
Discourse.AdminSiteSettingsCategoryView = Discourse.View.extend({
templateName: 'admin/templates/site_settings_category'
});

View File

@ -8,11 +8,10 @@ class SiteSetting < ActiveRecord::Base
validates_presence_of :data_type
SiteSettings::YamlLoader.new("#{Rails.root}/config/site_settings.yml").load do |category, name, default, opts|
# TODO: category support
if opts.delete(:client)
client_setting(name.to_sym, default)
client_setting(name, default, category)
else
setting(name.to_sym, default, opts)
setting(name, default, category, opts)
end
end

View File

@ -1417,5 +1417,13 @@ en:
title: 'Settings'
reset: 'reset to default'
none: 'none'
categories:
mandatory: 'Mandatory'
users: 'Users'
posting: 'Posting'
email: 'Email'
files: 'Files'
trust: 'Trust Levels'
spam: 'Spam'
rate_limits: 'Rate Limits'
uncategorized: 'Uncategorized'

View File

@ -21,8 +21,11 @@ Discourse::Application.routes.draw do
namespace :admin, constraints: StaffConstraint.new do
get '' => 'admin#index'
resources :site_settings, constraints: AdminConstraint.new
resources :site_settings, constraints: AdminConstraint.new do
collection do
get 'category/:id' => 'site_settings#index'
end
end
get 'reports/:type' => 'reports#show'

View File

@ -1,239 +1,41 @@
all:
mandatory:
title:
client: true
default: 'Discourse'
site_description: ''
contact_email: ''
notification_email: 'info@discourse.org'
site_contact_username: ''
logo_url:
client: true
default: '/assets/d-logo-sketch.png'
logo_small_url:
client: true
default: '/assets/d-logo-sketch-small.png'
contact_email: ''
company_full_name: 'My Unconfigured Forum Ltd.'
company_short_name: 'Unconfigured Forum'
company_domain: 'www.example.com'
tos_url:
client: true
default: ''
faq_url:
client: true
default: ''
privacy_policy_url:
client: true
default: ''
traditional_markdown_linebreaks:
client: true
default: false
top_menu:
client: true
default: 'latest|new|unread|favorited|categories'
post_menu:
client: true
default: 'like|edit|flag|delete|share|bookmark|reply'
share_links:
client: true
default: 'twitter|facebook|google+|email'
track_external_right_clicks:
client: true
default: false
must_approve_users:
client: true
default: false
ga_tracking_code:
client: true
default: ''
ga_domain_name:
client: true
default: ''
enable_escaped_fragments:
client: true
default: false
enable_noscript_support:
client: true
default: true
enable_long_polling:
client: true
default: true
polling_interval:
client: true
default: 3000
anon_polling_interval:
client: true
default: 30000
min_post_length:
client: true
default:
test: 5
default: 20
min_private_message_post_length:
client: true
default:
test: 5
default: 10
max_post_length:
client: true
default: 32000
min_topic_title_length:
client: true
default: 15
max_topic_title_length:
client: true
default: 255
min_private_message_title_length:
client: true
default: 2
allow_uncategorized_topics:
client: true
default: true
min_search_term_length:
client: true
default: 3
flush_timings_secs:
client: true
default: 5
suppress_reply_directly_below:
client: true
default: true
suppress_reply_directly_above:
client: true
default: true
email_domains_blacklist:
client: true
default: 'mailinator.com'
email_domains_whitelist:
client: true
default: ''
version_checks:
client: true
default: true
new_version_emails: true
min_title_similar_length:
client: true
default: 10
min_body_similar_length:
client: true
default: 15
category_colors:
client: true
default: 'BF1E2E|F1592A|F7941D|9EB83B|3AB54A|12A89D|25AAE2|0E76BD|652D90|92278F|ED207B|8C6238|231F20|808281|B3B5B4|283890'
enable_wide_category_list:
client: true
default: false
title_prettify: true
max_image_size_kb:
client: true
default: 2048
max_attachment_size_kb:
client: true
default: 1024
authorized_extensions:
client: true
default: '.jpg|.jpeg|.png|.gif'
auto_track_topics_after: 240000
new_topic_duration_minutes: 2880
long_polling_interval: 15000
flags_required_to_hide_post: 3
cooldown_minutes_after_hiding_posts: 10
max_topics_in_first_day: 5
max_replies_in_first_day: 10
num_flags_to_block_new_user: 3
num_users_to_block_new_user: 3
notify_mods_when_user_blocked: false
flag_sockpuppets: true
force_hostname: ''
port:
default:
development: 3000
default: ''
enable_private_messages: true
use_ssl: false
queue_jobs:
default:
test: false
default: true
crawl_images:
default:
test: false
default: true
max_image_width:
client: true
default: 690
max_image_height:
client: true
default: 500
create_thumbnails: true
category_featured_topics:
client: true
default: 6
topics_per_page: 30
posts_per_page:
client: true
default: 20
invite_expiry_days: 14
active_user_rate_limit_secs: 60
previous_visit_timeout_hours: 1
favicon_url:
client: true
default: '/assets/default-favicon.ico'
apple_touch_icon_url: /assets/default-apple-touch-icon.png'
ninja_edit_window: 300
edit_history_visible_to_public:
client: true
default: true
delete_removed_posts_after:
client: true
default: 24
post_undo_action_window_mins: 10
site_contact_username: ''
max_mentions_per_post: 10
newuser_max_mentions_per_post: 2
unique_posts_mins:
default:
test: 0
default: 5
rate_limit_create_topic: 5
rate_limit_create_post: 5
max_topics_per_day: 20
max_private_messages_per_day: 20
max_likes_per_day: 50
max_bookmarks_per_day: 20
max_flags_per_day: 20
max_edits_per_day: 30
max_favorites_per_day: 20
email_time_window_mins: 10
email_posts_context: 5
default_digest_email_frequency:
default: 7
enum: 'DigestEmailSiteSetting'
onebox_max_chars: 5000
suggested_topics: 5
allow_duplicate_topic_titles: false
staff_like_weight: 3
add_rel_nofollow_to_user_content: true
exclude_rel_nofollow_domains: ''
post_excerpt_maxlength: 300
post_onebox_maxlength: 500
best_of_score_threshold: 15
best_of_posts_required: 50
best_of_likes_required: 1
best_of_percent_filter: 20
notification_email: 'info@discourse.org'
email_custom_headers: 'Auto-Submitted: auto-generated'
allow_index_in_robots_txt: true
send_welcome_message: true
invite_only:
client: true
default: false
login_required:
client: true
default: false
company_full_name: 'My Unconfigured Forum Ltd.'
company_short_name: 'Unconfigured Forum'
company_domain: 'www.example.com'
users:
enable_local_logins:
client: true
default: true
enable_local_account_create:
client: true
default: true
invite_only:
client: true
default: false
login_required:
client: true
default: false
must_approve_users:
client: true
default: false
enable_google_logins:
client: true
default: true
@ -265,6 +67,131 @@ all:
default: false
enforce_global_nicknames: true
discourse_org_access_key: ''
invite_expiry_days: 14
username_change_period: 3
email_editable: true
enable_names:
client: true
default: true
invites_shown:
client: true
default: 30
delete_user_max_age:
client: true
default: 14
delete_all_posts_max: 15
posting:
min_post_length:
client: true
default:
test: 5
default: 20
min_private_message_post_length:
client: true
default:
test: 5
default: 10
max_post_length:
client: true
default: 32000
min_topic_title_length:
client: true
default: 15
max_topic_title_length:
client: true
default: 255
title_prettify: true
title_fancy_entities: true
min_private_message_title_length:
client: true
default: 2
allow_uncategorized_topics:
client: true
default: true
allow_duplicate_topic_titles: false
min_title_similar_length:
client: true
default: 10
min_body_similar_length:
client: true
default: 15
enable_private_messages: true
ninja_edit_window: 300
edit_history_visible_to_public:
client: true
default: true
delete_removed_posts_after:
client: true
default: 24
traditional_markdown_linebreaks:
client: true
default: false
suppress_reply_directly_below:
client: true
default: true
suppress_reply_directly_above:
client: true
default: true
post_undo_action_window_mins: 10
max_mentions_per_post: 10
newuser_max_mentions_per_post: 2
onebox_max_chars: 5000
title_min_entropy: 10
body_min_entropy: 7
max_word_length: 30
newuser_max_links: 2
newuser_max_images:
client: true
default: 0
newuser_max_attachments:
client: true
default: 0
uncategorized_category_id:
default: -1
hidden: true
post_excerpt_maxlength: 300
post_onebox_maxlength: 500
display_name_on_posts:
client: true
default: false
email:
email_time_window_mins: 10
email_posts_context: 5
default_digest_email_frequency:
default: 7
enum: 'DigestEmailSiteSetting'
email_custom_headers: 'Auto-Submitted: auto-generated'
reply_by_email_enabled: false
reply_by_email_address: ''
pop3s_polling_enabled: false
pop3s_polling_host: ''
pop3s_polling_port: 995
pop3s_polling_username: ''
pop3s_polling_password: ''
files:
max_image_size_kb:
client: true
default: 2048
max_attachment_size_kb:
client: true
default: 1024
authorized_extensions:
client: true
default: '.jpg|.jpeg|.png|.gif'
crawl_images:
default:
test: false
default: true
max_image_width:
client: true
default: 690
max_image_height:
client: true
default: 500
create_thumbnails: true
clean_up_uploads: false
uploads_grace_period_in_hours: 1
enable_s3_uploads: false
@ -274,10 +201,18 @@ all:
default: ''
enum: 'S3RegionSiteSetting'
s3_upload_bucket: ''
enable_flash_video_onebox: false
allow_uploaded_avatars:
client: true
default: true
allow_animated_avatars:
client: true
default: false
detect_custom_avatars: true
max_daily_gravatar_crawls: 500
trust:
default_trust_level: 0
default_invitee_trust_level: 1
allow_import: false
basic_requires_topics_entered: 5
basic_requires_read_posts: 50
basic_requires_time_spent_mins: 15
@ -291,25 +226,136 @@ all:
min_trust_to_create_topic:
default: 0
enum: 'MinTrustToCreateTopicSetting'
reply_by_email_enabled: false
reply_by_email_address: ''
pop3s_polling_enabled: false
pop3s_polling_host: ''
pop3s_polling_port: 995
pop3s_polling_username: ''
pop3s_polling_password: ''
title_min_entropy: 10
body_min_entropy: 7
max_word_length: 30
newuser_max_links: 2
newuser_max_images:
spam:
email_domains_blacklist:
client: true
default: 0
newuser_max_attachments:
default: 'mailinator.com'
email_domains_whitelist:
client: true
default: 0
default: ''
flags_required_to_hide_post: 3
cooldown_minutes_after_hiding_posts: 10
max_topics_in_first_day: 5
max_replies_in_first_day: 10
num_flags_to_block_new_user: 3
num_users_to_block_new_user: 3
notify_mods_when_user_blocked: false
flag_sockpuppets: true
newuser_spam_host_threshold: 3
title_fancy_entities: true
rate_limits:
unique_posts_mins:
default:
test: 0
default: 5
rate_limit_create_topic: 5
rate_limit_create_post: 5
max_topics_per_day: 20
max_private_messages_per_day: 20
max_likes_per_day: 50
max_bookmarks_per_day: 20
max_flags_per_day: 20
max_edits_per_day: 30
max_favorites_per_day: 20
uncategorized:
tos_url:
client: true
default: ''
faq_url:
client: true
default: ''
privacy_policy_url:
client: true
default: ''
top_menu:
client: true
default: 'latest|new|unread|favorited|categories'
post_menu:
client: true
default: 'like|edit|flag|delete|share|bookmark|reply'
share_links:
client: true
default: 'twitter|facebook|google+|email'
track_external_right_clicks:
client: true
default: false
ga_tracking_code:
client: true
default: ''
ga_domain_name:
client: true
default: ''
enable_escaped_fragments:
client: true
default: false
enable_noscript_support:
client: true
default: true
enable_long_polling:
client: true
default: true
polling_interval:
client: true
default: 3000
anon_polling_interval:
client: true
default: 30000
min_search_term_length:
client: true
default: 3
flush_timings_secs:
client: true
default: 5
version_checks:
client: true
default: true
new_version_emails: true
category_colors:
client: true
default: 'BF1E2E|F1592A|F7941D|9EB83B|3AB54A|12A89D|25AAE2|0E76BD|652D90|92278F|ED207B|8C6238|231F20|808281|B3B5B4|283890'
enable_wide_category_list:
client: true
default: false
auto_track_topics_after: 240000
new_topic_duration_minutes: 2880
long_polling_interval: 15000
force_hostname: ''
port:
default:
development: 3000
default: ''
use_ssl: false
queue_jobs:
default:
test: false
default: true
category_featured_topics:
client: true
default: 6
topics_per_page: 30
posts_per_page:
client: true
default: 20
active_user_rate_limit_secs: 60
previous_visit_timeout_hours: 1
suggested_topics: 5
staff_like_weight: 3
add_rel_nofollow_to_user_content: true
exclude_rel_nofollow_domains: ''
best_of_score_threshold: 15
best_of_posts_required: 50
best_of_likes_required: 1
best_of_percent_filter: 20
allow_index_in_robots_txt: true
send_welcome_message: true
enable_flash_video_onebox: false
allow_import: false
default_locale:
default: 'en'
enum: 'LocaleSiteSetting'
@ -330,34 +376,10 @@ all:
relative_date_duration:
client: true
default: 30
delete_user_max_age:
client: true
default: 14
delete_all_posts_max: 15
username_change_period: 3
email_editable: true
allow_uploaded_avatars:
client: true
default: true
allow_animated_avatars:
client: true
default: false
detect_custom_avatars: true
max_daily_gravatar_crawls: 500
sequential_replies_threshold: 2
enable_mobile_theme:
client: true
default: true
dominating_topic_minimum_percent: 20
uncategorized_category_id:
default: -1
hidden: true
display_name_on_posts:
client: true
default: false
enable_names:
client: true
default: true
invites_shown:
client: true
default: 30

View File

@ -30,6 +30,10 @@ module SiteSettingExtension
@defaults ||= {}
end
def categories
@categories ||= {}
end
def enums
@enums ||= {}
end
@ -38,9 +42,11 @@ module SiteSettingExtension
@hidden_settings ||= []
end
def setting(name, default = nil, opts = {})
def setting(name_arg, default = nil, category = nil, opts = {})
name = name_arg.to_sym
mutex.synchronize do
self.defaults[name] = default
categories[name] = category.try(:to_sym) || :uncategorized
current_value = current.has_key?(name) ? current[name] : default
if opts[:enum]
enum = opts[:enum]
@ -54,8 +60,8 @@ module SiteSettingExtension
end
# just like a setting, except that it is available in javascript via DiscourseSession
def client_setting(name, default = nil)
setting(name,default)
def client_setting(name, default = nil, category = nil)
setting(name, default, category)
@@client_settings ||= []
@@client_settings << name
end
@ -93,7 +99,8 @@ module SiteSettingExtension
description: description(s),
default: v,
type: type.to_s,
value: value.to_s}.merge( type == :enum ? {valid_values: enum_class(s).values, translate_names: enum_class(s).translate_names?} : {})
value: value.to_s,
category: categories[s]}.merge( type == :enum ? {valid_values: enum_class(s).values, translate_names: enum_class(s).translate_names?} : {})
end
end

View File

@ -161,4 +161,32 @@ describe SiteSettingExtension do
# end
# end
# end
describe 'a setting with a category' do
before do
settings.setting(:test_setting, 88, :tests)
settings.refresh!
end
it "should return the category in all_settings" do
settings.all_settings.find {|s| s[:setting] == :test_setting }[:category].should == :tests
end
context "when overidden" do
after :each do
settings.remove_override!(:test_setting)
end
it "should have the correct override" do
settings.test_setting = 101
settings.test_setting.should == 101
end
it "should still have the correct category" do
settings.test_setting = 102
settings.all_settings.find {|s| s[:setting] == :test_setting }[:category].should == :tests
end
end
end
end