diff --git a/app/lib/status_filter.rb b/app/lib/status_filter.rb index b6c80b801..0f8841885 100644 --- a/app/lib/status_filter.rb +++ b/app/lib/status_filter.rb @@ -21,7 +21,46 @@ class StatusFilter end def filtered_status? - blocking_account? || blocking_domain? || muting_account? + blocking_account? || blocking_domain? || muting_account? || filtered_reference? + end + + def filtered_reference? + filtered_reply = reply_to_blocked? || reply_to_muted? + + # I don't think this should happen, but just in case... + return filtered_reply if status&.mentions.nil? + + # Grab a list of account IDs mentioned in the status. + mentioned_account_ids = status.mentions.pluck(:account_id) + + # Don't filter statuses mentioning you. + return false if mentioned_account_ids.include?(account.id) + + # Otherwise, filter replies to someone you've muted or blocked. + return true if filtered_reply + + # Otherwise, filter the status if it mentions someone in the preloaded muting relation. + return true if @preloaded_relations[:muting] && mentioned_account_ids.any? do |mentioned_account_id| + @preloaded_relations[:muting][mentioned_account_id] + end + + # Otherwise, filter the status if it mentions someone you've muted. + return true if account.muting?(mentioned_account_ids) + + # Same as above, but for blocks: + return true if @preloaded_relations[:blocking] && mentioned_account_ids.any? do |mentioned_account_id| + @preloaded_relations[:blocking][mentioned_account_id] + end + + account.blocking?(mentioned_account_ids) + end + + def reply_to_blocked? + @preloaded_relations[:blocking] ? @preloaded_relations[:blocking][status.in_reply_to_account_id] : account.blocking?(status.in_reply_to_account_id) + end + + def reply_to_muted? + @preloaded_relations[:muting] ? @preloaded_relations[:muting][status.in_reply_to_account_id] : account.muting?(status.in_reply_to_account_id) end def blocking_account? diff --git a/app/models/status.rb b/app/models/status.rb index 7a3b4da36..21a0ac84f 100644 --- a/app/models/status.rb +++ b/app/models/status.rb @@ -92,6 +92,8 @@ class Status < ApplicationRecord scope :excluding_silenced_accounts, -> { left_outer_joins(:account).where(accounts: { silenced_at: nil }) } scope :including_silenced_accounts, -> { left_outer_joins(:account).where.not(accounts: { silenced_at: nil }) } scope :not_excluded_by_account, ->(account) { where.not(account_id: account.excluded_from_timeline_account_ids) } + scope :reply_not_excluded_by_account, ->(account) { where('statuses.in_reply_to_account_id IS NULL OR statuses.in_reply_to_account_id NOT IN (?)', account.excluded_from_timeline_account_ids) } + scope :mention_not_excluded_by_account, ->(account) { left_outer_joins(:mentions).where('mentions.account_id IS NULL OR mentions.account_id NOT IN (?)', account.excluded_from_timeline_account_ids) } scope :not_domain_blocked_by_account, ->(account) { account.excluded_from_timeline_domains.blank? ? left_outer_joins(:account) : left_outer_joins(:account).where('accounts.domain IS NULL OR accounts.domain NOT IN (?)', account.excluded_from_timeline_domains) } scope :tagged_with_all, ->(tags) { Array(tags).map(&:id).map(&:to_i).reduce(self) do |result, id| @@ -433,6 +435,8 @@ class Status < ApplicationRecord query = query.not_excluded_by_account(account) query = query.not_domain_blocked_by_account(account) unless local_only query = query.in_chosen_languages(account) if account.chosen_languages.present? + query = query.reply_not_excluded_by_account(account) + query = query.mention_not_excluded_by_account(account) query.merge(account_silencing_filter(account)) end