Federate creation of collections (#37618)

This commit is contained in:
David Roetzel 2026-01-27 11:52:54 +01:00 committed by GitHub
parent aa347708f5
commit 1d4c2c5670
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 61 additions and 4 deletions

View File

@ -10,11 +10,13 @@ class ActivityPub::AddSerializer < ActivityPub::Serializer
end
def self.serializer_for(model, options)
case model.class.name
when 'Status'
case model
when Status
UriSerializer
when 'FeaturedTag'
when FeaturedTag
ActivityPub::HashtagSerializer
when Collection
ActivityPub::FeaturedCollectionSerializer
else
super
end
@ -38,6 +40,16 @@ class ActivityPub::AddSerializer < ActivityPub::Serializer
end
def target
ActivityPub::TagManager.instance.collection_uri_for(object.account, :featured)
case object
when Status, FeaturedTag
# Technically this is not correct, as tags have their own collection.
# But sadly we do not store the collection URI for tags anywhere so cannot
# handle `Add` activities to that properly (yet). The receiving code for
# this currently looks at the type of the contained objects to do the
# right thing.
ActivityPub::TagManager.instance.collection_uri_for(object.account, :featured)
when Collection
ap_account_featured_collections_url(object.account_id)
end
end
end

View File

@ -8,11 +8,18 @@ class CreateCollectionService
build_items
@collection.save!
distribute_add_activity if Mastodon::Feature.collections_federation_enabled?
@collection
end
private
def distribute_add_activity
ActivityPub::AccountRawDistributionWorker.perform_async(activity_json, @account.id)
end
def build_items
return if @accounts_to_add.empty?
@ -23,4 +30,8 @@ class CreateCollectionService
@collection.collection_items.build(account: account_to_add)
end
end
def activity_json
ActiveModelSerializers::SerializableResource.new(@collection, serializer: ActivityPub::AddSerializer, adapter: ActivityPub::Adapter).to_json
end
end

View File

@ -18,10 +18,38 @@ RSpec.describe ActivityPub::AddSerializer do
it { is_expected.to eq(ActivityPub::HashtagSerializer) }
end
context 'with a Collection model' do
let(:model) { Collection.new }
it { is_expected.to eq(ActivityPub::FeaturedCollectionSerializer) }
end
context 'with an Array' do
let(:model) { [] }
it { is_expected.to eq(ActiveModel::Serializer::CollectionSerializer) }
end
end
describe '#target' do
subject { described_class.new(object).target }
context 'when object is a Status' do
let(:object) { Fabricate(:status) }
it { is_expected.to match(%r{/#{object.account_id}/collections/featured$}) }
end
context 'when object is a FeaturedTag' do
let(:object) { Fabricate(:featured_tag) }
it { is_expected.to match(%r{/#{object.account_id}/collections/featured$}) }
end
context 'when object is a Collection' do
let(:object) { Fabricate(:collection) }
it { is_expected.to match(%r{/#{object.account_id}/featured_collections$}) }
end
end
end

View File

@ -29,6 +29,12 @@ RSpec.describe CreateCollectionService do
expect(collection).to be_local
end
it 'federates an `Add` activity', feature: :collections_federation do
subject.call(base_params, author)
expect(ActivityPub::AccountRawDistributionWorker).to have_enqueued_sidekiq_job
end
context 'when given account ids' do
let(:accounts) do
Fabricate.times(2, :account)