mirror of
https://github.com/discourse/discourse.git
synced 2025-05-22 16:21:18 +08:00
Initial release of Discourse
This commit is contained in:
230
lib/site_setting_extension.rb
Normal file
230
lib/site_setting_extension.rb
Normal file
@ -0,0 +1,230 @@
|
||||
module SiteSettingExtension
|
||||
|
||||
module Types
|
||||
String = 1
|
||||
Time = 2
|
||||
Fixnum = 3
|
||||
Float = 4
|
||||
Bool = 5
|
||||
Null = 6
|
||||
end
|
||||
|
||||
def mutex
|
||||
@mutex ||= Mutex.new
|
||||
end
|
||||
|
||||
def current
|
||||
@@containers ||= {}
|
||||
@@containers[RailsMultisite::ConnectionManagement.current_db] ||= {}
|
||||
end
|
||||
|
||||
def defaults
|
||||
@defaults ||= {}
|
||||
end
|
||||
|
||||
def setting(name, default = nil, type = nil)
|
||||
mutex.synchronize do
|
||||
self.defaults[name] = default
|
||||
current_value = current.has_key?(name) ? current[name] : default
|
||||
setup_methods(name, current_value)
|
||||
end
|
||||
end
|
||||
|
||||
# just like a setting, except that it is available in javascript via DiscourseSession
|
||||
def client_setting(name, defualt = nil, type = nil)
|
||||
setting(name,defualt,type)
|
||||
@@client_settings ||= []
|
||||
@@client_settings << name
|
||||
end
|
||||
|
||||
def client_settings
|
||||
@@client_settings
|
||||
end
|
||||
|
||||
|
||||
def client_settings_json
|
||||
Rails.cache.fetch(SiteSettingExtension.client_settings_cache_key, expires_in: 30.minutes) do
|
||||
MultiJson.dump(Hash[*@@client_settings.map{|n| [n, self.send(n)]}.flatten])
|
||||
end
|
||||
end
|
||||
|
||||
# Retrieve all settings
|
||||
def all_settings
|
||||
@defaults.map do |s, v|
|
||||
{setting: s,
|
||||
description: description(s),
|
||||
default: v,
|
||||
value: send(s).to_s}
|
||||
end
|
||||
end
|
||||
|
||||
def description(setting)
|
||||
I18n.t("site_settings.#{setting}")
|
||||
end
|
||||
|
||||
# table is not in the db yet, initial migration, etc
|
||||
def table_exists?
|
||||
@table_exists = ActiveRecord::Base.connection.table_exists? 'site_settings' if @table_exists == nil
|
||||
@table_exists
|
||||
end
|
||||
|
||||
def self.client_settings_cache_key
|
||||
"client_settings_json"
|
||||
end
|
||||
|
||||
# refresh all the site settings
|
||||
def refresh!
|
||||
return unless table_exists?
|
||||
mutex.synchronize do
|
||||
ensure_listen_for_changes
|
||||
old = current
|
||||
changes = []
|
||||
deletions = []
|
||||
|
||||
all_settings = SiteSetting.select([:name,:value,:data_type])
|
||||
new_hash = Hash[*(all_settings.map{|s| [s.name.intern, convert(s.value,s.data_type)]}.to_a.flatten)]
|
||||
|
||||
# add defaults
|
||||
new_hash = defaults.merge(new_hash)
|
||||
|
||||
new_hash.each do |name, value|
|
||||
changes << [name,value] if !old.has_key?(name) || old[name] != value
|
||||
end
|
||||
|
||||
old.each do |name,value|
|
||||
deletions << [name,value] unless new_hash.has_key?(name)
|
||||
end
|
||||
|
||||
if deletions.length > 0 || changes.length > 0
|
||||
@current = new_hash
|
||||
changes.each do |name, val|
|
||||
setup_methods name, val
|
||||
end
|
||||
deletions.each do |name,val|
|
||||
setup_methods name, defaults[name]
|
||||
end
|
||||
end
|
||||
|
||||
$redis.del(SiteSettingExtension.client_settings_cache_key)
|
||||
end
|
||||
end
|
||||
|
||||
def ensure_listen_for_changes
|
||||
unless @subscribed
|
||||
pid = process_id
|
||||
MessageBus.subscribe("/site_settings") do |msg|
|
||||
message = msg.data
|
||||
if message["process"] != pid
|
||||
begin
|
||||
# picks a db
|
||||
MessageBus.on_connect.call(msg.site_id)
|
||||
SiteSetting.refresh!
|
||||
ensure
|
||||
MessageBus.on_disconnect.call(msg.site_id)
|
||||
end
|
||||
end
|
||||
end
|
||||
@subscribed = true
|
||||
end
|
||||
end
|
||||
|
||||
def process_id
|
||||
@@process_id ||= SecureRandom.uuid
|
||||
end
|
||||
|
||||
def remove_override!(name)
|
||||
return unless table_exists?
|
||||
SiteSetting.where(:name => name).destroy_all
|
||||
end
|
||||
|
||||
def add_override!(name,val)
|
||||
return unless table_exists?
|
||||
|
||||
setting = SiteSetting.where(:name => name).first
|
||||
type = get_data_type(defaults[name])
|
||||
|
||||
if type == Types::Bool && val != true && val != false
|
||||
val = (val == "t" || val == "true")
|
||||
end
|
||||
|
||||
if type == Types::Fixnum && !(Fixnum === val)
|
||||
val = val.to_i
|
||||
end
|
||||
|
||||
if setting
|
||||
setting.value = val
|
||||
setting.data_type = type
|
||||
setting.save
|
||||
else
|
||||
SiteSetting.create!(:name => name, :value => val, :data_type => type)
|
||||
end
|
||||
|
||||
MessageBus.publish('/site_settings', {process: process_id})
|
||||
end
|
||||
|
||||
|
||||
protected
|
||||
|
||||
def get_data_type(val)
|
||||
return Types::Null if val.nil?
|
||||
|
||||
if String === val
|
||||
Types::String
|
||||
elsif Fixnum === val
|
||||
Types::Fixnum
|
||||
elsif TrueClass === val || FalseClass === val
|
||||
Types::Bool
|
||||
else
|
||||
raise ArgumentError.new :val
|
||||
end
|
||||
end
|
||||
|
||||
def convert(value, type)
|
||||
case type
|
||||
when Types::Fixnum
|
||||
value.to_i
|
||||
when Types::String
|
||||
value
|
||||
when Types::Bool
|
||||
value == "t"
|
||||
when Types::Null
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def setup_methods(name, current_value)
|
||||
|
||||
# trivial multi db support, we can optimize this later
|
||||
db = RailsMultisite::ConnectionManagement.current_db
|
||||
|
||||
@@containers ||= {}
|
||||
@@containers[db] ||= {}
|
||||
@@containers[db][name] = current_value
|
||||
|
||||
setter = ("#{name}=").sub("?","")
|
||||
|
||||
eval "define_singleton_method :#{name} do
|
||||
c = @@containers[RailsMultisite::ConnectionManagement.current_db]
|
||||
c = c[name] if c
|
||||
c
|
||||
end
|
||||
|
||||
define_singleton_method :#{setter} do |val|
|
||||
add_override!(:#{name}, val)
|
||||
refresh!
|
||||
end
|
||||
"
|
||||
end
|
||||
|
||||
def method_missing(method, *args, &block)
|
||||
as_question = method.to_s.gsub(/\?$/, '')
|
||||
if respond_to?(as_question)
|
||||
return send(as_question, *args, &block)
|
||||
end
|
||||
super(method, *args, &block)
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
Reference in New Issue
Block a user