2014-05-03 05:46:03 +08:00
|
|
|
require_dependency 'sass/discourse_sass_compiler'
|
2014-11-21 05:32:16 +08:00
|
|
|
require_dependency 'sass/discourse_stylesheets'
|
2014-12-23 09:46:10 +08:00
|
|
|
require_dependency 'distributed_cache'
|
2014-04-01 19:42:14 +08:00
|
|
|
|
2013-02-06 03:16:51 +08:00
|
|
|
class SiteCustomization < ActiveRecord::Base
|
2013-02-07 15:11:56 +08:00
|
|
|
ENABLED_KEY = '7e202ef2-56d7-47d5-98d8-a9c8d15e57dd'
|
2014-12-23 09:46:10 +08:00
|
|
|
@cache = DistributedCache.new('site_customization')
|
2013-02-06 03:16:51 +08:00
|
|
|
|
2013-02-07 23:45:24 +08:00
|
|
|
before_create do
|
2013-02-06 03:16:51 +08:00
|
|
|
self.enabled ||= false
|
|
|
|
self.key ||= SecureRandom.uuid
|
|
|
|
true
|
|
|
|
end
|
|
|
|
|
2014-03-08 21:25:03 +08:00
|
|
|
def compile_stylesheet(scss)
|
2014-05-03 05:46:03 +08:00
|
|
|
DiscourseSassCompiler.compile(scss, 'custom')
|
2014-04-07 09:34:35 +08:00
|
|
|
rescue => e
|
|
|
|
puts e.backtrace.join("\n") unless Sass::SyntaxError === e
|
|
|
|
raise e
|
2014-03-08 21:25:03 +08:00
|
|
|
end
|
|
|
|
|
2013-02-07 23:45:24 +08:00
|
|
|
before_save do
|
2013-09-17 00:21:49 +08:00
|
|
|
['stylesheet', 'mobile_stylesheet'].each do |stylesheet_attr|
|
|
|
|
if self.send("#{stylesheet_attr}_changed?")
|
|
|
|
begin
|
2014-03-08 21:25:03 +08:00
|
|
|
self.send("#{stylesheet_attr}_baked=", compile_stylesheet(self.send(stylesheet_attr)))
|
2013-09-17 00:21:49 +08:00
|
|
|
rescue Sass::SyntaxError => e
|
2014-05-03 05:46:03 +08:00
|
|
|
self.send("#{stylesheet_attr}_baked=", DiscourseSassCompiler.error_as_css(e, "custom stylesheet"))
|
2013-09-17 00:21:49 +08:00
|
|
|
end
|
2013-02-06 03:16:51 +08:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2014-04-02 13:24:36 +08:00
|
|
|
after_save do
|
2013-03-01 02:54:12 +08:00
|
|
|
remove_from_cache!
|
2014-11-11 04:51:55 +08:00
|
|
|
if stylesheet_changed? || mobile_stylesheet_changed?
|
2015-05-04 10:21:00 +08:00
|
|
|
MessageBus.publish "/file-change/#{key}", SecureRandom.hex
|
|
|
|
MessageBus.publish "/file-change/#{SiteCustomization::ENABLED_KEY}", SecureRandom.hex
|
2013-02-06 03:16:51 +08:00
|
|
|
end
|
2015-05-04 10:21:00 +08:00
|
|
|
MessageBus.publish "/header-change/#{key}", header if header_changed?
|
|
|
|
MessageBus.publish "/footer-change/#{key}", footer if footer_changed?
|
2014-11-21 05:32:16 +08:00
|
|
|
DiscourseStylesheets.cache.clear
|
2013-02-06 03:16:51 +08:00
|
|
|
end
|
|
|
|
|
2014-04-02 13:24:36 +08:00
|
|
|
after_destroy do
|
2014-12-23 09:46:10 +08:00
|
|
|
remove_from_cache!
|
2013-02-06 03:16:51 +08:00
|
|
|
end
|
|
|
|
|
2013-02-07 21:55:04 +08:00
|
|
|
def self.enabled_key
|
|
|
|
ENABLED_KEY.dup << RailsMultisite::ConnectionManagement.current_db
|
|
|
|
end
|
|
|
|
|
2014-12-23 09:46:10 +08:00
|
|
|
def self.enabled_stylesheet_contents(target=:desktop)
|
|
|
|
@cache["enabled_stylesheet_#{target}"] ||= where(enabled: true)
|
|
|
|
.order(:name)
|
|
|
|
.pluck(target == :desktop ? :stylesheet_baked : :mobile_stylesheet_baked)
|
|
|
|
.compact
|
|
|
|
.join("\n")
|
2013-02-07 15:11:56 +08:00
|
|
|
end
|
2013-02-06 03:16:51 +08:00
|
|
|
|
2014-12-23 09:46:10 +08:00
|
|
|
def self.stylesheet_contents(key, target)
|
|
|
|
if key == ENABLED_KEY
|
|
|
|
enabled_stylesheet_contents(target)
|
2013-02-07 15:25:18 +08:00
|
|
|
else
|
2014-12-23 09:46:10 +08:00
|
|
|
where(key: key)
|
|
|
|
.pluck(target == :mobile ? :mobile_stylesheet_baked : :stylesheet_baked)
|
|
|
|
.first
|
2013-02-07 15:25:18 +08:00
|
|
|
end
|
2013-02-06 03:16:51 +08:00
|
|
|
end
|
|
|
|
|
2014-12-23 09:46:10 +08:00
|
|
|
def self.custom_stylesheet(preview_style=nil, target=:desktop)
|
|
|
|
preview_style ||= ENABLED_KEY
|
|
|
|
if preview_style == ENABLED_KEY
|
|
|
|
stylesheet_link_tag(ENABLED_KEY, target, enabled_stylesheet_contents(target))
|
2014-11-11 04:51:55 +08:00
|
|
|
else
|
2014-12-23 09:46:10 +08:00
|
|
|
lookup_field(preview_style, target, :stylesheet_link_tag)
|
2014-11-11 04:51:55 +08:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2015-01-14 18:52:42 +08:00
|
|
|
%i{header top footer head_tag body_tag}.each do |name|
|
|
|
|
define_singleton_method("custom_#{name}") do |preview_style=nil, target=:desktop|
|
|
|
|
preview_style ||= ENABLED_KEY
|
|
|
|
lookup_field(preview_style, target, name)
|
|
|
|
end
|
2014-12-23 09:46:10 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
def self.lookup_field(key, target, field)
|
2013-02-06 03:16:51 +08:00
|
|
|
return if key.blank?
|
2013-02-07 23:45:24 +08:00
|
|
|
|
2014-12-23 09:46:10 +08:00
|
|
|
cache_key = key + target.to_s + field.to_s;
|
2013-02-07 23:45:24 +08:00
|
|
|
|
2014-12-23 09:46:10 +08:00
|
|
|
lookup = @cache[cache_key]
|
|
|
|
return lookup.html_safe if lookup
|
2013-02-06 03:16:51 +08:00
|
|
|
|
2015-01-14 18:52:42 +08:00
|
|
|
styles = if key == ENABLED_KEY
|
|
|
|
order(:name).where(enabled:true).to_a
|
|
|
|
else
|
|
|
|
[find_by(key: key)].compact
|
|
|
|
end
|
2013-02-06 03:16:51 +08:00
|
|
|
|
2015-01-14 18:52:42 +08:00
|
|
|
val = if styles.present?
|
|
|
|
styles.map do |style|
|
|
|
|
lookup = target == :mobile ? "mobile_#{field}" : field
|
|
|
|
style.send(lookup)
|
|
|
|
end.compact.join("\n")
|
|
|
|
end
|
2014-12-23 09:46:10 +08:00
|
|
|
|
|
|
|
(@cache[cache_key] = val || "").html_safe
|
2013-02-06 03:16:51 +08:00
|
|
|
end
|
|
|
|
|
2013-03-01 02:54:12 +08:00
|
|
|
def self.remove_from_cache!(key, broadcast = true)
|
2015-05-04 10:21:00 +08:00
|
|
|
MessageBus.publish('/site_customization', key: key) if broadcast
|
2014-12-23 09:46:10 +08:00
|
|
|
clear_cache!
|
|
|
|
end
|
|
|
|
|
|
|
|
def self.clear_cache!
|
|
|
|
@cache.clear
|
2013-02-06 03:16:51 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
def remove_from_cache!
|
2013-02-07 21:55:04 +08:00
|
|
|
self.class.remove_from_cache!(self.class.enabled_key)
|
2013-03-01 02:54:12 +08:00
|
|
|
self.class.remove_from_cache!(key)
|
2013-02-06 03:16:51 +08:00
|
|
|
end
|
|
|
|
|
2014-12-23 09:46:10 +08:00
|
|
|
def mobile_stylesheet_link_tag
|
|
|
|
stylesheet_link_tag(:mobile)
|
2013-02-06 03:16:51 +08:00
|
|
|
end
|
|
|
|
|
2013-09-17 00:21:49 +08:00
|
|
|
def stylesheet_link_tag(target=:desktop)
|
2014-12-23 09:46:10 +08:00
|
|
|
content = target == :mobile ? mobile_stylesheet : stylesheet
|
|
|
|
SiteCustomization.stylesheet_link_tag(key, target, content)
|
2013-02-06 03:16:51 +08:00
|
|
|
end
|
2013-09-17 00:21:49 +08:00
|
|
|
|
2014-12-23 09:46:10 +08:00
|
|
|
def self.stylesheet_link_tag(key, target, content)
|
|
|
|
return "" unless content.present?
|
|
|
|
|
|
|
|
hash = Digest::MD5.hexdigest(content)
|
|
|
|
link_css_tag "/site_customizations/#{key}.css?target=#{target}&v=#{hash}"
|
2014-07-29 12:55:48 +08:00
|
|
|
end
|
|
|
|
|
2014-12-23 09:46:10 +08:00
|
|
|
def self.link_css_tag(href)
|
2015-03-10 04:38:25 +08:00
|
|
|
href = (GlobalSetting.cdn_url || "") + "#{GlobalSetting.relative_url_root}#{href}&__ws=#{Discourse.current_hostname}"
|
2014-12-23 09:46:10 +08:00
|
|
|
%Q{<link class="custom-css" rel="stylesheet" href="#{href}" type="text/css" media="all">}.html_safe
|
2013-09-17 00:21:49 +08:00
|
|
|
end
|
2013-02-06 03:16:51 +08:00
|
|
|
end
|
2013-05-24 10:48:32 +08:00
|
|
|
|
|
|
|
# == Schema Information
|
|
|
|
#
|
|
|
|
# Table name: site_customizations
|
|
|
|
#
|
2013-10-04 11:28:49 +08:00
|
|
|
# id :integer not null, primary key
|
|
|
|
# name :string(255) not null
|
|
|
|
# stylesheet :text
|
|
|
|
# header :text
|
|
|
|
# user_id :integer not null
|
|
|
|
# enabled :boolean not null
|
|
|
|
# key :string(255) not null
|
2014-08-27 13:19:25 +08:00
|
|
|
# created_at :datetime not null
|
|
|
|
# updated_at :datetime not null
|
2013-10-04 11:28:49 +08:00
|
|
|
# stylesheet_baked :text default(""), not null
|
|
|
|
# mobile_stylesheet :text
|
|
|
|
# mobile_header :text
|
|
|
|
# mobile_stylesheet_baked :text
|
2014-11-20 11:53:15 +08:00
|
|
|
# footer :text
|
|
|
|
# mobile_footer :text
|
2015-02-04 12:09:00 +08:00
|
|
|
# head_tag :text
|
|
|
|
# body_tag :text
|
|
|
|
# top :text
|
|
|
|
# mobile_top :text
|
2013-05-24 10:48:32 +08:00
|
|
|
#
|
|
|
|
# Indexes
|
|
|
|
#
|
|
|
|
# index_site_customizations_on_key (key)
|
|
|
|
#
|