Fetch an actor's featured collections (#38306)

This commit is contained in:
David Roetzel
2026-03-20 16:34:04 +01:00
committed by GitHub
parent 8bce0b99d4
commit 7aa696149f
15 changed files with 220 additions and 18 deletions

View File

@@ -0,0 +1,118 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe ActivityPub::FetchFeaturedCollectionsCollectionService do
subject { described_class.new }
let(:account) { Fabricate(:remote_account, collections_url: 'https://example.com/account/featured_collections') }
let(:featured_collection_one) do
{
'@context' => 'https://www.w3.org/ns/activitystreams',
'id' => 'https://example.com/featured_collections/1',
'type' => 'FeaturedCollection',
'name' => 'Incredible people',
'summary' => 'These are really amazing',
'attributedTo' => account.uri,
'sensitive' => false,
'discoverable' => true,
'totalItems' => 0,
}
end
let(:featured_collection_two) do
{
'@context' => 'https://www.w3.org/ns/activitystreams',
'id' => 'https://example.com/featured_collections/2',
'type' => 'FeaturedCollection',
'name' => 'Even cooler people',
'summary' => 'These are just as amazing',
'attributedTo' => account.uri,
'sensitive' => false,
'discoverable' => true,
'totalItems' => 0,
}
end
let(:items) { [featured_collection_one, featured_collection_two] }
let(:collection_json) do
{
'@context' => 'https://www.w3.org/ns/activitystreams',
'type' => 'Collection',
'id' => account.collections_url,
'items' => items,
}
end
describe '#call' do
subject { described_class.new.call(account) }
before do
stub_request(:get, account.collections_url)
.to_return_json(status: 200, body: collection_json, headers: { 'Content-Type': 'application/activity+json' })
end
shared_examples 'collection creation' do
it 'creates the expected collections' do
expect { subject }.to change(account.collections, :count).by(2)
expect(account.collections.pluck(:name)).to contain_exactly('Incredible people', 'Even cooler people')
end
end
context 'when the endpoint is not paginated' do
context 'when all items are inlined' do
it_behaves_like 'collection creation'
end
context 'when items are URIs' do
let(:items) { [featured_collection_one['id'], featured_collection_two['id']] }
before do
[featured_collection_one, featured_collection_two].each do |featured_collection|
stub_request(:get, featured_collection['id'])
.to_return_json(status: 200, body: featured_collection, headers: { 'Content-Type': 'application/activity+json' })
end
end
it_behaves_like 'collection creation'
end
end
context 'when the endpoint is a paginated Collection' do
let(:first_page) do
{
'@context' => 'https://www.w3.org/ns/activitystreams',
'type' => 'CollectionPage',
'partOf' => account.collections_url,
'id' => 'https://example.com/featured_collections/1/1',
'items' => [featured_collection_one],
'next' => second_page['id'],
}
end
let(:second_page) do
{
'@context' => 'https://www.w3.org/ns/activitystreams',
'type' => 'CollectionPage',
'partOf' => account.collections_url,
'id' => 'https://example.com/featured_collections/1/2',
'items' => [featured_collection_two],
}
end
let(:collection_json) do
{
'@context' => 'https://www.w3.org/ns/activitystreams',
'type' => 'Collection',
'id' => account.collections_url,
'first' => first_page['id'],
}
end
before do
[first_page, second_page].each do |page|
stub_request(:get, page['id'])
.to_return_json(status: 200, body: page, headers: { 'Content-Type': 'application/activity+json' })
end
end
it_behaves_like 'collection creation'
end
end
end

View File

@@ -63,7 +63,7 @@ RSpec.describe ActivityPub::ProcessAccountService do
end
end
context 'with collection URIs' do
context 'with collection URIs', feature: :collections_federation do
let(:payload) do
{
'id' => 'https://foo.test',
@@ -81,13 +81,16 @@ RSpec.describe ActivityPub::ProcessAccountService do
.to_return(status: 200, body: '', headers: {})
end
it 'parses and sets the URIs' do
it 'parses and sets the URIs, queues jobs to synchronize' do
account = subject.call('alice', 'example.com', payload)
expect(account.featured_collection_url).to eq 'https://foo.test/featured'
expect(account.followers_url).to eq 'https://foo.test/followers'
expect(account.following_url).to eq 'https://foo.test/following'
expect(account.collections_url).to eq 'https://foo.test/featured_collections'
expect(ActivityPub::SynchronizeFeaturedCollectionWorker).to have_enqueued_sidekiq_job
expect(ActivityPub::SynchronizeFeaturedCollectionsCollectionWorker).to have_enqueued_sidekiq_job
end
end

View File

@@ -55,7 +55,7 @@ RSpec.describe ActivityPub::VerifyFeaturedItemService do
let(:stubbed_service) { instance_double(ActivityPub::FetchRemoteAccountService) }
before do
allow(stubbed_service).to receive(:call).with('https://example.com/actor/1') { featured_account }
allow(stubbed_service).to receive(:call).with('https://example.com/actor/1', request_id: nil) { featured_account }
allow(ActivityPub::FetchRemoteAccountService).to receive(:new).and_return(stubbed_service)
end

View File

@@ -19,7 +19,7 @@ RSpec.describe ActivityPub::ProcessFeaturedItemWorker do
it 'calls the service to process the item' do
subject.perform(collection.id, object)
expect(stubbed_service).to have_received(:call).with(collection, object)
expect(stubbed_service).to have_received(:call).with(collection, object, request_id: nil)
end
end
end

View File

@@ -0,0 +1,28 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe ActivityPub::SynchronizeFeaturedCollectionsCollectionWorker do
let(:worker) { described_class.new }
let(:service) { instance_double(ActivityPub::FetchFeaturedCollectionsCollectionService, call: true) }
describe '#perform' do
before do
allow(ActivityPub::FetchFeaturedCollectionsCollectionService).to receive(:new).and_return(service)
end
let(:account) { Fabricate(:account) }
it 'sends the account to the service' do
worker.perform(account.id)
expect(service).to have_received(:call).with(account, request_id: nil)
end
it 'returns true for non-existent record' do
result = worker.perform(123_123_123)
expect(result).to be(true)
end
end
end

View File

@@ -14,7 +14,7 @@ RSpec.describe ActivityPub::VerifyFeaturedItemWorker do
it 'sends the status to the service' do
worker.perform(collection_item.id, 'https://example.com/authorizations/1')
expect(service).to have_received(:call).with(collection_item, 'https://example.com/authorizations/1')
expect(service).to have_received(:call).with(collection_item, 'https://example.com/authorizations/1', request_id: nil)
end
it 'returns nil for non-existent record' do