about summary refs log tree commit diff
path: root/app/services
diff options
context:
space:
mode:
Diffstat (limited to 'app/services')
-rw-r--r--app/services/authorize_follow_service.rb11
-rw-r--r--app/services/block_service.rb4
-rw-r--r--app/services/concerns/stream_entry_renderer.rb8
-rw-r--r--app/services/favourite_service.rb4
-rw-r--r--app/services/fetch_remote_account_service.rb4
-rw-r--r--app/services/follow_service.rb17
-rw-r--r--app/services/process_feed_service.rb18
-rw-r--r--app/services/process_interaction_service.rb22
-rw-r--r--app/services/process_mentions_service.rb6
-rw-r--r--app/services/reblog_service.rb10
-rw-r--r--app/services/reject_follow_service.rb11
-rw-r--r--app/services/remove_status_service.rb4
-rw-r--r--app/services/send_interaction_service.rb19
-rw-r--r--app/services/unblock_service.rb4
-rw-r--r--app/services/unfavourite_service.rb4
-rw-r--r--app/services/unfollow_service.rb4
-rw-r--r--app/services/update_remote_profile_service.rb1
17 files changed, 103 insertions, 48 deletions
diff --git a/app/services/authorize_follow_service.rb b/app/services/authorize_follow_service.rb
new file mode 100644
index 000000000..1590d8433
--- /dev/null
+++ b/app/services/authorize_follow_service.rb
@@ -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
diff --git a/app/services/block_service.rb b/app/services/block_service.rb
index e04b6cc39..095d2a8eb 100644
--- a/app/services/block_service.rb
+++ b/app/services/block_service.rb
@@ -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
diff --git a/app/services/concerns/stream_entry_renderer.rb b/app/services/concerns/stream_entry_renderer.rb
new file mode 100644
index 000000000..a4255daea
--- /dev/null
+++ b/app/services/concerns/stream_entry_renderer.rb
@@ -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
diff --git a/app/services/favourite_service.rb b/app/services/favourite_service.rb
index d5fbd29e9..ce1722b77 100644
--- a/app/services/favourite_service.rb
+++ b/app/services/favourite_service.rb
@@ -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
diff --git a/app/services/fetch_remote_account_service.rb b/app/services/fetch_remote_account_service.rb
index 3c3694a65..baefa3a86 100644
--- a/app/services/fetch_remote_account_service.rb
+++ b/app/services/fetch_remote_account_service.rb
@@ -22,7 +22,9 @@ class FetchRemoteAccountService < BaseService
 
     Rails.logger.debug "Going to webfinger #{username}@#{domain}"
 
-    return FollowRemoteAccountService.new.call("#{username}@#{domain}")
+    account = FollowRemoteAccountService.new.call("#{username}@#{domain}")
+    UpdateRemoteProfileService.new.call(xml, account) unless account.nil?
+    account
   rescue TypeError
     Rails.logger.debug "Unparseable URL given: #{url}"
     nil
diff --git a/app/services/follow_service.rb b/app/services/follow_service.rb
index 9f34cb6ac..ac0392d16 100644
--- a/app/services/follow_service.rb
+++ b/app/services/follow_service.rb
@@ -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,14 @@ 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)
+      AfterRemoteFollowRequestWorker.perform_async(follow_request.id)
+    end
 
     follow_request
   end
@@ -34,8 +40,9 @@ class FollowService < BaseService
     if target_account.local?
       NotifyService.new.call(target_account, follow)
     else
-      subscribe_service.call(target_account)
-      NotificationWorker.perform_async(follow.stream_entry.id, target_account.id)
+      subscribe_service.call(target_account) unless target_account.subscribed?
+      NotificationWorker.perform_async(stream_entry_to_xml(follow.stream_entry), source_account.id, target_account.id)
+      AfterRemoteFollowWorker.perform_async(follow.id)
     end
 
     MergeWorker.perform_async(target_account.id, source_account.id)
diff --git a/app/services/process_feed_service.rb b/app/services/process_feed_service.rb
index c411e3e82..f0a62aa14 100644
--- a/app/services/process_feed_service.rb
+++ b/app/services/process_feed_service.rb
@@ -106,7 +106,8 @@ class ProcessFeedService < BaseService
         text: content(entry),
         spoiler_text: content_warning(entry),
         created_at: published(entry),
-        reply: thread?(entry)
+        reply: thread?(entry),
+        visibility: visibility_scope(entry)
       )
 
       if thread?(entry)
@@ -144,15 +145,9 @@ class ProcessFeedService < BaseService
 
     def mentions_from_xml(parent, xml)
       processed_account_ids = []
-      public_visibility     = false
 
       xml.xpath('./xmlns:link[@rel="mentioned"]', xmlns: TagManager::XMLNS).each do |link|
-        if link['ostatus:object-type'] == TagManager::TYPES[:collection] && link['href'] == TagManager::COLLECTIONS[:public]
-          public_visibility = true
-          next
-        elsif link['ostatus:object-type'] == TagManager::TYPES[:group]
-          next
-        end
+        next if [TagManager::TYPES[:group], TagManager::TYPES[:collection]].include? link['ostatus:object-type']
 
         url = Addressable::URI.parse(link['href'])
 
@@ -172,9 +167,6 @@ class ProcessFeedService < BaseService
         # So we can skip duplicate mentions
         processed_account_ids << mentioned_account.id
       end
-
-      parent.visibility = public_visibility ? :public : :unlisted
-      parent.save!
     end
 
     def hashtags_from_xml(parent, xml)
@@ -230,6 +222,10 @@ class ProcessFeedService < BaseService
       xml.at_xpath('./xmlns:summary', xmlns: TagManager::XMLNS)&.content || ''
     end
 
+    def visibility_scope(xml = @xml)
+      xml.at_xpath('./mastodon:scope', mastodon: TagManager::MTDN_XMLNS)&.content&.to_sym || :public
+    end
+
     def published(xml = @xml)
       xml.at_xpath('./xmlns:published', xmlns: TagManager::XMLNS).content
     end
diff --git a/app/services/process_interaction_service.rb b/app/services/process_interaction_service.rb
index 5f91e3127..8420ca351 100644
--- a/app/services/process_interaction_service.rb
+++ b/app/services/process_interaction_service.rb
@@ -29,6 +29,12 @@ 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 :reject
+        reject_follow_request!(account, target_account)
       when :unfollow
         unfollow!(account, target_account)
       when :favorite
@@ -72,6 +78,22 @@ 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_follow_request!(account, target_account)
+    follow_request = FollowRequest.find_by(account: target_account, target_account: account)
+    follow_request&.authorize!
+    SubscribeService.new.call(account) unless account.subscribed?
+  end
+
+  def reject_follow_request!(account, target_account)
+    follow_request = FollowRequest.find_by(account: target_account, target_account: account)
+    follow_request&.reject!
+  end
+
   def unfollow!(account, target_account)
     account.unfollow!(target_account)
   end
diff --git a/app/services/process_mentions_service.rb b/app/services/process_mentions_service.rb
index 72568e702..d3d3af8af 100644
--- a/app/services/process_mentions_service.rb
+++ b/app/services/process_mentions_service.rb
@@ -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
@@ -28,12 +30,10 @@ class ProcessMentionsService < BaseService
     status.mentions.each do |mention|
       mentioned_account = mention.account
 
-      next if status.private_visibility? && (!mentioned_account.following?(status.account) || !mentioned_account.local?)
-
       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
diff --git a/app/services/reblog_service.rb b/app/services/reblog_service.rb
index 4ea0dbf6c..7a52f041f 100644
--- a/app/services/reblog_service.rb
+++ b/app/services/reblog_service.rb
@@ -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
diff --git a/app/services/reject_follow_service.rb b/app/services/reject_follow_service.rb
new file mode 100644
index 000000000..0c568b981
--- /dev/null
+++ b/app/services/reject_follow_service.rb
@@ -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
diff --git a/app/services/remove_status_service.rb b/app/services/remove_status_service.rb
index 48e8dd3b8..b1a646b14 100644
--- a/app/services/remove_status_service.rb
+++ b/app/services/remove_status_service.rb
@@ -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)
diff --git a/app/services/send_interaction_service.rb b/app/services/send_interaction_service.rb
index 05a1e77e3..99113eeca 100644
--- a/app/services/send_interaction_service.rb
+++ b/app/services/send_interaction_service.rb
@@ -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
diff --git a/app/services/unblock_service.rb b/app/services/unblock_service.rb
index f389364f9..84b1050c1 100644
--- a/app/services/unblock_service.rb
+++ b/app/services/unblock_service.rb
@@ -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
diff --git a/app/services/unfavourite_service.rb b/app/services/unfavourite_service.rb
index de6e84e7d..04293ee08 100644
--- a/app/services/unfavourite_service.rb
+++ b/app/services/unfavourite_service.rb
@@ -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
diff --git a/app/services/unfollow_service.rb b/app/services/unfollow_service.rb
index f469793c1..178da4da3 100644
--- a/app/services/unfollow_service.rb
+++ b/app/services/unfollow_service.rb
@@ -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
diff --git a/app/services/update_remote_profile_service.rb b/app/services/update_remote_profile_service.rb
index ad9c56540..dc315db19 100644
--- a/app/services/update_remote_profile_service.rb
+++ b/app/services/update_remote_profile_service.rb
@@ -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?