diff --git a/.haml-lint_todo.yml b/.haml-lint_todo.yml index 09764c2f3..af2d2e8f4 100644 --- a/.haml-lint_todo.yml +++ b/.haml-lint_todo.yml @@ -1,20 +1,13 @@ # This configuration was generated by # `haml-lint --auto-gen-config` -# on 2024-01-08 14:02:57 -0500 using Haml-Lint version 0.53.0. +# on 2024-01-09 11:30:07 -0500 using Haml-Lint version 0.53.0. # The point is for the user to remove these configuration records # one by one as the lints are removed from the code base. # Note that changes in the inspected code, or installation of new # versions of Haml-Lint, may require this file to be generated again. linters: - # Offense count: 10 + # Offense count: 1 LineLength: exclude: - 'app/views/admin/roles/_form.html.haml' - - 'app/views/auth/registrations/edit.html.haml' - - 'app/views/auth/registrations/new.html.haml' - - 'app/views/media/player.html.haml' - - 'app/views/settings/applications/_fields.html.haml' - - 'app/views/settings/imports/index.html.haml' - - 'app/views/settings/preferences/appearance/show.html.haml' - - 'app/views/settings/preferences/other/show.html.haml' diff --git a/Gemfile b/Gemfile index d65386dac..28bab57a5 100644 --- a/Gemfile +++ b/Gemfile @@ -48,6 +48,7 @@ gem 'omniauth', '~> 2.0' gem 'omniauth-rails_csrf_protection', '~> 1.0' gem 'color_diff', '~> 0.1' +gem 'csv', '~> 3.2' gem 'discard', '~> 1.2' gem 'doorkeeper', '~> 5.6' gem 'ed25519', '~> 1.3' @@ -75,7 +76,6 @@ gem 'premailer-rails' gem 'rack-attack', '~> 6.6' gem 'rack-cors', '~> 2.0', require: 'rack/cors' gem 'rails-i18n', '~> 7.0' -gem 'rails-settings-cached', '~> 0.6', git: 'https://github.com/mastodon/rails-settings-cached.git', branch: 'v0.6.6-aliases-true' gem 'redcarpet', '~> 3.6' gem 'redis', '~> 4.5', require: ['redis', 'redis/connection/hiredis'] gem 'mario-redis-lock', '~> 1.2', require: 'redis_lock' diff --git a/Gemfile.lock b/Gemfile.lock index 442022e81..595c9fd27 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -18,14 +18,6 @@ GIT sidekiq (>= 3.5) statsd-ruby (~> 1.4, >= 1.4.0) -GIT - remote: https://github.com/mastodon/rails-settings-cached.git - revision: 86328ef0bd04ce21cc0504ff5e334591e8c2ccab - branch: v0.6.6-aliases-true - specs: - rails-settings-cached (0.6.6) - rails (>= 4.2.0) - GIT remote: https://github.com/stanhu/omniauth-cas.git revision: 4211e6d05941b4a981f9a36b49ec166cecd0e271 @@ -216,6 +208,7 @@ GEM crass (1.0.6) css_parser (1.14.0) addressable + csv (3.2.8) database_cleaner-active_record (2.1.0) activerecord (>= 5.a) database_cleaner-core (~> 2.0.0) @@ -272,7 +265,7 @@ GEM erubi (1.12.0) et-orbi (1.2.7) tzinfo - excon (0.104.0) + excon (0.109.0) fabrication (2.31.0) faker (3.2.2) i18n (>= 1.8.11, < 2) @@ -307,7 +300,7 @@ GEM ffi-compiler (1.0.1) ffi (>= 1.0.0) rake - fog-core (2.3.0) + fog-core (2.4.0) builder excon (~> 0.71) formatador (>= 0.2, < 2.0) @@ -378,9 +371,9 @@ GEM terminal-table (>= 1.5.1) idn-ruby (0.1.5) io-console (0.7.1) - irb (1.11.0) + irb (1.11.1) rdoc - reline (>= 0.3.8) + reline (>= 0.4.2) jmespath (1.6.2) json (2.7.1) json-canonicalization (1.0.0) @@ -624,7 +617,7 @@ GEM redlock (1.3.2) redis (>= 3.0.0, < 6.0) regexp_parser (2.8.3) - reline (0.4.1) + reline (0.4.2) io-console (~> 0.5) request_store (1.5.1) rack (>= 1.4) @@ -692,7 +685,7 @@ GEM rubocop (~> 1.40) rubocop-capybara (~> 2.17) rubocop-factory_bot (~> 2.22) - ruby-prof (1.6.3) + ruby-prof (1.7.0) ruby-progressbar (1.13.0) ruby-saml (1.15.0) nokogiri (>= 1.13.10) @@ -724,7 +717,7 @@ GEM rufus-scheduler (~> 3.2) sidekiq (>= 6, < 8) tilt (>= 1.4.0) - sidekiq-unique-jobs (7.1.30) + sidekiq-unique-jobs (7.1.31) brpoplpush-redis_script (> 0.1.1, <= 2.0.0) concurrent-ruby (~> 1.0, >= 1.0.5) redis (< 5.0) @@ -853,6 +846,7 @@ DEPENDENCIES color_diff (~> 0.1) concurrent-ruby connection_pool + csv (~> 3.2) database_cleaner-active_record debug (~> 1.8) devise (~> 4.9) @@ -922,7 +916,6 @@ DEPENDENCIES rails (~> 7.1.1) rails-controller-testing (~> 1.0) rails-i18n (~> 7.0) - rails-settings-cached (~> 0.6)! rdf-normalize (~> 0.5) redcarpet (~> 3.6) redis (~> 4.5) diff --git a/app/controllers/api/v1/streaming_controller.rb b/app/controllers/api/v1/streaming_controller.rb index 0cb6e856f..adb14676e 100644 --- a/app/controllers/api/v1/streaming_controller.rb +++ b/app/controllers/api/v1/streaming_controller.rb @@ -2,7 +2,7 @@ class Api::V1::StreamingController < Api::BaseController def index - if Rails.configuration.x.streaming_api_base_url == request.host + if same_host? not_found else redirect_to streaming_api_url, status: 301, allow_other_host: true @@ -11,6 +11,11 @@ class Api::V1::StreamingController < Api::BaseController private + def same_host? + base_url = Addressable::URI.parse(Rails.configuration.x.streaming_api_base_url) + request.host == base_url.host && request.port == (base_url.port || 80) + end + def streaming_api_url Addressable::URI.parse(request.url).tap do |uri| base_url = Addressable::URI.parse(Rails.configuration.x.streaming_api_base_url) diff --git a/app/helpers/languages_helper.rb b/app/helpers/languages_helper.rb index 0d4edceb7..87f0f288d 100644 --- a/app/helpers/languages_helper.rb +++ b/app/helpers/languages_helper.rb @@ -224,7 +224,7 @@ module LanguagesHelper 'en-GB': 'English (British)', 'es-AR': 'Español (Argentina)', 'es-MX': 'Español (México)', - 'fr-QC': 'Français (Canadien)', + 'fr-CA': 'Français (Canadien)', 'pt-BR': 'Português (Brasil)', 'pt-PT': 'Português (Portugal)', 'sr-Latn': 'Srpski (latinica)', diff --git a/app/javascript/mastodon/locales/fr-QC.json b/app/javascript/mastodon/locales/fr-CA.json similarity index 100% rename from app/javascript/mastodon/locales/fr-QC.json rename to app/javascript/mastodon/locales/fr-CA.json diff --git a/app/lib/settings/scoped_settings.rb b/app/lib/settings/scoped_settings.rb deleted file mode 100644 index 983865a68..000000000 --- a/app/lib/settings/scoped_settings.rb +++ /dev/null @@ -1,80 +0,0 @@ -# frozen_string_literal: true - -module Settings - class ScopedSettings - DEFAULTING_TO_UNSCOPED = %w( - flavour - skin - noindex - ).freeze - - def initialize(object) - @object = object - end - - def method_missing(method, *args) - method_name = method.to_s - # set a value for a variable - if method_name[-1] == '=' - var_name = method_name.sub('=', '') - value = args.first - self[var_name] = value - else - # retrieve a value - self[method_name] - end - end - - def respond_to_missing?(*) - true - end - - def all_as_records - vars = thing_scoped - records = vars.index_by(&:var) - - Setting.default_settings.each do |key, default_value| - next if records.key?(key) || default_value.is_a?(Hash) - - records[key] = Setting.new(var: key, value: default_value) - end - - records - end - - def []=(key, value) - key = key.to_s - record = thing_scoped.find_or_initialize_by(var: key) - record.update!(value: value) - - Rails.cache.write(Setting.cache_key(key, @object), value) - end - - def [](key) - Rails.cache.fetch(Setting.cache_key(key, @object)) do - db_val = thing_scoped.find_by(var: key.to_s) - if db_val - default_value = ScopedSettings.default_settings[key] - return default_value.with_indifferent_access.merge!(db_val.value) if default_value.is_a?(Hash) - - db_val.value - else - ScopedSettings.default_settings[key] - end - end - end - - class << self - def default_settings - defaulting = DEFAULTING_TO_UNSCOPED.index_with { |k| Setting[k] } - Setting.default_settings.merge!(defaulting) - end - end - - protected - - def thing_scoped - Setting.unscoped.where(thing_type: @object.class.base_class.to_s, thing_id: @object.id) - end - end -end diff --git a/app/models/setting.rb b/app/models/setting.rb index 3bdc6ffb4..6af7a98c6 100644 --- a/app/models/setting.rb +++ b/app/models/setting.rb @@ -13,49 +13,114 @@ # thing_id :bigint(8) # -class Setting < RailsSettings::Base - source Rails.root.join('config', 'settings.yml') +# This file is derived from a fork of the `rails-settings-cached` gem available at +# https://github.com/mastodon/rails-settings-cached/tree/v0.6.6-aliases-true, with +# the original available at: +# https://github.com/huacnlee/rails-settings-cached/tree/0.x + +# It is licensed as follows: + +# Copyright (c) 2006 Alex Wayne +# Some additional features added 2009 by Georg Ledermann + +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: + +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. + +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOa AND +# NONINFRINGEMENT. IN NO EVENT SaALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +class Setting < ApplicationRecord + after_commit :rewrite_cache, on: %i(create update) + after_commit :expire_cache, on: %i(destroy) + + # Settings are server-wide settings only, but they were previously + # used for users too. This can be dropped later with a database + # migration dropping any scoped setting. + default_scope { where(thing_type: nil, thing_id: nil) } + + class << self + # get or set a variable with the variable as the called method + # rubocop:disable Style/MissingRespondToMissing + def method_missing(method, *args) + # set a value for a variable + if method.end_with?('=') + var_name = method.to_s.chomp('=') + value = args.first + self[var_name] = value + else + # retrieve a value + self[method.to_s] + end + end + # rubocop:enable Style/MissingRespondToMissing + + def cache_prefix_by_startup + @cache_prefix_by_startup ||= Digest::MD5.hexdigest(default_settings.to_s) + end + + def cache_key(var_name) + "rails_settings_cached/#{cache_prefix_by_startup}/#{var_name}" + end + + def [](key) + Rails.cache.fetch(cache_key(key)) do + db_val = find_by(var: key) + db_val ? db_val.value : default_settings[key] + end + end + + # set a setting value by [] notation + def []=(var_name, value) + record = find_or_initialize_by(var: var_name.to_s) + record.value = value + record.save! + end + + def default_settings + return @default_settings if defined?(@default_settings) + + content = Rails.root.join('config', 'settings.yml').read + hash = content.empty? ? {} : YAML.safe_load(ERB.new(content).result, aliases: true).to_hash + @default_settings = (hash[Rails.env] || {}).freeze + end + end + + # get the value field, YAML decoded + def value + YAML.safe_load(self[:value], permitted_classes: [ActiveSupport::HashWithIndifferentAccess, Symbol]) if self[:value].present? + end + + # set the value field, YAML encoded + def value=(new_value) + self[:value] = new_value.to_yaml + end + + def rewrite_cache + Rails.cache.write(cache_key, value) + end + + def expire_cache + Rails.cache.delete(cache_key) + end + + def cache_key + self.class.cache_key(var) + end def to_param var end - - class << self - def [](key) - return super(key) unless rails_initialized? - - Rails.cache.fetch(cache_key(key, nil)) do - db_val = object(key) - - if db_val - default_value = default_settings[key] - - return default_value.with_indifferent_access.merge!(db_val.value) if default_value.is_a?(Hash) - - db_val.value - else - default_settings[key] - end - end - end - - def all_as_records - vars = thing_scoped - records = vars.index_by(&:var) - - default_settings.each do |key, default_value| - next if records.key?(key) || default_value.is_a?(Hash) - - records[key] = Setting.new(var: key, value: default_value) - end - - records - end - - def default_settings - return {} unless RailsSettings::Default.enabled? - - RailsSettings::Default.instance - end - end end diff --git a/app/models/user.rb b/app/models/user.rb index bf78b3f0f..56e575ca4 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -118,14 +118,15 @@ class User < ApplicationRecord scope :matches_email, ->(value) { where(arel_table[:email].matches("#{value}%")) } scope :matches_ip, ->(value) { left_joins(:ips).where('user_ips.ip <<= ?', value).group('users.id') } - before_validation :sanitize_languages before_validation :sanitize_role - before_validation :sanitize_time_zone - before_validation :sanitize_locale before_create :set_approved after_commit :send_pending_devise_notifications after_create_commit :trigger_webhooks + normalizes :locale, with: ->(locale) { I18n.available_locales.exclude?(locale.to_sym) ? nil : locale } + normalizes :time_zone, with: ->(time_zone) { ActiveSupport::TimeZone[time_zone].nil? ? nil : time_zone } + normalizes :chosen_languages, with: ->(chosen_languages) { chosen_languages.compact_blank.presence } + # This avoids a deprecation warning from Rails 5.1 # It seems possible that a future release of devise-two-factor will # handle this itself, and this can be removed from our User class. @@ -447,25 +448,10 @@ class User < ApplicationRecord @bypass_invite_request_check end - def sanitize_languages - return if chosen_languages.nil? - - chosen_languages.compact_blank! - self.chosen_languages = nil if chosen_languages.empty? - end - def sanitize_role self.role = nil if role.present? && role.everyone? end - def sanitize_time_zone - self.time_zone = nil if time_zone.present? && ActiveSupport::TimeZone[time_zone].nil? - end - - def sanitize_locale - self.locale = nil if locale.present? && I18n.available_locales.exclude?(locale.to_sym) - end - def prepare_new_user! BootstrapTimelineWorker.perform_async(account_id) ActivityTracker.increment('activity:accounts:local') diff --git a/app/views/auth/challenges/new.html.haml b/app/views/auth/challenges/new.html.haml index 4f21e4af6..50dcebb00 100644 --- a/app/views/auth/challenges/new.html.haml +++ b/app/views/auth/challenges/new.html.haml @@ -5,7 +5,11 @@ = f.input :return_to, as: :hidden .field-group - = f.input :current_password, wrapper: :with_block_label, input_html: { autocomplete: 'current-password', autofocus: true }, label: t('challenge.prompt'), required: true + = f.input :current_password, + input_html: { autocomplete: 'current-password', autofocus: true }, + label: t('challenge.prompt'), + required: true, + wrapper: :with_block_label .actions = f.button :button, t('challenge.confirm'), type: :submit diff --git a/app/views/auth/confirmations/new.html.haml b/app/views/auth/confirmations/new.html.haml index 0cb82a1f8..eaa9d9add 100644 --- a/app/views/auth/confirmations/new.html.haml +++ b/app/views/auth/confirmations/new.html.haml @@ -21,7 +21,13 @@ = render 'shared/error_messages', object: resource .fields-group - = f.input :email, autofocus: true, wrapper: :with_label, label: t('simple_form.labels.defaults.email'), input_html: { 'aria-label': t('simple_form.labels.defaults.email') }, readonly: current_user.present?, hint: current_user.present? && t('auth.confirmations.wrong_email_hint') + = f.input :email, + autofocus: true, + hint: current_user.present? && t('auth.confirmations.wrong_email_hint'), + input_html: { 'aria-label': t('simple_form.labels.defaults.email') }, + label: t('simple_form.labels.defaults.email'), + readonly: current_user.present?, + wrapper: :with_label .actions = f.button :button, t('auth.resend_confirmation'), type: :submit diff --git a/app/views/auth/passwords/edit.html.haml b/app/views/auth/passwords/edit.html.haml index b95a9b676..a75dc2d9f 100644 --- a/app/views/auth/passwords/edit.html.haml +++ b/app/views/auth/passwords/edit.html.haml @@ -8,9 +8,18 @@ = f.input :reset_password_token, as: :hidden .fields-group - = f.input :password, wrapper: :with_label, autofocus: true, label: t('simple_form.labels.defaults.new_password'), input_html: { 'aria-label': t('simple_form.labels.defaults.new_password'), autocomplete: 'new-password', minlength: User.password_length.first, maxlength: User.password_length.last }, required: true + = f.input :password, + autofocus: true, + input_html: { 'aria-label': t('simple_form.labels.defaults.new_password'), autocomplete: 'new-password', minlength: User.password_length.first, maxlength: User.password_length.last }, + label: t('simple_form.labels.defaults.new_password'), + required: true, + wrapper: :with_label .fields-group - = f.input :password_confirmation, wrapper: :with_label, label: t('simple_form.labels.defaults.confirm_new_password'), input_html: { 'aria-label': t('simple_form.labels.defaults.confirm_new_password'), autocomplete: 'new-password' }, required: true + = f.input :password_confirmation, + input_html: { 'aria-label': t('simple_form.labels.defaults.confirm_new_password'), autocomplete: 'new-password' }, + label: t('simple_form.labels.defaults.confirm_new_password'), + required: true, + wrapper: :with_label .actions = f.button :button, t('auth.set_new_password'), type: :submit diff --git a/app/views/auth/passwords/new.html.haml b/app/views/auth/passwords/new.html.haml index 10ad108ea..8d5adaf3b 100644 --- a/app/views/auth/passwords/new.html.haml +++ b/app/views/auth/passwords/new.html.haml @@ -5,7 +5,12 @@ = render 'shared/error_messages', object: resource .fields-group - = f.input :email, autofocus: true, wrapper: :with_label, label: t('simple_form.labels.defaults.email'), input_html: { 'aria-label': t('simple_form.labels.defaults.email') }, hint: false + = f.input :email, + autofocus: true, + hint: false, + input_html: { 'aria-label': t('simple_form.labels.defaults.email') }, + label: t('simple_form.labels.defaults.email'), + wrapper: :with_label .actions = f.button :button, t('auth.reset_password'), type: :submit diff --git a/app/views/auth/registrations/_account_warning.html.haml b/app/views/auth/registrations/_account_warning.html.haml index 40e7e1296..19e5746ff 100644 --- a/app/views/auth/registrations/_account_warning.html.haml +++ b/app/views/auth/registrations/_account_warning.html.haml @@ -5,7 +5,9 @@ = fa_icon 'warning' .log-entry__content .log-entry__title - = t('disputes.strikes.title', action: t(account_warning.action, scope: 'disputes.strikes.title_actions'), date: l(account_warning.created_at.to_date)) + = t 'disputes.strikes.title', + action: t(account_warning.action, scope: 'disputes.strikes.title_actions'), + date: l(account_warning.created_at.to_date) .log-entry__timestamp %time.formatted{ datetime: account_warning.created_at.iso8601 }= l(account_warning.created_at) diff --git a/app/views/auth/registrations/_session.html.haml b/app/views/auth/registrations/_session.html.haml index 28499a7c9..2fa7db70c 100644 --- a/app/views/auth/registrations/_session.html.haml +++ b/app/views/auth/registrations/_session.html.haml @@ -3,7 +3,9 @@ %span{ title: session.user_agent }< = fa_icon "#{session_device_icon(session)} fw", 'aria-label': session_device_icon(session)   - = t 'sessions.description', browser: t("sessions.browsers.#{session.browser}", default: session.browser.to_s), platform: t("sessions.platforms.#{session.platform}", default: session.platform.to_s) + = t 'sessions.description', + browser: t("sessions.browsers.#{session.browser}", default: session.browser.to_s), + platform: t("sessions.platforms.#{session.platform}", default: session.platform.to_s) %td %samp= session.ip %td diff --git a/app/views/auth/registrations/edit.html.haml b/app/views/auth/registrations/edit.html.haml index f5ef4e97e..48350f478 100644 --- a/app/views/auth/registrations/edit.html.haml +++ b/app/views/auth/registrations/edit.html.haml @@ -15,15 +15,33 @@ - if (!use_seamless_external_login? || resource.encrypted_password.present?) && !omniauth_only? .fields-row .fields-row__column.fields-group.fields-row__column-6 - = f.input :email, wrapper: :with_label, input_html: { 'aria-label': t('simple_form.labels.defaults.email') }, required: true, disabled: current_account.suspended? + = f.input :email, + disabled: current_account.suspended?, + input_html: { 'aria-label': t('simple_form.labels.defaults.email') }, + required: true, + wrapper: :with_label .fields-row__column.fields-group.fields-row__column-6 - = f.input :current_password, wrapper: :with_label, input_html: { 'aria-label': t('simple_form.labels.defaults.current_password'), autocomplete: 'current-password' }, required: true, disabled: current_account.suspended?, hint: false + = f.input :current_password, + disabled: current_account.suspended?, + hint: false, + input_html: { 'aria-label': t('simple_form.labels.defaults.current_password'), autocomplete: 'current-password' }, + required: true, + wrapper: :with_label .fields-row .fields-row__column.fields-group.fields-row__column-6 - = f.input :password, wrapper: :with_label, label: t('simple_form.labels.defaults.new_password'), input_html: { 'aria-label': t('simple_form.labels.defaults.new_password'), autocomplete: 'new-password', minlength: User.password_length.first, maxlength: User.password_length.last }, hint: t('simple_form.hints.defaults.password'), disabled: current_account.suspended? + = f.input :password, + disabled: current_account.suspended?, + hint: t('simple_form.hints.defaults.password'), + input_html: { 'aria-label': t('simple_form.labels.defaults.new_password'), autocomplete: 'new-password', minlength: User.password_length.first, maxlength: User.password_length.last }, + label: t('simple_form.labels.defaults.new_password'), + wrapper: :with_label .fields-row__column.fields-group.fields-row__column-6 - = f.input :password_confirmation, wrapper: :with_label, label: t('simple_form.labels.defaults.confirm_new_password'), input_html: { 'aria-label': t('simple_form.labels.defaults.confirm_new_password'), autocomplete: 'new-password' }, disabled: current_account.suspended? + = f.input :password_confirmation, + disabled: current_account.suspended?, + input_html: { 'aria-label': t('simple_form.labels.defaults.confirm_new_password'), autocomplete: 'new-password' }, + label: t('simple_form.labels.defaults.confirm_new_password'), + wrapper: :with_label .actions = f.button :button, t('generic.save_changes'), type: :submit, class: 'button', disabled: current_account.suspended? diff --git a/app/views/auth/registrations/new.html.haml b/app/views/auth/registrations/new.html.haml index 4cac7b51b..1e5aac297 100644 --- a/app/views/auth/registrations/new.html.haml +++ b/app/views/auth/registrations/new.html.haml @@ -19,25 +19,61 @@ .fields-group = f.simple_fields_for :account do |ff| - = ff.input :username, wrapper: :with_label, label: false, required: true, input_html: { 'aria-label': t('simple_form.labels.defaults.username'), autocomplete: 'off', placeholder: t('simple_form.labels.defaults.username'), pattern: '[a-zA-Z0-9_]+', maxlength: 30 }, append: "@#{site_hostname}" - = f.input :email, placeholder: t('simple_form.labels.defaults.email'), required: true, input_html: { 'aria-label': t('simple_form.labels.defaults.email'), autocomplete: 'username' }, hint: false - = f.input :password, placeholder: t('simple_form.labels.defaults.password'), required: true, input_html: { 'aria-label': t('simple_form.labels.defaults.password'), autocomplete: 'new-password', minlength: User.password_length.first, maxlength: User.password_length.last }, hint: false - = f.input :password_confirmation, placeholder: t('simple_form.labels.defaults.confirm_password'), required: true, input_html: { 'aria-label': t('simple_form.labels.defaults.confirm_password'), autocomplete: 'new-password' }, hint: false - = f.input :confirm_password, as: :string, placeholder: t('simple_form.labels.defaults.honeypot', label: t('simple_form.labels.defaults.password')), required: false, input_html: { 'aria-label': t('simple_form.labels.defaults.honeypot', label: t('simple_form.labels.defaults.password')), autocomplete: 'off' }, hint: false - = f.input :website, as: :url, wrapper: :with_label, label: t('simple_form.labels.defaults.honeypot', label: 'Website'), required: false, input_html: { 'aria-label': t('simple_form.labels.defaults.honeypot', label: 'Website'), autocomplete: 'off' } + = ff.input :username, + append: "@#{site_hostname}", + input_html: { 'aria-label': t('simple_form.labels.defaults.username'), autocomplete: 'off', placeholder: t('simple_form.labels.defaults.username'), pattern: '[a-zA-Z0-9_]+', maxlength: 30 }, + label: false, + required: true, + wrapper: :with_label + = f.input :email, + hint: false, + input_html: { 'aria-label': t('simple_form.labels.defaults.email'), autocomplete: 'username' }, + placeholder: t('simple_form.labels.defaults.email'), + required: true + = f.input :password, + hint: false, + input_html: { 'aria-label': t('simple_form.labels.defaults.password'), autocomplete: 'new-password', minlength: User.password_length.first, maxlength: User.password_length.last }, + placeholder: t('simple_form.labels.defaults.password'), + required: true + = f.input :password_confirmation, + hint: false, + input_html: { 'aria-label': t('simple_form.labels.defaults.confirm_password'), autocomplete: 'new-password' }, + placeholder: t('simple_form.labels.defaults.confirm_password'), + required: true + = f.input :confirm_password, + as: :string, + hint: false, + input_html: { 'aria-label': t('simple_form.labels.defaults.honeypot', label: t('simple_form.labels.defaults.password')), autocomplete: 'off' }, + placeholder: t('simple_form.labels.defaults.honeypot', label: t('simple_form.labels.defaults.password')), + required: false + = f.input :website, + as: :url, + input_html: { 'aria-label': t('simple_form.labels.defaults.honeypot', label: 'Website'), autocomplete: 'off' }, + label: t('simple_form.labels.defaults.honeypot', label: 'Website'), + required: false, + wrapper: :with_label - if approved_registrations? && @invite.blank? %p.lead= t('auth.sign_up.manual_review', domain: site_hostname) .fields-group = f.simple_fields_for :invite_request, resource.invite_request || resource.build_invite_request do |invite_request_fields| - = invite_request_fields.input :text, as: :text, wrapper: :with_block_label, required: Setting.require_invite_text, label: false, hint: false + = invite_request_fields.input :text, + as: :text, + hint: false, + label: false, + required: Setting.require_invite_text, + wrapper: :with_block_label = hidden_field_tag :accept, params[:accept] = f.input :invite_code, as: :hidden .fields-group - = f.input :agreement, as: :boolean, wrapper: :with_label, label: t('auth.privacy_policy_agreement_html', rules_path: about_more_path, privacy_policy_path: privacy_policy_path), required: true + = f.input :agreement, + as: :boolean, + label: t('auth.privacy_policy_agreement_html', rules_path: about_more_path, privacy_policy_path: privacy_policy_path), + required: true, + wrapper: :with_label .actions = f.button :button, @invite.present? ? t('auth.register') : sign_up_message, type: :submit diff --git a/app/views/auth/sessions/new.html.haml b/app/views/auth/sessions/new.html.haml index 7914e0157..89903581a 100644 --- a/app/views/auth/sessions/new.html.haml +++ b/app/views/auth/sessions/new.html.haml @@ -10,11 +10,25 @@ %p.lead= t('auth.sign_in.preamble_html', domain: site_hostname) .fields-group - if use_seamless_external_login? - = f.input :email, autofocus: true, wrapper: :with_label, label: t('simple_form.labels.defaults.username_or_email'), input_html: { 'aria-label': t('simple_form.labels.defaults.username_or_email') }, hint: false + = f.input :email, + autofocus: true, + hint: false, + input_html: { 'aria-label': t('simple_form.labels.defaults.username_or_email') }, + label: t('simple_form.labels.defaults.username_or_email'), + wrapper: :with_label - else - = f.input :email, autofocus: true, wrapper: :with_label, label: t('simple_form.labels.defaults.email'), input_html: { 'aria-label': t('simple_form.labels.defaults.email') }, hint: false + = f.input :email, + autofocus: true, + hint: false, + input_html: { 'aria-label': t('simple_form.labels.defaults.email') }, + label: t('simple_form.labels.defaults.email'), + wrapper: :with_label .fields-group - = f.input :password, wrapper: :with_label, label: t('simple_form.labels.defaults.password'), input_html: { 'aria-label': t('simple_form.labels.defaults.password'), autocomplete: 'current-password' }, hint: false + = f.input :password, + hint: false, + input_html: { 'aria-label': t('simple_form.labels.defaults.password'), autocomplete: 'current-password' }, + label: t('simple_form.labels.defaults.password'), + wrapper: :with_label .actions = f.button :button, t('auth.login'), type: :submit diff --git a/app/views/auth/sessions/two_factor/_otp_authentication_form.html.haml b/app/views/auth/sessions/two_factor/_otp_authentication_form.html.haml index 8cc2c8561..30e97a68c 100644 --- a/app/views/auth/sessions/two_factor/_otp_authentication_form.html.haml +++ b/app/views/auth/sessions/two_factor/_otp_authentication_form.html.haml @@ -5,7 +5,12 @@ %p.hint.authentication-hint= t('simple_form.hints.sessions.otp') .fields-group - = f.input :otp_attempt, type: :number, wrapper: :with_label, label: t('simple_form.labels.defaults.otp_attempt'), input_html: { 'aria-label': t('simple_form.labels.defaults.otp_attempt'), autocomplete: 'one-time-code' }, autofocus: true + = f.input :otp_attempt, + autofocus: true, + input_html: { 'aria-label': t('simple_form.labels.defaults.otp_attempt'), autocomplete: 'one-time-code' }, + label: t('simple_form.labels.defaults.otp_attempt'), + type: :number, + wrapper: :with_label .actions = f.button :button, t('auth.login'), type: :submit diff --git a/app/views/auth/setup/show.html.haml b/app/views/auth/setup/show.html.haml index ab9b00bed..097e3416e 100644 --- a/app/views/auth/setup/show.html.haml +++ b/app/views/auth/setup/show.html.haml @@ -14,7 +14,10 @@ %p.lead= t('auth.setup.email_below_hint_html') .fields-group - = f.input :email, required: true, hint: false, input_html: { 'aria-label': t('simple_form.labels.defaults.email'), autocomplete: 'off' } + = f.input :email, + hint: false, + input_html: { 'aria-label': t('simple_form.labels.defaults.email'), autocomplete: 'off' }, + required: true .actions = f.button :button, t('auth.resend_confirmation'), type: :submit, class: 'button timer-button', disabled: true diff --git a/app/views/media/player.html.haml b/app/views/media/player.html.haml index d34e15538..d4e3c1cfa 100644 --- a/app/views/media/player.html.haml +++ b/app/views/media/player.html.haml @@ -13,14 +13,39 @@ meta = @media_attachment.file.meta || {} - if @media_attachment.video? - = react_component :video, src: @media_attachment.file.url(:original), preview: @media_attachment.thumbnail.present? ? @media_attachment.thumbnail.url : @media_attachment.file.url(:small), frameRate: meta.dig('original', 'frame_rate'), blurhash: @media_attachment.blurhash, width: 670, height: 380, editable: true, detailed: true, inline: true, alt: @media_attachment.description, media: [ActiveModelSerializers::SerializableResource.new(@media_attachment, serializer: REST::MediaAttachmentSerializer)].as_json do + = react_component :video, + alt: @media_attachment.description, + blurhash: @media_attachment.blurhash, + detailed: true, + editable: true, + frameRate: meta.dig('original', 'frame_rate'), + height: 380, + inline: true, + media: [ActiveModelSerializers::SerializableResource.new(@media_attachment, serializer: REST::MediaAttachmentSerializer)].as_json, + preview: @media_attachment.thumbnail.present? ? @media_attachment.thumbnail.url : @media_attachment.file.url(:small), + src: @media_attachment.file.url(:original), + width: 670 do %video{ controls: 'controls' } %source{ src: @media_attachment.file.url(:original) } - elsif @media_attachment.gifv? - = react_component :media_gallery, height: 380, standalone: true, autoplay: true, media: [ActiveModelSerializers::SerializableResource.new(@media_attachment, serializer: REST::MediaAttachmentSerializer).as_json] do + = react_component :media_gallery, + autoplay: true, + height: 380, + media: [ActiveModelSerializers::SerializableResource.new(@media_attachment, serializer: REST::MediaAttachmentSerializer).as_json], + standalone: true do %video{ autoplay: 'autoplay', muted: 'muted', loop: 'loop' } %source{ src: @media_attachment.file.url(:original) } - elsif @media_attachment.audio? - = react_component :audio, src: @media_attachment.file.url(:original), poster: @media_attachment.thumbnail.present? ? @media_attachment.thumbnail.url : @media_attachment.account.avatar_static_url, backgroundColor: meta.dig('colors', 'background'), foregroundColor: meta.dig('colors', 'foreground'), accentColor: meta.dig('colors', 'accent'), width: 670, height: 380, fullscreen: true, alt: @media_attachment.description, duration: meta.dig(:original, :duration) do + = react_component :audio, + accentColor: meta.dig('colors', 'accent'), + alt: @media_attachment.description, + backgroundColor: meta.dig('colors', 'background'), + duration: meta.dig(:original, :duration), + foregroundColor: meta.dig('colors', 'foreground'), + fullscreen: true, + height: 380, + poster: @media_attachment.thumbnail.present? ? @media_attachment.thumbnail.url : @media_attachment.account.avatar_static_url, + src: @media_attachment.file.url(:original), + width: 670 do %audio{ controls: 'controls' } %source{ src: @media_attachment.file.url(:original) } diff --git a/app/views/settings/applications/_fields.html.haml b/app/views/settings/applications/_fields.html.haml index 29e2bcb5a..ed97e880f 100644 --- a/app/views/settings/applications/_fields.html.haml +++ b/app/views/settings/applications/_fields.html.haml @@ -1,11 +1,17 @@ .fields-group - = f.input :name, wrapper: :with_label, label: t('activerecord.attributes.doorkeeper/application.name') + = f.input :name, + label: t('activerecord.attributes.doorkeeper/application.name'), + wrapper: :with_label .fields-group - = f.input :website, wrapper: :with_label, label: t('activerecord.attributes.doorkeeper/application.website') + = f.input :website, + label: t('activerecord.attributes.doorkeeper/application.website'), + wrapper: :with_label .fields-group - = f.input :redirect_uri, wrapper: :with_block_label, label: t('activerecord.attributes.doorkeeper/application.redirect_uri'), hint: t('doorkeeper.applications.help.redirect_uri') + = f.input :redirect_uri, + label: t('activerecord.attributes.doorkeeper/application.redirect_uri'), hint: t('doorkeeper.applications.help.redirect_uri'), + wrapper: :with_block_label %p.hint= t('doorkeeper.applications.help.native_redirect_uri', native_redirect_uri: content_tag(:code, Doorkeeper.configuration.native_redirect_uri)).html_safe @@ -15,4 +21,15 @@ %span.hint= t('simple_form.hints.defaults.scopes') - Doorkeeper.configuration.scopes.group_by { |s| s.split(':').first }.each_value do |value| - = f.input :scopes, label: false, hint: false, collection: value.sort, wrapper: :with_block_label, include_blank: false, label_method: ->(scope) { safe_join([content_tag(:samp, scope, class: class_for_scope(scope)), content_tag(:span, t("doorkeeper.scopes.#{scope}"), class: 'hint')]) }, selected: f.object.scopes.all, required: false, as: :check_boxes, collection_wrapper_tag: 'ul', item_wrapper_tag: 'li' + = f.input :scopes, + as: :check_boxes, + collection_wrapper_tag: 'ul', + collection: value.sort, + hint: false, + include_blank: false, + item_wrapper_tag: 'li', + label_method: ->(scope) { safe_join([content_tag(:samp, scope, class: class_for_scope(scope)), content_tag(:span, t("doorkeeper.scopes.#{scope}"), class: 'hint')]) }, + label: false, + required: false, + selected: f.object.scopes.all, + wrapper: :with_block_label diff --git a/app/views/settings/featured_tags/index.html.haml b/app/views/settings/featured_tags/index.html.haml index 387eb290e..22f918012 100644 --- a/app/views/settings/featured_tags/index.html.haml +++ b/app/views/settings/featured_tags/index.html.haml @@ -11,7 +11,9 @@ %p.lead= t('featured_tags.hint_html') .fields-group - = f.input :name, wrapper: :with_block_label, hint: safe_join([t('simple_form.hints.featured_tag.name'), safe_join(@recently_used_tags.map { |tag| link_to("##{tag.display_name}", settings_featured_tags_path(featured_tag: { name: tag.name }), method: :post) }, ', ')], ' ') + = f.input :name, + hint: safe_join([t('simple_form.hints.featured_tag.name'), safe_join(@recently_used_tags.map { |tag| link_to("##{tag.display_name}", settings_featured_tags_path(featured_tag: { name: tag.name }), method: :post) }, ', ')], ' '), + wrapper: :with_block_label .actions = f.button :button, t('featured_tags.add_new'), type: :submit diff --git a/app/views/settings/imports/index.html.haml b/app/views/settings/imports/index.html.haml index 5f7950b59..d5ca252dc 100644 --- a/app/views/settings/imports/index.html.haml +++ b/app/views/settings/imports/index.html.haml @@ -3,13 +3,29 @@ = simple_form_for @import, url: settings_imports_path do |f| .field-group - = f.input :type, as: :grouped_select, collection: { constructive: %i(following bookmarks lists), destructive: %i(muting blocking domain_blocking) }, wrapper: :with_block_label, include_blank: false, label_method: ->(type) { I18n.t("imports.types.#{type}") }, group_label_method: ->(group) { I18n.t("imports.type_groups.#{group.first}") }, group_method: :last, hint: t('imports.preface') + = f.input :type, + as: :grouped_select, + collection: { constructive: %i(following bookmarks lists), destructive: %i(muting blocking domain_blocking) }, + group_label_method: ->(group) { I18n.t("imports.type_groups.#{group.first}") }, + group_method: :last, + hint: t('imports.preface'), + include_blank: false, + label_method: ->(type) { I18n.t("imports.types.#{type}") }, + wrapper: :with_block_label .fields-row .fields-group.fields-row__column.fields-row__column-6 - = f.input :data, as: :file, wrapper: :with_block_label, hint: t('simple_form.hints.imports.data') + = f.input :data, + as: :file, + hint: t('simple_form.hints.imports.data'), + wrapper: :with_block_label .fields-group.fields-row__column.fields-row__column-6 - = f.input :mode, as: :radio_buttons, collection: Import::MODES, label_method: ->(mode) { safe_join([I18n.t("imports.modes.#{mode}"), content_tag(:span, I18n.t("imports.modes.#{mode}_long"), class: 'hint')]) }, collection_wrapper_tag: 'ul', item_wrapper_tag: 'li' + = f.input :mode, + as: :radio_buttons, + collection_wrapper_tag: 'ul', + collection: Import::MODES, + item_wrapper_tag: 'li', + label_method: ->(mode) { safe_join([I18n.t("imports.modes.#{mode}"), content_tag(:span, I18n.t("imports.modes.#{mode}_long"), class: 'hint')]) } .actions = f.button :button, t('imports.upload'), type: :submit diff --git a/app/views/settings/migration/redirects/new.html.haml b/app/views/settings/migration/redirects/new.html.haml index 370087879..731acb9db 100644 --- a/app/views/settings/migration/redirects/new.html.haml +++ b/app/views/settings/migration/redirects/new.html.haml @@ -15,7 +15,11 @@ .fields-row .fields-row__column.fields-group.fields-row__column-6 - = f.input :acct, wrapper: :with_block_label, input_html: { autocapitalize: 'none', autocorrect: 'off' }, label: t('simple_form.labels.account_migration.acct'), hint: t('simple_form.hints.account_migration.acct') + = f.input :acct, + hint: t('simple_form.hints.account_migration.acct'), + input_html: { autocapitalize: 'none', autocorrect: 'off' }, + label: t('simple_form.labels.account_migration.acct'), + wrapper: :with_block_label .fields-row__column.fields-group.fields-row__column-6 - if current_user.encrypted_password.present? diff --git a/app/views/settings/preferences/appearance/show.html.haml b/app/views/settings/preferences/appearance/show.html.haml index 959b72361..f7b244ca0 100644 --- a/app/views/settings/preferences/appearance/show.html.haml +++ b/app/views/settings/preferences/appearance/show.html.haml @@ -7,9 +7,18 @@ = simple_form_for current_user, url: settings_preferences_appearance_path, html: { method: :put, id: 'edit_user' } do |f| .fields-row .fields-group.fields-row__column.fields-row__column-6 - = f.input :locale, collection: ui_languages, wrapper: :with_label, include_blank: false, label_method: ->(locale) { native_locale_name(locale) }, selected: I18n.locale, hint: false + = f.input :locale, + collection: ui_languages, + hint: false, + include_blank: false, + label_method: ->(locale) { native_locale_name(locale) }, + selected: I18n.locale, + wrapper: :with_label .fields-group.fields-row__column.fields-row__column-6 - = f.input :time_zone, wrapper: :with_label, collection: ActiveSupport::TimeZone.all.map { |tz| ["(GMT#{tz.formatted_offset}) #{tz.name}", tz.tzinfo.name] }, hint: false + = f.input :time_zone, + collection: ActiveSupport::TimeZone.all.map { |tz| ["(GMT#{tz.formatted_offset}) #{tz.name}", tz.tzinfo.name] }, + hint: false, + wrapper: :with_label - unless I18n.locale == :en .flash-message.translation-prompt @@ -23,11 +32,17 @@ %p.hint= t 'appearance.advanced_web_interface_hint' .fields-group - = ff.input :'web.advanced_layout', wrapper: :with_label, hint: false, label: I18n.t('simple_form.labels.defaults.setting_advanced_layout') + = ff.input :'web.advanced_layout', + hint: false, + label: I18n.t('simple_form.labels.defaults.setting_advanced_layout'), + wrapper: :with_label %h4= t 'appearance.animations_and_accessibility' .fields-group - = ff.input :'web.use_pending_items', wrapper: :with_label, label: I18n.t('simple_form.labels.defaults.setting_use_pending_items'), hint: I18n.t('simple_form.hints.defaults.setting_use_pending_items') + = ff.input :'web.use_pending_items', + hint: I18n.t('simple_form.hints.defaults.setting_use_pending_items'), + label: I18n.t('simple_form.labels.defaults.setting_use_pending_items'), + wrapper: :with_label .fields-group = ff.input :'web.auto_play', wrapper: :with_label, recommended: true, label: I18n.t('simple_form.labels.defaults.setting_auto_play_gif') @@ -52,10 +67,21 @@ %h4= t 'appearance.sensitive_content' .fields-group - = ff.input :'web.display_media', collection: %w(default show_all hide_all), label_method: ->(item) { t("simple_form.hints.defaults.setting_display_media_#{item}") }, hint: false, as: :radio_buttons, collection_wrapper_tag: 'ul', item_wrapper_tag: 'li', wrapper: :with_floating_label, label: I18n.t('simple_form.labels.defaults.setting_display_media') + = ff.input :'web.display_media', + as: :radio_buttons, + collection_wrapper_tag: 'ul', + collection: %w(default show_all hide_all), + hint: false, + item_wrapper_tag: 'li', + label_method: ->(item) { t("simple_form.hints.defaults.setting_display_media_#{item}") }, + label: I18n.t('simple_form.labels.defaults.setting_display_media'), + wrapper: :with_floating_label .fields-group - = ff.input :'web.use_blurhash', wrapper: :with_label, label: I18n.t('simple_form.labels.defaults.setting_use_blurhash'), hint: I18n.t('simple_form.hints.defaults.setting_use_blurhash') + = ff.input :'web.use_blurhash', + hint: I18n.t('simple_form.hints.defaults.setting_use_blurhash'), + label: I18n.t('simple_form.labels.defaults.setting_use_blurhash'), + wrapper: :with_label .fields-group = ff.input :'web.expand_content_warnings', wrapper: :with_label, label: I18n.t('simple_form.labels.defaults.setting_expand_spoilers') diff --git a/app/views/settings/preferences/other/show.html.haml b/app/views/settings/preferences/other/show.html.haml index fe1cdbf48..49d03ca00 100644 --- a/app/views/settings/preferences/other/show.html.haml +++ b/app/views/settings/preferences/other/show.html.haml @@ -9,27 +9,66 @@ = f.simple_fields_for :settings, current_user.settings do |ff| .fields-group - = ff.input :aggregate_reblogs, wrapper: :with_label, recommended: true, label: I18n.t('simple_form.labels.defaults.setting_aggregate_reblogs'), hint: I18n.t('simple_form.hints.defaults.setting_aggregate_reblogs') + = ff.input :aggregate_reblogs, + hint: I18n.t('simple_form.hints.defaults.setting_aggregate_reblogs'), + label: I18n.t('simple_form.labels.defaults.setting_aggregate_reblogs'), + recommended: true, + wrapper: :with_label %h4= t 'preferences.posting_defaults' .fields-row .fields-group.fields-row__column.fields-row__column-6 - = ff.input :default_privacy, collection: Status.selectable_visibilities, wrapper: :with_label, include_blank: false, label_method: ->(visibility) { safe_join([I18n.t("statuses.visibilities.#{visibility}"), I18n.t("statuses.visibilities.#{visibility}_long")], ' - ') }, required: false, hint: false, label: I18n.t('simple_form.labels.defaults.setting_default_privacy') + = ff.input :default_privacy, + collection: Status.selectable_visibilities, + hint: false, + include_blank: false, + label_method: ->(visibility) { safe_join([I18n.t("statuses.visibilities.#{visibility}"), I18n.t("statuses.visibilities.#{visibility}_long")], ' - ') }, + label: I18n.t('simple_form.labels.defaults.setting_default_privacy'), + required: false, + wrapper: :with_label .fields-group.fields-row__column.fields-row__column-6 - = ff.input :default_language, collection: [nil] + filterable_languages, wrapper: :with_label, label_method: ->(locale) { locale.nil? ? I18n.t('statuses.default_language') : native_locale_name(locale) }, required: false, include_blank: false, hint: false, label: I18n.t('simple_form.labels.defaults.setting_default_language') + = ff.input :default_language, + collection: [nil] + filterable_languages, + hint: false, + include_blank: false, + label_method: ->(locale) { locale.nil? ? I18n.t('statuses.default_language') : native_locale_name(locale) }, + label: I18n.t('simple_form.labels.defaults.setting_default_language'), + required: false, + wrapper: :with_label .fields-group - = ff.input :default_sensitive, wrapper: :with_label, label: I18n.t('simple_form.labels.defaults.setting_default_sensitive'), hint: I18n.t('simple_form.hints.defaults.setting_default_sensitive') + = ff.input :default_sensitive, + hint: I18n.t('simple_form.hints.defaults.setting_default_sensitive'), + label: I18n.t('simple_form.labels.defaults.setting_default_sensitive'), + wrapper: :with_label .fields-group - = ff.input :default_content_type, collection: ['text/plain', 'text/markdown', 'text/html'], wrapper: :with_label, label: I18n.t('simple_form.labels.defaults.setting_default_content_type'), include_blank: false, label_method: ->(item) { safe_join([t("simple_form.labels.defaults.setting_default_content_type_#{item.split('/')[1]}"), content_tag(:span, t("simple_form.hints.defaults.setting_default_content_type_#{item.split('/')[1]}"), class: 'hint')]) }, required: false, as: :radio_buttons, collection_wrapper_tag: 'ul', item_wrapper_tag: 'li', glitch_only: true + = ff.input :default_content_type, + collection: %w(text/plain text/markdown text/html), + wrapper: :with_label, + label: I18n.t('simple_form.labels.defaults.setting_default_content_type'), + include_blank: false, + label_method: ->(item) { safe_join([t("simple_form.labels.defaults.setting_default_content_type_#{item.split('/')[1]}"), content_tag(:span, t("simple_form.hints.defaults.setting_default_content_type_#{item.split('/')[1]}"), class: 'hint')]) }, + required: false, + as: :radio_buttons, + collection_wrapper_tag: 'ul', + item_wrapper_tag: 'li', + glitch_only: true %h4= t 'preferences.public_timelines' .fields-group - = f.input :chosen_languages, collection: filterable_languages, wrapper: :with_block_label, include_blank: false, label_method: ->(locale) { native_locale_name(locale) }, required: false, as: :check_boxes, collection_wrapper_tag: 'ul', item_wrapper_tag: 'li' + = f.input :chosen_languages, + as: :check_boxes, + collection_wrapper_tag: 'ul', + collection: filterable_languages, + include_blank: false, + item_wrapper_tag: 'li', + label_method: ->(locale) { native_locale_name(locale) }, + required: false, + wrapper: :with_block_label .actions = f.button :button, t('generic.save_changes'), type: :submit diff --git a/app/views/settings/profiles/show.html.haml b/app/views/settings/profiles/show.html.haml index fbd36b7f5..3e8daee60 100644 --- a/app/views/settings/profiles/show.html.haml +++ b/app/views/settings/profiles/show.html.haml @@ -33,7 +33,10 @@ .fields-row .fields-row__column.fields-row__column-6 .fields-group - = f.input :avatar, wrapper: :with_block_label, input_html: { accept: Account::Avatar::IMAGE_MIME_TYPES.join(',') }, hint: t('simple_form.hints.defaults.avatar', dimensions: '400x400', size: number_to_human_size(Account::Avatar::LIMIT)) + = f.input :avatar, + hint: t('simple_form.hints.defaults.avatar', dimensions: '400x400', size: number_to_human_size(Account::Avatar::LIMIT)), + input_html: { accept: Account::Avatar::IMAGE_MIME_TYPES.join(',') }, + wrapper: :with_block_label .fields-row__column.fields-row__column-6 .fields-group @@ -46,7 +49,10 @@ .fields-row .fields-row__column.fields-row__column-6 .fields-group - = f.input :header, wrapper: :with_block_label, input_html: { accept: Account::Header::IMAGE_MIME_TYPES.join(',') }, hint: t('simple_form.hints.defaults.header', dimensions: '1500x500', size: number_to_human_size(Account::Header::LIMIT)) + = f.input :header, + hint: t('simple_form.hints.defaults.header', dimensions: '1500x500', size: number_to_human_size(Account::Header::LIMIT)), + input_html: { accept: Account::Header::IMAGE_MIME_TYPES.join(',') }, + wrapper: :with_block_label .fields-row__column.fields-row__column-6 .fields-group diff --git a/app/views/settings/two_factor_authentication/confirmations/new.html.haml b/app/views/settings/two_factor_authentication/confirmations/new.html.haml index 43830ac27..0b8278a10 100644 --- a/app/views/settings/two_factor_authentication/confirmations/new.html.haml +++ b/app/views/settings/two_factor_authentication/confirmations/new.html.haml @@ -12,7 +12,12 @@ %samp.qr-alternative__code= @new_otp_secret.scan(/.{4}/).join(' ') .fields-group - = f.input :otp_attempt, wrapper: :with_label, hint: t('otp_authentication.code_hint'), label: t('simple_form.labels.defaults.otp_attempt'), input_html: { autocomplete: 'off' }, required: true + = f.input :otp_attempt, + hint: t('otp_authentication.code_hint'), + input_html: { autocomplete: 'off' }, + label: t('simple_form.labels.defaults.otp_attempt'), + required: true, + wrapper: :with_label .actions = f.button :button, t('otp_authentication.enable'), type: :submit diff --git a/config/initializers/i18n.rb b/config/initializers/i18n.rb index 39b7a3cc4..1c1cea1b9 100644 --- a/config/initializers/i18n.rb +++ b/config/initializers/i18n.rb @@ -31,7 +31,7 @@ Rails.application.configure do :fi, :fo, :fr, - :'fr-QC', + :'fr-CA', :fy, :ga, :gd, diff --git a/config/initializers/new_framework_defaults_7_1.rb b/config/initializers/new_framework_defaults_7_1.rb index 1475fe2fd..bcc300c89 100644 --- a/config/initializers/new_framework_defaults_7_1.rb +++ b/config/initializers/new_framework_defaults_7_1.rb @@ -29,7 +29,7 @@ Rails.application.config.add_autoload_paths_to_load_path = false # Do not treat an `ActionController::Parameters` instance # as equal to an equivalent `Hash` by default. -# Rails.application.config.action_controller.allow_deprecated_parameters_hash_equality = false +Rails.application.config.action_controller.allow_deprecated_parameters_hash_equality = false # Active Record Encryption now uses SHA-256 as its hash digest algorithm. Important: If you have # data encrypted with previous Rails versions, there are two scenarios to consider: @@ -50,7 +50,7 @@ Rails.application.config.add_autoload_paths_to_load_path = false # Instead, run these callbacks on the instance most likely to have internal # state which matches what was committed to the database, typically the last # instance to save. -# Rails.application.config.active_record.run_commit_callbacks_on_first_saved_instances_in_transaction = false +Rails.application.config.active_record.run_commit_callbacks_on_first_saved_instances_in_transaction = false # Configures SQLite with a strict strings mode, which disables double-quoted string literals. # @@ -59,10 +59,10 @@ Rails.application.config.add_autoload_paths_to_load_path = false # it then considers them as string literals. Because of this, typos can silently go unnoticed. # For example, it is possible to create an index for a non existing column. # See https://www.sqlite.org/quirks.html#double_quoted_string_literals_are_accepted for more details. -# Rails.application.config.active_record.sqlite3_adapter_strict_strings_by_default = true +Rails.application.config.active_record.sqlite3_adapter_strict_strings_by_default = true # Disable deprecated singular associations names -# Rails.application.config.active_record.allow_deprecated_singular_associations_name = false +Rails.application.config.active_record.allow_deprecated_singular_associations_name = false # Enable the Active Job `BigDecimal` argument serializer, which guarantees # roundtripping. Without this serializer, some queue adapters may serialize @@ -78,12 +78,12 @@ Rails.application.config.add_autoload_paths_to_load_path = false # `write` are given an invalid `expires_at` or `expires_in` time. # Options are `true`, and `false`. If `false`, the exception will be reported # as `handled` and logged instead. -# Rails.application.config.active_support.raise_on_invalid_cache_expiration_time = true +Rails.application.config.active_support.raise_on_invalid_cache_expiration_time = true # Specify whether Query Logs will format tags using the SQLCommenter format # (https://open-telemetry.github.io/opentelemetry-sqlcommenter/), or using the legacy format. # Options are `:legacy` and `:sqlcommenter`. -# Rails.application.config.active_record.query_log_tags_format = :sqlcommenter +Rails.application.config.active_record.query_log_tags_format = :sqlcommenter # Specify the default serializer used by `MessageEncryptor` and `MessageVerifier` # instances. @@ -129,39 +129,37 @@ Rails.application.config.add_autoload_paths_to_load_path = false # `config.load_defaults 7.1` does not set this value for environments other than # development and test. # -# if Rails.env.local? -# Rails.application.config.log_file_size = 100 * 1024 * 1024 -# end +Rails.application.config.log_file_size = 100 * 1024 * 1024 if Rails.env.local? # Enable raising on assignment to attr_readonly attributes. The previous # behavior would allow assignment but silently not persist changes to the # database. -# Rails.application.config.active_record.raise_on_assign_to_attr_readonly = true +Rails.application.config.active_record.raise_on_assign_to_attr_readonly = true # Enable validating only parent-related columns for presence when the parent is mandatory. # The previous behavior was to validate the presence of the parent record, which performed an extra query # to get the parent every time the child record was updated, even when parent has not changed. -# Rails.application.config.active_record.belongs_to_required_validates_foreign_key = false +Rails.application.config.active_record.belongs_to_required_validates_foreign_key = false # Enable precompilation of `config.filter_parameters`. Precompilation can # improve filtering performance, depending on the quantity and types of filters. -# Rails.application.config.precompile_filter_parameters = true +Rails.application.config.precompile_filter_parameters = true # Enable before_committed! callbacks on all enrolled records in a transaction. # The previous behavior was to only run the callbacks on the first copy of a record # if there were multiple copies of the same record enrolled in the transaction. -# Rails.application.config.active_record.before_committed_on_all_records = true +Rails.application.config.active_record.before_committed_on_all_records = true # Disable automatic column serialization into YAML. # To keep the historic behavior, you can set it to `YAML`, however it is # recommended to explicitly define the serialization method for each column # rather than to rely on a global default. -# Rails.application.config.active_record.default_column_serializer = nil +Rails.application.config.active_record.default_column_serializer = nil # Run `after_commit` and `after_*_commit` callbacks in the order they are defined in a model. # This matches the behaviour of all other callbacks. # In previous versions of Rails, they ran in the inverse order. -# Rails.application.config.active_record.run_after_transaction_callbacks_in_order_defined = true +Rails.application.config.active_record.run_after_transaction_callbacks_in_order_defined = true # Whether a `transaction` block is committed or rolled back when exited via `return`, `break` or `throw`. # @@ -169,7 +167,7 @@ Rails.application.config.add_autoload_paths_to_load_path = false # Controls when to generate a value for has_secure_token declarations. # -# Rails.application.config.active_record.generate_secure_token_on = :initialize +Rails.application.config.active_record.generate_secure_token_on = :initialize # ** Please read carefully, this must be configured in config/application.rb ** # Change the format of the cache entry. @@ -190,7 +188,7 @@ Rails.application.config.add_autoload_paths_to_load_path = false # # In previous versions of Rails, Action View always used `Rails::HTML4::Sanitizer` as its vendor. # -# Rails.application.config.action_view.sanitizer_vendor = Rails::HTML::Sanitizer.best_supported_vendor +Rails.application.config.action_view.sanitizer_vendor = Rails::HTML::Sanitizer.best_supported_vendor # Configure Action Text to use an HTML5 standards-compliant sanitizer when it is supported on your # platform. @@ -213,4 +211,4 @@ Rails.application.config.add_autoload_paths_to_load_path = false # # In previous versions of Rails, these test helpers always used an HTML4 parser. # -# Rails.application.config.dom_testing_default_html_version = :html5 +Rails.application.config.dom_testing_default_html_version = :html5 diff --git a/config/locales/activerecord.fr-QC.yml b/config/locales/activerecord.fr-CA.yml similarity index 99% rename from config/locales/activerecord.fr-QC.yml rename to config/locales/activerecord.fr-CA.yml index 607758add..1a83a0e9e 100644 --- a/config/locales/activerecord.fr-QC.yml +++ b/config/locales/activerecord.fr-CA.yml @@ -1,5 +1,5 @@ --- -fr-QC: +fr-CA: activerecord: attributes: poll: diff --git a/config/locales/devise.fr-QC.yml b/config/locales/devise.fr-CA.yml similarity index 96% rename from config/locales/devise.fr-QC.yml rename to config/locales/devise.fr-CA.yml index 8c1a94dab..e9f09a698 100644 --- a/config/locales/devise.fr-QC.yml +++ b/config/locales/devise.fr-CA.yml @@ -1,5 +1,5 @@ --- -fr-QC: +fr-CA: devise: confirmations: confirmed: Votre adresse de courriel a été validée avec succès. @@ -20,8 +20,8 @@ fr-QC: confirmation_instructions: action: Vérifier l’adresse courriel action_with_app: Confirmer et retourner à %{app} - explanation: Vous avez créé un compte sur %{host} avec cette adresse courriel. Vous êtes à un clic de l’activer. Si ce n'était pas vous, veuiller ignorer ce courriel. - explanation_when_pending: Vous avez demandé à vous inscrire à %{host} avec cette adresse courriel. Une fois que vous aurez confirmé cette adresse, nous étudierons votre demande. Vous pouvez vous connecter pour changer vos détails ou supprimer votre compte, mais vous ne pouvez pas accéder à la plupart des fonctionalités du compte avant que votre compte ne soit approuvé. Si votre demande est rejetée, vos données seront supprimées, donc aucune action supplémentaire ne sera requise de votre part. Si ce n'était pas vous, veuiller ignorer ce courriel. + explanation: Vous avez créé un compte sur %{host} avec cette adresse courriel. Vous êtes à un clic de l’activer. Si ce n'était pas vous, veuillez ignorer ce courriel. + explanation_when_pending: Vous avez demandé à vous inscrire à %{host} avec cette adresse courriel. Une fois que vous aurez confirmé cette adresse, nous étudierons votre demande. Vous pouvez vous connecter pour changer vos détails ou supprimer votre compte, mais vous ne pouvez pas accéder à la plupart des fonctionnalités du compte avant que votre compte ne soit approuvé. Si votre demande est rejetée, vos données seront supprimées, donc aucune action supplémentaire ne sera requise de votre part. Si ce n'était pas vous, veuillez ignorer ce courriel. extra_html: Veuillez également consulter les règles du serveur et nos conditions d’utilisation. subject: 'Mastodon: Instructions de confirmation pour %{instance}' title: Vérifier l’adresse courriel diff --git a/config/locales/doorkeeper.fr-QC.yml b/config/locales/doorkeeper.fr-CA.yml similarity index 99% rename from config/locales/doorkeeper.fr-QC.yml rename to config/locales/doorkeeper.fr-CA.yml index 043b4a6cd..9d671569f 100644 --- a/config/locales/doorkeeper.fr-QC.yml +++ b/config/locales/doorkeeper.fr-CA.yml @@ -1,5 +1,5 @@ --- -fr-QC: +fr-CA: activerecord: attributes: doorkeeper/application: diff --git a/config/locales/fr-QC.yml b/config/locales/fr-CA.yml similarity index 99% rename from config/locales/fr-QC.yml rename to config/locales/fr-CA.yml index 3d85ced15..c43fa013c 100644 --- a/config/locales/fr-QC.yml +++ b/config/locales/fr-CA.yml @@ -1,5 +1,5 @@ --- -fr-QC: +fr-CA: about: about_mastodon_html: 'Le réseau social de l''avenir : pas de publicité, pas de surveillance institutionnelle, conception éthique et décentralisation ! Gardez le contrôle de vos données avec Mastodon !' contact_missing: Non défini diff --git a/config/locales/simple_form.fr-QC.yml b/config/locales/simple_form.fr-CA.yml similarity index 99% rename from config/locales/simple_form.fr-QC.yml rename to config/locales/simple_form.fr-CA.yml index 7a95a1c88..f5a2a428e 100644 --- a/config/locales/simple_form.fr-QC.yml +++ b/config/locales/simple_form.fr-CA.yml @@ -1,5 +1,5 @@ --- -fr-QC: +fr-CA: simple_form: hints: account: diff --git a/db/migrate/20170716191202_add_hide_notifications_to_mute.rb b/db/migrate/20170716191202_add_hide_notifications_to_mute.rb index b817d512d..2ef5d2579 100644 --- a/db/migrate/20170716191202_add_hide_notifications_to_mute.rb +++ b/db/migrate/20170716191202_add_hide_notifications_to_mute.rb @@ -1,14 +1,10 @@ # frozen_string_literal: true -require Rails.root.join('lib', 'mastodon', 'migration_helpers') - class AddHideNotificationsToMute < ActiveRecord::Migration[5.1] - include Mastodon::MigrationHelpers - disable_ddl_transaction! def up - add_column_with_default :mutes, :hide_notifications, :boolean, default: true, allow_null: false + add_column :mutes, :hide_notifications, :boolean, default: true, null: false end def down diff --git a/db/migrate/20171005171936_add_disabled_to_custom_emojis.rb b/db/migrate/20171005171936_add_disabled_to_custom_emojis.rb index d6fd228f9..eaf5f4ef2 100644 --- a/db/migrate/20171005171936_add_disabled_to_custom_emojis.rb +++ b/db/migrate/20171005171936_add_disabled_to_custom_emojis.rb @@ -1,14 +1,10 @@ # frozen_string_literal: true -require Rails.root.join('lib', 'mastodon', 'migration_helpers') - class AddDisabledToCustomEmojis < ActiveRecord::Migration[5.2] - include Mastodon::MigrationHelpers - disable_ddl_transaction! def up - safety_assured { add_column_with_default :custom_emojis, :disabled, :bool, default: false } + safety_assured { add_column :custom_emojis, :disabled, :bool, default: false, null: false } end def down diff --git a/db/migrate/20171028221157_add_reblogs_to_follows.rb b/db/migrate/20171028221157_add_reblogs_to_follows.rb index 0dab84c79..068d66d1d 100644 --- a/db/migrate/20171028221157_add_reblogs_to_follows.rb +++ b/db/migrate/20171028221157_add_reblogs_to_follows.rb @@ -1,16 +1,12 @@ # frozen_string_literal: true -require Rails.root.join('lib', 'mastodon', 'migration_helpers') - class AddReblogsToFollows < ActiveRecord::Migration[5.2] - include Mastodon::MigrationHelpers - disable_ddl_transaction! def up safety_assured do - add_column_with_default :follows, :show_reblogs, :boolean, default: true, allow_null: false - add_column_with_default :follow_requests, :show_reblogs, :boolean, default: true, allow_null: false + add_column :follows, :show_reblogs, :boolean, default: true, null: false + add_column :follow_requests, :show_reblogs, :boolean, default: true, null: false end end diff --git a/db/migrate/20171107143332_add_memorial_to_accounts.rb b/db/migrate/20171107143332_add_memorial_to_accounts.rb index 3cf782b81..35a98f45e 100644 --- a/db/migrate/20171107143332_add_memorial_to_accounts.rb +++ b/db/migrate/20171107143332_add_memorial_to_accounts.rb @@ -1,14 +1,10 @@ # frozen_string_literal: true -require Rails.root.join('lib', 'mastodon', 'migration_helpers') - class AddMemorialToAccounts < ActiveRecord::Migration[5.2] - include Mastodon::MigrationHelpers - disable_ddl_transaction! def up - safety_assured { add_column_with_default :accounts, :memorial, :bool, default: false } + safety_assured { add_column :accounts, :memorial, :bool, default: false, null: false } end def down diff --git a/db/migrate/20171107143624_add_disabled_to_users.rb b/db/migrate/20171107143624_add_disabled_to_users.rb index 4ab4df737..055d05b10 100644 --- a/db/migrate/20171107143624_add_disabled_to_users.rb +++ b/db/migrate/20171107143624_add_disabled_to_users.rb @@ -1,14 +1,10 @@ # frozen_string_literal: true -require Rails.root.join('lib', 'mastodon', 'migration_helpers') - class AddDisabledToUsers < ActiveRecord::Migration[5.2] - include Mastodon::MigrationHelpers - disable_ddl_transaction! def up - safety_assured { add_column_with_default :users, :disabled, :bool, default: false } + safety_assured { add_column :users, :disabled, :bool, default: false, null: false } end def down diff --git a/db/migrate/20171109012327_add_moderator_to_accounts.rb b/db/migrate/20171109012327_add_moderator_to_accounts.rb index e8fc313c8..6a29e5aaf 100644 --- a/db/migrate/20171109012327_add_moderator_to_accounts.rb +++ b/db/migrate/20171109012327_add_moderator_to_accounts.rb @@ -1,14 +1,10 @@ # frozen_string_literal: true -require Rails.root.join('lib', 'mastodon', 'migration_helpers') - class AddModeratorToAccounts < ActiveRecord::Migration[5.2] - include Mastodon::MigrationHelpers - disable_ddl_transaction! def up - safety_assured { add_column_with_default :users, :moderator, :bool, default: false } + safety_assured { add_column :users, :moderator, :bool, default: false, null: false } end def down diff --git a/db/migrate/20171130000000_add_embed_url_to_preview_cards.rb b/db/migrate/20171130000000_add_embed_url_to_preview_cards.rb index e78373b24..f2336e8e2 100644 --- a/db/migrate/20171130000000_add_embed_url_to_preview_cards.rb +++ b/db/migrate/20171130000000_add_embed_url_to_preview_cards.rb @@ -1,15 +1,11 @@ # frozen_string_literal: true -require Rails.root.join('lib', 'mastodon', 'migration_helpers') - class AddEmbedURLToPreviewCards < ActiveRecord::Migration[5.2] - include Mastodon::MigrationHelpers - disable_ddl_transaction! def up safety_assured do - add_column_with_default :preview_cards, :embed_url, :string, default: '', allow_null: false + add_column :preview_cards, :embed_url, :string, default: '', null: false end end diff --git a/db/migrate/20180604000556_add_apply_to_mentions_flag_to_keyword_mutes.rb b/db/migrate/20180604000556_add_apply_to_mentions_flag_to_keyword_mutes.rb index 8078a07bf..563251b21 100644 --- a/db/migrate/20180604000556_add_apply_to_mentions_flag_to_keyword_mutes.rb +++ b/db/migrate/20180604000556_add_apply_to_mentions_flag_to_keyword_mutes.rb @@ -9,7 +9,7 @@ class AddApplyToMentionsFlagToKeywordMutes < ActiveRecord::Migration[5.2] def up safety_assured do - add_column_with_default :glitch_keyword_mutes, :apply_to_mentions, :boolean, allow_null: false, default: true + add_column :glitch_keyword_mutes, :apply_to_mentions, :boolean, null: false, default: true end end diff --git a/db/migrate/20180615122121_add_autofollow_to_invites.rb b/db/migrate/20180615122121_add_autofollow_to_invites.rb index ef129003a..19a5f0d17 100644 --- a/db/migrate/20180615122121_add_autofollow_to_invites.rb +++ b/db/migrate/20180615122121_add_autofollow_to_invites.rb @@ -1,15 +1,11 @@ # frozen_string_literal: true -require Rails.root.join('lib', 'mastodon', 'migration_helpers') - class AddAutofollowToInvites < ActiveRecord::Migration[5.2] - include Mastodon::MigrationHelpers - disable_ddl_transaction! def up safety_assured do - add_column_with_default :invites, :autofollow, :bool, default: false, allow_null: false + add_column :invites, :autofollow, :bool, default: false, null: false end end diff --git a/db/migrate/20180707154237_add_whole_word_to_custom_filter.rb b/db/migrate/20180707154237_add_whole_word_to_custom_filter.rb index 793c3e6cf..519dfdfae 100644 --- a/db/migrate/20180707154237_add_whole_word_to_custom_filter.rb +++ b/db/migrate/20180707154237_add_whole_word_to_custom_filter.rb @@ -1,15 +1,11 @@ # frozen_string_literal: true -require Rails.root.join('lib', 'mastodon', 'migration_helpers') - class AddWholeWordToCustomFilter < ActiveRecord::Migration[5.2] - include Mastodon::MigrationHelpers - disable_ddl_transaction! def change safety_assured do - add_column_with_default :custom_filters, :whole_word, :boolean, default: true, allow_null: false + add_column :custom_filters, :whole_word, :boolean, default: true, null: false end end diff --git a/db/migrate/20180814171349_add_confidential_to_doorkeeper_application.rb b/db/migrate/20180814171349_add_confidential_to_doorkeeper_application.rb index 7360c71ac..6544b81c8 100644 --- a/db/migrate/20180814171349_add_confidential_to_doorkeeper_application.rb +++ b/db/migrate/20180814171349_add_confidential_to_doorkeeper_application.rb @@ -1,19 +1,15 @@ # frozen_string_literal: true -require Rails.root.join('lib', 'mastodon', 'migration_helpers') - class AddConfidentialToDoorkeeperApplication < ActiveRecord::Migration[5.2] - include Mastodon::MigrationHelpers - disable_ddl_transaction! def up safety_assured do - add_column_with_default( + add_column( :oauth_applications, :confidential, :boolean, - allow_null: false, + null: false, default: true # maintaining backwards compatibility: require secrets ) end diff --git a/db/migrate/20181010141500_add_silent_to_mentions.rb b/db/migrate/20181010141500_add_silent_to_mentions.rb index f9bfc5169..029119e79 100644 --- a/db/migrate/20181010141500_add_silent_to_mentions.rb +++ b/db/migrate/20181010141500_add_silent_to_mentions.rb @@ -1,19 +1,15 @@ # frozen_string_literal: true -require Rails.root.join('lib', 'mastodon', 'migration_helpers') - class AddSilentToMentions < ActiveRecord::Migration[5.2] - include Mastodon::MigrationHelpers - disable_ddl_transaction! def up safety_assured do - add_column_with_default( + add_column( :mentions, :silent, :boolean, - allow_null: false, + null: false, default: false ) end diff --git a/db/migrate/20181017170937_add_reject_reports_to_domain_blocks.rb b/db/migrate/20181017170937_add_reject_reports_to_domain_blocks.rb index b6cfd31d2..49bd2b02f 100644 --- a/db/migrate/20181017170937_add_reject_reports_to_domain_blocks.rb +++ b/db/migrate/20181017170937_add_reject_reports_to_domain_blocks.rb @@ -1,15 +1,11 @@ # frozen_string_literal: true -require Rails.root.join('lib', 'mastodon', 'migration_helpers') - class AddRejectReportsToDomainBlocks < ActiveRecord::Migration[5.2] - include Mastodon::MigrationHelpers - disable_ddl_transaction! def up safety_assured do - add_column_with_default :domain_blocks, :reject_reports, :boolean, default: false, allow_null: false + add_column :domain_blocks, :reject_reports, :boolean, default: false, null: false end end diff --git a/db/migrate/20181018205649_add_unread_to_account_conversations.rb b/db/migrate/20181018205649_add_unread_to_account_conversations.rb index fec947639..ae4576255 100644 --- a/db/migrate/20181018205649_add_unread_to_account_conversations.rb +++ b/db/migrate/20181018205649_add_unread_to_account_conversations.rb @@ -1,19 +1,15 @@ # frozen_string_literal: true -require Rails.root.join('lib', 'mastodon', 'migration_helpers') - class AddUnreadToAccountConversations < ActiveRecord::Migration[5.2] - include Mastodon::MigrationHelpers - disable_ddl_transaction! def up safety_assured do - add_column_with_default( + add_column( :account_conversations, :unread, :boolean, - allow_null: false, + null: false, default: false ) end diff --git a/db/migrate/20181127165847_add_show_replies_to_lists.rb b/db/migrate/20181127165847_add_show_replies_to_lists.rb index 45d457b74..a391d9f6f 100644 --- a/db/migrate/20181127165847_add_show_replies_to_lists.rb +++ b/db/migrate/20181127165847_add_show_replies_to_lists.rb @@ -1,19 +1,15 @@ # frozen_string_literal: true -require Rails.root.join('lib', 'mastodon', 'migration_helpers') - class AddShowRepliesToLists < ActiveRecord::Migration[5.2] - include Mastodon::MigrationHelpers - disable_ddl_transaction! def up safety_assured do - add_column_with_default( + add_column( :lists, :replies_policy, :integer, - allow_null: false, + null: false, default: 0 ) end diff --git a/db/migrate/20190201012802_add_overwrite_to_imports.rb b/db/migrate/20190201012802_add_overwrite_to_imports.rb index fe9423ed0..b497950ee 100644 --- a/db/migrate/20190201012802_add_overwrite_to_imports.rb +++ b/db/migrate/20190201012802_add_overwrite_to_imports.rb @@ -1,15 +1,11 @@ # frozen_string_literal: true -require Rails.root.join('lib', 'mastodon', 'migration_helpers') - class AddOverwriteToImports < ActiveRecord::Migration[5.2] - include Mastodon::MigrationHelpers - disable_ddl_transaction! def up safety_assured do - add_column_with_default :imports, :overwrite, :boolean, default: false, allow_null: false + add_column :imports, :overwrite, :boolean, default: false, null: false end end diff --git a/db/migrate/20190306145741_add_lock_version_to_polls.rb b/db/migrate/20190306145741_add_lock_version_to_polls.rb index 760818d97..ec4430ea9 100644 --- a/db/migrate/20190306145741_add_lock_version_to_polls.rb +++ b/db/migrate/20190306145741_add_lock_version_to_polls.rb @@ -1,19 +1,15 @@ # frozen_string_literal: true -require Rails.root.join('lib', 'mastodon', 'migration_helpers') - class AddLockVersionToPolls < ActiveRecord::Migration[5.2] - include Mastodon::MigrationHelpers - disable_ddl_transaction! def up safety_assured do - add_column_with_default( + add_column( :polls, :lock_version, :integer, - allow_null: false, + null: false, default: 0 ) end diff --git a/db/migrate/20190307234537_add_approved_to_users.rb b/db/migrate/20190307234537_add_approved_to_users.rb index 9abab29c9..ffdc24716 100644 --- a/db/migrate/20190307234537_add_approved_to_users.rb +++ b/db/migrate/20190307234537_add_approved_to_users.rb @@ -1,19 +1,15 @@ # frozen_string_literal: true -require Rails.root.join('lib', 'mastodon', 'migration_helpers') - class AddApprovedToUsers < ActiveRecord::Migration[5.2] - include Mastodon::MigrationHelpers - disable_ddl_transaction! def up safety_assured do - add_column_with_default( + add_column( :users, :approved, :bool, - allow_null: false, + null: false, default: true ) end diff --git a/db/migrate/20191001213028_add_lock_version_to_account_stats.rb b/db/migrate/20191001213028_add_lock_version_to_account_stats.rb index 0dc165559..3ffbacf25 100644 --- a/db/migrate/20191001213028_add_lock_version_to_account_stats.rb +++ b/db/migrate/20191001213028_add_lock_version_to_account_stats.rb @@ -1,14 +1,10 @@ # frozen_string_literal: true -require Rails.root.join('lib', 'mastodon', 'migration_helpers') - class AddLockVersionToAccountStats < ActiveRecord::Migration[5.2] - include Mastodon::MigrationHelpers - disable_ddl_transaction! def up - safety_assured { add_column_with_default :account_stats, :lock_version, :integer, allow_null: false, default: 0 } + safety_assured { add_column :account_stats, :lock_version, :integer, null: false, default: 0 } end def down diff --git a/db/migrate/20200312144258_add_title_to_account_warning_presets.rb b/db/migrate/20200312144258_add_title_to_account_warning_presets.rb index 78b854f82..63d339c49 100644 --- a/db/migrate/20200312144258_add_title_to_account_warning_presets.rb +++ b/db/migrate/20200312144258_add_title_to_account_warning_presets.rb @@ -1,14 +1,10 @@ # frozen_string_literal: true -require Rails.root.join('lib', 'mastodon', 'migration_helpers') - class AddTitleToAccountWarningPresets < ActiveRecord::Migration[5.2] - include Mastodon::MigrationHelpers - disable_ddl_transaction! def up - safety_assured { add_column_with_default :account_warning_presets, :title, :string, default: '', allow_null: false } + safety_assured { add_column :account_warning_presets, :title, :string, default: '', null: false } end def down diff --git a/db/migrate/20200917192924_add_notify_to_follows.rb b/db/migrate/20200917192924_add_notify_to_follows.rb index a57bb36dc..1dc831dc4 100644 --- a/db/migrate/20200917192924_add_notify_to_follows.rb +++ b/db/migrate/20200917192924_add_notify_to_follows.rb @@ -1,16 +1,12 @@ # frozen_string_literal: true -require Rails.root.join('lib', 'mastodon', 'migration_helpers') - class AddNotifyToFollows < ActiveRecord::Migration[5.2] - include Mastodon::MigrationHelpers - disable_ddl_transaction! def up safety_assured do - add_column_with_default :follows, :notify, :boolean, default: false, allow_null: false - add_column_with_default :follow_requests, :notify, :boolean, default: false, allow_null: false + add_column :follows, :notify, :boolean, default: false, null: false + add_column :follow_requests, :notify, :boolean, default: false, null: false end end diff --git a/db/migrate/20201218054746_add_obfuscate_to_domain_blocks.rb b/db/migrate/20201218054746_add_obfuscate_to_domain_blocks.rb index 91bba38c5..d7038c83d 100644 --- a/db/migrate/20201218054746_add_obfuscate_to_domain_blocks.rb +++ b/db/migrate/20201218054746_add_obfuscate_to_domain_blocks.rb @@ -1,14 +1,10 @@ # frozen_string_literal: true -require Rails.root.join('lib', 'mastodon', 'migration_helpers') - class AddObfuscateToDomainBlocks < ActiveRecord::Migration[5.2] - include Mastodon::MigrationHelpers - disable_ddl_transaction! def up - safety_assured { add_column_with_default :domain_blocks, :obfuscate, :boolean, default: false, allow_null: false } + safety_assured { add_column :domain_blocks, :obfuscate, :boolean, default: false, null: false } end def down diff --git a/db/migrate/20211231080958_add_category_to_reports.rb b/db/migrate/20211231080958_add_category_to_reports.rb index f114cda61..a20a3155d 100644 --- a/db/migrate/20211231080958_add_category_to_reports.rb +++ b/db/migrate/20211231080958_add_category_to_reports.rb @@ -1,15 +1,11 @@ # frozen_string_literal: true -require Rails.root.join('lib', 'mastodon', 'migration_helpers') - class AddCategoryToReports < ActiveRecord::Migration[6.1] - include Mastodon::MigrationHelpers - disable_ddl_transaction! def up safety_assured do - add_column_with_default :reports, :category, :int, default: 0, allow_null: false + add_column :reports, :category, :int, default: 0, null: false change_table(:reports, bulk: true) do |t| t.column :action_taken_at, :datetime t.column :rule_ids, :bigint, array: true diff --git a/db/migrate/20220613110834_add_action_to_custom_filters.rb b/db/migrate/20220613110834_add_action_to_custom_filters.rb index c1daf3c94..ab2f7c65e 100644 --- a/db/migrate/20220613110834_add_action_to_custom_filters.rb +++ b/db/migrate/20220613110834_add_action_to_custom_filters.rb @@ -1,15 +1,11 @@ # frozen_string_literal: true -require Rails.root.join('lib', 'mastodon', 'migration_helpers') - class AddActionToCustomFilters < ActiveRecord::Migration[6.1] - include Mastodon::MigrationHelpers - disable_ddl_transaction! def up safety_assured do - add_column_with_default :custom_filters, :action, :integer, allow_null: false, default: 0 + add_column :custom_filters, :action, :integer, null: false, default: 0 execute 'UPDATE custom_filters SET action = 1 WHERE irreversible IS TRUE' end end diff --git a/db/migrate/20230605085710_add_exclusive_to_lists.rb b/db/migrate/20230605085710_add_exclusive_to_lists.rb index 315c9d487..abcb8fae1 100644 --- a/db/migrate/20230605085710_add_exclusive_to_lists.rb +++ b/db/migrate/20230605085710_add_exclusive_to_lists.rb @@ -1,14 +1,10 @@ # frozen_string_literal: true -require Rails.root.join('lib', 'mastodon', 'migration_helpers') - class AddExclusiveToLists < ActiveRecord::Migration[6.1] - include Mastodon::MigrationHelpers - disable_ddl_transaction! def up - safety_assured { add_column_with_default :lists, :exclusive, :boolean, default: false, allow_null: false } + safety_assured { add_column :lists, :exclusive, :boolean, default: false, null: false } end def down diff --git a/db/migrate/20230725213448_add_image_description_to_preview_cards.rb b/db/migrate/20230725213448_add_image_description_to_preview_cards.rb index 03020db65..7445a0e7f 100644 --- a/db/migrate/20230725213448_add_image_description_to_preview_cards.rb +++ b/db/migrate/20230725213448_add_image_description_to_preview_cards.rb @@ -1,14 +1,10 @@ # frozen_string_literal: true -require Rails.root.join('lib', 'mastodon', 'migration_helpers') - class AddImageDescriptionToPreviewCards < ActiveRecord::Migration[7.0] - include Mastodon::MigrationHelpers - disable_ddl_transaction! def up - safety_assured { add_column_with_default :preview_cards, :image_description, :string, default: '', allow_null: false } + safety_assured { add_column :preview_cards, :image_description, :string, default: '', null: false } end def down diff --git a/db/migrate/20230814223300_add_indexable_to_accounts.rb b/db/migrate/20230814223300_add_indexable_to_accounts.rb index 6729c05ef..0544eb92f 100644 --- a/db/migrate/20230814223300_add_indexable_to_accounts.rb +++ b/db/migrate/20230814223300_add_indexable_to_accounts.rb @@ -1,14 +1,10 @@ # frozen_string_literal: true -require Rails.root.join('lib', 'mastodon', 'migration_helpers') - class AddIndexableToAccounts < ActiveRecord::Migration[7.0] - include Mastodon::MigrationHelpers - disable_ddl_transaction! def up - safety_assured { add_column_with_default :accounts, :indexable, :boolean, default: false, allow_null: false } + safety_assured { add_column :accounts, :indexable, :boolean, default: false, null: false } end def down diff --git a/db/migrate/20240109103012_fix_canadian_french_locale.rb b/db/migrate/20240109103012_fix_canadian_french_locale.rb new file mode 100644 index 000000000..1b8ef7a4a --- /dev/null +++ b/db/migrate/20240109103012_fix_canadian_french_locale.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +class FixCanadianFrenchLocale < ActiveRecord::Migration[7.0] + class User < ApplicationRecord + # Dummy class, to make migration possible across version changes + end + + disable_ddl_transaction! + + def up + User.where(locale: 'fr-QC').in_batches do |users| + users.update_all(locale: 'fr-CA') + end + end + + def down + User.where(locale: 'fr-CA').in_batches do |users| + users.update_all(locale: 'fr-QC') + end + end +end diff --git a/db/post_migrate/20220613110802_remove_whole_word_from_custom_filters.rb b/db/post_migrate/20220613110802_remove_whole_word_from_custom_filters.rb index 99c3366a2..5e477d9b1 100644 --- a/db/post_migrate/20220613110802_remove_whole_word_from_custom_filters.rb +++ b/db/post_migrate/20220613110802_remove_whole_word_from_custom_filters.rb @@ -1,10 +1,6 @@ # frozen_string_literal: true -require Rails.root.join('lib', 'mastodon', 'migration_helpers') - class RemoveWholeWordFromCustomFilters < ActiveRecord::Migration[6.1] - include Mastodon::MigrationHelpers - disable_ddl_transaction! def up @@ -15,7 +11,7 @@ class RemoveWholeWordFromCustomFilters < ActiveRecord::Migration[6.1] def down safety_assured do - add_column_with_default :custom_filters, :whole_word, :boolean, default: true, allow_null: false + add_column :custom_filters, :whole_word, :boolean, default: true, null: false end end end diff --git a/db/post_migrate/20220613110903_remove_irreversible_from_custom_filters.rb b/db/post_migrate/20220613110903_remove_irreversible_from_custom_filters.rb index 1c366ee53..1ed009fe9 100644 --- a/db/post_migrate/20220613110903_remove_irreversible_from_custom_filters.rb +++ b/db/post_migrate/20220613110903_remove_irreversible_from_custom_filters.rb @@ -1,10 +1,6 @@ # frozen_string_literal: true -require Rails.root.join('lib', 'mastodon', 'migration_helpers') - class RemoveIrreversibleFromCustomFilters < ActiveRecord::Migration[6.1] - include Mastodon::MigrationHelpers - disable_ddl_transaction! def up @@ -15,7 +11,7 @@ class RemoveIrreversibleFromCustomFilters < ActiveRecord::Migration[6.1] def down safety_assured do - add_column_with_default :custom_filters, :irreversible, :boolean, allow_null: false, default: false + add_column :custom_filters, :irreversible, :boolean, null: false, default: false end end end diff --git a/db/schema.rb b/db/schema.rb index 05db802b6..18d51c8bf 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.1].define(version: 2023_12_22_100226) do +ActiveRecord::Schema[7.1].define(version: 2024_01_09_103012) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" diff --git a/lib/mastodon/migration_helpers.rb b/lib/mastodon/migration_helpers.rb index 7bc129883..1a2ce6420 100644 --- a/lib/mastodon/migration_helpers.rb +++ b/lib/mastodon/migration_helpers.rb @@ -104,18 +104,7 @@ module Mastodon 'in the body of your migration class' end - # If default value is presented, use `add_column_with_default` method instead. - if options[:default] - add_column_with_default( - table_name, - column_name, - :datetime_with_timezone, - default: options[:default], - allow_null: options[:null] - ) - else - add_column(table_name, column_name, :datetime_with_timezone, **options) - end + add_column(table_name, column_name, :datetime_with_timezone, **options) end end @@ -377,34 +366,6 @@ module Mastodon end end - # Adds a column with a default value without locking an entire table. - # - # This method runs the following steps: - # - # 1. Add the column with a default value of NULL. - # 2. Change the default value of the column to the specified value. - # 3. Update all existing rows in batches. - # 4. Set a `NOT NULL` constraint on the column if desired (the default). - # - # These steps ensure a column can be added to a large and commonly used - # table without locking the entire table for the duration of the table - # modification. - # - # table - The name of the table to update. - # column - The name of the column to add. - # type - The column type (e.g. `:integer`). - # default - The default value for the column. - # limit - Sets a column limit. For example, for :integer, the default is - # 4-bytes. Set `limit: 8` to allow 8-byte integers. - # allow_null - When set to `true` the column will allow NULL values, the - # default is to not allow NULL values. - # - # This method can also take a block which is passed directly to the - # `update_column_in_batches` method. - def add_column_with_default(table, column, type, default:, limit: nil, allow_null: false, &block) - add_column(table, column, type, default: default, limit: limit, null: allow_null) - end - # Renames a column without requiring downtime. # # Concurrent renames work by using database triggers to ensure both the diff --git a/lib/tasks/tests.rake b/lib/tasks/tests.rake index 209a73efa..c3a9dbfd7 100644 --- a/lib/tasks/tests.rake +++ b/lib/tasks/tests.rake @@ -83,6 +83,11 @@ namespace :tests do puts 'Default posting language not migrated as expected for kmr users' exit(1) end + + unless Account.find_local('qcuser').user.locale == 'fr-CA' + puts 'Locale for fr-QC users not updated to fr-CA as expected' + exit(1) + end end desc 'Populate the database with test data for 2.4.3' @@ -142,13 +147,19 @@ namespace :tests do INSERT INTO "accounts" (id, username, domain, private_key, public_key, created_at, updated_at) VALUES - (10, 'kmruser', NULL, #{user_private_key}, #{user_public_key}, now(), now()); + (10, 'kmruser', NULL, #{user_private_key}, #{user_public_key}, now(), now()), + (11, 'qcuser', NULL, #{user_private_key}, #{user_public_key}, now(), now()); INSERT INTO "users" (id, account_id, email, created_at, updated_at, admin, locale, chosen_languages) VALUES (4, 10, 'kmruser@localhost', now(), now(), false, 'ku', '{en,kmr,ku,ckb}'); + INSERT INTO "users" + (id, account_id, email, created_at, updated_at, locale) + VALUES + (5, 11, 'qcuser@localhost', now(), now(), 'fr-QC'); + INSERT INTO "settings" (id, thing_type, thing_id, var, value, created_at, updated_at) VALUES diff --git a/spec/controllers/admin/disputes/appeals_controller_spec.rb b/spec/controllers/admin/disputes/appeals_controller_spec.rb index 4581d00d6..f830c3b95 100644 --- a/spec/controllers/admin/disputes/appeals_controller_spec.rb +++ b/spec/controllers/admin/disputes/appeals_controller_spec.rb @@ -44,7 +44,7 @@ RSpec.describe Admin::Disputes::AppealsController do expect(response).to redirect_to(disputes_strike_path(appeal.strike)) end - it 'notifies target account about approved appeal' do + it 'notifies target account about approved appeal', :sidekiq_inline do expect(UserMailer.deliveries.size).to eq(1) expect(UserMailer.deliveries.first.to.first).to eq(target_account.user.email) expect(UserMailer.deliveries.first.subject).to eq(I18n.t('user_mailer.appeal_approved.subject', date: I18n.l(appeal.created_at))) @@ -62,7 +62,7 @@ RSpec.describe Admin::Disputes::AppealsController do expect(response).to redirect_to(disputes_strike_path(appeal.strike)) end - it 'notifies target account about rejected appeal' do + it 'notifies target account about rejected appeal', :sidekiq_inline do expect(UserMailer.deliveries.size).to eq(1) expect(UserMailer.deliveries.first.to.first).to eq(target_account.user.email) expect(UserMailer.deliveries.first.subject).to eq(I18n.t('user_mailer.appeal_rejected.subject', date: I18n.l(appeal.created_at))) diff --git a/spec/controllers/admin/domain_blocks_controller_spec.rb b/spec/controllers/admin/domain_blocks_controller_spec.rb index 22960f531..87b08323d 100644 --- a/spec/controllers/admin/domain_blocks_controller_spec.rb +++ b/spec/controllers/admin/domain_blocks_controller_spec.rb @@ -176,7 +176,7 @@ RSpec.describe Admin::DomainBlocksController do end end - describe 'PUT #update' do + describe 'PUT #update', :sidekiq_inline do subject do post :update, params: { :id => domain_block.id, :domain_block => { domain: 'example.com', severity: new_severity }, 'confirm' => '' } end diff --git a/spec/controllers/admin/resets_controller_spec.rb b/spec/controllers/admin/resets_controller_spec.rb index 14826973c..e82a3a6af 100644 --- a/spec/controllers/admin/resets_controller_spec.rb +++ b/spec/controllers/admin/resets_controller_spec.rb @@ -11,7 +11,7 @@ describe Admin::ResetsController do sign_in Fabricate(:user, role: UserRole.find_by(name: 'Admin')), scope: :user end - describe 'POST #create' do + describe 'POST #create', :sidekiq_inline do it 'redirects to admin accounts page' do expect do post :create, params: { account_id: account.id } diff --git a/spec/controllers/api/v1/conversations_controller_spec.rb b/spec/controllers/api/v1/conversations_controller_spec.rb index 50e2a62ef..2734e4a07 100644 --- a/spec/controllers/api/v1/conversations_controller_spec.rb +++ b/spec/controllers/api/v1/conversations_controller_spec.rb @@ -13,7 +13,7 @@ RSpec.describe Api::V1::ConversationsController do allow(controller).to receive(:doorkeeper_token) { token } end - describe 'GET #index' do + describe 'GET #index', :sidekiq_inline do let(:scopes) { 'read:statuses' } before do diff --git a/spec/controllers/api/v1/statuses/reblogs_controller_spec.rb b/spec/controllers/api/v1/statuses/reblogs_controller_spec.rb index e3a9bdb50..014a03c1a 100644 --- a/spec/controllers/api/v1/statuses/reblogs_controller_spec.rb +++ b/spec/controllers/api/v1/statuses/reblogs_controller_spec.rb @@ -9,7 +9,7 @@ describe Api::V1::Statuses::ReblogsController do let(:app) { Fabricate(:application, name: 'Test app', website: 'http://testapp.com') } let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'write:statuses', application: app) } - context 'with an oauth token', :sidekiq_fake do + context 'with an oauth token' do before do allow(controller).to receive(:doorkeeper_token) { token } end @@ -46,7 +46,7 @@ describe Api::V1::Statuses::ReblogsController do end end - describe 'POST #destroy' do + describe 'POST #destroy', :sidekiq_inline do context 'with public status' do let(:status) { Fabricate(:status, account: user.account) } diff --git a/spec/controllers/api/v1/streaming_controller_spec.rb b/spec/controllers/api/v1/streaming_controller_spec.rb index c3e7153ce..099f68a74 100644 --- a/spec/controllers/api/v1/streaming_controller_spec.rb +++ b/spec/controllers/api/v1/streaming_controller_spec.rb @@ -5,7 +5,7 @@ require 'rails_helper' describe Api::V1::StreamingController do around do |example| before = Rails.configuration.x.streaming_api_base_url - Rails.configuration.x.streaming_api_base_url = Rails.configuration.x.web_domain + Rails.configuration.x.streaming_api_base_url = "wss://#{Rails.configuration.x.web_domain}" example.run Rails.configuration.x.streaming_api_base_url = before end diff --git a/spec/controllers/auth/sessions_controller_spec.rb b/spec/controllers/auth/sessions_controller_spec.rb index 212cc4d5e..e3f2b278b 100644 --- a/spec/controllers/auth/sessions_controller_spec.rb +++ b/spec/controllers/auth/sessions_controller_spec.rb @@ -138,7 +138,7 @@ RSpec.describe Auth::SessionsController do expect(controller.current_user).to eq user end - it 'sends a suspicious sign-in mail' do + it 'sends a suspicious sign-in mail', :sidekiq_inline do expect(UserMailer.deliveries.size).to eq(1) expect(UserMailer.deliveries.first.to.first).to eq(user.email) expect(UserMailer.deliveries.first.subject).to eq(I18n.t('user_mailer.suspicious_sign_in.subject')) diff --git a/spec/controllers/concerns/user_tracking_concern_spec.rb b/spec/controllers/concerns/user_tracking_concern_spec.rb index dd0b3c042..b1de3cf4e 100644 --- a/spec/controllers/concerns/user_tracking_concern_spec.rb +++ b/spec/controllers/concerns/user_tracking_concern_spec.rb @@ -75,7 +75,7 @@ describe UserTrackingConcern do expect(redis.ttl("account:#{user.account_id}:regeneration")).to be >= 0 end - it 'regenerates feed when sign in is older than two weeks' do + it 'regenerates feed when sign in is older than two weeks', :sidekiq_inline do get :show expect_updated_sign_in_at(user) diff --git a/spec/controllers/disputes/appeals_controller_spec.rb b/spec/controllers/disputes/appeals_controller_spec.rb index c8444a2a9..452bd60dc 100644 --- a/spec/controllers/disputes/appeals_controller_spec.rb +++ b/spec/controllers/disputes/appeals_controller_spec.rb @@ -17,7 +17,7 @@ RSpec.describe Disputes::AppealsController do post :create, params: { strike_id: strike.id, appeal: { text: 'Foo' } } end - it 'notifies staff about new appeal' do + it 'notifies staff about new appeal', :sidekiq_inline do expect(ActionMailer::Base.deliveries.first.to).to eq([admin.email]) end diff --git a/spec/controllers/settings/deletes_controller_spec.rb b/spec/controllers/settings/deletes_controller_spec.rb index 2c1532ecd..ccca4564e 100644 --- a/spec/controllers/settings/deletes_controller_spec.rb +++ b/spec/controllers/settings/deletes_controller_spec.rb @@ -50,7 +50,7 @@ describe Settings::DeletesController do delete :destroy, params: { form_delete_confirmation: { password: 'petsmoldoggos' } } end - it 'removes user record and redirects', :aggregate_failures do + it 'removes user record and redirects', :aggregate_failures, :sidekiq_inline do expect(response).to redirect_to '/auth/sign_in' expect(User.find_by(id: user.id)).to be_nil expect(user.account.reload).to be_suspended diff --git a/spec/controllers/settings/exports_controller_spec.rb b/spec/controllers/settings/exports_controller_spec.rb index 0bd1e80c3..3399f78ac 100644 --- a/spec/controllers/settings/exports_controller_spec.rb +++ b/spec/controllers/settings/exports_controller_spec.rb @@ -38,7 +38,7 @@ describe Settings::ExportsController do expect(response).to redirect_to(settings_export_path) end - it 'queues BackupWorker job by 1', :sidekiq_fake do + it 'queues BackupWorker job by 1' do expect do post :create end.to change(BackupWorker.jobs, :size).by(1) diff --git a/spec/features/admin/accounts_spec.rb b/spec/features/admin/accounts_spec.rb index 6d7bab184..54d755b91 100644 --- a/spec/features/admin/accounts_spec.rb +++ b/spec/features/admin/accounts_spec.rb @@ -48,7 +48,7 @@ describe 'Admin::Accounts' do end end - context 'with action of `reject`' do + context 'with action of `reject`', :sidekiq_inline do it 'rejects and removes the account' do batch_checkbox_for(unapproved_user_account).check diff --git a/spec/lib/activitypub/activity/create_spec.rb b/spec/lib/activitypub/activity/create_spec.rb index a0340216a..3c80ab453 100644 --- a/spec/lib/activitypub/activity/create_spec.rb +++ b/spec/lib/activitypub/activity/create_spec.rb @@ -23,7 +23,7 @@ RSpec.describe ActivityPub::Activity::Create do stub_request(:get, 'http://example.com/emojib.png').to_return(body: attachment_fixture('emojo.png'), headers: { 'Content-Type' => 'application/octet-stream' }) end - describe 'processing posts received out of order', :sidekiq_fake do + describe 'processing posts received out of order' do let(:follower) { Fabricate(:account, username: 'bob') } let(:object_json) do diff --git a/spec/lib/activitypub/activity/delete_spec.rb b/spec/lib/activitypub/activity/delete_spec.rb index aec2c71e5..48421a116 100644 --- a/spec/lib/activitypub/activity/delete_spec.rb +++ b/spec/lib/activitypub/activity/delete_spec.rb @@ -47,7 +47,7 @@ RSpec.describe ActivityPub::Activity::Delete do expect(Status.find_by(id: status.id)).to be_nil end - it 'sends delete activity to followers of rebloggers' do + it 'sends delete activity to followers of rebloggers', :sidekiq_inline do expect(a_request(:post, 'http://example.com/inbox')).to have_been_made.once end diff --git a/spec/lib/activitypub/activity/move_spec.rb b/spec/lib/activitypub/activity/move_spec.rb index f3973c70c..4dda014a0 100644 --- a/spec/lib/activitypub/activity/move_spec.rb +++ b/spec/lib/activitypub/activity/move_spec.rb @@ -38,7 +38,7 @@ RSpec.describe ActivityPub::Activity::Move do subject.perform end - context 'when all conditions are met' do + context 'when all conditions are met', :sidekiq_inline do it 'sets moved account on old account' do expect(old_account.reload.moved_to_account_id).to eq new_account.id end diff --git a/spec/lib/mastodon/cli/media_spec.rb b/spec/lib/mastodon/cli/media_spec.rb index 071bcd9e3..10005107a 100644 --- a/spec/lib/mastodon/cli/media_spec.rb +++ b/spec/lib/mastodon/cli/media_spec.rb @@ -183,6 +183,21 @@ describe Mastodon::CLI::Media do .to output_results('Downloaded 1 media') end end + + context 'with --days option' do + before do + Fabricate(:media_attachment, remote_url: 'https://example.com/image.jpg', id: Mastodon::Snowflake.id_at(50.days.ago)) + Fabricate(:media_attachment, remote_url: 'https://example.com/image.jpg', id: Mastodon::Snowflake.id_at(5.days.ago)) + Fabricate(:media_attachment, remote_url: '', id: Mastodon::Snowflake.id_at(5.days.ago)) + end + + let(:options) { { days: 10 } } + + it 'redownloads the attachment file for the remote records more recent than the option' do + expect { subject } + .to output_results('Downloaded 1 media') + end + end end describe '#remove_orphans' do diff --git a/spec/models/account_spec.rb b/spec/models/account_spec.rb index 87aa8bc75..b4fcb805a 100644 --- a/spec/models/account_spec.rb +++ b/spec/models/account_spec.rb @@ -1009,4 +1009,27 @@ RSpec.describe Account do expect(subject.reload.followers_count).to eq 15 end end + + describe '.followable_by' do + context 'with follows and follow requests' do + let!(:account) { Fabricate(:account) } + let!(:eligible_account) { Fabricate(:account) } + let!(:following_account) { Fabricate(:account) } + let!(:follow_requested_account) { Fabricate(:account) } + + before do + Fabricate :follow, account: account, target_account: following_account + Fabricate :follow_request, account: account, target_account: follow_requested_account + end + + it 'returns accounts not already following or requested to follow' do + results = described_class.followable_by(account) + + expect(results) + .to include(eligible_account) + .and not_include(following_account) + .and not_include(follow_requested_account) + end + end + end end diff --git a/spec/models/admin/account_action_spec.rb b/spec/models/admin/account_action_spec.rb index 5d64d565f..9bc9f8061 100644 --- a/spec/models/admin/account_action_spec.rb +++ b/spec/models/admin/account_action_spec.rb @@ -46,7 +46,7 @@ RSpec.describe Admin::AccountAction do expect(target_account).to be_suspended end - it 'queues Admin::SuspensionWorker by 1', :sidekiq_fake do + it 'queues Admin::SuspensionWorker by 1' do expect do subject end.to change { Admin::SuspensionWorker.jobs.size }.by 1 diff --git a/spec/models/setting_spec.rb b/spec/models/setting_spec.rb index e98062810..a1e24e835 100644 --- a/spec/models/setting_spec.rb +++ b/spec/models/setting_spec.rb @@ -13,189 +13,65 @@ RSpec.describe Setting do end describe '.[]' do + let(:key) { 'key' } + let(:cache_key) { 'cache-key' } + let(:cache_value) { 'cache-value' } + before do - allow(described_class).to receive(:rails_initialized?).and_return(rails_initialized) + allow(described_class).to receive(:cache_key).with(key).and_return(cache_key) end - let(:key) { 'key' } - - context 'when rails_initialized? is falsey' do - let(:rails_initialized) { false } - - it 'calls RailsSettings::Base#[]' do - allow(RailsSettings::Base).to receive(:[]).with(key) - - described_class[key] - - expect(RailsSettings::Base).to have_received(:[]).with(key) - end - end - - context 'when rails_initialized? is truthy' do + context 'when Rails.cache does not exists' do before do - allow(RailsSettings::Base).to receive(:cache_key).with(key, nil).and_return(cache_key) + allow(described_class).to receive(:default_settings).and_return(default_settings) + + Fabricate(:setting, var: key, value: 42) if save_setting + + Rails.cache.delete(cache_key) end - let(:rails_initialized) { true } - let(:cache_key) { 'cache-key' } - let(:cache_value) { 'cache-value' } + let(:default_value) { 'default_value' } + let(:default_settings) { { key => default_value } } + let(:save_setting) { true } - it 'calls not RailsSettings::Base#[]' do - allow(RailsSettings::Base).to receive(:[]).with(key) - - described_class[key] - - expect(RailsSettings::Base).to_not have_received(:[]).with(key) - end - - context 'when Rails.cache does not exists' do - before do - allow(RailsSettings::Settings).to receive(:object).with(key).and_return(object) - allow(described_class).to receive(:default_settings).and_return(default_settings) - settings_double = instance_double(Settings::ScopedSettings, thing_scoped: records) - allow(Settings::ScopedSettings).to receive(:new).and_return(settings_double) - Rails.cache.delete(cache_key) - end - - let(:object) { nil } - let(:default_value) { 'default_value' } - let(:default_settings) { { key => default_value } } - let(:records) { [Fabricate(:setting, var: key, value: nil)] } - - it 'calls RailsSettings::Settings.object' do - allow(RailsSettings::Settings).to receive(:object).with(key) - - described_class[key] - - expect(RailsSettings::Settings).to have_received(:object).with(key) - end - - context 'when RailsSettings::Settings.object returns truthy' do - let(:object) { db_val } - let(:db_val) { instance_double(described_class, value: 'db_val') } - - context 'when default_value is a Hash' do - let(:default_value) { { default_value: 'default_value' } } - - it 'calls default_value.with_indifferent_access.merge!' do - indifferent_hash = instance_double(Hash, merge!: nil) - allow(default_value).to receive(:with_indifferent_access).and_return(indifferent_hash) - - described_class[key] - - expect(default_value).to have_received(:with_indifferent_access) - expect(indifferent_hash).to have_received(:merge!).with(db_val.value) - end - end - - context 'when default_value is not a Hash' do - let(:default_value) { 'default_value' } - - it 'returns db_val.value' do - expect(described_class[key]).to be db_val.value - end - end - end - - context 'when RailsSettings::Settings.object returns falsey' do - let(:object) { nil } - - it 'returns default_settings[key]' do - expect(described_class[key]).to be default_settings[key] - end - end - end - - context 'when Rails.cache exists' do - before do - Rails.cache.write(cache_key, cache_value) - end - - it 'does not query the database' do + context 'when the setting has been saved to database' do + it 'returns the value from database' do callback = double allow(callback).to receive(:call) + ActiveSupport::Notifications.subscribed callback, 'sql.active_record' do - described_class[key] + expect(described_class[key]).to eq 42 end - expect(callback).to_not have_received(:call) - end - it 'returns the cached value' do - expect(described_class[key]).to eq cache_value - end - end - end - end - - describe '.all_as_records' do - before do - settings_double = instance_double(Settings::ScopedSettings, thing_scoped: records) - allow(Settings::ScopedSettings).to receive(:new).and_return(settings_double) - allow(described_class).to receive(:default_settings).and_return(default_settings) - end - - let(:key) { 'key' } - let(:default_value) { 'default_value' } - let(:default_settings) { { key => default_value } } - let(:original_setting) { Fabricate(:setting, var: key, value: nil) } - let(:records) { [original_setting] } - - it 'returns a Hash' do - expect(described_class.all_as_records).to be_a Hash - end - - context 'when records includes Setting with var as the key' do - let(:records) { [original_setting] } - - it 'includes the original Setting' do - setting = described_class.all_as_records[key] - expect(setting).to eq original_setting - end - end - - context 'when records includes nothing' do - let(:records) { [] } - - context 'when default_value is not a Hash' do - it 'includes Setting with value of default_value' do - setting = described_class.all_as_records[key] - - expect(setting).to be_a described_class - expect(setting).to have_attributes(var: key) - expect(setting).to have_attributes(value: 'default_value') + expect(callback).to have_received(:call) end end - context 'when default_value is a Hash' do - let(:default_value) { { 'foo' => 'fuga' } } + context 'when the setting has not been saved to database' do + let(:save_setting) { false } - it 'returns {}' do - expect(described_class.all_as_records).to eq({}) + it 'returns default_settings[key]' do + expect(described_class[key]).to be default_settings[key] end end end - end - describe '.default_settings' do - subject { described_class.default_settings } - - before do - allow(RailsSettings::Default).to receive(:enabled?).and_return(enabled) - end - - context 'when RailsSettings::Default.enabled? is false' do - let(:enabled) { false } - - it 'returns {}' do - expect(subject).to eq({}) + context 'when Rails.cache exists' do + before do + Rails.cache.write(cache_key, cache_value) end - end - context 'when RailsSettings::Settings.enabled? is true' do - let(:enabled) { true } + it 'does not query the database' do + callback = double + allow(callback).to receive(:call) + ActiveSupport::Notifications.subscribed callback, 'sql.active_record' do + described_class[key] + end + expect(callback).to_not have_received(:call) + end - it 'returns instance of RailsSettings::Default' do - expect(subject).to be_a RailsSettings::Default + it 'returns the cached value' do + expect(described_class[key]).to eq cache_value end end end diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index ab5bd39b7..7f68671df 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -38,27 +38,53 @@ RSpec.describe User do user.save(validate: false) expect(user.valid?).to be true end + end - it 'cleans out invalid locale' do - user = Fabricate.build(:user, locale: 'toto') - expect(user.valid?).to be true - expect(user.locale).to be_nil + describe 'Normalizations' do + describe 'locale' do + it 'preserves valid locale' do + user = Fabricate.build(:user, locale: 'en') + + expect(user.locale).to eq('en') + end + + it 'cleans out invalid locale' do + user = Fabricate.build(:user, locale: 'toto') + + expect(user.locale).to be_nil + end end - it 'cleans out invalid timezone' do - user = Fabricate.build(:user, time_zone: 'toto') - expect(user.valid?).to be true - expect(user.time_zone).to be_nil + describe 'time_zone' do + it 'preserves valid timezone' do + user = Fabricate.build(:user, time_zone: 'UTC') + + expect(user.time_zone).to eq('UTC') + end + + it 'cleans out invalid timezone' do + user = Fabricate.build(:user, time_zone: 'toto') + + expect(user.time_zone).to be_nil + end end - it 'cleans out empty string from languages' do - user = Fabricate.build(:user, chosen_languages: ['']) - user.valid? - expect(user.chosen_languages).to be_nil + describe 'languages' do + it 'preserves valid options for languages' do + user = Fabricate.build(:user, chosen_languages: ['en', 'fr', '']) + + expect(user.chosen_languages).to eq(['en', 'fr']) + end + + it 'cleans out empty string from languages' do + user = Fabricate.build(:user, chosen_languages: ['']) + + expect(user.chosen_languages).to be_nil + end end end - describe 'scopes' do + describe 'scopes', :sidekiq_inline do describe 'recent' do it 'returns an array of recent users ordered by id' do first_user = Fabricate(:user) @@ -452,7 +478,7 @@ RSpec.describe User do expect(user.confirmed_at).to be_present end - it 'delivers mails' do + it 'delivers mails', :sidekiq_inline do expect(ActionMailer::Base.deliveries.count).to eq 2 end end diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index e5d432b45..aabb121fc 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -26,7 +26,6 @@ Dir[Rails.root.join('spec', 'support', '**', '*.rb')].each { |f| require f } ActiveRecord::Migration.maintain_test_schema! WebMock.disable_net_connect!(allow: Chewy.settings[:host], allow_localhost: RUN_SYSTEM_SPECS) -Sidekiq::Testing.inline! Sidekiq.logger = nil # System tests config @@ -96,11 +95,8 @@ RSpec.configure do |config| self.use_transactional_tests = true end - config.around(:each, :sidekiq_fake) do |example| - Sidekiq::Testing.fake! do - example.run - Sidekiq::Worker.clear_all - end + config.around(:each, :sidekiq_inline) do |example| + Sidekiq::Testing.inline!(&example) end config.before :each, type: :cli do @@ -112,8 +108,6 @@ RSpec.configure do |config| end config.around :each, type: :system do |example| - driven_by :selenium, using: :headless_chrome, screen_size: [1600, 1200] - # The streaming server needs access to the database # but with use_transactional_tests every transaction # is rolled-back, so the streaming server never sees the data diff --git a/spec/requests/api/v1/featured_tags_spec.rb b/spec/requests/api/v1/featured_tags_spec.rb index c4aa2c0a2..f499dd1d0 100644 --- a/spec/requests/api/v1/featured_tags_spec.rb +++ b/spec/requests/api/v1/featured_tags_spec.rb @@ -147,7 +147,7 @@ RSpec.describe 'FeaturedTags' do expect(body).to be_empty end - it 'deletes the featured tag' do + it 'deletes the featured tag', :sidekiq_inline do delete "/api/v1/featured_tags/#{id}", headers: headers featured_tag = FeaturedTag.find_by(id: id) diff --git a/spec/requests/api/v1/notifications_spec.rb b/spec/requests/api/v1/notifications_spec.rb index 7a904816e..222ff67fc 100644 --- a/spec/requests/api/v1/notifications_spec.rb +++ b/spec/requests/api/v1/notifications_spec.rb @@ -8,7 +8,7 @@ RSpec.describe 'Notifications' do let(:scopes) { 'read:notifications write:notifications' } let(:headers) { { 'Authorization' => "Bearer #{token.token}" } } - describe 'GET /api/v1/notifications' do + describe 'GET /api/v1/notifications', :sidekiq_inline do subject do get '/api/v1/notifications', headers: headers, params: params end diff --git a/spec/requests/api/v1/statuses/favourites_spec.rb b/spec/requests/api/v1/statuses/favourites_spec.rb index 8f3e6e5c4..033aed7e2 100644 --- a/spec/requests/api/v1/statuses/favourites_spec.rb +++ b/spec/requests/api/v1/statuses/favourites_spec.rb @@ -2,7 +2,7 @@ require 'rails_helper' -RSpec.describe 'Favourites' do +RSpec.describe 'Favourites', :sidekiq_inline do let(:user) { Fabricate(:user) } let(:scopes) { 'write:favourites' } let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) } @@ -70,7 +70,7 @@ RSpec.describe 'Favourites' do end end - describe 'POST /api/v1/statuses/:status_id/unfavourite', :sidekiq_fake do + describe 'POST /api/v1/statuses/:status_id/unfavourite' do subject do post "/api/v1/statuses/#{status.id}/unfavourite", headers: headers end @@ -88,9 +88,7 @@ RSpec.describe 'Favourites' do subject expect(response).to have_http_status(200) - expect(user.account.favourited?(status)).to be true - UnfavouriteWorker.drain expect(user.account.favourited?(status)).to be false end @@ -113,9 +111,7 @@ RSpec.describe 'Favourites' do subject expect(response).to have_http_status(200) - expect(user.account.favourited?(status)).to be true - UnfavouriteWorker.drain expect(user.account.favourited?(status)).to be false end diff --git a/spec/requests/api/v1/timelines/home_spec.rb b/spec/requests/api/v1/timelines/home_spec.rb index 5834b9095..e57e9643b 100644 --- a/spec/requests/api/v1/timelines/home_spec.rb +++ b/spec/requests/api/v1/timelines/home_spec.rb @@ -2,7 +2,7 @@ require 'rails_helper' -describe 'Home' do +describe 'Home', :sidekiq_inline do let(:user) { Fabricate(:user) } let(:scopes) { 'read:statuses' } let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) } diff --git a/spec/search/models/concerns/account/statuses_search_spec.rb b/spec/search/models/concerns/account/statuses_search_spec.rb index bf2606eec..915bc094c 100644 --- a/spec/search/models/concerns/account/statuses_search_spec.rb +++ b/spec/search/models/concerns/account/statuses_search_spec.rb @@ -2,7 +2,7 @@ require 'rails_helper' -describe Account::StatusesSearch do +describe Account::StatusesSearch, :sidekiq_inline do describe 'a non-indexable account becoming indexable' do let(:account) { Account.find_by(username: 'search_test_account_1') } diff --git a/spec/services/activitypub/fetch_remote_status_service_spec.rb b/spec/services/activitypub/fetch_remote_status_service_spec.rb index 3c64feaee..0fb32d20b 100644 --- a/spec/services/activitypub/fetch_remote_status_service_spec.rb +++ b/spec/services/activitypub/fetch_remote_status_service_spec.rb @@ -225,7 +225,7 @@ RSpec.describe ActivityPub::FetchRemoteStatusService, type: :service do end end - context 'with statuses referencing other statuses' do + context 'with statuses referencing other statuses', :sidekiq_inline do before do stub_const 'ActivityPub::FetchRemoteStatusService::DISCOVERIES_PER_REQUEST', 5 end diff --git a/spec/services/activitypub/process_account_service_spec.rb b/spec/services/activitypub/process_account_service_spec.rb index 58dd2badb..9abe03181 100644 --- a/spec/services/activitypub/process_account_service_spec.rb +++ b/spec/services/activitypub/process_account_service_spec.rb @@ -193,7 +193,7 @@ RSpec.describe ActivityPub::ProcessAccountService, type: :service do end end - it 'creates accounts without exceeding rate limit' do + it 'creates accounts without exceeding rate limit', :sidekiq_inline do expect { subject.call('user1', 'foo.test', payload) } .to create_some_remote_accounts .and create_fewer_than_rate_limit_accounts diff --git a/spec/services/authorize_follow_service_spec.rb b/spec/services/authorize_follow_service_spec.rb index d07645ab6..602250ee9 100644 --- a/spec/services/authorize_follow_service_spec.rb +++ b/spec/services/authorize_follow_service_spec.rb @@ -41,7 +41,7 @@ RSpec.describe AuthorizeFollowService, type: :service do expect(bob.following?(sender)).to be true end - it 'sends an accept activity' do + it 'sends an accept activity', :sidekiq_inline do expect(a_request(:post, bob.inbox_url)).to have_been_made.once end end diff --git a/spec/services/batched_remove_status_service_spec.rb b/spec/services/batched_remove_status_service_spec.rb index 991a852f0..1c59d5ed0 100644 --- a/spec/services/batched_remove_status_service_spec.rb +++ b/spec/services/batched_remove_status_service_spec.rb @@ -2,7 +2,7 @@ require 'rails_helper' -RSpec.describe BatchedRemoveStatusService, type: :service do +RSpec.describe BatchedRemoveStatusService, :sidekiq_inline, type: :service do subject { described_class.new } let!(:alice) { Fabricate(:account) } diff --git a/spec/services/block_domain_service_spec.rb b/spec/services/block_domain_service_spec.rb index fc3a1397d..7ad00fff6 100644 --- a/spec/services/block_domain_service_spec.rb +++ b/spec/services/block_domain_service_spec.rb @@ -68,7 +68,7 @@ RSpec.describe BlockDomainService, type: :service do expect(already_banned_account.reload.silenced_at).to_not eq DomainBlock.find_by(domain: 'evil.org').created_at end - it 'leaves the domains status and attachments, but clears media' do + it 'leaves the domains status and attachments, but clears media', :sidekiq_inline do expect { bad_status_plain.reload }.to_not raise_error expect { bad_status_with_attachment.reload }.to_not raise_error expect { bad_attachment.reload }.to_not raise_error diff --git a/spec/services/block_service_spec.rb b/spec/services/block_service_spec.rb index 5f7c2e8da..9e4ff8e59 100644 --- a/spec/services/block_service_spec.rb +++ b/spec/services/block_service_spec.rb @@ -31,7 +31,7 @@ RSpec.describe BlockService, type: :service do expect(sender.blocking?(bob)).to be true end - it 'sends a block activity' do + it 'sends a block activity', :sidekiq_inline do expect(a_request(:post, 'http://example.com/inbox')).to have_been_made.once end end diff --git a/spec/services/bulk_import_service_spec.rb b/spec/services/bulk_import_service_spec.rb index f703650c3..c3a716058 100644 --- a/spec/services/bulk_import_service_spec.rb +++ b/spec/services/bulk_import_service_spec.rb @@ -12,7 +12,7 @@ RSpec.describe BulkImportService do import.update(total_items: import.rows.count) end - describe '#call', :sidekiq_fake do + describe '#call' do context 'when importing follows' do let(:import_type) { 'following' } let(:overwrite) { false } diff --git a/spec/services/delete_account_service_spec.rb b/spec/services/delete_account_service_spec.rb index f04ba9cf1..1965b7daa 100644 --- a/spec/services/delete_account_service_spec.rb +++ b/spec/services/delete_account_service_spec.rb @@ -62,7 +62,7 @@ RSpec.describe DeleteAccountService, type: :service do end end - describe '#call on local account' do + describe '#call on local account', :sidekiq_inline do before do stub_request(:post, remote_alice.inbox_url).to_return(status: 201) stub_request(:post, remote_bob.inbox_url).to_return(status: 201) @@ -83,7 +83,7 @@ RSpec.describe DeleteAccountService, type: :service do end end - describe '#call on remote account' do + describe '#call on remote account', :sidekiq_inline do before do stub_request(:post, account.inbox_url).to_return(status: 201) end diff --git a/spec/services/fan_out_on_write_service_spec.rb b/spec/services/fan_out_on_write_service_spec.rb index 6ad041193..77237dffb 100644 --- a/spec/services/fan_out_on_write_service_spec.rb +++ b/spec/services/fan_out_on_write_service_spec.rb @@ -38,7 +38,7 @@ RSpec.describe FanOutOnWriteService, type: :service do expect(home_feed_of(alice)).to include status.id end - it 'is added to the home feed of a follower' do + it 'is added to the home feed of a follower', :sidekiq_inline do expect(home_feed_of(bob)).to include status.id expect(home_feed_of(tom)).to include status.id end @@ -62,7 +62,7 @@ RSpec.describe FanOutOnWriteService, type: :service do expect(home_feed_of(alice)).to include status.id end - it 'is added to the home feed of the mentioned follower' do + it 'is added to the home feed of the mentioned follower', :sidekiq_inline do expect(home_feed_of(bob)).to include status.id end @@ -83,7 +83,7 @@ RSpec.describe FanOutOnWriteService, type: :service do expect(home_feed_of(alice)).to include status.id end - it 'is added to the home feed of a follower' do + it 'is added to the home feed of a follower', :sidekiq_inline do expect(home_feed_of(bob)).to include status.id expect(home_feed_of(tom)).to include status.id end @@ -101,7 +101,7 @@ RSpec.describe FanOutOnWriteService, type: :service do expect(home_feed_of(alice)).to include status.id end - it 'is added to the home feed of the mentioned follower' do + it 'is added to the home feed of the mentioned follower', :sidekiq_inline do expect(home_feed_of(bob)).to include status.id end @@ -114,7 +114,7 @@ RSpec.describe FanOutOnWriteService, type: :service do expect(redis).to_not have_received(:publish).with('timeline:public', anything) end - context 'when handling status updates', :sidekiq_fake do + context 'when handling status updates' do before do subject.call(status) @@ -123,8 +123,6 @@ RSpec.describe FanOutOnWriteService, type: :service do status.snapshot!(account_id: status.account_id) redis.set("subscribed:timeline:#{eve.id}:notifications", '1') - - Sidekiq::Worker.clear_all end it 'pushes the update to mentioned users through the notifications streaming channel' do diff --git a/spec/services/favourite_service_spec.rb b/spec/services/favourite_service_spec.rb index 782c235c4..3143e7b66 100644 --- a/spec/services/favourite_service_spec.rb +++ b/spec/services/favourite_service_spec.rb @@ -33,7 +33,7 @@ RSpec.describe FavouriteService, type: :service do expect(status.favourites.first).to_not be_nil end - it 'sends a like activity' do + it 'sends a like activity', :sidekiq_inline do expect(a_request(:post, 'http://example.com/inbox')).to have_been_made.once end end diff --git a/spec/services/follow_service_spec.rb b/spec/services/follow_service_spec.rb index c2ad0d717..cf4de34c8 100644 --- a/spec/services/follow_service_spec.rb +++ b/spec/services/follow_service_spec.rb @@ -150,7 +150,7 @@ RSpec.describe FollowService, type: :service do expect(FollowRequest.find_by(account: sender, target_account: bob)).to_not be_nil end - it 'sends a follow activity to the inbox' do + it 'sends a follow activity to the inbox', :sidekiq_inline do expect(a_request(:post, 'http://example.com/inbox')).to have_been_made.once end end diff --git a/spec/services/import_service_spec.rb b/spec/services/import_service_spec.rb index d67da66ca..7d005c8a1 100644 --- a/spec/services/import_service_spec.rb +++ b/spec/services/import_service_spec.rb @@ -2,7 +2,7 @@ require 'rails_helper' -RSpec.describe ImportService, type: :service do +RSpec.describe ImportService, :sidekiq_inline, type: :service do include RoutingHelper let!(:account) { Fabricate(:account, locked: false) } diff --git a/spec/services/mute_service_spec.rb b/spec/services/mute_service_spec.rb index 50f74ff27..a2ca2ffe1 100644 --- a/spec/services/mute_service_spec.rb +++ b/spec/services/mute_service_spec.rb @@ -17,7 +17,7 @@ RSpec.describe MuteService, type: :service do redis.del(home_timeline_key) end - it "clears account's statuses" do + it "clears account's statuses", :sidekiq_inline do FeedManager.instance.push_to_home(account, status) FeedManager.instance.push_to_home(account, other_account_status) diff --git a/spec/services/notify_service_spec.rb b/spec/services/notify_service_spec.rb index 50055dafc..38a33c522 100644 --- a/spec/services/notify_service_spec.rb +++ b/spec/services/notify_service_spec.rb @@ -166,7 +166,7 @@ RSpec.describe NotifyService, type: :service do context 'when email notification is enabled' do let(:enabled) { true } - it 'sends email' do + it 'sends email', :sidekiq_inline do expect { subject }.to change(ActionMailer::Base.deliveries, :count).by(1) end end diff --git a/spec/services/reblog_service_spec.rb b/spec/services/reblog_service_spec.rb index 7b85e37ed..c6d13e5a1 100644 --- a/spec/services/reblog_service_spec.rb +++ b/spec/services/reblog_service_spec.rb @@ -87,7 +87,7 @@ RSpec.describe ReblogService, type: :service do expect(ActivityPub::DistributionWorker).to have_received(:perform_async) end - it 'sends an announce activity to the author' do + it 'sends an announce activity to the author', :sidekiq_inline do expect(a_request(:post, bob.inbox_url)).to have_been_made.once end end diff --git a/spec/services/reject_follow_service_spec.rb b/spec/services/reject_follow_service_spec.rb index d28104b2c..48316a6c4 100644 --- a/spec/services/reject_follow_service_spec.rb +++ b/spec/services/reject_follow_service_spec.rb @@ -41,7 +41,7 @@ RSpec.describe RejectFollowService, type: :service do expect(bob.following?(sender)).to be false end - it 'sends a reject activity' do + it 'sends a reject activity', :sidekiq_inline do expect(a_request(:post, bob.inbox_url)).to have_been_made.once end end diff --git a/spec/services/remove_from_followers_service_spec.rb b/spec/services/remove_from_followers_service_spec.rb index 1b29cdcbe..21da38a97 100644 --- a/spec/services/remove_from_followers_service_spec.rb +++ b/spec/services/remove_from_followers_service_spec.rb @@ -33,7 +33,7 @@ RSpec.describe RemoveFromFollowersService, type: :service do expect(bob.followed_by?(sender)).to be false end - it 'sends a reject activity' do + it 'sends a reject activity', :sidekiq_inline do expect(a_request(:post, sender.inbox_url)).to have_been_made.once end end diff --git a/spec/services/remove_status_service_spec.rb b/spec/services/remove_status_service_spec.rb index cd3224e02..63a9df548 100644 --- a/spec/services/remove_status_service_spec.rb +++ b/spec/services/remove_status_service_spec.rb @@ -2,7 +2,7 @@ require 'rails_helper' -RSpec.describe RemoveStatusService, type: :service do +RSpec.describe RemoveStatusService, :sidekiq_inline, type: :service do subject { described_class.new } let!(:alice) { Fabricate(:account) } diff --git a/spec/services/report_service_spec.rb b/spec/services/report_service_spec.rb index 2a919f640..39e14a6a1 100644 --- a/spec/services/report_service_spec.rb +++ b/spec/services/report_service_spec.rb @@ -23,7 +23,7 @@ RSpec.describe ReportService, type: :service do stub_request(:post, 'http://example.com/inbox').to_return(status: 200) end - context 'when forward is true' do + context 'when forward is true', :sidekiq_inline do let(:forward) { true } it 'sends ActivityPub payload when forward is true' do diff --git a/spec/services/resolve_account_service_spec.rb b/spec/services/resolve_account_service_spec.rb index 3c4b182e2..1c4c3b401 100644 --- a/spec/services/resolve_account_service_spec.rb +++ b/spec/services/resolve_account_service_spec.rb @@ -195,7 +195,7 @@ RSpec.describe ResolveAccountService, type: :service do expect(account.uri).to eq 'https://ap.example.com/users/foo' end - it 'merges accounts' do + it 'merges accounts', :sidekiq_inline do account = subject.call('foo@ap.example.com') expect(status.reload.account_id).to eq account.id diff --git a/spec/services/suspend_account_service_spec.rb b/spec/services/suspend_account_service_spec.rb index dcc8dbfd3..4a5f8a0b6 100644 --- a/spec/services/suspend_account_service_spec.rb +++ b/spec/services/suspend_account_service_spec.rb @@ -2,7 +2,7 @@ require 'rails_helper' -RSpec.describe SuspendAccountService, type: :service do +RSpec.describe SuspendAccountService, :sidekiq_inline, type: :service do shared_examples 'common behavior' do subject { described_class.new.call(account) } diff --git a/spec/services/unallow_domain_service_spec.rb b/spec/services/unallow_domain_service_spec.rb index d96e35418..6ac6bc401 100644 --- a/spec/services/unallow_domain_service_spec.rb +++ b/spec/services/unallow_domain_service_spec.rb @@ -12,7 +12,7 @@ RSpec.describe UnallowDomainService, type: :service do let!(:already_banned_account) { Fabricate(:account, username: 'badguy', domain: 'evil.org', suspended: true, silenced: true) } let!(:domain_allow) { Fabricate(:domain_allow, domain: 'evil.org') } - context 'with limited federation mode' do + context 'with limited federation mode', :sidekiq_inline do before do allow(Rails.configuration.x).to receive(:limited_federation_mode).and_return(true) end diff --git a/spec/services/unblock_service_spec.rb b/spec/services/unblock_service_spec.rb index 86632c393..9813c5e7f 100644 --- a/spec/services/unblock_service_spec.rb +++ b/spec/services/unblock_service_spec.rb @@ -33,7 +33,7 @@ RSpec.describe UnblockService, type: :service do expect(sender.blocking?(bob)).to be false end - it 'sends an unblock activity' do + it 'sends an unblock activity', :sidekiq_inline do expect(a_request(:post, 'http://example.com/inbox')).to have_been_made.once end end diff --git a/spec/services/unfollow_service_spec.rb b/spec/services/unfollow_service_spec.rb index 3e65e610b..18a25a676 100644 --- a/spec/services/unfollow_service_spec.rb +++ b/spec/services/unfollow_service_spec.rb @@ -20,7 +20,7 @@ RSpec.describe UnfollowService, type: :service do end end - describe 'remote ActivityPub' do + describe 'remote ActivityPub', :sidekiq_inline do let(:bob) { Fabricate(:account, username: 'bob', protocol: :activitypub, domain: 'example.com', inbox_url: 'http://example.com/inbox') } before do @@ -38,7 +38,7 @@ RSpec.describe UnfollowService, type: :service do end end - describe 'remote ActivityPub (reverse)' do + describe 'remote ActivityPub (reverse)', :sidekiq_inline do let(:bob) { Fabricate(:account, username: 'bob', protocol: :activitypub, domain: 'example.com', inbox_url: 'http://example.com/inbox') } before do diff --git a/spec/services/unsuspend_account_service_spec.rb b/spec/services/unsuspend_account_service_spec.rb index 211c39e6c..c848767cd 100644 --- a/spec/services/unsuspend_account_service_spec.rb +++ b/spec/services/unsuspend_account_service_spec.rb @@ -45,7 +45,7 @@ RSpec.describe UnsuspendAccountService, type: :service do remote_follower.follow!(account) end - it 'merges back into feeds of local followers and sends update' do + it 'merges back into feeds of local followers and sends update', :sidekiq_inline do subject expect_feeds_merged diff --git a/spec/services/update_account_service_spec.rb b/spec/services/update_account_service_spec.rb index 6318cc95f..9f4e36862 100644 --- a/spec/services/update_account_service_spec.rb +++ b/spec/services/update_account_service_spec.rb @@ -5,7 +5,7 @@ require 'rails_helper' RSpec.describe UpdateAccountService, type: :service do subject { described_class.new } - describe 'switching form locked to unlocked accounts' do + describe 'switching form locked to unlocked accounts', :sidekiq_inline do let(:account) { Fabricate(:account, locked: true) } let(:alice) { Fabricate(:account) } let(:bob) { Fabricate(:account) } diff --git a/spec/services/update_status_service_spec.rb b/spec/services/update_status_service_spec.rb index 7f9f746c2..55651c305 100644 --- a/spec/services/update_status_service_spec.rb +++ b/spec/services/update_status_service_spec.rb @@ -111,7 +111,7 @@ RSpec.describe UpdateStatusService, type: :service do end end - context 'when poll changes', :sidekiq_fake do + context 'when poll changes' do let(:account) { Fabricate(:account) } let!(:status) { Fabricate(:status, text: 'Foo', account: account, poll_attributes: { options: %w(Foo Bar), account: account, multiple: false, hide_totals: false, expires_at: 7.days.from_now }) } let!(:poll) { status.poll } diff --git a/spec/support/capybara.rb b/spec/support/capybara.rb new file mode 100644 index 000000000..d4f27e209 --- /dev/null +++ b/spec/support/capybara.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +Capybara.server_host = 'localhost' +Capybara.server_port = 3000 +Capybara.app_host = "http://#{Capybara.server_host}:#{Capybara.server_port}" + +require 'selenium/webdriver' + +Capybara.register_driver :chrome do |app| + Capybara::Selenium::Driver.new(app, browser: :chrome) +end + +Capybara.register_driver :headless_chrome do |app| + options = Selenium::WebDriver::Chrome::Options.new + options.add_argument '--headless=new' + options.add_argument '--window-size=1680,1050' + + Capybara::Selenium::Driver.new( + app, + browser: :chrome, + options: options + ) +end + +Capybara.javascript_driver = :headless_chrome + +RSpec.configure do |config| + config.before(:each, type: :system) do + driven_by Capybara.javascript_driver + end +end diff --git a/spec/system/new_statuses_spec.rb b/spec/system/new_statuses_spec.rb index 02f2e2839..a3b816b4d 100644 --- a/spec/system/new_statuses_spec.rb +++ b/spec/system/new_statuses_spec.rb @@ -2,7 +2,7 @@ require 'rails_helper' -describe 'NewStatuses' do +describe 'NewStatuses', :sidekiq_inline do include ProfileStories subject { page } diff --git a/spec/system/share_entrypoint_spec.rb b/spec/system/share_entrypoint_spec.rb new file mode 100644 index 000000000..fd02d1120 --- /dev/null +++ b/spec/system/share_entrypoint_spec.rb @@ -0,0 +1,33 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe 'ShareEntrypoint' do + include ProfileStories + + subject { page } + + let(:email) { 'test@example.com' } + let(:password) { 'password' } + let(:confirmed_at) { Time.zone.now } + let(:finished_onboarding) { true } + + before do + as_a_logged_in_user + visit share_path + end + + it 'can be used to post a new status' do + expect(subject).to have_css('div#mastodon-compose') + expect(subject).to have_css('.compose-form__publish-button-wrapper > button') + + status_text = 'This is a new status!' + + within('.compose-form') do + fill_in "What's on your mind?", with: status_text + click_on 'Publish!' + end + + expect(subject).to have_css('.notification-bar-message', text: 'Post published.') + end +end diff --git a/spec/workers/backup_worker_spec.rb b/spec/workers/backup_worker_spec.rb index 1a169513e..987cbc7d6 100644 --- a/spec/workers/backup_worker_spec.rb +++ b/spec/workers/backup_worker_spec.rb @@ -14,7 +14,7 @@ describe BackupWorker do let(:backup) { Fabricate(:backup) } let!(:other_backup) { Fabricate(:backup, user: backup.user) } - it 'sends the backup to the service and removes other backups' do + it 'sends the backup to the service and removes other backups', :sidekiq_inline do expect do worker.perform(backup.id) end.to change(UserMailer.deliveries, :size).by(1) diff --git a/spec/workers/move_worker_spec.rb b/spec/workers/move_worker_spec.rb index 34b342710..0513dc42e 100644 --- a/spec/workers/move_worker_spec.rb +++ b/spec/workers/move_worker_spec.rb @@ -104,7 +104,7 @@ describe MoveWorker do end shared_examples 'lists handling' do - it 'puts the new account on the list and makes valid lists', sidekiq: :inline do + it 'puts the new account on the list and makes valid lists', :sidekiq_inline do subject.perform(source_account.id, target_account.id) expect(list.accounts.include?(target_account)).to be true @@ -159,7 +159,7 @@ describe MoveWorker do describe '#perform' do context 'when both accounts are distant' do - it 'calls UnfollowFollowWorker', :sidekiq_fake do + it 'calls UnfollowFollowWorker' do subject.perform(source_account.id, target_account.id) expect(UnfollowFollowWorker).to have_enqueued_sidekiq_job(local_follower.id, source_account.id, target_account.id, false) end @@ -170,7 +170,7 @@ describe MoveWorker do context 'when target account is local' do let(:target_account) { Fabricate(:account) } - it 'calls UnfollowFollowWorker', :sidekiq_fake do + it 'calls UnfollowFollowWorker' do subject.perform(source_account.id, target_account.id) expect(UnfollowFollowWorker).to have_enqueued_sidekiq_job(local_follower.id, source_account.id, target_account.id, true) end diff --git a/spec/workers/poll_expiration_notify_worker_spec.rb b/spec/workers/poll_expiration_notify_worker_spec.rb index ca36a3759..4bd90270d 100644 --- a/spec/workers/poll_expiration_notify_worker_spec.rb +++ b/spec/workers/poll_expiration_notify_worker_spec.rb @@ -10,7 +10,7 @@ describe PollExpirationNotifyWorker do let(:remote?) { false } let(:poll_vote) { Fabricate(:poll_vote, poll: poll) } - describe '#perform', :sidekiq_fake do + describe '#perform' do it 'runs without error for missing record' do expect { worker.perform(nil) }.to_not raise_error end