DEV: Apply syntax_tree formatting to `config/*`

This commit is contained in:
David Taylor 2023-01-07 11:59:28 +00:00
parent 436b3b392b
commit 7c77cc6a58
No known key found for this signature in database
GPG Key ID: 46904C18B1D3F434
47 changed files with 1627 additions and 1091 deletions

View File

@ -2,7 +2,6 @@
--plugins=plugin/trailing_comma,disable_ternary --plugins=plugin/trailing_comma,disable_ternary
--ignore-files=Gemfile --ignore-files=Gemfile
--ignore-files=app/* --ignore-files=app/*
--ignore-files=config/*
--ignore-files=db/* --ignore-files=db/*
--ignore-files=lib/* --ignore-files=lib/*
--ignore-files=spec/* --ignore-files=spec/*

View File

@ -5,12 +5,12 @@ if Gem::Version.new(RUBY_VERSION) < Gem::Version.new("2.7.0")
exit 1 exit 1
end end
require File.expand_path('../boot', __FILE__) require File.expand_path("../boot", __FILE__)
require 'active_record/railtie' require "active_record/railtie"
require 'action_controller/railtie' require "action_controller/railtie"
require 'action_view/railtie' require "action_view/railtie"
require 'action_mailer/railtie' require "action_mailer/railtie"
require 'sprockets/railtie' require "sprockets/railtie"
if !Rails.env.production? if !Rails.env.production?
recommended = File.read(".ruby-version.sample").strip recommended = File.read(".ruby-version.sample").strip
@ -20,66 +20,59 @@ if !Rails.env.production?
end end
# Plugin related stuff # Plugin related stuff
require_relative '../lib/plugin' require_relative "../lib/plugin"
require_relative '../lib/discourse_event' require_relative "../lib/discourse_event"
require_relative '../lib/discourse_plugin_registry' require_relative "../lib/discourse_plugin_registry"
require_relative '../lib/plugin_gem' require_relative "../lib/plugin_gem"
# Global config # Global config
require_relative '../app/models/global_setting' require_relative "../app/models/global_setting"
GlobalSetting.configure! GlobalSetting.configure!
if GlobalSetting.load_plugins? if GlobalSetting.load_plugins?
# Support for plugins to register custom setting providers. They can do this # Support for plugins to register custom setting providers. They can do this
# by having a file, `register_provider.rb` in their root that will be run # by having a file, `register_provider.rb` in their root that will be run
# at this point. # at this point.
Dir.glob(File.join(File.dirname(__FILE__), '../plugins', '*', "register_provider.rb")) do |p| Dir.glob(File.join(File.dirname(__FILE__), "../plugins", "*", "register_provider.rb")) do |p|
require p require p
end end
end end
GlobalSetting.load_defaults GlobalSetting.load_defaults
if GlobalSetting.try(:cdn_url).present? && GlobalSetting.cdn_url !~ /^https?:\/\// if GlobalSetting.try(:cdn_url).present? && GlobalSetting.cdn_url !~ %r{^https?://}
STDERR.puts "WARNING: Your CDN URL does not begin with a protocol like `https://` - this is probably not going to work" STDERR.puts "WARNING: Your CDN URL does not begin with a protocol like `https://` - this is probably not going to work"
end end
if ENV['SKIP_DB_AND_REDIS'] == '1' if ENV["SKIP_DB_AND_REDIS"] == "1"
GlobalSetting.skip_db = true GlobalSetting.skip_db = true
GlobalSetting.skip_redis = true GlobalSetting.skip_redis = true
end end
if !GlobalSetting.skip_db? require "rails_failover/active_record" if !GlobalSetting.skip_db?
require 'rails_failover/active_record'
end
if !GlobalSetting.skip_redis? require "rails_failover/redis" if !GlobalSetting.skip_redis?
require 'rails_failover/redis'
end
require 'pry-rails' if Rails.env.development? require "pry-rails" if Rails.env.development?
require 'pry-byebug' if Rails.env.development? require "pry-byebug" if Rails.env.development?
require 'discourse_fonts' require "discourse_fonts"
require_relative '../lib/ember_cli' require_relative "../lib/ember_cli"
if defined?(Bundler) if defined?(Bundler)
bundler_groups = [:default] bundler_groups = [:default]
if !Rails.env.production? if !Rails.env.production?
bundler_groups = bundler_groups.concat(Rails.groups( bundler_groups = bundler_groups.concat(Rails.groups(assets: %w[development test profile]))
assets: %w(development test profile)
))
end end
Bundler.require(*bundler_groups) Bundler.require(*bundler_groups)
end end
require_relative '../lib/require_dependency_backward_compatibility' require_relative "../lib/require_dependency_backward_compatibility"
module Discourse module Discourse
class Application < Rails::Application class Application < Rails::Application
def config.database_configuration def config.database_configuration
if Rails.env.production? if Rails.env.production?
GlobalSetting.database_config GlobalSetting.database_config
@ -91,18 +84,23 @@ module Discourse
# Application configuration should go into files in config/initializers # Application configuration should go into files in config/initializers
# -- all .rb files in that directory are automatically loaded. # -- all .rb files in that directory are automatically loaded.
require 'discourse' require "discourse"
require 'js_locale_helper' require "js_locale_helper"
# tiny file needed by site settings # tiny file needed by site settings
require 'highlight_js' require "highlight_js"
config.load_defaults 6.1 config.load_defaults 6.1
config.active_record.cache_versioning = false # our custom cache class doesnt support this config.active_record.cache_versioning = false # our custom cache class doesnt support this
config.action_controller.forgery_protection_origin_check = false config.action_controller.forgery_protection_origin_check = false
config.active_record.belongs_to_required_by_default = false config.active_record.belongs_to_required_by_default = false
config.active_record.legacy_connection_handling = true config.active_record.legacy_connection_handling = true
config.active_record.yaml_column_permitted_classes = [Hash, HashWithIndifferentAccess, Time, Symbol] config.active_record.yaml_column_permitted_classes = [
Hash,
HashWithIndifferentAccess,
Time,
Symbol,
]
# we skip it cause we configure it in the initializer # we skip it cause we configure it in the initializer
# the railtie for message_bus would insert it in the # the railtie for message_bus would insert it in the
@ -111,7 +109,8 @@ module Discourse
config.skip_multisite_middleware = true config.skip_multisite_middleware = true
config.skip_rails_failover_active_record_middleware = true config.skip_rails_failover_active_record_middleware = true
multisite_config_path = ENV['DISCOURSE_MULTISITE_CONFIG_PATH'] || GlobalSetting.multisite_config_path multisite_config_path =
ENV["DISCOURSE_MULTISITE_CONFIG_PATH"] || GlobalSetting.multisite_config_path
config.multisite_config_path = File.absolute_path(multisite_config_path, Rails.root) config.multisite_config_path = File.absolute_path(multisite_config_path, Rails.root)
# Custom directories with classes and modules you want to be autoloadable. # Custom directories with classes and modules you want to be autoloadable.
@ -129,14 +128,14 @@ module Discourse
# Set Time.zone default to the specified zone and make Active Record auto-convert to this zone. # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
# Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC. # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
config.time_zone = 'UTC' config.time_zone = "UTC"
# auto-load locales in plugins # auto-load locales in plugins
# NOTE: we load both client & server locales since some might be used by PrettyText # NOTE: we load both client & server locales since some might be used by PrettyText
config.i18n.load_path += Dir["#{Rails.root}/plugins/*/config/locales/*.yml"] config.i18n.load_path += Dir["#{Rails.root}/plugins/*/config/locales/*.yml"]
# Configure the default encoding used in templates for Ruby 1.9. # Configure the default encoding used in templates for Ruby 1.9.
config.encoding = 'utf-8' config.encoding = "utf-8"
# see: http://stackoverflow.com/questions/11894180/how-does-one-correctly-add-custom-sql-dml-in-migrations/11894420#11894420 # see: http://stackoverflow.com/questions/11894180/how-does-one-correctly-add-custom-sql-dml-in-migrations/11894420#11894420
config.active_record.schema_format = :sql config.active_record.schema_format = :sql
@ -145,7 +144,7 @@ module Discourse
config.active_record.use_schema_cache_dump = false config.active_record.use_schema_cache_dump = false
# per https://www.owasp.org/index.php/Password_Storage_Cheat_Sheet # per https://www.owasp.org/index.php/Password_Storage_Cheat_Sheet
config.pbkdf2_iterations = 64000 config.pbkdf2_iterations = 64_000
config.pbkdf2_algorithm = "sha256" config.pbkdf2_algorithm = "sha256"
# rack lock is nothing but trouble, get rid of it # rack lock is nothing but trouble, get rid of it
@ -160,32 +159,39 @@ module Discourse
# supports etags (post 1.7) # supports etags (post 1.7)
config.middleware.delete Rack::ETag config.middleware.delete Rack::ETag
if !(Rails.env.development? || ENV['SKIP_ENFORCE_HOSTNAME'] == "1") if !(Rails.env.development? || ENV["SKIP_ENFORCE_HOSTNAME"] == "1")
require 'middleware/enforce_hostname' require "middleware/enforce_hostname"
config.middleware.insert_after Rack::MethodOverride, Middleware::EnforceHostname config.middleware.insert_after Rack::MethodOverride, Middleware::EnforceHostname
end end
require 'content_security_policy/middleware' require "content_security_policy/middleware"
config.middleware.swap ActionDispatch::ContentSecurityPolicy::Middleware, ContentSecurityPolicy::Middleware config.middleware.swap ActionDispatch::ContentSecurityPolicy::Middleware,
ContentSecurityPolicy::Middleware
require 'middleware/discourse_public_exceptions' require "middleware/discourse_public_exceptions"
config.exceptions_app = Middleware::DiscoursePublicExceptions.new(Rails.public_path) config.exceptions_app = Middleware::DiscoursePublicExceptions.new(Rails.public_path)
require 'discourse_js_processor' require "discourse_js_processor"
require 'discourse_sourcemapping_url_processor' require "discourse_sourcemapping_url_processor"
Sprockets.register_mime_type 'application/javascript', extensions: ['.js', '.es6', '.js.es6'], charset: :unicode Sprockets.register_mime_type "application/javascript",
Sprockets.register_postprocessor 'application/javascript', DiscourseJsProcessor extensions: %w[.js .es6 .js.es6],
charset: :unicode
Sprockets.register_postprocessor "application/javascript", DiscourseJsProcessor
Discourse::Application.initializer :prepend_ember_assets do |app| Discourse::Application.initializer :prepend_ember_assets do |app|
# Needs to be in its own initializer so it runs after the append_assets_path initializer defined by Sprockets # Needs to be in its own initializer so it runs after the append_assets_path initializer defined by Sprockets
app.config.assets.paths.unshift "#{app.config.root}/app/assets/javascripts/discourse/dist/assets" app
Sprockets.unregister_postprocessor 'application/javascript', Sprockets::Rails::SourcemappingUrlProcessor .config
Sprockets.register_postprocessor 'application/javascript', DiscourseSourcemappingUrlProcessor .assets
.paths.unshift "#{app.config.root}/app/assets/javascripts/discourse/dist/assets"
Sprockets.unregister_postprocessor "application/javascript",
Sprockets::Rails::SourcemappingUrlProcessor
Sprockets.register_postprocessor "application/javascript", DiscourseSourcemappingUrlProcessor
end end
require 'discourse_redis' require "discourse_redis"
require 'logster/redis_store' require "logster/redis_store"
# Use redis for our cache # Use redis for our cache
config.cache_store = DiscourseRedis.new_redis_store config.cache_store = DiscourseRedis.new_redis_store
Discourse.redis = DiscourseRedis.new Discourse.redis = DiscourseRedis.new
@ -198,7 +204,7 @@ module Discourse
# our setup does not use rack cache and instead defers to nginx # our setup does not use rack cache and instead defers to nginx
config.action_dispatch.rack_cache = nil config.action_dispatch.rack_cache = nil
require 'auth' require "auth"
if GlobalSetting.relative_url_root.present? if GlobalSetting.relative_url_root.present?
config.relative_url_root = GlobalSetting.relative_url_root config.relative_url_root = GlobalSetting.relative_url_root
@ -207,38 +213,28 @@ module Discourse
if Rails.env.test? && GlobalSetting.load_plugins? if Rails.env.test? && GlobalSetting.load_plugins?
Discourse.activate_plugins! Discourse.activate_plugins!
elsif GlobalSetting.load_plugins? elsif GlobalSetting.load_plugins?
Plugin.initialization_guard do Plugin.initialization_guard { Discourse.activate_plugins! }
Discourse.activate_plugins!
end
end end
# Use discourse-fonts gem to symlink fonts and generate .scss file # Use discourse-fonts gem to symlink fonts and generate .scss file
fonts_path = File.join(config.root, 'public/fonts') fonts_path = File.join(config.root, "public/fonts")
Discourse::Utils.atomic_ln_s(DiscourseFonts.path_for_fonts, fonts_path) Discourse::Utils.atomic_ln_s(DiscourseFonts.path_for_fonts, fonts_path)
require 'stylesheet/manager' require "stylesheet/manager"
require 'svg_sprite' require "svg_sprite"
config.after_initialize do config.after_initialize do
# Load plugins # Load plugins
Plugin.initialization_guard do Plugin.initialization_guard { Discourse.plugins.each(&:notify_after_initialize) }
Discourse.plugins.each(&:notify_after_initialize)
end
# we got to clear the pool in case plugins connect # we got to clear the pool in case plugins connect
ActiveRecord::Base.connection_handler.clear_active_connections! ActiveRecord::Base.connection_handler.clear_active_connections!
end end
if ENV['RBTRACE'] == "1" require "rbtrace" if ENV["RBTRACE"] == "1"
require 'rbtrace'
end
if ENV['RAILS_QUERY_LOG_TAGS'] == "1" config.active_record.query_log_tags_enabled = true if ENV["RAILS_QUERY_LOG_TAGS"] == "1"
config.active_record.query_log_tags_enabled = true
end
config.generators do |g| config.generators { |g| g.test_framework :rspec, fixture: false }
g.test_framework :rspec, fixture: false
end
end end
end end

View File

@ -1,48 +1,49 @@
# frozen_string_literal: true # frozen_string_literal: true
if ENV['DISCOURSE_DUMP_HEAP'] == "1" if ENV["DISCOURSE_DUMP_HEAP"] == "1"
require 'objspace' require "objspace"
ObjectSpace.trace_object_allocations_start ObjectSpace.trace_object_allocations_start
end end
require 'rubygems' require "rubygems"
# Set up gems listed in the Gemfile. # Set up gems listed in the Gemfile.
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", __FILE__)
require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE']) require "bundler/setup" if File.exist?(ENV["BUNDLE_GEMFILE"])
if (ENV['DISABLE_BOOTSNAP'] != '1') if (ENV["DISABLE_BOOTSNAP"] != "1")
begin begin
require 'bootsnap' require "bootsnap"
rescue LoadError rescue LoadError
# not a strong requirement # not a strong requirement
end end
if defined? Bootsnap if defined?(Bootsnap)
Bootsnap.setup( Bootsnap.setup(
cache_dir: 'tmp/cache', # Path to your cache cache_dir: "tmp/cache", # Path to your cache
load_path_cache: true, # Should we optimize the LOAD_PATH with a cache? load_path_cache: true, # Should we optimize the LOAD_PATH with a cache?
compile_cache_iseq: true, # Should compile Ruby code into ISeq cache? compile_cache_iseq: true, # Should compile Ruby code into ISeq cache?
compile_cache_yaml: false # Skip YAML cache for now, cause we were seeing issues with it compile_cache_yaml: false, # Skip YAML cache for now, cause we were seeing issues with it
) )
end end
end end
# Parallel spec system # Parallel spec system
if ENV['RAILS_ENV'] == "test" && ENV['TEST_ENV_NUMBER'] if ENV["RAILS_ENV"] == "test" && ENV["TEST_ENV_NUMBER"]
if ENV['TEST_ENV_NUMBER'] == '' if ENV["TEST_ENV_NUMBER"] == ""
n = 1 n = 1
else else
n = ENV['TEST_ENV_NUMBER'].to_i n = ENV["TEST_ENV_NUMBER"].to_i
end end
port = 10000 + n port = 10_000 + n
STDERR.puts "Setting up parallel test mode - starting Redis #{n} on port #{port}" STDERR.puts "Setting up parallel test mode - starting Redis #{n} on port #{port}"
`rm -rf tmp/test_data_#{n} && mkdir -p tmp/test_data_#{n}/redis` `rm -rf tmp/test_data_#{n} && mkdir -p tmp/test_data_#{n}/redis`
pid = Process.spawn("redis-server --dir tmp/test_data_#{n}/redis --port #{port}", out: "/dev/null") pid =
Process.spawn("redis-server --dir tmp/test_data_#{n}/redis --port #{port}", out: "/dev/null")
ENV["DISCOURSE_REDIS_PORT"] = port.to_s ENV["DISCOURSE_REDIS_PORT"] = port.to_s
ENV["RAILS_DB"] = "discourse_test_#{n}" ENV["RAILS_DB"] = "discourse_test_#{n}"

View File

@ -7,7 +7,7 @@ Discourse::Application.configure do
config.cache_classes = true config.cache_classes = true
# Full error reports are disabled and caching is turned on # Full error reports are disabled and caching is turned on
config.consider_all_requests_local = false config.consider_all_requests_local = false
config.action_controller.perform_caching = true config.action_controller.perform_caching = true
# Disable Rails's static asset server (Apache or nginx will already do this) # Disable Rails's static asset server (Apache or nginx will already do this)
@ -23,19 +23,20 @@ Discourse::Application.configure do
config.assets.digest = true config.assets.digest = true
# Specifies the header that your server uses for sending files # Specifies the header that your server uses for sending files
config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for nginx config.action_dispatch.x_sendfile_header = "X-Accel-Redirect" # for nginx
# you may use other configuration here for mail eg: sendgrid # you may use other configuration here for mail eg: sendgrid
config.action_mailer.delivery_method = :smtp config.action_mailer.delivery_method = :smtp
config.action_mailer.smtp_settings = { config.action_mailer.smtp_settings = {
address: ENV['SMTP_ADDRESS'], address: ENV["SMTP_ADDRESS"],
port: ENV['SMTP_PORT'], port: ENV["SMTP_PORT"],
domain: ENV['SMTP_DOMAIN'], domain: ENV["SMTP_DOMAIN"],
user_name: ENV['SMTP_USERNAME'], user_name: ENV["SMTP_USERNAME"],
password: ENV['SMTP_PASSWORD'], password: ENV["SMTP_PASSWORD"],
authentication: 'plain', authentication: "plain",
enable_starttls_auto: true } enable_starttls_auto: true,
}
#config.action_mailer.delivery_method = :sendmail #config.action_mailer.delivery_method = :sendmail
#config.action_mailer.sendmail_settings = {arguments: '-i'} #config.action_mailer.sendmail_settings = {arguments: '-i'}
@ -59,5 +60,4 @@ Discourse::Application.configure do
# Discourse strongly recommend you use a CDN. # Discourse strongly recommend you use a CDN.
# For origin pull cdns all you need to do is register an account and configure # For origin pull cdns all you need to do is register an account and configure
# config.action_controller.asset_host = "http://YOUR_CDN_HERE" # config.action_controller.asset_host = "http://YOUR_CDN_HERE"
end end

View File

@ -7,6 +7,7 @@ require_relative "application"
Rails.application.initialize! Rails.application.initialize!
# When in "dev" mode, ensure we won't be sending any emails # When in "dev" mode, ensure we won't be sending any emails
if Rails.env.development? && ActionMailer::Base.smtp_settings.slice(:address, :port) != { address: "localhost", port: 1025 } if Rails.env.development? &&
ActionMailer::Base.smtp_settings.slice(:address, :port) != { address: "localhost", port: 1025 }
fail "In development mode, you should be using mailhog otherwise you might end up sending thousands of digest emails" fail "In development mode, you should be using mailhog otherwise you might end up sending thousands of digest emails"
end end

View File

@ -16,7 +16,7 @@ Discourse::Application.configure do
config.active_record.use_schema_cache_dump = true config.active_record.use_schema_cache_dump = true
# Show full error reports and disable caching # Show full error reports and disable caching
config.consider_all_requests_local = true config.consider_all_requests_local = true
config.action_controller.perform_caching = false config.action_controller.perform_caching = false
config.action_controller.asset_host = GlobalSetting.cdn_url config.action_controller.asset_host = GlobalSetting.cdn_url
@ -32,27 +32,23 @@ Discourse::Application.configure do
config.assets.debug = false config.assets.debug = false
config.public_file_server.headers = { config.public_file_server.headers = { "Access-Control-Allow-Origin" => "*" }
'Access-Control-Allow-Origin' => '*'
}
# Raise an error on page load if there are pending migrations # Raise an error on page load if there are pending migrations
config.active_record.migration_error = :page_load config.active_record.migration_error = :page_load
config.watchable_dirs['lib'] = [:rb] config.watchable_dirs["lib"] = [:rb]
# we recommend you use mailhog https://github.com/mailhog/MailHog # we recommend you use mailhog https://github.com/mailhog/MailHog
config.action_mailer.smtp_settings = { address: "localhost", port: 1025 } config.action_mailer.smtp_settings = { address: "localhost", port: 1025 }
config.action_mailer.raise_delivery_errors = true config.action_mailer.raise_delivery_errors = true
config.log_level = ENV['DISCOURSE_DEV_LOG_LEVEL'] if ENV['DISCOURSE_DEV_LOG_LEVEL'] config.log_level = ENV["DISCOURSE_DEV_LOG_LEVEL"] if ENV["DISCOURSE_DEV_LOG_LEVEL"]
if ENV['RAILS_VERBOSE_QUERY_LOGS'] == "1" config.active_record.verbose_query_logs = true if ENV["RAILS_VERBOSE_QUERY_LOGS"] == "1"
config.active_record.verbose_query_logs = true
end
if defined?(BetterErrors) if defined?(BetterErrors)
BetterErrors::Middleware.allow_ip! ENV['TRUSTED_IP'] if ENV['TRUSTED_IP'] BetterErrors::Middleware.allow_ip! ENV["TRUSTED_IP"] if ENV["TRUSTED_IP"]
if defined?(Unicorn) && ENV["UNICORN_WORKERS"].to_i != 1 if defined?(Unicorn) && ENV["UNICORN_WORKERS"].to_i != 1
# BetterErrors doesn't work with multiple unicorn workers. Disable it to avoid confusion # BetterErrors doesn't work with multiple unicorn workers. Disable it to avoid confusion
@ -60,51 +56,44 @@ Discourse::Application.configure do
end end
end end
if !ENV["DISABLE_MINI_PROFILER"] config.load_mini_profiler = true if !ENV["DISABLE_MINI_PROFILER"]
config.load_mini_profiler = true
end
if hosts = ENV['DISCOURSE_DEV_HOSTS'] if hosts = ENV["DISCOURSE_DEV_HOSTS"]
Discourse.deprecate("DISCOURSE_DEV_HOSTS is deprecated. Use RAILS_DEVELOPMENT_HOSTS instead.") Discourse.deprecate("DISCOURSE_DEV_HOSTS is deprecated. Use RAILS_DEVELOPMENT_HOSTS instead.")
config.hosts.concat(hosts.split(",")) config.hosts.concat(hosts.split(","))
end end
require 'middleware/turbo_dev' require "middleware/turbo_dev"
config.middleware.insert 0, Middleware::TurboDev config.middleware.insert 0, Middleware::TurboDev
require 'middleware/missing_avatars' require "middleware/missing_avatars"
config.middleware.insert 1, Middleware::MissingAvatars config.middleware.insert 1, Middleware::MissingAvatars
config.enable_anon_caching = false config.enable_anon_caching = false
if RUBY_ENGINE == "ruby" require "rbtrace" if RUBY_ENGINE == "ruby"
require 'rbtrace'
end
if emails = GlobalSetting.developer_emails if emails = GlobalSetting.developer_emails
config.developer_emails = emails.split(",").map(&:downcase).map(&:strip) config.developer_emails = emails.split(",").map(&:downcase).map(&:strip)
end end
if ENV["DISCOURSE_SKIP_CSS_WATCHER"] != "1" && (defined?(Rails::Server) || defined?(Puma) || defined?(Unicorn)) if ENV["DISCOURSE_SKIP_CSS_WATCHER"] != "1" &&
require 'stylesheet/watcher' (defined?(Rails::Server) || defined?(Puma) || defined?(Unicorn))
require "stylesheet/watcher"
STDERR.puts "Starting CSS change watcher" STDERR.puts "Starting CSS change watcher"
@watcher = Stylesheet::Watcher.watch @watcher = Stylesheet::Watcher.watch
end end
config.after_initialize do config.after_initialize do
if ENV["RAILS_COLORIZE_LOGGING"] == "1" config.colorize_logging = true if ENV["RAILS_COLORIZE_LOGGING"] == "1"
config.colorize_logging = true
end
if ENV["RAILS_VERBOSE_QUERY_LOGS"] == "1" if ENV["RAILS_VERBOSE_QUERY_LOGS"] == "1"
ActiveRecord::LogSubscriber.backtrace_cleaner.add_silencer do |line| ActiveRecord::LogSubscriber.backtrace_cleaner.add_silencer do |line|
line =~ /lib\/freedom_patches/ line =~ %r{lib/freedom_patches}
end end
end end
if ENV["RAILS_DISABLE_ACTIVERECORD_LOGS"] == "1" ActiveRecord::Base.logger = nil if ENV["RAILS_DISABLE_ACTIVERECORD_LOGS"] == "1"
ActiveRecord::Base.logger = nil
end
if ENV['BULLET'] if ENV["BULLET"]
Bullet.enable = true Bullet.enable = true
Bullet.rails_logger = true Bullet.rails_logger = true
end end

View File

@ -8,7 +8,7 @@ Discourse::Application.configure do
config.eager_load = true config.eager_load = true
# Full error reports are disabled and caching is turned on # Full error reports are disabled and caching is turned on
config.consider_all_requests_local = false config.consider_all_requests_local = false
config.action_controller.perform_caching = true config.action_controller.perform_caching = true
# Disable Rails's static asset server (Apache or nginx will already do this) # Disable Rails's static asset server (Apache or nginx will already do this)
@ -34,19 +34,19 @@ Discourse::Application.configure do
authentication: GlobalSetting.smtp_authentication, authentication: GlobalSetting.smtp_authentication,
enable_starttls_auto: GlobalSetting.smtp_enable_start_tls, enable_starttls_auto: GlobalSetting.smtp_enable_start_tls,
open_timeout: GlobalSetting.smtp_open_timeout, open_timeout: GlobalSetting.smtp_open_timeout,
read_timeout: GlobalSetting.smtp_read_timeout read_timeout: GlobalSetting.smtp_read_timeout,
} }
settings[:openssl_verify_mode] = GlobalSetting.smtp_openssl_verify_mode if GlobalSetting.smtp_openssl_verify_mode settings[
:openssl_verify_mode
] = GlobalSetting.smtp_openssl_verify_mode if GlobalSetting.smtp_openssl_verify_mode
if GlobalSetting.smtp_force_tls settings[:tls] = true if GlobalSetting.smtp_force_tls
settings[:tls] = true
end
config.action_mailer.smtp_settings = settings.compact config.action_mailer.smtp_settings = settings.compact
else else
config.action_mailer.delivery_method = :sendmail config.action_mailer.delivery_method = :sendmail
config.action_mailer.sendmail_settings = { arguments: '-i' } config.action_mailer.sendmail_settings = { arguments: "-i" }
end end
# Send deprecation notices to registered listeners # Send deprecation notices to registered listeners

View File

@ -11,7 +11,7 @@ Discourse::Application.configure do
config.log_level = :info config.log_level = :info
# Full error reports are disabled and caching is turned on # Full error reports are disabled and caching is turned on
config.consider_all_requests_local = false config.consider_all_requests_local = false
config.action_controller.perform_caching = true config.action_controller.perform_caching = true
# in profile mode we serve static assets # in profile mode we serve static assets
@ -27,7 +27,7 @@ Discourse::Application.configure do
config.assets.digest = true config.assets.digest = true
# Specifies the header that your server uses for sending files # Specifies the header that your server uses for sending files
config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for nginx config.action_dispatch.x_sendfile_header = "X-Accel-Redirect" # for nginx
# we recommend you use mailhog https://github.com/mailhog/MailHog # we recommend you use mailhog https://github.com/mailhog/MailHog
config.action_mailer.smtp_settings = { address: "localhost", port: 1025 } config.action_mailer.smtp_settings = { address: "localhost", port: 1025 }
@ -39,9 +39,7 @@ Discourse::Application.configure do
config.load_mini_profiler = false config.load_mini_profiler = false
# we don't need full logster support, but need to keep it working # we don't need full logster support, but need to keep it working
config.after_initialize do config.after_initialize { Logster.logger = Rails.logger }
Logster.logger = Rails.logger
end
# for profiling with perftools # for profiling with perftools
# config.middleware.use ::Rack::PerftoolsProfiler, default_printer: 'gif' # config.middleware.use ::Rack::PerftoolsProfiler, default_printer: 'gif'

View File

@ -46,21 +46,22 @@ Discourse::Application.configure do
config.eager_load = false config.eager_load = false
if ENV['RAILS_ENABLE_TEST_LOG'] if ENV["RAILS_ENABLE_TEST_LOG"]
config.logger = Logger.new(STDOUT) config.logger = Logger.new(STDOUT)
config.log_level = ENV['RAILS_TEST_LOG_LEVEL'].present? ? ENV['RAILS_TEST_LOG_LEVEL'].to_sym : :info config.log_level =
ENV["RAILS_TEST_LOG_LEVEL"].present? ? ENV["RAILS_TEST_LOG_LEVEL"].to_sym : :info
else else
config.logger = Logger.new(nil) config.logger = Logger.new(nil)
config.log_level = :fatal config.log_level = :fatal
end end
if defined? RspecErrorTracker if defined?(RspecErrorTracker)
config.middleware.insert_after ActionDispatch::Flash, RspecErrorTracker config.middleware.insert_after ActionDispatch::Flash, RspecErrorTracker
end end
config.after_initialize do config.after_initialize do
SiteSetting.defaults.tap do |s| SiteSetting.defaults.tap do |s|
s.set_regardless_of_locale(:s3_upload_bucket, 'bucket') s.set_regardless_of_locale(:s3_upload_bucket, "bucket")
s.set_regardless_of_locale(:min_post_length, 5) s.set_regardless_of_locale(:min_post_length, 5)
s.set_regardless_of_locale(:min_first_post_length, 5) s.set_regardless_of_locale(:min_first_post_length, 5)
s.set_regardless_of_locale(:min_personal_message_post_length, 10) s.set_regardless_of_locale(:min_personal_message_post_length, 10)
@ -73,7 +74,7 @@ Discourse::Application.configure do
s.set_regardless_of_locale(:allow_uncategorized_topics, true) s.set_regardless_of_locale(:allow_uncategorized_topics, true)
# disable plugins # disable plugins
if ENV['LOAD_PLUGINS'] == '1' if ENV["LOAD_PLUGINS"] == "1"
s.set_regardless_of_locale(:discourse_narrative_bot_enabled, false) s.set_regardless_of_locale(:discourse_narrative_bot_enabled, false)
end end
end end

View File

@ -8,25 +8,35 @@ if Rails.env.development? && !Rails.configuration.cache_classes && Discourse.run
*Dir["#{Rails.root}/app/*"].reject { |path| path.end_with? "/assets" }, *Dir["#{Rails.root}/app/*"].reject { |path| path.end_with? "/assets" },
"#{Rails.root}/config", "#{Rails.root}/config",
"#{Rails.root}/lib", "#{Rails.root}/lib",
"#{Rails.root}/plugins" "#{Rails.root}/plugins",
] ]
Listen.to(*paths, only: /\.rb$/) do |modified, added, removed| Listen
supervisor_pid = UNICORN_DEV_SUPERVISOR_PID .to(*paths, only: /\.rb$/) do |modified, added, removed|
auto_restart = supervisor_pid && ENV["AUTO_RESTART"] != "0" supervisor_pid = UNICORN_DEV_SUPERVISOR_PID
auto_restart = supervisor_pid && ENV["AUTO_RESTART"] != "0"
files = modified + added + removed files = modified + added + removed
not_autoloaded = files.filter_map do |file| not_autoloaded =
autoloaded = Rails.autoloaders.main.autoloads.key? file files.filter_map do |file|
Pathname.new(file).relative_path_from(Rails.root) if !autoloaded autoloaded = Rails.autoloaders.main.autoloads.key? file
Pathname.new(file).relative_path_from(Rails.root) if !autoloaded
end
if not_autoloaded.length > 0
message =
(
if auto_restart
"Restarting server..."
else
"Server restart required. Automate this by setting AUTO_RESTART=1."
end
)
STDERR.puts "[DEV]: Edited files which are not autoloaded. #{message}"
STDERR.puts not_autoloaded.map { |path| "- #{path}".indent(7) }.join("\n")
Process.kill("USR2", supervisor_pid) if auto_restart
end
end end
.start
if not_autoloaded.length > 0
message = auto_restart ? "Restarting server..." : "Server restart required. Automate this by setting AUTO_RESTART=1."
STDERR.puts "[DEV]: Edited files which are not autoloaded. #{message}"
STDERR.puts not_autoloaded.map { |path| "- #{path}".indent(7) }.join("\n")
Process.kill("USR2", supervisor_pid) if auto_restart
end
end.start
end end

View File

@ -1,4 +1,4 @@
# frozen_string_literal: true # frozen_string_literal: true
require 'mini_sql_multisite_connection' require "mini_sql_multisite_connection"
::DB = MiniSqlMultisiteConnection.instance ::DB = MiniSqlMultisiteConnection.instance

View File

@ -1,7 +1,8 @@
# frozen_string_literal: true # frozen_string_literal: true
unless Discourse.skip_post_deployment_migrations? unless Discourse.skip_post_deployment_migrations?
ActiveRecord::Tasks::DatabaseTasks.migrations_paths << Rails.root.join( ActiveRecord::Tasks::DatabaseTasks.migrations_paths << Rails
Discourse::DB_POST_MIGRATE_PATH .root
).to_s .join(Discourse::DB_POST_MIGRATE_PATH)
.to_s
end end

View File

@ -15,31 +15,32 @@
# Warning: this could create some very large files! # Warning: this could create some very large files!
if ENV["TRACE_PG_CONNECTIONS"] if ENV["TRACE_PG_CONNECTIONS"]
PG::Connection.prepend(Module.new do PG::Connection.prepend(
TRACE_DIR = "tmp/pgtrace" Module.new do
TRACE_DIR = "tmp/pgtrace"
def initialize(*args) def initialize(*args)
super(*args).tap do super(*args).tap do
next if ENV["TRACE_PG_CONNECTIONS"] == "SIDEKIQ" && !Sidekiq.server? next if ENV["TRACE_PG_CONNECTIONS"] == "SIDEKIQ" && !Sidekiq.server?
FileUtils.mkdir_p(TRACE_DIR) FileUtils.mkdir_p(TRACE_DIR)
@trace_filename = "#{TRACE_DIR}/#{Process.pid}_#{self.object_id}.txt" @trace_filename = "#{TRACE_DIR}/#{Process.pid}_#{self.object_id}.txt"
trace File.new(@trace_filename, "w") trace File.new(@trace_filename, "w")
end
@access_log_mutex = Mutex.new
@accessor_thread = nil
end end
@access_log_mutex = Mutex.new
@accessor_thread = nil
end
def close def close
super.tap do super.tap do
next if ENV["TRACE_PG_CONNECTIONS"] == "SIDEKIQ" && !Sidekiq.server? next if ENV["TRACE_PG_CONNECTIONS"] == "SIDEKIQ" && !Sidekiq.server?
File.delete(@trace_filename) File.delete(@trace_filename)
end
end end
end
def log_access(&blk) def log_access(&blk)
@access_log_mutex.synchronize do @access_log_mutex.synchronize do
if !@accessor_thread.nil? if !@accessor_thread.nil?
Rails.logger.error <<~TEXT Rails.logger.error <<~TEXT
PG Clash: A connection is being accessed from two locations PG Clash: A connection is being accessed from two locations
#{@accessor_thread} was using the connection. Backtrace: #{@accessor_thread} was using the connection. Backtrace:
@ -51,37 +52,38 @@ if ENV["TRACE_PG_CONNECTIONS"]
#{Thread.current&.backtrace&.join("\n")} #{Thread.current&.backtrace&.join("\n")}
TEXT TEXT
if ENV["ON_PG_CLASH"] == "byebug" if ENV["ON_PG_CLASH"] == "byebug"
require "byebug" require "byebug"
byebug # rubocop:disable Lint/Debugger byebug # rubocop:disable Lint/Debugger
end
end end
@accessor_thread = Thread.current
end end
@accessor_thread = Thread.current yield
ensure
@access_log_mutex.synchronize { @accessor_thread = nil }
end end
yield end,
ensure )
@access_log_mutex.synchronize do
@accessor_thread = nil
end
end
end)
class PG::Connection class PG::Connection
LOG_ACCESS_METHODS = [:exec, :sync_exec, :async_exec, LOG_ACCESS_METHODS = %i[
:sync_exec_params, :async_exec_params, exec
:sync_prepare, :async_prepare, sync_exec
:sync_exec_prepared, :async_exec_prepared, async_exec
] sync_exec_params
async_exec_params
sync_prepare
async_prepare
sync_exec_prepared
async_exec_prepared
]
LOG_ACCESS_METHODS.each do |method| LOG_ACCESS_METHODS.each do |method|
new_method = "#{method}_without_logging".to_sym new_method = "#{method}_without_logging".to_sym
alias_method new_method, method alias_method new_method, method
define_method(method) do |*args, &blk| define_method(method) { |*args, &blk| log_access { send(new_method, *args, &blk) } }
log_access { send(new_method, *args, &blk) }
end
end end
end end
end end

View File

@ -11,7 +11,7 @@ module DiscourseInflector
def self.camelize(basename, abspath) def self.camelize(basename, abspath)
return basename.camelize if abspath.ends_with?("onceoff.rb") return basename.camelize if abspath.ends_with?("onceoff.rb")
return 'Jobs' if abspath.ends_with?("jobs/base.rb") return "Jobs" if abspath.ends_with?("jobs/base.rb")
@overrides[basename] || basename.camelize @overrides[basename] || basename.camelize
end end
@ -26,27 +26,29 @@ Rails.autoloaders.each do |autoloader|
# We have filenames that do not follow Zeitwerk's camelization convention. Maintain an inflections for these files # We have filenames that do not follow Zeitwerk's camelization convention. Maintain an inflections for these files
# for now until we decide to fix them one day. # for now until we decide to fix them one day.
autoloader.inflector.inflect( autoloader.inflector.inflect(
'canonical_url' => 'CanonicalURL', "canonical_url" => "CanonicalURL",
'clean_up_unmatched_ips' => 'CleanUpUnmatchedIPs', "clean_up_unmatched_ips" => "CleanUpUnmatchedIPs",
'homepage_constraint' => 'HomePageConstraint', "homepage_constraint" => "HomePageConstraint",
'ip_addr' => 'IPAddr', "ip_addr" => "IPAddr",
'onpdiff' => 'ONPDiff', "onpdiff" => "ONPDiff",
'pop3_polling_enabled_setting_validator' => 'POP3PollingEnabledSettingValidator', "pop3_polling_enabled_setting_validator" => "POP3PollingEnabledSettingValidator",
'version' => 'Discourse', "version" => "Discourse",
'onceoff' => 'Jobs', "onceoff" => "Jobs",
'regular' => 'Jobs', "regular" => "Jobs",
'scheduled' => 'Jobs', "scheduled" => "Jobs",
'google_oauth2_authenticator' => 'GoogleOAuth2Authenticator', "google_oauth2_authenticator" => "GoogleOAuth2Authenticator",
'omniauth_strategies' => 'OmniAuthStrategies', "omniauth_strategies" => "OmniAuthStrategies",
'csrf_token_verifier' => 'CSRFTokenVerifier', "csrf_token_verifier" => "CSRFTokenVerifier",
'html' => 'HTML', "html" => "HTML",
'json' => 'JSON', "json" => "JSON",
'ssrf_detector' => 'SSRFDetector', "ssrf_detector" => "SSRFDetector",
'http' => 'HTTP', "http" => "HTTP",
) )
end end
Rails.autoloaders.main.ignore("lib/tasks", Rails.autoloaders.main.ignore(
"lib/generators", "lib/tasks",
"lib/freedom_patches", "lib/generators",
"lib/i18n/backend", "lib/freedom_patches",
"lib/unicorn_logstash_patch.rb") "lib/i18n/backend",
"lib/unicorn_logstash_patch.rb",
)

View File

@ -1,12 +1,12 @@
# frozen_string_literal: true # frozen_string_literal: true
if Rails.env.development? && ENV['DISCOURSE_FLUSH_REDIS'] if Rails.env.development? && ENV["DISCOURSE_FLUSH_REDIS"]
puts "Flushing redis (development mode)" puts "Flushing redis (development mode)"
Discourse.redis.flushdb Discourse.redis.flushdb
end end
begin begin
if Gem::Version.new(Discourse.redis.info['redis_version']) < Gem::Version.new("6.2.0") if Gem::Version.new(Discourse.redis.info["redis_version"]) < Gem::Version.new("6.2.0")
STDERR.puts "Discourse requires Redis 6.2.0 or up" STDERR.puts "Discourse requires Redis 6.2.0 or up"
exit 1 exit 1
end end

View File

@ -14,16 +14,12 @@ if defined?(RailsFailover::Redis)
Discourse.request_refresh! Discourse.request_refresh!
MessageBus.keepalive_interval = message_bus_keepalive_interval MessageBus.keepalive_interval = message_bus_keepalive_interval
ObjectSpace.each_object(DistributedCache) do |cache| ObjectSpace.each_object(DistributedCache) { |cache| cache.clear }
cache.clear
end
SiteSetting.refresh! SiteSetting.refresh!
end end
if Rails.logger.respond_to? :chained RailsFailover::Redis.logger = Rails.logger.chained.first if Rails.logger.respond_to? :chained
RailsFailover::Redis.logger = Rails.logger.chained.first
end
end end
if defined?(RailsFailover::ActiveRecord) if defined?(RailsFailover::ActiveRecord)
@ -73,10 +69,7 @@ if defined?(RailsFailover::ActiveRecord)
end end
RailsFailover::ActiveRecord.register_force_reading_role_callback do RailsFailover::ActiveRecord.register_force_reading_role_callback do
Discourse.redis.exists?( Discourse.redis.exists?(Discourse::PG_READONLY_MODE_KEY, Discourse::PG_FORCE_READONLY_MODE_KEY)
Discourse::PG_READONLY_MODE_KEY,
Discourse::PG_FORCE_READONLY_MODE_KEY
)
rescue => e rescue => e
if !e.is_a?(Redis::CannotConnectError) if !e.is_a?(Redis::CannotConnectError)
Rails.logger.warn "#{e.class} #{e.message}: #{e.backtrace.join("\n")}" Rails.logger.warn "#{e.class} #{e.message}: #{e.backtrace.join("\n")}"

View File

@ -30,7 +30,8 @@ def setup_message_bus_env(env)
extra_headers = { extra_headers = {
"Access-Control-Allow-Origin" => Discourse.base_url_no_prefix, "Access-Control-Allow-Origin" => Discourse.base_url_no_prefix,
"Access-Control-Allow-Methods" => "GET, POST", "Access-Control-Allow-Methods" => "GET, POST",
"Access-Control-Allow-Headers" => "X-SILENCE-LOGGER, X-Shared-Session-Key, Dont-Chunk, Discourse-Present", "Access-Control-Allow-Headers" =>
"X-SILENCE-LOGGER, X-Shared-Session-Key, Dont-Chunk, Discourse-Present",
"Access-Control-Max-Age" => "7200", "Access-Control-Max-Age" => "7200",
} }
@ -40,7 +41,7 @@ def setup_message_bus_env(env)
rescue Discourse::InvalidAccess => e rescue Discourse::InvalidAccess => e
# this is bad we need to remove the cookie # this is bad we need to remove the cookie
if e.opts[:delete_cookie].present? if e.opts[:delete_cookie].present?
extra_headers['Set-Cookie'] = '_t=del; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT' extra_headers["Set-Cookie"] = "_t=del; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT"
end end
rescue => e rescue => e
Discourse.warn_exception(e, message: "Unexpected error in Message Bus", env: env) Discourse.warn_exception(e, message: "Unexpected error in Message Bus", env: env)
@ -51,23 +52,22 @@ def setup_message_bus_env(env)
raise Discourse::InvalidAccess if !user_id && SiteSetting.login_required raise Discourse::InvalidAccess if !user_id && SiteSetting.login_required
is_admin = !!(user && user.admin?) is_admin = !!(user && user.admin?)
group_ids = if is_admin group_ids =
# special rule, admin is allowed access to all groups if is_admin
Group.pluck(:id) # special rule, admin is allowed access to all groups
elsif user Group.pluck(:id)
user.groups.pluck('groups.id') elsif user
end user.groups.pluck("groups.id")
end
if env[Auth::DefaultCurrentUserProvider::BAD_TOKEN] extra_headers["Discourse-Logged-Out"] = "1" if env[Auth::DefaultCurrentUserProvider::BAD_TOKEN]
extra_headers['Discourse-Logged-Out'] = '1'
end
hash = { hash = {
extra_headers: extra_headers, extra_headers: extra_headers,
user_id: user_id, user_id: user_id,
group_ids: group_ids, group_ids: group_ids,
is_admin: is_admin, is_admin: is_admin,
site_id: RailsMultisite::ConnectionManagement.current_db site_id: RailsMultisite::ConnectionManagement.current_db,
} }
env["__mb"] = hash env["__mb"] = hash
end end
@ -99,7 +99,7 @@ MessageBus.on_middleware_error do |env, e|
if Discourse::InvalidAccess === e if Discourse::InvalidAccess === e
[403, {}, ["Invalid Access"]] [403, {}, ["Invalid Access"]]
elsif RateLimiter::LimitExceeded === e elsif RateLimiter::LimitExceeded === e
[429, { 'Retry-After' => e.available_in.to_s }, [e.description]] [429, { "Retry-After" => e.available_in.to_s }, [e.description]]
end end
end end
@ -119,8 +119,9 @@ end
MessageBus.backend_instance.max_backlog_size = GlobalSetting.message_bus_max_backlog_size MessageBus.backend_instance.max_backlog_size = GlobalSetting.message_bus_max_backlog_size
MessageBus.backend_instance.clear_every = GlobalSetting.message_bus_clear_every MessageBus.backend_instance.clear_every = GlobalSetting.message_bus_clear_every
MessageBus.long_polling_enabled = GlobalSetting.enable_long_polling.nil? ? true : GlobalSetting.enable_long_polling MessageBus.long_polling_enabled =
MessageBus.long_polling_interval = GlobalSetting.long_polling_interval || 25000 GlobalSetting.enable_long_polling.nil? ? true : GlobalSetting.enable_long_polling
MessageBus.long_polling_interval = GlobalSetting.long_polling_interval || 25_000
if Rails.env == "test" || $0 =~ /rake$/ if Rails.env == "test" || $0 =~ /rake$/
# disable keepalive in testing # disable keepalive in testing

View File

@ -6,7 +6,7 @@
Discourse.git_version Discourse.git_version
if GlobalSetting.skip_redis? if GlobalSetting.skip_redis?
require 'site_settings/local_process_provider' require "site_settings/local_process_provider"
Rails.cache = Discourse.cache Rails.cache = Discourse.cache
Rails.application.config.to_prepare do Rails.application.config.to_prepare do
SiteSetting.provider = SiteSettings::LocalProcessProvider.new SiteSetting.provider = SiteSettings::LocalProcessProvider.new
@ -19,7 +19,8 @@ Rails.application.config.to_prepare do
begin begin
SiteSetting.refresh! SiteSetting.refresh!
unless String === SiteSetting.push_api_secret_key && SiteSetting.push_api_secret_key.length == 32 unless String === SiteSetting.push_api_secret_key &&
SiteSetting.push_api_secret_key.length == 32
SiteSetting.push_api_secret_key = SecureRandom.hex SiteSetting.push_api_secret_key = SecureRandom.hex
end end
rescue ActiveRecord::StatementInvalid rescue ActiveRecord::StatementInvalid

View File

@ -5,17 +5,15 @@ return if GlobalSetting.skip_db?
Rails.application.config.to_prepare do Rails.application.config.to_prepare do
# Some sanity checking so we don't count on an unindexed column on boot # Some sanity checking so we don't count on an unindexed column on boot
begin begin
if ActiveRecord::Base.connection.table_exists?(:users) && if ActiveRecord::Base.connection.table_exists?(:users) && User.limit(20).count < 20 &&
User.limit(20).count < 20 && User.where(admin: true).human_users.count == 0
User.where(admin: true).human_users.count == 0
notice = notice =
if GlobalSetting.developer_emails.blank? if GlobalSetting.developer_emails.blank?
"Congratulations, you installed Discourse! Unfortunately, no administrator emails were defined during setup, so finalizing the configuration <a href='https://meta.discourse.org/t/create-admin-account-from-console/17274'>may be difficult</a>." "Congratulations, you installed Discourse! Unfortunately, no administrator emails were defined during setup, so finalizing the configuration <a href='https://meta.discourse.org/t/create-admin-account-from-console/17274'>may be difficult</a>."
else else
emails = GlobalSetting.developer_emails.split(",") emails = GlobalSetting.developer_emails.split(",")
if emails.length > 1 if emails.length > 1
emails = emails[0..-2].join(', ') << " or #{emails[-1]} " emails = emails[0..-2].join(", ") << " or #{emails[-1]} "
else else
emails = emails[0] emails = emails[0]
end end

View File

@ -1,12 +1,13 @@
# frozen_string_literal: true # frozen_string_literal: true
# If Mini Profiler is included via gem # If Mini Profiler is included via gem
if Rails.configuration.respond_to?(:load_mini_profiler) && Rails.configuration.load_mini_profiler && RUBY_ENGINE == "ruby" if Rails.configuration.respond_to?(:load_mini_profiler) && Rails.configuration.load_mini_profiler &&
require 'rack-mini-profiler' RUBY_ENGINE == "ruby"
require 'stackprof' require "rack-mini-profiler"
require "stackprof"
begin begin
require 'memory_profiler' require "memory_profiler"
rescue => e rescue => e
STDERR.put "#{e} failed to require mini profiler" STDERR.put "#{e} failed to require mini profiler"
end end
@ -20,55 +21,56 @@ if defined?(Rack::MiniProfiler) && defined?(Rack::MiniProfiler::Config)
# raw_connection means results are not namespaced # raw_connection means results are not namespaced
# #
# namespacing gets complex, cause mini profiler is in the rack chain way before multisite # namespacing gets complex, cause mini profiler is in the rack chain way before multisite
Rack::MiniProfiler.config.storage_instance = Rack::MiniProfiler::RedisStore.new( Rack::MiniProfiler.config.storage_instance =
connection: DiscourseRedis.new(nil, namespace: false) Rack::MiniProfiler::RedisStore.new(connection: DiscourseRedis.new(nil, namespace: false))
)
Rack::MiniProfiler.config.snapshot_every_n_requests = GlobalSetting.mini_profiler_snapshots_period Rack::MiniProfiler.config.snapshot_every_n_requests = GlobalSetting.mini_profiler_snapshots_period
Rack::MiniProfiler.config.snapshots_transport_destination_url = GlobalSetting.mini_profiler_snapshots_transport_url Rack::MiniProfiler.config.snapshots_transport_destination_url =
Rack::MiniProfiler.config.snapshots_transport_auth_key = GlobalSetting.mini_profiler_snapshots_transport_auth_key GlobalSetting.mini_profiler_snapshots_transport_url
Rack::MiniProfiler.config.snapshots_transport_auth_key =
GlobalSetting.mini_profiler_snapshots_transport_auth_key
Rack::MiniProfiler.config.skip_paths = [ Rack::MiniProfiler.config.skip_paths = [
/^\/message-bus/, %r{^/message-bus},
/^\/extra-locales/, %r{^/extra-locales},
/topics\/timings/, %r{topics/timings},
/assets/, /assets/,
/\/user_avatar\//, %r{/user_avatar/},
/\/letter_avatar\//, %r{/letter_avatar/},
/\/letter_avatar_proxy\//, %r{/letter_avatar_proxy/},
/\/highlight-js\//, %r{/highlight-js/},
/\/svg-sprite\//, %r{/svg-sprite/},
/qunit/, /qunit/,
/srv\/status/, %r{srv/status},
/commits-widget/, /commits-widget/,
/^\/cdn_asset/, %r{^/cdn_asset},
/^\/logs/, %r{^/logs},
/^\/site_customizations/, %r{^/site_customizations},
/^\/uploads/, %r{^/uploads},
/^\/secure-media-uploads/, %r{^/secure-media-uploads},
/^\/secure-uploads/, %r{^/secure-uploads},
/^\/javascripts\//, %r{^/javascripts/},
/^\/images\//, %r{^/images/},
/^\/stylesheets\//, %r{^/stylesheets/},
/^\/favicon\/proxied/, %r{^/favicon/proxied},
/^\/theme-javascripts/ %r{^/theme-javascripts},
] ]
# we DO NOT WANT mini-profiler loading on anything but real desktops and laptops # we DO NOT WANT mini-profiler loading on anything but real desktops and laptops
# so let's rule out all handheld, tablet, and mobile devices # so let's rule out all handheld, tablet, and mobile devices
Rack::MiniProfiler.config.pre_authorize_cb = lambda do |env| Rack::MiniProfiler.config.pre_authorize_cb =
env['HTTP_USER_AGENT'] !~ /iPad|iPhone|Android/ lambda { |env| env["HTTP_USER_AGENT"] !~ /iPad|iPhone|Android/ }
end
# without a user provider our results will use the ip address for namespacing # without a user provider our results will use the ip address for namespacing
# with a load balancer in front this becomes really bad as some results can # with a load balancer in front this becomes really bad as some results can
# be stored associated with ip1 as the user and retrieved using ip2 causing 404s # be stored associated with ip1 as the user and retrieved using ip2 causing 404s
Rack::MiniProfiler.config.user_provider = lambda do |env| Rack::MiniProfiler.config.user_provider =
request = Rack::Request.new(env) lambda do |env|
id = request.cookies["_t"] || request.ip || "unknown" request = Rack::Request.new(env)
id = id.to_s id = request.cookies["_t"] || request.ip || "unknown"
# some security, lets not have these tokens floating about id = id.to_s
Digest::MD5.hexdigest(id) # some security, lets not have these tokens floating about
end Digest::MD5.hexdigest(id)
end
# Cookie path should be set to the base path so Discourse's session cookie path # Cookie path should be set to the base path so Discourse's session cookie path
# does not get clobbered. # does not get clobbered.
@ -77,15 +79,15 @@ if defined?(Rack::MiniProfiler) && defined?(Rack::MiniProfiler::Config)
Rack::MiniProfiler.config.position = "right" Rack::MiniProfiler.config.position = "right"
Rack::MiniProfiler.config.backtrace_ignores ||= [] Rack::MiniProfiler.config.backtrace_ignores ||= []
Rack::MiniProfiler.config.backtrace_ignores << /lib\/rack\/message_bus.rb/ Rack::MiniProfiler.config.backtrace_ignores << %r{lib/rack/message_bus.rb}
Rack::MiniProfiler.config.backtrace_ignores << /config\/initializers\/silence_logger/ Rack::MiniProfiler.config.backtrace_ignores << %r{config/initializers/silence_logger}
Rack::MiniProfiler.config.backtrace_ignores << /config\/initializers\/quiet_logger/ Rack::MiniProfiler.config.backtrace_ignores << %r{config/initializers/quiet_logger}
Rack::MiniProfiler.config.backtrace_includes = [/^\/?(app|config|lib|test|plugins)/] Rack::MiniProfiler.config.backtrace_includes = [%r{^/?(app|config|lib|test|plugins)}]
Rack::MiniProfiler.config.max_traces_to_show = 100 if Rails.env.development? Rack::MiniProfiler.config.max_traces_to_show = 100 if Rails.env.development?
Rack::MiniProfiler.counter_method(Redis::Client, :call) { 'redis' } Rack::MiniProfiler.counter_method(Redis::Client, :call) { "redis" }
# Rack::MiniProfiler.counter_method(ActiveRecord::QueryMethods, 'build_arel') # Rack::MiniProfiler.counter_method(ActiveRecord::QueryMethods, 'build_arel')
# Rack::MiniProfiler.counter_method(Array, 'uniq') # Rack::MiniProfiler.counter_method(Array, 'uniq')
# require "#{Rails.root}/vendor/backports/notification" # require "#{Rails.root}/vendor/backports/notification"
@ -115,10 +117,11 @@ if defined?(Rack::MiniProfiler) && defined?(Rack::MiniProfiler::Config)
end end
if ENV["PRINT_EXCEPTIONS"] if ENV["PRINT_EXCEPTIONS"]
trace = TracePoint.new(:raise) do |tp| trace =
puts tp.raised_exception TracePoint.new(:raise) do |tp|
puts tp.raised_exception.backtrace.join("\n") puts tp.raised_exception
puts puts tp.raised_exception.backtrace.join("\n")
end puts
end
trace.enable trace.enable
end end

View File

@ -6,18 +6,17 @@ class Discourse::Cors
def initialize(app, options = nil) def initialize(app, options = nil)
@app = app @app = app
if GlobalSetting.enable_cors && GlobalSetting.cors_origin.present? if GlobalSetting.enable_cors && GlobalSetting.cors_origin.present?
@global_origins = GlobalSetting.cors_origin.split(',').map { |x| x.strip.chomp('/') } @global_origins = GlobalSetting.cors_origin.split(",").map { |x| x.strip.chomp("/") }
end end
end end
def call(env) def call(env)
cors_origins = @global_origins || [] cors_origins = @global_origins || []
cors_origins += SiteSetting.cors_origins.split('|') if SiteSetting.cors_origins.present? cors_origins += SiteSetting.cors_origins.split("|") if SiteSetting.cors_origins.present?
cors_origins = cors_origins.presence cors_origins = cors_origins.presence
if env['REQUEST_METHOD'] == ('OPTIONS') && env['HTTP_ACCESS_CONTROL_REQUEST_METHOD'] if env["REQUEST_METHOD"] == ("OPTIONS") && env["HTTP_ACCESS_CONTROL_REQUEST_METHOD"]
return [200, Discourse::Cors.apply_headers(cors_origins, env, {}), []] return 200, Discourse::Cors.apply_headers(cors_origins, env, {}), []
end end
env[Discourse::Cors::ORIGINS_ENV] = cors_origins if cors_origins env[Discourse::Cors::ORIGINS_ENV] = cors_origins if cors_origins
@ -31,21 +30,24 @@ class Discourse::Cors
end end
def self.apply_headers(cors_origins, env, headers) def self.apply_headers(cors_origins, env, headers)
request_method = env['REQUEST_METHOD'] request_method = env["REQUEST_METHOD"]
if env['REQUEST_PATH'] =~ /\/(javascripts|assets)\// && Discourse.is_cdn_request?(env, request_method) if env["REQUEST_PATH"] =~ %r{/(javascripts|assets)/} &&
Discourse.is_cdn_request?(env, request_method)
Discourse.apply_cdn_headers(headers) Discourse.apply_cdn_headers(headers)
elsif cors_origins elsif cors_origins
origin = nil origin = nil
if origin = env['HTTP_ORIGIN'] if origin = env["HTTP_ORIGIN"]
origin = nil unless cors_origins.include?(origin) origin = nil unless cors_origins.include?(origin)
end end
headers['Access-Control-Allow-Origin'] = origin || cors_origins[0] headers["Access-Control-Allow-Origin"] = origin || cors_origins[0]
headers['Access-Control-Allow-Headers'] = 'Content-Type, Cache-Control, X-Requested-With, X-CSRF-Token, Discourse-Present, User-Api-Key, User-Api-Client-Id, Authorization' headers[
headers['Access-Control-Allow-Credentials'] = 'true' "Access-Control-Allow-Headers"
headers['Access-Control-Allow-Methods'] = 'POST, PUT, GET, OPTIONS, DELETE' ] = "Content-Type, Cache-Control, X-Requested-With, X-CSRF-Token, Discourse-Present, User-Api-Key, User-Api-Client-Id, Authorization"
headers['Access-Control-Max-Age'] = '7200' headers["Access-Control-Allow-Credentials"] = "true"
headers["Access-Control-Allow-Methods"] = "POST, PUT, GET, OPTIONS, DELETE"
headers["Access-Control-Max-Age"] = "7200"
end end
headers headers

View File

@ -1,11 +1,7 @@
# frozen_string_literal: true # frozen_string_literal: true
%i( %i[topic_recovered].each do |event|
topic_recovered DiscourseEvent.on(event) { |topic, _| WebHook.enqueue_topic_hooks(event, topic) }
).each do |event|
DiscourseEvent.on(event) do |topic, _|
WebHook.enqueue_topic_hooks(event, topic)
end
end end
DiscourseEvent.on(:topic_status_updated) do |topic, status| DiscourseEvent.on(:topic_status_updated) do |topic, status|
@ -16,18 +12,12 @@ DiscourseEvent.on(:topic_created) do |topic, _, _|
WebHook.enqueue_topic_hooks(:topic_created, topic) WebHook.enqueue_topic_hooks(:topic_created, topic)
end end
%i( %i[post_created post_recovered].each do |event|
post_created DiscourseEvent.on(event) { |post, _, _| WebHook.enqueue_post_hooks(event, post) }
post_recovered
).each do |event|
DiscourseEvent.on(event) do |post, _, _|
WebHook.enqueue_post_hooks(event, post)
end
end end
DiscourseEvent.on(:post_edited) do |post, topic_changed| DiscourseEvent.on(:post_edited) do |post, topic_changed|
unless post.topic&.trashed? unless post.topic&.trashed?
# if we are editing the OP and the topic is changed, do not send # if we are editing the OP and the topic is changed, do not send
# the post_edited event -- this event is sent separately because # the post_edited event -- this event is sent separately because
# when we update the OP in the UI we send two API calls in this order: # when we update the OP in the UI we send two API calls in this order:
@ -42,49 +32,30 @@ DiscourseEvent.on(:post_edited) do |post, topic_changed|
end end
end end
%i( %i[
user_logged_out user_logged_out
user_created user_created
user_logged_in user_logged_in
user_approved user_approved
user_updated user_updated
user_confirmed_email user_confirmed_email
).each do |event| ].each do |event|
DiscourseEvent.on(event) do |user| DiscourseEvent.on(event) { |user| WebHook.enqueue_object_hooks(:user, user, event) }
WebHook.enqueue_object_hooks(:user, user, event)
end
end end
%i( %i[group_created group_updated].each do |event|
group_created DiscourseEvent.on(event) { |group| WebHook.enqueue_object_hooks(:group, group, event) }
group_updated
).each do |event|
DiscourseEvent.on(event) do |group|
WebHook.enqueue_object_hooks(:group, group, event)
end
end end
%i( %i[category_created category_updated].each do |event|
category_created DiscourseEvent.on(event) { |category| WebHook.enqueue_object_hooks(:category, category, event) }
category_updated
).each do |event|
DiscourseEvent.on(event) do |category|
WebHook.enqueue_object_hooks(:category, category, event)
end
end end
%i( %i[tag_created tag_updated].each do |event|
tag_created DiscourseEvent.on(event) { |tag| WebHook.enqueue_object_hooks(:tag, tag, event, TagSerializer) }
tag_updated
).each do |event|
DiscourseEvent.on(event) do |tag|
WebHook.enqueue_object_hooks(:tag, tag, event, TagSerializer)
end
end end
%i( %i[user_badge_granted].each do |event|
user_badge_granted
).each do |event|
# user_badge_revoked # user_badge_revoked
DiscourseEvent.on(event) do |badge, user_id| DiscourseEvent.on(event) do |badge, user_id|
ub = UserBadge.find_by(badge: badge, user_id: user_id) ub = UserBadge.find_by(badge: badge, user_id: user_id)
@ -92,30 +63,43 @@ end
end end
end end
%i( %i[reviewable_created reviewable_score_updated].each do |event|
reviewable_created
reviewable_score_updated
).each do |event|
DiscourseEvent.on(event) do |reviewable| DiscourseEvent.on(event) do |reviewable|
WebHook.enqueue_object_hooks(:reviewable, reviewable, event, reviewable.serializer) WebHook.enqueue_object_hooks(:reviewable, reviewable, event, reviewable.serializer)
end end
end end
DiscourseEvent.on(:reviewable_transitioned_to) do |status, reviewable| DiscourseEvent.on(:reviewable_transitioned_to) do |status, reviewable|
WebHook.enqueue_object_hooks(:reviewable, reviewable, :reviewable_transitioned_to, reviewable.serializer) WebHook.enqueue_object_hooks(
:reviewable,
reviewable,
:reviewable_transitioned_to,
reviewable.serializer,
)
end end
DiscourseEvent.on(:notification_created) do |notification| DiscourseEvent.on(:notification_created) do |notification|
WebHook.enqueue_object_hooks(:notification, notification, :notification_created, NotificationSerializer) WebHook.enqueue_object_hooks(
:notification,
notification,
:notification_created,
NotificationSerializer,
)
end end
DiscourseEvent.on(:user_added_to_group) do |user, group, options| DiscourseEvent.on(:user_added_to_group) do |user, group, options|
group_user = GroupUser.find_by(user: user, group: group) group_user = GroupUser.find_by(user: user, group: group)
WebHook.enqueue_object_hooks(:group_user, group_user, :user_added_to_group, WebHookGroupUserSerializer) WebHook.enqueue_object_hooks(
:group_user,
group_user,
:user_added_to_group,
WebHookGroupUserSerializer,
)
end end
DiscourseEvent.on(:user_promoted) do |payload| DiscourseEvent.on(:user_promoted) do |payload|
user_id, new_trust_level, old_trust_level = payload.values_at(:user_id, :new_trust_level, :old_trust_level) user_id, new_trust_level, old_trust_level =
payload.values_at(:user_id, :new_trust_level, :old_trust_level)
next if new_trust_level < old_trust_level next if new_trust_level < old_trust_level
@ -130,8 +114,13 @@ DiscourseEvent.on(:like_created) do |post_action|
category_id = topic&.category_id category_id = topic&.category_id
tag_ids = topic&.tag_ids tag_ids = topic&.tag_ids
WebHook.enqueue_object_hooks(:like, WebHook.enqueue_object_hooks(
post_action, :post_liked, WebHookLikeSerializer, :like,
group_ids: group_ids, category_id: category_id, tag_ids: tag_ids post_action,
:post_liked,
WebHookLikeSerializer,
group_ids: group_ids,
category_id: category_id,
tag_ids: tag_ids,
) )
end end

View File

@ -1,4 +1,4 @@
# frozen_string_literal: true # frozen_string_literal: true
require 'excon' require "excon"
Excon::DEFAULTS[:omit_default_port] = true Excon::DEFAULTS[:omit_default_port] = true

View File

@ -6,10 +6,11 @@ DiscourseEvent.on(:site_setting_changed) do |name, old_value, new_value|
# Enabling `must_approve_users` on an existing site is odd, so we assume that the # Enabling `must_approve_users` on an existing site is odd, so we assume that the
# existing users are approved. # existing users are approved.
if name == :must_approve_users && new_value == true if name == :must_approve_users && new_value == true
User
User.where(approved: false) .where(approved: false)
.joins("LEFT JOIN reviewables r ON r.target_id = users.id") .joins("LEFT JOIN reviewables r ON r.target_id = users.id")
.where(r: { id: nil }).update_all(approved: true) .where(r: { id: nil })
.update_all(approved: true)
end end
if name == :emoji_set if name == :emoji_set
@ -19,31 +20,28 @@ DiscourseEvent.on(:site_setting_changed) do |name, old_value, new_value|
after = "/images/emoji/#{new_value}/" after = "/images/emoji/#{new_value}/"
Scheduler::Defer.later("Fix Emoji Links") do Scheduler::Defer.later("Fix Emoji Links") do
DB.exec("UPDATE posts SET cooked = REPLACE(cooked, :before, :after) WHERE cooked LIKE :like", DB.exec(
"UPDATE posts SET cooked = REPLACE(cooked, :before, :after) WHERE cooked LIKE :like",
before: before, before: before,
after: after, after: after,
like: "%#{before}%" like: "%#{before}%",
) )
end end
end end
Stylesheet::Manager.clear_color_scheme_cache! if [:base_font, :heading_font].include?(name) Stylesheet::Manager.clear_color_scheme_cache! if %i[base_font heading_font].include?(name)
Report.clear_cache(:storage_stats) if [:backup_location, :s3_backup_bucket].include?(name) Report.clear_cache(:storage_stats) if %i[backup_location s3_backup_bucket].include?(name)
if name == :slug_generation_method if name == :slug_generation_method
Scheduler::Defer.later("Null topic slug") do Scheduler::Defer.later("Null topic slug") { Topic.update_all(slug: nil) }
Topic.update_all(slug: nil)
end
end end
Jobs.enqueue(:update_s3_inventory) if [:enable_s3_inventory, :s3_upload_bucket].include?(name) Jobs.enqueue(:update_s3_inventory) if %i[enable_s3_inventory s3_upload_bucket].include?(name)
SvgSprite.expire_cache if name.to_s.include?("_icon") SvgSprite.expire_cache if name.to_s.include?("_icon")
if SiteIconManager::WATCHED_SETTINGS.include?(name) SiteIconManager.ensure_optimized! if SiteIconManager::WATCHED_SETTINGS.include?(name)
SiteIconManager.ensure_optimized!
end
# Make sure medium and high priority thresholds were calculated. # Make sure medium and high priority thresholds were calculated.
if name == :reviewable_low_priority_threshold && Reviewable.min_score_for_priority(:medium) > 0 if name == :reviewable_low_priority_threshold && Reviewable.min_score_for_priority(:medium) > 0

View File

@ -9,7 +9,7 @@ enabled =
Rails.env.production? Rails.env.production?
end end
if !ENV['DISCOURSE_DISABLE_ANON_CACHE'] && enabled if !ENV["DISCOURSE_DISABLE_ANON_CACHE"] && enabled
# in an ideal world this is position 0, but mobile detection uses ... session and request and params # in an ideal world this is position 0, but mobile detection uses ... session and request and params
Rails.configuration.middleware.insert_after ActionDispatch::Flash, Middleware::AnonymousCache Rails.configuration.middleware.insert_after ActionDispatch::Flash, Middleware::AnonymousCache
end end

View File

@ -0,0 +1 @@

View File

@ -2,8 +2,8 @@
# order: after 02-freedom_patches.rb # order: after 02-freedom_patches.rb
require 'i18n/backend/discourse_i18n' require "i18n/backend/discourse_i18n"
require 'i18n/backend/fallback_locale_list' require "i18n/backend/fallback_locale_list"
# Requires the `translate_accelerator.rb` freedom patch to be loaded # Requires the `translate_accelerator.rb` freedom patch to be loaded
Rails.application.reloader.to_prepare do Rails.application.reloader.to_prepare do
@ -11,7 +11,7 @@ Rails.application.reloader.to_prepare do
I18n.fallbacks = I18n::Backend::FallbackLocaleList.new I18n.fallbacks = I18n::Backend::FallbackLocaleList.new
I18n.config.missing_interpolation_argument_handler = proc { throw(:exception) } I18n.config.missing_interpolation_argument_handler = proc { throw(:exception) }
I18n.reload! I18n.reload!
I18n.init_accelerator!(overrides_enabled: ENV['DISABLE_TRANSLATION_OVERRIDES'] != '1') I18n.init_accelerator!(overrides_enabled: ENV["DISABLE_TRANSLATION_OVERRIDES"] != "1")
unless Rails.env.test? unless Rails.env.test?
MessageBus.subscribe("/i18n-flush") do MessageBus.subscribe("/i18n-flush") do

View File

@ -2,9 +2,7 @@
if GlobalSetting.skip_redis? if GlobalSetting.skip_redis?
Rails.application.reloader.to_prepare do Rails.application.reloader.to_prepare do
if Rails.logger.respond_to? :chained Rails.logger = Rails.logger.chained.first if Rails.logger.respond_to? :chained
Rails.logger = Rails.logger.chained.first
end
end end
return return
end end
@ -39,9 +37,7 @@ if Rails.env.production?
# https://github.com/rails/rails/blob/f2caed1e/actionpack/lib/action_dispatch/middleware/exception_wrapper.rb#L39-L42 # https://github.com/rails/rails/blob/f2caed1e/actionpack/lib/action_dispatch/middleware/exception_wrapper.rb#L39-L42
/^ActionController::RoutingError \(No route matches/, /^ActionController::RoutingError \(No route matches/,
/^ActionDispatch::Http::MimeNegotiation::InvalidType/, /^ActionDispatch::Http::MimeNegotiation::InvalidType/,
/^PG::Error: ERROR:\s+duplicate key/, /^PG::Error: ERROR:\s+duplicate key/,
/^ActionController::UnknownFormat/, /^ActionController::UnknownFormat/,
/^ActionController::UnknownHttpMethod/, /^ActionController::UnknownHttpMethod/,
/^AbstractController::ActionNotFound/, /^AbstractController::ActionNotFound/,
@ -51,29 +47,21 @@ if Rails.env.production?
# Column: # Column:
# #
/(?m).*?Line: (?:\D|0).*?Column: (?:\D|0)/, /(?m).*?Line: (?:\D|0).*?Column: (?:\D|0)/,
# suppress empty JS errors (covers MSIE 9, etc) # suppress empty JS errors (covers MSIE 9, etc)
/^(Syntax|Script) error.*Line: (0|1)\b/m, /^(Syntax|Script) error.*Line: (0|1)\b/m,
# CSRF errors are not providing enough data # CSRF errors are not providing enough data
# suppress unconditionally for now # suppress unconditionally for now
/^Can't verify CSRF token authenticity.$/, /^Can't verify CSRF token authenticity.$/,
# Yandex bot triggers this JS error a lot # Yandex bot triggers this JS error a lot
/^Uncaught ReferenceError: I18n is not defined/, /^Uncaught ReferenceError: I18n is not defined/,
# related to browser plugins somehow, we don't care # related to browser plugins somehow, we don't care
/Error calling method on NPObject/, /Error calling method on NPObject/,
# 404s can be dealt with elsewhere # 404s can be dealt with elsewhere
/^ActiveRecord::RecordNotFound/, /^ActiveRecord::RecordNotFound/,
# bad asset requested, no need to log # bad asset requested, no need to log
/^ActionController::BadRequest/, /^ActionController::BadRequest/,
# we can't do anything about invalid parameters # we can't do anything about invalid parameters
/Rack::QueryParser::InvalidParameterError/, /Rack::QueryParser::InvalidParameterError/,
# we handle this cleanly in the message bus middleware # we handle this cleanly in the message bus middleware
# no point logging to logster # no point logging to logster
/RateLimiter::LimitExceeded.*/m, /RateLimiter::LimitExceeded.*/m,
@ -98,33 +86,37 @@ store.redis_raw_connection = redis.without_namespace
severities = [Logger::WARN, Logger::ERROR, Logger::FATAL, Logger::UNKNOWN] severities = [Logger::WARN, Logger::ERROR, Logger::FATAL, Logger::UNKNOWN]
RailsMultisite::ConnectionManagement.each_connection do RailsMultisite::ConnectionManagement.each_connection do
error_rate_per_minute = SiteSetting.alert_admins_if_errors_per_minute rescue 0 error_rate_per_minute =
begin
SiteSetting.alert_admins_if_errors_per_minute
rescue StandardError
0
end
if (error_rate_per_minute || 0) > 0 if (error_rate_per_minute || 0) > 0
store.register_rate_limit_per_minute(severities, error_rate_per_minute) do |rate| store.register_rate_limit_per_minute(severities, error_rate_per_minute) do |rate|
MessageBus.publish("/logs_error_rate_exceeded", MessageBus.publish(
{ "/logs_error_rate_exceeded",
rate: rate, { rate: rate, duration: "minute", publish_at: Time.current.to_i },
duration: 'minute', group_ids: [Group::AUTO_GROUPS[:admins]],
publish_at: Time.current.to_i )
},
group_ids: [Group::AUTO_GROUPS[:admins]]
)
end end
end end
error_rate_per_hour = SiteSetting.alert_admins_if_errors_per_hour rescue 0 error_rate_per_hour =
begin
SiteSetting.alert_admins_if_errors_per_hour
rescue StandardError
0
end
if (error_rate_per_hour || 0) > 0 if (error_rate_per_hour || 0) > 0
store.register_rate_limit_per_hour(severities, error_rate_per_hour) do |rate| store.register_rate_limit_per_hour(severities, error_rate_per_hour) do |rate|
MessageBus.publish("/logs_error_rate_exceeded", MessageBus.publish(
{ "/logs_error_rate_exceeded",
rate: rate, { rate: rate, duration: "hour", publish_at: Time.current.to_i },
duration: 'hour', group_ids: [Group::AUTO_GROUPS[:admins]],
publish_at: Time.current.to_i, )
},
group_ids: [Group::AUTO_GROUPS[:admins]]
)
end end
end end
end end
@ -137,13 +129,13 @@ if Rails.configuration.multisite
end end
Logster.config.project_directories = [ Logster.config.project_directories = [
{ path: Rails.root.to_s, url: "https://github.com/discourse/discourse", main_app: true } { path: Rails.root.to_s, url: "https://github.com/discourse/discourse", main_app: true },
] ]
Discourse.plugins.each do |plugin| Discourse.plugins.each do |plugin|
next if !plugin.metadata.url next if !plugin.metadata.url
Logster.config.project_directories << { Logster.config.project_directories << {
path: "#{Rails.root.to_s}/plugins/#{plugin.directory_name}", path: "#{Rails.root.to_s}/plugins/#{plugin.directory_name}",
url: plugin.metadata.url url: plugin.metadata.url,
} }
end end

View File

@ -6,13 +6,13 @@ Rails.application.config.to_prepare do
twitter_client: TwitterApi, twitter_client: TwitterApi,
redirect_limit: 3, redirect_limit: 3,
user_agent: "Discourse Forum Onebox v#{Discourse::VERSION::STRING}", user_agent: "Discourse Forum Onebox v#{Discourse::VERSION::STRING}",
allowed_ports: [80, 443, SiteSetting.port.to_i] allowed_ports: [80, 443, SiteSetting.port.to_i],
} }
else else
Onebox.options = { Onebox.options = {
twitter_client: TwitterApi, twitter_client: TwitterApi,
redirect_limit: 3, redirect_limit: 3,
user_agent: "Discourse Forum Onebox v#{Discourse::VERSION::STRING}" user_agent: "Discourse Forum Onebox v#{Discourse::VERSION::STRING}",
} }
end end
end end

View File

@ -3,13 +3,11 @@
return if GlobalSetting.skip_db? return if GlobalSetting.skip_db?
Rails.application.config.to_prepare do Rails.application.config.to_prepare do
require 'web-push' require "web-push"
def generate_vapid_key? def generate_vapid_key?
SiteSetting.vapid_public_key.blank? || SiteSetting.vapid_public_key.blank? || SiteSetting.vapid_private_key.blank? ||
SiteSetting.vapid_private_key.blank? || SiteSetting.vapid_public_key_bytes.blank? || SiteSetting.vapid_base_url != Discourse.base_url
SiteSetting.vapid_public_key_bytes.blank? ||
SiteSetting.vapid_base_url != Discourse.base_url
end end
SiteSetting.vapid_base_url = Discourse.base_url if SiteSetting.vapid_base_url.blank? SiteSetting.vapid_base_url = Discourse.base_url if SiteSetting.vapid_base_url.blank?
@ -19,15 +17,12 @@ Rails.application.config.to_prepare do
SiteSetting.vapid_public_key = vapid_key.public_key SiteSetting.vapid_public_key = vapid_key.public_key
SiteSetting.vapid_private_key = vapid_key.private_key SiteSetting.vapid_private_key = vapid_key.private_key
SiteSetting.vapid_public_key_bytes = Base64.urlsafe_decode64(SiteSetting.vapid_public_key).bytes.join("|") SiteSetting.vapid_public_key_bytes =
Base64.urlsafe_decode64(SiteSetting.vapid_public_key).bytes.join("|")
SiteSetting.vapid_base_url = Discourse.base_url SiteSetting.vapid_base_url = Discourse.base_url
if ActiveRecord::Base.connection.table_exists?(:push_subscriptions) PushSubscription.delete_all if ActiveRecord::Base.connection.table_exists?(:push_subscriptions)
PushSubscription.delete_all
end
end end
DiscourseEvent.on(:user_logged_out) do |user| DiscourseEvent.on(:user_logged_out) { |user| PushNotificationPusher.clear_subscriptions(user) }
PushNotificationPusher.clear_subscriptions(user)
end
end end

View File

@ -1,30 +1,23 @@
# frozen_string_literal: true # frozen_string_literal: true
Rails.application.config.assets.configure do |env| Rails.application.config.assets.configure { |env| env.logger = Logger.new("/dev/null") }
env.logger = Logger.new('/dev/null')
end
module DiscourseRackQuietAssetsLogger module DiscourseRackQuietAssetsLogger
def call(env) def call(env)
override = false override = false
if (env['PATH_INFO'].index("/assets/") == 0) || if (env["PATH_INFO"].index("/assets/") == 0) || (env["PATH_INFO"].index("/stylesheets") == 0) ||
(env['PATH_INFO'].index("/stylesheets") == 0) || (env["PATH_INFO"].index("/svg-sprite") == 0) ||
(env['PATH_INFO'].index("/svg-sprite") == 0) || (env["PATH_INFO"].index("/manifest") == 0) ||
(env['PATH_INFO'].index("/manifest") == 0) || (env["PATH_INFO"].index("/service-worker") == 0) ||
(env['PATH_INFO'].index("/service-worker") == 0) || (env["PATH_INFO"].index("mini-profiler-resources") == 0) ||
(env['PATH_INFO'].index("mini-profiler-resources") == 0) || (env["PATH_INFO"].index("/srv/status") == 0)
(env['PATH_INFO'].index("/srv/status") == 0)
if ::Logster::Logger === Rails.logger if ::Logster::Logger === Rails.logger
override = true override = true
Rails.logger.override_level = Logger::ERROR Rails.logger.override_level = Logger::ERROR
end end
end end
super(env).tap do super(env).tap { Rails.logger.override_level = nil if override }
if override
Rails.logger.override_level = nil
end
end
end end
end end

View File

@ -4,8 +4,15 @@
Rails.application.config.session_store( Rails.application.config.session_store(
:discourse_cookie_store, :discourse_cookie_store,
key: '_forum_session', key: "_forum_session",
path: (Rails.application.config.relative_url_root.nil?) ? '/' : Rails.application.config.relative_url_root path:
(
if (Rails.application.config.relative_url_root.nil?)
"/"
else
Rails.application.config.relative_url_root
end
),
) )
Rails.application.config.to_prepare do Rails.application.config.to_prepare do

View File

@ -1,22 +1,17 @@
# frozen_string_literal: true # frozen_string_literal: true
require "sidekiq/pausable" require "sidekiq/pausable"
require 'sidekiq_logster_reporter' require "sidekiq_logster_reporter"
Sidekiq.configure_client do |config| Sidekiq.configure_client { |config| config.redis = Discourse.sidekiq_redis_config }
config.redis = Discourse.sidekiq_redis_config
end
Sidekiq.configure_server do |config| Sidekiq.configure_server do |config|
config.redis = Discourse.sidekiq_redis_config config.redis = Discourse.sidekiq_redis_config
config.server_middleware do |chain| config.server_middleware { |chain| chain.add Sidekiq::Pausable }
chain.add Sidekiq::Pausable
end
end end
if Sidekiq.server? if Sidekiq.server?
module Sidekiq module Sidekiq
class CLI class CLI
private private
@ -34,13 +29,17 @@ if Sidekiq.server?
# warm up AR # warm up AR
RailsMultisite::ConnectionManagement.safe_each_connection do RailsMultisite::ConnectionManagement.safe_each_connection do
(ActiveRecord::Base.connection.tables - %w[schema_migrations versions]).each do |table| (ActiveRecord::Base.connection.tables - %w[schema_migrations versions]).each do |table|
table.classify.constantize.first rescue nil begin
table.classify.constantize.first
rescue StandardError
nil
end
end end
end end
scheduler_hostname = ENV["UNICORN_SCHEDULER_HOSTNAME"] scheduler_hostname = ENV["UNICORN_SCHEDULER_HOSTNAME"]
if !scheduler_hostname || scheduler_hostname.split(',').include?(Discourse.os_hostname) if !scheduler_hostname || scheduler_hostname.split(",").include?(Discourse.os_hostname)
begin begin
MiniScheduler.start(workers: GlobalSetting.mini_scheduler_workers) MiniScheduler.start(workers: GlobalSetting.mini_scheduler_workers)
rescue MiniScheduler::DistributedMutex::Timeout rescue MiniScheduler::DistributedMutex::Timeout
@ -57,9 +56,11 @@ else
# Instead, this patch adds a dedicated logger instance and patches # Instead, this patch adds a dedicated logger instance and patches
# the #add method to forward messages to Rails.logger. # the #add method to forward messages to Rails.logger.
Sidekiq.logger = Logger.new(nil) Sidekiq.logger = Logger.new(nil)
Sidekiq.logger.define_singleton_method(:add) do |severity, message = nil, progname = nil, &blk| Sidekiq
Rails.logger.add(severity, message, progname, &blk) .logger
end .define_singleton_method(:add) do |severity, message = nil, progname = nil, &blk|
Rails.logger.add(severity, message, progname, &blk)
end
end end
Sidekiq.error_handlers.clear Sidekiq.error_handlers.clear
@ -69,28 +70,20 @@ Sidekiq.strict_args!
Rails.application.config.to_prepare do Rails.application.config.to_prepare do
# Ensure that scheduled jobs are loaded before mini_scheduler is configured. # Ensure that scheduled jobs are loaded before mini_scheduler is configured.
if Rails.env.development? Dir.glob("#{Rails.root}/app/jobs/scheduled/*.rb") { |f| require(f) } if Rails.env.development?
Dir.glob("#{Rails.root}/app/jobs/scheduled/*.rb") do |f|
require(f)
end
end
MiniScheduler.configure do |config| MiniScheduler.configure do |config|
config.redis = Discourse.redis config.redis = Discourse.redis
config.job_exception_handler do |ex, context| config.job_exception_handler { |ex, context| Discourse.handle_job_exception(ex, context) }
Discourse.handle_job_exception(ex, context)
end
config.job_ran do |stat| config.job_ran { |stat| DiscourseEvent.trigger(:scheduled_job_ran, stat) }
DiscourseEvent.trigger(:scheduled_job_ran, stat)
end
config.skip_schedule { Sidekiq.paused? } config.skip_schedule { Sidekiq.paused? }
config.before_sidekiq_web_request do config.before_sidekiq_web_request do
RailsMultisite::ConnectionManagement.establish_connection( RailsMultisite::ConnectionManagement.establish_connection(
db: RailsMultisite::ConnectionManagement::DEFAULT db: RailsMultisite::ConnectionManagement::DEFAULT,
) )
end end
end end

View File

@ -1,8 +1,8 @@
# frozen_string_literal: true # frozen_string_literal: true
class SilenceLogger < Rails::Rack::Logger class SilenceLogger < Rails::Rack::Logger
PATH_INFO = 'PATH_INFO' PATH_INFO = "PATH_INFO"
HTTP_X_SILENCE_LOGGER = 'HTTP_X_SILENCE_LOGGER' HTTP_X_SILENCE_LOGGER = "HTTP_X_SILENCE_LOGGER"
def initialize(app, opts = {}) def initialize(app, opts = {})
@app = app @app = app
@ -17,11 +17,9 @@ class SilenceLogger < Rails::Rack::Logger
path_info = env[PATH_INFO] path_info = env[PATH_INFO]
override = false override = false
if env[HTTP_X_SILENCE_LOGGER] || if env[HTTP_X_SILENCE_LOGGER] || @opts[:silenced].include?(path_info) ||
@opts[:silenced].include?(path_info) || path_info.start_with?("/logs") || path_info.start_with?("/user_avatar") ||
path_info.start_with?('/logs') || path_info.start_with?("/letter_avatar")
path_info.start_with?('/user_avatar') ||
path_info.start_with?('/letter_avatar')
if ::Logster::Logger === Rails.logger if ::Logster::Logger === Rails.logger
override = true override = true
Rails.logger.override_level = Logger::WARN Rails.logger.override_level = Logger::WARN
@ -35,10 +33,10 @@ class SilenceLogger < Rails::Rack::Logger
end end
end end
silenced = [ silenced = %w[
"/mini-profiler-resources/results", /mini-profiler-resources/results
"/mini-profiler-resources/includes.js", /mini-profiler-resources/includes.js
"/mini-profiler-resources/includes.css", /mini-profiler-resources/includes.css
"/mini-profiler-resources/jquery.tmpl.js" /mini-profiler-resources/jquery.tmpl.js
] ]
Rails.configuration.middleware.swap Rails::Rack::Logger, SilenceLogger, silenced: silenced Rails.configuration.middleware.swap Rails::Rack::Logger, SilenceLogger, silenced: silenced

View File

@ -3,8 +3,7 @@
# Check that the app is configured correctly. Raise some helpful errors if something is wrong. # Check that the app is configured correctly. Raise some helpful errors if something is wrong.
if defined?(Rails::Server) && Rails.env.production? # Only run these checks when starting up a production server if defined?(Rails::Server) && Rails.env.production? # Only run these checks when starting up a production server
if %w[localhost production.localhost].include?(Discourse.current_hostname)
if ['localhost', 'production.localhost'].include?(Discourse.current_hostname)
puts <<~TEXT puts <<~TEXT
Discourse.current_hostname = '#{Discourse.current_hostname}' Discourse.current_hostname = '#{Discourse.current_hostname}'
@ -18,7 +17,7 @@ if defined?(Rails::Server) && Rails.env.production? # Only run these checks when
raise "Invalid host_names in database.yml" raise "Invalid host_names in database.yml"
end end
if !Dir.glob(File.join(Rails.root, 'public', 'assets', 'application*.js')).present? if !Dir.glob(File.join(Rails.root, "public", "assets", "application*.js")).present?
puts <<~TEXT puts <<~TEXT
Assets have not been precompiled. Please run the following command Assets have not been precompiled. Please run the following command

View File

@ -6,11 +6,7 @@
# is enabled by default. # is enabled by default.
# Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array. # Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array.
ActiveSupport.on_load(:action_controller) do ActiveSupport.on_load(:action_controller) { wrap_parameters format: [:json] }
wrap_parameters format: [:json]
end
# Disable root element in JSON by default. # Disable root element in JSON by default.
ActiveSupport.on_load(:active_record) do ActiveSupport.on_load(:active_record) { self.include_root_in_json = false }
self.include_root_in_json = false
end

View File

@ -1,8 +1,9 @@
# frozen_string_literal: true # frozen_string_literal: true
Rails.application.config.to_prepare do Rails.application.config.to_prepare do
if (Rails.env.production? && SiteSetting.logging_provider == 'lograge') || (ENV["ENABLE_LOGRAGE"] == "1") if (Rails.env.production? && SiteSetting.logging_provider == "lograge") ||
require 'lograge' (ENV["ENABLE_LOGRAGE"] == "1")
require "lograge"
if Rails.configuration.multisite if Rails.configuration.multisite
Rails.logger.formatter = ActiveSupport::Logger::SimpleFormatter.new Rails.logger.formatter = ActiveSupport::Logger::SimpleFormatter.new
@ -11,20 +12,20 @@ Rails.application.config.to_prepare do
Rails.application.configure do Rails.application.configure do
config.lograge.enabled = true config.lograge.enabled = true
Lograge.ignore(lambda do |event| Lograge.ignore(
# this is our hijack magic status, lambda do |event|
# no point logging this cause we log again # this is our hijack magic status,
# direct from hijack # no point logging this cause we log again
event.payload[:status] == 418 # direct from hijack
end) event.payload[:status] == 418
end,
)
config.lograge.custom_payload do |controller| config.lograge.custom_payload do |controller|
begin begin
username = username =
begin begin
if controller.respond_to?(:current_user) controller.current_user&.username if controller.respond_to?(:current_user)
controller.current_user&.username
end
rescue Discourse::InvalidAccess, Discourse::ReadOnly, ActiveRecord::ReadOnlyError rescue Discourse::InvalidAccess, Discourse::ReadOnly, ActiveRecord::ReadOnlyError
nil nil
end end
@ -36,78 +37,77 @@ Rails.application.config.to_prepare do
nil nil
end end
{ { ip: ip, username: username }
ip: ip,
username: username
}
rescue => e rescue => e
Rails.logger.warn("Failed to append custom payload: #{e.message}\n#{e.backtrace.join("\n")}") Rails.logger.warn(
"Failed to append custom payload: #{e.message}\n#{e.backtrace.join("\n")}",
)
{} {}
end end
end end
config.lograge.custom_options = lambda do |event| config.lograge.custom_options =
begin lambda do |event|
exceptions = %w(controller action format id) begin
exceptions = %w[controller action format id]
params = event.payload[:params].except(*exceptions) params = event.payload[:params].except(*exceptions)
if (file = params[:file]) && file.respond_to?(:headers) if (file = params[:file]) && file.respond_to?(:headers)
params[:file] = file.headers params[:file] = file.headers
end
if (files = params[:files]) && files.respond_to?(:map)
params[:files] = files.map { |f| f.respond_to?(:headers) ? f.headers : f }
end
output = {
params: params.to_query,
database: RailsMultisite::ConnectionManagement.current_db,
}
if data = (Thread.current[:_method_profiler] || event.payload[:timings])
sql = data[:sql]
if sql
output[:db] = sql[:duration] * 1000
output[:db_calls] = sql[:calls]
end
redis = data[:redis]
if redis
output[:redis] = redis[:duration] * 1000
output[:redis_calls] = redis[:calls]
end
net = data[:net]
if net
output[:net] = net[:duration] * 1000
output[:net_calls] = net[:calls]
end
end
output
rescue RateLimiter::LimitExceeded
# no idea who this is, but they are limited
{}
rescue => e
Rails.logger.warn(
"Failed to append custom options: #{e.message}\n#{e.backtrace.join("\n")}",
)
{}
end end
if (files = params[:files]) && files.respond_to?(:map)
params[:files] = files.map do |f|
f.respond_to?(:headers) ? f.headers : f
end
end
output = {
params: params.to_query,
database: RailsMultisite::ConnectionManagement.current_db,
}
if data = (Thread.current[:_method_profiler] || event.payload[:timings])
sql = data[:sql]
if sql
output[:db] = sql[:duration] * 1000
output[:db_calls] = sql[:calls]
end
redis = data[:redis]
if redis
output[:redis] = redis[:duration] * 1000
output[:redis_calls] = redis[:calls]
end
net = data[:net]
if net
output[:net] = net[:duration] * 1000
output[:net_calls] = net[:calls]
end
end
output
rescue RateLimiter::LimitExceeded
# no idea who this is, but they are limited
{}
rescue => e
Rails.logger.warn("Failed to append custom options: #{e.message}\n#{e.backtrace.join("\n")}")
{}
end end
end
if ENV["LOGSTASH_URI"] if ENV["LOGSTASH_URI"]
config.lograge.formatter = Lograge::Formatters::Logstash.new config.lograge.formatter = Lograge::Formatters::Logstash.new
require 'discourse_logstash_logger' require "discourse_logstash_logger"
config.lograge.logger = DiscourseLogstashLogger.logger( config.lograge.logger =
uri: ENV['LOGSTASH_URI'], type: :rails DiscourseLogstashLogger.logger(uri: ENV["LOGSTASH_URI"], type: :rails)
)
# Remove ActiveSupport::Logger from the chain and replace with Lograge's # Remove ActiveSupport::Logger from the chain and replace with Lograge's
# logger # logger

View File

@ -11,13 +11,11 @@ Rails.configuration.middleware.unshift(MessageBus::Rack::Middleware)
# no reason to track this in development, that is 300+ redis calls saved per # no reason to track this in development, that is 300+ redis calls saved per
# page view (we serve all assets out of thin in development) # page view (we serve all assets out of thin in development)
if Rails.env != 'development' || ENV['TRACK_REQUESTS'] if Rails.env != "development" || ENV["TRACK_REQUESTS"]
require 'middleware/request_tracker' require "middleware/request_tracker"
Rails.configuration.middleware.unshift Middleware::RequestTracker Rails.configuration.middleware.unshift Middleware::RequestTracker
if GlobalSetting.enable_performance_http_headers MethodProfiler.ensure_discourse_instrumentation! if GlobalSetting.enable_performance_http_headers
MethodProfiler.ensure_discourse_instrumentation!
end
end end
if Rails.env.test? if Rails.env.test?
@ -30,23 +28,27 @@ if Rails.env.test?
super(env) super(env)
end end
end end
Rails.configuration.middleware.unshift TestMultisiteMiddleware, RailsMultisite::DiscoursePatches.config Rails.configuration.middleware.unshift TestMultisiteMiddleware,
RailsMultisite::DiscoursePatches.config
elsif Rails.configuration.multisite elsif Rails.configuration.multisite
assets_hostnames = GlobalSetting.cdn_hostnames assets_hostnames = GlobalSetting.cdn_hostnames
if assets_hostnames.empty? if assets_hostnames.empty?
assets_hostnames = assets_hostnames = Discourse::Application.config.database_configuration[Rails.env]["host_names"]
Discourse::Application.config.database_configuration[Rails.env]["host_names"]
end end
RailsMultisite::ConnectionManagement.asset_hostnames = assets_hostnames RailsMultisite::ConnectionManagement.asset_hostnames = assets_hostnames
# Multisite needs to be first, because the request tracker and message bus rely on it # Multisite needs to be first, because the request tracker and message bus rely on it
Rails.configuration.middleware.unshift RailsMultisite::Middleware, RailsMultisite::DiscoursePatches.config Rails.configuration.middleware.unshift RailsMultisite::Middleware,
RailsMultisite::DiscoursePatches.config
Rails.configuration.middleware.delete ActionDispatch::Executor Rails.configuration.middleware.delete ActionDispatch::Executor
if defined?(RailsFailover::ActiveRecord) && Rails.configuration.active_record_rails_failover if defined?(RailsFailover::ActiveRecord) && Rails.configuration.active_record_rails_failover
Rails.configuration.middleware.insert_after(RailsMultisite::Middleware, RailsFailover::ActiveRecord::Middleware) Rails.configuration.middleware.insert_after(
RailsMultisite::Middleware,
RailsFailover::ActiveRecord::Middleware,
)
end end
if Rails.env.development? if Rails.env.development?
@ -57,5 +59,8 @@ elsif Rails.configuration.multisite
end end
end end
elsif defined?(RailsFailover::ActiveRecord) && Rails.configuration.active_record_rails_failover elsif defined?(RailsFailover::ActiveRecord) && Rails.configuration.active_record_rails_failover
Rails.configuration.middleware.insert_before(MessageBus::Rack::Middleware, RailsFailover::ActiveRecord::Middleware) Rails.configuration.middleware.insert_before(
MessageBus::Rack::Middleware,
RailsFailover::ActiveRecord::Middleware,
)
end end

View File

@ -2,18 +2,32 @@
if !GlobalSetting.skip_redis? if !GlobalSetting.skip_redis?
if GlobalSetting.respond_to?(:redis_slave_host) && GlobalSetting.redis_slave_host.present? if GlobalSetting.respond_to?(:redis_slave_host) && GlobalSetting.redis_slave_host.present?
Discourse.deprecate("redis_slave_host is deprecated, use redis_replica_host instead", drop_from: "2.8") Discourse.deprecate(
"redis_slave_host is deprecated, use redis_replica_host instead",
drop_from: "2.8",
)
end end
if GlobalSetting.respond_to?(:redis_slave_port) && GlobalSetting.redis_slave_port.present? if GlobalSetting.respond_to?(:redis_slave_port) && GlobalSetting.redis_slave_port.present?
Discourse.deprecate("redis_slave_port is deprecated, use redis_replica_port instead", drop_from: "2.8") Discourse.deprecate(
"redis_slave_port is deprecated, use redis_replica_port instead",
drop_from: "2.8",
)
end end
if GlobalSetting.respond_to?(:message_bus_redis_slave_host) && GlobalSetting.message_bus_redis_slave_host.present? if GlobalSetting.respond_to?(:message_bus_redis_slave_host) &&
Discourse.deprecate("message_bus_redis_slave_host is deprecated, use message_bus_redis_replica_host", drop_from: "2.8") GlobalSetting.message_bus_redis_slave_host.present?
Discourse.deprecate(
"message_bus_redis_slave_host is deprecated, use message_bus_redis_replica_host",
drop_from: "2.8",
)
end end
if GlobalSetting.respond_to?(:message_bus_redis_slave_port) && GlobalSetting.message_bus_redis_slave_port.present? if GlobalSetting.respond_to?(:message_bus_redis_slave_port) &&
Discourse.deprecate("message_bus_redis_slave_port is deprecated, use message_bus_redis_replica_port", drop_from: "2.8") GlobalSetting.message_bus_redis_slave_port.present?
Discourse.deprecate(
"message_bus_redis_slave_port is deprecated, use message_bus_redis_replica_port",
drop_from: "2.8",
)
end end
end end

View File

@ -17,11 +17,13 @@ Rails.application.config.assets.paths << "#{Rails.root}/public/javascripts"
# folder are already added. # folder are already added.
# explicitly precompile any images in plugins ( /assets/images ) path # explicitly precompile any images in plugins ( /assets/images ) path
Rails.application.config.assets.precompile += [lambda do |filename, path| Rails.application.config.assets.precompile += [
path =~ /assets\/images/ && !%w(.js .css).include?(File.extname(filename)) lambda do |filename, path|
end] path =~ %r{assets/images} && !%w[.js .css].include?(File.extname(filename))
end,
]
Rails.application.config.assets.precompile += %w{ Rails.application.config.assets.precompile += %w[
discourse.js discourse.js
vendor.js vendor.js
admin.js admin.js
@ -49,15 +51,21 @@ Rails.application.config.assets.precompile += %w{
embed-application.js embed-application.js
scripts/discourse-test-listen-boot scripts/discourse-test-listen-boot
scripts/discourse-boot scripts/discourse-boot
} ]
Rails.application.config.assets.precompile += EmberCli.assets.map { |name| name.sub('.js', '.map') } Rails.application.config.assets.precompile += EmberCli.assets.map { |name| name.sub(".js", ".map") }
# Precompile all available locales # Precompile all available locales
unless GlobalSetting.try(:omit_base_locales) unless GlobalSetting.try(:omit_base_locales)
Dir.glob("#{Rails.root}/app/assets/javascripts/locales/*.js.erb").each do |file| Dir
Rails.application.config.assets.precompile << "locales/#{file.match(/([a-z_A-Z]+\.js)\.erb$/)[1]}" .glob("#{Rails.root}/app/assets/javascripts/locales/*.js.erb")
end .each do |file|
Rails
.application
.config
.assets
.precompile << "locales/#{file.match(/([a-z_A-Z]+\.js)\.erb$/)[1]}"
end
end end
# out of the box sprockets 3 grabs loose files that are hanging in assets, # out of the box sprockets 3 grabs loose files that are hanging in assets,
@ -65,18 +73,16 @@ end
Rails.application.config.assets.precompile.delete(Sprockets::Railtie::LOOSE_APP_ASSETS) Rails.application.config.assets.precompile.delete(Sprockets::Railtie::LOOSE_APP_ASSETS)
# We don't want application from node_modules, only from the root # We don't want application from node_modules, only from the root
Rails.application.config.assets.precompile.delete(/(?:\/|\\|\A)application\.(css|js)$/) Rails.application.config.assets.precompile.delete(%r{(?:/|\\|\A)application\.(css|js)$})
Rails.application.config.assets.precompile += ['application.js'] Rails.application.config.assets.precompile += ["application.js"]
start_path = ::Rails.root.join("app/assets").to_s start_path = ::Rails.root.join("app/assets").to_s
exclude = ['.es6', '.hbs', '.hbr', '.js', '.css', '.lock', '.json', '.log', '.html', ''] exclude = [".es6", ".hbs", ".hbr", ".js", ".css", ".lock", ".json", ".log", ".html", ""]
Rails.application.config.assets.precompile << lambda do |logical_path, filename| Rails.application.config.assets.precompile << lambda do |logical_path, filename|
filename.start_with?(start_path) && filename.start_with?(start_path) && !filename.include?("/node_modules/") &&
!filename.include?("/node_modules/") && !filename.include?("/dist/") && !exclude.include?(File.extname(logical_path))
!filename.include?("/dist/") &&
!exclude.include?(File.extname(logical_path))
end end
Discourse.find_plugin_js_assets(include_disabled: true).each do |file| Discourse
Rails.application.config.assets.precompile << "#{file}.js" .find_plugin_js_assets(include_disabled: true)
end .each { |file| Rails.application.config.assets.precompile << "#{file}.js" }

View File

@ -3,13 +3,13 @@
# Be sure to restart your server when you modify this file. # Be sure to restart your server when you modify this file.
# Configure sensitive parameters which will be filtered from the log file. # Configure sensitive parameters which will be filtered from the log file.
Rails.application.config.filter_parameters += [ Rails.application.config.filter_parameters += %i[
:password, password
:pop3_polling_password, pop3_polling_password
:api_key, api_key
:s3_secret_access_key, s3_secret_access_key
:twitter_consumer_secret, twitter_consumer_secret
:facebook_app_secret, facebook_app_secret
:github_client_secret, github_client_secret
:second_factor_token, second_factor_token
] ]

View File

@ -102,5 +102,5 @@ Rails.application.config.action_dispatch.default_headers = {
"X-Content-Type-Options" => "nosniff", "X-Content-Type-Options" => "nosniff",
"X-Download-Options" => "noopen", "X-Download-Options" => "noopen",
"X-Permitted-Cross-Domain-Policies" => "none", "X-Permitted-Cross-Domain-Policies" => "none",
"Referrer-Policy" => "strict-origin-when-cross-origin" "Referrer-Policy" => "strict-origin-when-cross-origin",
} }

View File

@ -3,6 +3,7 @@
# source: https://github.com/svenfuchs/i18n/blob/master/test/test_data/locales/plurals.rb # source: https://github.com/svenfuchs/i18n/blob/master/test/test_data/locales/plurals.rb
# stree-ignore
{ {
af: { i18n: { plural: { keys: [:one, :other], rule: lambda { |n| n == 1 ? :one : :other } } } }, af: { i18n: { plural: { keys: [:one, :other], rule: lambda { |n| n == 1 ? :one : :other } } } },
am: { i18n: { plural: { keys: [:one, :other], rule: lambda { |n| [0, 1].include?(n) ? :one : :other } } } }, am: { i18n: { plural: { keys: [:one, :other], rule: lambda { |n| [0, 1].include?(n) ? :one : :other } } } },

View File

@ -1,9 +1,8 @@
# frozen_string_literal: true # frozen_string_literal: true
if ENV['RAILS_ENV'] == 'production' if ENV["RAILS_ENV"] == "production"
# First, you need to change these below to your situation. # First, you need to change these below to your situation.
APP_ROOT = ENV["APP_ROOT"] || '/home/discourse/discourse' APP_ROOT = ENV["APP_ROOT"] || "/home/discourse/discourse"
num_workers = ENV["NUM_WEBS"].to_i > 0 ? ENV["NUM_WEBS"].to_i : 4 num_workers = ENV["NUM_WEBS"].to_i > 0 ? ENV["NUM_WEBS"].to_i : 4
# Second, you can choose how many threads that you are going to run at same time. # Second, you can choose how many threads that you are going to run at same time.
@ -16,5 +15,4 @@ if ENV['RAILS_ENV'] == 'production'
pidfile "#{APP_ROOT}/tmp/pids/puma.pid" pidfile "#{APP_ROOT}/tmp/pids/puma.pid"
state_path "#{APP_ROOT}/tmp/pids/puma.state" state_path "#{APP_ROOT}/tmp/pids/puma.state"
preload_app! preload_app!
end end

File diff suppressed because it is too large Load Diff

View File

@ -7,7 +7,5 @@
# spring binstub rails # spring binstub rails
# spring binstub rake # spring binstub rake
# spring binstub rspec # spring binstub rspec
Spring.after_fork do Spring.after_fork { Discourse.after_fork }
Discourse.after_fork
end
Spring::Commands::Rake.environment_matchers["spec"] = "test" Spring::Commands::Rake.environment_matchers["spec"] = "test"

View File

@ -3,9 +3,9 @@
# See http://unicorn.bogomips.org/Unicorn/Configurator.html # See http://unicorn.bogomips.org/Unicorn/Configurator.html
if (ENV["LOGSTASH_UNICORN_URI"] || "").length > 0 if (ENV["LOGSTASH_UNICORN_URI"] || "").length > 0
require_relative '../lib/discourse_logstash_logger' require_relative "../lib/discourse_logstash_logger"
require_relative '../lib/unicorn_logstash_patch' require_relative "../lib/unicorn_logstash_patch"
logger DiscourseLogstashLogger.logger(uri: ENV['LOGSTASH_UNICORN_URI'], type: :unicorn) logger DiscourseLogstashLogger.logger(uri: ENV["LOGSTASH_UNICORN_URI"], type: :unicorn)
end end
discourse_path = File.expand_path(File.expand_path(File.dirname(__FILE__)) + "/../") discourse_path = File.expand_path(File.expand_path(File.dirname(__FILE__)) + "/../")
@ -16,11 +16,10 @@ worker_processes (ENV["UNICORN_WORKERS"] || 3).to_i
working_directory discourse_path working_directory discourse_path
# listen "#{discourse_path}/tmp/sockets/unicorn.sock" # listen "#{discourse_path}/tmp/sockets/unicorn.sock"
listen ENV["UNICORN_LISTENER"] || "#{(ENV["UNICORN_BIND_ALL"] ? "" : "127.0.0.1:")}#{(ENV["UNICORN_PORT"] || 3000).to_i}" listen ENV["UNICORN_LISTENER"] ||
"#{(ENV["UNICORN_BIND_ALL"] ? "" : "127.0.0.1:")}#{(ENV["UNICORN_PORT"] || 3000).to_i}"
if !File.exist?("#{discourse_path}/tmp/pids") FileUtils.mkdir_p("#{discourse_path}/tmp/pids") if !File.exist?("#{discourse_path}/tmp/pids")
FileUtils.mkdir_p("#{discourse_path}/tmp/pids")
end
# feel free to point this anywhere accessible on the filesystem # feel free to point this anywhere accessible on the filesystem
pid (ENV["UNICORN_PID_PATH"] || "#{discourse_path}/tmp/pids/unicorn.pid") pid (ENV["UNICORN_PID_PATH"] || "#{discourse_path}/tmp/pids/unicorn.pid")
@ -52,7 +51,6 @@ check_client_connection false
initialized = false initialized = false
before_fork do |server, worker| before_fork do |server, worker|
unless initialized unless initialized
Discourse.preload_rails! Discourse.preload_rails!
@ -67,7 +65,7 @@ before_fork do |server, worker|
initialized = true initialized = true
supervisor = ENV['UNICORN_SUPERVISOR_PID'].to_i supervisor = ENV["UNICORN_SUPERVISOR_PID"].to_i
if supervisor > 0 if supervisor > 0
Thread.new do Thread.new do
while true while true
@ -80,14 +78,12 @@ before_fork do |server, worker|
end end
end end
sidekiqs = ENV['UNICORN_SIDEKIQS'].to_i sidekiqs = ENV["UNICORN_SIDEKIQS"].to_i
if sidekiqs > 0 if sidekiqs > 0
server.logger.info "starting #{sidekiqs} supervised sidekiqs" server.logger.info "starting #{sidekiqs} supervised sidekiqs"
require 'demon/sidekiq' require "demon/sidekiq"
Demon::Sidekiq.after_fork do Demon::Sidekiq.after_fork { DiscourseEvent.trigger(:sidekiq_fork_started) }
DiscourseEvent.trigger(:sidekiq_fork_started)
end
Demon::Sidekiq.start(sidekiqs) Demon::Sidekiq.start(sidekiqs)
@ -98,13 +94,14 @@ before_fork do |server, worker|
# Trap USR1, so we can re-issue to sidekiq workers # Trap USR1, so we can re-issue to sidekiq workers
# but chain the default unicorn implementation as well # but chain the default unicorn implementation as well
old_handler = Signal.trap("USR1") do old_handler =
Demon::Sidekiq.kill("USR1") Signal.trap("USR1") do
old_handler.call Demon::Sidekiq.kill("USR1")
end old_handler.call
end
end end
if ENV['DISCOURSE_ENABLE_EMAIL_SYNC_DEMON'] == 'true' if ENV["DISCOURSE_ENABLE_EMAIL_SYNC_DEMON"] == "true"
server.logger.info "starting up EmailSync demon" server.logger.info "starting up EmailSync demon"
Demon::EmailSync.start Demon::EmailSync.start
Signal.trap("SIGTSTP") do Signal.trap("SIGTSTP") do
@ -119,13 +116,13 @@ before_fork do |server, worker|
end end
class ::Unicorn::HttpServer class ::Unicorn::HttpServer
alias :master_sleep_orig :master_sleep alias master_sleep_orig master_sleep
def max_sidekiq_rss def max_sidekiq_rss
rss = `ps -eo rss,args | grep sidekiq | grep -v grep | awk '{print $1}'` rss =
.split("\n") `ps -eo rss,args | grep sidekiq | grep -v grep | awk '{print $1}'`.split("\n")
.map(&:to_i) .map(&:to_i)
.max .max
rss ||= 0 rss ||= 0
@ -133,18 +130,24 @@ before_fork do |server, worker|
end end
def max_allowed_sidekiq_rss def max_allowed_sidekiq_rss
[ENV['UNICORN_SIDEKIQ_MAX_RSS'].to_i, 500].max.megabytes [ENV["UNICORN_SIDEKIQ_MAX_RSS"].to_i, 500].max.megabytes
end end
def force_kill_rogue_sidekiq def force_kill_rogue_sidekiq
info = `ps -eo pid,rss,args | grep sidekiq | grep -v grep | awk '{print $1,$2}'` info = `ps -eo pid,rss,args | grep sidekiq | grep -v grep | awk '{print $1,$2}'`
info.split("\n").each do |row| info
pid, mem = row.split(" ").map(&:to_i) .split("\n")
if pid > 0 && (mem * 1024) > max_allowed_sidekiq_rss .each do |row|
Rails.logger.warn "Detected rogue Sidekiq pid #{pid} mem #{mem * 1024}, killing" pid, mem = row.split(" ").map(&:to_i)
Process.kill("KILL", pid) rescue nil if pid > 0 && (mem * 1024) > max_allowed_sidekiq_rss
Rails.logger.warn "Detected rogue Sidekiq pid #{pid} mem #{mem * 1024}, killing"
begin
Process.kill("KILL", pid)
rescue StandardError
nil
end
end
end end
end
end end
def check_sidekiq_heartbeat def check_sidekiq_heartbeat
@ -152,13 +155,15 @@ before_fork do |server, worker|
@sidekiq_next_heartbeat_check ||= Time.now.to_i + @sidekiq_heartbeat_interval @sidekiq_next_heartbeat_check ||= Time.now.to_i + @sidekiq_heartbeat_interval
if @sidekiq_next_heartbeat_check < Time.now.to_i if @sidekiq_next_heartbeat_check < Time.now.to_i
last_heartbeat = Jobs::RunHeartbeat.last_heartbeat last_heartbeat = Jobs::RunHeartbeat.last_heartbeat
restart = false restart = false
sidekiq_rss = max_sidekiq_rss sidekiq_rss = max_sidekiq_rss
if sidekiq_rss > max_allowed_sidekiq_rss if sidekiq_rss > max_allowed_sidekiq_rss
Rails.logger.warn("Sidekiq is consuming too much memory (using: %0.2fM) for '%s', restarting" % [(sidekiq_rss.to_f / 1.megabyte), ENV["DISCOURSE_HOSTNAME"]]) Rails.logger.warn(
"Sidekiq is consuming too much memory (using: %0.2fM) for '%s', restarting" %
[(sidekiq_rss.to_f / 1.megabyte), ENV["DISCOURSE_HOSTNAME"]],
)
restart = true restart = true
end end
@ -185,16 +190,18 @@ before_fork do |server, worker|
email_sync_pids = Demon::EmailSync.demons.map { |uid, demon| demon.pid } email_sync_pids = Demon::EmailSync.demons.map { |uid, demon| demon.pid }
return 0 if email_sync_pids.empty? return 0 if email_sync_pids.empty?
rss = `ps -eo pid,rss,args | grep '#{email_sync_pids.join('|')}' | grep -v grep | awk '{print $2}'` rss =
.split("\n") `ps -eo pid,rss,args | grep '#{email_sync_pids.join("|")}' | grep -v grep | awk '{print $2}'`.split(
.map(&:to_i) "\n",
.max )
.map(&:to_i)
.max
(rss || 0) * 1024 (rss || 0) * 1024
end end
def max_allowed_email_sync_rss def max_allowed_email_sync_rss
[ENV['UNICORN_EMAIL_SYNC_MAX_RSS'].to_i, 500].max.megabytes [ENV["UNICORN_EMAIL_SYNC_MAX_RSS"].to_i, 500].max.megabytes
end end
def check_email_sync_heartbeat def check_email_sync_heartbeat
@ -207,16 +214,22 @@ before_fork do |server, worker|
restart = false restart = false
# Restart process if it does not respond anymore # Restart process if it does not respond anymore
last_heartbeat_ago = Time.now.to_i - Discourse.redis.get(Demon::EmailSync::HEARTBEAT_KEY).to_i last_heartbeat_ago =
Time.now.to_i - Discourse.redis.get(Demon::EmailSync::HEARTBEAT_KEY).to_i
if last_heartbeat_ago > Demon::EmailSync::HEARTBEAT_INTERVAL.to_i if last_heartbeat_ago > Demon::EmailSync::HEARTBEAT_INTERVAL.to_i
STDERR.puts("EmailSync heartbeat test failed (last heartbeat was #{last_heartbeat_ago}s ago), restarting") STDERR.puts(
"EmailSync heartbeat test failed (last heartbeat was #{last_heartbeat_ago}s ago), restarting",
)
restart = true restart = true
end end
# Restart process if memory usage is too high # Restart process if memory usage is too high
email_sync_rss = max_email_sync_rss email_sync_rss = max_email_sync_rss
if email_sync_rss > max_allowed_email_sync_rss if email_sync_rss > max_allowed_email_sync_rss
STDERR.puts("EmailSync is consuming too much memory (using: %0.2fM) for '%s', restarting" % [(email_sync_rss.to_f / 1.megabyte), ENV["DISCOURSE_HOSTNAME"]]) STDERR.puts(
"EmailSync is consuming too much memory (using: %0.2fM) for '%s', restarting" %
[(email_sync_rss.to_f / 1.megabyte), ENV["DISCOURSE_HOSTNAME"]],
)
restart = true restart = true
end end
@ -224,25 +237,22 @@ before_fork do |server, worker|
end end
def master_sleep(sec) def master_sleep(sec)
sidekiqs = ENV['UNICORN_SIDEKIQS'].to_i sidekiqs = ENV["UNICORN_SIDEKIQS"].to_i
if sidekiqs > 0 if sidekiqs > 0
Demon::Sidekiq.ensure_running Demon::Sidekiq.ensure_running
check_sidekiq_heartbeat check_sidekiq_heartbeat
end end
if ENV['DISCOURSE_ENABLE_EMAIL_SYNC_DEMON'] == 'true' if ENV["DISCOURSE_ENABLE_EMAIL_SYNC_DEMON"] == "true"
Demon::EmailSync.ensure_running Demon::EmailSync.ensure_running
check_email_sync_heartbeat check_email_sync_heartbeat
end end
DiscoursePluginRegistry.demon_processes.each do |demon_class| DiscoursePluginRegistry.demon_processes.each { |demon_class| demon_class.ensure_running }
demon_class.ensure_running
end
master_sleep_orig(sec) master_sleep_orig(sec)
end end
end end
end end
Discourse.redis.close Discourse.redis.close