Make follow requests federate
This commit is contained in:
11
app/services/authorize_follow_service.rb
Normal file
11
app/services/authorize_follow_service.rb
Normal file
@ -0,0 +1,11 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class AuthorizeFollowService < BaseService
|
||||
include StreamEntryRenderer
|
||||
|
||||
def call(source_account, target_account)
|
||||
follow_request = FollowRequest.find_by!(account: source_account, target_account: target_account)
|
||||
follow_request.authorize!
|
||||
NotificationWorker.perform_async(stream_entry_to_xml(follow_request.stream_entry), target_account.id, source_account.id) unless source_account.local?
|
||||
end
|
||||
end
|
@ -1,6 +1,8 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class BlockService < BaseService
|
||||
include StreamEntryRenderer
|
||||
|
||||
def call(account, target_account)
|
||||
return if account.id == target_account.id
|
||||
|
||||
@ -10,6 +12,6 @@ class BlockService < BaseService
|
||||
block = account.block!(target_account)
|
||||
|
||||
BlockWorker.perform_async(account.id, target_account.id)
|
||||
NotificationWorker.perform_async(block.stream_entry.id, target_account.id) unless target_account.local?
|
||||
NotificationWorker.perform_async(stream_entry_to_xml(block.stream_entry), account.id, target_account.id) unless target_account.local?
|
||||
end
|
||||
end
|
||||
|
8
app/services/concerns/stream_entry_renderer.rb
Normal file
8
app/services/concerns/stream_entry_renderer.rb
Normal file
@ -0,0 +1,8 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module StreamEntryRenderer
|
||||
def stream_entry_to_xml(stream_entry)
|
||||
renderer = StreamEntriesController.renderer.new(method: 'get', http_host: Rails.configuration.x.local_domain, https: Rails.configuration.x.use_https)
|
||||
renderer.render(:show, assigns: { stream_entry: stream_entry }, formats: [:atom])
|
||||
end
|
||||
end
|
@ -1,6 +1,8 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class FavouriteService < BaseService
|
||||
include StreamEntryRenderer
|
||||
|
||||
# Favourite a status and notify remote user
|
||||
# @param [Account] account
|
||||
# @param [Status] status
|
||||
@ -15,7 +17,7 @@ class FavouriteService < BaseService
|
||||
if status.local?
|
||||
NotifyService.new.call(favourite.status.account, favourite)
|
||||
else
|
||||
NotificationWorker.perform_async(favourite.stream_entry.id, status.account_id)
|
||||
NotificationWorker.perform_async(stream_entry_to_xml(favourite.stream_entry), account.id, status.account_id)
|
||||
end
|
||||
|
||||
favourite
|
||||
|
@ -1,6 +1,8 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class FollowService < BaseService
|
||||
include StreamEntryRenderer
|
||||
|
||||
# Follow a remote user, notify remote user about the follow
|
||||
# @param [Account] source_account From which to follow
|
||||
# @param [String] uri User URI to follow in the form of username@domain
|
||||
@ -20,10 +22,13 @@ class FollowService < BaseService
|
||||
private
|
||||
|
||||
def request_follow(source_account, target_account)
|
||||
return unless target_account.local?
|
||||
|
||||
follow_request = FollowRequest.create!(account: source_account, target_account: target_account)
|
||||
NotifyService.new.call(target_account, follow_request)
|
||||
|
||||
if target_account.local?
|
||||
NotifyService.new.call(target_account, follow_request)
|
||||
else
|
||||
NotificationWorker.perform_async(stream_entry_to_xml(follow_request.stream_entry), source_account.id, target_account.id)
|
||||
end
|
||||
|
||||
follow_request
|
||||
end
|
||||
@ -35,7 +40,7 @@ class FollowService < BaseService
|
||||
NotifyService.new.call(target_account, follow)
|
||||
else
|
||||
subscribe_service.call(target_account)
|
||||
NotificationWorker.perform_async(follow.stream_entry.id, target_account.id)
|
||||
NotificationWorker.perform_async(stream_entry_to_xml(follow.stream_entry), source_account.id, target_account.id)
|
||||
end
|
||||
|
||||
MergeWorker.perform_async(target_account.id, source_account.id)
|
||||
|
@ -29,6 +29,10 @@ class ProcessInteractionService < BaseService
|
||||
case verb(xml)
|
||||
when :follow
|
||||
follow!(account, target_account) unless target_account.locked? || target_account.blocking?(account)
|
||||
when :request_friend
|
||||
follow_request!(account, target_account) unless !target_account.locked? || target_account.blocking?(account)
|
||||
when :authorize
|
||||
authorize_follow_request!(account, target_account)
|
||||
when :unfollow
|
||||
unfollow!(account, target_account)
|
||||
when :favorite
|
||||
@ -72,6 +76,16 @@ class ProcessInteractionService < BaseService
|
||||
NotifyService.new.call(target_account, follow)
|
||||
end
|
||||
|
||||
def follow_request(account, target_account)
|
||||
follow_request = FollowRequest.create!(account: account, target_account: target_account)
|
||||
NotifyService.new.call(target_account, follow_request)
|
||||
end
|
||||
|
||||
def authorize_target_account!(account, target_account)
|
||||
follow_request = FollowRequest.find_by(account: target_account, target_account: account)
|
||||
follow_request&.authorize!
|
||||
end
|
||||
|
||||
def unfollow!(account, target_account)
|
||||
account.unfollow!(target_account)
|
||||
end
|
||||
|
@ -1,6 +1,8 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class ProcessMentionsService < BaseService
|
||||
include StreamEntryRenderer
|
||||
|
||||
# Scan status for mentions and fetch remote mentioned users, create
|
||||
# local mention pointers, send Salmon notifications to mentioned
|
||||
# remote users
|
||||
@ -33,7 +35,7 @@ class ProcessMentionsService < BaseService
|
||||
if mentioned_account.local?
|
||||
NotifyService.new.call(mentioned_account, mention)
|
||||
else
|
||||
NotificationWorker.perform_async(status.stream_entry.id, mentioned_account.id)
|
||||
NotificationWorker.perform_async(stream_entry_to_xml(status.stream_entry), status.account_id, mentioned_account.id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -1,6 +1,8 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class ReblogService < BaseService
|
||||
include StreamEntryRenderer
|
||||
|
||||
# Reblog a status and notify its remote author
|
||||
# @param [Account] account Account to reblog from
|
||||
# @param [Status] reblogged_status Status to be reblogged
|
||||
@ -18,15 +20,9 @@ class ReblogService < BaseService
|
||||
if reblogged_status.local?
|
||||
NotifyService.new.call(reblog.reblog.account, reblog)
|
||||
else
|
||||
NotificationWorker.perform_async(reblog.stream_entry.id, reblog.reblog.account_id)
|
||||
NotificationWorker.perform_async(stream_entry_to_xml(reblog.stream_entry), account.id, reblog.reblog.account_id)
|
||||
end
|
||||
|
||||
reblog
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def send_interaction_service
|
||||
@send_interaction_service ||= SendInteractionService.new
|
||||
end
|
||||
end
|
||||
|
11
app/services/reject_follow_service.rb
Normal file
11
app/services/reject_follow_service.rb
Normal file
@ -0,0 +1,11 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class RejectFollowService < BaseService
|
||||
include StreamEntryRenderer
|
||||
|
||||
def call(source_account, target_account)
|
||||
follow_request = FollowRequest.find_by!(account: source_account, target_account: target_account)
|
||||
follow_request.reject!
|
||||
NotificationWorker.perform_async(stream_entry_to_xml(follow_request.stream_entry), target_account.id, source_account.id) unless source_account.local?
|
||||
end
|
||||
end
|
@ -1,6 +1,8 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class RemoveStatusService < BaseService
|
||||
include StreamEntryRenderer
|
||||
|
||||
def call(status)
|
||||
remove_from_self(status) if status.account.local?
|
||||
remove_from_followers(status)
|
||||
@ -43,7 +45,7 @@ class RemoveStatusService < BaseService
|
||||
|
||||
def send_delete_salmon(account, status)
|
||||
return unless status.local?
|
||||
NotificationWorker.perform_async(status.stream_entry.id, account.id)
|
||||
NotificationWorker.perform_async(stream_entry_to_xml(status.stream_entry), status.account_id, account.id)
|
||||
end
|
||||
|
||||
def remove_reblogs(status)
|
||||
|
@ -2,27 +2,16 @@
|
||||
|
||||
class SendInteractionService < BaseService
|
||||
# Send an Atom representation of an interaction to a remote Salmon endpoint
|
||||
# @param [StreamEntry] stream_entry
|
||||
# @param [String] Entry XML
|
||||
# @param [Account] source_account
|
||||
# @param [Account] target_account
|
||||
def call(stream_entry, target_account)
|
||||
envelope = salmon.pack(entry_xml(stream_entry), stream_entry.account.keypair)
|
||||
def call(xml, source_account, target_account)
|
||||
envelope = salmon.pack(xml, source_account.keypair)
|
||||
salmon.post(target_account.salmon_url, envelope)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def entry_xml(stream_entry)
|
||||
Nokogiri::XML::Builder.new do |xml|
|
||||
entry(xml, true) do
|
||||
author(xml) do
|
||||
include_author xml, stream_entry.account
|
||||
end
|
||||
|
||||
include_entry xml, stream_entry
|
||||
end
|
||||
end.to_xml
|
||||
end
|
||||
|
||||
def salmon
|
||||
@salmon ||= OStatus2::Salmon.new
|
||||
end
|
||||
|
@ -1,10 +1,12 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class UnblockService < BaseService
|
||||
include StreamEntryRenderer
|
||||
|
||||
def call(account, target_account)
|
||||
return unless account.blocking?(target_account)
|
||||
|
||||
unblock = account.unblock!(target_account)
|
||||
NotificationWorker.perform_async(unblock.stream_entry.id, target_account.id) unless target_account.local?
|
||||
NotificationWorker.perform_async(stream_entry_to_xml(unblock.stream_entry), account.id, target_account.id) unless target_account.local?
|
||||
end
|
||||
end
|
||||
|
@ -1,12 +1,14 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class UnfavouriteService < BaseService
|
||||
include StreamEntryRenderer
|
||||
|
||||
def call(account, status)
|
||||
favourite = Favourite.find_by!(account: account, status: status)
|
||||
favourite.destroy!
|
||||
|
||||
unless status.local?
|
||||
NotificationWorker.perform_async(favourite.stream_entry.id, status.account_id)
|
||||
NotificationWorker.perform_async(stream_entry_to_xml(favourite.stream_entry), account.id, status.account_id)
|
||||
end
|
||||
|
||||
favourite
|
||||
|
@ -1,12 +1,14 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class UnfollowService < BaseService
|
||||
include StreamEntryRenderer
|
||||
|
||||
# Unfollow and notify the remote user
|
||||
# @param [Account] source_account Where to unfollow from
|
||||
# @param [Account] target_account Which to unfollow
|
||||
def call(source_account, target_account)
|
||||
follow = source_account.unfollow!(target_account)
|
||||
NotificationWorker.perform_async(follow.stream_entry.id, target_account.id) unless target_account.local?
|
||||
NotificationWorker.perform_async(stream_entry_to_xml(follow.stream_entry), source_account.id, target_account.id) unless target_account.local?
|
||||
UnmergeWorker.perform_async(target_account.id, source_account.id)
|
||||
end
|
||||
end
|
||||
|
@ -10,6 +10,7 @@ class UpdateRemoteProfileService < BaseService
|
||||
unless author_xml.nil?
|
||||
account.display_name = author_xml.at_xpath('./poco:displayName', poco: TagManager::POCO_XMLNS).content unless author_xml.at_xpath('./poco:displayName', poco: TagManager::POCO_XMLNS).nil?
|
||||
account.note = author_xml.at_xpath('./poco:note', poco: TagManager::POCO_XMLNS).content unless author_xml.at_xpath('./poco:note', poco: TagManager::POCO_XMLNS).nil?
|
||||
account.locked = author_xml.at_xpath('./mastodon:scope', mastodon: TagManager::MTDN_XMLNS)&.content == 'private'
|
||||
|
||||
unless account.suspended? || DomainBlock.find_by(domain: account.domain)&.reject_media?
|
||||
account.avatar_remote_url = author_xml.at_xpath('./xmlns:link[@rel="avatar"]', xmlns: TagManager::XMLNS)['href'] unless author_xml.at_xpath('./xmlns:link[@rel="avatar"]', xmlns: TagManager::XMLNS).nil? || author_xml.at_xpath('./xmlns:link[@rel="avatar"]', xmlns: TagManager::XMLNS)['href'].blank?
|
||||
|
Reference in New Issue
Block a user