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/batched_remove_status_service.rb11
-rw-r--r--app/services/fan_out_on_write_service.rb13
-rw-r--r--app/services/follow_service.rb29
-rw-r--r--app/services/mute_service.rb1
-rw-r--r--app/services/notify_service.rb2
-rw-r--r--app/services/post_status_service.rb10
-rw-r--r--app/services/reblog_service.rb7
-rw-r--r--app/services/remove_status_service.rb8
8 files changed, 65 insertions, 16 deletions
diff --git a/app/services/batched_remove_status_service.rb b/app/services/batched_remove_status_service.rb
index 5d83771c9..aa2229f13 100644
--- a/app/services/batched_remove_status_service.rb
+++ b/app/services/batched_remove_status_service.rb
@@ -40,6 +40,7 @@ class BatchedRemoveStatusService < BaseService
     # Cannot be batched
     statuses.each do |status|
       unpush_from_public_timelines(status)
+      unpush_from_direct_timelines(status) if status.direct_visibility?
       batch_salmon_slaps(status) if status.local?
     end
 
@@ -100,6 +101,16 @@ class BatchedRemoveStatusService < BaseService
     end
   end
 
+  def unpush_from_direct_timelines(status)
+    payload = @json_payloads[status.id]
+    redis.pipelined do
+      @mentions[status.id].each do |mention|
+        redis.publish("timeline:direct:#{mention.account.id}", payload) if mention.account.local?
+      end
+      redis.publish("timeline:direct:#{status.account.id}", payload) if status.account.local?
+    end
+  end
+
   def batch_salmon_slaps(status)
     return if @mentions[status.id].empty?
 
diff --git a/app/services/fan_out_on_write_service.rb b/app/services/fan_out_on_write_service.rb
index 47a47a735..2214d73dd 100644
--- a/app/services/fan_out_on_write_service.rb
+++ b/app/services/fan_out_on_write_service.rb
@@ -10,15 +10,17 @@ class FanOutOnWriteService < BaseService
 
     deliver_to_self(status) if status.account.local?
 
+    render_anonymous_payload(status)
+
     if status.direct_visibility?
       deliver_to_mentioned_followers(status)
+      deliver_to_direct_timelines(status)
     else
       deliver_to_followers(status)
     end
 
     return if status.account.silenced? || !status.public_visibility? || status.reblog?
 
-    render_anonymous_payload(status)
     deliver_to_hashtags(status)
 
     return if status.reply? && status.in_reply_to_account_id != status.account_id
@@ -73,4 +75,13 @@ class FanOutOnWriteService < BaseService
     Redis.current.publish('timeline:public', @payload)
     Redis.current.publish('timeline:public:local', @payload) if status.local?
   end
+
+  def deliver_to_direct_timelines(status)
+    Rails.logger.debug "Delivering status #{status.id} to direct timelines"
+
+    status.mentions.includes(:account).each do |mention|
+      Redis.current.publish("timeline:direct:#{mention.account.id}", @payload) if mention.account.local?
+    end
+    Redis.current.publish("timeline:direct:#{status.account.id}", @payload) if status.account.local?
+  end
 end
diff --git a/app/services/follow_service.rb b/app/services/follow_service.rb
index 791773f25..20579ca63 100644
--- a/app/services/follow_service.rb
+++ b/app/services/follow_service.rb
@@ -6,25 +6,38 @@ class FollowService < BaseService
   # Follow a remote user, notify remote user about the follow
   # @param [Account] source_account From which to follow
   # @param [String, Account] uri User URI to follow in the form of username@domain (or account record)
-  def call(source_account, uri)
+  # @param [true, false, nil] reblogs Whether or not to show reblogs, defaults to true
+  def call(source_account, uri, reblogs: nil)
+    reblogs = true if reblogs.nil?
     target_account = uri.is_a?(Account) ? uri : ResolveRemoteAccountService.new.call(uri)
 
     raise ActiveRecord::RecordNotFound if target_account.nil? || target_account.id == source_account.id || target_account.suspended?
     raise Mastodon::NotPermittedError  if target_account.blocking?(source_account) || source_account.blocking?(target_account)
 
-    return if source_account.following?(target_account) || source_account.requested?(target_account)
+    if source_account.following?(target_account)
+      # We're already following this account, but we'll call follow! again to
+      # make sure the reblogs status is set correctly.
+      source_account.follow!(target_account, reblogs: reblogs)
+      return
+    elsif source_account.requested?(target_account)
+      # This isn't managed by a method in AccountInteractions, so we modify it
+      # ourselves if necessary.
+      req = follow_requests.find_by(target_account: other_account)
+      req.update!(show_reblogs: reblogs)
+      return
+    end
 
     if target_account.locked? || target_account.activitypub?
-      request_follow(source_account, target_account)
+      request_follow(source_account, target_account, reblogs: reblogs)
     else
-      direct_follow(source_account, target_account)
+      direct_follow(source_account, target_account, reblogs: reblogs)
     end
   end
 
   private
 
-  def request_follow(source_account, target_account)
-    follow_request = FollowRequest.create!(account: source_account, target_account: target_account)
+  def request_follow(source_account, target_account, reblogs: true)
+    follow_request = FollowRequest.create!(account: source_account, target_account: target_account, show_reblogs: reblogs)
 
     if target_account.local?
       NotifyService.new.call(target_account, follow_request)
@@ -38,8 +51,8 @@ class FollowService < BaseService
     follow_request
   end
 
-  def direct_follow(source_account, target_account)
-    follow = source_account.follow!(target_account)
+  def direct_follow(source_account, target_account, reblogs: true)
+    follow = source_account.follow!(target_account, reblogs: reblogs)
 
     if target_account.local?
       NotifyService.new.call(target_account, follow)
diff --git a/app/services/mute_service.rb b/app/services/mute_service.rb
index 9b7cbd81f..547b2efa1 100644
--- a/app/services/mute_service.rb
+++ b/app/services/mute_service.rb
@@ -3,7 +3,6 @@
 class MuteService < BaseService
   def call(account, target_account, notifications: nil)
     return if account.id == target_account.id
-    FeedManager.instance.clear_from_timeline(account, target_account)
     mute = account.mute!(target_account, notifications: notifications)
     BlockWorker.perform_async(account.id, target_account.id)
     mute
diff --git a/app/services/notify_service.rb b/app/services/notify_service.rb
index 8a77f2f38..d5960c3ad 100644
--- a/app/services/notify_service.rb
+++ b/app/services/notify_service.rb
@@ -29,7 +29,7 @@ class NotifyService < BaseService
   end
 
   def blocked_reblog?
-    false
+    @recipient.muting_reblogs?(@notification.from_account)
   end
 
   def blocked_follow_request?
diff --git a/app/services/post_status_service.rb b/app/services/post_status_service.rb
index de350f8e6..974c586f2 100644
--- a/app/services/post_status_service.rb
+++ b/app/services/post_status_service.rb
@@ -39,9 +39,13 @@ class PostStatusService < BaseService
 
     LinkCrawlWorker.perform_async(status.id) unless status.spoiler_text?
     DistributionWorker.perform_async(status.id)
-    Pubsubhubbub::DistributionWorker.perform_async(status.stream_entry.id)
-    ActivityPub::DistributionWorker.perform_async(status.id)
-    ActivityPub::ReplyDistributionWorker.perform_async(status.id) if status.reply? && status.thread.account.local?
+
+    # match both with and without U+FE0F (the emoji variation selector)
+    unless /👁\ufe0f?\z/.match?(status.content)
+      Pubsubhubbub::DistributionWorker.perform_async(status.stream_entry.id)
+      ActivityPub::DistributionWorker.perform_async(status.id)
+      ActivityPub::ReplyDistributionWorker.perform_async(status.id) if status.reply? && status.thread.account.local?
+    end
 
     if options[:idempotency].present?
       redis.setex("idempotency:status:#{account.id}:#{options[:idempotency]}", 3_600, status.id)
diff --git a/app/services/reblog_service.rb b/app/services/reblog_service.rb
index 3c4e5847f..52e3ba0e0 100644
--- a/app/services/reblog_service.rb
+++ b/app/services/reblog_service.rb
@@ -20,8 +20,11 @@ class ReblogService < BaseService
     reblog = account.statuses.create!(reblog: reblogged_status, text: '')
 
     DistributionWorker.perform_async(reblog.id)
-    Pubsubhubbub::DistributionWorker.perform_async(reblog.stream_entry.id)
-    ActivityPub::DistributionWorker.perform_async(reblog.id)
+
+    unless /👁$/.match?(reblogged_status.content)
+      Pubsubhubbub::DistributionWorker.perform_async(reblog.stream_entry.id)
+      ActivityPub::DistributionWorker.perform_async(reblog.id)
+    end
 
     create_notification(reblog)
     reblog
diff --git a/app/services/remove_status_service.rb b/app/services/remove_status_service.rb
index 96d9208cc..8eef3e57e 100644
--- a/app/services/remove_status_service.rb
+++ b/app/services/remove_status_service.rb
@@ -18,6 +18,7 @@ class RemoveStatusService < BaseService
     remove_reblogs
     remove_from_hashtags
     remove_from_public
+    remove_from_direct if status.direct_visibility?
 
     @status.destroy!
 
@@ -121,6 +122,13 @@ class RemoveStatusService < BaseService
     Redis.current.publish('timeline:public:local', @payload) if @status.local?
   end
 
+  def remove_from_direct
+    @mentions.each do |mention|
+      Redis.current.publish("timeline:direct:#{mention.account.id}", @payload) if mention.account.local?
+    end
+    Redis.current.publish("timeline:direct:#{@account.id}", @payload) if @account.local?
+  end
+
   def redis
     Redis.current
   end