diff options
Diffstat (limited to 'app/models')
-rw-r--r-- | app/models/account.rb | 109 | ||||
-rw-r--r-- | app/models/account_domain_block.rb | 26 | ||||
-rw-r--r-- | app/models/concerns/account_avatar.rb | 2 | ||||
-rw-r--r-- | app/models/concerns/account_header.rb | 2 | ||||
-rw-r--r-- | app/models/concerns/account_interactions.rb | 127 | ||||
-rw-r--r-- | app/models/status.rb | 13 |
6 files changed, 172 insertions, 107 deletions
diff --git a/app/models/account.rb b/app/models/account.rb index 03e7db398..f418a0f8b 100644 --- a/app/models/account.rb +++ b/app/models/account.rb @@ -43,6 +43,7 @@ class Account < ApplicationRecord include AccountAvatar include AccountHeader + include AccountInteractions include Attachmentable include Remotable include Targetable @@ -67,26 +68,6 @@ class Account < ApplicationRecord has_many :mentions, inverse_of: :account, dependent: :destroy has_many :notifications, inverse_of: :account, dependent: :destroy - # Follow relations - has_many :follow_requests, dependent: :destroy - - has_many :active_relationships, class_name: 'Follow', foreign_key: 'account_id', dependent: :destroy - has_many :passive_relationships, class_name: 'Follow', foreign_key: 'target_account_id', dependent: :destroy - - has_many :following, -> { order('follows.id desc') }, through: :active_relationships, source: :target_account - has_many :followers, -> { order('follows.id desc') }, through: :passive_relationships, source: :account - - # Block relationships - has_many :block_relationships, class_name: 'Block', foreign_key: 'account_id', dependent: :destroy - has_many :blocking, -> { order('blocks.id desc') }, through: :block_relationships, source: :target_account - has_many :blocked_by_relationships, class_name: 'Block', foreign_key: :target_account_id, dependent: :destroy - has_many :blocked_by, -> { order('blocks.id desc') }, through: :blocked_by_relationships, source: :account - - # Mute relationships - has_many :mute_relationships, class_name: 'Mute', foreign_key: 'account_id', dependent: :destroy - has_many :muting, -> { order('mutes.id desc') }, through: :mute_relationships, source: :target_account - has_many :conversation_mutes - # Media has_many :media_attachments, dependent: :destroy @@ -120,62 +101,6 @@ class Account < ApplicationRecord delegate :allowed_languages, to: :user, prefix: false, allow_nil: true - def follow!(other_account) - active_relationships.find_or_create_by!(target_account: other_account) - end - - def block!(other_account) - block_relationships.find_or_create_by!(target_account: other_account) - end - - def mute!(other_account) - mute_relationships.find_or_create_by!(target_account: other_account) - end - - def mute_conversation!(conversation) - conversation_mutes.find_or_create_by!(conversation: conversation) - end - - def unfollow!(other_account) - follow = active_relationships.find_by(target_account: other_account) - follow&.destroy - end - - def unblock!(other_account) - block = block_relationships.find_by(target_account: other_account) - block&.destroy - end - - def unmute!(other_account) - mute = mute_relationships.find_by(target_account: other_account) - mute&.destroy - end - - def unmute_conversation!(conversation) - mute = conversation_mutes.find_by(conversation: conversation) - mute&.destroy! - end - - def following?(other_account) - following.include?(other_account) - end - - def blocking?(other_account) - blocking.include?(other_account) - end - - def muting?(other_account) - muting.include?(other_account) - end - - def muting_conversation?(conversation) - conversation_mutes.where(conversation: conversation).exists? - end - - def requested?(other_account) - follow_requests.where(target_account: other_account).exists? - end - def local? domain.nil? end @@ -200,14 +125,6 @@ class Account < ApplicationRecord followers.reorder(nil).pluck('distinct accounts.domain') end - def favourited?(status) - status.proper.favourites.where(account: self).exists? - end - - def reblogged?(status) - status.proper.reblogs.where(account: self).exists? - end - def keypair OpenSSL::PKey::RSA.new(private_key || public_key) end @@ -238,6 +155,10 @@ class Account < ApplicationRecord Rails.cache.fetch("exclude_account_ids_for:#{id}") { blocking.pluck(:target_account_id) + blocked_by.pluck(:account_id) + muting.pluck(:target_account_id) } end + def excluded_from_timeline_domains + Rails.cache.fetch("exclude_domains_for:#{id}") { domain_blocks.pluck(:domain) } + end + class << self def find_local!(username) find_remote!(username, nil) @@ -321,26 +242,6 @@ class Account < ApplicationRecord find_by_sql([sql, account.id, account.id, limit]) end - def following_map(target_account_ids, account_id) - follow_mapping(Follow.where(target_account_id: target_account_ids, account_id: account_id), :target_account_id) - end - - def followed_by_map(target_account_ids, account_id) - follow_mapping(Follow.where(account_id: target_account_ids, target_account_id: account_id), :account_id) - end - - def blocking_map(target_account_ids, account_id) - follow_mapping(Block.where(target_account_id: target_account_ids, account_id: account_id), :target_account_id) - end - - def muting_map(target_account_ids, account_id) - follow_mapping(Mute.where(target_account_id: target_account_ids, account_id: account_id), :target_account_id) - end - - def requested_map(target_account_ids, account_id) - follow_mapping(FollowRequest.where(target_account_id: target_account_ids, account_id: account_id), :target_account_id) - end - private def generate_query_for_search(terms) diff --git a/app/models/account_domain_block.rb b/app/models/account_domain_block.rb new file mode 100644 index 000000000..9241d9720 --- /dev/null +++ b/app/models/account_domain_block.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true +# == Schema Information +# +# Table name: account_domain_blocks +# +# id :integer not null, primary key +# account_id :integer +# domain :string +# created_at :datetime not null +# updated_at :datetime not null +# + +class AccountDomainBlock < ApplicationRecord + include Paginable + + belongs_to :account, required: true + + after_create :remove_blocking_cache + after_destroy :remove_blocking_cache + + private + + def remove_blocking_cache + Rails.cache.delete("exclude_domains_for:#{account_id}") + end +end diff --git a/app/models/concerns/account_avatar.rb b/app/models/concerns/account_avatar.rb index c664366ef..73507a328 100644 --- a/app/models/concerns/account_avatar.rb +++ b/app/models/concerns/account_avatar.rb @@ -2,6 +2,7 @@ module AccountAvatar extend ActiveSupport::Concern + IMAGE_MIME_TYPES = ['image/jpeg', 'image/png', 'image/gif'].freeze class_methods do @@ -10,6 +11,7 @@ module AccountAvatar styles[:static] = { format: 'png' } if file.content_type == 'image/gif' styles end + private :avatar_styles end diff --git a/app/models/concerns/account_header.rb b/app/models/concerns/account_header.rb index f1b0883ee..4d96e990a 100644 --- a/app/models/concerns/account_header.rb +++ b/app/models/concerns/account_header.rb @@ -2,6 +2,7 @@ module AccountHeader extend ActiveSupport::Concern + IMAGE_MIME_TYPES = ['image/jpeg', 'image/png', 'image/gif'].freeze class_methods do @@ -10,6 +11,7 @@ module AccountHeader styles[:static] = { format: 'png' } if file.content_type == 'image/gif' styles end + private :header_styles end diff --git a/app/models/concerns/account_interactions.rb b/app/models/concerns/account_interactions.rb new file mode 100644 index 000000000..d51e6643e --- /dev/null +++ b/app/models/concerns/account_interactions.rb @@ -0,0 +1,127 @@ +# frozen_string_literal: true + +module AccountInteractions + extend ActiveSupport::Concern + + class_methods do + def following_map(target_account_ids, account_id) + follow_mapping(Follow.where(target_account_id: target_account_ids, account_id: account_id), :target_account_id) + end + + def followed_by_map(target_account_ids, account_id) + follow_mapping(Follow.where(account_id: target_account_ids, target_account_id: account_id), :account_id) + end + + def blocking_map(target_account_ids, account_id) + follow_mapping(Block.where(target_account_id: target_account_ids, account_id: account_id), :target_account_id) + end + + def muting_map(target_account_ids, account_id) + follow_mapping(Mute.where(target_account_id: target_account_ids, account_id: account_id), :target_account_id) + end + + def requested_map(target_account_ids, account_id) + follow_mapping(FollowRequest.where(target_account_id: target_account_ids, account_id: account_id), :target_account_id) + end + end + + included do + # Follow relations + has_many :follow_requests, dependent: :destroy + + has_many :active_relationships, class_name: 'Follow', foreign_key: 'account_id', dependent: :destroy + has_many :passive_relationships, class_name: 'Follow', foreign_key: 'target_account_id', dependent: :destroy + + has_many :following, -> { order('follows.id desc') }, through: :active_relationships, source: :target_account + has_many :followers, -> { order('follows.id desc') }, through: :passive_relationships, source: :account + + # Block relationships + has_many :block_relationships, class_name: 'Block', foreign_key: 'account_id', dependent: :destroy + has_many :blocking, -> { order('blocks.id desc') }, through: :block_relationships, source: :target_account + has_many :blocked_by_relationships, class_name: 'Block', foreign_key: :target_account_id, dependent: :destroy + has_many :blocked_by, -> { order('blocks.id desc') }, through: :blocked_by_relationships, source: :account + + # Mute relationships + has_many :mute_relationships, class_name: 'Mute', foreign_key: 'account_id', dependent: :destroy + has_many :muting, -> { order('mutes.id desc') }, through: :mute_relationships, source: :target_account + has_many :conversation_mutes, dependent: :destroy + has_many :domain_blocks, class_name: 'AccountDomainBlock', dependent: :destroy + + def follow!(other_account) + active_relationships.find_or_create_by!(target_account: other_account) + end + + def block!(other_account) + block_relationships.find_or_create_by!(target_account: other_account) + end + + def mute!(other_account) + mute_relationships.find_or_create_by!(target_account: other_account) + end + + def mute_conversation!(conversation) + conversation_mutes.find_or_create_by!(conversation: conversation) + end + + def block_domain!(other_domain) + domain_blocks.find_or_create_by!(domain: other_domain) + end + + def unfollow!(other_account) + follow = active_relationships.find_by(target_account: other_account) + follow&.destroy + end + + def unblock!(other_account) + block = block_relationships.find_by(target_account: other_account) + block&.destroy + end + + def unmute!(other_account) + mute = mute_relationships.find_by(target_account: other_account) + mute&.destroy + end + + def unmute_conversation!(conversation) + mute = conversation_mutes.find_by(conversation: conversation) + mute&.destroy! + end + + def unblock_domain!(other_domain) + block = domain_blocks.find_by(domain: other_domain) + block&.destroy + end + + def following?(other_account) + active_relationships.where(target_account: other_account).exists? + end + + def blocking?(other_account) + block_relationships.where(target_account: other_account).exists? + end + + def domain_blocking?(other_domain) + domain_blocks.where(domain: other_domain).exists? + end + + def muting?(other_account) + mute_relationships.where(target_account: other_account).exists? + end + + def muting_conversation?(conversation) + conversation_mutes.where(conversation: conversation).exists? + end + + def requested?(other_account) + follow_requests.where(target_account: other_account).exists? + end + + def favourited?(status) + status.proper.favourites.where(account: self).exists? + end + + def reblogged?(status) + status.proper.reblogs.where(account: self).exists? + end + end +end diff --git a/app/models/status.rb b/app/models/status.rb index fd1049116..760ecc928 100644 --- a/app/models/status.rb +++ b/app/models/status.rb @@ -67,7 +67,7 @@ class Status < ApplicationRecord scope :local_only, -> { left_outer_joins(:account).where(accounts: { domain: nil }) } scope :excluding_silenced_accounts, -> { left_outer_joins(:account).where(accounts: { silenced: false }) } scope :including_silenced_accounts, -> { left_outer_joins(:account).where(accounts: { silenced: true }) } - scope :not_excluded_by_account, ->(account) { where.not(account_id: account.excluded_from_timeline_account_ids) } + scope :not_excluded_by_account, ->(account) { where.not(account_id: account.excluded_from_timeline_account_ids, accounts: { domain: account.excluded_from_timeline_domains }) } cache_associated :account, :application, :media_attachments, :tags, :stream_entry, mentions: :account, reblog: [:account, :application, :stream_entry, :tags, :media_attachments, mentions: :account], thread: :account @@ -284,7 +284,9 @@ class Status < ApplicationRecord end def find_statuses_from_tree_path(ids, account) - statuses = Status.where(id: ids).to_a + statuses = Status.where(id: ids).includes(:account).to_a + + # FIXME: n+1 bonanza statuses.reject! { |status| filter_from_context?(status, account) } # Order ancestors/descendants by tree path @@ -292,6 +294,11 @@ class Status < ApplicationRecord end def filter_from_context?(status, account) - account&.blocking?(status.account_id) || account&.muting?(status.account_id) || (status.account.silenced? && !account&.following?(status.account_id)) || !status.permitted?(account) + should_filter = account&.blocking?(status.account_id) + should_filter ||= account&.domain_blocking?(status.account.domain) + should_filter ||= account&.muting?(status.account_id) + should_filter ||= (status.account.silenced? && !account&.following?(status.account_id)) + should_filter ||= !status.permitted?(account) + should_filter end end |