fetch_featured_collection_service.rb 2.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576
  1. # frozen_string_literal: true
  2. class ActivityPub::FetchFeaturedCollectionService < BaseService
  3. include JsonLdHelper
  4. def call(account, **options)
  5. return if account.featured_collection_url.blank? || account.suspended? || account.local?
  6. @account = account
  7. @options = options
  8. @json = fetch_resource(@account.featured_collection_url, true, local_follower)
  9. return unless supported_context?(@json)
  10. process_items(collection_items(@json))
  11. end
  12. private
  13. def collection_items(collection)
  14. collection = fetch_collection(collection['first']) if collection['first'].present?
  15. return unless collection.is_a?(Hash)
  16. case collection['type']
  17. when 'Collection', 'CollectionPage'
  18. collection['items']
  19. when 'OrderedCollection', 'OrderedCollectionPage'
  20. collection['orderedItems']
  21. end
  22. end
  23. def fetch_collection(collection_or_uri)
  24. return collection_or_uri if collection_or_uri.is_a?(Hash)
  25. return if invalid_origin?(collection_or_uri)
  26. fetch_resource_without_id_validation(collection_or_uri, local_follower, true)
  27. end
  28. def process_items(items)
  29. status_ids = items.filter_map do |item|
  30. uri = value_or_id(item)
  31. next if ActivityPub::TagManager.instance.local_uri?(uri) || invalid_origin?(uri)
  32. status = ActivityPub::FetchRemoteStatusService.new.call(uri, on_behalf_of: local_follower, expected_actor_uri: @account.uri, request_id: @options[:request_id])
  33. next unless status&.account_id == @account.id
  34. status.id
  35. rescue ActiveRecord::RecordInvalid => e
  36. Rails.logger.debug "Invalid pinned status #{uri}: #{e.message}"
  37. nil
  38. end
  39. to_remove = []
  40. to_add = status_ids
  41. StatusPin.where(account: @account).pluck(:status_id).each do |status_id|
  42. if status_ids.include?(status_id)
  43. to_add.delete(status_id)
  44. else
  45. to_remove << status_id
  46. end
  47. end
  48. StatusPin.where(account: @account, status_id: to_remove).delete_all unless to_remove.empty?
  49. to_add.each do |status_id|
  50. StatusPin.create!(account: @account, status_id: status_id)
  51. end
  52. end
  53. def local_follower
  54. return @local_follower if defined?(@local_follower)
  55. @local_follower = @account.followers.local.without_suspended.first
  56. end
  57. end