DEV: Upgrade to Rails 7

This patch upgrades Rails to version 7.0.2.4.
This commit is contained in:
Loïc Guitaut 2022-03-21 15:28:52 +01:00 committed by Loïc Guitaut
parent 532f9cdb1a
commit 008b700a3f
99 changed files with 724 additions and 691 deletions

View File

@ -13,6 +13,7 @@ allowed:
ignored:
bundler:
- rchardet # Ruby terms
- strscan # Ruby
reviewed:
bundler:
@ -31,10 +32,16 @@ reviewed:
- highline # GPL-2.0 OR Ruby terms
- htmlentities # MIT
- image_size # MIT
- io-wait # Ruby terms
- json # Ruby terms
- jwt # MIT
- kgio # LGPL-2.1+
- logstash-event # Apache-2.0
- net-http # Ruby
- net-imap # Ruby
- net-pop # Ruby
- net-protocol # Ruby
- net-smtp # Ruby
- omniauth # MIT
- openssl # Ruby terms
- pg # Ruby terms
@ -44,5 +51,7 @@ reviewed:
- rubyzip # Ruby terms
- sidekiq # LGPL (Sidekiq)
- tilt
- timeout # Ruby
- unf # BSD-2-Clause
- unicorn
- uri # Ruby

10
Gemfile
View File

@ -18,7 +18,7 @@ else
# this allows us to include the bits of rails we use without pieces we do not.
#
# To issue a rails update bump the version number here
rails_version = '6.1.4.7'
rails_version = '7.0.2.4'
gem 'actionmailer', rails_version
gem 'actionpack', rails_version
gem 'actionview', rails_version
@ -68,7 +68,7 @@ gem 'http_accept_language', require: false
gem 'discourse-ember-rails', '0.18.6', require: 'ember-rails'
gem 'discourse-ember-source', '~> 3.12.2'
gem 'ember-handlebars-template', '0.8.0'
gem 'discourse-fonts'
gem 'discourse-fonts', require: 'discourse_fonts'
gem 'barber'
@ -190,7 +190,7 @@ if ENV["ALLOW_DEV_POPULATE"] == "1"
gem 'discourse_dev_assets'
gem 'faker', "~> 2.16"
else
group :development do
group :development, :test do
gem 'discourse_dev_assets'
gem 'faker', "~> 2.16"
end
@ -268,3 +268,7 @@ gem 'colored2', require: false
gem 'maxminddb'
gem 'rails_failover', require: false
# workaround for faraday-net_http, see
# https://github.com/ruby/net-imap/issues/16#issuecomment-803086765
gem 'net-http'

View File

@ -8,22 +8,25 @@ GIT
GEM
remote: https://rubygems.org/
specs:
actionmailer (6.1.4.7)
actionpack (= 6.1.4.7)
actionview (= 6.1.4.7)
activejob (= 6.1.4.7)
activesupport (= 6.1.4.7)
actionmailer (7.0.2.4)
actionpack (= 7.0.2.4)
actionview (= 7.0.2.4)
activejob (= 7.0.2.4)
activesupport (= 7.0.2.4)
mail (~> 2.5, >= 2.5.4)
net-imap
net-pop
net-smtp
rails-dom-testing (~> 2.0)
actionpack (6.1.4.7)
actionview (= 6.1.4.7)
activesupport (= 6.1.4.7)
rack (~> 2.0, >= 2.0.9)
actionpack (7.0.2.4)
actionview (= 7.0.2.4)
activesupport (= 7.0.2.4)
rack (~> 2.0, >= 2.2.0)
rack-test (>= 0.6.3)
rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.0, >= 1.2.0)
actionview (6.1.4.7)
activesupport (= 6.1.4.7)
actionview (7.0.2.4)
activesupport (= 7.0.2.4)
builder (~> 3.1)
erubi (~> 1.4)
rails-dom-testing (~> 2.0)
@ -32,20 +35,19 @@ GEM
actionview (>= 6.0.a)
active_model_serializers (0.8.4)
activemodel (>= 3.0)
activejob (6.1.4.7)
activesupport (= 6.1.4.7)
activejob (7.0.2.4)
activesupport (= 7.0.2.4)
globalid (>= 0.3.6)
activemodel (6.1.4.7)
activesupport (= 6.1.4.7)
activerecord (6.1.4.7)
activemodel (= 6.1.4.7)
activesupport (= 6.1.4.7)
activesupport (6.1.4.7)
activemodel (7.0.2.4)
activesupport (= 7.0.2.4)
activerecord (7.0.2.4)
activemodel (= 7.0.2.4)
activesupport (= 7.0.2.4)
activesupport (7.0.2.4)
concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (>= 1.6, < 2)
minitest (>= 5.1)
tzinfo (~> 2.0)
zeitwerk (~> 2.3)
addressable (2.8.0)
public_suffix (>= 2.0.2, < 5.0)
annotate (3.2.0)
@ -106,6 +108,7 @@ GEM
debug_inspector (1.1.0)
diff-lcs (1.5.0)
diffy (3.4.0)
digest (3.1.0)
discourse-ember-rails (0.18.6)
active_model_serializers
ember-data-source (>= 1.0.0.beta.5)
@ -185,6 +188,7 @@ GEM
progress (~> 3.0, >= 3.0.1)
image_size (3.0.1)
in_threads (1.6.0)
io-wait (0.2.1)
ipaddr (1.2.4)
jmespath (1.6.1)
jquery-rails (4.4.0)
@ -246,6 +250,24 @@ GEM
multi_xml (0.6.0)
multipart-post (2.1.1)
mustache (1.1.1)
net-http (0.2.0)
net-protocol
uri
net-imap (0.2.3)
digest
net-protocol
strscan
net-pop (0.1.1)
digest
net-protocol
timeout
net-protocol (0.1.2)
io-wait
timeout
net-smtp (0.3.1)
digest
net-protocol
timeout
nio4r (2.5.8)
nokogiri (1.13.4)
mini_portile2 (~> 2.8.0)
@ -332,12 +354,13 @@ GEM
rails_multisite (4.0.1)
activerecord (> 5.0, < 7.1)
railties (> 5.0, < 7.1)
railties (6.1.4.7)
actionpack (= 6.1.4.7)
activesupport (= 6.1.4.7)
railties (7.0.2.4)
actionpack (= 7.0.2.4)
activesupport (= 7.0.2.4)
method_source
rake (>= 0.13)
rake (>= 12.2)
thor (~> 1.0)
zeitwerk (~> 2.5)
rainbow (3.1.1)
raindrops (0.20.0)
rake (13.0.6)
@ -452,9 +475,11 @@ GEM
sprockets (>= 3.0.0)
sshkey (2.0.0)
stackprof (0.2.19)
strscan (3.0.1)
test-prof (1.0.8)
thor (1.2.1)
tilt (2.0.10)
timeout (0.2.0)
tzinfo (2.0.4)
concurrent-ruby (~> 1.0)
uglifier (4.2.0)
@ -467,6 +492,7 @@ GEM
kgio (~> 2.6)
raindrops (~> 0.7)
uniform_notifier (1.16.0)
uri (0.11.0)
uri_template (0.7.0)
webmock (3.14.0)
addressable (>= 2.8.0)
@ -489,14 +515,14 @@ PLATFORMS
x86_64-linux
DEPENDENCIES
actionmailer (= 6.1.4.7)
actionpack (= 6.1.4.7)
actionview (= 6.1.4.7)
actionmailer (= 7.0.2.4)
actionpack (= 7.0.2.4)
actionview (= 7.0.2.4)
actionview_precompiler
active_model_serializers (~> 0.8.3)
activemodel (= 6.1.4.7)
activerecord (= 6.1.4.7)
activesupport (= 6.1.4.7)
activemodel (= 7.0.2.4)
activerecord (= 7.0.2.4)
activesupport (= 7.0.2.4)
addressable
annotate
aws-sdk-s3
@ -556,6 +582,7 @@ DEPENDENCIES
mocha
multi_json
mustache
net-http
nokogiri
oj
omniauth
@ -575,7 +602,7 @@ DEPENDENCIES
rack-protection
rails_failover
rails_multisite
railties (= 6.1.4.7)
railties (= 7.0.2.4)
rake
rb-fsevent
rbtrace

View File

@ -68,7 +68,7 @@ class ApplicationController < ActionController::Base
def use_crawler_layout?
@use_crawler_layout ||=
request.user_agent &&
(request.content_type.blank? || request.content_type.include?('html')) &&
(request.media_type.blank? || request.media_type.include?('html')) &&
!['json', 'rss'].include?(params[:format]) &&
(has_escaped_fragment? || params.key?("print") || show_browser_update? ||
CrawlerDetection.crawler?(request.user_agent, request.headers["HTTP_VIA"])
@ -287,7 +287,7 @@ class ApplicationController < ActionController::Base
# cause category / topic was deleted
if permalink.present? && permalink.target_url
# permalink present, redirect to that URL
redirect_with_client_support permalink.target_url, status: :moved_permanently
redirect_with_client_support permalink.target_url, status: :moved_permanently, allow_other_host: true
return
end
end
@ -834,7 +834,7 @@ class ApplicationController < ActionController::Base
end
if UserApiKey.allowed_scopes.superset?(Set.new(["one_time_password"]))
redirect_to("#{params[:auth_redirect]}?otp=true")
redirect_to("#{params[:auth_redirect]}?otp=true", allow_other_host: true)
return
end
end

View File

@ -1,6 +1,9 @@
# frozen_string_literal: true
class PostsController < ApplicationController
# Bug with Rails 7+
# see https://github.com/rails/rails/issues/44867
self._flash_types -= [:notice]
requires_login except: [
:show,

View File

@ -33,7 +33,7 @@ class SessionController < ApplicationController
if SiteSetting.verbose_discourse_connect_logging
Rails.logger.warn("Verbose SSO log: Started SSO process\n\n#{sso.diagnostics}")
end
redirect_to sso_url(sso)
redirect_to sso_url(sso), allow_other_host: true
else
render body: nil, status: 404
end
@ -69,14 +69,14 @@ class SessionController < ApplicationController
# for the login modal
cookies[:sso_destination_url] = data[:sso_redirect_url]
else
redirect_to data[:sso_redirect_url]
redirect_to data[:sso_redirect_url], allow_other_host: true
end
elsif result.no_second_factors_enabled?
if request.xhr?
# for the login modal
cookies[:sso_destination_url] = result.data[:sso_redirect_url]
else
redirect_to result.data[:sso_redirect_url]
redirect_to result.data[:sso_redirect_url], allow_other_host: true
end
elsif result.second_factor_auth_completed?
redirect_url = result.data[:sso_redirect_url]
@ -169,7 +169,7 @@ class SessionController < ApplicationController
# they are already pre-approved because they have been invited
if SiteSetting.must_approve_users? && !user.approved? && invite.blank?
if SiteSetting.discourse_connect_not_approved_url.present?
redirect_to SiteSetting.discourse_connect_not_approved_url
redirect_to SiteSetting.discourse_connect_not_approved_url, allow_other_host: true
else
render_sso_error(text: I18n.t("discourse_connect.account_not_approved"), status: 403)
end
@ -220,7 +220,7 @@ class SessionController < ApplicationController
return_path = path("/")
end
redirect_to return_path
redirect_to return_path, allow_other_host: true
else
render_sso_error(text: I18n.t("discourse_connect.not_found"), status: 500)
end
@ -583,7 +583,7 @@ class SessionController < ApplicationController
redirect_url: redirect_url
}
else
redirect_to redirect_url
redirect_to redirect_url, allow_other_host: true
end
end

View File

@ -30,7 +30,7 @@ class StaticController < ApplicationController
if map.has_key?(@page)
site_setting_key = map[@page][:redirect]
url = SiteSetting.get(site_setting_key) if site_setting_key
return redirect_to(url) if url.present?
return redirect_to(url, allow_other_host: true) if url.present?
end
# The /guidelines route ALWAYS shows our FAQ, ignoring the faq_url site setting.

View File

@ -15,7 +15,7 @@ class SvgSpriteController < ApplicationController
theme_id = params[:theme_id].to_i if params[:theme_id].present?
if SvgSprite.version(theme_id) != params[:version]
return redirect_to UrlHelper.absolute((SvgSprite.path(theme_id)))
return redirect_to UrlHelper.absolute((SvgSprite.path(theme_id))), allow_other_host: true
end
svg_sprite = "window.__svg_sprite = #{SvgSprite.bundle(theme_id).inspect};"

View File

@ -118,7 +118,7 @@ class UploadsController < ApplicationController
if Discourse.store.internal?
send_file_local_upload(upload)
else
redirect_to Discourse.store.url_for(upload, force_download: force_download?)
redirect_to Discourse.store.url_for(upload, force_download: force_download?), allow_other_host: true
end
else
render_404
@ -149,7 +149,7 @@ class UploadsController < ApplicationController
# private, so we don't want to go to the CDN url just yet otherwise we
# will get a 403. if the upload is not secure we assume the ACL is public
signed_secure_url = Discourse.store.signed_url_for_path(path_with_ext)
redirect_to upload.secure? ? signed_secure_url : Discourse.store.cdn_url(upload.url)
redirect_to upload.secure? ? signed_secure_url : Discourse.store.cdn_url(upload.url), allow_other_host: true
end
def handle_secure_upload_request(upload, path_with_ext = nil)
@ -166,14 +166,14 @@ class UploadsController < ApplicationController
# url_for figures out the full URL, handling multisite DBs,
# and will return a presigned URL for the upload
if path_with_ext.blank?
return redirect_to Discourse.store.url_for(upload, force_download: force_download?)
return redirect_to Discourse.store.url_for(upload, force_download: force_download?), allow_other_host: true
end
redirect_to Discourse.store.signed_url_for_path(
path_with_ext,
expires_in: S3Helper::DOWNLOAD_URL_EXPIRES_AFTER_SECONDS,
force_download: force_download?
)
), allow_other_host: true
end
def metadata

View File

@ -97,7 +97,7 @@ class UserApiKeysController < ApplicationController
query_attributes << "oneTimePassword=#{CGI.escape(otp_payload)}" if scopes.include?("one_time_password")
uri.query = query_attributes.compact.join('&')
redirect_to(uri.to_s)
redirect_to(uri.to_s, allow_other_host: true)
else
respond_to do |format|
format.html { render :show }
@ -138,7 +138,7 @@ class UserApiKeysController < ApplicationController
otp_payload = one_time_password(public_key, current_user.username)
redirect_path = "#{params[:auth_redirect]}?oneTimePassword=#{CGI.escape(otp_payload)}"
redirect_to(redirect_path)
redirect_to(redirect_path, allow_other_host: true)
end
def revoke

View File

@ -112,7 +112,7 @@ class UserAvatarsController < ApplicationController
if !Discourse.avatar_sizes.include?(size) && Discourse.store.external?
closest = Discourse.avatar_sizes.to_a.min { |a, b| (size - a).abs <=> (size - b).abs }
avatar_url = UserAvatar.local_avatar_url(hostname, user.encoded_username(lower: true), upload_id, closest)
return redirect_to cdn_path(avatar_url)
return redirect_to cdn_path(avatar_url), allow_other_host: true
end
upload = Upload.find_by(id: upload_id) if user&.user_avatar&.contains_upload?(upload_id)
@ -120,7 +120,7 @@ class UserAvatarsController < ApplicationController
if user.uploaded_avatar && !upload
avatar_url = UserAvatar.local_avatar_url(hostname, user.encoded_username(lower: true), user.uploaded_avatar_id, size)
return redirect_to cdn_path(avatar_url)
return redirect_to cdn_path(avatar_url), allow_other_host: true
elsif upload && optimized = get_optimized_image(upload, size)
if optimized.local?
optimized_path = Discourse.store.path_for(optimized)

View File

@ -1024,7 +1024,7 @@ class UsersController < ApplicationController
if SiteSetting.enable_discourse_connect_provider && payload = cookies.delete(:sso_payload)
return redirect_to(session_sso_provider_url + "?" + payload)
elsif destination_url = cookies.delete(:destination_url)
return redirect_to(destination_url)
return redirect_to(destination_url, allow_other_host: true)
else
return redirect_to(path('/'))
end
@ -1086,7 +1086,7 @@ class UsersController < ApplicationController
if Wizard.user_requires_completion?(@user)
return redirect_to(wizard_path)
elsif destination_url.present?
return redirect_to(destination_url)
return redirect_to(destination_url, allow_other_host: true)
elsif SiteSetting.enable_discourse_connect_provider && payload = cookies.delete(:sso_payload)
return redirect_to(session_sso_provider_url + "?" + payload)
end

View File

@ -1,7 +1,5 @@
# frozen_string_literal: true
require_dependency 'email/sender'
module Jobs
class GroupSmtpEmail < ::Jobs::Base
include Skippable

View File

@ -57,8 +57,8 @@ module Jobs
end
def keys_list
messages = old_site_settings_keys.map { |key| "#{key.name} - #{key.updated_at.to_date.to_s(:db)}" }
old_api_keys.each_with_object(messages) { |key, array| array << "#{[key.description, key.user&.username, key.created_at.to_date.to_s(:db)].compact.join(" - ")}" }
messages = old_site_settings_keys.map { |key| "#{key.name} - #{key.updated_at.to_date.to_fs(:db)}" }
old_api_keys.each_with_object(messages) { |key, array| array << "#{[key.description, key.user&.username, key.created_at.to_date.to_fs(:db)].compact.join(" - ")}" }
messages.join("\n")
end
end

View File

@ -1,7 +1,5 @@
# frozen_string_literal: true
require_dependency 'email/message_builder'
class GroupSmtpMailer < ActionMailer::Base
include Email::BuildEmailHelper

View File

@ -1,6 +1,5 @@
# frozen_string_literal: true
require_dependency 'global_path'
require 'csv'
require 'json_schemer'

View File

@ -153,7 +153,9 @@ class TopicList
ft.topic_list = self
end
ActiveRecord::Associations::Preloader.new.preload(@topics, [:image_upload, topic_thumbnails: :optimized_image])
ActiveRecord::Associations::Preloader
.new(records: @topics, associations: [:image_upload, topic_thumbnails: :optimized_image])
.call
if preloaded_custom_fields.present?
Topic.preload_custom_fields(@topics, preloaded_custom_fields)

View File

@ -1,7 +1,5 @@
# frozen_string_literal: true
require "i18n/i18n_interpolation_keys_finder"
class TranslationOverride < ActiveRecord::Base
# Allowlist i18n interpolation keys that can be included when customizing translations
ALLOWED_CUSTOM_INTERPOLATION_KEYS = {

View File

@ -73,8 +73,8 @@ class Bookmarkable
# @param [Array] bookmarks The array of bookmarks after initial listing and filtering, note this is
# array _not_ an ActiveRecord::Relation.
def perform_preload(bookmarks)
ActiveRecord::Associations::Preloader.new.preload(
Bookmark.select_type(bookmarks, model.to_s), { bookmarkable: preload_associations }
)
ActiveRecord::Associations::Preloader
.new(records: Bookmark.select_type(bookmarks, model.to_s), associations: [bookmarkable: preload_associations])
.call
end
end

View File

@ -21,7 +21,7 @@ require 'action_mailer/railtie'
require 'sprockets/railtie'
# Plugin related stuff
require_relative '../lib/plugin_initialization_guard'
require_relative '../lib/plugin'
require_relative '../lib/discourse_event'
require_relative '../lib/discourse_plugin_registry'
@ -31,7 +31,13 @@ require_relative '../lib/plugin_gem'
require_relative '../app/models/global_setting'
GlobalSetting.configure!
if GlobalSetting.load_plugins?
require_relative '../lib/custom_setting_providers'
# 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
# at this point.
Dir.glob(File.join(File.dirname(__FILE__), '../plugins', '*', "register_provider.rb")) do |p|
require p
end
end
GlobalSetting.load_defaults
if GlobalSetting.try(:cdn_url).present? && GlobalSetting.cdn_url !~ /^https?:\/\//
@ -85,14 +91,11 @@ module Discourse
# Application configuration should go into files in config/initializers
# -- all .rb files in that directory are automatically loaded.
# this pattern is somewhat odd but the reloader gets very
# confused here if we load the deps without `lib` it thinks
# discourse.rb is under the discourse folder incorrectly
require_dependency 'lib/discourse'
require_dependency 'lib/js_locale_helper'
require 'discourse'
require 'js_locale_helper'
# tiny file needed by site settings
require_dependency 'lib/highlight_js/highlight_js'
require 'highlight_js'
# we skip it cause we configure it in the initializer
# the railtie for message_bus would insert it in the
@ -109,120 +112,19 @@ module Discourse
# issue is image_optim crashes on missing dependencies
config.assets.image_optim = false
config.autoloader = :zeitwerk
# Custom directories with classes and modules you want to be autoloadable.
config.autoload_paths += Dir["#{config.root}/lib"]
config.autoload_paths += Dir["#{config.root}/lib/common_passwords"]
config.autoload_paths += Dir["#{config.root}/lib/highlight_js"]
config.autoload_paths += Dir["#{config.root}/lib/i18n"]
config.autoload_paths += Dir["#{config.root}/lib/validators/"]
Rails.autoloaders.main.ignore(Dir["#{config.root}/app/models/reports"])
Rails.autoloaders.main.ignore(Dir["#{config.root}/lib/freedom_patches"])
def watchable_args
files, dirs = super
# Skip the assets directory. It doesn't contain any .rb files, so watching it
# is just slowing things down and raising warnings about node_modules symlinks
app_file_extensions = dirs.delete("#{config.root}/app")
Dir["#{config.root}/app/*"].reject { |path| path.end_with? "/assets" }.each do |path|
dirs[path] = app_file_extensions
end
[files, dirs]
end
config.autoload_paths << "#{root}/lib"
config.autoload_paths << "#{root}/lib/guardian"
config.autoload_paths << "#{root}/lib/i18n"
config.autoload_paths << "#{root}/lib/validators"
# Only load the plugins named here, in the order given (default is alphabetical).
# :all can be used as a placeholder for all plugins not explicitly named.
# config.plugins = [ :exception_notification, :ssl_requirement, :all ]
config.assets.paths += %W(#{config.root}/config/locales #{config.root}/public/javascripts)
# Allows us to skip minification on some files
config.assets.skip_minification = []
# explicitly precompile any images in plugins ( /assets/images ) path
config.assets.precompile += [lambda do |filename, path|
path =~ /assets\/images/ && !%w(.js .css).include?(File.extname(filename))
end]
config.assets.precompile += %w{
vendor.js
admin.js
browser-detect.js
browser-update.js
break_string.js
ember_jquery.js
pretty-text-bundle.js
wizard-application.js
wizard-vendor.js
markdown-it-bundle.js
service-worker.js
google-tag-manager.js
google-universal-analytics-v3.js
google-universal-analytics-v4.js
start-discourse.js
print-page.js
omniauth-complete.js
activate-account.js
auto-redirect.js
wizard-start.js
locales/i18n.js
discourse/app/lib/webauthn.js
confirm-new-email/confirm-new-email.js
confirm-new-email/bootstrap.js
onpopstate-handler.js
embed-application.js
discourse/tests/active-plugins.js
admin-plugins.js
discourse/tests/test_starter.js
}
if EmberCli.enabled?
config.assets.precompile += %w{
discourse.js
test-support.js
test-helpers.js
scripts/discourse-test-listen-boot
scripts/discourse-boot
}
else
config.assets.precompile += %w{
application.js
discourse/tests/test-support-rails.js
discourse/tests/test-helpers-rails.js
vendor-theme-tests.js
}
end
# Precompile all available locales
unless GlobalSetting.try(:omit_base_locales)
Dir.glob("#{config.root}/app/assets/javascripts/locales/*.js.erb").each do |file|
config.assets.precompile << "locales/#{file.match(/([a-z_A-Z]+\.js)\.erb$/)[1]}"
end
end
# out of the box sprockets 3 grabs loose files that are hanging in assets,
# the exclusion list does not include hbs so you double compile all this stuff
initializer :fix_sprockets_loose_file_searcher, after: :set_default_precompile do |app|
app.config.assets.precompile.delete(Sprockets::Railtie::LOOSE_APP_ASSETS)
# We don't want application from node_modules, only from the root
app.config.assets.precompile.delete(/(?:\/|\\|\A)application\.(css|js)$/)
app.config.assets.precompile += ['application.js']
start_path = ::Rails.root.join("app/assets").to_s
exclude = ['.es6', '.hbs', '.hbr', '.js', '.css', '.lock', '.json', '.log', '.html', '']
app.config.assets.precompile << lambda do |logical_path, filename|
filename.start_with?(start_path) &&
!filename.include?("/node_modules/") &&
!filename.include?("/dist/") &&
!exclude.include?(File.extname(logical_path))
end
end
# 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.
config.time_zone = 'UTC'
@ -234,24 +136,6 @@ module Discourse
# Configure the default encoding used in templates for Ruby 1.9.
config.encoding = 'utf-8'
# Configure sensitive parameters which will be filtered from the log file.
config.filter_parameters += [
:password,
:pop3_polling_password,
:api_key,
:s3_secret_access_key,
:twitter_consumer_secret,
:facebook_app_secret,
:github_client_secret,
:second_factor_token,
]
# Enable the asset pipeline
config.assets.enabled = true
# Version of your assets, change this if you want to expire all your assets
config.assets.version = '1.2.5'
# see: http://stackoverflow.com/questions/11894180/how-does-one-correctly-add-custom-sql-dml-in-migrations/11894420#11894420
config.active_record.schema_format = :sql
@ -336,45 +220,21 @@ module Discourse
if Rails.env.test? && GlobalSetting.load_plugins?
Discourse.activate_plugins!
elsif GlobalSetting.load_plugins?
plugin_initialization_guard do
Plugin.initialization_guard do
Discourse.activate_plugins!
end
end
Discourse.find_plugin_js_assets(include_disabled: true).each do |file|
config.assets.precompile << "#{file}.js"
end
# Use discourse-fonts gem to symlink fonts and generate .scss file
fonts_path = File.join(config.root, 'public/fonts')
Discourse::Utils.atomic_ln_s(DiscourseFonts.path_for_fonts, fonts_path)
require_dependency 'stylesheet/manager'
require_dependency 'svg_sprite/svg_sprite'
require 'stylesheet/manager'
require 'svg_sprite'
config.after_initialize do
# require common dependencies that are often required by plugins
# in the past observers would load them as side-effects
# correct behavior is for plugins to require stuff they need,
# however it would be a risky and breaking change not to require here
require_dependency 'category'
require_dependency 'post'
require_dependency 'topic'
require_dependency 'user'
require_dependency 'post_action'
require_dependency 'post_revision'
require_dependency 'notification'
require_dependency 'topic_user'
require_dependency 'topic_view'
require_dependency 'topic_list'
require_dependency 'group'
require_dependency 'user_field'
require_dependency 'post_action_type'
# Ensure that Discourse event triggers for web hooks are loaded
require_dependency 'web_hook'
# Load plugins
plugin_initialization_guard do
Plugin.initialization_guard do
Discourse.plugins.each(&:notify_after_initialize)
end

View File

@ -1,12 +1,12 @@
# frozen_string_literal: true
# Load the rails application
require File.expand_path('../application', __FILE__)
# Load the Rails application.
require_relative "application"
# Initialize the rails application
Discourse::Application.initialize!
# Initialize the Rails application.
Rails.application.initialize!
# When in "dev" mode, ensure we won't be sending any emails
if Rails.env.development? && ActionMailer::Base.smtp_settings != { 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"
end

View File

@ -36,5 +36,15 @@ Rails.autoloaders.each do |autoloader|
'onceoff' => 'Jobs',
'regular' => 'Jobs',
'scheduled' => 'Jobs',
'google_oauth2_authenticator' => 'GoogleOAuth2Authenticator',
'omniauth_strategies' => 'OmniAuthStrategies',
'csrf_token_verifier' => 'CSRFTokenVerifier',
'html' => 'HTML',
'json' => 'JSON'
)
end
Rails.autoloaders.main.ignore("lib/tasks",
"lib/generators",
"lib/freedom_patches",
"lib/i18n/backend",
"lib/unicorn_logstash_patch.rb")

View File

@ -30,14 +30,14 @@ if defined?(RailsFailover::ActiveRecord)
return unless Rails.configuration.active_record_rails_failover
if Rails.configuration.multisite
if ActiveRecord::Base.current_role == ActiveRecord::Base.reading_role
if ActiveRecord::Base.current_role == ActiveRecord.reading_role
RailsMultisite::ConnectionManagement.default_connection_handler =
ActiveRecord::Base.connection_handlers[ActiveRecord::Base.reading_role]
ActiveRecord::Base.connection_handlers[ActiveRecord.reading_role]
end
end
RailsFailover::ActiveRecord.on_failover do |role|
if role == ActiveRecord::Base.writing_role # Multisite master
if role == ActiveRecord.writing_role # Multisite master
RailsMultisite::ConnectionManagement.each_connection do
Discourse.enable_readonly_mode(Discourse::PG_READONLY_MODE_KEY)
end
@ -47,16 +47,16 @@ if defined?(RailsFailover::ActiveRecord)
end
# Test connection to the master, and trigger master failover if needed
ActiveRecord::Base.connected_to(role: ActiveRecord::Base.writing_role) do
ActiveRecord::Base.connected_to(role: ActiveRecord.writing_role) do
ActiveRecord::Base.connection.active?
rescue PG::ConnectionBad, PG::UnableToSend, PG::ServerError
RailsFailover::ActiveRecord.verify_primary(ActiveRecord::Base.writing_role)
RailsFailover::ActiveRecord.verify_primary(ActiveRecord.writing_role)
end
end
end
RailsFailover::ActiveRecord.on_fallback do |role|
if role == ActiveRecord::Base.writing_role # Multisite master
if role == ActiveRecord.writing_role # Multisite master
RailsMultisite::ConnectionManagement.each_connection do
Discourse.disable_readonly_mode(Discourse::PG_READONLY_MODE_KEY)
end
@ -68,7 +68,7 @@ if defined?(RailsFailover::ActiveRecord)
if Rails.configuration.multisite
RailsMultisite::ConnectionManagement.default_connection_handler =
ActiveRecord::Base.connection_handlers[ActiveRecord::Base.writing_role]
ActiveRecord::Base.connection_handlers[ActiveRecord.writing_role]
end
end

View File

@ -6,17 +6,15 @@
Discourse.git_version
if GlobalSetting.skip_redis?
# Requiring this file explicitly prevents it from being autoloaded and so the
# provider attribute is not cleared
require File.expand_path('../../../app/models/site_setting', __FILE__)
require 'site_settings/local_process_provider'
Rails.cache = Discourse.cache
Rails.application.config.to_prepare do
SiteSetting.provider = SiteSettings::LocalProcessProvider.new
end
return
end
reload_settings = lambda {
Rails.application.config.to_prepare do
RailsMultisite::ConnectionManagement.safe_each_connection do
begin
SiteSetting.refresh!
@ -28,12 +26,4 @@ reload_settings = lambda {
# This will happen when migrating a new database
end
end
}
reload_settings.call
if !Rails.configuration.cache_classes
ActiveSupport::Reloader.to_prepare do
reload_settings.call
end
end

View File

@ -2,6 +2,7 @@
return if GlobalSetting.skip_db?
Rails.application.config.to_prepare do
# Some sanity checking so we don't count on an unindexed column on boot
begin
if ActiveRecord::Base.connection.table_exists?(:users) &&
@ -29,3 +30,4 @@ begin
rescue ActiveRecord::NoDatabaseError
# Database might not have been created
end
end

View File

@ -1,5 +1,6 @@
# frozen_string_literal: true
Rails.application.config.to_prepare do
if Rails.env.development? && SiteSetting.port.to_i > 0
Onebox.options = {
twitter_client: TwitterApi,
@ -14,3 +15,4 @@ else
user_agent: "Discourse Forum Onebox v#{Discourse::VERSION::STRING}"
}
end
end

View File

@ -2,7 +2,8 @@
return if GlobalSetting.skip_db?
require_dependency 'webpush'
Rails.application.config.to_prepare do
require 'webpush'
def generate_vapid_key?
SiteSetting.vapid_public_key.blank? ||
@ -29,3 +30,4 @@ end
DiscourseEvent.on(:user_logged_out) do |user|
PushNotificationPusher.clear_subscriptions(user)
end
end

View File

@ -1,10 +1,15 @@
# frozen_string_literal: true
# Be sure to restart your server when you modify this file.
#
require_dependency 'discourse_cookie_store'
if Rails.env == "development" && SiteSetting.force_https
Rails.application.config.session_store(
:discourse_cookie_store,
key: '_forum_session',
path: (Rails.application.config.relative_url_root.nil?) ? '/' : Rails.application.config.relative_url_root
)
Rails.application.config.to_prepare do
if Rails.env.development? && SiteSetting.force_https
STDERR.puts
STDERR.puts "WARNING: force_https is enabled in dev"
STDERR.puts "It is very unlikely you are running HTTPS in dev."
@ -13,9 +18,4 @@ if Rails.env == "development" && SiteSetting.force_https
STDERR.puts "SiteSetting.force_https = false"
STDERR.puts
end
Discourse::Application.config.session_store(
:discourse_cookie_store,
key: '_forum_session',
path: (Rails.application.config.relative_url_root.nil?) ? '/' : Rails.application.config.relative_url_root
)
end

View File

@ -1,5 +1,6 @@
# frozen_string_literal: true
Rails.application.config.to_prepare do
if (Rails.env.production? && SiteSetting.logging_provider == 'lograge') || (ENV["ENABLE_LOGRAGE"] == "1")
require 'lograge'
@ -115,3 +116,4 @@ if (Rails.env.production? && SiteSetting.logging_provider == 'lograge') || (ENV[
end
end
end
end

View File

@ -0,0 +1,99 @@
# frozen_string_literal: true
# Be sure to restart your server when you modify this file.
# Enable the asset pipeline
Rails.application.config.assets.enabled = true
# Version of your assets, change this if you want to expire all your assets.
Rails.application.config.assets.version = "1.2.5"
# Add additional assets to the asset load path.
Rails.application.config.assets.paths << "#{Rails.root}/config/locales"
Rails.application.config.assets.paths << "#{Rails.root}/public/javascripts"
# Precompile additional assets.
# application.js, application.css, and all non-JS/CSS in the app/assets
# folder are already added.
# explicitly precompile any images in plugins ( /assets/images ) path
Rails.application.config.assets.precompile += [lambda do |filename, path|
path =~ /assets\/images/ && !%w(.js .css).include?(File.extname(filename))
end]
Rails.application.config.assets.precompile += %w{
vendor.js
admin.js
browser-detect.js
browser-update.js
break_string.js
ember_jquery.js
pretty-text-bundle.js
wizard-application.js
wizard-vendor.js
markdown-it-bundle.js
service-worker.js
google-tag-manager.js
google-universal-analytics-v3.js
google-universal-analytics-v4.js
start-discourse.js
print-page.js
omniauth-complete.js
activate-account.js
auto-redirect.js
wizard-start.js
locales/i18n.js
discourse/app/lib/webauthn.js
confirm-new-email/confirm-new-email.js
confirm-new-email/bootstrap.js
onpopstate-handler.js
embed-application.js
discourse/tests/active-plugins.js
admin-plugins.js
discourse/tests/test_starter.js
}
if EmberCli.enabled?
Rails.application.config.assets.precompile += %w{
discourse.js
test-support.js
test-helpers.js
scripts/discourse-test-listen-boot
scripts/discourse-boot
}
else
Rails.application.config.assets.precompile += %w{
application.js
discourse/tests/test-support-rails.js
discourse/tests/test-helpers-rails.js
vendor-theme-tests.js
}
end
# Precompile all available locales
unless GlobalSetting.try(:omit_base_locales)
Dir.glob("#{Rails.root}/app/assets/javascripts/locales/*.js.erb").each do |file|
Rails.application.config.assets.precompile << "locales/#{file.match(/([a-z_A-Z]+\.js)\.erb$/)[1]}"
end
end
# out of the box sprockets 3 grabs loose files that are hanging in assets,
# the exclusion list does not include hbs so you double compile all this stuff
Rails.application.config.assets.precompile.delete(Sprockets::Railtie::LOOSE_APP_ASSETS)
# 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 += ['application.js']
start_path = ::Rails.root.join("app/assets").to_s
exclude = ['.es6', '.hbs', '.hbr', '.js', '.css', '.lock', '.json', '.log', '.html', '']
Rails.application.config.assets.precompile << lambda do |logical_path, filename|
filename.start_with?(start_path) &&
!filename.include?("/node_modules/") &&
!filename.include?("/dist/") &&
!exclude.include?(File.extname(logical_path))
end
Discourse.find_plugin_js_assets(include_disabled: true).each do |file|
Rails.application.config.assets.precompile << "#{file}.js"
end

View File

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

View File

@ -0,0 +1,106 @@
# frozen_string_literal: true
# Be sure to restart your server when you modify this file.
#
# This file eases your Rails 7.0 framework defaults upgrade.
#
# Uncomment each configuration one by one to switch to the new default.
# Once your application is ready to run with all new defaults, you can remove
# this file and set the `config.load_defaults` to `7.0`.
#
# Read the Guide for Upgrading Ruby on Rails for more info on each option.
# https://guides.rubyonrails.org/upgrading_ruby_on_rails.html
# `button_to` view helper will render `<button>` element, regardless of whether
# or not the content is passed as the first argument or as a block.
Rails.application.config.action_view.button_to_generates_button_tag = true
# `stylesheet_link_tag` view helper will not render the media attribute by default.
Rails.application.config.action_view.apply_stylesheet_media_default = false
# Change the digest class for the key generators to `OpenSSL::Digest::SHA256`.
# Changing this default means invalidate all encrypted messages generated by
# your application and, all the encrypted cookies. Only change this after you
# rotated all the messages using the key rotator.
#
# See upgrading guide for more information on how to build a rotator.
# https://guides.rubyonrails.org/v7.0/upgrading_ruby_on_rails.html
# Rails.application.config.active_support.key_generator_hash_digest_class = OpenSSL::Digest::SHA256
# Change the digest class for ActiveSupport::Digest.
# Changing this default means that for example Etags change and
# various cache keys leading to cache invalidation.
# Rails.application.config.active_support.hash_digest_class = OpenSSL::Digest::SHA256
# Don't override ActiveSupport::TimeWithZone.name and use the default Ruby
# implementation.
Rails.application.config.active_support.remove_deprecated_time_with_zone_name = true
# Change the format of the cache entry.
# Changing this default means that all new cache entries added to the cache
# will have a different format that is not supported by Rails 6.1 applications.
# Only change this value after your application is fully deployed to Rails 7.0
# and you have no plans to rollback.
# Rails.application.config.active_support.cache_format_version = 7.0
# Calls `Rails.application.executor.wrap` around test cases.
# This makes test cases behave closer to an actual request or job.
# Several features that are normally disabled in test, such as Active Record query cache
# and asynchronous queries will then be enabled.
Rails.application.config.active_support.executor_around_test_case = true
# Define the isolation level of most of Rails internal state.
# If you use a fiber based server or job processor, you should set it to `:fiber`.
# Otherwise the default of `:thread` if preferable.
Rails.application.config.active_support.isolation_level = :thread
# Set both the `:open_timeout` and `:read_timeout` values for `:smtp` delivery method.
Rails.application.config.action_mailer.smtp_timeout = 5
# Automatically infer `inverse_of` for associations with a scope.
Rails.application.config.active_record.automatic_scope_inversing = true
# Raise when running tests if fixtures contained foreign key violations
Rails.application.config.active_record.verify_foreign_keys_for_fixtures = true
# Disable partial inserts.
# This default means that all columns will be referenced in INSERT queries
# regardless of whether they have a default or not.
Rails.application.config.active_record.partial_inserts = false
#
# Protect from open redirect attacks in `redirect_back_or_to` and `redirect_to`.
Rails.application.config.action_controller.raise_on_open_redirects = true
# If you're upgrading and haven't set `cookies_serializer` previously, your cookie serializer
# was `:marshal`. Convert all cookies to JSON, using the `:hybrid` formatter.
#
# If you're confident all your cookies are JSON formatted, you can switch to the `:json` formatter.
#
# Continue to use `:marshal` for backward-compatibility with old cookies.
#
# If you have configured the serializer elsewhere, you can remove this.
#
# See https://guides.rubyonrails.org/action_controller_overview.html#cookies for more information.
Rails.application.config.action_dispatch.cookies_serializer = :marshal
# Enable parameter wrapping for JSON.
# Previously this was set in an initializer. It's fine to keep using that initializer if you've customized it.
# To disable parameter wrapping entirely, set this config to `false`.
# Rails.application.config.action_controller.wrap_parameters_by_default = true
# Specifies whether generated namespaced UUIDs follow the RFC 4122 standard for namespace IDs provided as a
# `String` to `Digest::UUID.uuid_v3` or `Digest::UUID.uuid_v5` method calls.
#
# See https://guides.rubyonrails.org/configuring.html#config-active-support-use-rfc4122-namespaced-uuids for
# more information.
Rails.application.config.active_support.use_rfc4122_namespaced_uuids = true
# Change the default headers to disable browsers' flawed legacy XSS protection.
Rails.application.config.action_dispatch.default_headers = {
"X-Frame-Options" => "SAMEORIGIN",
"X-XSS-Protection" => "0",
"X-Content-Type-Options" => "nosniff",
"X-Download-Options" => "noopen",
"X-Permitted-Cross-Domain-Policies" => "none",
"Referrer-Policy" => "strict-origin-when-cross-origin"
}

View File

@ -1,6 +1,6 @@
# frozen_string_literal: true
require "common_passwords/common_passwords"
require "common_passwords"
class ClearCommonPasswordsCache < ActiveRecord::Migration[4.2]
def change

View File

@ -1,6 +1,6 @@
# frozen_string_literal: true
require_dependency 'has_errors'
require 'has_errors'
class Auth::GithubAuthenticator < Auth::ManagedAuthenticator

View File

@ -1,59 +0,0 @@
# frozen_string_literal: true
class Auth::OAuth2Authenticator < Auth::Authenticator
def name
@name
end
# only option at the moment is :trusted
def initialize(name, opts = {})
Discourse.deprecate("OAuth2Authenticator is deprecated. Use `ManagedAuthenticator` and `UserAssociatedAccount` instead. For more information, see https://meta.discourse.org/t/106695", drop_from: '2.9.0', output_in_test: true)
@name = name
@opts = opts
end
def after_authenticate(auth_token)
result = Auth::Result.new
oauth2_provider = auth_token[:provider]
oauth2_uid = auth_token[:uid]
data = auth_token[:info]
result.email = email = data[:email]
result.name = name = data[:name]
oauth2_user_info = Oauth2UserInfo.find_by(uid: oauth2_uid, provider: oauth2_provider)
if !oauth2_user_info && @opts[:trusted] && user = User.find_by_email(email)
oauth2_user_info = Oauth2UserInfo.create(uid: oauth2_uid,
provider: oauth2_provider,
name: name,
email: email,
user: user)
end
result.user = oauth2_user_info.try(:user)
result.email_valid = @opts[:trusted]
result.extra_data = {
uid: oauth2_uid,
provider: oauth2_provider
}
result
end
def after_create_account(user, auth)
data = auth[:extra_data]
association = Oauth2UserInfo.find_or_initialize_by(provider: data[:provider], uid: data[:uid])
association.user = user
association.email = auth[:email]
association.save!
end
def description_for_user(user)
info = Oauth2UserInfo.find_by(user_id: user.id, provider: @name)
info&.email || info&.name || info&.uid || ""
end
end

View File

@ -75,7 +75,7 @@ class Auth::Result
def self.from_session_data(data, user:)
result = new
data = data.symbolize_keys
data = data.with_indifferent_access
SESSION_ATTRIBUTES.each { |att| result.public_send("#{att}=", data[att]) }
result.user = user
result

View File

@ -10,10 +10,10 @@ module BackupRestore
def self.create(opts = {})
case opts[:location] || SiteSetting.backup_location
when BackupLocationSiteSetting::LOCAL
require_dependency "backup_restore/local_backup_store"
require "backup_restore/local_backup_store"
BackupRestore::LocalBackupStore.new(opts)
when BackupLocationSiteSetting::S3
require_dependency "backup_restore/s3_backup_store"
require "backup_restore/s3_backup_store"
BackupRestore::S3BackupStore.new(opts)
end
end

View File

@ -1,5 +1,5 @@
# frozen_string_literal: true
require_dependency 'content_security_policy/default'
require 'content_security_policy/default'
class ContentSecurityPolicy
class Builder

View File

@ -1,5 +1,5 @@
# frozen_string_literal: true
require_dependency 'content_security_policy'
require 'content_security_policy'
class ContentSecurityPolicy
class Default

View File

@ -1,5 +1,5 @@
# frozen_string_literal: true
require_dependency 'content_security_policy'
require 'content_security_policy'
class ContentSecurityPolicy
class Middleware

View File

@ -1,9 +0,0 @@
# frozen_string_literal: true
# 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
# at this point.
Dir.glob(File.join(File.dirname(__FILE__), '../plugins', '*', "register_provider.rb")) do |p|
require p
end

View File

@ -1,6 +1,6 @@
# frozen_string_literal: true
require_dependency "migration/base_dropper"
require "migration/base_dropper"
class DbHelper

View File

@ -2,8 +2,8 @@
require 'cache'
require 'open3'
require_dependency 'plugin/instance'
require_dependency 'version'
require 'plugin/instance'
require 'version'
module Discourse
DB_POST_MIGRATE_PATH ||= "db/post_migrate"

View File

@ -1,6 +1,6 @@
# frozen_string_literal: true
require_dependency 'file_store/base_store'
require 'file_store/base_store'
module FileStore

View File

@ -2,9 +2,9 @@
require "uri"
require "mini_mime"
require_dependency "file_store/base_store"
require_dependency "s3_helper"
require_dependency "file_helper"
require "file_store/base_store"
require "s3_helper"
require "file_helper"
module FileStore

View File

@ -1,19 +0,0 @@
# frozen_string_literal: true
# Pulls in https://github.com/rails/rails/pull/42368 early since the query is
# definitely more efficient as it does not involved the PG planner.
# Remove once Rails 7 has been released.
module ActiveRecord
module ConnectionAdapters
class PostgreSQLAdapter
def active?
@lock.synchronize do
@connection.query ";"
end
true
rescue PG::Error
false
end
end
end
end

View File

@ -0,0 +1,50 @@
# frozen_string_literal: true
# This patch is a backport of https://github.com/rails/rails/pull/42350
# It fixes a bug introduced by Rails which affects reference columns marking
# them as integer instead of bigint.
#
# This should be deleted when version 7.0.3 is released.
module FreedomPatches
module ArReferencesFix
module SchemaDefinition
def index_options(table_name)
index_options = as_options(index)
# legacy reference index names are used on versions 6.0 and earlier
return index_options if options[:_uses_legacy_reference_index_name]
index_options[:name] ||= polymorphic_index_name(table_name) if polymorphic
index_options
end
ActiveRecord::ConnectionAdapters::ReferenceDefinition.prepend(self)
end
end
end
class ActiveRecord::Migration::Compatibility::V6_0
module TableDefinition
def references(*args, **options)
options[:_uses_legacy_reference_index_name] = true
super
end
alias :belongs_to :references
end
def add_reference(table_name, ref_name, **options)
if connection.adapter_name == "SQLite"
options[:type] = :integer
end
options[:_uses_legacy_reference_index_name] = true
super
end
alias :add_belongs_to :add_reference
def compatible_table_definition(t)
class << t
prepend TableDefinition
end
super
end
end

View File

@ -10,7 +10,7 @@ module RailsMultisite
break if !defined?(RailsFailover::ActiveRecord)
break if db == RailsMultisite::ConnectionManagement::DEFAULT
reading_role = :"#{db}_#{ActiveRecord::Base.reading_role}"
reading_role = :"#{db}_#{ActiveRecord.reading_role}"
spec = RailsMultisite::ConnectionManagement.connection_spec(db: db)
ActiveRecord::Base.connection_handlers[reading_role] ||= begin

View File

@ -59,13 +59,13 @@ class HtmlToMarkdown
before, after = parent.children.slice_when { |n| n == br }.to_a
if before.size > 1
b = Nokogiri::XML::Node.new(parent.name, doc)
b = Nokogiri::XML::Node.new(parent.name, doc.document)
before[0...-1].each { |c| b.add_child(c) }
parent.previous = b if b.inner_html.present?
end
if after.present?
a = Nokogiri::XML::Node.new(parent.name, doc)
a = Nokogiri::XML::Node.new(parent.name, doc.document)
after.each { |c| a.add_child(c) }
parent.next = a if a.inner_html.present?
end

View File

@ -1,6 +1,6 @@
# frozen_string_literal: true
require_relative "locale_file_walker"
require "locale_file_walker"
class DuplicateKeyFinder < LocaleFileWalker

View File

@ -1,9 +1,9 @@
# frozen_string_literal: true
require_dependency "mobile_detection"
require_dependency "crawler_detection"
require_dependency "guardian"
require_dependency "http_language_parser"
require "mobile_detection"
require "crawler_detection"
require "guardian"
require "http_language_parser"
module Middleware
class AnonymousCache

View File

@ -1,6 +1,6 @@
# frozen_string_literal: true
require_dependency 'migration/base_dropper'
require 'migration/base_dropper'
module Migration
class ColumnDropper

View File

@ -1,6 +1,6 @@
# frozen_string_literal: true
require_dependency 'migration/base_dropper'
require 'migration/base_dropper'
module Migration
class Migration::TableDropper

53
lib/plugin.rb Normal file
View File

@ -0,0 +1,53 @@
# frozen_string_literal: true
module Plugin
def self.initialization_guard(&block)
begin
block.call
rescue => error
plugins_directory = Rails.root + 'plugins'
if error.backtrace && error.backtrace_locations
plugin_path = error.backtrace_locations.lazy.map do |location|
Pathname.new(location.absolute_path)
.ascend
.lazy
.find { |path| path.parent == plugins_directory }
end.next
raise unless plugin_path
stack_trace = error.backtrace.each_with_index.inject([]) do |messages, (line, index)|
if index == 0
messages << "#{line}: #{error} (#{error.class})"
else
messages << "\t#{index}: from #{line}"
end
end.reverse.join("\n")
STDERR.puts <<~TEXT
#{stack_trace}
** INCOMPATIBLE PLUGIN **
You are unable to build Discourse due to errors in the plugin at
#{plugin_path}
Please try removing this plugin and rebuilding again!
TEXT
else
STDERR.puts <<~TEXT
** PLUGIN FAILURE **
You are unable to build Discourse due to this error during plugin
initialization:
#{error}
#{error.backtrace.join("\n")}
TEXT
end
exit 1
end
end
end

View File

@ -2,8 +2,8 @@
require 'digest/sha1'
require 'fileutils'
require_dependency 'plugin/metadata'
require_dependency 'auth'
require 'plugin/metadata'
require 'auth'
class Plugin::CustomEmoji
CACHE_KEY ||= "plugin-emoji"

View File

@ -1,51 +0,0 @@
# frozen_string_literal: true
def plugin_initialization_guard(&block)
begin
block.call
rescue => error
plugins_directory = Rails.root + 'plugins'
if error.backtrace && error.backtrace_locations
plugin_path = error.backtrace_locations.lazy.map do |location|
Pathname.new(location.absolute_path)
.ascend
.lazy
.find { |path| path.parent == plugins_directory }
end.next
raise unless plugin_path
stack_trace = error.backtrace.each_with_index.inject([]) do |messages, (line, index)|
if index == 0
messages << "#{line}: #{error} (#{error.class})"
else
messages << "\t#{index}: from #{line}"
end
end.reverse.join("\n")
STDERR.puts <<~TEXT
#{stack_trace}
** INCOMPATIBLE PLUGIN **
You are unable to build Discourse due to errors in the plugin at
#{plugin_path}
Please try removing this plugin and rebuilding again!
TEXT
else
STDERR.puts <<~TEXT
** PLUGIN FAILURE **
You are unable to build Discourse due to this error during plugin
initialization:
#{error}
#{error.backtrace.join("\n")}
TEXT
end
exit 1
end
end

View File

@ -1,6 +1,6 @@
# frozen_string_literal: true
require_dependency 'has_errors'
require 'has_errors'
class PostActionResult
include HasErrors

View File

@ -18,5 +18,5 @@ module RequireDependencyBackwardCompatibility
super
end
ActiveSupport::Dependencies::ZeitwerkIntegration::RequireDependency.prepend(self)
Object.prepend(self)
end

View File

@ -1,6 +1,6 @@
# frozen_string_literal: true
require_dependency 'reviewable/collection'
require 'reviewable/collection'
class Reviewable < ActiveRecord::Base
class Actions < Reviewable::Collection

View File

@ -1,6 +1,6 @@
# frozen_string_literal: true
require_dependency "s3_helper"
require "s3_helper"
class S3CorsRulesets
ASSETS = {

View File

@ -1,7 +1,6 @@
# frozen_string_literal: true
require 'stylesheet/importer'
require 'stylesheet/functions'
module Stylesheet

View File

@ -1,16 +0,0 @@
# frozen_string_literal: true
module Stylesheet
module ScssFunctions
def asset_url(path)
Discourse.deprecate("The `asset-url` SCSS function is deprecated. Use `absolute-image-url` instead.", drop_from: '2.9.0')
SassC::Script::Value::String.new("url('#{ActionController::Base.helpers.asset_url(path.value)}')")
end
def image_url(path)
Discourse.deprecate("The `image-url` SCSS function is deprecated. Use `absolute-image-url` instead.", drop_from: '2.9.0')
SassC::Script::Value::String.new("url('#{ActionController::Base.helpers.image_url(path.value)}')")
end
end
end
::SassC::Script::Functions.include(Stylesheet::ScssFunctions)

View File

@ -1,6 +1,6 @@
# frozen_string_literal: true
require_dependency 'global_path'
require 'global_path'
module Stylesheet
class Importer

View File

@ -1,7 +1,7 @@
# frozen_string_literal: true
require_dependency 'distributed_cache'
require_dependency 'stylesheet/compiler'
require 'distributed_cache'
require 'stylesheet/compiler'
module Stylesheet; end

View File

@ -5,7 +5,7 @@ require "fileutils"
require "json"
require "nokogiri"
require "open-uri"
require_dependency "file_helper"
require "file_helper"
EMOJI_GROUPS_PATH ||= "lib/emoji/groups.json"

View File

@ -1,6 +1,6 @@
# frozen_string_literal: true
require_dependency "file_helper"
require "file_helper"
task "images:compress" => :environment do
images = Dir.glob("#{Rails.root}/app/**/*.png")

View File

@ -1,6 +1,6 @@
# frozen_string_literal: true
require_dependency "rake_helpers"
require "rake_helpers"
def close_old_topics(category)
topics = Topic.where(closed: false, category_id: category.id)

View File

@ -8,7 +8,7 @@ require "base62"
# gather #
################################################################################
require_dependency "rake_helpers"
require "rake_helpers"
task "uploads:gather" => :environment do
ENV["RAILS_DB"] ? gather_uploads : gather_uploads_for_all_sites

View File

@ -1,6 +1,6 @@
# frozen_string_literal: true
require_dependency 'compression/zip'
require 'compression/zip'
module ThemeStore; end

View File

@ -1,6 +1,6 @@
# frozen_string_literal: true
require_dependency 'compression/engine'
require 'compression/engine'
module ThemeStore; end

View File

@ -1,6 +1,6 @@
# frozen_string_literal: true
require_dependency "file_helper"
require "file_helper"
module Validators; end

View File

@ -1,7 +1,5 @@
# frozen_string_literal: true
require "i18n/duplicate_key_finder"
def extract_locale(path)
path[/\.([^.]{2,})\.yml$/, 1]
end

View File

@ -1,7 +1,5 @@
# frozen_string_literal: true
require "i18n/duplicate_key_finder"
describe "site setting integrity checks" do
let(:site_setting_file) { File.join(Rails.root, 'config', 'site_settings.yml') }
let(:yaml) { YAML.load_file(site_setting_file) }

View File

@ -1,13 +1,11 @@
# frozen_string_literal: true
describe Jobs::CreateLinkedTopic do
it "returns when the post cannot be found" do
expect { Jobs::CreateLinkedTopic.new.perform(post_id: 1, sync_exec: true) }.not_to raise_error
end
context 'with a post' do
fab!(:category) { Fabricate(:category) }
fab!(:topic) { Fabricate(:topic, category: category) }
fab!(:post) do
@ -54,5 +52,4 @@ describe Jobs::CreateLinkedTopic do
expect(linked_topic.sequence).to eq(2)
end
end
end

View File

@ -1,7 +1,6 @@
# frozen_string_literal: true
describe Jobs::FeatureTopicUsers do
it "raises an error without a topic_id" do
expect { Jobs::FeatureTopicUsers.new.execute({}) }.to raise_error(Discourse::InvalidParameters)
end
@ -32,16 +31,13 @@ describe Jobs::FeatureTopicUsers do
Jobs::FeatureTopicUsers.new.execute(topic_id: topic.id)
expect(topic.reload.featured_user_ids.include?(evil_trout.id)).to eq(false)
end
end
context "participant count" do
let!(:post) { create_post }
let(:topic) { post.topic }
it "it works as expected" do
# It has 1 participant after creation
expect(topic.participant_count).to eq(1)
@ -58,9 +54,6 @@ describe Jobs::FeatureTopicUsers do
create_post(topic: topic, user: Fabricate(:evil_trout))
Jobs::FeatureTopicUsers.new.execute(topic_id: topic.id)
expect(topic.reload.participant_count).to eq(2)
end
end
end

View File

@ -28,9 +28,9 @@ describe Jobs::OldKeysReminder do
As a courtesy, we wanted to let you know that the following credentials used on your Discourse instance have not been updated in more than two years:
google_oauth2_client_secret - #{google_secret.updated_at.to_date.to_s(:db)}
github_client_secret - #{github_secret.updated_at.to_date.to_s(:db)}
api key description - #{api_key.created_at.to_date.to_s(:db)}
google_oauth2_client_secret - #{google_secret.updated_at.to_date.to_fs(:db)}
github_client_secret - #{github_secret.updated_at.to_date.to_fs(:db)}
api key description - #{api_key.created_at.to_date.to_fs(:db)}
No action is required at this time, however, it is considered good security practice to cycle all your important credentials every few years.
TEXT
@ -45,11 +45,11 @@ describe Jobs::OldKeysReminder do
As a courtesy, we wanted to let you know that the following credentials used on your Discourse instance have not been updated in more than two years:
google_oauth2_client_secret - #{google_secret.updated_at.to_date.to_s(:db)}
github_client_secret - #{github_secret.updated_at.to_date.to_s(:db)}
twitter_consumer_secret - #{recent_twitter_secret.updated_at.to_date.to_s(:db)}
api key description - #{api_key.created_at.to_date.to_s(:db)}
recent api key description - #{admin.username} - #{recent_api_key.created_at.to_date.to_s(:db)}
google_oauth2_client_secret - #{google_secret.updated_at.to_date.to_fs(:db)}
github_client_secret - #{github_secret.updated_at.to_date.to_fs(:db)}
twitter_consumer_secret - #{recent_twitter_secret.updated_at.to_date.to_fs(:db)}
api key description - #{api_key.created_at.to_date.to_fs(:db)}
recent api key description - #{admin.username} - #{recent_api_key.created_at.to_date.to_fs(:db)}
No action is required at this time, however, it is considered good security practice to cycle all your important credentials every few years.
TEXT

View File

@ -1,13 +1,11 @@
# frozen_string_literal: true
describe Jobs::ProcessPost do
it "returns when the post cannot be found" do
expect { Jobs::ProcessPost.new.perform(post_id: 1, sync_exec: true) }.not_to raise_error
end
context 'with a post' do
fab!(:post) { Fabricate(:post) }
it 'does not erase posts when CookedPostProcessor malfunctions' do
@ -90,5 +88,4 @@ describe Jobs::ProcessPost do
expect(post.topic.reload.excerpt).to eq("Some OP content")
end
end
end

View File

@ -1,7 +1,6 @@
# frozen_string_literal: true
describe Jobs::PullHotlinkedImages do
let(:image_url) { "http://wiki.mozilla.org/images/2/2e/Longcat1.png" }
let(:broken_image_url) { "http://wiki.mozilla.org/images/2/2e/Longcat2.png" }
let(:large_image_url) { "http://wiki.mozilla.org/images/2/2e/Longcat3.png" }

View File

@ -1,7 +1,6 @@
# frozen_string_literal: true
describe Jobs::SendSystemMessage do
it "raises an error without a user_id" do
expect { Jobs::SendSystemMessage.new.execute(message_type: 'welcome_invite') }.to raise_error(Discourse::InvalidParameters)
end
@ -11,7 +10,6 @@ describe Jobs::SendSystemMessage do
end
context 'with valid parameters' do
fab!(:user) { Fabricate(:user) }
it "should call SystemMessage.create" do
@ -24,7 +22,5 @@ describe Jobs::SendSystemMessage do
SystemMessage.any_instance.expects(:create).with('post_hidden', options)
Jobs::SendSystemMessage.new.execute(user_id: user.id, message_type: 'post_hidden', message_options: options)
end
end
end

View File

@ -1,7 +1,5 @@
# frozen_string_literal: true
require 'guardian'
describe Guardian do
fab!(:user) { Fabricate(:user) }

View File

@ -193,7 +193,7 @@ describe Hijack do
Process.stubs(:clock_gettime).returns(1.0)
tester.hijack_test do
Process.stubs(:clock_gettime).returns(2.0)
redirect_to 'http://awesome.com'
redirect_to 'http://awesome.com', allow_other_host: true
end
result = "HTTP/1.1 302 Found\r\nLocation: http://awesome.com\r\nContent-Type: text/html; charset=utf-8\r\nContent-Length: 84\r\nConnection: close\r\nX-Runtime: 1.000000\r\n\r\n<html><body>You are being <a href=\"http://awesome.com\">redirected</a>.</body></html>"

View File

@ -1,7 +1,5 @@
# frozen_string_literal: true
require "i18n/i18n_interpolation_keys_finder"
RSpec.describe I18nInterpolationKeysFinder do
describe '#find' do
it 'should return the right keys' do

View File

@ -1,7 +1,5 @@
# frozen_string_literal: true
require 'onpdiff'
describe ONPDiff do
describe "diff" do

View File

@ -74,20 +74,6 @@ describe Stylesheet::Compiler do
end
end
it "supports asset-url" do
css, _map = Stylesheet::Compiler.compile(".body{background-image: asset-url('/images/favicons/github.png');}", "test.scss")
expect(css).to include("url('/images/favicons/github.png')")
expect(css).not_to include('asset-url')
end
it "supports image-url" do
css, _map = Stylesheet::Compiler.compile(".body{background-image: image-url('/favicons/github.png');}", "test.scss")
expect(css).to include("url('/favicons/github.png')")
expect(css).not_to include('image-url')
end
it "supports absolute-image-url" do
scss = Stylesheet::Importer.new({}).prepended_scss
scss += ".body{background-image: absolute-image-url('/favicons/github.png');}"

View File

@ -1,7 +1,5 @@
# frozen_string_literal: true
require 'validators/category_search_priority_weights_validator'
RSpec.describe CategorySearchPriorityWeightsValidator do
it "should validate the results correctly" do
[1, 1.1].each do |value|

View File

@ -1,8 +1,6 @@
# encoding: UTF-8
# frozen_string_literal: true
require 'validators/max_emojis_validator'
describe MaxEmojisValidator do
# simulate Rails behavior (singleton)

View File

@ -1,7 +1,6 @@
# encoding: UTF-8
# frozen_string_literal: true
require 'validators/quality_title_validator'
require 'ostruct'
module QualityTitleValidatorSpec

View File

@ -1,8 +1,6 @@
# encoding: UTF-8
# frozen_string_literal: true
require 'validators/topic_title_length_validator'
describe TopicTitleLengthValidator do
# simulate Rails behavior (singleton)

View File

@ -1,7 +1,5 @@
# frozen_string_literal: true
require 'validators/topic_title_length_validator'
RSpec.describe UrlValidator do
let(:record) { Fabricate.build(:user_profile, user: Fabricate.build(:user)) }
let(:validator) { described_class.new(attributes: :website) }

View File

@ -3,8 +3,8 @@
describe GivenDailyLike do
it 'no errors without a user' do
expect(-> { GivenDailyLike.increment_for(nil) }).not_to raise_error
expect(-> { GivenDailyLike.decrement_for(nil) }).not_to raise_error
expect { GivenDailyLike.increment_for(nil) }.not_to raise_error
expect { GivenDailyLike.decrement_for(nil) }.not_to raise_error
end
context 'with a user' do

View File

@ -487,7 +487,7 @@ end
def decrypt_auth_cookie(cookie)
request = ActionDispatch::Request.new(create_request_env.merge("HTTP_COOKIE" => "_t=#{cookie}"))
request.cookie_jar.encrypted["_t"]
request.cookie_jar.encrypted["_t"].with_indifferent_access
end
class SpecSecureRandom

View File

@ -22,14 +22,23 @@ describe InvitesController do
end
end
it 'shows unobfuscated email if email data is present in authentication data' do
ActionDispatch::Request.any_instance.stubs(:session).returns(authentication: { email: invite.email })
context 'when email data is present in authentication data' do
let(:store) { ActionDispatch::Session::CookieStore.new({}) }
let(:session_stub) { ActionDispatch::Request::Session.create(store, ActionDispatch::TestRequest.create, {}) }
before do
session_stub[:authentication] = { email: invite.email }
ActionDispatch::Request.any_instance.stubs(:session).returns(session_stub)
end
it 'shows unobfuscated email' do
get "/invites/#{invite.invite_key}"
expect(response.status).to eq(200)
expect(response.body).to have_tag(:script, with: { src: "/assets/#{EmberCli.transform_name("application")}.js" })
expect(response.body).to include(invite.email)
expect(response.body).not_to include('i*****g@a***********e.ooo')
end
end
it 'shows default user fields' do
user_field = Fabricate(:user_field)

View File

@ -38,7 +38,7 @@ RSpec.describe EmailSettingsExceptionHandler do
end
it "formats a Net::SMTPAuthenticationError with application-specific password Gmail error" do
exception = Net::SMTPAuthenticationError.new("Application-specific password required")
exception = Net::SMTPAuthenticationError.new(nil, message: "Application-specific password required")
expect(subject.class.friendly_exception_message(exception, "smtp.gmail.com")).to eq(
I18n.t("email_settings.authentication_error_gmail_app_password")
)
@ -52,15 +52,15 @@ RSpec.describe EmailSettingsExceptionHandler do
end
it "formats a Net::SMTPSyntaxError, Net::SMTPFatalError, and Net::SMTPUnknownError" do
exception = Net::SMTPSyntaxError.new("bad syntax")
exception = Net::SMTPSyntaxError.new(nil, message: "bad syntax")
expect(subject.class.friendly_exception_message(exception, "smtp.test.com")).to eq(
I18n.t("email_settings.smtp_unhandled_error", message: exception.message)
)
exception = Net::SMTPFatalError.new("fatal")
exception = Net::SMTPFatalError.new(nil, message: "fatal")
expect(subject.class.friendly_exception_message(exception, "smtp.test.com")).to eq(
I18n.t("email_settings.smtp_unhandled_error", message: exception.message)
)
exception = Net::SMTPUnknownError.new("unknown")
exception = Net::SMTPUnknownError.new(nil, message: "unknown")
expect(subject.class.friendly_exception_message(exception, "smtp.test.com")).to eq(
I18n.t("email_settings.smtp_unhandled_error", message: exception.message)
)

View File

@ -112,7 +112,7 @@ RSpec.describe EmailSettingsValidator do
it "logs a warning if debug: true passed in and still raises the error" do
Rails.logger.expects(:warn).with(regexp_matches(/\[EmailSettingsValidator\] Error encountered/)).at_least_once
net_smtp_stub.stubs(:start).raises(Net::SMTPAuthenticationError, "invalid credentials")
net_smtp_stub.stubs(:start).raises(Net::SMTPAuthenticationError, stub(message: "invalid credentials"))
expect { subject.class.validate_smtp(host: host, port: port, username: username, password: password, debug: true, domain: domain) }.to raise_error(Net::SMTPAuthenticationError)
end

View File

@ -1,12 +1,13 @@
# frozen_string_literal: true
describe "users/omniauth_callbacks/failure.html.erb" do
before do
flash[:error] = I18n.t("login.omniauth_error", strategy: 'test')
end
it "renders the failure page" do
flash[:error] = I18n.t("login.omniauth_error", strategy: 'test')
render
render template: 'users/omniauth_callbacks/failure'
expect(rendered.match(I18n.t("login.omniauth_error.generic", strategy: 'test'))).not_to eq(nil)
expect(rendered).to match I18n.t("login.omniauth_error.generic", strategy: 'test')
end
end