about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--app/lib/feed_manager.rb44
-rw-r--r--app/models/list.rb1
-rw-r--r--db/migrate/20200923000003_add_reblogs_flag_to_lists.rb8
-rw-r--r--db/schema.rb4
4 files changed, 50 insertions, 7 deletions
diff --git a/app/lib/feed_manager.rb b/app/lib/feed_manager.rb
index 9a0a304e5..5601785fe 100644
--- a/app/lib/feed_manager.rb
+++ b/app/lib/feed_manager.rb
@@ -79,7 +79,8 @@ class FeedManager
   # @param [Status] status
   # @return [Boolean]
   def push_to_list(list, status)
-    return false if status.reblog? || status.account_id == list.account_id || filter_from_list?(status, list) || !add_to_feed(:list, list.id, status, false)
+    return false if filter_from_list?(status, list)
+    return false unless add_to_feed(:list, list.id, status, list.reblogs? && list.account.user&.aggregates_reblogs?)
 
     trim(:list, list.id)
     PushUpdateWorker.perform_async(list.account_id, status.id, "timeline:list:#{list.id}") if push_update_required?("timeline:list:#{list.id}")
@@ -91,7 +92,7 @@ class FeedManager
   # @param [Status] status
   # @return [Boolean]
   def unpush_from_list(list, status)
-    return false unless remove_from_feed(:list, list.id, status, false)
+    return false unless remove_from_feed(:list, list.id, status, list.account.user&.aggregates_reblogs?)
 
     redis.publish("timeline:list:#{list.id}", Oj.dump(event: :delete, payload: status.id.to_s))
     true
@@ -127,7 +128,7 @@ class FeedManager
     unpush_from_direct(account, status) if status.direct_visibility?
 
     account.lists_for_local_distribution.select(:id, :account_id).each do |list|
-      unpush_from_list(list, status)
+      unpush_from_list(list, status, list.reblogs? && list.account.user&.aggregates_reblogs?)
     end
   end
 
@@ -215,7 +216,7 @@ class FeedManager
     oldest_list_score = redis.zrange(timeline_key, 0, 0, with_scores: true)&.first&.last&.to_i || 0
 
     from_account.statuses.select('id, reblog_of_id').where('id > ?', oldest_list_score).reorder(nil).find_each do |status|
-      remove_from_feed(:list, list.id, status, list.account.user&.aggregates_reblogs?)
+      remove_from_feed(:list, list.id, status, list.reblogs? && list.account.user&.aggregates_reblogs?)
     end
   end
 
@@ -264,7 +265,9 @@ class FeedManager
         crutches = build_crutches(account.id, statuses)
 
         statuses.each do |status|
-          add_to_feed(:list, list.id, status, false) unless filter_from_list?(status, account.id) || filter_from_home?(status, account.id, crutches, filter_options)
+          next if filter_from_list?(status, account.id) || filter_from_home?(status, account.id, crutches, filter_options)
+
+          add_to_feed(:list, list.id, status, list.reblogs? && list.account.user&.aggregates_reblogs?)
         end
 
         trim(:list, list.id)
@@ -300,7 +303,9 @@ class FeedManager
       filter_options = filter_options_for(account.id)
 
       statuses.each do |status|
-        add_to_feed(:home, account.id, status, aggregate) unless filter_from_home?(status, account.id, crutches, filter_options)
+        next if filter_from_home?(status, account.id, crutches, filter_options)
+
+        add_to_feed(:home, account.id, status, aggregate)
       end
 
       trim(:home, account.id)
@@ -483,6 +488,9 @@ class FeedManager
   # @param [List] list
   # @return [Boolean]
   def filter_from_list?(status, list)
+    return true if (list.reblogs? && !status.reblog?) || (!list.reblogs? && status.reblog?)
+    return true if status.reblog? ? status.reblog.account_id == list.account_id : status.account_id == list.account_id
+
     if status.reply? && status.in_reply_to_account_id != status.account_id
       should_filter = status.in_reply_to_account_id != list.account_id
       should_filter &&= !list.show_all_replies?
@@ -575,6 +583,16 @@ class FeedManager
       redis.zadd(timeline_key, status.id, status.id)
     end
 
+    if timeline_type == :home && status.reblog?
+      reblogs_list_id = find_or_create_reblogs_list(account_id).id
+      if add_to_feed(:list, reblogs_list_id, status, aggregate_reblogs)
+        trim(:list, reblogs_list_id)
+        if push_update_required?("timeline:list:#{reblogs_list_id}")
+          PushUpdateWorker.perform_async(account_id, status.id, "timeline:list:#{reblogs_list_id}")
+        end
+      end
+    end
+
     true
   end
 
@@ -591,6 +609,13 @@ class FeedManager
     timeline_key = key(timeline_type, account_id)
     reblog_key   = key(timeline_type, account_id, 'reblogs')
 
+    if timeline_type == :home && status.reblog?
+      reblogs_list_id = find_or_create_reblogs_list(account_id).id
+      if remove_from_feed(:list, reblogs_list_id, status, aggregate_reblogs)
+        redis.publish("timeline:list:#{reblogs_list_id}", Oj.dump(event: :delete, payload: status.id.to_s))
+      end
+    end
+
     if status.reblog? && (aggregate_reblogs.nil? || aggregate_reblogs)
       # 1. If the reblogging status is not in the feed, stop.
       status_rank = redis.zrevrank(timeline_key, status.id)
@@ -654,4 +679,11 @@ class FeedManager
 
     crutches
   end
+
+  def find_or_create_reblogs_list(account_id)
+    List.find_or_create_by!(account_id: account_id, reblogs: true) do |list|
+      list.title = I18n.t('accounts.reblogs')
+      list.replies_policy = :no_replies
+    end
+  end
 end
diff --git a/app/models/list.rb b/app/models/list.rb
index e0606488f..006b7e745 100644
--- a/app/models/list.rb
+++ b/app/models/list.rb
@@ -9,6 +9,7 @@
 #  created_at     :datetime         not null
 #  updated_at     :datetime         not null
 #  replies_policy :integer          default("list_replies"), not null
+#  reblogs        :boolean          default(FALSE), not null
 #
 
 class List < ApplicationRecord
diff --git a/db/migrate/20200923000003_add_reblogs_flag_to_lists.rb b/db/migrate/20200923000003_add_reblogs_flag_to_lists.rb
new file mode 100644
index 000000000..bb6bcc6c2
--- /dev/null
+++ b/db/migrate/20200923000003_add_reblogs_flag_to_lists.rb
@@ -0,0 +1,8 @@
+class AddReblogsFlagToLists < ActiveRecord::Migration[5.2]
+  def change
+    safety_assured do
+      add_column :lists, :reblogs, :boolean, default: false, null: false
+      add_index :lists, :id, name: :lists_reblog_feeds, where: '(reblogs = TRUE)'
+    end
+  end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 4e3114068..ab1fc6453 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -10,7 +10,7 @@
 #
 # It's strongly recommended that you check this file into your version control system.
 
-ActiveRecord::Schema.define(version: 2020_09_23_000002) do
+ActiveRecord::Schema.define(version: 2020_09_23_000003) do
 
   # These are extensions that must be enabled in order to support this database
   enable_extension "plpgsql"
@@ -528,7 +528,9 @@ ActiveRecord::Schema.define(version: 2020_09_23_000002) do
     t.datetime "created_at", null: false
     t.datetime "updated_at", null: false
     t.integer "replies_policy", default: 0, null: false
+    t.boolean "reblogs", default: false, null: false
     t.index ["account_id"], name: "index_lists_on_account_id"
+    t.index ["id"], name: "lists_reblog_feeds", where: "(reblogs = true)"
   end
 
   create_table "markers", force: :cascade do |t|