FEATURE: new bootstrap mode settings for brand new Discourse community (#4193)

* FEATURE: new bootstrap mode settings for brand new Discourse community

* new SiteSetting.set_and_log method
This commit is contained in:
Arpit Jalan 2016-04-26 22:38:19 +05:30 committed by Robin Ward
parent 6c5548c2e4
commit 74b3807f60
15 changed files with 157 additions and 7 deletions

View File

@ -17,6 +17,14 @@ export default Ember.Component.extend(StringBuffer, {
notices.push([I18n.t("emails_are_disabled"), 'alert-emails-disabled']);
}
if (this.currentUser && this.currentUser.get('staff') && this.siteSettings.bootstrap_mode_enabled) {
if (this.siteSettings.bootstrap_mode_min_users > 0) {
notices.push([I18n.t("bootstrap_mode_enabled", {min_users: this.siteSettings.bootstrap_mode_min_users}), 'alert-bootstrap-mode']);
} else {
notices.push([I18n.t("bootstrap_mode_disabled"), 'alert-bootstrap-mode']);
}
}
if (!_.isEmpty(this.siteSettings.global_notice)) {
notices.push([this.siteSettings.global_notice, 'alert-global-notice']);
}

View File

@ -10,9 +10,7 @@ class Admin::SiteSettingsController < Admin::AdminController
value = params[id]
value.strip! if value.is_a?(String)
begin
prev_value = SiteSetting.send(id)
SiteSetting.set(id, value)
StaffActionLogger.new(current_user).log_site_setting_change(id, prev_value, value) if SiteSetting.has_setting?(id)
SiteSetting.set_and_log(id, value, current_user)
render nothing: true
rescue Discourse::InvalidParameters => e
render json: {errors: [e.message]}, status: 422

View File

@ -0,0 +1,18 @@
module Jobs
class EnableBootstrapMode < Jobs::Base
sidekiq_options queue: 'critical'
def execute(args)
raise Discourse::InvalidParameters.new(:user_id) unless args[:user_id].present?
return if SiteSetting.bootstrap_mode_enabled
user = User.find_by(id: args[:user_id])
return unless user.is_singular_admin?
# let's enable bootstrap mode settings
SiteSetting.set_and_log('default_trust_level', TrustLevel[1])
SiteSetting.set_and_log('default_email_digest_frequency', 1440)
SiteSetting.set_and_log('bootstrap_mode_enabled', true)
end
end
end

View File

@ -0,0 +1,16 @@
module Jobs
class DisableBootstrapMode < Jobs::Scheduled
every 1.day
def execute(args)
return unless SiteSetting.bootstrap_mode_enabled
total_users = User.where.not(id: Discourse::SYSTEM_USER_ID).count
if SiteSetting.bootstrap_mode_min_users == 0 || total_users > SiteSetting.bootstrap_mode_min_users
SiteSetting.set_and_log('default_trust_level', TrustLevel[0])
SiteSetting.set_and_log('default_email_digest_frequency', 10080)
SiteSetting.set_and_log('bootstrap_mode_enabled', false)
end
end
end
end

View File

@ -845,6 +845,10 @@ class User < ActiveRecord::Base
custom_fields["master_id"].to_i > 0
end
def is_singular_admin?
User.where(admin: true).where.not(id: id).where.not(id: Discourse::SYSTEM_USER_ID).blank?
end
protected
def badge_grant

View File

@ -147,6 +147,9 @@ en:
emails_are_disabled: "All outgoing email has been globally disabled by an administrator. No email notifications of any kind will be sent."
bootstrap_mode_enabled: "To make launching your new site easier, you are in bootstrap mode. All new users will be granted trust level 1 and have daily email digest updates enabled. This will be automatically turned off when total user count exceeds %{min_users} users."
bootstrap_mode_disabled: "Bootstrap mode will be disabled in next 24 hours."
s3:
regions:
us_east_1: "US East (N. Virginia)"

View File

@ -1272,6 +1272,8 @@ en:
delete_drafts_older_than_n_days: Delete drafts older than (n) days.
bootstrap_mode_min_users: "Minimum number of users required to disable bootstrap mode (set to 0 to disable)"
vacuum_db_days: "Run VACUUM ANALYZE to reclaim DB space after migrations (set to 0 to disable)"
prevent_anons_from_downloading_files: "Prevent anonymous users from downloading attachments. WARNING: this will prevent any non-image site assets posted as attachments from working."

View File

@ -1090,6 +1090,17 @@ uncategorized:
default: -1
hidden: true
bootstrap_mode_min_users:
default: 50
client: true
min: 0
max: 5000
bootstrap_mode_enabled:
default: false
client: true
hidden: true
automatically_unpin_topics:
default: true
client: true

View File

@ -68,6 +68,7 @@ class Auth::DefaultCurrentUserProvider
end
cookies.permanent[TOKEN_COOKIE] = { value: user.auth_token, httponly: true }
make_developer_admin(user)
enable_bootstrap_mode(user)
@env[CURRENT_USER_KEY] = user
end
@ -81,6 +82,10 @@ class Auth::DefaultCurrentUserProvider
end
end
def enable_bootstrap_mode(user)
Jobs.enqueue(:enable_bootstrap_mode, user_id: user.id) if user.admin && user.last_seen_at.nil? && !SiteSetting.bootstrap_mode_enabled && user.is_singular_admin?
end
def log_off_user(session, cookies)
if SiteSetting.log_out_strict && (user = current_user)
user.auth_token = nil

View File

@ -371,6 +371,12 @@ module SiteSettingExtension
end
end
def set_and_log(name, value, user=Discourse.system_user)
prev_value = send(name)
set(name, value)
StaffActionLogger.new(user).log_site_setting_change(name, prev_value, value) if has_setting?(name)
end
protected
def clear_cache!

View File

@ -64,7 +64,7 @@ describe CategoriesController do
expect(category.slug).to eq("hello-cat")
expect(category.color).to eq("ff0")
expect(category.auto_close_hours).to eq(72)
expect(UserHistory.count).to eq(1)
expect(UserHistory.count).to eq(4) # 1 + 3 (bootstrap mode)
end
end
end
@ -228,7 +228,7 @@ describe CategoriesController do
"everyone" => CategoryGroup.permission_types[:create_post]
}
expect(UserHistory.count).to eq(2)
expect(UserHistory.count).to eq(5) # 2 + 3 (bootstrap mode)
end
end
end

View File

@ -77,9 +77,8 @@ describe UploadsController do
end
it 'correctly sets retain_hours for admins' do
Jobs.expects(:enqueue).with(:create_thumbnails, anything)
log_in :admin
Jobs.expects(:enqueue).with(:create_thumbnails, anything)
message = MessageBus.track_publish do
xhr :post, :create, file: logo, retain_hours: 100, type: "profile_background"

View File

@ -0,0 +1,33 @@
require 'rails_helper'
describe Jobs::DisableBootstrapMode do
context '.execute' do
let(:admin) { Fabricate(:admin) }
before do
SiteSetting.bootstrap_mode_enabled = true
end
it 'does not execute if bootstrap mode is already disabled' do
SiteSetting.bootstrap_mode_enabled = false
StaffActionLogger.any_instance.expects(:log_site_setting_change).never
Jobs::DisableBootstrapMode.new.execute(user_id: admin.id)
end
it 'turns off bootstrap mode if bootstrap_mode_min_users is set to 0' do
SiteSetting.bootstrap_mode_min_users = 0
StaffActionLogger.any_instance.expects(:log_site_setting_change).times(3)
Jobs::DisableBootstrapMode.new.execute(user_id: admin.id)
end
it 'successfully turns off bootstrap mode' do
SiteSetting.bootstrap_mode_min_users = 5
6.times do
Fabricate(:user)
end
StaffActionLogger.any_instance.expects(:log_site_setting_change).times(3)
Jobs::DisableBootstrapMode.new.execute(user_id: admin.id)
end
end
end

View File

@ -0,0 +1,33 @@
require 'rails_helper'
describe Jobs::EnableBootstrapMode do
context '.execute' do
let(:admin) { Fabricate(:admin) }
before do
SiteSetting.bootstrap_mode_enabled = false
end
it 'raises an error when user_id is missing' do
expect { Jobs::EnableBootstrapMode.new.execute({}) }.to raise_error(Discourse::InvalidParameters)
end
it 'does not execute if bootstrap mode is already enabled' do
SiteSetting.bootstrap_mode_enabled = true
StaffActionLogger.any_instance.expects(:log_site_setting_change).never
Jobs::EnableBootstrapMode.new.execute(user_id: admin.id)
end
it 'does not turn on bootstrap mode if first admin already exists' do
first_admin = Fabricate(:admin)
StaffActionLogger.any_instance.expects(:log_site_setting_change).never
Jobs::EnableBootstrapMode.new.execute(user_id: admin.id)
end
it 'successfully turns on bootstrap mode' do
StaffActionLogger.any_instance.expects(:log_site_setting_change).times(3)
Jobs::EnableBootstrapMode.new.execute(user_id: admin.id)
end
end
end

View File

@ -330,6 +330,20 @@ describe User do
end
end
describe '.is_singular_admin?' do
it 'returns true if user is singular admin' do
admin = Fabricate(:admin)
expect(admin.is_singular_admin?).to eq(true)
end
it 'returns false if user is not the only admin' do
admin = Fabricate(:admin)
second_admin = Fabricate(:admin)
expect(admin.is_singular_admin?).to eq(false)
end
end
describe 'name heuristics' do
it 'is able to guess a decent name from an email' do
expect(User.suggest_name('sam.saffron@gmail.com')).to eq('Sam Saffron')