From e140d05a6a6d679153fe02ac38588aaa4656e464 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 16 Feb 2024 13:59:51 +0100 Subject: [PATCH 01/43] Update dependency doorkeeper to v5.6.9 (#29196) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Gemfile.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 0b53df82e064de..79d3b1e637d90c 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -219,7 +219,7 @@ GEM docile (1.4.0) domain_name (0.5.20190701) unf (>= 0.0.5, < 1.0.0) - doorkeeper (5.6.8) + doorkeeper (5.6.9) railties (>= 5) dotenv (2.8.1) dotenv-rails (2.8.1) @@ -811,7 +811,7 @@ GEM xorcist (1.1.3) xpath (3.2.0) nokogiri (~> 1.8) - zeitwerk (2.6.12) + zeitwerk (2.6.13) PLATFORMS ruby From bba488c189084d8499173c3e65dcce8e40a5606a Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Fri, 16 Feb 2024 08:00:09 -0500 Subject: [PATCH 02/43] Reduce `RSpec/MultipleExpectations` in media_attachment spec (#29228) --- spec/models/media_attachment_spec.rb | 51 ++++++++++++++-------------- 1 file changed, 26 insertions(+), 25 deletions(-) diff --git a/spec/models/media_attachment_spec.rb b/spec/models/media_attachment_spec.rb index 89916f9f500eee..1b9a13c38c2d62 100644 --- a/spec/models/media_attachment_spec.rb +++ b/spec/models/media_attachment_spec.rb @@ -91,20 +91,15 @@ end it 'saves media attachment with correct file metadata' do - expect(media.persisted?).to be true - expect(media.file).to_not be_nil - - # completes processing - expect(media.processing_complete?).to be true - - # sets type - expect(media.type).to eq 'image' - - # sets content type - expect(media.file_content_type).to eq content_type - - # sets file extension - expect(media.file_file_name).to end_with extension + expect(media) + .to be_persisted + .and be_processing_complete + .and have_attributes( + file: be_present, + type: eq('image'), + file_content_type: eq(content_type), + file_file_name: end_with(extension) + ) # Rack::Mime (used by PublicFileServerMiddleware) recognizes file extension expect(Rack::Mime.mime_type(extension, nil)).to eq content_type @@ -112,17 +107,23 @@ it 'saves media attachment with correct size metadata' do # strips original file name - expect(media.file_file_name).to_not start_with '600x400' - - # sets meta for original - expect(media.file.meta['original']['width']).to eq 600 - expect(media.file.meta['original']['height']).to eq 400 - expect(media.file.meta['original']['aspect']).to eq 1.5 - - # sets meta for thumbnail - expect(media.file.meta['small']['width']).to eq 588 - expect(media.file.meta['small']['height']).to eq 392 - expect(media.file.meta['small']['aspect']).to eq 1.5 + expect(media.file_file_name) + .to_not start_with '600x400' + + # sets meta for original and thumbnail + expect(media.file.meta.deep_symbolize_keys) + .to include( + original: include( + width: eq(600), + height: eq(400), + aspect: eq(1.5) + ), + small: include( + width: eq(588), + height: eq(392), + aspect: eq(1.5) + ) + ) end end From 1690fb39e6e4a26cc5f708626920d3491d7dd95b Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Fri, 16 Feb 2024 08:00:11 -0500 Subject: [PATCH 03/43] Reduce `RSpec/MultipleExpectations` in instance_actors_controller spec (#29229) --- .../instance_actors_controller_spec.rb | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/spec/controllers/instance_actors_controller_spec.rb b/spec/controllers/instance_actors_controller_spec.rb index 36b9049fbcf3c4..be1eefa7b22747 100644 --- a/spec/controllers/instance_actors_controller_spec.rb +++ b/spec/controllers/instance_actors_controller_spec.rb @@ -13,17 +13,19 @@ end it 'returns http success with correct media type, headers, and session values' do - expect(response).to have_http_status(200) + expect(response) + .to have_http_status(200) + .and have_attributes( + media_type: eq('application/activity+json'), + cookies: be_empty + ) - expect(response.media_type).to eq 'application/activity+json' - - expect(response.cookies).to be_empty - expect(response.headers['Set-Cookies']).to be_nil + expect(response.headers) + .to include('Cache-Control' => include('public')) + .and not_include('Set-Cookies') expect(session).to be_empty - expect(response.headers['Cache-Control']).to include 'public' - expect(body_as_json) .to include(:id, :type, :preferredUsername, :inbox, :publicKey, :inbox, :outbox, :url) end From 117b507df59b2f302c278797a0ea312aee68d570 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Fri, 16 Feb 2024 08:01:04 -0500 Subject: [PATCH 04/43] Extract `subject` from `User#mark_email_as_confirmed!` spec (#29231) --- spec/models/user_spec.rb | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 845335e87341e9..1baa3ccbf9c957 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -451,35 +451,32 @@ end describe '#mark_email_as_confirmed!' do - subject(:user) { Fabricate(:user, confirmed_at: confirmed_at) } + subject { user.mark_email_as_confirmed! } - before do - ActionMailer::Base.deliveries.clear - user.mark_email_as_confirmed! - end + let!(:user) { Fabricate(:user, confirmed_at: confirmed_at) } + + before { ActionMailer::Base.deliveries.clear } after { ActionMailer::Base.deliveries.clear } context 'when user is new' do let(:confirmed_at) { nil } - it 'confirms user' do - expect(user.confirmed_at).to be_present - end + it 'confirms user and delivers welcome email', :sidekiq_inline do + subject - it 'delivers mails', :sidekiq_inline do - expect(ActionMailer::Base.deliveries.count).to eq 2 + expect(user.confirmed_at).to be_present + expect(ActionMailer::Base.deliveries.count).to eq 1 end end context 'when user is not new' do let(:confirmed_at) { Time.zone.now } - it 'confirms user' do - expect(user.confirmed_at).to be_present - end + it 'confirms user but does not deliver welcome email' do + subject - it 'does not deliver mail' do + expect(user.confirmed_at).to be_present expect(ActionMailer::Base.deliveries.count).to eq 0 end end From a316c0e38de9e0dd5853c1c7a1f8d8b7188fb253 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Fri, 16 Feb 2024 08:01:15 -0500 Subject: [PATCH 05/43] Reduce round trips in disputes/appeals spec (#29232) --- .../disputes/appeals_controller_spec.rb | 22 +++++++------------ 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/spec/controllers/disputes/appeals_controller_spec.rb b/spec/controllers/disputes/appeals_controller_spec.rb index da2f86ade5efeb..d763068ebe8c67 100644 --- a/spec/controllers/disputes/appeals_controller_spec.rb +++ b/spec/controllers/disputes/appeals_controller_spec.rb @@ -10,19 +10,17 @@ let!(:admin) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')) } describe '#create' do + subject { post :create, params: params } + context 'with valid params' do let(:current_user) { Fabricate(:user) } let(:strike) { Fabricate(:account_warning, target_account: current_user.account) } + let(:params) { { strike_id: strike.id, appeal: { text: 'Foo' } } } - before do - post :create, params: { strike_id: strike.id, appeal: { text: 'Foo' } } - end + it 'notifies staff about new appeal and redirects back to strike page', :sidekiq_inline do + subject - it 'notifies staff about new appeal', :sidekiq_inline do expect(ActionMailer::Base.deliveries.first.to).to eq([admin.email]) - end - - it 'redirects back to the strike page' do expect(response).to redirect_to(disputes_strike_path(strike.id)) end end @@ -30,16 +28,12 @@ context 'with invalid params' do let(:current_user) { Fabricate(:user) } let(:strike) { Fabricate(:account_warning, target_account: current_user.account) } + let(:params) { { strike_id: strike.id, appeal: { text: '' } } } - before do - post :create, params: { strike_id: strike.id, appeal: { text: '' } } - end + it 'does not send email and renders strike show page', :sidekiq_inline do + subject - it 'does not send email', :sidekiq_inline do expect(ActionMailer::Base.deliveries.size).to eq(0) - end - - it 'renders the strike show page' do expect(response).to render_template('disputes/strikes/show') end end From 3454fcbd719f3f28b1466fd65c42c14d394212c0 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Fri, 16 Feb 2024 08:38:49 -0500 Subject: [PATCH 06/43] Reduce round trips in auth/sessions spec (#29233) --- .../auth/sessions_controller_spec.rb | 80 ++++++------------- 1 file changed, 25 insertions(+), 55 deletions(-) diff --git a/spec/controllers/auth/sessions_controller_spec.rb b/spec/controllers/auth/sessions_controller_spec.rb index b663f55afacd51..dcbaf1fcbb78c9 100644 --- a/spec/controllers/auth/sessions_controller_spec.rb +++ b/spec/controllers/auth/sessions_controller_spec.rb @@ -57,11 +57,9 @@ post :create, params: { user: { email: 'pam_user1', password: '123456' } } end - it 'redirects to home' do + it 'redirects to home and logs the user in' do expect(response).to redirect_to(root_path) - end - it 'logs the user in' do expect(controller.current_user).to be_instance_of(User) end end @@ -71,11 +69,9 @@ post :create, params: { user: { email: 'pam_user1', password: 'WRONGPW' } } end - it 'shows a login error' do + it 'shows a login error and does not log the user in' do expect(flash[:alert]).to match I18n.t('devise.failure.invalid', authentication_keys: I18n.t('activerecord.attributes.user.email')) - end - it "doesn't log the user in" do expect(controller.current_user).to be_nil end end @@ -92,11 +88,9 @@ post :create, params: { user: { email: user.email, password: '123456' } } end - it 'redirects to home' do + it 'redirects to home and logs the user in' do expect(response).to redirect_to(root_path) - end - it 'logs the user in' do expect(controller.current_user).to eq user end end @@ -110,16 +104,16 @@ post :create, params: { user: { email: user.email, password: user.password } } end - it 'redirects to home' do + it 'redirects to home and logs the user in' do expect(response).to redirect_to(root_path) - end - it 'logs the user in' do expect(controller.current_user).to eq user end end context 'when using a valid password on a previously-used account with a new IP address' do + subject { post :create, params: { user: { email: user.email, password: user.password } } } + let(:previous_ip) { '1.2.3.4' } let(:current_ip) { '4.3.2.1' } @@ -127,18 +121,17 @@ Fabricate(:login_activity, user: user, ip: previous_ip) allow(controller.request).to receive(:remote_ip).and_return(current_ip) user.update(current_sign_in_at: 1.month.ago) - post :create, params: { user: { email: user.email, password: user.password } } end - it 'redirects to home' do - expect(response).to redirect_to(root_path) - end + it 'logs the user in and sends suspicious email and redirects home', :sidekiq_inline do + subject - it 'logs the user in' do - expect(controller.current_user).to eq user - end + expect(response) + .to redirect_to(root_path) + + expect(controller.current_user) + .to eq user - 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')) @@ -150,11 +143,9 @@ post :create, params: { user: { email: user.email.upcase, password: user.password } } end - it 'redirects to home' do + it 'redirects to home and logs the user in' do expect(response).to redirect_to(root_path) - end - it 'logs the user in' do expect(controller.current_user).to eq user end end @@ -164,11 +155,9 @@ post :create, params: { user: { email: user.email, password: 'wrongpw' } } end - it 'shows a login error' do + it 'shows a login error and does not log the user in' do expect(flash[:alert]).to match I18n.t('devise.failure.invalid', authentication_keys: I18n.t('activerecord.attributes.user.email')) - end - it "doesn't log the user in" do expect(controller.current_user).to be_nil end end @@ -270,7 +259,7 @@ travel_to '2023-12-20T10:00:00Z' end - it 'does not log the user in' do + it 'does not log the user in, sets a flash message, and sends a suspicious sign in email', :sidekiq_inline do Auth::SessionsController::MAX_2FA_ATTEMPTS_PER_HOUR.times do post :create, params: { user: { otp_attempt: '1234' } }, session: { attempt_user_id: user.id, attempt_user_updated_at: user.updated_at.to_s } expect(controller.current_user).to be_nil @@ -278,17 +267,10 @@ post :create, params: { user: { otp_attempt: user.current_otp } }, session: { attempt_user_id: user.id, attempt_user_updated_at: user.updated_at.to_s } - expect(controller.current_user).to be_nil - expect(flash[:alert]).to match I18n.t('users.rate_limited') - end - - it 'sends a suspicious sign-in mail', :sidekiq_inline do - Auth::SessionsController::MAX_2FA_ATTEMPTS_PER_HOUR.times do - post :create, params: { user: { otp_attempt: '1234' } }, session: { attempt_user_id: user.id, attempt_user_updated_at: user.updated_at.to_s } - expect(controller.current_user).to be_nil - end - - post :create, params: { user: { otp_attempt: user.current_otp } }, session: { attempt_user_id: user.id, attempt_user_updated_at: user.updated_at.to_s } + expect(controller.current_user) + .to be_nil + expect(flash[:alert]) + .to match I18n.t('users.rate_limited') expect(UserMailer.deliveries.size).to eq(1) expect(UserMailer.deliveries.first.to.first).to eq(user.email) @@ -301,11 +283,9 @@ post :create, params: { user: { otp_attempt: user.current_otp } }, session: { attempt_user_id: user.id, attempt_user_updated_at: user.updated_at.to_s } end - it 'redirects to home' do + it 'redirects to home and logs the user in' do expect(response).to redirect_to(root_path) - end - it 'logs the user in' do expect(controller.current_user).to eq user end end @@ -318,11 +298,9 @@ post :create, params: { user: { otp_attempt: user.current_otp } }, session: { attempt_user_id: user.id, attempt_user_updated_at: user.updated_at.to_s } end - it 'shows a login error' do + it 'shows a login error and does not log the user in' do expect(flash[:alert]).to match I18n.t('users.invalid_otp_token') - end - it "doesn't log the user in" do expect(controller.current_user).to be_nil end end @@ -332,11 +310,9 @@ post :create, params: { user: { otp_attempt: recovery_codes.first } }, session: { attempt_user_id: user.id, attempt_user_updated_at: user.updated_at.to_s } end - it 'redirects to home' do + it 'redirects to home and logs the user in' do expect(response).to redirect_to(root_path) - end - it 'logs the user in' do expect(controller.current_user).to eq user end end @@ -346,11 +322,9 @@ post :create, params: { user: { otp_attempt: 'wrongotp' } }, session: { attempt_user_id: user.id, attempt_user_updated_at: user.updated_at.to_s } end - it 'shows a login error' do + it 'shows a login error and does not log the user in' do expect(flash[:alert]).to match I18n.t('users.invalid_otp_token') - end - it "doesn't log the user in" do expect(controller.current_user).to be_nil end end @@ -417,15 +391,11 @@ post :create, params: { user: { credential: fake_credential } }, session: { attempt_user_id: user.id, attempt_user_updated_at: user.updated_at.to_s } end - it 'instructs the browser to redirect to home' do + it 'instructs the browser to redirect to home, logs the user in, and updates the sign count' do expect(body_as_json[:redirect_path]).to eq(root_path) - end - it 'logs the user in' do expect(controller.current_user).to eq user - end - it 'updates the sign count' do expect(webauthn_credential.reload.sign_count).to eq(sign_count) end end From 1946e171e6d150cecedf3949c3c4630d5bce1066 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Fri, 16 Feb 2024 08:46:28 -0500 Subject: [PATCH 07/43] Reduce round trips in admin/disputes/appeals spec (#29234) --- .../admin/disputes/appeals_controller_spec.rb | 31 +++++++++---------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/spec/controllers/admin/disputes/appeals_controller_spec.rb b/spec/controllers/admin/disputes/appeals_controller_spec.rb index f830c3b95c974c..d36523316746aa 100644 --- a/spec/controllers/admin/disputes/appeals_controller_spec.rb +++ b/spec/controllers/admin/disputes/appeals_controller_spec.rb @@ -30,21 +30,19 @@ end describe 'POST #approve' do + subject { post :approve, params: { id: appeal.id } } + let(:current_user) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')) } - before do - post :approve, params: { id: appeal.id } - end + it 'redirects back to the strike page and notifies target account about approved appeal', :sidekiq_inline do + subject - it 'unsuspends a suspended account' do - expect(target_account.reload.suspended?).to be false - end + expect(response) + .to redirect_to(disputes_strike_path(appeal.strike)) - it 'redirects back to the strike page' do - expect(response).to redirect_to(disputes_strike_path(appeal.strike)) - end + expect(target_account.reload) + .to_not be_suspended - 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))) @@ -52,17 +50,16 @@ end describe 'POST #reject' do + subject { post :reject, params: { id: appeal.id } } + let(:current_user) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')) } - before do - post :reject, params: { id: appeal.id } - end + it 'redirects back to the strike page and notifies target account about rejected appeal', :sidekiq_inline do + subject - it 'redirects back to the strike page' do - expect(response).to redirect_to(disputes_strike_path(appeal.strike)) - end + expect(response) + .to redirect_to(disputes_strike_path(appeal.strike)) - 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))) From 1d9d14b8de67daab169d10293e1f09901734c445 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Fri, 16 Feb 2024 09:29:24 -0500 Subject: [PATCH 08/43] Use `abort` instead of `warn(); exit` in boot.rb env check (#29209) --- .rubocop.yml | 6 ------ config/boot.rb | 11 +++++++++-- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/.rubocop.yml b/.rubocop.yml index a8310489ea7084..dce33eab30d1b1 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -96,12 +96,6 @@ Rails/FilePath: Rails/HttpStatus: EnforcedStyle: numeric -# Reason: Allowed in boot ENV checker -# https://docs.rubocop.org/rubocop-rails/cops_rails.html#railsexit -Rails/Exit: - Exclude: - - 'config/boot.rb' - # Reason: Conflicts with `Lint/UselessMethodDefinition` for inherited controller actions # https://docs.rubocop.org/rubocop-rails/cops_rails.html#railslexicallyscopedactionfilter Rails/LexicallyScopedActionFilter: diff --git a/config/boot.rb b/config/boot.rb index 717de85f20f5e7..70ffe22c04d979 100644 --- a/config/boot.rb +++ b/config/boot.rb @@ -1,8 +1,15 @@ # frozen_string_literal: true unless ENV.key?('RAILS_ENV') - warn 'ERROR: Missing RAILS_ENV environment variable, please set it to "production", "development", or "test".' - exit 1 + abort <<~ERROR + The RAILS_ENV environment variable is not set. + + Please set it correctly depending on context: + + - Use "production" for a live deployment of the application + - Use "development" for local feature work + - Use "test" when running the automated spec suite + ERROR end ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__) From cfadb8707737ff679b1b08fa9dcab627a632f6ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolfgang=20Fourn=C3=A8s?= Date: Fri, 16 Feb 2024 15:54:23 +0100 Subject: [PATCH 09/43] Update enum syntax to use the new Rails 7.0 style (#29217) --- app/models/account.rb | 4 ++-- app/models/account_warning.rb | 4 ++-- app/models/bulk_import.rb | 4 ++-- app/models/custom_filter.rb | 2 +- app/models/domain_block.rb | 2 +- app/models/import.rb | 2 +- app/models/ip_block.rb | 2 +- app/models/list.rb | 2 +- app/models/login_activity.rb | 2 +- app/models/media_attachment.rb | 4 ++-- app/models/preview_card.rb | 4 ++-- app/models/relay.rb | 2 +- app/models/report.rb | 2 +- app/models/software_update.rb | 2 +- app/models/status.rb | 2 +- 15 files changed, 20 insertions(+), 20 deletions(-) diff --git a/app/models/account.rb b/app/models/account.rb index 05e1f943cae197..442d4a431d6c13 100644 --- a/app/models/account.rb +++ b/app/models/account.rb @@ -85,8 +85,8 @@ class Account < ApplicationRecord include DomainNormalizable include Paginable - enum protocol: { ostatus: 0, activitypub: 1 } - enum suspension_origin: { local: 0, remote: 1 }, _prefix: true + enum :protocol, { ostatus: 0, activitypub: 1 } + enum :suspension_origin, { local: 0, remote: 1 }, prefix: true validates :username, presence: true validates_with UniqueUsernameValidator, if: -> { will_save_change_to_username? } diff --git a/app/models/account_warning.rb b/app/models/account_warning.rb index 9286577f516e65..a54387a562f222 100644 --- a/app/models/account_warning.rb +++ b/app/models/account_warning.rb @@ -17,7 +17,7 @@ # class AccountWarning < ApplicationRecord - enum action: { + enum :action, { none: 0, disable: 1_000, mark_statuses_as_sensitive: 1_250, @@ -25,7 +25,7 @@ class AccountWarning < ApplicationRecord sensitive: 2_000, silence: 3_000, suspend: 4_000, - }, _suffix: :action + }, suffix: :action normalizes :text, with: ->(text) { text.to_s }, apply_to_nil: true diff --git a/app/models/bulk_import.rb b/app/models/bulk_import.rb index 406fb2aba26c7a..4cd228705a860a 100644 --- a/app/models/bulk_import.rb +++ b/app/models/bulk_import.rb @@ -24,7 +24,7 @@ class BulkImport < ApplicationRecord belongs_to :account has_many :rows, class_name: 'BulkImportRow', inverse_of: :bulk_import, dependent: :delete_all - enum type: { + enum :type, { following: 0, blocking: 1, muting: 2, @@ -33,7 +33,7 @@ class BulkImport < ApplicationRecord lists: 5, } - enum state: { + enum :state, { unconfirmed: 0, scheduled: 1, in_progress: 2, diff --git a/app/models/custom_filter.rb b/app/models/custom_filter.rb index c8120c239547a0..5e2d152e34895e 100644 --- a/app/models/custom_filter.rb +++ b/app/models/custom_filter.rb @@ -31,7 +31,7 @@ class CustomFilter < ApplicationRecord include Expireable include Redisable - enum action: { warn: 0, hide: 1 }, _suffix: :action + enum :action, { warn: 0, hide: 1 }, suffix: :action belongs_to :account has_many :keywords, class_name: 'CustomFilterKeyword', inverse_of: :custom_filter, dependent: :destroy diff --git a/app/models/domain_block.rb b/app/models/domain_block.rb index a05db099a8d1d8..e310918e9b436e 100644 --- a/app/models/domain_block.rb +++ b/app/models/domain_block.rb @@ -21,7 +21,7 @@ class DomainBlock < ApplicationRecord include DomainNormalizable include DomainMaterializable - enum severity: { silence: 0, suspend: 1, noop: 2 } + enum :severity, { silence: 0, suspend: 1, noop: 2 } validates :domain, presence: true, uniqueness: true, domain: true diff --git a/app/models/import.rb b/app/models/import.rb index 7cd6cccf7cec0b..4bdb392014b70d 100644 --- a/app/models/import.rb +++ b/app/models/import.rb @@ -28,7 +28,7 @@ class Import < ApplicationRecord belongs_to :account - enum type: { following: 0, blocking: 1, muting: 2, domain_blocking: 3, bookmarks: 4 } + enum :type, { following: 0, blocking: 1, muting: 2, domain_blocking: 3, bookmarks: 4 } validates :type, presence: true diff --git a/app/models/ip_block.rb b/app/models/ip_block.rb index 99783050b8aac7..9def5b0cde1016 100644 --- a/app/models/ip_block.rb +++ b/app/models/ip_block.rb @@ -19,7 +19,7 @@ class IpBlock < ApplicationRecord include Expireable include Paginable - enum severity: { + enum :severity, { sign_up_requires_approval: 5000, sign_up_block: 5500, no_access: 9999, diff --git a/app/models/list.rb b/app/models/list.rb index fcef49e6e9ad5f..b45bd057bc7caa 100644 --- a/app/models/list.rb +++ b/app/models/list.rb @@ -18,7 +18,7 @@ class List < ApplicationRecord PER_ACCOUNT_LIMIT = 50 - enum replies_policy: { list: 0, followed: 1, none: 2 }, _prefix: :show + enum :replies_policy, { list: 0, followed: 1, none: 2 }, prefix: :show belongs_to :account, optional: true diff --git a/app/models/login_activity.rb b/app/models/login_activity.rb index 2b7b37f8e499f6..654dd623ad13ca 100644 --- a/app/models/login_activity.rb +++ b/app/models/login_activity.rb @@ -16,7 +16,7 @@ # class LoginActivity < ApplicationRecord - enum authentication_method: { password: 'password', otp: 'otp', webauthn: 'webauthn', sign_in_token: 'sign_in_token', omniauth: 'omniauth' } + enum :authentication_method, { password: 'password', otp: 'otp', webauthn: 'webauthn', sign_in_token: 'sign_in_token', omniauth: 'omniauth' } belongs_to :user diff --git a/app/models/media_attachment.rb b/app/models/media_attachment.rb index 7ff6a15f5dcd49..f53da04a9755be 100644 --- a/app/models/media_attachment.rb +++ b/app/models/media_attachment.rb @@ -34,8 +34,8 @@ class MediaAttachment < ApplicationRecord include Attachmentable - enum type: { image: 0, gifv: 1, video: 2, unknown: 3, audio: 4 } - enum processing: { queued: 0, in_progress: 1, complete: 2, failed: 3 }, _prefix: true + enum :type, { image: 0, gifv: 1, video: 2, unknown: 3, audio: 4 } + enum :processing, { queued: 0, in_progress: 1, complete: 2, failed: 3 }, prefix: true MAX_DESCRIPTION_LENGTH = 1_500 diff --git a/app/models/preview_card.rb b/app/models/preview_card.rb index 83759274306cf3..9fe02bd1681014 100644 --- a/app/models/preview_card.rb +++ b/app/models/preview_card.rb @@ -47,8 +47,8 @@ class PreviewCard < ApplicationRecord self.inheritance_column = false - enum type: { link: 0, photo: 1, video: 2, rich: 3 } - enum link_type: { unknown: 0, article: 1 } + enum :type, { link: 0, photo: 1, video: 2, rich: 3 } + enum :link_type, { unknown: 0, article: 1 } has_many :preview_cards_statuses, dependent: :delete_all, inverse_of: :preview_card has_many :statuses, through: :preview_cards_statuses diff --git a/app/models/relay.rb b/app/models/relay.rb index 8d697b891f9360..f652b4864b66c0 100644 --- a/app/models/relay.rb +++ b/app/models/relay.rb @@ -15,7 +15,7 @@ class Relay < ApplicationRecord validates :inbox_url, presence: true, uniqueness: true, url: true, if: :will_save_change_to_inbox_url? - enum state: { idle: 0, pending: 1, accepted: 2, rejected: 3 } + enum :state, { idle: 0, pending: 1, accepted: 2, rejected: 3 } scope :enabled, -> { accepted } diff --git a/app/models/report.rb b/app/models/report.rb index 1b132753b515f5..df7e3d2efc0f62 100644 --- a/app/models/report.rb +++ b/app/models/report.rb @@ -55,7 +55,7 @@ class Report < ApplicationRecord # - app/javascript/mastodon/features/notifications/components/report.jsx # - app/javascript/mastodon/features/report/category.jsx # - app/javascript/mastodon/components/admin/ReportReasonSelector.jsx - enum category: { + enum :category, { other: 0, spam: 1_000, legal: 1_500, diff --git a/app/models/software_update.rb b/app/models/software_update.rb index cb3a6df2aeb96e..51a73c27311d9a 100644 --- a/app/models/software_update.rb +++ b/app/models/software_update.rb @@ -16,7 +16,7 @@ class SoftwareUpdate < ApplicationRecord self.inheritance_column = nil - enum type: { patch: 0, minor: 1, major: 2 }, _suffix: :type + enum :type, { patch: 0, minor: 1, major: 2 }, suffix: :type def gem_version Gem::Version.new(version) diff --git a/app/models/status.rb b/app/models/status.rb index e3d41ccedafcc7..0ec69c8dd14123 100644 --- a/app/models/status.rb +++ b/app/models/status.rb @@ -50,7 +50,7 @@ class Status < ApplicationRecord update_index('statuses', :proper) update_index('public_statuses', :proper) - enum visibility: { public: 0, unlisted: 1, private: 2, direct: 3, limited: 4 }, _suffix: :visibility + enum :visibility, { public: 0, unlisted: 1, private: 2, direct: 3, limited: 4 }, suffix: :visibility belongs_to :application, class_name: 'Doorkeeper::Application', optional: true From 96ddf1d4820419a6b5367af022be5cf17526109e Mon Sep 17 00:00:00 2001 From: Claire Date: Fri, 16 Feb 2024 17:57:23 +0100 Subject: [PATCH 10/43] Fix flaky end-to-end OCR test (#29244) --- spec/system/ocr_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/system/ocr_spec.rb b/spec/system/ocr_spec.rb index 3ab815c047ae60..254efa71370aff 100644 --- a/spec/system/ocr_spec.rb +++ b/spec/system/ocr_spec.rb @@ -28,6 +28,6 @@ click_on('Detect text from picture') - expect(page).to have_css('#upload-modal__description', text: 'Hello Mastodon') + expect(page).to have_css('#upload-modal__description', text: /Hello Mastodon\s*/, wait: 10) end end From 245064bb98ab11face7a04303fd62724820d9610 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Mon, 19 Feb 2024 06:09:43 -0500 Subject: [PATCH 11/43] Move "everyone" role and "instance actor" account magic number IDs to constants (#29260) --- app/models/account.rb | 5 +++-- app/models/concerns/account/finder_concern.rb | 4 ++-- app/models/user_role.rb | 10 ++++++---- db/migrate/20190715164535_add_instance_actor.rb | 6 ++++-- .../20220704024901_migrate_settings_to_user_roles.rb | 6 ++++-- db/seeds/02_instance_actor.rb | 2 +- lib/tasks/tests.rake | 2 +- spec/models/account_spec.rb | 4 ++-- spec/models/user_role_spec.rb | 6 +++--- 9 files changed, 26 insertions(+), 19 deletions(-) diff --git a/app/models/account.rb b/app/models/account.rb index 442d4a431d6c13..d627fd6b64422f 100644 --- a/app/models/account.rb +++ b/app/models/account.rb @@ -64,6 +64,7 @@ class Account < ApplicationRecord ) BACKGROUND_REFRESH_INTERVAL = 1.week.freeze + INSTANCE_ACTOR_ID = -99 USERNAME_RE = /[a-z0-9_]+([a-z0-9_.-]+[a-z0-9_]+)?/i MENTION_RE = %r{(? { where.not(sensitized_at: nil) } scope :without_suspended, -> { where(suspended_at: nil) } scope :without_silenced, -> { where(silenced_at: nil) } - scope :without_instance_actor, -> { where.not(id: -99) } + scope :without_instance_actor, -> { where.not(id: INSTANCE_ACTOR_ID) } scope :recent, -> { reorder(id: :desc) } scope :bots, -> { where(actor_type: %w(Application Service)) } scope :groups, -> { where(actor_type: 'Group') } @@ -176,7 +177,7 @@ def bot? end def instance_actor? - id == -99 + id == INSTANCE_ACTOR_ID end alias bot bot? diff --git a/app/models/concerns/account/finder_concern.rb b/app/models/concerns/account/finder_concern.rb index 7faaddeb4302c6..a7acff1cbbf968 100644 --- a/app/models/concerns/account/finder_concern.rb +++ b/app/models/concerns/account/finder_concern.rb @@ -13,11 +13,11 @@ def find_remote!(username, domain) end def representative - actor = Account.find(-99).tap(&:ensure_keys!) + actor = Account.find(Account::INSTANCE_ACTOR_ID).tap(&:ensure_keys!) actor.update!(username: 'mastodon.internal') if actor.username.include?(':') actor rescue ActiveRecord::RecordNotFound - Account.create!(id: -99, actor_type: 'Application', locked: true, username: 'mastodon.internal') + Account.create!(id: Account::INSTANCE_ACTOR_ID, actor_type: 'Application', locked: true, username: 'mastodon.internal') end def find_local(username) diff --git a/app/models/user_role.rb b/app/models/user_role.rb index 89354da5423bb3..ed64ca05380ad9 100644 --- a/app/models/user_role.rb +++ b/app/models/user_role.rb @@ -38,6 +38,8 @@ class UserRole < ApplicationRecord delete_user_data: (1 << 19), }.freeze + EVERYONE_ROLE_ID = -99 + module Flags NONE = 0 ALL = FLAGS.values.reduce(&:|) @@ -94,7 +96,7 @@ module Flags before_validation :set_position - scope :assignable, -> { where.not(id: -99).order(position: :asc) } + scope :assignable, -> { where.not(id: EVERYONE_ROLE_ID).order(position: :asc) } has_many :users, inverse_of: :role, foreign_key: 'role_id', dependent: :nullify @@ -103,9 +105,9 @@ def self.nobody end def self.everyone - UserRole.find(-99) + UserRole.find(EVERYONE_ROLE_ID) rescue ActiveRecord::RecordNotFound - UserRole.create!(id: -99, permissions: Flags::DEFAULT) + UserRole.create!(id: EVERYONE_ROLE_ID, permissions: Flags::DEFAULT) end def self.that_can(*any_of_privileges) @@ -113,7 +115,7 @@ def self.that_can(*any_of_privileges) end def everyone? - id == -99 + id == EVERYONE_ROLE_ID end def nobody? diff --git a/db/migrate/20190715164535_add_instance_actor.rb b/db/migrate/20190715164535_add_instance_actor.rb index 3785dc2553c4bd..6871b37bdf91c7 100644 --- a/db/migrate/20190715164535_add_instance_actor.rb +++ b/db/migrate/20190715164535_add_instance_actor.rb @@ -5,6 +5,8 @@ class Account < ApplicationRecord # Dummy class, to make migration possible across version changes validates :username, uniqueness: { scope: :domain, case_sensitive: false } + INSTANCE_ACTOR_ID = -99 + before_create :generate_keys def generate_keys @@ -15,10 +17,10 @@ def generate_keys end def up - Account.create!(id: -99, actor_type: 'Application', locked: true, username: Rails.configuration.x.local_domain) + Account.create!(id: Account::INSTANCE_ACTOR_ID, actor_type: 'Application', locked: true, username: Rails.configuration.x.local_domain) end def down - Account.find_by(id: -99, actor_type: 'Application').destroy! + Account.find_by(id: Account::INSTANCE_ACTOR_ID, actor_type: 'Application').destroy! end end diff --git a/db/post_migrate/20220704024901_migrate_settings_to_user_roles.rb b/db/post_migrate/20220704024901_migrate_settings_to_user_roles.rb index 00afee26d0c8d5..42dc37f08b42ed 100644 --- a/db/post_migrate/20220704024901_migrate_settings_to_user_roles.rb +++ b/db/post_migrate/20220704024901_migrate_settings_to_user_roles.rb @@ -3,7 +3,9 @@ class MigrateSettingsToUserRoles < ActiveRecord::Migration[6.1] disable_ddl_transaction! - class UserRole < ApplicationRecord; end + class UserRole < ApplicationRecord + EVERYONE_ROLE_ID = -99 + end def up process_role_everyone @@ -17,7 +19,7 @@ def down; end private def process_role_everyone - everyone_role = UserRole.find_by(id: -99) + everyone_role = UserRole.find_by(id: UserRole::EVERYONE_ROLE_ID) return unless everyone_role everyone_role.permissions &= ~::UserRole::FLAGS[:invite_users] unless min_invite_role == 'user' diff --git a/db/seeds/02_instance_actor.rb b/db/seeds/02_instance_actor.rb index 55e83e8a0815ca..2b6befec0d98e7 100644 --- a/db/seeds/02_instance_actor.rb +++ b/db/seeds/02_instance_actor.rb @@ -1,3 +1,3 @@ # frozen_string_literal: true -Account.create_with(actor_type: 'Application', locked: true, username: 'mastodon.internal').find_or_create_by(id: -99) +Account.create_with(actor_type: 'Application', locked: true, username: 'mastodon.internal').find_or_create_by(id: Account::INSTANCE_ACTOR_ID) diff --git a/lib/tasks/tests.rake b/lib/tasks/tests.rake index 885be79f4168dc..935f6d24a38eaa 100644 --- a/lib/tasks/tests.rake +++ b/lib/tasks/tests.rake @@ -50,7 +50,7 @@ namespace :tests do exit(1) end - if Account.find(-99).private_key.blank? + if Account.find(Account::INSTANCE_ACTOR_ID).private_key.blank? puts 'Instance actor does not have a private key' exit(1) end diff --git a/spec/models/account_spec.rb b/spec/models/account_spec.rb index b1dca52dc5e916..f6376eb36e7789 100644 --- a/spec/models/account_spec.rb +++ b/spec/models/account_spec.rb @@ -746,13 +746,13 @@ end it 'is valid if we are creating an instance actor account with a period' do - account = Fabricate.build(:account, id: -99, actor_type: 'Application', locked: true, username: 'example.com') + account = Fabricate.build(:account, id: described_class::INSTANCE_ACTOR_ID, actor_type: 'Application', locked: true, username: 'example.com') expect(account.valid?).to be true end it 'is valid if we are creating a possibly-conflicting instance actor account' do _account = Fabricate(:account, username: 'examplecom') - instance_account = Fabricate.build(:account, id: -99, actor_type: 'Application', locked: true, username: 'example.com') + instance_account = Fabricate.build(:account, id: described_class::INSTANCE_ACTOR_ID, actor_type: 'Application', locked: true, username: 'example.com') expect(instance_account.valid?).to be true end diff --git a/spec/models/user_role_spec.rb b/spec/models/user_role_spec.rb index d5234ebe8d96a9..9dd04a8172e424 100644 --- a/spec/models/user_role_spec.rb +++ b/spec/models/user_role_spec.rb @@ -164,12 +164,12 @@ end describe '#everyone?' do - it 'returns true when id is -99' do - subject.id = -99 + it 'returns true when id matches the everyone id' do + subject.id = described_class::EVERYONE_ROLE_ID expect(subject.everyone?).to be true end - it 'returns false when id is not -99' do + it 'returns false when id does not match the everyone id' do subject.id = 123 expect(subject.everyone?).to be false end From 63f4ea055aceff47ae47eabe6da103af05ffafd5 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 19 Feb 2024 12:09:58 +0100 Subject: [PATCH 12/43] Change follow suggestions design in web UI (#29272) --- .../components/inline_follow_suggestions.jsx | 25 ++++++++++++++++--- app/javascript/mastodon/locales/en.json | 7 +++++- .../styles/mastodon/components.scss | 9 +++++-- 3 files changed, 34 insertions(+), 7 deletions(-) diff --git a/app/javascript/mastodon/features/home_timeline/components/inline_follow_suggestions.jsx b/app/javascript/mastodon/features/home_timeline/components/inline_follow_suggestions.jsx index f76526e04502e2..c39b43badefac0 100644 --- a/app/javascript/mastodon/features/home_timeline/components/inline_follow_suggestions.jsx +++ b/app/javascript/mastodon/features/home_timeline/components/inline_follow_suggestions.jsx @@ -21,6 +21,7 @@ import { DisplayName } from 'mastodon/components/display_name'; import { Icon } from 'mastodon/components/icon'; import { IconButton } from 'mastodon/components/icon_button'; import { VerifiedBadge } from 'mastodon/components/verified_badge'; +import { domain } from 'mastodon/initial_state'; const messages = defineMessages({ follow: { id: 'account.follow', defaultMessage: 'Follow' }, @@ -28,27 +29,43 @@ const messages = defineMessages({ previous: { id: 'lightbox.previous', defaultMessage: 'Previous' }, next: { id: 'lightbox.next', defaultMessage: 'Next' }, dismiss: { id: 'follow_suggestions.dismiss', defaultMessage: "Don't show again" }, + friendsOfFriendsHint: { id: 'follow_suggestions.hints.friends_of_friends', defaultMessage: 'This profile is popular among the people you follow.' }, + similarToRecentlyFollowedHint: { id: 'follow_suggestions.hints.similar_to_recently_followed', defaultMessage: 'This profile is similar to the profiles you have most recently followed.' }, + featuredHint: { id: 'follow_suggestions.hints.featured', defaultMessage: 'This profile has been hand-picked by the {domain} team.' }, + mostFollowedHint: { id: 'follow_suggestions.hints.most_followed', defaultMessage: 'This profile is one of the most followed on {domain}.'}, + mostInteractionsHint: { id: 'follow_suggestions.hints.most_interactions', defaultMessage: 'This profile has been recently getting a lot of attention on {domain}.' }, }); const Source = ({ id }) => { - let label; + const intl = useIntl(); + + let label, hint; switch (id) { case 'friends_of_friends': + hint = intl.formatMessage(messages.friendsOfFriendsHint); + label = ; + break; case 'similar_to_recently_followed': + hint = intl.formatMessage(messages.similarToRecentlyFollowedHint); label = ; break; case 'featured': - label = ; + hint = intl.formatMessage(messages.featuredHint, { domain }); + label = ; break; case 'most_followed': + hint = intl.formatMessage(messages.mostFollowedHint, { domain }); + label = ; + break; case 'most_interactions': + hint = intl.formatMessage(messages.mostInteractionsHint, { domain }); label = ; break; } return ( -
+
{label}
@@ -92,7 +109,7 @@ const Card = ({ id, sources }) => { {firstVerifiedField ? : }
-