2019-06-18 02:51:17 +08:00
|
|
|
# coding: utf-8
|
2018-06-05 15:29:17 +08:00
|
|
|
# frozen_string_literal: true
|
2013-02-06 03:16:51 +08:00
|
|
|
require 'current_user'
|
2013-02-13 19:04:43 +08:00
|
|
|
require 'canonical_url'
|
2013-02-06 03:16:51 +08:00
|
|
|
|
|
|
|
module ApplicationHelper
|
|
|
|
include CurrentUser
|
2013-02-13 19:04:43 +08:00
|
|
|
include CanonicalURL::Helpers
|
2013-05-01 23:48:42 +08:00
|
|
|
include ConfigurableUrls
|
2015-03-10 03:24:16 +08:00
|
|
|
include GlobalPath
|
2017-09-29 01:16:51 +08:00
|
|
|
|
2017-09-29 23:04:05 +08:00
|
|
|
def self.extra_body_classes
|
|
|
|
@extra_body_classes ||= Set.new
|
|
|
|
end
|
2013-02-06 03:16:51 +08:00
|
|
|
|
2022-01-14 04:16:34 +08:00
|
|
|
def discourse_config_environment(testing: false)
|
|
|
|
|
2021-05-05 21:02:48 +08:00
|
|
|
# TODO: Can this come from Ember CLI somehow?
|
2022-01-14 04:16:34 +08:00
|
|
|
config = {
|
|
|
|
modulePrefix: "discourse",
|
2021-05-05 21:02:48 +08:00
|
|
|
environment: Rails.env,
|
|
|
|
rootURL: Discourse.base_path,
|
|
|
|
locationType: "auto",
|
|
|
|
historySupportMiddleware: false,
|
|
|
|
EmberENV: {
|
|
|
|
FEATURES: {},
|
|
|
|
EXTEND_PROTOTYPES: { "Date": false },
|
|
|
|
_APPLICATION_TEMPLATE_WRAPPER: false,
|
|
|
|
_DEFAULT_ASYNC_OBSERVERS: true,
|
|
|
|
_JQUERY_INTEGRATION: true
|
|
|
|
},
|
|
|
|
APP: {
|
|
|
|
name: "discourse",
|
|
|
|
version: "#{Discourse::VERSION::STRING} #{Discourse.git_version}",
|
|
|
|
exportApplicationGlobal: true
|
|
|
|
}
|
2022-01-14 04:16:34 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if testing
|
|
|
|
config[:environment] = "test"
|
|
|
|
config[:locationType] = "none"
|
|
|
|
config[:APP][:autoboot] = false
|
|
|
|
config[:APP][:rootElement] = '#ember-testing'
|
|
|
|
end
|
|
|
|
|
|
|
|
config.to_json
|
2021-05-05 21:02:48 +08:00
|
|
|
end
|
|
|
|
|
2016-08-03 02:54:06 +08:00
|
|
|
def google_universal_analytics_json(ua_domain_name = nil)
|
|
|
|
result = {}
|
|
|
|
if ua_domain_name
|
|
|
|
result[:cookieDomain] = ua_domain_name.gsub(/^http(s)?:\/\//, '')
|
|
|
|
end
|
2015-04-08 01:09:49 +08:00
|
|
|
if current_user.present?
|
|
|
|
result[:userId] = current_user.id
|
|
|
|
end
|
2017-07-14 03:21:44 +08:00
|
|
|
if SiteSetting.ga_universal_auto_link_domains.present?
|
|
|
|
result[:allowLinker] = true
|
|
|
|
end
|
2018-09-10 14:10:20 +08:00
|
|
|
result.to_json
|
2015-04-08 01:09:49 +08:00
|
|
|
end
|
|
|
|
|
2016-07-15 01:52:37 +08:00
|
|
|
def ga_universal_json
|
|
|
|
google_universal_analytics_json(SiteSetting.ga_universal_domain_name)
|
|
|
|
end
|
|
|
|
|
|
|
|
def google_tag_manager_json
|
2016-08-03 02:54:06 +08:00
|
|
|
google_universal_analytics_json
|
2016-07-15 01:52:37 +08:00
|
|
|
end
|
|
|
|
|
2021-03-26 23:19:31 +08:00
|
|
|
def self.google_tag_manager_nonce
|
|
|
|
@gtm_nonce ||= SecureRandom.hex
|
|
|
|
end
|
|
|
|
|
2014-10-24 10:38:00 +08:00
|
|
|
def shared_session_key
|
2020-04-30 14:48:34 +08:00
|
|
|
if SiteSetting.long_polling_base_url != '/' && current_user
|
2014-10-24 10:38:00 +08:00
|
|
|
sk = "shared_session_key"
|
|
|
|
return request.env[sk] if request.env[sk]
|
|
|
|
|
|
|
|
request.env[sk] = key = (session[sk] ||= SecureRandom.hex)
|
2019-12-03 17:05:53 +08:00
|
|
|
Discourse.redis.setex "#{sk}_#{key}", 7.days, current_user.id.to_s
|
2014-10-24 10:38:00 +08:00
|
|
|
key
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2017-10-06 13:20:01 +08:00
|
|
|
def is_brotli_req?
|
|
|
|
request.env["HTTP_ACCEPT_ENCODING"] =~ /br/
|
|
|
|
end
|
|
|
|
|
2019-07-16 22:05:37 +08:00
|
|
|
def is_gzip_req?
|
|
|
|
request.env["HTTP_ACCEPT_ENCODING"] =~ /gzip/
|
|
|
|
end
|
|
|
|
|
2018-11-16 05:13:18 +08:00
|
|
|
def script_asset_path(script)
|
2020-09-05 03:23:01 +08:00
|
|
|
path = ActionController::Base.helpers.asset_path("#{script}.js")
|
2017-04-17 23:52:43 +08:00
|
|
|
|
2017-10-06 13:20:01 +08:00
|
|
|
if GlobalSetting.use_s3? && GlobalSetting.s3_cdn_url
|
|
|
|
if GlobalSetting.cdn_url
|
2019-06-18 02:51:17 +08:00
|
|
|
folder = ActionController::Base.config.relative_url_root || "/"
|
|
|
|
path = path.gsub(File.join(GlobalSetting.cdn_url, folder, "/"), File.join(GlobalSetting.s3_cdn_url, "/"))
|
2017-10-06 13:20:01 +08:00
|
|
|
else
|
2018-08-22 10:31:13 +08:00
|
|
|
# we must remove the subfolder path here, assets are uploaded to s3
|
|
|
|
# without it getting involved
|
|
|
|
if ActionController::Base.config.relative_url_root
|
|
|
|
path = path.sub(ActionController::Base.config.relative_url_root, "")
|
|
|
|
end
|
|
|
|
|
2017-10-06 13:20:01 +08:00
|
|
|
path = "#{GlobalSetting.s3_cdn_url}#{path}"
|
|
|
|
end
|
|
|
|
|
2021-07-15 03:52:35 +08:00
|
|
|
# assets needed for theme testing are not compressed because they take a fair
|
|
|
|
# amount of time to compress (+30 seconds) during rebuilds/deploys when the
|
|
|
|
# vast majority of sites will never need them, so it makes more sense to serve
|
|
|
|
# them uncompressed instead of making everyone's rebuild/deploy take +30 more
|
|
|
|
# seconds.
|
|
|
|
if !script.start_with?("discourse/tests/")
|
|
|
|
if is_brotli_req?
|
|
|
|
path = path.gsub(/\.([^.]+)$/, '.br.\1')
|
|
|
|
elsif is_gzip_req?
|
|
|
|
path = path.gsub(/\.([^.]+)$/, '.gz.\1')
|
|
|
|
end
|
2017-10-06 13:20:01 +08:00
|
|
|
end
|
|
|
|
|
2020-09-23 14:22:16 +08:00
|
|
|
elsif GlobalSetting.cdn_url&.start_with?("https") && is_brotli_req? && Rails.env != "development"
|
2018-06-05 15:29:17 +08:00
|
|
|
path = path.gsub("#{GlobalSetting.cdn_url}/assets/", "#{GlobalSetting.cdn_url}/brotli_asset/")
|
2014-05-19 06:46:09 +08:00
|
|
|
end
|
2017-10-06 13:20:01 +08:00
|
|
|
|
2018-05-07 09:25:05 +08:00
|
|
|
if Rails.env == "development"
|
|
|
|
if !path.include?("?")
|
|
|
|
# cache breaker for mobile iOS
|
|
|
|
path = path + "?#{Time.now.to_f}"
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2018-11-16 05:13:18 +08:00
|
|
|
path
|
|
|
|
end
|
|
|
|
|
2022-02-04 19:00:51 +08:00
|
|
|
def preload_vendor_scripts
|
|
|
|
scripts = ["vendor"]
|
|
|
|
|
2022-02-07 23:25:57 +08:00
|
|
|
if ENV["EMBER_CLI_PROD_ASSETS"] != "0"
|
2022-02-04 19:00:51 +08:00
|
|
|
@@vendor_chunks ||= begin
|
|
|
|
all_assets = ActionController::Base.helpers.assets_manifest.assets
|
|
|
|
all_assets.keys.filter_map { |name| name[/\A(chunk\..*)\.js\z/, 1] }
|
|
|
|
end
|
|
|
|
scripts.push(*@@vendor_chunks)
|
|
|
|
end
|
|
|
|
|
|
|
|
scripts.map do |name|
|
|
|
|
preload_script(name)
|
|
|
|
end.join("\n").html_safe
|
|
|
|
end
|
|
|
|
|
2018-11-16 05:13:18 +08:00
|
|
|
def preload_script(script)
|
|
|
|
path = script_asset_path(script)
|
2019-11-05 09:15:44 +08:00
|
|
|
preload_script_url(path)
|
|
|
|
end
|
2018-11-16 05:13:18 +08:00
|
|
|
|
2019-11-05 09:15:44 +08:00
|
|
|
def preload_script_url(url)
|
|
|
|
<<~HTML.html_safe
|
|
|
|
<link rel="preload" href="#{url}" as="script">
|
|
|
|
<script src="#{url}"></script>
|
|
|
|
HTML
|
2014-05-15 10:59:26 +08:00
|
|
|
end
|
|
|
|
|
2013-05-03 14:43:11 +08:00
|
|
|
def discourse_csrf_tags
|
|
|
|
# anon can not have a CSRF token cause these are all pages
|
2013-06-06 06:23:43 +08:00
|
|
|
# that may be cached, causing a mismatch between session CSRF
|
2013-05-03 14:43:11 +08:00
|
|
|
# and CSRF on page and horrible impossible to debug login issues
|
|
|
|
if current_user
|
|
|
|
csrf_meta_tags
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2013-12-19 03:47:22 +08:00
|
|
|
def html_classes
|
2019-01-14 21:21:46 +08:00
|
|
|
list = []
|
|
|
|
list << (mobile_view? ? 'mobile-view' : 'desktop-view')
|
|
|
|
list << (mobile_device? ? 'mobile-device' : 'not-mobile-device')
|
2019-05-07 22:44:43 +08:00
|
|
|
list << 'ios-device' if ios_device?
|
2019-01-14 21:21:46 +08:00
|
|
|
list << 'rtl' if rtl?
|
|
|
|
list << text_size_class
|
2019-01-23 12:43:36 +08:00
|
|
|
list << 'anon' unless current_user
|
2019-01-14 21:21:46 +08:00
|
|
|
list.join(' ')
|
2014-08-27 19:38:03 +08:00
|
|
|
end
|
|
|
|
|
2016-07-05 00:10:52 +08:00
|
|
|
def body_classes
|
2017-09-29 01:16:51 +08:00
|
|
|
result = ApplicationHelper.extra_body_classes.to_a
|
2017-06-16 02:20:04 +08:00
|
|
|
|
2016-07-05 00:10:52 +08:00
|
|
|
if @category && @category.url.present?
|
2017-06-16 02:20:04 +08:00
|
|
|
result << "category-#{@category.url.sub(/^\/c\//, '').gsub(/\//, '-')}"
|
|
|
|
end
|
|
|
|
|
2019-03-26 14:59:05 +08:00
|
|
|
if current_user.present? &&
|
|
|
|
current_user.primary_group_id &&
|
2019-10-21 18:32:27 +08:00
|
|
|
primary_group_name = Group.where(id: current_user.primary_group_id).pluck_first(:name)
|
2017-06-16 02:20:04 +08:00
|
|
|
result << "primary-group-#{primary_group_name.downcase}"
|
2016-07-05 00:10:52 +08:00
|
|
|
end
|
2017-06-16 02:20:04 +08:00
|
|
|
|
|
|
|
result.join(' ')
|
2016-07-05 00:10:52 +08:00
|
|
|
end
|
|
|
|
|
2019-01-14 21:21:46 +08:00
|
|
|
def text_size_class
|
2019-01-28 19:19:50 +08:00
|
|
|
requested_cookie_size, cookie_seq = cookies[:text_size]&.split("|")
|
|
|
|
server_seq = current_user&.user_option&.text_size_seq
|
|
|
|
if cookie_seq && server_seq && cookie_seq.to_i >= server_seq &&
|
|
|
|
UserOption.text_sizes.keys.include?(requested_cookie_size&.to_sym)
|
|
|
|
cookie_size = requested_cookie_size
|
|
|
|
end
|
|
|
|
|
2019-01-25 23:06:06 +08:00
|
|
|
size = cookie_size || current_user&.user_option&.text_size || SiteSetting.default_text_size
|
2019-01-14 21:21:46 +08:00
|
|
|
"text-size-#{size}"
|
2013-12-19 03:47:22 +08:00
|
|
|
end
|
|
|
|
|
2013-07-03 08:43:52 +08:00
|
|
|
def escape_unicode(javascript)
|
|
|
|
if javascript
|
2013-12-30 11:05:25 +08:00
|
|
|
javascript = javascript.scrub
|
2013-09-10 14:01:36 +08:00
|
|
|
javascript.gsub!(/\342\200\250/u, '
')
|
|
|
|
javascript.gsub!(/(<\/)/u, '\u003C/')
|
2018-09-17 16:31:46 +08:00
|
|
|
javascript
|
2013-07-03 08:43:52 +08:00
|
|
|
else
|
|
|
|
''
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2016-03-08 22:38:23 +08:00
|
|
|
def format_topic_title(title)
|
2016-11-23 01:37:22 +08:00
|
|
|
PrettyText.unescape_emoji strip_tags(title)
|
2015-10-15 15:59:29 +08:00
|
|
|
end
|
|
|
|
|
2013-02-06 03:16:51 +08:00
|
|
|
def with_format(format, &block)
|
|
|
|
old_formats = formats
|
|
|
|
self.formats = [format]
|
|
|
|
block.call
|
|
|
|
self.formats = old_formats
|
|
|
|
nil
|
|
|
|
end
|
|
|
|
|
|
|
|
def age_words(secs)
|
|
|
|
AgeWords.age_words(secs)
|
|
|
|
end
|
|
|
|
|
2016-11-11 07:16:24 +08:00
|
|
|
def short_date(dt)
|
|
|
|
if dt.year == Time.now.year
|
|
|
|
I18n.l(dt, format: :short_no_year)
|
|
|
|
else
|
|
|
|
I18n.l(dt, format: :date_only)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2013-02-06 03:16:51 +08:00
|
|
|
def guardian
|
|
|
|
@guardian ||= Guardian.new(current_user)
|
|
|
|
end
|
|
|
|
|
|
|
|
def admin?
|
|
|
|
current_user.try(:admin?)
|
|
|
|
end
|
|
|
|
|
2013-05-02 13:15:17 +08:00
|
|
|
def moderator?
|
|
|
|
current_user.try(:moderator?)
|
|
|
|
end
|
|
|
|
|
2013-05-02 15:22:27 +08:00
|
|
|
def staff?
|
|
|
|
current_user.try(:staff?)
|
|
|
|
end
|
|
|
|
|
2015-05-20 13:56:54 +08:00
|
|
|
def rtl?
|
2016-12-11 07:57:48 +08:00
|
|
|
["ar", "ur", "fa_IR", "he"].include? I18n.locale.to_s
|
2015-05-20 13:56:54 +08:00
|
|
|
end
|
|
|
|
|
2018-08-20 19:55:58 +08:00
|
|
|
def html_lang
|
2021-02-10 23:12:09 +08:00
|
|
|
(request ? I18n.locale.to_s : SiteSetting.default_locale).sub("_", "-")
|
2015-05-20 13:56:54 +08:00
|
|
|
end
|
|
|
|
|
2013-03-09 04:04:37 +08:00
|
|
|
# Creates open graph and twitter card meta data
|
|
|
|
def crawlable_meta_data(opts = nil)
|
|
|
|
opts ||= {}
|
2015-10-02 00:24:07 +08:00
|
|
|
opts[:url] ||= "#{Discourse.base_url_no_prefix}#{request.fullpath}"
|
2013-03-08 06:31:06 +08:00
|
|
|
|
2019-02-01 03:44:20 +08:00
|
|
|
if opts[:image].blank?
|
|
|
|
twitter_summary_large_image_url = SiteSetting.site_twitter_summary_large_image_url
|
|
|
|
|
|
|
|
if twitter_summary_large_image_url.present?
|
|
|
|
opts[:twitter_summary_large_image] = twitter_summary_large_image_url
|
|
|
|
end
|
|
|
|
|
2019-05-01 21:44:45 +08:00
|
|
|
opts[:image] = SiteSetting.site_opengraph_image_url
|
2016-08-22 17:28:46 +08:00
|
|
|
end
|
|
|
|
|
2019-01-08 13:47:05 +08:00
|
|
|
# Use the correct scheme for opengraph/twitter image
|
|
|
|
opts[:image] = get_absolute_image_url(opts[:image]) if opts[:image].present?
|
|
|
|
opts[:twitter_summary_large_image] =
|
|
|
|
get_absolute_image_url(opts[:twitter_summary_large_image]) if opts[:twitter_summary_large_image].present?
|
2014-08-08 00:58:26 +08:00
|
|
|
|
2016-09-19 19:41:12 +08:00
|
|
|
# Add opengraph & twitter tags
|
2015-10-15 17:00:47 +08:00
|
|
|
result = []
|
|
|
|
result << tag(:meta, property: 'og:site_name', content: SiteSetting.title)
|
2021-06-15 02:13:55 +08:00
|
|
|
result << tag(:meta, property: 'og:type', content: 'website')
|
2014-08-08 00:58:26 +08:00
|
|
|
|
2016-09-19 19:41:12 +08:00
|
|
|
if opts[:twitter_summary_large_image].present?
|
|
|
|
result << tag(:meta, name: 'twitter:card', content: "summary_large_image")
|
|
|
|
result << tag(:meta, name: "twitter:image", content: opts[:twitter_summary_large_image])
|
|
|
|
elsif opts[:image].present?
|
|
|
|
result << tag(:meta, name: 'twitter:card', content: "summary")
|
|
|
|
result << tag(:meta, name: "twitter:image", content: opts[:image])
|
|
|
|
else
|
|
|
|
result << tag(:meta, name: 'twitter:card', content: "summary")
|
|
|
|
end
|
|
|
|
result << tag(:meta, property: "og:image", content: opts[:image]) if opts[:image].present?
|
|
|
|
|
|
|
|
[:url, :title, :description].each do |property|
|
2013-03-09 04:04:37 +08:00
|
|
|
if opts[property].present?
|
2017-02-23 05:24:05 +08:00
|
|
|
content = (property == :url ? opts[property] : gsub_emoji_to_unicode(opts[property]))
|
2017-11-28 19:27:43 +08:00
|
|
|
result << tag(:meta, { property: "og:#{property}", content: content }, nil, true)
|
|
|
|
result << tag(:meta, { name: "twitter:#{property}", content: content }, nil, true)
|
2013-03-09 04:04:37 +08:00
|
|
|
end
|
|
|
|
end
|
2013-03-08 06:31:06 +08:00
|
|
|
|
2016-01-07 19:18:05 +08:00
|
|
|
if opts[:read_time] && opts[:read_time] > 0 && opts[:like_count] && opts[:like_count] > 0
|
2015-12-28 20:52:31 +08:00
|
|
|
result << tag(:meta, name: 'twitter:label1', value: I18n.t("reading_time"))
|
|
|
|
result << tag(:meta, name: 'twitter:data1', value: "#{opts[:read_time]} mins 🕑")
|
|
|
|
result << tag(:meta, name: 'twitter:label2', value: I18n.t("likes"))
|
2015-12-29 06:36:02 +08:00
|
|
|
result << tag(:meta, name: 'twitter:data2', value: "#{opts[:like_count]} ❤")
|
2015-12-28 20:52:31 +08:00
|
|
|
end
|
|
|
|
|
2018-07-30 18:52:51 +08:00
|
|
|
if opts[:published_time]
|
|
|
|
result << tag(:meta, property: 'article:published_time', content: opts[:published_time])
|
|
|
|
end
|
|
|
|
|
2017-08-15 21:53:03 +08:00
|
|
|
if opts[:ignore_canonical]
|
|
|
|
result << tag(:meta, property: 'og:ignore_canonical', content: true)
|
|
|
|
end
|
|
|
|
|
2015-10-15 17:00:47 +08:00
|
|
|
result.join("\n")
|
2013-03-08 06:31:06 +08:00
|
|
|
end
|
|
|
|
|
2016-02-14 02:29:53 +08:00
|
|
|
def render_sitelinks_search_tag
|
|
|
|
json = {
|
2016-04-14 17:22:26 +08:00
|
|
|
'@context' => 'http://schema.org',
|
|
|
|
'@type' => 'WebSite',
|
2016-02-14 02:29:53 +08:00
|
|
|
url: Discourse.base_url,
|
|
|
|
potentialAction: {
|
2016-04-14 17:22:26 +08:00
|
|
|
'@type' => 'SearchAction',
|
2016-02-14 02:29:53 +08:00
|
|
|
target: "#{Discourse.base_url}/search?q={search_term_string}",
|
2016-04-14 17:22:26 +08:00
|
|
|
'query-input' => 'required name=search_term_string',
|
2016-02-14 02:29:53 +08:00
|
|
|
}
|
|
|
|
}
|
2020-04-30 14:48:34 +08:00
|
|
|
content_tag(:script, MultiJson.dump(json).html_safe, type: 'application/ld+json')
|
2016-02-14 02:29:53 +08:00
|
|
|
end
|
|
|
|
|
2017-02-23 05:24:05 +08:00
|
|
|
def gsub_emoji_to_unicode(str)
|
2017-07-22 02:24:28 +08:00
|
|
|
Emoji.gsub_emoji_to_unicode(str)
|
2017-02-23 05:24:05 +08:00
|
|
|
end
|
|
|
|
|
2015-02-26 00:35:47 +08:00
|
|
|
def application_logo_url
|
2019-01-18 13:03:38 +08:00
|
|
|
@application_logo_url ||= begin
|
2020-11-13 02:50:55 +08:00
|
|
|
if mobile_view?
|
|
|
|
if dark_color_scheme? && SiteSetting.site_mobile_logo_dark_url.present?
|
|
|
|
SiteSetting.site_mobile_logo_dark_url
|
|
|
|
elsif SiteSetting.site_mobile_logo_url.present?
|
|
|
|
SiteSetting.site_mobile_logo_url
|
|
|
|
end
|
2019-01-18 13:03:38 +08:00
|
|
|
else
|
2020-11-13 02:50:55 +08:00
|
|
|
if dark_color_scheme? && SiteSetting.site_logo_dark_url.present?
|
|
|
|
SiteSetting.site_logo_dark_url
|
|
|
|
else
|
|
|
|
SiteSetting.site_logo_url
|
|
|
|
end
|
2019-01-18 13:03:38 +08:00
|
|
|
end
|
|
|
|
end
|
2015-02-26 00:35:47 +08:00
|
|
|
end
|
|
|
|
|
2021-09-17 05:47:51 +08:00
|
|
|
def application_logo_dark_url
|
|
|
|
@application_logo_dark_url ||= begin
|
|
|
|
if dark_scheme_id != -1
|
|
|
|
if mobile_view? && SiteSetting.site_mobile_logo_dark_url != application_logo_url
|
|
|
|
SiteSetting.site_mobile_logo_dark_url
|
|
|
|
elsif !mobile_view? && SiteSetting.site_logo_dark_url != application_logo_url
|
|
|
|
SiteSetting.site_logo_dark_url
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2013-03-20 00:15:14 +08:00
|
|
|
def login_path
|
2020-10-09 19:51:24 +08:00
|
|
|
"#{Discourse.base_path}/login"
|
2013-03-20 00:15:14 +08:00
|
|
|
end
|
2013-08-28 02:57:42 +08:00
|
|
|
|
2013-12-19 03:47:22 +08:00
|
|
|
def mobile_view?
|
2014-01-09 11:08:42 +08:00
|
|
|
MobileDetection.resolve_mobile_view!(request.user_agent, params, session)
|
2013-12-19 03:47:22 +08:00
|
|
|
end
|
|
|
|
|
2016-04-07 22:28:31 +08:00
|
|
|
def crawler_layout?
|
2017-09-08 13:07:22 +08:00
|
|
|
controller&.use_crawler_layout?
|
2016-04-07 22:28:31 +08:00
|
|
|
end
|
|
|
|
|
2016-03-17 02:35:58 +08:00
|
|
|
def include_crawler_content?
|
2016-04-07 22:28:31 +08:00
|
|
|
crawler_layout? || !mobile_view?
|
2016-03-17 02:35:58 +08:00
|
|
|
end
|
|
|
|
|
2013-12-19 03:47:22 +08:00
|
|
|
def mobile_device?
|
2014-01-09 11:08:42 +08:00
|
|
|
MobileDetection.mobile_device?(request.user_agent)
|
2013-08-30 03:19:28 +08:00
|
|
|
end
|
2013-11-14 23:41:16 +08:00
|
|
|
|
2019-05-07 22:44:43 +08:00
|
|
|
def ios_device?
|
|
|
|
MobileDetection.ios_device?(request.user_agent)
|
|
|
|
end
|
|
|
|
|
2013-11-14 23:41:16 +08:00
|
|
|
def customization_disabled?
|
2017-04-15 01:35:12 +08:00
|
|
|
request.env[ApplicationController::NO_CUSTOM]
|
2016-11-21 13:46:02 +08:00
|
|
|
end
|
|
|
|
|
2019-04-18 00:25:13 +08:00
|
|
|
def include_ios_native_app_banner?
|
|
|
|
current_user && current_user.trust_level >= 1 && SiteSetting.native_app_install_banner_ios
|
|
|
|
end
|
|
|
|
|
2019-08-27 22:23:57 +08:00
|
|
|
def ios_app_argument
|
|
|
|
# argument only makes sense for DiscourseHub app
|
|
|
|
SiteSetting.ios_app_id == "1173672076" ?
|
|
|
|
", app-argument=discourse://new?siteUrl=#{Discourse.base_url}" : ""
|
|
|
|
end
|
|
|
|
|
2016-11-21 13:46:02 +08:00
|
|
|
def allow_plugins?
|
2017-04-15 01:35:12 +08:00
|
|
|
!request.env[ApplicationController::NO_PLUGINS]
|
2016-11-21 13:46:02 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
def allow_third_party_plugins?
|
2017-04-15 01:35:12 +08:00
|
|
|
allow_plugins? && !request.env[ApplicationController::ONLY_OFFICIAL]
|
2016-12-19 07:11:51 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
def normalized_safe_mode
|
2018-10-02 12:29:04 +08:00
|
|
|
safe_mode = []
|
|
|
|
|
|
|
|
safe_mode << ApplicationController::NO_CUSTOM if customization_disabled?
|
|
|
|
safe_mode << ApplicationController::NO_PLUGINS if !allow_plugins?
|
|
|
|
safe_mode << ApplicationController::ONLY_OFFICIAL if !allow_third_party_plugins?
|
|
|
|
|
|
|
|
safe_mode.join(",")
|
2013-11-14 23:41:16 +08:00
|
|
|
end
|
|
|
|
|
2015-03-03 06:31:04 +08:00
|
|
|
def loading_admin?
|
2020-06-04 02:45:23 +08:00
|
|
|
return false unless defined?(controller)
|
2021-04-21 17:36:32 +08:00
|
|
|
return false if controller.class.name.blank?
|
|
|
|
|
2015-03-03 06:31:04 +08:00
|
|
|
controller.class.name.split("::").first == "Admin"
|
|
|
|
end
|
|
|
|
|
2015-01-29 03:56:18 +08:00
|
|
|
def category_badge(category, opts = nil)
|
|
|
|
CategoryBadge.html_for(category, opts).html_safe
|
|
|
|
end
|
2014-01-09 11:08:42 +08:00
|
|
|
|
2015-06-03 02:27:52 +08:00
|
|
|
def self.all_connectors
|
|
|
|
@all_connectors = Dir.glob("plugins/*/app/views/connectors/**/*.html.erb")
|
|
|
|
end
|
|
|
|
|
|
|
|
def server_plugin_outlet(name)
|
|
|
|
|
|
|
|
# Don't evaluate plugins in test
|
|
|
|
return "" if Rails.env.test?
|
|
|
|
|
|
|
|
matcher = Regexp.new("/connectors/#{name}/.*\.html\.erb$")
|
|
|
|
erbs = ApplicationHelper.all_connectors.select { |c| c =~ matcher }
|
|
|
|
return "" if erbs.blank?
|
|
|
|
|
2018-06-07 13:44:20 +08:00
|
|
|
result = +""
|
2019-09-20 02:51:06 +08:00
|
|
|
erbs.each { |erb| result << render(inline: File.read(erb)) }
|
2015-06-03 02:27:52 +08:00
|
|
|
result.html_safe
|
|
|
|
end
|
|
|
|
|
2016-12-05 20:31:43 +08:00
|
|
|
def topic_featured_link_domain(link)
|
|
|
|
begin
|
2019-12-12 10:49:21 +08:00
|
|
|
uri = UrlHelper.encode_and_parse(link)
|
2016-12-05 20:31:43 +08:00
|
|
|
uri = URI.parse("http://#{uri}") if uri.scheme.nil?
|
|
|
|
host = uri.host.downcase
|
|
|
|
host.start_with?('www.') ? host[4..-1] : host
|
|
|
|
rescue
|
|
|
|
''
|
|
|
|
end
|
|
|
|
end
|
2017-04-12 22:52:52 +08:00
|
|
|
|
2021-06-15 14:57:17 +08:00
|
|
|
def theme_id
|
2017-04-12 22:52:52 +08:00
|
|
|
if customization_disabled?
|
2021-06-15 14:57:17 +08:00
|
|
|
nil
|
2017-04-12 22:52:52 +08:00
|
|
|
else
|
2021-06-15 14:57:17 +08:00
|
|
|
request.env[:resolved_theme_id]
|
2017-04-12 22:52:52 +08:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2021-06-15 14:57:17 +08:00
|
|
|
def stylesheet_manager
|
|
|
|
return @stylesheet_manager if defined?(@stylesheet_manager)
|
|
|
|
@stylesheet_manager = Stylesheet::Manager.new(theme_id: theme_id)
|
|
|
|
end
|
|
|
|
|
2018-09-12 09:04:58 +08:00
|
|
|
def scheme_id
|
2020-09-09 15:15:15 +08:00
|
|
|
return @scheme_id if defined?(@scheme_id)
|
|
|
|
|
2020-08-28 22:36:52 +08:00
|
|
|
custom_user_scheme_id = cookies[:color_scheme_id] || current_user&.user_option&.color_scheme_id
|
|
|
|
if custom_user_scheme_id && ColorScheme.find_by_id(custom_user_scheme_id)
|
|
|
|
return custom_user_scheme_id
|
|
|
|
end
|
|
|
|
|
2021-06-15 14:57:17 +08:00
|
|
|
return if theme_id.blank?
|
2020-09-09 15:15:15 +08:00
|
|
|
|
2021-06-15 14:57:17 +08:00
|
|
|
@scheme_id = Theme.where(id: theme_id).pluck_first(:color_scheme_id)
|
2018-09-12 09:04:58 +08:00
|
|
|
end
|
|
|
|
|
2020-08-28 22:36:52 +08:00
|
|
|
def dark_scheme_id
|
|
|
|
cookies[:dark_scheme_id] || current_user&.user_option&.dark_scheme_id || SiteSetting.default_dark_mode_color_scheme_id
|
|
|
|
end
|
|
|
|
|
2017-11-10 03:45:19 +08:00
|
|
|
def current_homepage
|
|
|
|
current_user&.user_option&.homepage || SiteSetting.anonymous_homepage
|
|
|
|
end
|
|
|
|
|
2017-04-18 03:47:21 +08:00
|
|
|
def build_plugin_html(name)
|
|
|
|
return "" unless allow_plugins?
|
2017-04-19 00:35:19 +08:00
|
|
|
DiscoursePluginRegistry.build_html(name, controller) || ""
|
2017-04-18 03:47:21 +08:00
|
|
|
end
|
|
|
|
|
2017-11-15 05:31:44 +08:00
|
|
|
# If there is plugin HTML return that, otherwise yield to the template
|
|
|
|
def replace_plugin_html(name)
|
2017-12-08 07:30:00 +08:00
|
|
|
if (html = build_plugin_html(name)).present?
|
|
|
|
html
|
|
|
|
else
|
|
|
|
yield
|
|
|
|
nil
|
|
|
|
end
|
2017-11-15 05:31:44 +08:00
|
|
|
end
|
|
|
|
|
2017-04-12 22:52:52 +08:00
|
|
|
def theme_lookup(name)
|
2021-04-12 20:02:58 +08:00
|
|
|
Theme.lookup_field(
|
2021-06-15 14:57:17 +08:00
|
|
|
theme_id,
|
2021-04-12 20:02:58 +08:00
|
|
|
mobile_view? ? :mobile : :desktop,
|
|
|
|
name,
|
|
|
|
skip_transformation: request.env[:skip_theme_ids_transformation].present?
|
|
|
|
)
|
2019-01-17 19:46:11 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
def theme_translations_lookup
|
2021-04-12 20:02:58 +08:00
|
|
|
Theme.lookup_field(
|
2021-06-15 14:57:17 +08:00
|
|
|
theme_id,
|
2021-04-12 20:02:58 +08:00
|
|
|
:translations,
|
|
|
|
I18n.locale,
|
|
|
|
skip_transformation: request.env[:skip_theme_ids_transformation].present?
|
|
|
|
)
|
2017-04-12 22:52:52 +08:00
|
|
|
end
|
|
|
|
|
2019-06-03 17:41:00 +08:00
|
|
|
def theme_js_lookup
|
2021-04-12 20:02:58 +08:00
|
|
|
Theme.lookup_field(
|
2021-06-15 14:57:17 +08:00
|
|
|
theme_id,
|
2021-04-12 20:02:58 +08:00
|
|
|
:extra_js,
|
|
|
|
nil,
|
|
|
|
skip_transformation: request.env[:skip_theme_ids_transformation].present?
|
|
|
|
)
|
2019-06-03 17:41:00 +08:00
|
|
|
end
|
|
|
|
|
2017-04-12 22:52:52 +08:00
|
|
|
def discourse_stylesheet_link_tag(name, opts = {})
|
2021-06-15 14:57:17 +08:00
|
|
|
manager =
|
|
|
|
if opts.key?(:theme_id)
|
|
|
|
Stylesheet::Manager.new(
|
|
|
|
theme_id: customization_disabled? ? nil : opts[:theme_id]
|
|
|
|
)
|
|
|
|
else
|
|
|
|
stylesheet_manager
|
|
|
|
end
|
2017-04-12 22:52:52 +08:00
|
|
|
|
2021-06-15 14:57:17 +08:00
|
|
|
manager.stylesheet_link_tag(name, 'all')
|
2017-04-12 22:52:52 +08:00
|
|
|
end
|
2018-09-17 16:31:46 +08:00
|
|
|
|
2020-08-04 10:57:10 +08:00
|
|
|
def discourse_color_scheme_stylesheets
|
|
|
|
result = +""
|
2021-06-15 14:57:17 +08:00
|
|
|
result << stylesheet_manager.color_scheme_stylesheet_link_tag(scheme_id, 'all')
|
2020-08-04 10:57:10 +08:00
|
|
|
|
|
|
|
if dark_scheme_id != -1
|
2021-06-15 14:57:17 +08:00
|
|
|
result << stylesheet_manager.color_scheme_stylesheet_link_tag(dark_scheme_id, '(prefers-color-scheme: dark)')
|
2020-08-04 10:57:10 +08:00
|
|
|
end
|
2021-06-15 14:57:17 +08:00
|
|
|
|
2020-08-04 10:57:10 +08:00
|
|
|
result.html_safe
|
|
|
|
end
|
|
|
|
|
2020-08-21 02:23:18 +08:00
|
|
|
def dark_color_scheme?
|
2020-09-09 15:18:52 +08:00
|
|
|
return false if scheme_id.blank?
|
2020-08-21 02:23:18 +08:00
|
|
|
ColorScheme.find_by_id(scheme_id)&.is_dark?
|
|
|
|
end
|
|
|
|
|
2018-09-17 16:31:46 +08:00
|
|
|
def preloaded_json
|
|
|
|
return '{}' if @preloaded.blank?
|
|
|
|
@preloaded.transform_values { |value| escape_unicode(value) }.to_json
|
|
|
|
end
|
2018-10-02 12:29:04 +08:00
|
|
|
|
|
|
|
def client_side_setup_data
|
|
|
|
setup_data = {
|
|
|
|
cdn: Rails.configuration.action_controller.asset_host,
|
2019-05-07 12:36:40 +08:00
|
|
|
base_url: Discourse.base_url,
|
2020-10-09 19:51:24 +08:00
|
|
|
base_uri: Discourse.base_path,
|
2018-10-02 12:29:04 +08:00
|
|
|
environment: Rails.env,
|
|
|
|
letter_avatar_version: LetterAvatar.version,
|
2018-11-16 05:13:18 +08:00
|
|
|
markdown_it_url: script_asset_path('markdown-it-bundle'),
|
2021-05-26 06:39:31 +08:00
|
|
|
service_worker_url: 'service-worker.js',
|
2018-10-02 12:29:04 +08:00
|
|
|
default_locale: SiteSetting.default_locale,
|
|
|
|
asset_version: Discourse.assets_digest,
|
|
|
|
disable_custom_css: loading_admin?,
|
2020-07-15 20:52:35 +08:00
|
|
|
highlight_js_path: HighlightJs.path,
|
2021-06-15 14:57:17 +08:00
|
|
|
svg_sprite_path: SvgSprite.path(theme_id),
|
2019-08-20 09:29:11 +08:00
|
|
|
enable_js_error_reporting: GlobalSetting.enable_js_error_reporting,
|
2020-08-28 22:36:52 +08:00
|
|
|
color_scheme_is_dark: dark_color_scheme?,
|
|
|
|
user_color_scheme_id: scheme_id,
|
|
|
|
user_dark_scheme_id: dark_scheme_id
|
2018-10-02 12:29:04 +08:00
|
|
|
}
|
|
|
|
|
2018-11-27 05:49:57 +08:00
|
|
|
if Rails.env.development?
|
2021-06-15 14:57:17 +08:00
|
|
|
setup_data[:svg_icon_list] = SvgSprite.all_icons(theme_id)
|
2020-02-06 11:14:33 +08:00
|
|
|
|
|
|
|
if ENV['DEBUG_PRELOADED_APP_DATA']
|
|
|
|
setup_data[:debug_preloaded_app_data] = true
|
|
|
|
end
|
2021-05-15 00:36:53 +08:00
|
|
|
setup_data[:mb_last_file_change_id] = MessageBus.last_id('/file-change')
|
2018-11-27 05:49:57 +08:00
|
|
|
end
|
|
|
|
|
2018-10-02 12:29:04 +08:00
|
|
|
if guardian.can_enable_safe_mode? && params["safe_mode"]
|
|
|
|
setup_data[:safe_mode] = normalized_safe_mode
|
|
|
|
end
|
|
|
|
|
|
|
|
if SiteSetting.Upload.enable_s3_uploads
|
|
|
|
setup_data[:s3_cdn] = SiteSetting.Upload.s3_cdn_url.presence
|
|
|
|
setup_data[:s3_base_url] = SiteSetting.Upload.s3_base_url
|
|
|
|
end
|
|
|
|
|
|
|
|
setup_data
|
|
|
|
end
|
2019-01-08 13:47:05 +08:00
|
|
|
|
|
|
|
def get_absolute_image_url(link)
|
|
|
|
absolute_url = link
|
2020-04-22 14:55:59 +08:00
|
|
|
if link.start_with?('//')
|
2019-01-08 13:47:05 +08:00
|
|
|
uri = URI(Discourse.base_url)
|
|
|
|
absolute_url = "#{uri.scheme}:#{link}"
|
2020-04-22 14:55:59 +08:00
|
|
|
elsif link.start_with?('/uploads/', '/images/', '/user_avatar/')
|
2020-04-22 14:38:59 +08:00
|
|
|
absolute_url = "#{Discourse.base_url}#{link}"
|
2019-01-08 13:47:05 +08:00
|
|
|
elsif GlobalSetting.relative_url_root && link.start_with?(GlobalSetting.relative_url_root)
|
|
|
|
absolute_url = "#{Discourse.base_url_no_prefix}#{link}"
|
|
|
|
end
|
|
|
|
absolute_url
|
|
|
|
end
|
2019-07-09 07:21:19 +08:00
|
|
|
|
2021-10-07 04:41:52 +08:00
|
|
|
def manifest_url
|
|
|
|
# If you want the `manifest_url` to be different for a specific action,
|
|
|
|
# in the action set @manifest_url = X. Originally added for chat to add a
|
|
|
|
# separate manifest
|
|
|
|
@manifest_url || "#{Discourse.base_path}/manifest.webmanifest"
|
|
|
|
end
|
|
|
|
|
2019-07-09 07:21:19 +08:00
|
|
|
def can_sign_up?
|
|
|
|
SiteSetting.allow_new_registrations &&
|
|
|
|
!SiteSetting.invite_only &&
|
2021-02-08 18:04:33 +08:00
|
|
|
!SiteSetting.enable_discourse_connect
|
2019-07-09 07:21:19 +08:00
|
|
|
end
|
2020-04-20 14:08:24 +08:00
|
|
|
|
|
|
|
def rss_creator(user)
|
|
|
|
if user
|
|
|
|
if SiteSetting.prioritize_username_in_ux
|
|
|
|
"#{user.username}"
|
|
|
|
else
|
|
|
|
"#{user.name.presence || user.username }"
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2021-01-25 21:47:44 +08:00
|
|
|
|
|
|
|
def authentication_data
|
|
|
|
return @authentication_data if defined?(@authentication_data)
|
|
|
|
|
|
|
|
@authentication_data = begin
|
|
|
|
value = cookies[:authentication_data]
|
|
|
|
if value
|
|
|
|
cookies.delete(:authentication_data, path: Discourse.base_path("/"))
|
|
|
|
end
|
|
|
|
current_user ? nil : value
|
|
|
|
end
|
|
|
|
end
|
2013-02-06 03:16:51 +08:00
|
|
|
end
|