remove_status_service.rb 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. # frozen_string_literal: true
  2. class RemoveStatusService < BaseService
  3. include StreamEntryRenderer
  4. def call(status, **options)
  5. @payload = Oj.dump(event: :delete, payload: status.id.to_s)
  6. @status = status
  7. @account = status.account
  8. @tags = status.tags.pluck(:name).to_a
  9. @mentions = status.mentions.includes(:account).to_a
  10. @reblogs = status.reblogs.to_a
  11. @stream_entry = status.stream_entry
  12. @options = options
  13. remove_from_self if status.account.local?
  14. remove_from_followers
  15. remove_from_lists
  16. remove_from_affected
  17. remove_reblogs
  18. remove_from_hashtags
  19. remove_from_public
  20. @status.destroy!
  21. # There is no reason to send out Undo activities when the
  22. # cause is that the original object has been removed, since
  23. # original object being removed implicitly removes reblogs
  24. # of it. The Delete activity of the original is forwarded
  25. # separately.
  26. return if !@account.local? || @options[:original_removed]
  27. remove_from_remote_followers
  28. remove_from_remote_affected
  29. end
  30. private
  31. def remove_from_self
  32. FeedManager.instance.unpush_from_home(@account, @status)
  33. end
  34. def remove_from_followers
  35. @account.followers.local.find_each do |follower|
  36. FeedManager.instance.unpush_from_home(follower, @status)
  37. end
  38. end
  39. def remove_from_lists
  40. @account.lists.select(:id, :account_id).find_each do |list|
  41. FeedManager.instance.unpush_from_list(list, @status)
  42. end
  43. end
  44. def remove_from_affected
  45. @mentions.map(&:account).select(&:local?).each do |account|
  46. Redis.current.publish("timeline:#{account.id}", @payload)
  47. end
  48. end
  49. def remove_from_remote_affected
  50. # People who got mentioned in the status, or who
  51. # reblogged it from someone else might not follow
  52. # the author and wouldn't normally receive the
  53. # delete notification - so here, we explicitly
  54. # send it to them
  55. target_accounts = (@mentions.map(&:account).reject(&:local?) + @reblogs.map(&:account).reject(&:local?)).uniq(&:id)
  56. # Ostatus
  57. NotificationWorker.push_bulk(target_accounts.select(&:ostatus?).uniq(&:domain)) do |target_account|
  58. [salmon_xml, @account.id, target_account.id]
  59. end
  60. # ActivityPub
  61. ActivityPub::DeliveryWorker.push_bulk(target_accounts.select(&:activitypub?).uniq(&:inbox_url)) do |target_account|
  62. [signed_activity_json, @account.id, target_account.inbox_url]
  63. end
  64. end
  65. def remove_from_remote_followers
  66. # OStatus
  67. Pubsubhubbub::RawDistributionWorker.perform_async(salmon_xml, @account.id)
  68. # ActivityPub
  69. ActivityPub::DeliveryWorker.push_bulk(@account.followers.inboxes) do |inbox_url|
  70. [signed_activity_json, @account.id, inbox_url]
  71. end
  72. end
  73. def salmon_xml
  74. @salmon_xml ||= stream_entry_to_xml(@stream_entry)
  75. end
  76. def signed_activity_json
  77. @signed_activity_json ||= Oj.dump(ActivityPub::LinkedDataSignature.new(activity_json).sign!(@account))
  78. end
  79. def activity_json
  80. @activity_json ||= ActiveModelSerializers::SerializableResource.new(
  81. @status,
  82. serializer: @status.reblog? ? ActivityPub::UndoAnnounceSerializer : ActivityPub::DeleteSerializer,
  83. adapter: ActivityPub::Adapter
  84. ).as_json
  85. end
  86. def remove_reblogs
  87. # We delete reblogs of the status before the original status,
  88. # because once original status is gone, reblogs will disappear
  89. # without us being able to do all the fancy stuff
  90. @reblogs.each do |reblog|
  91. RemoveStatusService.new.call(reblog, original_removed: true)
  92. end
  93. end
  94. def remove_from_hashtags
  95. return unless @status.public_visibility?
  96. @tags.each do |hashtag|
  97. Redis.current.publish("timeline:hashtag:#{hashtag}", @payload)
  98. Redis.current.publish("timeline:hashtag:#{hashtag}:local", @payload) if @status.local?
  99. end
  100. end
  101. def remove_from_public
  102. return unless @status.public_visibility?
  103. Redis.current.publish('timeline:public', @payload)
  104. Redis.current.publish('timeline:public:local', @payload) if @status.local?
  105. end
  106. def redis
  107. Redis.current
  108. end
  109. end