Make follow requests federate
This commit is contained in:
		@@ -18,12 +18,12 @@ class Api::V1::FollowRequestsController < ApiController
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def authorize
 | 
			
		||||
    FollowRequest.find_by!(account_id: params[:id], target_account: current_account).authorize!
 | 
			
		||||
    AuthorizeFollowService.new.call(Account.find(params[:id]), current_account)
 | 
			
		||||
    render_empty
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def reject
 | 
			
		||||
    FollowRequest.find_by!(account_id: params[:id], target_account: current_account).reject!
 | 
			
		||||
    RejectFollowService.new.call(Account.find(params[:id]), current_account)
 | 
			
		||||
    render_empty
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,5 @@
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
module ObfuscateFilename
 | 
			
		||||
  extend ActiveSupport::Concern
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -143,6 +143,10 @@ module AtomBuilderHelper
 | 
			
		||||
    xml.link(:rel => 'mentioned', :href => TagManager::COLLECTIONS[:public], 'ostatus:object-type' => TagManager::TYPES[:collection])
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def privacy_scope(xml, level)
 | 
			
		||||
    xml['mastodon'].scope(level)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def include_author(xml, account)
 | 
			
		||||
    object_type      xml, :person
 | 
			
		||||
    uri              xml, TagManager.instance.uri_for(account)
 | 
			
		||||
@@ -152,6 +156,7 @@ module AtomBuilderHelper
 | 
			
		||||
    link_alternate   xml, TagManager.instance.url_for(account)
 | 
			
		||||
    link_avatar      xml, account
 | 
			
		||||
    portable_contact xml, account
 | 
			
		||||
    privacy_scope    xml, account.locked? ? :private : :public
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def rich_content(xml, activity)
 | 
			
		||||
@@ -216,6 +221,7 @@ module AtomBuilderHelper
 | 
			
		||||
          end
 | 
			
		||||
 | 
			
		||||
          category(xml, 'nsfw') if stream_entry.target.sensitive?
 | 
			
		||||
          privacy_scope(xml, stream_entry.target.visibility)
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
@@ -237,6 +243,7 @@ module AtomBuilderHelper
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    category(xml, 'nsfw') if stream_entry.activity.sensitive?
 | 
			
		||||
    privacy_scope(xml, stream_entry.activity.visibility)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  private
 | 
			
		||||
@@ -249,6 +256,7 @@ module AtomBuilderHelper
 | 
			
		||||
               'xmlns:poco'     => TagManager::POCO_XMLNS,
 | 
			
		||||
               'xmlns:media'    => TagManager::MEDIA_XMLNS,
 | 
			
		||||
               'xmlns:ostatus'  => TagManager::OS_XMLNS,
 | 
			
		||||
               'xmlns:mastodon' => TagManager::MTDN_XMLNS,
 | 
			
		||||
             }, &block)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -7,15 +7,18 @@ class TagManager
 | 
			
		||||
  include RoutingHelper
 | 
			
		||||
 | 
			
		||||
  VERBS = {
 | 
			
		||||
    post:       'http://activitystrea.ms/schema/1.0/post',
 | 
			
		||||
    share:      'http://activitystrea.ms/schema/1.0/share',
 | 
			
		||||
    favorite:   'http://activitystrea.ms/schema/1.0/favorite',
 | 
			
		||||
    unfavorite: 'http://activitystrea.ms/schema/1.0/unfavorite',
 | 
			
		||||
    delete:     'http://activitystrea.ms/schema/1.0/delete',
 | 
			
		||||
    follow:     'http://activitystrea.ms/schema/1.0/follow',
 | 
			
		||||
    unfollow:   'http://ostatus.org/schema/1.0/unfollow',
 | 
			
		||||
    block:      'http://mastodon.social/schema/1.0/block',
 | 
			
		||||
    unblock:    'http://mastodon.social/schema/1.0/unblock',
 | 
			
		||||
    post:           'http://activitystrea.ms/schema/1.0/post',
 | 
			
		||||
    share:          'http://activitystrea.ms/schema/1.0/share',
 | 
			
		||||
    favorite:       'http://activitystrea.ms/schema/1.0/favorite',
 | 
			
		||||
    unfavorite:     'http://activitystrea.ms/schema/1.0/unfavorite',
 | 
			
		||||
    delete:         'http://activitystrea.ms/schema/1.0/delete',
 | 
			
		||||
    follow:         'http://activitystrea.ms/schema/1.0/follow',
 | 
			
		||||
    request_friend: 'http://activitystrea.ms/schema/1.0/request-friend',
 | 
			
		||||
    authorize:      'http://activitystrea.ms/schema/1.0/authorize',
 | 
			
		||||
    reject:         'http://activitystrea.ms/schema/1.0/reject',
 | 
			
		||||
    unfollow:       'http://ostatus.org/schema/1.0/unfollow',
 | 
			
		||||
    block:          'http://mastodon.social/schema/1.0/block',
 | 
			
		||||
    unblock:        'http://mastodon.social/schema/1.0/unblock',
 | 
			
		||||
  }.freeze
 | 
			
		||||
 | 
			
		||||
  TYPES = {
 | 
			
		||||
@@ -38,6 +41,7 @@ class TagManager
 | 
			
		||||
  POCO_XMLNS  = 'http://portablecontacts.net/spec/1.0'
 | 
			
		||||
  DFRN_XMLNS  = 'http://purl.org/macgirvin/dfrn/1.0'
 | 
			
		||||
  OS_XMLNS    = 'http://ostatus.org/schema/1.0'
 | 
			
		||||
  MTDN_XMLNS  = 'http://mastodon.social/schema/1.0'
 | 
			
		||||
 | 
			
		||||
  def unique_tag(date, id, type)
 | 
			
		||||
    "tag:#{Rails.configuration.x.local_domain},#{date.strftime('%Y-%m-%d')}:objectId=#{id}:objectType=#{type}"
 | 
			
		||||
 
 | 
			
		||||
@@ -12,11 +12,11 @@ class Favourite < ApplicationRecord
 | 
			
		||||
  validates :status_id, uniqueness: { scope: :account_id }
 | 
			
		||||
 | 
			
		||||
  def verb
 | 
			
		||||
    :favorite
 | 
			
		||||
    destroyed? ? :unfavorite : :favorite
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def title
 | 
			
		||||
    "#{account.acct} favourited a status by #{status.account.acct}"
 | 
			
		||||
    destroyed? ? "#{account.acct} no longer favourites a status by #{status.account.acct}" : "#{account.acct} favourited a status by #{status.account.acct}"
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  delegate :object_type, to: :target
 | 
			
		||||
 
 | 
			
		||||
@@ -2,6 +2,7 @@
 | 
			
		||||
 | 
			
		||||
class FollowRequest < ApplicationRecord
 | 
			
		||||
  include Paginable
 | 
			
		||||
  include Streamable
 | 
			
		||||
 | 
			
		||||
  belongs_to :account
 | 
			
		||||
  belongs_to :target_account, class_name: 'Account'
 | 
			
		||||
@@ -12,12 +13,47 @@ class FollowRequest < ApplicationRecord
 | 
			
		||||
  validates :account_id, uniqueness: { scope: :target_account_id }
 | 
			
		||||
 | 
			
		||||
  def authorize!
 | 
			
		||||
    @verb = :authorize
 | 
			
		||||
 | 
			
		||||
    account.follow!(target_account)
 | 
			
		||||
    MergeWorker.perform_async(target_account.id, account.id)
 | 
			
		||||
 | 
			
		||||
    destroy!
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def reject!
 | 
			
		||||
    @verb = :reject
 | 
			
		||||
    destroy!
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def verb
 | 
			
		||||
    destroyed? ? (@verb || :delete) : :request_friend
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def target
 | 
			
		||||
    target_account
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def object_type
 | 
			
		||||
    :person
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def hidden?
 | 
			
		||||
    true
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def title
 | 
			
		||||
    if destroyed?
 | 
			
		||||
      case @verb
 | 
			
		||||
      when :authorize
 | 
			
		||||
        "#{target_account.acct} authorized #{account.acct}'s request to follow"
 | 
			
		||||
      when :reject
 | 
			
		||||
        "#{target_account.acct} rejected #{account.acct}'s request to follow"
 | 
			
		||||
      else
 | 
			
		||||
        "#{account.acct} withdrew the request to follow #{target_account.acct}"
 | 
			
		||||
      end
 | 
			
		||||
    else
 | 
			
		||||
      "#{account.acct} requested to follow #{target_account.acct}"
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
 
 | 
			
		||||
@@ -30,7 +30,7 @@ class StreamEntry < ApplicationRecord
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def targeted?
 | 
			
		||||
    [:follow, :unfollow, :block, :unblock, :share, :favorite].include? verb
 | 
			
		||||
    [:follow, :request_friend, :authorize, :unfollow, :block, :unblock, :share, :favorite].include? verb
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def target
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										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?
 | 
			
		||||
 
 | 
			
		||||
@@ -5,7 +5,7 @@ class NotificationWorker
 | 
			
		||||
 | 
			
		||||
  sidekiq_options retry: 5
 | 
			
		||||
 | 
			
		||||
  def perform(stream_entry_id, target_account_id)
 | 
			
		||||
    SendInteractionService.new.call(StreamEntry.find(stream_entry_id), Account.find(target_account_id))
 | 
			
		||||
  def perform(xml, source_account_id, target_account_id)
 | 
			
		||||
    SendInteractionService.new.call(xml, Account.find(source_account_id), Account.find(target_account_id))
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
 
 | 
			
		||||
@@ -1,11 +0,0 @@
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
class PushNotificationWorker
 | 
			
		||||
  include Sidekiq::Worker
 | 
			
		||||
 | 
			
		||||
  def perform(notification_id)
 | 
			
		||||
    SendPushNotificationService.new.call(Notification.find(notification_id))
 | 
			
		||||
  rescue ActiveRecord::RecordNotFound
 | 
			
		||||
    true
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
		Reference in New Issue
	
	Block a user