From 68c7def8d3646e1e334ea956fda9800615534eaa Mon Sep 17 00:00:00 2001 From: KMY Date: Sun, 26 Feb 2023 11:37:48 +0900 Subject: [PATCH] Add activitypub emoji_reaction receiving --- app/lib/activitypub/activity/like.rb | 90 ++++++++++++++++++++++++++-- app/lib/activitypub/activity/undo.rb | 55 ++++++++++++++++- app/services/emoji_react_service.rb | 6 -- 3 files changed, 139 insertions(+), 12 deletions(-) diff --git a/app/lib/activitypub/activity/like.rb b/app/lib/activitypub/activity/like.rb index aa1dc3040..db3cb91b3 100644 --- a/app/lib/activitypub/activity/like.rb +++ b/app/lib/activitypub/activity/like.rb @@ -2,13 +2,93 @@ class ActivityPub::Activity::Like < ActivityPub::Activity def perform - original_status = status_from_uri(object_uri) + @original_status = status_from_uri(object_uri) - return if original_status.nil? || !original_status.account.local? || delete_arrived_first?(@json['id']) || @account.favourited?(original_status) + return if @original_status.nil? || !@original_status.account.local? || delete_arrived_first?(@json['id']) - favourite = original_status.favourites.create!(account: @account) + lock_or_fail("like:#{object_uri}") do + if shortcode.nil? + process_favourite + else + process_emoji_reaction + end + end + end - LocalNotificationWorker.perform_async(original_status.account_id, favourite.id, 'Favourite', 'favourite') - Trends.statuses.register(original_status) + private + + def process_favourite + return if @account.favourited?(@original_status) + + favourite = @original_status.favourites.create!(account: @account) + + LocalNotificationWorker.perform_async(@original_status.account_id, favourite.id, 'Favourite', 'favourite') + Trends.statuses.register(@original_status) + end + + def process_emoji_reaction + if emoji_tag.present? + return if emoji_tag['id'].blank? || emoji_tag['name'].blank? || emoji_tag['icon'].blank? || emoji_tag['icon']['url'].blank? + + image_url = emoji_tag['icon']['url'] + uri = emoji_tag['id'] + domain = URI.split(uri)[2] + + emoji = CustomEmoji.find_or_create_by!(shortcode: shortcode, domain: domain) do |emoji| + emoji.uri = uri + emoji.image_remote_url = image_url + end + end + + return if @account.reacted?(@original_status, shortcode, emoji) + + EmojiReaction.find_by(account: @account, status: @original_status)&.destroy + reaction = @original_status.emoji_reactions.create!(account: @account, name: shortcode, custom_emoji: emoji, uri: @json['id']) + + if @original_status.account.local? + NotifyService.new.call(@original_status.account, :emoji_reaction, reaction) + forward_for_emoji_reaction + relay_for_emoji_reaction + end + rescue Seahorse::Client::NetworkingError + nil + end + + def forward_for_emoji_reaction + return unless @json['signature'].present? + + ActivityPub::RawDistributionWorker.perform_async(Oj.dump(@json), @original_status.account.id, [@account.preferred_inbox_url]) + end + + def relay_for_emoji_reaction + return unless @json['signature'].present? && @original_status.public_visibility? + + ActivityPub::DeliveryWorker.push_bulk(Relay.enabled.pluck(:inbox_url)) do |inbox_url| + [Oj.dump(@json), @original_status.account.id, inbox_url] + end + end + + def shortcode + return @shortcode if defined?(@shortcode) + + @shortcode = begin + if @json['_misskey_reaction'] == '⭐' + nil + else + @json['content']&.delete(':') + end + end + end + + def misskey_favourite? + misskey_shortcode = @json['_misskey_reaction']&.delete(':') + + return misskey_shortcode == shortcode && misskey_shortcode == '⭐' + end + + def emoji_tag + return @emoji_tag if defined?(@emoji_tag) + + @emoji_tag = @json['tag'].is_a?(Array) ? @json['tag']&.first : @json['tag'] end end diff --git a/app/lib/activitypub/activity/undo.rb b/app/lib/activitypub/activity/undo.rb index 9eff1b71c..b36ff0daf 100644 --- a/app/lib/activitypub/activity/undo.rb +++ b/app/lib/activitypub/activity/undo.rb @@ -100,7 +100,7 @@ class ActivityPub::Activity::Undo < ActivityPub::Activity end end - def undo_like + def undo_like_original status = status_from_uri(target_uri) return if status.nil? || !status.account.local? @@ -113,6 +113,59 @@ class ActivityPub::Activity::Undo < ActivityPub::Activity end end + def undo_like + @original_status = status_from_uri(target_uri) + + return if @original_status.nil? + + if shortcode.present? + emoji_tag = @object['tag'].is_a?(Array) ? @object['tag']&.first : @object['tag'] + + if emoji_tag.present? && emoji_tag['id'].present? + emoji = CustomEmoji.find_by(shortcode: shortcode, domain: @account.domain) + end + + if @account.reacted?(@original_status, shortcode, emoji) + @original_status.emoji_reactions.where(account: @account, name: shortcode, custom_emoji: emoji).first&.destroy + + if @original_status.account.local? + forward_for_undo_emoji_reaction + relay_for_undo_emoji_reaction + end + else + delete_later!(object_uri) + end + else + undo_like_original + end + end + + def forward_for_undo_emoji_reaction + return unless @json['signature'].present? + + ActivityPub::RawDistributionWorker.perform_async(Oj.dump(@json), @original_status.account.id, [@account.preferred_inbox_url]) + end + + def relay_for_undo_emoji_reaction + return unless @json['signature'].present? && @original_status.public_visibility? + + ActivityPub::DeliveryWorker.push_bulk(Relay.enabled.pluck(:inbox_url)) do |inbox_url| + [Oj.dump(@json), @original_status.account.id, inbox_url] + end + end + + def shortcode + return @shortcode if defined?(@shortcode) + + @shortcode = begin + if @object['_misskey_reaction'] == '⭐' + nil + else + @object['content']&.delete(':') + end + end + end + def undo_block target_account = account_from_uri(target_uri) diff --git a/app/services/emoji_react_service.rb b/app/services/emoji_react_service.rb index 0f45d9d86..2beffff33 100644 --- a/app/services/emoji_react_service.rb +++ b/app/services/emoji_react_service.rb @@ -53,12 +53,6 @@ class EmojiReactService < BaseService ActivityPub::RawDistributionWorker.perform_async(build_json(emoji_reaction), status.account_id) end - def broadcast_updates!(emoji_reaction) - status = emoji_reaction.status - - DistributionWorker.perform_async(status.id, { 'update' => true }) - end - def write_stream(emoji_reaction) emoji_group = emoji_reaction.status.emoji_reactions_grouped_by_name .find { |reaction_group| reaction_group['name'] == emoji_reaction.name && (!reaction_group.key?(:domain) || reaction_group['domain'] == emoji_reaction.domain) }