From 192e9d16eb60255770d468df4f9fa3297e5549ef Mon Sep 17 00:00:00 2001 From: Claire Date: Mon, 14 Oct 2024 10:18:25 +0200 Subject: [PATCH 1/9] Fix follow recommendation suppressions not applying immediately (#32392) --- app/models/follow_recommendation.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/models/follow_recommendation.rb b/app/models/follow_recommendation.rb index 7ac9e6dfb9..0435437a81 100644 --- a/app/models/follow_recommendation.rb +++ b/app/models/follow_recommendation.rb @@ -18,5 +18,6 @@ class FollowRecommendation < ApplicationRecord belongs_to :account_summary, foreign_key: :account_id, inverse_of: false belongs_to :account - scope :localized, ->(locale) { joins(:account_summary).merge(AccountSummary.localized(locale)) } + scope :unsupressed, -> { where.not(FollowRecommendationSuppression.where(FollowRecommendationSuppression.arel_table[:account_id].eq(arel_table[:account_id])).select(1).arel.exists) } + scope :localized, ->(locale) { unsupressed.joins(:account_summary).merge(AccountSummary.localized(locale)) } end From 5ee72f0e2d3381e7b9f08c3663feeea2f2ff33a1 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Mon, 14 Oct 2024 04:31:12 -0400 Subject: [PATCH 2/9] Convert `admin/tags` controller specs to system specs (#32447) --- .../controllers/admin/tags_controller_spec.rb | 82 ------------------- spec/system/admin/tags_spec.rb | 38 +++++++++ 2 files changed, 38 insertions(+), 82 deletions(-) delete mode 100644 spec/controllers/admin/tags_controller_spec.rb create mode 100644 spec/system/admin/tags_spec.rb diff --git a/spec/controllers/admin/tags_controller_spec.rb b/spec/controllers/admin/tags_controller_spec.rb deleted file mode 100644 index 1df2bc4003..0000000000 --- a/spec/controllers/admin/tags_controller_spec.rb +++ /dev/null @@ -1,82 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe Admin::TagsController do - render_views - - before do - sign_in Fabricate(:user, role: UserRole.find_by(name: 'Admin')) - end - - describe 'GET #index' do - before do - Fabricate(:tag) - - tag_filter = instance_double(Admin::TagFilter, results: Tag.all) - allow(Admin::TagFilter).to receive(:new).and_return(tag_filter) - end - - let(:params) { { order: 'newest' } } - - it 'returns http success' do - get :index - - expect(response).to have_http_status(200) - expect(response).to render_template(:index) - - expect(Admin::TagFilter) - .to have_received(:new) - .with(hash_including(params)) - end - - describe 'with filters' do - let(:params) { { order: 'newest', name: 'test' } } - - it 'returns http success' do - get :index, params: { name: 'test' } - - expect(response).to have_http_status(200) - expect(response).to render_template(:index) - - expect(Admin::TagFilter) - .to have_received(:new) - .with(hash_including(params)) - end - end - end - - describe 'GET #show' do - let!(:tag) { Fabricate(:tag) } - - before do - get :show, params: { id: tag.id } - end - - it 'returns status 200' do - expect(response).to have_http_status(200) - end - end - - describe 'PUT #update' do - let!(:tag) { Fabricate(:tag, listable: false) } - - context 'with valid params' do - it 'updates the tag' do - put :update, params: { id: tag.id, tag: { listable: '1' } } - - expect(response).to redirect_to(admin_tag_path(tag.id)) - expect(tag.reload).to be_listable - end - end - - context 'with invalid params' do - it 'does not update the tag' do - put :update, params: { id: tag.id, tag: { name: 'cant-change-name' } } - - expect(response).to have_http_status(200) - expect(response).to render_template(:show) - end - end - end -end diff --git a/spec/system/admin/tags_spec.rb b/spec/system/admin/tags_spec.rb new file mode 100644 index 0000000000..a3eca80d13 --- /dev/null +++ b/spec/system/admin/tags_spec.rb @@ -0,0 +1,38 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe 'Admin Tags' do + describe 'Tag interaction' do + let!(:tag) { Fabricate(:tag, name: 'test') } + + before { sign_in Fabricate(:user, role: UserRole.find_by(name: 'Admin')) } + + it 'allows tags listing and editing' do + visit admin_tags_path + + expect(page) + .to have_title(I18n.t('admin.tags.title')) + + click_on '#test' + + fill_in display_name_field, with: 'NewTagName' + expect { click_on submit_button } + .to_not(change { tag.reload.display_name }) + expect(page) + .to have_content(match_error_text) + + fill_in display_name_field, with: 'TEST' + expect { click_on submit_button } + .to(change { tag.reload.display_name }.to('TEST')) + end + + def display_name_field + I18n.t('simple_form.labels.defaults.display_name') + end + + def match_error_text + I18n.t('tags.does_not_match_previous_name') + end + end +end From ee61f7772a4fab239fe758072a8b493183f37013 Mon Sep 17 00:00:00 2001 From: Claire Date: Mon, 14 Oct 2024 15:00:20 +0200 Subject: [PATCH 3/9] Add further warnings about encryption secrets (#32476) --- config/initializers/active_record_encryption.rb | 1 + lib/tasks/db.rake | 11 +++++++++++ 2 files changed, 12 insertions(+) diff --git a/config/initializers/active_record_encryption.rb b/config/initializers/active_record_encryption.rb index b7a874e404..c53f16d4d1 100644 --- a/config/initializers/active_record_encryption.rb +++ b/config/initializers/active_record_encryption.rb @@ -20,6 +20,7 @@ - ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY Run `bin/rails db:encryption:init` to generate new secrets and then assign the environment variables. + Do not change the secrets once they are set, as doing so may cause data loss and other issues that will be difficult or impossible to recover from. MESSAGE end diff --git a/lib/tasks/db.rake b/lib/tasks/db.rake index 79599bd917..73de0c120f 100644 --- a/lib/tasks/db.rake +++ b/lib/tasks/db.rake @@ -7,6 +7,17 @@ namespace :db do namespace :encryption do desc 'Generate a set of keys for configuring Active Record encryption in a given environment' task :init do # rubocop:disable Rails/RakeEnvironment + if %w( + ACTIVE_RECORD_ENCRYPTION_DETERMINISTIC_KEY + ACTIVE_RECORD_ENCRYPTION_KEY_DERIVATION_SALT + ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY + ).any? { |key| ENV.key?(key) } + pastel = Pastel.new + puts pastel.red(<<~MSG) + WARNING: It looks like encryption secrets have already been set. Please ensure you are not changing secrets for a Mastodon installation that already uses them, as this will cause data loss and other issues that are difficult to recover from. + MSG + end + puts <<~MSG Add the following secret environment variables to your Mastodon environment (e.g. .env.production), ensure they are shared across all your nodes and do not change them after they are set:#{' '} From a2e24ee2de7e0b103a59ef5c6db121c4a3b3e0f9 Mon Sep 17 00:00:00 2001 From: Claire Date: Mon, 14 Oct 2024 17:25:32 +0200 Subject: [PATCH 4/9] Fix follow recommendation carrousel scrolling on RTL layouts (#32462) --- .../components/inline_follow_suggestions.jsx | 9 +++++++-- 1 file changed, 7 insertions(+), 2 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 1b8040e55b..14ea6bd996 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 @@ -129,8 +129,13 @@ export const InlineFollowSuggestions = ({ hidden }) => { return; } - setCanScrollLeft(bodyRef.current.scrollLeft > 0); - setCanScrollRight((bodyRef.current.scrollLeft + bodyRef.current.clientWidth) < bodyRef.current.scrollWidth); + if (getComputedStyle(bodyRef.current).direction === 'rtl') { + setCanScrollLeft((bodyRef.current.clientWidth - bodyRef.current.scrollLeft) < bodyRef.current.scrollWidth); + setCanScrollRight(bodyRef.current.scrollLeft < 0); + } else { + setCanScrollLeft(bodyRef.current.scrollLeft > 0); + setCanScrollRight((bodyRef.current.scrollLeft + bodyRef.current.clientWidth) < bodyRef.current.scrollWidth); + } }, [setCanScrollRight, setCanScrollLeft, bodyRef, suggestions]); const handleLeftNav = useCallback(() => { From 066efc2d3f6a3b07ac6c92b29507a0dea22bbecd Mon Sep 17 00:00:00 2001 From: Emelia Smith Date: Tue, 15 Oct 2024 09:40:18 +0200 Subject: [PATCH 5/9] Fix: Use consistent REDIS_USER environment variable in streaming (#32493) --- streaming/redis.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/streaming/redis.js b/streaming/redis.js index 2a36b89dc5..0b582ef2f5 100644 --- a/streaming/redis.js +++ b/streaming/redis.js @@ -50,9 +50,9 @@ function getSentinelConfiguration(env, commonOptions) { return { db: redisDatabase, name: env.REDIS_SENTINEL_MASTER, - username: env.REDIS_USERNAME, + username: env.REDIS_USER, password: env.REDIS_PASSWORD, - sentinelUsername: env.REDIS_SENTINEL_USERNAME ?? env.REDIS_USERNAME, + sentinelUsername: env.REDIS_SENTINEL_USERNAME ?? env.REDIS_USER, sentinelPassword: env.REDIS_SENTINEL_PASSWORD ?? env.REDIS_PASSWORD, sentinels, ...commonOptions, @@ -104,7 +104,7 @@ export function configFromEnv(env) { host: env.REDIS_HOST ?? '127.0.0.1', port: redisPort, db: redisDatabase, - username: env.REDIS_USERNAME, + username: env.REDIS_USER, password: env.REDIS_PASSWORD, ...commonOptions, }; From ca68a3cacbad0b462c5a3c89d694419254dd6e93 Mon Sep 17 00:00:00 2001 From: Renaud Chaput Date: Tue, 15 Oct 2024 11:15:25 +0200 Subject: [PATCH 6/9] Fix back arrow pointing to the incorrect direction in RTL languages (#32485) --- app/javascript/styles/mastodon/rtl.scss | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/javascript/styles/mastodon/rtl.scss b/app/javascript/styles/mastodon/rtl.scss index e4e299ff82..0a05ce7c62 100644 --- a/app/javascript/styles/mastodon/rtl.scss +++ b/app/javascript/styles/mastodon/rtl.scss @@ -35,6 +35,10 @@ body.rtl { direction: rtl; } + .column-back-button__icon { + transform: scale(-1, 1); + } + .simple_form select { background: $ui-base-color url("data:image/svg+xml;utf8,") From 304e440f88a3eccba60bc1ba8f0be40d1f623bc4 Mon Sep 17 00:00:00 2001 From: kenkiku1021 Date: Tue, 15 Oct 2024 18:28:07 +0900 Subject: [PATCH 7/9] add SWIFT object storage uri to CSP media hosts (#32439) Co-authored-by: Claire --- app/lib/content_security_policy.rb | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/app/lib/content_security_policy.rb b/app/lib/content_security_policy.rb index 0b60b0d98c..c764d1856d 100644 --- a/app/lib/content_security_policy.rb +++ b/app/lib/content_security_policy.rb @@ -36,7 +36,7 @@ class ContentSecurityPolicy end def cdn_host_value - s3_alias_host || s3_cloudfront_host || azure_alias_host || s3_hostname_host + s3_alias_host || s3_cloudfront_host || azure_alias_host || s3_hostname_host || swift_object_url end def paperclip_root_url @@ -72,6 +72,14 @@ class ContentSecurityPolicy host_to_url ENV.fetch('S3_HOSTNAME', nil) end + def swift_object_url + url = ENV.fetch('SWIFT_OBJECT_URL', nil) + return if url.blank? || !url.start_with?('https://') + + url += '/' unless url.end_with?('/') + url + end + def uri_from_configuration_and_string(host_string) Addressable::URI.parse("#{host_protocol}://#{host_string}").tap do |uri| uri.path += '/' unless uri.path.blank? || uri.path.end_with?('/') From 70472de726af69330ed1ef842e988cd678c454ab Mon Sep 17 00:00:00 2001 From: Claire Date: Tue, 15 Oct 2024 11:38:04 +0200 Subject: [PATCH 8/9] Fix follow recommendation carrousel scrolling on RTL layouts, for real (#32505) --- .../components/inline_follow_suggestions.jsx | 9 +++++++-- 1 file changed, 7 insertions(+), 2 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 14ea6bd996..3269b5a497 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 @@ -151,8 +151,13 @@ export const InlineFollowSuggestions = ({ hidden }) => { return; } - setCanScrollLeft(bodyRef.current.scrollLeft > 0); - setCanScrollRight((bodyRef.current.scrollLeft + bodyRef.current.clientWidth) < bodyRef.current.scrollWidth); + if (getComputedStyle(bodyRef.current).direction === 'rtl') { + setCanScrollLeft((bodyRef.current.clientWidth - bodyRef.current.scrollLeft) < bodyRef.current.scrollWidth); + setCanScrollRight(bodyRef.current.scrollLeft < 0); + } else { + setCanScrollLeft(bodyRef.current.scrollLeft > 0); + setCanScrollRight((bodyRef.current.scrollLeft + bodyRef.current.clientWidth) < bodyRef.current.scrollWidth); + } }, [setCanScrollRight, setCanScrollLeft, bodyRef]); const handleDismiss = useCallback(() => { From 49b3d5692e6f217e6506674ad8a623a4ba8d0c5f Mon Sep 17 00:00:00 2001 From: Jeong Arm Date: Tue, 15 Oct 2024 06:01:21 -0400 Subject: [PATCH 9/9] Fix reblog icons on account media view (#32506) --- .../features/picture_in_picture/components/footer.jsx | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/app/javascript/mastodon/features/picture_in_picture/components/footer.jsx b/app/javascript/mastodon/features/picture_in_picture/components/footer.jsx index 300c8dd5b3..5c83f99b54 100644 --- a/app/javascript/mastodon/features/picture_in_picture/components/footer.jsx +++ b/app/javascript/mastodon/features/picture_in_picture/components/footer.jsx @@ -14,6 +14,8 @@ import RepeatIcon from '@/material-icons/400-24px/repeat.svg?react'; import ReplyIcon from '@/material-icons/400-24px/reply.svg?react'; import ReplyAllIcon from '@/material-icons/400-24px/reply_all.svg?react'; import StarIcon from '@/material-icons/400-24px/star.svg?react'; +import RepeatDisabledIcon from '@/svg-icons/repeat_disabled.svg?react'; +import RepeatPrivateIcon from '@/svg-icons/repeat_private.svg?react'; import { replyCompose } from 'mastodon/actions/compose'; import { toggleReblog, toggleFavourite } from 'mastodon/actions/interactions'; import { openModal } from 'mastodon/actions/modal'; @@ -159,22 +161,26 @@ class Footer extends ImmutablePureComponent { replyTitle = intl.formatMessage(messages.replyAll); } - let reblogTitle = ''; + let reblogTitle, reblogIconComponent; if (status.get('reblogged')) { reblogTitle = intl.formatMessage(messages.cancel_reblog_private); + reblogIconComponent = publicStatus ? RepeatIcon : RepeatPrivateIcon; } else if (publicStatus) { reblogTitle = intl.formatMessage(messages.reblog); + reblogIconComponent = RepeatIcon; } else if (reblogPrivate) { reblogTitle = intl.formatMessage(messages.reblog_private); + reblogIconComponent = RepeatPrivateIcon; } else { reblogTitle = intl.formatMessage(messages.cannot_reblog); + reblogIconComponent = RepeatDisabledIcon; } return (
- + {withOpenButton && }