discourse/app/models/site_customization.rb

172 lines
4.1 KiB
Ruby
Raw Normal View History

2013-02-05 14:16:51 -05:00
class SiteCustomization < ActiveRecord::Base
ENABLED_KEY = '7e202ef2-56d7-47d5-98d8-a9c8d15e57dd'
# placing this in uploads to ease deployment rules
CACHE_PATH = 'uploads/stylesheet-cache'
2013-02-07 10:45:24 -05:00
@lock = Mutex.new
2013-02-05 14:16:51 -05:00
2013-02-07 10:45:24 -05:00
before_create do
2013-02-05 14:16:51 -05:00
self.position ||= (SiteCustomization.maximum(:position) || 0) + 1
self.enabled ||= false
self.key ||= SecureRandom.uuid
true
end
2013-02-07 10:45:24 -05:00
before_save do
if stylesheet_changed?
2013-02-07 10:45:24 -05:00
begin
self.stylesheet_baked = Sass.compile stylesheet
2013-02-05 14:16:51 -05:00
rescue Sass::SyntaxError => e
error = e.sass_backtrace_str("custom stylesheet")
error.gsub!("\n", '\A ')
error.gsub!("'", '\27 ')
2013-02-07 10:45:24 -05:00
self.stylesheet_baked =
2013-02-05 14:16:51 -05:00
"#main {display: none;}
footer {white-space: pre; margin-left: 100px;}
footer:after{ content: '#{error}' }"
end
end
end
after_save do
if stylesheet_changed?
if File.exists?(stylesheet_fullpath)
File.delete stylesheet_fullpath
2013-02-05 14:16:51 -05:00
end
end
remove_from_cache!
if stylesheet_changed?
ensure_stylesheet_on_disk!
MessageBus.publish "/file-change/#{key}", stylesheet_hash
2013-02-05 14:16:51 -05:00
end
MessageBus.publish "/header-change/#{key}", header if header_changed?
2013-02-05 14:16:51 -05:00
end
2013-02-07 10:45:24 -05:00
after_destroy do
if File.exists?(stylesheet_fullpath)
File.delete stylesheet_fullpath
2013-02-05 14:16:51 -05:00
end
self.remove_from_cache!
end
def self.enabled_key
ENABLED_KEY.dup << RailsMultisite::ConnectionManagement.current_db
end
def self.enabled_style_key
@cache ||= {}
preview_style = @cache[enabled_key]
return if preview_style == :none
return preview_style if preview_style
2013-02-07 10:45:24 -05:00
@lock.synchronize do
style = where(enabled: true).first
if style
@cache[enabled_key] = style.key
else
@cache[enabled_key] = :none
nil
end
end
end
2013-02-05 14:16:51 -05:00
def self.custom_stylesheet(preview_style)
preview_style ||= enabled_style_key
2013-02-05 14:16:51 -05:00
style = lookup_style(preview_style)
style.stylesheet_link_tag.html_safe if style
end
def self.custom_header(preview_style)
preview_style ||= enabled_style_key
2013-02-05 14:16:51 -05:00
style = lookup_style(preview_style)
2013-02-07 02:25:18 -05:00
if style && style.header
style.header.html_safe
else
""
end
2013-02-05 14:16:51 -05:00
end
def self.override_default_style(preview_style)
preview_style ||= enabled_style_key
2013-02-05 14:16:51 -05:00
style = lookup_style(preview_style)
style.override_default_style if style
end
def self.lookup_style(key)
return if key.blank?
2013-02-07 10:45:24 -05:00
# cache is cross site resiliant cause key is secure random
2013-02-05 14:16:51 -05:00
@cache ||= {}
ensure_cache_listener
style = @cache[key]
return style if style
2013-02-07 10:45:24 -05:00
@lock.synchronize do
style = where(key: key).first
2013-02-19 01:57:14 -05:00
style.ensure_stylesheet_on_disk! if style
2013-02-05 14:16:51 -05:00
@cache[key] = style
end
end
def self.ensure_cache_listener
unless @subscribed
klass = self
MessageBus.subscribe("/site_customization") do |msg|
message = msg.data
2013-02-07 10:45:24 -05:00
klass.remove_from_cache!(message["key"], false)
2013-02-05 14:16:51 -05:00
end
@subscribed = true
end
end
def self.remove_from_cache!(key, broadcast = true)
MessageBus.publish('/site_customization', key: key) if broadcast
2013-02-05 14:16:51 -05:00
if @cache
2013-02-07 10:45:24 -05:00
@lock.synchronize do
2013-02-05 14:16:51 -05:00
@cache[key] = nil
end
end
end
def remove_from_cache!
self.class.remove_from_cache!(self.class.enabled_key)
self.class.remove_from_cache!(key)
2013-02-05 14:16:51 -05:00
end
def stylesheet_hash
Digest::MD5.hexdigest(stylesheet)
2013-02-05 14:16:51 -05:00
end
def cache_fullpath
"#{Rails.root}/public/#{CACHE_PATH}"
end
2013-02-05 14:16:51 -05:00
def ensure_stylesheet_on_disk!
path = stylesheet_fullpath
dir = cache_fullpath
2013-02-05 14:16:51 -05:00
FileUtils.mkdir_p(dir)
unless File.exists?(path)
File.open(path, "w") do |f|
f.puts stylesheet_baked
2013-02-05 14:16:51 -05:00
end
end
end
def stylesheet_filename
"/#{self.key}.css"
2013-02-05 14:16:51 -05:00
end
def stylesheet_fullpath
"#{cache_fullpath}#{stylesheet_filename}"
2013-02-05 14:16:51 -05:00
end
def stylesheet_link_tag
return "" unless stylesheet.present?
2013-02-05 14:16:51 -05:00
return @stylesheet_link_tag if @stylesheet_link_tag
ensure_stylesheet_on_disk!
@stylesheet_link_tag = "<link class=\"custom-css\" rel=\"stylesheet\" href=\"/#{CACHE_PATH}#{stylesheet_filename}?#{stylesheet_hash}\" type=\"text/css\" media=\"screen\">"
2013-02-05 14:16:51 -05:00
end
end