From 5027abecd1e5e511064de75fb5248139e1c8fe23 Mon Sep 17 00:00:00 2001 From: Claire Date: Thu, 18 Mar 2021 00:41:32 +0100 Subject: Fix cache_collection crashing when given an empty collection (#15921) * Fix cache_collection crashing when given an empty collection * Add tests --- app/controllers/concerns/cache_concern.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'app/controllers') diff --git a/app/controllers/concerns/cache_concern.rb b/app/controllers/concerns/cache_concern.rb index 3fb4b962a..05e431b19 100644 --- a/app/controllers/concerns/cache_concern.rb +++ b/app/controllers/concerns/cache_concern.rb @@ -31,7 +31,9 @@ module CacheConcern def cache_collection(raw, klass) return raw unless klass.respond_to?(:with_includes) - raw = raw.cache_ids.to_a if raw.is_a?(ActiveRecord::Relation) + raw = raw.cache_ids.to_a if raw.is_a?(ActiveRecord::Relation) + return [] if raw.empty? + cached_keys_with_value = Rails.cache.read_multi(*raw).transform_keys(&:id) uncached_ids = raw.map(&:id) - cached_keys_with_value.keys -- cgit From b3582298341e32528929c6f3292e36a6fa261ba5 Mon Sep 17 00:00:00 2001 From: Claire Date: Fri, 19 Mar 2021 02:45:34 +0100 Subject: Further preparation for Rails 6 (#15916) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Use ActiveRecord::Result#to_ary instead of deprecated to_hash They do the same thing, and to_hash has been removed from Rails 6.1 * Explicitly name polymorphic indexes to workaround a bug in Rails 6.1 cf. https://github.com/rails/rails/issues/41693 * Fix incorrect usage of “foreign_key” in migration script * Use `ActiveModel::Errors#delete` instead of deprecated clear method * Fix link headers tests on Rails 6.1 Rails 6.1 adds values to the Link header by default, thus it is not a LinkHeader object anymore. Fix the test to parse the Link header instead of assuming it is a LinkHeader. --- app/controllers/admin/domain_blocks_controller.rb | 2 +- db/migrate/20161006213403_rails_settings_migration.rb | 8 ++++---- db/migrate/20171119172437_create_admin_action_logs.rb | 2 +- db/migrate/20180528141303_fix_accounts_unique_index.rb | 2 +- db/migrate/20181024224956_migrate_account_conversations.rb | 4 ++-- db/migrate/20181207011115_downcase_custom_emoji_domains.rb | 2 +- db/migrate/20190726175042_add_case_insensitive_index_to_tags.rb | 2 +- lib/mastodon/migration_helpers.rb | 6 +++--- spec/requests/link_headers_spec.rb | 2 +- 9 files changed, 15 insertions(+), 15 deletions(-) (limited to 'app/controllers') diff --git a/app/controllers/admin/domain_blocks_controller.rb b/app/controllers/admin/domain_blocks_controller.rb index ba927b04a..b140c454c 100644 --- a/app/controllers/admin/domain_blocks_controller.rb +++ b/app/controllers/admin/domain_blocks_controller.rb @@ -22,7 +22,7 @@ module Admin if existing_domain_block.present? && !@domain_block.stricter_than?(existing_domain_block) @domain_block.save flash.now[:alert] = I18n.t('admin.domain_blocks.existing_domain_block_html', name: existing_domain_block.domain, unblock_url: admin_domain_block_path(existing_domain_block)).html_safe # rubocop:disable Rails/OutputSafety - @domain_block.errors[:domain].clear + @domain_block.errors.delete(:domain) render :new else if existing_domain_block.present? diff --git a/db/migrate/20161006213403_rails_settings_migration.rb b/db/migrate/20161006213403_rails_settings_migration.rb index 42875d7cb..9d565cb5c 100644 --- a/db/migrate/20161006213403_rails_settings_migration.rb +++ b/db/migrate/20161006213403_rails_settings_migration.rb @@ -7,12 +7,12 @@ end class RailsSettingsMigration < MIGRATION_BASE_CLASS def self.up create_table :settings do |t| - t.string :var, :null => false + t.string :var, null: false t.text :value - t.references :target, :null => false, :polymorphic => true - t.timestamps :null => true + t.references :target, null: false, polymorphic: true, index: { name: 'index_settings_on_target_type_and_target_id' } + t.timestamps null: true end - add_index :settings, [ :target_type, :target_id, :var ], :unique => true + add_index :settings, [ :target_type, :target_id, :var ], unique: true end def self.down diff --git a/db/migrate/20171119172437_create_admin_action_logs.rb b/db/migrate/20171119172437_create_admin_action_logs.rb index 0c2b6c623..b690735d2 100644 --- a/db/migrate/20171119172437_create_admin_action_logs.rb +++ b/db/migrate/20171119172437_create_admin_action_logs.rb @@ -3,7 +3,7 @@ class CreateAdminActionLogs < ActiveRecord::Migration[5.1] create_table :admin_action_logs do |t| t.belongs_to :account, foreign_key: { on_delete: :cascade } t.string :action, null: false, default: '' - t.references :target, polymorphic: true + t.references :target, polymorphic: true, index: { name: 'index_admin_action_logs_on_target_type_and_target_id' } t.text :recorded_changes, null: false, default: '' t.timestamps diff --git a/db/migrate/20180528141303_fix_accounts_unique_index.rb b/db/migrate/20180528141303_fix_accounts_unique_index.rb index 5d7b3c463..02813f363 100644 --- a/db/migrate/20180528141303_fix_accounts_unique_index.rb +++ b/db/migrate/20180528141303_fix_accounts_unique_index.rb @@ -37,7 +37,7 @@ class FixAccountsUniqueIndex < ActiveRecord::Migration[5.2] end end - duplicates = Account.connection.select_all('SELECT string_agg(id::text, \',\') AS ids FROM accounts GROUP BY lower(username), lower(domain) HAVING count(*) > 1').to_hash + duplicates = Account.connection.select_all('SELECT string_agg(id::text, \',\') AS ids FROM accounts GROUP BY lower(username), lower(domain) HAVING count(*) > 1').to_ary duplicates.each do |row| deduplicate_account!(row['ids'].split(',')) diff --git a/db/migrate/20181024224956_migrate_account_conversations.rb b/db/migrate/20181024224956_migrate_account_conversations.rb index 12e0a70fa..9e6497d81 100644 --- a/db/migrate/20181024224956_migrate_account_conversations.rb +++ b/db/migrate/20181024224956_migrate_account_conversations.rb @@ -17,8 +17,8 @@ class MigrateAccountConversations < ActiveRecord::Migration[5.2] belongs_to :account, optional: true belongs_to :activity, polymorphic: true, optional: true - belongs_to :status, foreign_type: 'Status', foreign_key: 'activity_id', optional: true - belongs_to :mention, foreign_type: 'Mention', foreign_key: 'activity_id', optional: true + belongs_to :status, foreign_key: 'activity_id', optional: true + belongs_to :mention, foreign_key: 'activity_id', optional: true def target_status mention&.status diff --git a/db/migrate/20181207011115_downcase_custom_emoji_domains.rb b/db/migrate/20181207011115_downcase_custom_emoji_domains.rb index 65f1fc8d9..e27e0249d 100644 --- a/db/migrate/20181207011115_downcase_custom_emoji_domains.rb +++ b/db/migrate/20181207011115_downcase_custom_emoji_domains.rb @@ -2,7 +2,7 @@ class DowncaseCustomEmojiDomains < ActiveRecord::Migration[5.2] disable_ddl_transaction! def up - duplicates = CustomEmoji.connection.select_all('SELECT string_agg(id::text, \',\') AS ids FROM custom_emojis GROUP BY shortcode, lower(domain) HAVING count(*) > 1').to_hash + duplicates = CustomEmoji.connection.select_all('SELECT string_agg(id::text, \',\') AS ids FROM custom_emojis GROUP BY shortcode, lower(domain) HAVING count(*) > 1').to_ary duplicates.each do |row| CustomEmoji.where(id: row['ids'].split(',')[0...-1]).destroy_all diff --git a/db/migrate/20190726175042_add_case_insensitive_index_to_tags.rb b/db/migrate/20190726175042_add_case_insensitive_index_to_tags.rb index 057fc86ba..eb03d7ca7 100644 --- a/db/migrate/20190726175042_add_case_insensitive_index_to_tags.rb +++ b/db/migrate/20190726175042_add_case_insensitive_index_to_tags.rb @@ -2,7 +2,7 @@ class AddCaseInsensitiveIndexToTags < ActiveRecord::Migration[5.2] disable_ddl_transaction! def up - Tag.connection.select_all('SELECT string_agg(id::text, \',\') AS ids FROM tags GROUP BY lower(name) HAVING count(*) > 1').to_hash.each do |row| + Tag.connection.select_all('SELECT string_agg(id::text, \',\') AS ids FROM tags GROUP BY lower(name) HAVING count(*) > 1').to_ary.each do |row| canonical_tag_id = row['ids'].split(',').first redundant_tag_ids = row['ids'].split(',')[1..-1] diff --git a/lib/mastodon/migration_helpers.rb b/lib/mastodon/migration_helpers.rb index bf2314ecb..fcaa9259e 100644 --- a/lib/mastodon/migration_helpers.rb +++ b/lib/mastodon/migration_helpers.rb @@ -319,7 +319,7 @@ module Mastodon count_arel = table.project(Arel.star.count.as('count')) count_arel = yield table, count_arel if block_given? - total = exec_query(count_arel.to_sql).to_hash.first['count'].to_i + total = exec_query(count_arel.to_sql).to_ary.first['count'].to_i return if total == 0 end @@ -335,7 +335,7 @@ module Mastodon start_arel = table.project(table[:id]).order(table[:id].asc).take(1) start_arel = yield table, start_arel if block_given? - first_row = exec_query(start_arel.to_sql).to_hash.first + first_row = exec_query(start_arel.to_sql).to_ary.first # In case there are no rows but we didn't catch it in the estimated size: return unless first_row start_id = first_row['id'].to_i @@ -356,7 +356,7 @@ module Mastodon .skip(batch_size) stop_arel = yield table, stop_arel if block_given? - stop_row = exec_query(stop_arel.to_sql).to_hash.first + stop_row = exec_query(stop_arel.to_sql).to_ary.first update_arel = Arel::UpdateManager.new .table(table) diff --git a/spec/requests/link_headers_spec.rb b/spec/requests/link_headers_spec.rb index 712ee262b..c32e0f79a 100644 --- a/spec/requests/link_headers_spec.rb +++ b/spec/requests/link_headers_spec.rb @@ -25,7 +25,7 @@ describe 'Link headers' do end def link_header_with_type(type) - response.headers['Link'].links.find do |link| + LinkHeader.parse(response.headers['Link'].to_s).links.find do |link| link.attr_pairs.any? { |pair| pair == ['type', type] } end end -- cgit From cbd0ee1d07c0d48e4ed14bd446cd23d334e76da8 Mon Sep 17 00:00:00 2001 From: Claire Date: Wed, 24 Mar 2021 10:44:31 +0100 Subject: Update Mastodon to Rails 6.1 (#15910) * Update devise-two-factor to unreleased fork for Rails 6 support Update tests to match new `rotp` version. * Update nsa gem to unreleased fork for Rails 6 support * Update rails to 6.1.3 and rails-i18n to 6.0 * Update to unreleased fork of pluck_each for Ruby 6 support * Run "rails app:update" * Add missing ActiveStorage config file * Use config.ssl_options instead of removed ApplicationController#force_ssl Disabled force_ssl-related tests as they do not seem to be easily testable anymore. * Fix nonce directives by removing Rails 5 specific monkey-patching * Fix fixture_file_upload deprecation warning * Fix yield-based test failing with Rails 6 * Use Rails 6's index_with when possible * Use ActiveRecord::Cache::Store#delete_multi from Rails 6 This will yield better performances when deleting an account * Disable Rails 6.1's automatic preload link headers Since Rails 6.1, ActionView adds preload links for javascript files in the Links header per default. In our case, that will bloat headers too much and potentially cause issues with reverse proxies. Furhermore, we don't need those links, as we already output them as HTML link tags. * Switch to Rails 6.0 default config * Switch to Rails 6.1 default config * Do not include autoload paths in the load path --- Gemfile | 10 +- Gemfile.lock | 181 +++++++++++++-------- app/controllers/application_controller.rb | 6 - app/lib/delivery_failure_tracker.rb | 2 +- app/lib/feed_manager.rb | 12 +- app/lib/settings/scoped_settings.rb | 2 +- app/models/concerns/account_interactions.rb | 2 +- app/models/report.rb | 2 +- app/services/delete_account_service.rb | 3 +- app/services/import_service.rb | 4 +- bin/setup | 16 +- bin/yarn | 12 +- config/application.rb | 3 +- config/environments/production.rb | 7 + .../application_controller_renderer.rb | 10 +- config/initializers/backtrace_silencers.rb | 7 +- config/initializers/content_security_policy.rb | 12 +- config/initializers/permissions_policy.rb | 11 ++ config/initializers/preload_link_headers.rb | 8 + config/storage.yml | 0 lib/tasks/emojis.rake | 2 +- .../api/v1/accounts/credentials_controller_spec.rb | 4 +- spec/controllers/api/v1/media_controller_spec.rb | 10 +- spec/controllers/application_controller_spec.rb | 14 -- .../settings/imports_controller_spec.rb | 4 +- .../settings/profiles_controller_spec.rb | 4 +- .../confirmations_controller_spec.rb | 2 +- spec/models/setting_spec.rb | 11 +- spec/models/user_spec.rb | 2 +- 29 files changed, 204 insertions(+), 159 deletions(-) create mode 100644 config/initializers/permissions_policy.rb create mode 100644 config/initializers/preload_link_headers.rb create mode 100644 config/storage.yml (limited to 'app/controllers') diff --git a/Gemfile b/Gemfile index 98af92def..0b2fdf156 100644 --- a/Gemfile +++ b/Gemfile @@ -6,7 +6,7 @@ ruby '>= 2.5.0', '< 3.0.0' gem 'pkg-config', '~> 1.4' gem 'puma', '~> 5.2' -gem 'rails', '~> 5.2.4.5' +gem 'rails', '~> 6.1.3' gem 'sprockets', '~> 3.7.2' gem 'thor', '~> 1.1' gem 'rack', '~> 2.2.3' @@ -34,7 +34,7 @@ gem 'iso-639' gem 'chewy', '~> 5.2' gem 'cld3', '~> 3.4.1' gem 'devise', '~> 4.7' -gem 'devise-two-factor', '~> 3.1' +gem 'devise-two-factor', git: 'https://github.com/ClearlyClaire/devise-two-factor', ref: '594bb8a32e6f94df7e5ba7c9399eaf9ff25bac0d' group :pam_authentication, optional: true do gem 'devise_pam_authenticatable2', '~> 9.2' @@ -65,7 +65,7 @@ gem 'link_header', '~> 0.0' gem 'mime-types', '~> 3.3.1', require: 'mime/types/columnar' gem 'nilsimsa', git: 'https://github.com/witgo/nilsimsa', ref: 'fd184883048b922b176939f851338d0a4971a532' gem 'nokogiri', '~> 1.11' -gem 'nsa', '~> 0.2' +gem 'nsa', git: 'https://github.com/Gargron/nsa', ref: 'd1079e0cdafdfed7f9f35478d13b9bdaa65965c0' gem 'oj', '~> 3.11' gem 'ox', '~> 2.14' gem 'parslet' @@ -75,7 +75,7 @@ gem 'pundit', '~> 2.1' gem 'premailer-rails' gem 'rack-attack', '~> 6.5' gem 'rack-cors', '~> 1.1', require: 'rack/cors' -gem 'rails-i18n', '~> 5.1' +gem 'rails-i18n', '~> 6.0' gem 'rails-settings-cached', '~> 0.6' gem 'redis', '~> 4.2', require: ['redis', 'redis/connection/hiredis'] gem 'mario-redis-lock', '~> 1.2', require: 'redis_lock' @@ -159,4 +159,4 @@ gem 'concurrent-ruby', require: false gem 'connection_pool', require: false gem 'xorcist', '~> 1.1' -gem 'pluck_each', '~> 0.1.3' +gem 'pluck_each', git: 'https://github.com/nsommer/pluck_each', ref: '73be0947c52fc54bf6d7085378db008358aac5eb' diff --git a/Gemfile.lock b/Gemfile.lock index 1a67f893d..1f7183b9d 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,3 +1,26 @@ +GIT + remote: https://github.com/ClearlyClaire/devise-two-factor + revision: 594bb8a32e6f94df7e5ba7c9399eaf9ff25bac0d + ref: 594bb8a32e6f94df7e5ba7c9399eaf9ff25bac0d + specs: + devise-two-factor (3.1.0) + activesupport (< 7.0) + attr_encrypted (>= 1.3, < 4, != 2) + devise + railties (< 7.0) + rotp (~> 6) + +GIT + remote: https://github.com/Gargron/nsa + revision: d1079e0cdafdfed7f9f35478d13b9bdaa65965c0 + ref: d1079e0cdafdfed7f9f35478d13b9bdaa65965c0 + specs: + nsa (0.2.8) + activesupport (>= 4.2, < 7) + concurrent-ruby (~> 1.0, >= 1.0.2) + sidekiq (>= 3.5) + statsd-ruby (~> 1.4, >= 1.4.0) + GIT remote: https://github.com/ianheggie/health_check revision: 0b799ead604f900ed50685e9b2d469cd2befba5b @@ -6,6 +29,15 @@ GIT health_check (4.0.0.pre) rails (>= 4.0) +GIT + remote: https://github.com/nsommer/pluck_each + revision: 73be0947c52fc54bf6d7085378db008358aac5eb + ref: 73be0947c52fc54bf6d7085378db008358aac5eb + specs: + pluck_each (0.1.3) + activerecord (>= 6.1.0) + activesupport (>= 6.1.0) + GIT remote: https://github.com/witgo/nilsimsa revision: fd184883048b922b176939f851338d0a4971a532 @@ -16,53 +48,71 @@ GIT GEM remote: https://rubygems.org/ specs: - actioncable (5.2.4.5) - actionpack (= 5.2.4.5) + actioncable (6.1.3) + actionpack (= 6.1.3) + activesupport (= 6.1.3) nio4r (~> 2.0) websocket-driver (>= 0.6.1) - actionmailer (5.2.4.5) - actionpack (= 5.2.4.5) - actionview (= 5.2.4.5) - activejob (= 5.2.4.5) + actionmailbox (6.1.3) + actionpack (= 6.1.3) + activejob (= 6.1.3) + activerecord (= 6.1.3) + activestorage (= 6.1.3) + activesupport (= 6.1.3) + mail (>= 2.7.1) + actionmailer (6.1.3) + actionpack (= 6.1.3) + actionview (= 6.1.3) + activejob (= 6.1.3) + activesupport (= 6.1.3) mail (~> 2.5, >= 2.5.4) rails-dom-testing (~> 2.0) - actionpack (5.2.4.5) - actionview (= 5.2.4.5) - activesupport (= 5.2.4.5) - rack (~> 2.0, >= 2.0.8) + actionpack (6.1.3) + actionview (= 6.1.3) + activesupport (= 6.1.3) + rack (~> 2.0, >= 2.0.9) rack-test (>= 0.6.3) rails-dom-testing (~> 2.0) - rails-html-sanitizer (~> 1.0, >= 1.0.2) - actionview (5.2.4.5) - activesupport (= 5.2.4.5) + rails-html-sanitizer (~> 1.0, >= 1.2.0) + actiontext (6.1.3) + actionpack (= 6.1.3) + activerecord (= 6.1.3) + activestorage (= 6.1.3) + activesupport (= 6.1.3) + nokogiri (>= 1.8.5) + actionview (6.1.3) + activesupport (= 6.1.3) builder (~> 3.1) erubi (~> 1.4) rails-dom-testing (~> 2.0) - rails-html-sanitizer (~> 1.0, >= 1.0.3) + rails-html-sanitizer (~> 1.1, >= 1.2.0) active_model_serializers (0.10.12) actionpack (>= 4.1, < 6.2) activemodel (>= 4.1, < 6.2) case_transform (>= 0.2) jsonapi-renderer (>= 0.1.1.beta1, < 0.3) active_record_query_trace (1.8) - activejob (5.2.4.5) - activesupport (= 5.2.4.5) + activejob (6.1.3) + activesupport (= 6.1.3) globalid (>= 0.3.6) - activemodel (5.2.4.5) - activesupport (= 5.2.4.5) - activerecord (5.2.4.5) - activemodel (= 5.2.4.5) - activesupport (= 5.2.4.5) - arel (>= 9.0) - activestorage (5.2.4.5) - actionpack (= 5.2.4.5) - activerecord (= 5.2.4.5) + activemodel (6.1.3) + activesupport (= 6.1.3) + activerecord (6.1.3) + activemodel (= 6.1.3) + activesupport (= 6.1.3) + activestorage (6.1.3) + actionpack (= 6.1.3) + activejob (= 6.1.3) + activerecord (= 6.1.3) + activesupport (= 6.1.3) marcel (~> 0.3.1) - activesupport (5.2.4.5) + mimemagic (~> 0.3.2) + activesupport (6.1.3) concurrent-ruby (~> 1.0, >= 1.0.2) - i18n (>= 0.7, < 2) - minitest (~> 5.1) - tzinfo (~> 1.1) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) + zeitwerk (~> 2.3) addressable (2.7.0) public_suffix (>= 2.0.2, < 5.0) airbrussh (1.4.0) @@ -71,7 +121,6 @@ GEM annotate (3.1.1) activerecord (>= 3.2, < 7.0) rake (>= 10.4, < 14.0) - arel (9.0.0) ast (2.4.2) attr_encrypted (3.1.0) encryptor (~> 3.0.0) @@ -175,12 +224,6 @@ GEM railties (>= 4.1.0) responders warden (~> 1.2.3) - devise-two-factor (3.1.0) - activesupport (< 6.1) - attr_encrypted (>= 1.3, < 4, != 2) - devise (~> 4.0) - railties (< 6.1) - rotp (~> 2.0) devise_pam_authenticatable2 (9.2.0) devise (>= 4.0.0) rpam2 (~> 4.0) @@ -370,11 +413,6 @@ GEM racc (~> 1.4) nokogumbo (2.0.4) nokogiri (~> 1.8, >= 1.8.4) - nsa (0.2.7) - activesupport (>= 4.2, < 6) - concurrent-ruby (~> 1.0, >= 1.0.2) - sidekiq (>= 3.5) - statsd-ruby (~> 1.4, >= 1.4.0) oj (3.11.3) omniauth (1.9.1) hashie (>= 3.4.6) @@ -414,9 +452,6 @@ GEM pghero (2.8.0) activerecord (>= 5) pkg-config (1.4.5) - pluck_each (0.1.3) - activerecord (> 3.2.0) - activesupport (> 3.0.0) posix-spawn (0.3.15) premailer (1.14.2) addressable @@ -450,18 +485,20 @@ GEM rack rack-test (1.1.0) rack (>= 1.0, < 3) - rails (5.2.4.5) - actioncable (= 5.2.4.5) - actionmailer (= 5.2.4.5) - actionpack (= 5.2.4.5) - actionview (= 5.2.4.5) - activejob (= 5.2.4.5) - activemodel (= 5.2.4.5) - activerecord (= 5.2.4.5) - activestorage (= 5.2.4.5) - activesupport (= 5.2.4.5) - bundler (>= 1.3.0) - railties (= 5.2.4.5) + rails (6.1.3) + actioncable (= 6.1.3) + actionmailbox (= 6.1.3) + actionmailer (= 6.1.3) + actionpack (= 6.1.3) + actiontext (= 6.1.3) + actionview (= 6.1.3) + activejob (= 6.1.3) + activemodel (= 6.1.3) + activerecord (= 6.1.3) + activestorage (= 6.1.3) + activesupport (= 6.1.3) + bundler (>= 1.15.0) + railties (= 6.1.3) sprockets-rails (>= 2.0.0) rails-controller-testing (1.0.5) actionpack (>= 5.0.1.rc1) @@ -472,17 +509,17 @@ GEM nokogiri (>= 1.6) rails-html-sanitizer (1.3.0) loofah (~> 2.3) - rails-i18n (5.1.3) + rails-i18n (6.0.0) i18n (>= 0.7, < 2) - railties (>= 5.0, < 6) + railties (>= 6.0.0, < 7) rails-settings-cached (0.6.6) rails (>= 4.2.0) - railties (5.2.4.5) - actionpack (= 5.2.4.5) - activesupport (= 5.2.4.5) + railties (6.1.3) + actionpack (= 6.1.3) + activesupport (= 6.1.3) method_source rake (>= 0.8.7) - thor (>= 0.19.0, < 2.0) + thor (~> 1.0) rainbow (3.0.0) rake (13.0.3) rdf (3.1.13) @@ -500,7 +537,7 @@ GEM actionpack (>= 5.0) railties (>= 5.0) rexml (3.2.4) - rotp (2.1.2) + rotp (6.2.0) rpam2 (4.0.2) rqrcode (1.2.0) chunky_png (~> 1.0) @@ -600,7 +637,7 @@ GEM net-scp (>= 1.1.2) net-ssh (>= 2.8.0) stackprof (0.2.16) - statsd-ruby (1.4.0) + statsd-ruby (1.5.0) stoplight (2.2.1) streamio-ffmpeg (3.0.2) multi_json (~> 1.8) @@ -612,7 +649,6 @@ GEM terrapin (0.6.0) climate_control (>= 0.0.3, < 1.0) thor (1.1.0) - thread_safe (0.3.6) thwait (0.2.0) e2mmap tilt (2.0.10) @@ -632,8 +668,8 @@ GEM twitter-text (3.1.0) idn-ruby unf (~> 0.1.0) - tzinfo (1.2.9) - thread_safe (~> 0.1) + tzinfo (2.0.4) + concurrent-ruby (~> 1.0) tzinfo-data (1.2021.1) tzinfo (>= 1.0.0) unf (0.1.4) @@ -672,6 +708,7 @@ GEM xorcist (1.1.2) xpath (3.2.0) nokogiri (~> 1.8) + zeitwerk (2.4.2) PLATFORMS ruby @@ -703,7 +740,7 @@ DEPENDENCIES concurrent-ruby connection_pool devise (~> 4.7) - devise-two-factor (~> 3.1) + devise-two-factor! devise_pam_authenticatable2 (~> 9.2) discard (~> 1.2) doorkeeper (~> 5.5) @@ -741,7 +778,7 @@ DEPENDENCIES net-ldap (~> 0.17) nilsimsa! nokogiri (~> 1.11) - nsa (~> 0.2) + nsa! oj (~> 3.11) omniauth (~> 1.9) omniauth-cas (~> 2.0) @@ -756,7 +793,7 @@ DEPENDENCIES pg (~> 1.2) pghero (~> 2.8) pkg-config (~> 1.4) - pluck_each (~> 0.1.3) + pluck_each! posix-spawn premailer-rails private_address_check (~> 0.5) @@ -767,9 +804,9 @@ DEPENDENCIES rack (~> 2.2.3) rack-attack (~> 6.5) rack-cors (~> 1.1) - rails (~> 5.2.4.5) + rails (~> 6.1.3) rails-controller-testing (~> 1.0) - rails-i18n (~> 5.1) + rails-i18n (~> 6.0) rails-settings-cached (~> 0.6) rdf-normalize (~> 0.4) redis (~> 4.2) diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 5b7eec94f..6361d4b27 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -5,8 +5,6 @@ class ApplicationController < ActionController::Base # For APIs, you may want to use :null_session instead. protect_from_forgery with: :exception - force_ssl if: :https_enabled? - include Localized include UserTrackingConcern include SessionTrackingConcern @@ -42,10 +40,6 @@ class ApplicationController < ActionController::Base private - def https_enabled? - Rails.env.production? && !request.path.start_with?('/health') && !request.headers["Host"].end_with?(".onion") - end - def authorized_fetch_mode? ENV['AUTHORIZED_FETCH'] == 'true' || Rails.configuration.x.whitelist_mode end diff --git a/app/lib/delivery_failure_tracker.rb b/app/lib/delivery_failure_tracker.rb index 25fa694d2..2cd6ef7ad 100644 --- a/app/lib/delivery_failure_tracker.rb +++ b/app/lib/delivery_failure_tracker.rb @@ -29,7 +29,7 @@ class DeliveryFailureTracker class << self def without_unavailable(urls) - unavailable_domains_map = Rails.cache.fetch('unavailable_domains') { UnavailableDomain.pluck(:domain).each_with_object({}) { |domain, hash| hash[domain] = true } } + unavailable_domains_map = Rails.cache.fetch('unavailable_domains') { UnavailableDomain.pluck(:domain).index_with(true) } urls.reject do |url| host = Addressable::URI.parse(url).normalized_host diff --git a/app/lib/feed_manager.rb b/app/lib/feed_manager.rb index 165338437..43aeecb35 100644 --- a/app/lib/feed_manager.rb +++ b/app/lib/feed_manager.rb @@ -533,12 +533,12 @@ class FeedManager arr end - crutches[:following] = Follow.where(account_id: receiver_id, target_account_id: statuses.map(&:in_reply_to_account_id).compact).pluck(:target_account_id).each_with_object({}) { |id, mapping| mapping[id] = true } - crutches[:hiding_reblogs] = Follow.where(account_id: receiver_id, target_account_id: statuses.map { |s| s.account_id if s.reblog? }.compact, show_reblogs: false).pluck(:target_account_id).each_with_object({}) { |id, mapping| mapping[id] = true } - crutches[:blocking] = Block.where(account_id: receiver_id, target_account_id: check_for_blocks).pluck(:target_account_id).each_with_object({}) { |id, mapping| mapping[id] = true } - crutches[:muting] = Mute.where(account_id: receiver_id, target_account_id: check_for_blocks).pluck(:target_account_id).each_with_object({}) { |id, mapping| mapping[id] = true } - crutches[:domain_blocking] = AccountDomainBlock.where(account_id: receiver_id, domain: statuses.map { |s| s.reblog&.account&.domain }.compact).pluck(:domain).each_with_object({}) { |domain, mapping| mapping[domain] = true } - crutches[:blocked_by] = Block.where(target_account_id: receiver_id, account_id: statuses.map { |s| s.reblog&.account_id }.compact).pluck(:account_id).each_with_object({}) { |id, mapping| mapping[id] = true } + crutches[:following] = Follow.where(account_id: receiver_id, target_account_id: statuses.map(&:in_reply_to_account_id).compact).pluck(:target_account_id).index_with(true) + crutches[:hiding_reblogs] = Follow.where(account_id: receiver_id, target_account_id: statuses.map { |s| s.account_id if s.reblog? }.compact, show_reblogs: false).pluck(:target_account_id).index_with(true) + crutches[:blocking] = Block.where(account_id: receiver_id, target_account_id: check_for_blocks).pluck(:target_account_id).index_with(true) + crutches[:muting] = Mute.where(account_id: receiver_id, target_account_id: check_for_blocks).pluck(:target_account_id).index_with(true) + crutches[:domain_blocking] = AccountDomainBlock.where(account_id: receiver_id, domain: statuses.map { |s| s.reblog&.account&.domain }.compact).pluck(:domain).index_with(true) + crutches[:blocked_by] = Block.where(target_account_id: receiver_id, account_id: statuses.map { |s| s.reblog&.account_id }.compact).pluck(:account_id).index_with(true) crutches end diff --git a/app/lib/settings/scoped_settings.rb b/app/lib/settings/scoped_settings.rb index acabf0c8e..1e18d6d46 100644 --- a/app/lib/settings/scoped_settings.rb +++ b/app/lib/settings/scoped_settings.rb @@ -63,7 +63,7 @@ module Settings class << self def default_settings - defaulting = DEFAULTING_TO_UNSCOPED.each_with_object({}) { |k, h| h[k] = Setting[k] } + defaulting = DEFAULTING_TO_UNSCOPED.index_with { |k| Setting[k] } Setting.default_settings.merge!(defaulting) end end diff --git a/app/models/concerns/account_interactions.rb b/app/models/concerns/account_interactions.rb index 974f57820..51e8e04a8 100644 --- a/app/models/concerns/account_interactions.rb +++ b/app/models/concerns/account_interactions.rb @@ -67,7 +67,7 @@ module AccountInteractions private def follow_mapping(query, field) - query.pluck(field).each_with_object({}) { |id, mapping| mapping[id] = true } + query.pluck(field).index_with(true) end end diff --git a/app/models/report.rb b/app/models/report.rb index cd08120e4..ef41547d9 100644 --- a/app/models/report.rb +++ b/app/models/report.rb @@ -32,7 +32,7 @@ class Report < ApplicationRecord scope :unresolved, -> { where(action_taken: false) } scope :resolved, -> { where(action_taken: true) } - scope :with_accounts, -> { includes([:account, :target_account, :action_taken_by_account, :assigned_account].each_with_object({}) { |k, h| h[k] = { user: [:invite_request, :invite] } }) } + scope :with_accounts, -> { includes([:account, :target_account, :action_taken_by_account, :assigned_account].index_with({ user: [:invite_request, :invite] })) } validates :comment, length: { maximum: 1000 } diff --git a/app/services/delete_account_service.rb b/app/services/delete_account_service.rb index 802799ccd..182f0e127 100644 --- a/app/services/delete_account_service.rb +++ b/app/services/delete_account_service.rb @@ -188,8 +188,7 @@ class DeleteAccountService < BaseService ids = favourites.pluck(:status_id) StatusStat.where(status_id: ids).update_all('favourites_count = GREATEST(0, favourites_count - 1)') Chewy.strategy.current.update(StatusesIndex::Status, ids) if Chewy.enabled? - # Rails.cache.delete_multi would be better, but we don't have it yet - ids.each { |id| Rails.cache.delete("statuses/#{id}") } + Rails.cache.delete_multi(ids.map { |id| "statuses/#{id}" }) favourites.delete_all end end diff --git a/app/services/import_service.rb b/app/services/import_service.rb index b11532283..74ad5b79f 100644 --- a/app/services/import_service.rb +++ b/app/services/import_service.rb @@ -45,7 +45,7 @@ class ImportService < BaseService items = @data.take(ROWS_PROCESSING_LIMIT).map { |row| row['#domain'].strip } if @import.overwrite? - presence_hash = items.each_with_object({}) { |id, mapping| mapping[id] = true } + presence_hash = items.index_with(true) @account.domain_blocks.find_each do |domain_block| if presence_hash[domain_block.domain] @@ -96,7 +96,7 @@ class ImportService < BaseService items = @data.take(ROWS_PROCESSING_LIMIT).map { |row| row['#uri'].strip } if @import.overwrite? - presence_hash = items.each_with_object({}) { |id, mapping| mapping[id] = true } + presence_hash = items.index_with(true) @account.bookmarks.find_each do |bookmark| if presence_hash[bookmark.status.uri] diff --git a/bin/setup b/bin/setup index fc77b0809..90700ac4f 100755 --- a/bin/setup +++ b/bin/setup @@ -1,6 +1,5 @@ #!/usr/bin/env ruby -require 'fileutils' -include FileUtils +require "fileutils" # path to your application root. APP_ROOT = File.expand_path('..', __dir__) @@ -9,22 +8,25 @@ def system!(*args) system(*args) || abort("\n== Command #{args} failed ==") end -chdir APP_ROOT do - # This script is a starting point to setup your application. +FileUtils.chdir APP_ROOT do + # This script is a way to set up or update your development environment automatically. + # This script is idempotent, so that you can run it at any time and get an expectable outcome. # Add necessary setup steps to this file. puts '== Installing dependencies ==' system! 'gem install bundler --conservative' system('bundle check') || system!('bundle install') - system!('yarn install') + + # Install JavaScript dependencies + system! 'bin/yarn' # puts "\n== Copying sample files ==" # unless File.exist?('config/database.yml') - # cp 'config/database.yml.sample', 'config/database.yml' + # FileUtils.cp 'config/database.yml.sample', 'config/database.yml' # end puts "\n== Preparing database ==" - system! 'bin/rails db:setup' + system! 'bin/rails db:prepare' puts "\n== Removing old logs and tempfiles ==" system! 'bin/rails log:clear tmp:clear' diff --git a/bin/yarn b/bin/yarn index 460dd565b..9fab2c350 100755 --- a/bin/yarn +++ b/bin/yarn @@ -1,9 +1,15 @@ #!/usr/bin/env ruby APP_ROOT = File.expand_path('..', __dir__) Dir.chdir(APP_ROOT) do - begin - exec "yarnpkg", *ARGV - rescue Errno::ENOENT + yarn = ENV["PATH"].split(File::PATH_SEPARATOR). + select { |dir| File.expand_path(dir) != __dir__ }. + product(["yarn", "yarn.cmd", "yarn.ps1"]). + map { |dir, file| File.expand_path(file, dir) }. + find { |file| File.executable?(file) } + + if yarn + exec yarn, *ARGV + else $stderr.puts "Yarn executable was not detected in the system." $stderr.puts "Download Yarn at https://yarnpkg.com/en/docs/install" exit 1 diff --git a/config/application.rb b/config/application.rb index 3267fa71b..c911e76dc 100644 --- a/config/application.rb +++ b/config/application.rb @@ -39,7 +39,8 @@ require_relative '../lib/mastodon/redis_config' module Mastodon class Application < Rails::Application # Initialize configuration defaults for originally generated Rails version. - config.load_defaults 5.2 + config.load_defaults 6.1 + config.add_autoload_paths_to_load_path = false # Settings in config/environments/* take precedence over those specified here. # Application configuration should go into files in config/initializers diff --git a/config/environments/production.rb b/config/environments/production.rb index 81a67902e..6df0a3365 100644 --- a/config/environments/production.rb +++ b/config/environments/production.rb @@ -44,6 +44,13 @@ Rails.application.configure do # Allow to specify public IP of reverse proxy if it's needed config.action_dispatch.trusted_proxies = ENV['TRUSTED_PROXY_IP'].split.map { |item| IPAddr.new(item) } if ENV['TRUSTED_PROXY_IP'].present? + config.force_ssl = true + config.ssl_options = { + redirect: { + exclude: -> request { request.path.start_with?('/health') || request.headers["Host"].end_with?('.onion') } + } + } + # Use the lowest log level to ensure availability of diagnostic information # when problems arise. config.log_level = ENV.fetch('RAILS_LOG_LEVEL', 'info').to_sym diff --git a/config/initializers/application_controller_renderer.rb b/config/initializers/application_controller_renderer.rb index 51639b67a..89d2efab2 100644 --- a/config/initializers/application_controller_renderer.rb +++ b/config/initializers/application_controller_renderer.rb @@ -1,6 +1,8 @@ # Be sure to restart your server when you modify this file. -# ApplicationController.renderer.defaults.merge!( -# http_host: 'example.org', -# https: false -# ) +# ActiveSupport::Reloader.to_prepare do +# ApplicationController.renderer.defaults.merge!( +# http_host: 'example.org', +# https: false +# ) +# end diff --git a/config/initializers/backtrace_silencers.rb b/config/initializers/backtrace_silencers.rb index 59385cdf3..33699c309 100644 --- a/config/initializers/backtrace_silencers.rb +++ b/config/initializers/backtrace_silencers.rb @@ -1,7 +1,8 @@ # Be sure to restart your server when you modify this file. # You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces. -# Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ } +# Rails.backtrace_cleaner.add_silencer { |line| /my_noisy_library/.match?(line) } -# You can also remove all the silencers if you're trying to debug a problem that might stem from framework code. -# Rails.backtrace_cleaner.remove_silencers! +# You can also remove all the silencers if you're trying to debug a problem that might stem from framework code +# by setting BACKTRACE=1 before calling your invocation, like "BACKTRACE=1 ./bin/rails runner 'MyClass.perform'". +Rails.backtrace_cleaner.remove_silencers! if ENV["BACKTRACE"] diff --git a/config/initializers/content_security_policy.rb b/config/initializers/content_security_policy.rb index 98dc711e1..92645ff28 100644 --- a/config/initializers/content_security_policy.rb +++ b/config/initializers/content_security_policy.rb @@ -49,17 +49,7 @@ end Rails.application.config.content_security_policy_nonce_generator = -> request { SecureRandom.base64(16) } -# Monkey-patching Rails 5 -module ActionDispatch - class ContentSecurityPolicy - def nonce_directive?(directive) - directive == 'style-src' - end - end -end - -# Rails 6 would require the following instead: -# Rails.application.config.content_security_policy_nonce_directives = %w(style-src) +Rails.application.config.content_security_policy_nonce_directives = %w(style-src) PgHero::HomeController.content_security_policy do |p| p.script_src :self, :unsafe_inline, assets_host diff --git a/config/initializers/permissions_policy.rb b/config/initializers/permissions_policy.rb new file mode 100644 index 000000000..00f64d71b --- /dev/null +++ b/config/initializers/permissions_policy.rb @@ -0,0 +1,11 @@ +# Define an application-wide HTTP permissions policy. For further +# information see https://developers.google.com/web/updates/2018/06/feature-policy +# +# Rails.application.config.permissions_policy do |f| +# f.camera :none +# f.gyroscope :none +# f.microphone :none +# f.usb :none +# f.fullscreen :self +# f.payment :self, "https://secure.example.com" +# end diff --git a/config/initializers/preload_link_headers.rb b/config/initializers/preload_link_headers.rb new file mode 100644 index 000000000..9f21c45ec --- /dev/null +++ b/config/initializers/preload_link_headers.rb @@ -0,0 +1,8 @@ +# Since Rails 6.1, ActionView adds preload links for javascript files +# in the Links header per default. + +# In our case, that will bloat headers too much and potentially cause +# issues with reverse proxies. Furhermore, we don't need those links, +# as we already output them as HTML link tags. + +Rails.application.config.action_view.preload_links_header = false diff --git a/config/storage.yml b/config/storage.yml new file mode 100644 index 000000000..e69de29bb diff --git a/lib/tasks/emojis.rake b/lib/tasks/emojis.rake index 01ae95564..c8655cc47 100644 --- a/lib/tasks/emojis.rake +++ b/lib/tasks/emojis.rake @@ -69,7 +69,7 @@ namespace :emojis do end end - existence_maps = grouped_codes.map { |c| c.map { |cc| [cc, File.exist?(Rails.root.join('public', 'emoji', codepoints_to_filename(cc) + '.svg'))] }.to_h } + existence_maps = grouped_codes.map { |c| c.index_with { |cc| File.exist?(Rails.root.join('public', 'emoji', codepoints_to_filename(cc) + '.svg')) } } map = {} existence_maps.each do |group| diff --git a/spec/controllers/api/v1/accounts/credentials_controller_spec.rb b/spec/controllers/api/v1/accounts/credentials_controller_spec.rb index ebd462a03..9fb0d8770 100644 --- a/spec/controllers/api/v1/accounts/credentials_controller_spec.rb +++ b/spec/controllers/api/v1/accounts/credentials_controller_spec.rb @@ -30,8 +30,8 @@ describe Api::V1::Accounts::CredentialsController do patch :update, params: { display_name: "Alice Isn't Dead", note: "Hi!\n\nToot toot!", - avatar: fixture_file_upload('files/avatar.gif', 'image/gif'), - header: fixture_file_upload('files/attachment.jpg', 'image/jpeg'), + avatar: fixture_file_upload('avatar.gif', 'image/gif'), + header: fixture_file_upload('attachment.jpg', 'image/jpeg'), source: { privacy: 'unlisted', sensitive: true, diff --git a/spec/controllers/api/v1/media_controller_spec.rb b/spec/controllers/api/v1/media_controller_spec.rb index 4e3037208..3eb015a1c 100644 --- a/spec/controllers/api/v1/media_controller_spec.rb +++ b/spec/controllers/api/v1/media_controller_spec.rb @@ -15,7 +15,7 @@ RSpec.describe Api::V1::MediaController, type: :controller do context 'when imagemagick cant identify the file type' do before do expect_any_instance_of(Account).to receive_message_chain(:media_attachments, :create!).and_raise(Paperclip::Errors::NotIdentifiedByImageMagickError) - post :create, params: { file: fixture_file_upload('files/attachment.jpg', 'image/jpeg') } + post :create, params: { file: fixture_file_upload('attachment.jpg', 'image/jpeg') } end it 'returns http 422' do @@ -26,7 +26,7 @@ RSpec.describe Api::V1::MediaController, type: :controller do context 'when there is a generic error' do before do expect_any_instance_of(Account).to receive_message_chain(:media_attachments, :create!).and_raise(Paperclip::Error) - post :create, params: { file: fixture_file_upload('files/attachment.jpg', 'image/jpeg') } + post :create, params: { file: fixture_file_upload('attachment.jpg', 'image/jpeg') } end it 'returns http 422' do @@ -37,7 +37,7 @@ RSpec.describe Api::V1::MediaController, type: :controller do context 'image/jpeg' do before do - post :create, params: { file: fixture_file_upload('files/attachment.jpg', 'image/jpeg') } + post :create, params: { file: fixture_file_upload('attachment.jpg', 'image/jpeg') } end it 'returns http success' do @@ -59,7 +59,7 @@ RSpec.describe Api::V1::MediaController, type: :controller do context 'image/gif' do before do - post :create, params: { file: fixture_file_upload('files/attachment.gif', 'image/gif') } + post :create, params: { file: fixture_file_upload('attachment.gif', 'image/gif') } end it 'returns http success' do @@ -81,7 +81,7 @@ RSpec.describe Api::V1::MediaController, type: :controller do context 'video/webm' do before do - post :create, params: { file: fixture_file_upload('files/attachment.webm', 'video/webm') } + post :create, params: { file: fixture_file_upload('attachment.webm', 'video/webm') } end it do diff --git a/spec/controllers/application_controller_spec.rb b/spec/controllers/application_controller_spec.rb index e73a08a0e..458298a6b 100644 --- a/spec/controllers/application_controller_spec.rb +++ b/spec/controllers/application_controller_spec.rb @@ -42,20 +42,6 @@ describe ApplicationController, type: :controller do include_examples 'respond_with_error', 422 end - it "does not force ssl if Rails.env.production? is not 'true'" do - routes.draw { get 'success' => 'anonymous#success' } - allow(Rails.env).to receive(:production?).and_return(false) - get 'success' - expect(response).to have_http_status(200) - end - - it "forces ssl if Rails.env.production? is 'true'" do - routes.draw { get 'success' => 'anonymous#success' } - allow(Rails.env).to receive(:production?).and_return(true) - get 'success' - expect(response).to redirect_to('https://test.host/success') - end - describe 'helper_method :current_account' do it 'returns nil if not signed in' do expect(controller.view_context.current_account).to be_nil diff --git a/spec/controllers/settings/imports_controller_spec.rb b/spec/controllers/settings/imports_controller_spec.rb index 7a9b02195..b8caf5941 100644 --- a/spec/controllers/settings/imports_controller_spec.rb +++ b/spec/controllers/settings/imports_controller_spec.rb @@ -21,7 +21,7 @@ RSpec.describe Settings::ImportsController, type: :controller do post :create, params: { import: { type: 'following', - data: fixture_file_upload('files/imports.txt') + data: fixture_file_upload('imports.txt') } } @@ -34,7 +34,7 @@ RSpec.describe Settings::ImportsController, type: :controller do post :create, params: { import: { type: 'blocking', - data: fixture_file_upload('files/imports.txt') + data: fixture_file_upload('imports.txt') } } diff --git a/spec/controllers/settings/profiles_controller_spec.rb b/spec/controllers/settings/profiles_controller_spec.rb index 5b1fe3aca..1ac286254 100644 --- a/spec/controllers/settings/profiles_controller_spec.rb +++ b/spec/controllers/settings/profiles_controller_spec.rb @@ -33,7 +33,7 @@ RSpec.describe Settings::ProfilesController, type: :controller do account = Fabricate(:account, user: @user, display_name: 'AvatarTest') expect(account.avatar.instance.avatar_file_name).to be_nil - put :update, params: { account: { avatar: fixture_file_upload('files/avatar.gif', 'image/gif') } } + put :update, params: { account: { avatar: fixture_file_upload('avatar.gif', 'image/gif') } } expect(response).to redirect_to(settings_profile_path) expect(account.reload.avatar.instance.avatar_file_name).not_to be_nil expect(ActivityPub::UpdateDistributionWorker).to have_received(:perform_async).with(account.id) @@ -44,7 +44,7 @@ RSpec.describe Settings::ProfilesController, type: :controller do it 'gives the user an error message' do allow(ActivityPub::UpdateDistributionWorker).to receive(:perform_async) account = Fabricate(:account, user: @user, display_name: 'AvatarTest') - put :update, params: { account: { avatar: fixture_file_upload('files/4096x4097.png', 'image/png') } } + put :update, params: { account: { avatar: fixture_file_upload('4096x4097.png', 'image/png') } } expect(response.body).to include('images are not supported') end end diff --git a/spec/controllers/settings/two_factor_authentication/confirmations_controller_spec.rb b/spec/controllers/settings/two_factor_authentication/confirmations_controller_spec.rb index cdfeef8d6..7b86513be 100644 --- a/spec/controllers/settings/two_factor_authentication/confirmations_controller_spec.rb +++ b/spec/controllers/settings/two_factor_authentication/confirmations_controller_spec.rb @@ -11,7 +11,7 @@ describe Settings::TwoFactorAuthentication::ConfirmationsController do subject expect(assigns(:confirmation)).to be_instance_of Form::TwoFactorConfirmation - expect(assigns(:provision_url)).to eq 'otpauth://totp/local-part@domain?secret=thisisasecretforthespecofnewview&issuer=cb6e6126.ngrok.io' + expect(assigns(:provision_url)).to eq 'otpauth://totp/cb6e6126.ngrok.io:local-part%40domain?secret=thisisasecretforthespecofnewview&issuer=cb6e6126.ngrok.io' expect(assigns(:qrcode)).to be_instance_of RQRCode::QRCode expect(response).to have_http_status(200) expect(response).to render_template(:new) diff --git a/spec/models/setting_spec.rb b/spec/models/setting_spec.rb index 1cc528674..3ccc21d6c 100644 --- a/spec/models/setting_spec.rb +++ b/spec/models/setting_spec.rb @@ -99,11 +99,12 @@ RSpec.describe Setting, type: :model do end it 'does not query the database' do - expect do |callback| - ActiveSupport::Notifications.subscribed callback, 'sql.active_record' do - described_class[key] - end - end.not_to yield_control + callback = double + allow(callback).to receive(:call) + ActiveSupport::Notifications.subscribed callback, 'sql.active_record' do + described_class[key] + end + expect(callback).not_to have_received(:call) end it 'returns the cached value' do diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 1dae43536..5db249be2 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -175,7 +175,7 @@ RSpec.describe User, type: :model do user = Fabricate(:user) ActiveJob::Base.queue_adapter = :test - expect { user.send_confirmation_instructions }.to have_enqueued_job(ActionMailer::DeliveryJob) + expect { user.send_confirmation_instructions }.to have_enqueued_job(ActionMailer::MailDeliveryJob) end end -- cgit From dd1eb9918ad54fec3a524a53e339ee6c8be9de11 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 25 Mar 2021 02:46:13 +0100 Subject: Add `email` param to `POST /api/v1/emails/confirmations` (#15949) Allow changing e-mail as long as the account is unconfirmed --- app/controllers/api/v1/emails/confirmations_controller.rb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'app/controllers') diff --git a/app/controllers/api/v1/emails/confirmations_controller.rb b/app/controllers/api/v1/emails/confirmations_controller.rb index 03ab5de8c..4a7aa9c32 100644 --- a/app/controllers/api/v1/emails/confirmations_controller.rb +++ b/app/controllers/api/v1/emails/confirmations_controller.rb @@ -5,7 +5,11 @@ class Api::V1::Emails::ConfirmationsController < Api::BaseController before_action :require_user_owned_by_application! def create - current_user.resend_confirmation_instructions if current_user.unconfirmed_email.present? + if !current_user.confirmed? && current_user.unconfirmed_email.present? + current_user.update!(email: params[:email]) if params.key?(:email) + current_user.resend_confirmation_instructions + end + render_empty end -- cgit From 59f94593d059239c28ab5fb8e2a0c23ce2590254 Mon Sep 17 00:00:00 2001 From: Claire Date: Fri, 26 Mar 2021 18:22:54 +0100 Subject: Add warning in admin dashboard if some required queues are not handled (#15954) --- app/controllers/admin/dashboard_controller.rb | 6 ++++++ config/locales/en.yml | 1 + 2 files changed, 7 insertions(+) (limited to 'app/controllers') diff --git a/app/controllers/admin/dashboard_controller.rb b/app/controllers/admin/dashboard_controller.rb index 7c2951acb..24162ec63 100644 --- a/app/controllers/admin/dashboard_controller.rb +++ b/app/controllers/admin/dashboard_controller.rb @@ -3,7 +3,13 @@ require 'sidekiq/api' module Admin class DashboardController < BaseController + SIDEKIQ_QUEUES = %w(default push mailers pull scheduler).freeze + def index + missing_queues = Sidekiq::ProcessSet.new.reduce(SIDEKIQ_QUEUES) { |queues, process| queues - process['queues'] } + + flash.now[:alert] = I18n.t('admin.dashboard.misconfigured_sidekiq_alert', queues: missing_queues.join(', ')) unless missing_queues.empty? + @users_count = User.count @pending_users_count = User.pending.count @registrations_week = Redis.current.get("activity:accounts:local:#{current_week}") || 0 diff --git a/config/locales/en.yml b/config/locales/en.yml index 14f1a08e4..b907d3882 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -367,6 +367,7 @@ en: feature_timeline_preview: Timeline preview features: Features hidden_service: Federation with hidden services + misconfigured_sidekiq_alert: 'No Sidekiq process seems to be handling the following queues: %{queues}. Please review your Sidekiq configuration.' open_reports: open reports pending_tags: hashtags waiting for review pending_users: users waiting for review -- cgit From a650a1157d5b71bc5718759643fe5bb572b16a8b Mon Sep 17 00:00:00 2001 From: Claire Date: Fri, 26 Mar 2021 18:36:16 +0100 Subject: Fix /admin/tags/:id crashing since Rails 6.1 update (#15953) Raw SQL passed to `pluck` now has to be explicitly marked as SQL via Arel.sql, see https://github.com/rails/rails/pull/27947 --- app/controllers/admin/tags_controller.rb | 4 ++-- spec/controllers/admin/tags_controller_spec.rb | 12 ++++++++++++ 2 files changed, 14 insertions(+), 2 deletions(-) (limited to 'app/controllers') diff --git a/app/controllers/admin/tags_controller.rb b/app/controllers/admin/tags_controller.rb index 59df4470e..eed4feea2 100644 --- a/app/controllers/admin/tags_controller.rb +++ b/app/controllers/admin/tags_controller.rb @@ -59,8 +59,8 @@ module Admin .where(Status.arel_table[:id].gteq(Mastodon::Snowflake.id_at(Time.now.utc.beginning_of_day))) .joins(:account) .group('accounts.domain') - .reorder('statuses_count desc') - .pluck('accounts.domain, count(*) AS statuses_count') + .reorder(statuses_count: :desc) + .pluck(Arel.sql('accounts.domain, count(*) AS statuses_count')) end def set_counters diff --git a/spec/controllers/admin/tags_controller_spec.rb b/spec/controllers/admin/tags_controller_spec.rb index 5c1944fc7..9145d887d 100644 --- a/spec/controllers/admin/tags_controller_spec.rb +++ b/spec/controllers/admin/tags_controller_spec.rb @@ -20,4 +20,16 @@ RSpec.describe Admin::TagsController, type: :controller do expect(response).to have_http_status(200) end end + + describe 'GET #show' do + let!(:tag) { Fabricate(:tag) } + + before do + get :show, params: { id: tag.id } + end + + it 'returns status 200' do + expect(response).to have_http_status(200) + end + end end -- cgit