From db8e5524db15e19c16b63943ada83b3ac7b75ec6 Mon Sep 17 00:00:00 2001 From: Fire Demon Date: Sat, 15 Aug 2020 03:26:55 -0500 Subject: [Profiles] Add category filters --- app/models/status.rb | 98 ++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 80 insertions(+), 18 deletions(-) (limited to 'app/models') diff --git a/app/models/status.rb b/app/models/status.rb index e568bfed7..d31e5668e 100644 --- a/app/models/status.rb +++ b/app/models/status.rb @@ -135,6 +135,10 @@ class Status < ApplicationRecord scope :without_semiprivate, -> { where(semiprivate: false) } scope :reblogs, -> { where('statuses.reblog_of_id IS NOT NULL') } scope :locally_reblogged, -> { where(id: Status.unscoped.local.reblogs.select(:reblog_of_id)) } + scope :public_conversations, -> { joins(:conversation).where(conversations: { public: true }) } + scope :conversations_by, ->(account) { joins(:conversation).where(conversations: { account: account }) } + scope :mentioning_account, ->(account) { joins(:mentions).where(mentions: { account: account }) } + scope :replies, -> { where(reply: true).where('statuses.in_reply_to_account_id != statuses.account_id') } scope :not_hidden_by_account, ->(account) do left_outer_joins(:mutes, :conversation_mute).where('(status_mutes.account_id IS NULL OR status_mutes.account_id != ?) AND (conversation_mutes.account_id IS NULL OR (conversation_mutes.account_id != ? AND conversation_mutes.hidden = TRUE))', account.id, account.id) @@ -504,27 +508,27 @@ class Status < ApplicationRecord end end - def permitted_for(target_account, account, user_signed_in: false) - visibility = user_signed_in || target_account.show_unlisted? ? [:public, :unlisted] : :public + def permitted_for(target_account, account, **options) + visibility = [:public, :unlisted] - if account.nil? - where(visibility: visibility).not_local_only.published - elsif target_account.blocking?(account) || (account.domain.present? && target_account.domain_blocking?(account.domain)) # get rid of blocked peeps - none - elsif account.id == target_account.id # author can see own stuff - all - else - # followers can see followers-only stuff, but also things they are mentioned in. - # non-followers can see everything that isn't private/direct, but can see stuff they are mentioned in. - visibility.push(:private) if account.following?(target_account) && user_signed_in - scope = left_outer_joins(:reblog) - - scope = scope.where(visibility: visibility) - .or(scope.where(id: account.mentions.select(:status_id))) - .merge(scope.where(reblog_of_id: nil).or(scope.where.not(reblogs_statuses: { account_id: account.excluded_from_timeline_account_ids }))) + if account.present? + return none if target_account.blocking?(account) || (account.domain.present? && target_account.domain_blocking?(account.domain)) + return apply_category_filters(all, target_account, account, **options) if account.id == target_account.id - apply_timeline_filters(scope.published, account, false) + visibility.push(:private) if account.following?(target_account) + elsif !target_account.show_unlisted? + visibility = :public end + + scope = where(visibility: visibility) + scope = apply_account_filters(scope, account, **options) + apply_category_filters(scope, target_account, account, **options) + end + + def mentions_between(account, target_account) + return none if account.blank? || target_account.blank? + + account.statuses.mentioning_account(target_account).or(target_account.statuses.mentioning_account(account)) end def from_text(text) @@ -544,6 +548,64 @@ class Status < ApplicationRecord private + # TODO: Cast cleanup spell. + # rubocop:disable Metrics/PerceivedComplexity + def apply_category_filters(query, target_account, account, **options) + return query if options[:without_category_filters] + + query = query.published unless options[:include_unpublished] + + if options[:only_reblogs] + query = query.joins(:reblog) + if account.present? && account.excluded_from_timeline_account_ids.present? + query = query.where.not( + reblogs_statuses: { account_id: account.excluded_from_timeline_account_ids } + ) + end + elsif target_account.id == account&.id + query = query.without_replies unless options[:include_replies] || options[:only_replies] + query = query.without_reblogs unless options[:include_reblogs] || options[:only_reblogs] + query = query.reblogs if options[:only_reblogs] + query = query.replies if options[:only_replies] + else + if options[:include_reblogs] && account.present? && account.excluded_from_timeline_account_ids.present? + query = query.left_outer_joins(:reblog).where( + '(statuses.reblog_of_id IS NULL OR reblogs_statuses.account_id NOT IN (?))', + account.excluded_from_timeline_account_ids + ) + elsif !options[:include_reblogs] + query = query.without_reblogs + end + + query = if options[:only_replies] + query.replies + elsif options[:include_replies] + if target_account.present? + query.public_conversations.or(query.conversations_by(target_account)) + else + query.public_conversations + end + else + query.without_replies + end + end + + return query if options[:tag].blank? + + (tag = Tag.find_normalized(options[:tag])) ? query.merge(Status.tagged_with(tag.id)) : none + end + # rubocop:enable Metrics/PerceivedComplexity + + def apply_account_filters(query, account, **options) + return query.not_local_only if account.blank? + return (account.local? ? query : query.not_local_only) if options[:without_account_filters] + + query = query.not_local_only unless account.local? + query = query.not_hidden_by_account(account) + query = query.in_chosen_languages(account) if account.chosen_languages.present? + query + end + def timeline_scope(scope = false, include_unlisted: false) starting_scope = case scope when :local, true -- cgit