2013-05-31 08:41:29 +10:00
require 'cache'
2013-08-23 16:21:52 +10:00
require_dependency 'plugin/instance'
2013-10-09 15:10:37 +11:00
require_dependency 'auth/default_current_user_provider'
2013-05-31 08:41:29 +10:00
2013-02-05 14:16:51 -05:00
module Discourse
2014-04-17 15:57:17 +10:00
require 'sidekiq/exception_handler'
2014-02-21 14:30:25 +11:00
class SidekiqExceptionHandler
extend Sidekiq :: ExceptionHandler
end
2014-07-17 13:22:46 -07:00
# Log an exception.
#
2014-07-17 15:07:25 -07:00
# If your code is in a scheduled job, it is recommended to use the
# error_context() method in Jobs::Base to pass the job arguments and any
# other desired context.
2014-07-17 13:22:46 -07:00
# See app/jobs/base.rb for the error_context function.
def self . handle_exception ( ex , context = { } , parent_logger = nil )
2014-02-21 14:30:25 +11:00
context || = { }
parent_logger || = SidekiqExceptionHandler
cm = RailsMultisite :: ConnectionManagement
parent_logger . handle_exception ( ex , {
current_db : cm . current_db ,
current_hostname : cm . current_hostname
} . merge ( context ) )
end
2013-06-19 10:31:19 +10:00
# Expected less matches than what we got in a find
class TooManyMatches < Exception ; end
2013-02-25 19:42:20 +03:00
# When they try to do something they should be logged in for
2013-02-05 14:16:51 -05:00
class NotLoggedIn < Exception ; end
# When the input is somehow bad
class InvalidParameters < Exception ; end
# When they don't have permission to do something
class InvalidAccess < Exception ; end
# When something they want is not found
class NotFound < Exception ; end
2013-06-05 00:34:53 +02:00
# When a setting is missing
class SiteSettingMissing < Exception ; end
2013-11-05 19:04:47 +01:00
# When ImageMagick is missing
class ImageMagickMissing < Exception ; end
2013-11-26 10:21:41 +11:00
class InvalidPost < Exception ; end
2014-02-12 20:37:28 -08:00
# When read-only mode is enabled
class ReadOnly < Exception ; end
2013-07-29 15:13:13 +10:00
# Cross site request forgery
class CSRF < Exception ; end
2013-12-24 00:50:36 +01:00
def self . filters
2015-01-25 15:53:11 +11:00
@filters || = [ :latest , :unread , :new , :read , :posted , :bookmarks ]
2013-12-24 00:50:36 +01:00
end
2014-09-11 15:30:10 -04:00
def self . feed_filters
@feed_filters || = [ :latest ]
end
2013-12-24 00:50:36 +01:00
def self . anonymous_filters
2014-09-11 14:42:23 -04:00
@anonymous_filters || = [ :latest , :top , :categories ]
2013-12-24 00:50:36 +01:00
end
def self . logged_in_filters
@logged_in_filters || = Discourse . filters - Discourse . anonymous_filters
end
def self . top_menu_items
2014-01-14 12:48:57 -05:00
@top_menu_items || = Discourse . filters + [ :category , :categories , :top ]
2013-12-24 00:50:36 +01:00
end
def self . anonymous_top_menu_items
2014-01-14 12:48:57 -05:00
@anonymous_top_menu_items || = Discourse . anonymous_filters + [ :category , :categories , :top ]
2013-12-24 00:50:36 +01:00
end
2013-08-01 15:59:57 +10:00
def self . activate_plugins!
2013-08-23 16:21:52 +10:00
@plugins = Plugin :: Instance . find_all ( " #{ Rails . root } /plugins " )
2013-12-24 00:50:36 +01:00
@plugins . each { | plugin | plugin . activate! }
2013-08-01 15:59:57 +10:00
end
2015-02-04 16:23:39 -05:00
def self . disabled_plugin_names
return [ ] if @plugins . blank?
@plugins . select { | p | ! p . enabled? } . map ( & :name )
end
2013-08-01 15:59:57 +10:00
def self . plugins
@plugins
end
2014-01-15 12:07:42 +11:00
def self . assets_digest
@assets_digest || = begin
digest = Digest :: MD5 . hexdigest ( ActionView :: Base . assets_manifest . assets . values . sort . join )
channel = " /global/asset-version "
message = MessageBus . last_message ( channel )
unless message && message . data == digest
MessageBus . publish channel , digest
end
digest
end
end
2013-08-26 11:04:16 +10:00
def self . authenticators
# TODO: perhaps we don't need auth providers and authenticators maybe one object is enough
# NOTE: this bypasses the site settings and gives a list of everything, we need to register every middleware
# for the cases of multisite
# In future we may change it so we don't include them all for cases where we are not a multisite, but we would
# require a restart after site settings change
Users :: OmniauthCallbacksController :: BUILTIN_AUTH + auth_providers . map ( & :authenticator )
end
2013-08-01 15:59:57 +10:00
def self . auth_providers
2013-08-01 16:05:46 +10:00
providers = [ ]
2013-08-01 15:59:57 +10:00
if plugins
plugins . each do | p |
next unless p . auth_providers
p . auth_providers . each do | prov |
providers << prov
end
end
end
providers
end
2013-05-31 08:41:29 +10:00
def self . cache
@cache || = Cache . new
end
2013-02-05 14:16:51 -05:00
# Get the current base URL for the current site
def self . current_hostname
2013-05-31 08:48:34 +10:00
if SiteSetting . force_hostname . present?
SiteSetting . force_hostname
else
RailsMultisite :: ConnectionManagement . current_hostname
end
2013-05-31 08:41:29 +10:00
end
2013-11-05 19:04:47 +01:00
def self . base_uri ( default_value = " " )
2013-05-31 08:41:29 +10:00
if ! ActionController :: Base . config . relative_url_root . blank?
2013-11-05 19:04:47 +01:00
ActionController :: Base . config . relative_url_root
2013-03-14 13:01:52 +01:00
else
2013-11-05 19:04:47 +01:00
default_value
2013-03-14 13:01:52 +01:00
end
end
2013-05-31 08:41:29 +10:00
def self . base_url_no_prefix
2013-05-31 08:48:34 +10:00
default_port = 80
2013-02-05 14:16:51 -05:00
protocol = " http "
2013-05-31 08:48:34 +10:00
2014-01-09 10:51:38 +11:00
if SiteSetting . use_https?
2013-05-31 08:48:34 +10:00
protocol = " https "
default_port = 443
2013-05-31 08:39:52 +10:00
end
2013-05-31 08:48:34 +10:00
result = " #{ protocol } :// #{ current_hostname } "
port = SiteSetting . port . present? && SiteSetting . port . to_i > 0 ? SiteSetting . port . to_i : default_port
result << " : #{ SiteSetting . port } " if port != default_port
2013-05-31 08:39:52 +10:00
result
2013-04-05 12:38:20 +02:00
end
2013-05-31 08:41:29 +10:00
def self . base_url
return base_url_no_prefix + base_uri
end
2014-02-12 20:37:28 -08:00
def self . enable_readonly_mode
$redis . set readonly_mode_key , 1
MessageBus . publish ( readonly_channel , true )
2013-02-05 14:16:51 -05:00
true
end
2014-02-12 20:37:28 -08:00
def self . disable_readonly_mode
$redis . del readonly_mode_key
MessageBus . publish ( readonly_channel , false )
2013-02-05 14:16:51 -05:00
true
end
2014-02-12 20:37:28 -08:00
def self . readonly_mode?
! ! $redis . get ( readonly_mode_key )
2013-02-05 14:16:51 -05:00
end
2014-02-20 21:52:11 -08:00
def self . request_refresh!
# Causes refresh on next click for all clients
#
# This is better than `MessageBus.publish "/file-change", ["refresh"]` because
# it spreads the refreshes out over a time period
MessageBus . publish '/global/asset-version' , 'clobber'
end
2013-02-18 17:39:54 +11:00
def self . git_version
2013-02-25 19:42:20 +03:00
return $git_version if $git_version
2013-08-02 23:25:57 +02:00
# load the version stamped by the "build:stamp" task
f = Rails . root . to_s + " /config/version "
2013-02-18 18:00:49 +11:00
require f if File . exists? ( " #{ f } .rb " )
2013-02-18 17:39:54 +11:00
begin
2013-02-18 18:00:49 +11:00
$git_version || = ` git rev-parse HEAD ` . strip
2013-02-18 17:39:54 +11:00
rescue
$git_version = " unknown "
end
end
2014-09-09 17:04:10 -04:00
def self . git_branch
return $git_branch if $git_branch
begin
$git_branch || = ` git rev-parse --abbrev-ref HEAD ` . strip
rescue
$git_branch = " unknown "
end
end
2013-09-06 17:28:37 +10:00
# Either returns the site_contact_username user or the first admin.
def self . site_contact_user
2014-05-06 14:41:59 +01:00
user = User . find_by ( username_lower : SiteSetting . site_contact_username . downcase ) if SiteSetting . site_contact_username . present?
2013-09-06 14:07:23 +10:00
user || = User . admins . real . order ( :id ) . first
2013-05-31 08:41:29 +10:00
end
2013-02-05 14:16:51 -05:00
2014-06-25 10:55:35 +10:00
SYSTEM_USER_ID = - 1 unless defined? SYSTEM_USER_ID
2014-06-25 10:45:20 +10:00
2013-09-06 17:28:37 +10:00
def self . system_user
2014-06-25 10:45:20 +10:00
User . find_by ( id : SYSTEM_USER_ID )
2013-09-06 17:28:37 +10:00
end
2013-07-31 23:26:34 +02:00
def self . store
if SiteSetting . enable_s3_uploads?
@s3_store_loaded || = require 'file_store/s3_store'
2013-11-05 19:04:47 +01:00
FileStore :: S3Store . new
2013-07-31 23:26:34 +02:00
else
@local_store_loaded || = require 'file_store/local_store'
2013-11-05 19:04:47 +01:00
FileStore :: LocalStore . new
2013-07-31 23:26:34 +02:00
end
end
2013-10-09 15:10:37 +11:00
def self . current_user_provider
@current_user_provider || Auth :: DefaultCurrentUserProvider
end
def self . current_user_provider = ( val )
@current_user_provider = val
end
2013-11-05 19:04:47 +01:00
def self . asset_host
Rails . configuration . action_controller . asset_host
end
2014-02-12 20:37:28 -08:00
def self . readonly_mode_key
" readonly_mode "
end
2013-02-05 14:16:51 -05:00
2014-02-12 20:37:28 -08:00
def self . readonly_channel
2014-02-19 18:21:41 +01:00
" /site/read-only "
2013-02-05 14:16:51 -05:00
end
2014-02-12 20:37:28 -08:00
2014-03-28 13:48:14 +11:00
# all forking servers must call this
# after fork, otherwise Discourse will be
# in a bad state
def self . after_fork
2014-04-07 19:38:47 +02:00
current_db = RailsMultisite :: ConnectionManagement . current_db
RailsMultisite :: ConnectionManagement . establish_connection ( db : current_db )
MessageBus . after_fork
2014-03-28 13:48:14 +11:00
SiteSetting . after_fork
$redis . client . reconnect
Rails . cache . reconnect
2014-05-08 08:05:28 +10:00
Logster . store . redis . reconnect
2014-04-23 11:01:17 +10:00
# shuts down all connections in the pool
Sidekiq . redis_pool . shutdown { | c | nil }
# re-establish
Sidekiq . redis = sidekiq_redis_config
2014-08-11 17:51:55 +10:00
start_connection_reaper
2014-05-08 08:05:28 +10:00
nil
2014-04-23 11:01:17 +10:00
end
2014-08-11 17:51:55 +10:00
def self . start_connection_reaper ( interval = 30 , age = 30 )
# this helps keep connection counts in check
Thread . new do
while true
sleep interval
pools = [ ]
ObjectSpace . each_object ( ActiveRecord :: ConnectionAdapters :: ConnectionPool ) { | pool | pools << pool }
pools . each do | pool |
pool . drain ( age . seconds )
end
end
end
end
2014-04-23 11:01:17 +10:00
def self . sidekiq_redis_config
{ url : $redis . url , namespace : 'sidekiq' }
2014-03-28 13:48:14 +11:00
end
2014-07-29 10:40:02 -04:00
def self . static_doc_topic_ids
[ SiteSetting . tos_topic_id , SiteSetting . guidelines_topic_id , SiteSetting . privacy_topic_id ]
end
2013-02-05 14:16:51 -05:00
end