Browse Source

PublicFeed: add a configuration setting to filter out bot accounts

This can be useful when running a smaller instance that also has bot
accounts, where you don't want them to clutter up the Local timeline.
pull/1296/head
Andrew Dunham 3 years ago
parent
commit
04447a05cb
  1. 7
      app/controllers/api/v1/timelines/public_controller.rb
  2. 1
      app/models/account.rb
  3. 11
      app/models/public_feed.rb
  4. 1
      app/models/tag_feed.rb
  5. 5
      config/initializers/99_hometown.rb
  6. 33
      spec/models/public_feed_spec.rb

7
app/controllers/api/v1/timelines/public_controller.rb

@ -37,10 +37,15 @@ class Api::V1::Timelines::PublicController < Api::BaseController
current_account,
local: truthy_param?(:local),
remote: truthy_param?(:remote),
only_media: truthy_param?(:only_media)
only_media: truthy_param?(:only_media),
without_bots: without_bots?
)
end
def without_bots?
Rails.configuration.x.local_timeline_exclude_bots && truthy_param?(:local)
end
def insert_pagination_headers
set_pagination_headers(next_path, prev_path)
end

1
app/models/account.rb

@ -103,6 +103,7 @@ class Account < ApplicationRecord
scope :without_suspended, -> { where(suspended_at: nil) }
scope :without_silenced, -> { where(silenced_at: nil) }
scope :without_instance_actor, -> { where.not(id: -99) }
scope :without_bots, -> { where.not(actor_type: %w(Application Service)).or(where(actor_type: nil)) }
scope :recent, -> { reorder(id: :desc) }
scope :bots, -> { where(actor_type: %w(Application Service)) }
scope :groups, -> { where(actor_type: 'Group') }

11
app/models/public_feed.rb

@ -8,6 +8,7 @@ class PublicFeed
# @option [Boolean] :local
# @option [Boolean] :remote
# @option [Boolean] :only_media
# @option [Boolean] :without_bots
def initialize(account, options = {})
@account = account
@options = options
@ -68,8 +69,16 @@ class PublicFeed
options[:only_media]
end
def without_bots?
options[:without_bots]
end
def public_scope
Status.with_public_visibility.joins(:account).merge(Account.without_suspended.without_silenced)
account_scope = Account.without_suspended.without_silenced
if without_bots?
account_scope = account_scope.without_bots
end
scope = Status.with_public_visibility.joins(:account).merge(account_scope)
end
def local_only_scope

1
app/models/tag_feed.rb

@ -12,6 +12,7 @@ class TagFeed < PublicFeed
# @option [Boolean] :local
# @option [Boolean] :remote
# @option [Boolean] :only_media
# @option [Boolean] :without_bots
def initialize(tag, account, options = {})
@tag = tag
super(account, options)

5
config/initializers/99_hometown.rb

@ -0,0 +1,5 @@
# frozen_string_literal: true
Rails.application.configure do
config.x.local_timeline_exclude_bots = ENV['LOCAL_TIMELINE_EXCLUDE_BOTS'] == 'true'
end

33
spec/models/public_feed_spec.rb

@ -39,6 +39,39 @@ RSpec.describe PublicFeed, type: :model do
expect(subject).not_to include(silenced_status.id)
end
describe '#without_bots=' do
let(:person_account) { Fabricate(:account, actor_type: 'Person') }
let(:bot_account) { Fabricate(:account, actor_type: 'Application') }
context 'when the setting is false' do
subject { described_class.new(nil, without_bots: false).get(20).map(&:id) }
it 'includes bots' do
status = Fabricate(:status, account: account)
person_status = Fabricate(:status, account: person_account)
bot_status = Fabricate(:status, account: bot_account)
expect(subject).to include(status.id)
expect(subject).to include(person_status.id)
expect(subject).to include(bot_status.id)
end
end
context 'when the setting is true' do
subject { described_class.new(nil, without_bots: true).get(20).map(&:id) }
it 'filters out bot accounts' do
status = Fabricate(:status, account: account)
person_status = Fabricate(:status, account: person_account)
bot_status = Fabricate(:status, account: bot_account)
expect(subject).to include(status.id)
expect(subject).to include(person_status.id)
expect(subject).not_to include(bot_status.id)
end
end
end
context 'without local_only option' do
let(:viewer) { nil }

Loading…
Cancel
Save