From dee744c79382ffd208bcf050cf8f32e02724e110 Mon Sep 17 00:00:00 2001 From: Claire Date: Wed, 23 Apr 2025 09:29:13 +0200 Subject: [PATCH] Fix quote serializer (#34510) --- .../status_relationships_presenter.rb | 33 +++++++++++++++---- app/serializers/rest/base_quote_serializer.rb | 2 +- spec/requests/api/v1/timelines/home_spec.rb | 7 +++- 3 files changed, 34 insertions(+), 8 deletions(-) diff --git a/app/presenters/status_relationships_presenter.rb b/app/presenters/status_relationships_presenter.rb index 2d95db82da..0807f1c95e 100644 --- a/app/presenters/status_relationships_presenter.rb +++ b/app/presenters/status_relationships_presenter.rb @@ -7,14 +7,24 @@ class StatusRelationshipsPresenter :bookmarks_map, :filters_map, :attributes_map def initialize(statuses, current_account_id = nil, **options) + @current_account_id = current_account_id + + # Keeping a reference to @statuses is ok since `StatusRelationshipsPresenter` + # basically never outlives the statuses collection it is passed + @statuses = statuses + if current_account_id.nil? - @reblogs_map = {} - @favourites_map = {} - @bookmarks_map = {} - @mutes_map = {} - @pins_map = {} - @filters_map = {} + @preloaded_account_relations = {} + @filters_map = {} + @reblogs_map = {} + @favourites_map = {} + @bookmarks_map = {} + @mutes_map = {} + @pins_map = {} + @attributes_map = {} else + @preloaded_account_relations = nil + statuses = statuses.compact status_ids = statuses.flat_map { |s| [s.id, s.reblog_of_id, s.proper.quote&.quoted_status_id] }.uniq.compact conversation_ids = statuses.flat_map { |s| [s.proper.conversation_id, s.proper.quote&.quoted_status&.conversation_id] }.uniq.compact @@ -30,6 +40,17 @@ class StatusRelationshipsPresenter end end + # This one is currently on-demand as it is only used for quote posts + def preloaded_account_relations + @preloaded_account_relations ||= begin + accounts = @statuses.compact.flat_map { |s| [s.account, s.proper.account, s.proper.quote&.quoted_account] }.uniq.compact + + account_ids = accounts.pluck(:id) + account_domains = accounts.pluck(:domain).uniq + Account.find(@current_account_id).relations_map(account_ids, account_domains) + end + end + private def build_filters_map(statuses, current_account_id) diff --git a/app/serializers/rest/base_quote_serializer.rb b/app/serializers/rest/base_quote_serializer.rb index 0434f342c9..20a53d1a20 100644 --- a/app/serializers/rest/base_quote_serializer.rb +++ b/app/serializers/rest/base_quote_serializer.rb @@ -20,6 +20,6 @@ class REST::BaseQuoteSerializer < ActiveModel::Serializer private def status_filter - @status_filter ||= StatusFilter.new(object.quoted_status, current_user&.account, instance_options[:relationships] || {}) + @status_filter ||= StatusFilter.new(object.quoted_status, current_user&.account, instance_options[:relationships]&.preloaded_account_relations || {}) end end diff --git a/spec/requests/api/v1/timelines/home_spec.rb b/spec/requests/api/v1/timelines/home_spec.rb index 2023b189ec..38e18979d2 100644 --- a/spec/requests/api/v1/timelines/home_spec.rb +++ b/spec/requests/api/v1/timelines/home_spec.rb @@ -26,8 +26,13 @@ RSpec.describe 'Home', :inline_jobs do before do user.account.follow!(bob) user.account.follow!(ana) - PostStatusService.new.call(bob, text: 'New toot from bob.') + quoted = PostStatusService.new.call(bob, text: 'New toot from bob.') PostStatusService.new.call(tim, text: 'New toot from tim.') + reblogged = PostStatusService.new.call(tim, text: 'New toot from tim, which will end up boosted.') + ReblogService.new.call(bob, reblogged) + # TODO: use PostStatusService argument when available rather than manually creating quote + quoting = PostStatusService.new.call(bob, text: 'Self-quote from bob.') + Quote.create!(status: quoting, quoted_status: quoted, state: :accepted) PostStatusService.new.call(ana, text: 'New toot from ana.') end