Fix filtering of mentions from filtered-on-their-origin-server accounts (#37583)

This commit is contained in:
Claire 2026-01-27 10:53:21 +01:00 committed by GitHub
parent cd7ffb5a10
commit 73fc40993b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 67 additions and 13 deletions

View File

@ -79,9 +79,11 @@ class FanOutOnWriteService < BaseService
end
def notify_mentioned_accounts!
@status.active_mentions.where.not(id: @options[:silenced_account_ids] || []).joins(:account).merge(Account.local).select(:id, :account_id).reorder(nil).find_in_batches do |mentions|
@status.active_mentions.joins(:account).merge(Account.local).select(:id, :account_id).reorder(nil).find_in_batches do |mentions|
LocalNotificationWorker.push_bulk(mentions) do |mention|
[mention.account_id, mention.id, 'Mention', 'mention']
options = { 'silenced' => true } if @options[:silenced_account_ids]&.include?(mention.account_id)
[mention.account_id, mention.id, 'Mention', 'mention', options].compact
end
next unless update?

View File

@ -30,12 +30,13 @@ class NotifyService < BaseService
annual_report
).freeze
def initialize(notification)
def initialize(notification, **options)
@recipient = notification.account
@sender = notification.from_account
@notification = notification
@policy = NotificationPolicy.find_or_initialize_by(account: @recipient)
@from_staff = @sender.local? && @sender.user.present? && @sender.user_role&.bypass_block?(@recipient.user_role)
@options = options
end
private
@ -164,7 +165,7 @@ class NotifyService < BaseService
end
def blocked_by_limited_accounts_policy?
@policy.drop_limited_accounts? && @sender.silenced? && not_following?
@policy.drop_limited_accounts? && (@options[:silenced] || @sender.silenced?) && not_following?
end
end
@ -200,13 +201,14 @@ class NotifyService < BaseService
end
def filtered_by_limited_accounts_policy?
@policy.filter_limited_accounts? && @sender.silenced? && not_following?
@policy.filter_limited_accounts? && (@options[:silenced] || @sender.silenced?) && not_following?
end
end
def call(recipient, type, activity)
def call(recipient, type, activity, **options)
return if recipient.user.nil?
@options = options
@recipient = recipient
@activity = activity
@notification = Notification.new(account: @recipient, type: type, activity: @activity)
@ -236,11 +238,11 @@ class NotifyService < BaseService
private
def drop?
DropCondition.new(@notification).drop?
DropCondition.new(@notification, silenced: @options[:silenced]).drop?
end
def filter?
FilterCondition.new(@notification).filter?
FilterCondition.new(@notification, silenced: @options[:silenced]).filter?
end
def update_notification_request!

View File

@ -3,7 +3,7 @@
class LocalNotificationWorker
include Sidekiq::Worker
def perform(receiver_account_id, activity_id = nil, activity_class_name = nil, type = nil)
def perform(receiver_account_id, activity_id = nil, activity_class_name = nil, type = nil, options = {})
if activity_id.nil? && activity_class_name.nil?
activity = Mention.find(receiver_account_id)
receiver = activity.account
@ -23,7 +23,7 @@ class LocalNotificationWorker
return
end
NotifyService.new.call(receiver, type || activity_class_name.underscore, activity)
NotifyService.new.call(receiver, type || activity_class_name.underscore, activity, **options.symbolize_keys)
rescue ActiveRecord::RecordNotFound
true
end

View File

@ -45,7 +45,9 @@ RSpec.describe FanOutOnWriteService do
let(:visibility) { 'public' }
it 'adds status to home feed of author and followers and broadcasts', :inline_jobs do
subject.call(status)
expect { subject.call(status) }
.to change(bob.notifications, :count).by(1)
.and change(eve.notifications, :count).by(1)
expect(status.id)
.to be_in(home_feed_of(alice))
@ -58,6 +60,14 @@ RSpec.describe FanOutOnWriteService do
expect(redis).to have_received(:publish).with('timeline:public:local', anything)
expect(redis).to have_received(:publish).with('timeline:public:media', anything)
end
context 'with silenced_account_ids' do
it 'calls LocalNotificationWorker with the expected arguments' do
expect { subject.call(status, silenced_account_ids: [eve.id]) }
.to enqueue_sidekiq_job(LocalNotificationWorker).with(bob.id, anything, 'Mention', 'mention')
.and enqueue_sidekiq_job(LocalNotificationWorker).with(eve.id, anything, 'Mention', 'mention', { 'silenced' => true })
end
end
end
context 'when status is limited' do

View File

@ -224,13 +224,25 @@ RSpec.describe NotifyService do
end
end
context 'when sender is considered silenced through `silenced` option and recipient has a policy to ignore silenced accounts' do
subject { described_class.new(notification, silenced: true) }
before do
notification.account.create_notification_policy!(for_limited_accounts: :drop)
end
it 'returns true' do
expect(subject.drop?).to be true
end
end
context 'when sender is new and recipient has a default policy' do
it 'returns false' do
expect(subject.drop?).to be false
end
end
context 'when sender is new and recipient has a policy to ignore silenced accounts' do
context 'when sender is new and recipient has a policy to ignore new accounts' do
before do
notification.account.create_notification_policy!(for_new_accounts: :drop)
end
@ -240,7 +252,7 @@ RSpec.describe NotifyService do
end
end
context 'when sender is new and followed and recipient has a policy to ignore silenced accounts' do
context 'when sender is new and followed and recipient has a policy to ignore new accounts' do
before do
notification.account.create_notification_policy!(for_new_accounts: :drop)
notification.account.follow!(notification.from_account)
@ -300,6 +312,34 @@ RSpec.describe NotifyService do
end
end
context 'when sender is considered silenced through the `silenced` option' do
subject { described_class.new(notification, silenced: true) }
it 'returns true' do
expect(subject.filter?).to be true
end
context 'when recipient follows sender' do
before do
notification.account.follow!(notification.from_account)
end
it 'returns false' do
expect(subject.filter?).to be false
end
end
context 'when recipient is allowing limited accounts' do
before do
notification.account.create_notification_policy!(for_limited_accounts: :accept)
end
it 'returns false' do
expect(subject.filter?).to be false
end
end
end
context 'when recipient is filtering not-followed senders' do
before do
Fabricate(:notification_policy, account: notification.account, filter_not_following: true)