about summary refs log tree commit diff
path: root/app
diff options
context:
space:
mode:
authorEugen Rochko <eugen@zeonfederated.com>2016-11-10 00:03:33 +0100
committerEugen Rochko <eugen@zeonfederated.com>2016-11-10 00:03:33 +0100
commit17903c6dae9eb38ac221fb7cf86e5e3cafe465d0 (patch)
tree4f1d32a1ec9b770407a919bcc46794fcc09f339b /app
parentc5e03a2e0d7eac132a5d62d1d7d523a6969697cc (diff)
Improve filtering of public/hashtag timelines, both in backlog and real-time
Diffstat (limited to 'app')
-rw-r--r--app/channels/application_cable/channel.rb2
-rw-r--r--app/controllers/api/v1/accounts_controller.rb2
-rw-r--r--app/lib/feed_manager.rb14
-rw-r--r--app/models/status.rb22
4 files changed, 32 insertions, 8 deletions
diff --git a/app/channels/application_cable/channel.rb b/app/channels/application_cable/channel.rb
index 43adadbd9..28bf0d9d3 100644
--- a/app/channels/application_cable/channel.rb
+++ b/app/channels/application_cable/channel.rb
@@ -14,7 +14,7 @@ module ApplicationCable
     end
 
     def filter?(status)
-      !status.nil? && (current_user.account.blocking?(status.account) || (status.reblog? && current_user.account.blocking?(status.reblog.account)))
+      !status.nil? && FeedManager.instance.filter?(:public, status, current_user.account)
     end
   end
 end
diff --git a/app/controllers/api/v1/accounts_controller.rb b/app/controllers/api/v1/accounts_controller.rb
index f2049cd55..5cc0817f6 100644
--- a/app/controllers/api/v1/accounts_controller.rb
+++ b/app/controllers/api/v1/accounts_controller.rb
@@ -16,7 +16,7 @@ class Api::V1::AccountsController < ApiController
 
   def following
     results   = Follow.where(account: @account).paginate_by_max_id(DEFAULT_ACCOUNTS_LIMIT, params[:max_id], params[:since_id])
-    @accounts = Account.where(id: results.map(&:account_id)).with_counters.to_a
+    @accounts = Account.where(id: results.map(&:target_account_id)).with_counters.to_a
 
     next_path = following_api_v1_account_url(max_id: results.last.id)    if results.size == DEFAULT_ACCOUNTS_LIMIT
     prev_path = following_api_v1_account_url(since_id: results.first.id) if results.size > 0
diff --git a/app/lib/feed_manager.rb b/app/lib/feed_manager.rb
index af7b2380e..fe88c0fb9 100644
--- a/app/lib/feed_manager.rb
+++ b/app/lib/feed_manager.rb
@@ -14,6 +14,8 @@ class FeedManager
       filter_from_home?(status, receiver)
     elsif timeline_type == :mentions
       filter_from_mentions?(status, receiver)
+    elsif timeline_type == :public
+      filter_from_public?(status, receiver)
     else
       false
     end
@@ -80,4 +82,16 @@ class FeedManager
     should_filter = should_filter || receiver.blocking?(status.account) # or it's from someone I blocked
     should_filter
   end
+
+  def filter_from_public?(status, receiver)
+    should_filter = receiver.blocking?(status.account)
+
+    if status.reply? && !status.thread.account.nil?
+      should_filter = should_filter || receiver.blocking?(status.thread.account)
+    elsif status.reblog?
+      should_filter = should_filter || receiver.blocking?(status.reblog.account)
+    end
+
+    should_filter
+  end
 end
diff --git a/app/models/status.rb b/app/models/status.rb
index 9db7a0a3a..41c3b0a92 100644
--- a/app/models/status.rb
+++ b/app/models/status.rb
@@ -88,12 +88,10 @@ class Status < ApplicationRecord
     end
 
     def as_public_timeline(account = nil)
-      query = joins('LEFT OUTER JOIN statuses AS reblogs ON statuses.reblog_of_id = reblogs.id')
-        .joins('LEFT OUTER JOIN accounts ON statuses.account_id = accounts.id')
-        .where('accounts.silenced = FALSE')
+      query = joins('LEFT OUTER JOIN accounts ON statuses.account_id = accounts.id').where('accounts.silenced = FALSE')
 
       unless account.nil?
-        query = query.where('(reblogs.account_id IS NULL OR reblogs.account_id NOT IN (SELECT target_account_id FROM blocks WHERE account_id = ?)) AND statuses.account_id NOT IN (SELECT target_account_id FROM blocks WHERE account_id = ?)', account.id, account.id)
+        query = filter_timeline(query, account)
       end
 
       query.with_includes.with_counters
@@ -101,12 +99,11 @@ class Status < ApplicationRecord
 
     def as_tag_timeline(tag, account = nil)
       query = tag.statuses
-        .joins('LEFT OUTER JOIN statuses AS reblogs ON statuses.reblog_of_id = reblogs.id')
         .joins('LEFT OUTER JOIN accounts ON statuses.account_id = accounts.id')
         .where('accounts.silenced = FALSE')
 
       unless account.nil?
-        query = query.where('(reblogs.account_id IS NULL OR reblogs.account_id NOT IN (SELECT target_account_id FROM blocks WHERE account_id = ?)) AND statuses.account_id NOT IN (SELECT target_account_id FROM blocks WHERE account_id = ?)', account.id, account.id)
+        query = filter_timeline(query, account)
       end
 
       query.with_includes.with_counters
@@ -119,6 +116,19 @@ class Status < ApplicationRecord
     def reblogs_map(status_ids, account_id)
       select('reblog_of_id').where(reblog_of_id: status_ids).where(account_id: account_id).map { |s| [s.reblog_of_id, true] }.to_h
     end
+
+    private
+
+    def filter_timeline(query, account)
+      blocked = Block.where(account: account).pluck(:target_account_id)
+
+      query
+        .joins('LEFT OUTER JOIN statuses AS parents ON statuses.in_reply_to_id = parents.id')
+        .joins('LEFT OUTER JOIN statuses AS reblogs ON statuses.reblog_of_id = reblogs.id')
+        .where('parents.account_id NOT IN (?)', blocked)
+        .where('statuses.account_id NOT IN (?)', blocked)
+        .where('(reblogs.id IS NULL OR reblogs.account_id NOT IN (?))', blocked)
+    end
   end
 
   before_validation do