# frozen_string_literal: true class ActivityPub::FetchCollectionItemsService < BaseService include JsonLdHelper def call(collection_or_uri, account, page_limit: 10, item_limit: 100, **options) @account = account @allow_synchronous_requests = options[:allow_synchronous_requests] @sync = options[:sync] return [] if collection_or_uri.is_a?(String) && ActivityPub::TagManager.instance.local_uri?(collection_or_uri) collection_items(collection_or_uri, page_limit, item_limit) end private def collection_items(collection_or_uri, page_limit, item_limit) collection = fetch_collection(collection_or_uri) return [] unless collection.is_a?(Hash) collection = fetch_collection(collection['first']) if collection['first'].present? page_count = 0 item_count = 0 items = [] while collection.present? && collection.is_a?(Hash) && collection['type'].present? batch = case collection['type'] when 'Collection', 'CollectionPage' collection['items'].each when 'OrderedCollection', 'OrderedCollectionPage' collection['orderedItems'] end batch_size = [batch.count, item_limit - item_count].min items.push( batch.take(batch_size) .map { |item| value_or_id(item) } .reject { |uri| unsupported_uri_scheme?(uri) || ActivityPub::TagManager.instance.local_uri?(uri) } ) item_count += batch_size page_count += 1 break unless item_count < item_limit && page_count < page_limit && collection['next'].present? collection = fetch_collection(collection['next']) end items.uniq end def fetch_collection(collection_or_uri) return collection_or_uri if collection_or_uri.is_a?(Hash) return unless @allow_synchronous_requests return if invalid_origin?(collection_or_uri) on_behalf_of = @account.present? ? @account.followers.local.first : nil fetch_resource_without_id_validation(collection_or_uri, on_behalf_of, true) rescue Mastodon::UnexpectedResponseError nil end end