follow_service.rb 3.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. # frozen_string_literal: true
  2. class FollowService < BaseService
  3. include StreamEntryRenderer
  4. # Follow a remote user, notify remote user about the follow
  5. # @param [Account] source_account From which to follow
  6. # @param [String, Account] uri User URI to follow in the form of username@domain (or account record)
  7. # @param [true, false, nil] reblogs Whether or not to show reblogs, defaults to true
  8. def call(source_account, target_account, reblogs: nil)
  9. reblogs = true if reblogs.nil?
  10. target_account = ResolveAccountService.new.call(target_account, skip_webfinger: true)
  11. raise ActiveRecord::RecordNotFound if target_account.nil? || target_account.id == source_account.id || target_account.suspended?
  12. raise Mastodon::NotPermittedError if target_account.blocking?(source_account) || source_account.blocking?(target_account) || target_account.moved?
  13. if source_account.following?(target_account)
  14. # We're already following this account, but we'll call follow! again to
  15. # make sure the reblogs status is set correctly.
  16. source_account.follow!(target_account, reblogs: reblogs)
  17. return
  18. elsif source_account.requested?(target_account)
  19. # This isn't managed by a method in AccountInteractions, so we modify it
  20. # ourselves if necessary.
  21. req = source_account.follow_requests.find_by(target_account: target_account)
  22. req.update!(show_reblogs: reblogs)
  23. return
  24. end
  25. ActivityTracker.increment('activity:interactions')
  26. if target_account.locked? || target_account.activitypub?
  27. request_follow(source_account, target_account, reblogs: reblogs)
  28. else
  29. direct_follow(source_account, target_account, reblogs: reblogs)
  30. end
  31. end
  32. private
  33. def request_follow(source_account, target_account, reblogs: true)
  34. follow_request = FollowRequest.create!(account: source_account, target_account: target_account, show_reblogs: reblogs)
  35. if target_account.local?
  36. LocalNotificationWorker.perform_async(target_account.id, follow_request.id, follow_request.class.name)
  37. elsif target_account.ostatus?
  38. NotificationWorker.perform_async(build_follow_request_xml(follow_request), source_account.id, target_account.id)
  39. AfterRemoteFollowRequestWorker.perform_async(follow_request.id)
  40. elsif target_account.activitypub?
  41. ActivityPub::DeliveryWorker.perform_async(build_json(follow_request), source_account.id, target_account.inbox_url)
  42. end
  43. follow_request
  44. end
  45. def direct_follow(source_account, target_account, reblogs: true)
  46. follow = source_account.follow!(target_account, reblogs: reblogs)
  47. if target_account.local?
  48. LocalNotificationWorker.perform_async(target_account.id, follow.id, follow.class.name)
  49. else
  50. Pubsubhubbub::SubscribeWorker.perform_async(target_account.id) unless target_account.subscribed?
  51. NotificationWorker.perform_async(build_follow_xml(follow), source_account.id, target_account.id)
  52. AfterRemoteFollowWorker.perform_async(follow.id)
  53. end
  54. MergeWorker.perform_async(target_account.id, source_account.id)
  55. follow
  56. end
  57. def redis
  58. Redis.current
  59. end
  60. def build_follow_request_xml(follow_request)
  61. OStatus::AtomSerializer.render(OStatus::AtomSerializer.new.follow_request_salmon(follow_request))
  62. end
  63. def build_follow_xml(follow)
  64. OStatus::AtomSerializer.render(OStatus::AtomSerializer.new.follow_salmon(follow))
  65. end
  66. def build_json(follow_request)
  67. Oj.dump(ActivityPub::LinkedDataSignature.new(ActiveModelSerializers::SerializableResource.new(
  68. follow_request,
  69. serializer: ActivityPub::FollowSerializer,
  70. adapter: ActivityPub::Adapter
  71. ).as_json).sign!(follow_request.account))
  72. end
  73. end