From 94aa5d7c9e27e537ec9ac455f91dc77da3838dd6 Mon Sep 17 00:00:00 2001 From: David Roetzel Date: Thu, 12 Mar 2026 11:14:22 +0100 Subject: [PATCH] Handle `Add` activity to `featuredCollections` (#38167) --- app/lib/activitypub/activity/add.rb | 8 +++++ spec/lib/activitypub/activity/add_spec.rb | 42 +++++++++++++++++++++++ 2 files changed, 50 insertions(+) diff --git a/app/lib/activitypub/activity/add.rb b/app/lib/activitypub/activity/add.rb index c86862c0a30..7b4576a06ae 100644 --- a/app/lib/activitypub/activity/add.rb +++ b/app/lib/activitypub/activity/add.rb @@ -12,6 +12,10 @@ class ActivityPub::Activity::Add < ActivityPub::Activity else add_featured end + when @account.collections_url + return unless Mastodon::Feature.collections_federation_enabled? + + add_collection else @collection = @account.collections.find_by(uri: @json['target']) add_collection_item if @collection && Mastodon::Feature.collections_federation_enabled? @@ -34,6 +38,10 @@ class ActivityPub::Activity::Add < ActivityPub::Activity FeaturedTag.create!(account: @account, name: name) if name.present? end + def add_collection + ActivityPub::ProcessFeaturedCollectionService.new.call(@account, @object) + end + def add_collection_item ActivityPub::ProcessFeaturedItemService.new.call(@collection, @object) end diff --git a/spec/lib/activitypub/activity/add_spec.rb b/spec/lib/activitypub/activity/add_spec.rb index 0f8ce53cfb9..d0bdfbe2185 100644 --- a/spec/lib/activitypub/activity/add_spec.rb +++ b/spec/lib/activitypub/activity/add_spec.rb @@ -80,6 +80,48 @@ RSpec.describe ActivityPub::Activity::Add do end end + context 'when the target is the `featuredCollections` collection', feature: :collections_federation do + subject { described_class.new(activity_json, account) } + + let(:account) { Fabricate(:remote_account, collections_url: 'https://example.com/actor/1/featured_collections') } + let(:featured_collection_json) do + { + '@context' => 'https://www.w3.org/ns/activitystreams', + 'id' => 'https://other.example.com/featured_item/1', + 'type' => 'FeaturedCollection', + 'attributedTo' => account.uri, + 'name' => 'Cool people', + 'summary' => 'People you should follow.', + 'totalItems' => 0, + 'sensitive' => false, + 'discoverable' => true, + 'published' => '2026-03-09T15:19:25Z', + } + end + let(:activity_json) do + { + '@context' => 'https://www.w3.org/ns/activitystreams', + 'type' => 'Add', + 'actor' => account.uri, + 'target' => 'https://example.com/actor/1/featured_collections', + 'object' => featured_collection_json, + } + end + let(:stubbed_service) do + instance_double(ActivityPub::ProcessFeaturedCollectionService, call: true) + end + + before do + allow(ActivityPub::ProcessFeaturedCollectionService).to receive(:new).and_return(stubbed_service) + end + + it 'calls the service' do + subject.perform + + expect(stubbed_service).to have_received(:call).with(account, featured_collection_json) + end + end + context 'when the target is a collection', feature: :collections_federation do subject { described_class.new(activity_json, collection.account) }