Fix processing of compacted single-item JSON-LD collections (#28816)
This commit is contained in:
		@@ -23,9 +23,9 @@ class ActivityPub::FetchFeaturedCollectionService < BaseService
 | 
			
		||||
 | 
			
		||||
    case collection['type']
 | 
			
		||||
    when 'Collection', 'CollectionPage'
 | 
			
		||||
      collection['items']
 | 
			
		||||
      as_array(collection['items'])
 | 
			
		||||
    when 'OrderedCollection', 'OrderedCollectionPage'
 | 
			
		||||
      collection['orderedItems']
 | 
			
		||||
      as_array(collection['orderedItems'])
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -26,9 +26,9 @@ class ActivityPub::FetchRepliesService < BaseService
 | 
			
		||||
 | 
			
		||||
    case collection['type']
 | 
			
		||||
    when 'Collection', 'CollectionPage'
 | 
			
		||||
      collection['items']
 | 
			
		||||
      as_array(collection['items'])
 | 
			
		||||
    when 'OrderedCollection', 'OrderedCollectionPage'
 | 
			
		||||
      collection['orderedItems']
 | 
			
		||||
      as_array(collection['orderedItems'])
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -59,9 +59,9 @@ class ActivityPub::SynchronizeFollowersService < BaseService
 | 
			
		||||
 | 
			
		||||
    case collection['type']
 | 
			
		||||
    when 'Collection', 'CollectionPage'
 | 
			
		||||
      collection['items']
 | 
			
		||||
      as_array(collection['items'])
 | 
			
		||||
    when 'OrderedCollection', 'OrderedCollectionPage'
 | 
			
		||||
      collection['orderedItems']
 | 
			
		||||
      as_array(collection['orderedItems'])
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -69,7 +69,7 @@ class Keys::QueryService < BaseService
 | 
			
		||||
 | 
			
		||||
    return if json['items'].blank?
 | 
			
		||||
 | 
			
		||||
    @devices = json['items'].map do |device|
 | 
			
		||||
    @devices = as_array(json['items']).map do |device|
 | 
			
		||||
      Device.new(device_id: device['id'], name: device['name'], identity_key: device.dig('identityKey', 'publicKeyBase64'), fingerprint_key: device.dig('fingerprintKey', 'publicKeyBase64'), claim_url: device['claim'])
 | 
			
		||||
    end
 | 
			
		||||
  rescue HTTP::Error, OpenSSL::SSL::SSLError, Mastodon::Error => e
 | 
			
		||||
 
 | 
			
		||||
@@ -31,7 +31,7 @@ RSpec.describe ActivityPub::FetchFeaturedCollectionService, type: :service do
 | 
			
		||||
    }
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  let(:status_json_pinned_unknown_unreachable) do
 | 
			
		||||
  let(:status_json_pinned_unknown_reachable) do
 | 
			
		||||
    {
 | 
			
		||||
      '@context': 'https://www.w3.org/ns/activitystreams',
 | 
			
		||||
      type: 'Note',
 | 
			
		||||
@@ -75,7 +75,7 @@ RSpec.describe ActivityPub::FetchFeaturedCollectionService, type: :service do
 | 
			
		||||
      stub_request(:get, 'https://example.com/account/pinned/known').to_return(status: 200, body: Oj.dump(status_json_pinned_known))
 | 
			
		||||
      stub_request(:get, 'https://example.com/account/pinned/unknown-inlined').to_return(status: 200, body: Oj.dump(status_json_pinned_unknown_inlined))
 | 
			
		||||
      stub_request(:get, 'https://example.com/account/pinned/unknown-unreachable').to_return(status: 404)
 | 
			
		||||
      stub_request(:get, 'https://example.com/account/pinned/unknown-reachable').to_return(status: 200, body: Oj.dump(status_json_pinned_unknown_unreachable))
 | 
			
		||||
      stub_request(:get, 'https://example.com/account/pinned/unknown-reachable').to_return(status: 200, body: Oj.dump(status_json_pinned_unknown_reachable))
 | 
			
		||||
      stub_request(:get, 'https://example.com/account/collections/featured').to_return(status: 200, body: Oj.dump(featured_with_null))
 | 
			
		||||
 | 
			
		||||
      subject.call(actor, note: true, hashtag: false)
 | 
			
		||||
@@ -115,6 +115,21 @@ RSpec.describe ActivityPub::FetchFeaturedCollectionService, type: :service do
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      it_behaves_like 'sets pinned posts'
 | 
			
		||||
 | 
			
		||||
      context 'when there is a single item, with the array compacted away' do
 | 
			
		||||
        let(:items) { 'https://example.com/account/pinned/unknown-reachable' }
 | 
			
		||||
 | 
			
		||||
        before do
 | 
			
		||||
          stub_request(:get, 'https://example.com/account/pinned/unknown-reachable').to_return(status: 200, body: Oj.dump(status_json_pinned_unknown_reachable))
 | 
			
		||||
          subject.call(actor, note: true, hashtag: false)
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        it 'sets expected posts as pinned posts' do
 | 
			
		||||
          expect(actor.pinned_statuses.pluck(:uri)).to contain_exactly(
 | 
			
		||||
            'https://example.com/account/pinned/unknown-reachable'
 | 
			
		||||
          )
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    context 'when the endpoint is a paginated Collection' do
 | 
			
		||||
@@ -136,6 +151,21 @@ RSpec.describe ActivityPub::FetchFeaturedCollectionService, type: :service do
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      it_behaves_like 'sets pinned posts'
 | 
			
		||||
 | 
			
		||||
      context 'when there is a single item, with the array compacted away' do
 | 
			
		||||
        let(:items) { 'https://example.com/account/pinned/unknown-reachable' }
 | 
			
		||||
 | 
			
		||||
        before do
 | 
			
		||||
          stub_request(:get, 'https://example.com/account/pinned/unknown-reachable').to_return(status: 200, body: Oj.dump(status_json_pinned_unknown_reachable))
 | 
			
		||||
          subject.call(actor, note: true, hashtag: false)
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        it 'sets expected posts as pinned posts' do
 | 
			
		||||
          expect(actor.pinned_statuses.pluck(:uri)).to contain_exactly(
 | 
			
		||||
            'https://example.com/account/pinned/unknown-reachable'
 | 
			
		||||
          )
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
 
 | 
			
		||||
@@ -34,6 +34,18 @@ RSpec.describe ActivityPub::FetchRepliesService, type: :service do
 | 
			
		||||
 | 
			
		||||
  describe '#call' do
 | 
			
		||||
    context 'when the payload is a Collection with inlined replies' do
 | 
			
		||||
      context 'when there is a single reply, with the array compacted away' do
 | 
			
		||||
        let(:items) { 'http://example.com/self-reply-1' }
 | 
			
		||||
 | 
			
		||||
        it 'queues the expected worker' do
 | 
			
		||||
          allow(FetchReplyWorker).to receive(:push_bulk)
 | 
			
		||||
 | 
			
		||||
          subject.call(status, payload)
 | 
			
		||||
 | 
			
		||||
          expect(FetchReplyWorker).to have_received(:push_bulk).with(['http://example.com/self-reply-1'])
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      context 'when passing the collection itself' do
 | 
			
		||||
        it 'spawns workers for up to 5 replies on the same server' do
 | 
			
		||||
          allow(FetchReplyWorker).to receive(:push_bulk)
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user