From c8f263c419368ccc469e32a462bb308e94b2ae3c Mon Sep 17 00:00:00 2001 From: Claire Date: Wed, 6 Aug 2025 13:31:36 +0200 Subject: [PATCH] Export interaction policies for local posts over ActivityPub (#35697) --- .../activitypub/note_serializer.rb | 21 ++++++++++++++++++- .../activitypub/note_serializer_spec.rb | 15 +++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/app/serializers/activitypub/note_serializer.rb b/app/serializers/activitypub/note_serializer.rb index 972f146bafc..05e3cf1bd21 100644 --- a/app/serializers/activitypub/note_serializer.rb +++ b/app/serializers/activitypub/note_serializer.rb @@ -3,7 +3,7 @@ class ActivityPub::NoteSerializer < ActivityPub::Serializer include FormattingHelper - context_extensions :atom_uri, :conversation, :sensitive, :voters_count, :quotes + context_extensions :atom_uri, :conversation, :sensitive, :voters_count, :quotes, :interaction_policies attributes :id, :type, :summary, :in_reply_to, :published, :url, @@ -35,6 +35,8 @@ class ActivityPub::NoteSerializer < ActivityPub::Serializer attribute :quote, key: :quote_uri, if: :quote? attribute :quote_authorization, if: :quote_authorization? + attribute :interaction_policy, if: -> { Mastodon::Feature.outgoing_quotes_enabled? } + def id ActivityPub::TagManager.instance.uri_for(object) end @@ -216,6 +218,23 @@ class ActivityPub::NoteSerializer < ActivityPub::Serializer ActivityPub::TagManager.instance.approval_uri_for(object.quote) end + def interaction_policy + approved_uris = [] + + # On outgoing posts, only automatic approval is supported + policy = object.quote_approval_policy >> 16 + approved_uris << ActivityPub::TagManager::COLLECTIONS[:public] if policy.anybits?(Status::QUOTE_APPROVAL_POLICY_FLAGS[:public]) + approved_uris << ActivityPub::TagManager.instance.followers_uri_for(object.account) if policy.anybits?(Status::QUOTE_APPROVAL_POLICY_FLAGS[:followers]) + approved_uris << ActivityPub::TagManager.instance.following_uri_for(object.account) if policy.anybits?(Status::QUOTE_APPROVAL_POLICY_FLAGS[:followed]) + approved_uris << ActivityPub::TagManager.instance.uri_for(object.account) if approved_uris.empty? + + { + canQuote: { + automaticApproval: approved_uris, + }, + } + end + class MediaAttachmentSerializer < ActivityPub::Serializer context_extensions :blurhash, :focal_point diff --git a/spec/serializers/activitypub/note_serializer_spec.rb b/spec/serializers/activitypub/note_serializer_spec.rb index 9c898e52121..d5d02a0d495 100644 --- a/spec/serializers/activitypub/note_serializer_spec.rb +++ b/spec/serializers/activitypub/note_serializer_spec.rb @@ -56,4 +56,19 @@ RSpec.describe ActivityPub::NoteSerializer do }) end end + + context 'with a quote policy', feature: :outgoing_quotes do + let(:parent) { Fabricate(:status, quote_approval_policy: Status::QUOTE_APPROVAL_POLICY_FLAGS[:followers] << 16) } + + it 'has the expected shape' do + expect(subject).to include({ + 'type' => 'Note', + 'interactionPolicy' => a_hash_including( + 'canQuote' => a_hash_including( + 'automaticApproval' => [ActivityPub::TagManager.instance.followers_uri_for(parent.account)] + ) + ), + }) + end + end end