Merge branch 'master' into glitch-soc/merge-upstream
Conflicts: - app/controllers/api/v1/timelines/public_controller.rb - app/lib/feed_manager.rb - app/models/status.rb - app/services/precompute_feed_service.rb - app/workers/feed_insert_worker.rb - spec/models/status_spec.rb All conflicts are due to upstream refactoring feed management and us having local-only toots on top of that. Rewrote local-only toots management for upstream's changes.
This commit is contained in:
104
app/models/public_feed.rb
Normal file
104
app/models/public_feed.rb
Normal file
@ -0,0 +1,104 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class PublicFeed < Feed
|
||||
# @param [Account] account
|
||||
# @param [Hash] options
|
||||
# @option [Boolean] :with_replies
|
||||
# @option [Boolean] :with_reblogs
|
||||
# @option [Boolean] :local
|
||||
# @option [Boolean] :remote
|
||||
# @option [Boolean] :only_media
|
||||
# @option [Boolean] :allow_local_only
|
||||
def initialize(account, options = {})
|
||||
@account = account
|
||||
@options = options
|
||||
end
|
||||
|
||||
# @param [Integer] limit
|
||||
# @param [Integer] max_id
|
||||
# @param [Integer] since_id
|
||||
# @param [Integer] min_id
|
||||
# @return [Array<Status>]
|
||||
def get(limit, max_id = nil, since_id = nil, min_id = nil)
|
||||
scope = public_scope
|
||||
|
||||
scope.merge!(without_local_only_scope) unless allow_local_only?
|
||||
scope.merge!(without_replies_scope) unless with_replies?
|
||||
scope.merge!(without_reblogs_scope) unless with_reblogs?
|
||||
scope.merge!(local_only_scope) if local_only?
|
||||
scope.merge!(remote_only_scope) if remote_only?
|
||||
scope.merge!(account_filters_scope) if account?
|
||||
scope.merge!(media_only_scope) if media_only?
|
||||
|
||||
scope.cache_ids.to_a_paginated_by_id(limit, max_id: max_id, since_id: since_id, min_id: min_id)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def allow_local_only?
|
||||
local_account? && (local_only? || @options[:allow_local_only])
|
||||
end
|
||||
|
||||
def with_reblogs?
|
||||
@options[:with_reblogs]
|
||||
end
|
||||
|
||||
def with_replies?
|
||||
@options[:with_replies]
|
||||
end
|
||||
|
||||
def local_only?
|
||||
@options[:local]
|
||||
end
|
||||
|
||||
def remote_only?
|
||||
@options[:remote]
|
||||
end
|
||||
|
||||
def account?
|
||||
@account.present?
|
||||
end
|
||||
|
||||
def local_account?
|
||||
@account&.local?
|
||||
end
|
||||
|
||||
def media_only?
|
||||
@options[:only_media]
|
||||
end
|
||||
|
||||
def public_scope
|
||||
Status.with_public_visibility.joins(:account).merge(Account.without_suspended.without_silenced)
|
||||
end
|
||||
|
||||
def local_only_scope
|
||||
Status.local
|
||||
end
|
||||
|
||||
def remote_only_scope
|
||||
Status.remote
|
||||
end
|
||||
|
||||
def without_replies_scope
|
||||
Status.without_replies
|
||||
end
|
||||
|
||||
def without_reblogs_scope
|
||||
Status.without_reblogs
|
||||
end
|
||||
|
||||
def media_only_scope
|
||||
Status.joins(:media_attachments).group(:id)
|
||||
end
|
||||
|
||||
def without_local_only_scope
|
||||
Status.not_local_only
|
||||
end
|
||||
|
||||
def account_filters_scope
|
||||
Status.not_excluded_by_account(@account).tap do |scope|
|
||||
scope.merge!(Status.not_domain_blocked_by_account(@account)) unless local_only?
|
||||
scope.merge!(Status.in_chosen_languages(@account)) if @account.chosen_languages.present?
|
||||
end
|
||||
end
|
||||
end
|
@ -89,12 +89,12 @@ class Status < ApplicationRecord
|
||||
scope :recent, -> { reorder(id: :desc) }
|
||||
scope :remote, -> { where(local: false).where.not(uri: nil) }
|
||||
scope :local, -> { where(local: true).or(where(uri: nil)) }
|
||||
|
||||
scope :with_accounts, ->(ids) { where(id: ids).includes(:account) }
|
||||
scope :without_replies, -> { where('statuses.reply = FALSE OR statuses.in_reply_to_account_id = statuses.account_id') }
|
||||
scope :without_reblogs, -> { where('statuses.reblog_of_id IS NULL') }
|
||||
scope :with_public_visibility, -> { where(visibility: :public) }
|
||||
scope :tagged_with, ->(tag) { joins(:statuses_tags).where(statuses_tags: { tag_id: tag }) }
|
||||
scope :in_chosen_languages, ->(account) { where(language: nil).or where(language: account.chosen_languages) }
|
||||
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) }
|
||||
@ -330,23 +330,6 @@ class Status < ApplicationRecord
|
||||
end
|
||||
end
|
||||
|
||||
def as_public_timeline(account = nil, local_only = false)
|
||||
query = timeline_scope(local_only)
|
||||
query = query.without_replies unless Setting.show_replies_in_public_timelines
|
||||
|
||||
apply_timeline_filters(query, account, [:local, true].include?(local_only))
|
||||
end
|
||||
|
||||
def as_tag_timeline(tag, account = nil, local_only = false)
|
||||
query = timeline_scope(local_only).tagged_with(tag)
|
||||
|
||||
apply_timeline_filters(query, account, local_only)
|
||||
end
|
||||
|
||||
def as_outbox_timeline(account)
|
||||
where(account: account, visibility: :public)
|
||||
end
|
||||
|
||||
def favourites_map(status_ids, account_id)
|
||||
Favourite.select('status_id').where(status_id: status_ids).where(account_id: account_id).each_with_object({}) { |f, h| h[f.status_id] = true }
|
||||
end
|
||||
@ -423,53 +406,6 @@ class Status < ApplicationRecord
|
||||
status&.distributable? ? status : nil
|
||||
end.compact
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def timeline_scope(scope = false)
|
||||
starting_scope = case scope
|
||||
when :local, true
|
||||
Status.local
|
||||
when :remote
|
||||
Status.remote
|
||||
else
|
||||
Status
|
||||
end
|
||||
starting_scope = starting_scope.with_public_visibility
|
||||
if Setting.show_reblogs_in_public_timelines
|
||||
starting_scope
|
||||
else
|
||||
starting_scope.without_reblogs
|
||||
end
|
||||
end
|
||||
|
||||
def apply_timeline_filters(query, account, local_only)
|
||||
if account.nil?
|
||||
filter_timeline_default(query)
|
||||
else
|
||||
filter_timeline_for_account(query, account, local_only)
|
||||
end
|
||||
end
|
||||
|
||||
def filter_timeline_for_account(query, account, local_only)
|
||||
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.merge(account_silencing_filter(account))
|
||||
end
|
||||
|
||||
def filter_timeline_default(query)
|
||||
query.not_local_only.excluding_silenced_accounts
|
||||
end
|
||||
|
||||
def account_silencing_filter(account)
|
||||
if account.silenced?
|
||||
including_myself = left_outer_joins(:account).where(account_id: account.id).references(:accounts)
|
||||
excluding_silenced_accounts.or(including_myself)
|
||||
else
|
||||
excluding_silenced_accounts
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def marked_local_only?
|
||||
|
@ -39,7 +39,7 @@ class Tag < ApplicationRecord
|
||||
scope :listable, -> { where(listable: [true, nil]) }
|
||||
scope :trendable, -> { Setting.trendable_by_default ? where(trendable: [true, nil]) : where(trendable: true) }
|
||||
scope :discoverable, -> { listable.joins(:account_tag_stat).where(AccountTagStat.arel_table[:accounts_count].gt(0)).order(Arel.sql('account_tag_stats.accounts_count desc')) }
|
||||
scope :most_used, ->(account) { joins(:statuses).where(statuses: { account: account }).group(:id).order(Arel.sql('count(*) desc')) }
|
||||
scope :recently_used, ->(account) { joins(:statuses).where(statuses: { id: account.statuses.select(:id).limit(1000) }).group(:id).order(Arel.sql('count(*) desc')) }
|
||||
scope :matches_name, ->(value) { where(arel_table[:name].matches("#{value}%")) }
|
||||
|
||||
delegate :accounts_count,
|
||||
|
58
app/models/tag_feed.rb
Normal file
58
app/models/tag_feed.rb
Normal file
@ -0,0 +1,58 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class TagFeed < PublicFeed
|
||||
LIMIT_PER_MODE = 4
|
||||
|
||||
# @param [Tag] tag
|
||||
# @param [Account] account
|
||||
# @param [Hash] options
|
||||
# @option [Enumerable<String>] :any
|
||||
# @option [Enumerable<String>] :all
|
||||
# @option [Enumerable<String>] :none
|
||||
# @option [Boolean] :local
|
||||
# @option [Boolean] :remote
|
||||
# @option [Boolean] :only_media
|
||||
def initialize(tag, account, options = {})
|
||||
@tag = tag
|
||||
@account = account
|
||||
@options = options
|
||||
end
|
||||
|
||||
# @param [Integer] limit
|
||||
# @param [Integer] max_id
|
||||
# @param [Integer] since_id
|
||||
# @param [Integer] min_id
|
||||
# @return [Array<Status>]
|
||||
def get(limit, max_id = nil, since_id = nil, min_id = nil)
|
||||
scope = public_scope
|
||||
|
||||
scope.merge!(without_local_only_scope) unless local_account?
|
||||
scope.merge!(tagged_with_any_scope)
|
||||
scope.merge!(tagged_with_all_scope)
|
||||
scope.merge!(tagged_with_none_scope)
|
||||
scope.merge!(local_only_scope) if local_only?
|
||||
scope.merge!(remote_only_scope) if remote_only?
|
||||
scope.merge!(account_filters_scope) if account?
|
||||
scope.merge!(media_only_scope) if media_only?
|
||||
|
||||
scope.cache_ids.to_a_paginated_by_id(limit, max_id: max_id, since_id: since_id, min_id: min_id)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def tagged_with_any_scope
|
||||
Status.group(:id).tagged_with(tags_for(Array(@tag.name) | Array(@options[:any])))
|
||||
end
|
||||
|
||||
def tagged_with_all_scope
|
||||
Status.group(:id).tagged_with_all(tags_for(@options[:all]))
|
||||
end
|
||||
|
||||
def tagged_with_none_scope
|
||||
Status.group(:id).tagged_with_none(tags_for(@options[:none]))
|
||||
end
|
||||
|
||||
def tags_for(names)
|
||||
Tag.matching_name(Array(names).take(LIMIT_PER_MODE)) if names.present?
|
||||
end
|
||||
end
|
Reference in New Issue
Block a user