diff --git a/.rubocop.yml b/.rubocop.yml index e022754eab..ef40e95a2a 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -89,6 +89,7 @@ Metrics/CyclomaticComplexity: - 'app/lib/feed_manager.rb' - 'app/policies/status_policy.rb' - 'app/services/activitypub/process_account_service.rb' + - 'app/services/delivery_antenna_service.rb' - 'app/services/post_status_service.rb' - lib/mastodon/cli/*.rb - db/*migrate/**/* @@ -101,6 +102,7 @@ Metrics/ParameterLists: Metrics/PerceivedComplexity: Exclude: - 'app/policies/status_policy.rb' + - 'app/services/delivery_antenna_service.rb' - 'app/services/post_status_service.rb' # Reason: Prevailing style is argument file paths diff --git a/app/services/delivery_antenna_service.rb b/app/services/delivery_antenna_service.rb index 31b61b71e1..3d4f7c0b51 100644 --- a/app/services/delivery_antenna_service.rb +++ b/app/services/delivery_antenna_service.rb @@ -20,6 +20,7 @@ class DeliveryAntennaService def delivery! tag_ids = @status.tags.pluck(:id) domain = @account.domain || Rails.configuration.x.local_domain + follower_ids = @status.unlisted_visibility? ? @status.account.followers.pluck(:id) : [] antennas = Antenna.availables antennas = antennas.left_joins(:antenna_domains).where(any_domains: true).or(Antenna.left_joins(:antenna_domains).where(antenna_domains: { name: domain })) @@ -32,7 +33,7 @@ class DeliveryAntennaService antennas = antennas.left_joins(:antenna_tags).where(any_tags: true).or(Antenna.left_joins(:antenna_tags).where(antenna_tags: { tag_id: tag_ids })) antennas = antennas.where(account_id: Account.without_suspended.joins(:user).select('accounts.id').where('users.current_sign_in_at > ?', User::ACTIVE_DURATION.ago)) - antennas = antennas.where(account: @status.account.followers) if [:public, :public_unlisted, :login, :limited].exclude?(@status.visibility.to_sym) + antennas = antennas.where(account: @status.account.followers) if [:public, :public_unlisted, :login, :limited].exclude?(@status.visibility.to_sym) && !@status.public_searchability? antennas = antennas.where(account: @status.mentioned_accounts) if @status.visibility.to_sym == :limited antennas = antennas.where(with_media_only: false) unless @status.with_media? antennas = antennas.where(ignore_reblog: false) if @status.reblog? @@ -49,6 +50,8 @@ class DeliveryAntennaService next if antenna.exclude_accounts&.include?(@status.account_id) next if antenna.exclude_domains&.include?(domain) next if antenna.exclude_tags&.any? { |tag_id| tag_ids.include?(tag_id) } + next if @status.unlisted_visibility? && !@status.public_searchability? && follower_ids.exclude?(antenna.account_id) + next if @status.unlisted_visibility? && @status.public_searchability? && follower_ids.exclude?(antenna.account_id) && antenna.any_keywords && antenna.any_tags collection.push(antenna) end @@ -84,10 +87,13 @@ class DeliveryAntennaService @stl_home = stl_home @home_account_ids = [] @list_ids = [] + @antenna_timeline_ids = [] end def push(antenna) - if antenna.list_id.zero? + if !antenna.insert_feeds? + @antenna_timeline_ids << { id: antenna.id, antenna_id: antenna.id } + elsif antenna.list_id.zero? @home_account_ids << { id: antenna.account_id, antenna_id: antenna.id } if @home_account_ids.none? { |id| id[:id] == antenna.account_id } elsif @list_ids.none? { |id| id[:id] == antenna.list_id } @list_ids << { id: antenna.list_id, antenna_id: antenna.id } @@ -97,6 +103,7 @@ class DeliveryAntennaService def deliver! lists = @list_ids homes = @home_account_ids + timelines = @antenna_timeline_ids if lists.any? FeedInsertWorker.push_bulk(lists) do |list| @@ -104,10 +111,16 @@ class DeliveryAntennaService end end - return unless homes.any? + if homes.any? + FeedInsertWorker.push_bulk(homes) do |home| + [@status.id, home[:id], 'home', { 'update' => @update, 'antenna_id' => home[:antenna_id] }] + end + end - FeedInsertWorker.push_bulk(homes) do |home| - [@status.id, home[:id], 'home', { 'update' => @update, 'antenna_id' => home[:antenna_id] }] + return unless timelines.any? + + FeedInsertWorker.push_bulk(timelines) do |antenna| + [@status.id, antenna[:id], 'antenna', { 'update' => @update }] end end end diff --git a/app/workers/feed_insert_worker.rb b/app/workers/feed_insert_worker.rb index 7bc046f2e2..22acd0aa6f 100644 --- a/app/workers/feed_insert_worker.rb +++ b/app/workers/feed_insert_worker.rb @@ -17,6 +17,9 @@ class FeedInsertWorker when :list @list = List.find(id) @follower = @list.account + when :antenna + @antenna = Antenna.find(id) + @follower = @antenna.account end end @@ -40,7 +43,7 @@ class FeedInsertWorker def feed_filtered? case @type - when :home + when :home, :antenna FeedManager.instance.filter?(:home, @status, @follower) when :tags FeedManager.instance.filter?(:tags, @status, @follower) diff --git a/spec/services/delivery_antenna_service_spec.rb b/spec/services/delivery_antenna_service_spec.rb index ba20157348..117fcf182c 100644 --- a/spec/services/delivery_antenna_service_spec.rb +++ b/spec/services/delivery_antenna_service_spec.rb @@ -7,8 +7,8 @@ RSpec.describe DeliveryAntennaService, type: :service do let(:last_active_at) { Time.now.utc } let(:last_active_at_tom) { Time.now.utc } - let(:visibility) { 'public' } - let(:searchability) { 'public' } + let(:visibility) { :public } + let(:searchability) { :public } let(:domain) { nil } let(:spoiler_text) { '' } let(:tags) { Tag.find_or_create_by_names(['hoge']) } @@ -35,7 +35,7 @@ RSpec.describe DeliveryAntennaService, type: :service do allow(redis).to receive(:publish) - subject.call(status, true, stl_home) + subject.call(status, false, stl_home) end def home_feed_of(account) @@ -241,6 +241,18 @@ RSpec.describe DeliveryAntennaService, type: :service do end end + context 'when multiple antennas from same owner with keyword' do + let!(:antenna) { antenna_with_keyword(tom, 'body') } + let!(:empty_antenna) { antenna_with_keyword(tom, 'body') } + + [1, 2, 3, 4, 5].each do |_| + it 'detecting antenna' do + expect(antenna_feed_of(antenna)).to include status.id + expect(antenna_feed_of(empty_antenna)).to include status.id + end + end + end + context 'when multiple antennas insert home with keyword' do let!(:antenna) { antenna_with_keyword(bob, 'body', insert_feeds: true) } let!(:empty_antenna) { antenna_with_keyword(tom, 'body', insert_feeds: true) } @@ -264,4 +276,18 @@ RSpec.describe DeliveryAntennaService, type: :service do expect(list_feed_of(empty_antenna.list)).to include status.id end end + + context 'with keyword and unlisted visibility/public searchability by not following' do + let!(:antenna) { antenna_with_keyword(tom, 'body') } + let!(:empty_antenna) { antenna_with_account(tom, alice) } + let(:visibility) { :unlisted } + + it 'detecting antenna' do + expect(antenna_feed_of(antenna)).to include status.id + end + + it 'not detecting antenna' do + expect(antenna_feed_of(empty_antenna)).to_not include status.id + end + end end