You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

72 lines
2.1 KiB

  1. # frozen_string_literal: true
  2. class ActivityPub::FetchFeaturedTagsCollectionService < BaseService
  3. include JsonLdHelper
  4. def call(account, url)
  5. return if url.blank? || account.suspended? || account.local?
  6. @account = account
  7. @json = fetch_resource(url, true, local_follower)
  8. return unless supported_context?(@json)
  9. process_items(collection_items(@json))
  10. end
  11. private
  12. def collection_items(collection)
  13. all_items = []
  14. collection = fetch_collection(collection['first']) if collection['first'].present?
  15. while collection.is_a?(Hash)
  16. items = case collection['type']
  17. when 'Collection', 'CollectionPage'
  18. collection['items']
  19. when 'OrderedCollection', 'OrderedCollectionPage'
  20. collection['orderedItems']
  21. end
  22. break if items.blank?
  23. all_items.concat(items)
  24. break if all_items.size >= FeaturedTag::LIMIT
  25. collection = collection['next'].present? ? fetch_collection(collection['next']) : nil
  26. end
  27. all_items
  28. end
  29. def fetch_collection(collection_or_uri)
  30. return collection_or_uri if collection_or_uri.is_a?(Hash)
  31. return if invalid_origin?(collection_or_uri)
  32. fetch_resource_without_id_validation(collection_or_uri, local_follower, true)
  33. end
  34. def process_items(items)
  35. names = items.filter_map { |item| item['type'] == 'Hashtag' && item['name']&.delete_prefix('#') }.take(FeaturedTag::LIMIT)
  36. tags = names.index_by { |name| HashtagNormalizer.new.normalize(name) }
  37. normalized_names = tags.keys
  38. FeaturedTag.includes(:tag).references(:tag).where(account: @account).where.not(tag: { name: normalized_names }).delete_all
  39. FeaturedTag.includes(:tag).references(:tag).where(account: @account, tag: { name: normalized_names }).each do |featured_tag|
  40. featured_tag.update(name: tags.delete(featured_tag.tag.name))
  41. end
  42. tags.each_value do |name|
  43. FeaturedTag.create!(account: @account, name: name)
  44. end
  45. end
  46. def local_follower
  47. return @local_follower if defined?(@local_follower)
  48. @local_follower = @account.followers.local.without_suspended.first
  49. end
  50. end