diff options
author | Takeshi Umeda <noel.yoshiba@gmail.com> | 2022-10-20 16:15:52 +0900 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-10-20 09:15:52 +0200 |
commit | b0e3f0312c3271a2705f912602fcba70f4ed8b69 (patch) | |
tree | d6bb397c87c249d39b5716e9da0342edadd93edc /app/services | |
parent | d19c7f4a4ce7bc7ee24e02cf0ba956e9297f2b45 (diff) |
Add synchronization of remote featured tags (#19380)
* Add LIMIT of featured tag to instance API response * Add featured_tags_collection_url to Account * Add synchronization of remote featured tags * Deliver update activity when updating featured tag * Remove featured_tags_collection_url * Revert "Add featured_tags_collection_url to Account" This reverts commit cff349fc27b104ded2df6bb5665132dc24dab09c. * Add hashtag sync from featured collections * Fix tag name normalize * Add target option to fetch featured collection * Refactor fetch_featured_tags_collection_service * Add LIMIT of featured tag to v1/instance API response
Diffstat (limited to 'app/services')
3 files changed, 114 insertions, 2 deletions
diff --git a/app/services/activitypub/fetch_featured_collection_service.rb b/app/services/activitypub/fetch_featured_collection_service.rb index 37d05e055..026fe24c5 100644 --- a/app/services/activitypub/fetch_featured_collection_service.rb +++ b/app/services/activitypub/fetch_featured_collection_service.rb @@ -3,10 +3,11 @@ class ActivityPub::FetchFeaturedCollectionService < BaseService include JsonLdHelper - def call(account) + def call(account, **options) return if account.featured_collection_url.blank? || account.suspended? || account.local? @account = account + @options = options @json = fetch_resource(@account.featured_collection_url, true, local_follower) return unless supported_context?(@json) @@ -36,7 +37,15 @@ class ActivityPub::FetchFeaturedCollectionService < BaseService end def process_items(items) + process_note_items(items) if @options[:note] + process_hashtag_items(items) if @options[:hashtag] + end + + def process_note_items(items) status_ids = items.filter_map do |item| + type = item['type'] + next unless type == 'Note' + uri = value_or_id(item) next if ActivityPub::TagManager.instance.local_uri?(uri) @@ -67,6 +76,26 @@ class ActivityPub::FetchFeaturedCollectionService < BaseService end end + def process_hashtag_items(items) + names = items.filter_map { |item| item['type'] == 'Hashtag' && item['name']&.delete_prefix('#') }.map { |name| HashtagNormalizer.new.normalize(name) } + to_remove = [] + to_add = names + + FeaturedTag.where(account: @account).map(&:name).each do |name| + if names.include?(name) + to_add.delete(name) + else + to_remove << name + end + end + + FeaturedTag.includes(:tag).where(account: @account, tags: { name: to_remove }).delete_all unless to_remove.empty? + + to_add.each do |name| + FeaturedTag.create!(account: @account, name: name) + end + end + def local_follower return @local_follower if defined?(@local_follower) diff --git a/app/services/activitypub/fetch_featured_tags_collection_service.rb b/app/services/activitypub/fetch_featured_tags_collection_service.rb new file mode 100644 index 000000000..555919938 --- /dev/null +++ b/app/services/activitypub/fetch_featured_tags_collection_service.rb @@ -0,0 +1,78 @@ +# frozen_string_literal: true + +class ActivityPub::FetchFeaturedTagsCollectionService < BaseService + include JsonLdHelper + + def call(account, url) + return if url.blank? || account.suspended? || account.local? + + @account = account + @json = fetch_resource(url, true, local_follower) + + return unless supported_context?(@json) + + process_items(collection_items(@json)) + end + + private + + def collection_items(collection) + all_items = [] + + collection = fetch_collection(collection['first']) if collection['first'].present? + + while collection.is_a?(Hash) + items = begin + case collection['type'] + when 'Collection', 'CollectionPage' + collection['items'] + when 'OrderedCollection', 'OrderedCollectionPage' + collection['orderedItems'] + end + end + + break if items.blank? + + all_items.concat(items) + + break if all_items.size >= FeaturedTag::LIMIT + + collection = collection['next'].present? ? fetch_collection(collection['next']) : nil + end + + all_items + end + + def fetch_collection(collection_or_uri) + return collection_or_uri if collection_or_uri.is_a?(Hash) + return if invalid_origin?(collection_or_uri) + + fetch_resource_without_id_validation(collection_or_uri, local_follower, true) + end + + def process_items(items) + names = items.filter_map { |item| item['type'] == 'Hashtag' && item['name']&.delete_prefix('#') }.map { |name| HashtagNormalizer.new.normalize(name) } + to_remove = [] + to_add = names + + FeaturedTag.where(account: @account).map(&:name).each do |name| + if names.include?(name) + to_add.delete(name) + else + to_remove << name + end + end + + FeaturedTag.includes(:tag).where(account: @account, tags: { name: to_remove }).delete_all unless to_remove.empty? + + to_add.each do |name| + FeaturedTag.create!(account: @account, name: name) + end + end + + def local_follower + return @local_follower if defined?(@local_follower) + + @local_follower = @account.followers.local.without_suspended.first + end +end diff --git a/app/services/activitypub/process_account_service.rb b/app/services/activitypub/process_account_service.rb index 456b3524b..3834d79cc 100644 --- a/app/services/activitypub/process_account_service.rb +++ b/app/services/activitypub/process_account_service.rb @@ -39,6 +39,7 @@ class ActivityPub::ProcessAccountService < BaseService unless @options[:only_key] || @account.suspended? check_featured_collection! if @account.featured_collection_url.present? + check_featured_tags_collection! if @json['featuredTags'].present? check_links! unless @account.fields.empty? end @@ -149,7 +150,11 @@ class ActivityPub::ProcessAccountService < BaseService end def check_featured_collection! - ActivityPub::SynchronizeFeaturedCollectionWorker.perform_async(@account.id) + ActivityPub::SynchronizeFeaturedCollectionWorker.perform_async(@account.id, { 'hashtag' => @json['featuredTags'].blank? }) + end + + def check_featured_tags_collection! + ActivityPub::SynchronizeFeaturedTagsCollectionWorker.perform_async(@account.id, @json['featuredTags']) end def check_links! |