- # frozen_string_literal: true
-
- module AccountInteractions
- extend ActiveSupport::Concern
-
- class_methods do
- def following_map(target_account_ids, account_id)
- Follow.where(target_account_id: target_account_ids, account_id: account_id).each_with_object({}) do |follow, mapping|
- mapping[follow.target_account_id] = {
- reblogs: follow.show_reblogs?,
- }
- end
- 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 blocked_by_map(target_account_ids, account_id)
- follow_mapping(Block.where(account_id: target_account_ids, target_account_id: account_id), :account_id)
- end
-
- def muting_map(target_account_ids, account_id)
- Mute.where(target_account_id: target_account_ids, account_id: account_id).each_with_object({}) do |mute, mapping|
- mapping[mute.target_account_id] = {
- notifications: mute.hide_notifications?,
- }
- end
- end
-
- def requested_map(target_account_ids, account_id)
- FollowRequest.where(target_account_id: target_account_ids, account_id: account_id).each_with_object({}) do |follow_request, mapping|
- mapping[follow_request.target_account_id] = {
- reblogs: follow_request.show_reblogs?,
- }
- end
- end
-
- def domain_blocking_map(target_account_ids, account_id)
- accounts_map = Account.where(id: target_account_ids).select('id, domain').map { |a| [a.id, a.domain] }.to_h
- blocked_domains = domain_blocking_map_by_domain(accounts_map.values.compact, account_id)
- accounts_map.map { |id, domain| [id, blocked_domains[domain]] }.to_h
- end
-
- def domain_blocking_map_by_domain(target_domains, account_id)
- follow_mapping(AccountDomainBlock.where(account_id: account_id, domain: target_domains), :domain)
- end
-
- private
-
- def follow_mapping(query, field)
- query.pluck(field).each_with_object({}) { |id, mapping| mapping[id] = true }
- 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 :muted_by_relationships, class_name: 'Mute', foreign_key: :target_account_id, dependent: :destroy
- has_many :muted_by, -> { order('mutes.id desc') }, through: :muted_by_relationships, source: :account
- has_many :conversation_mutes, dependent: :destroy
- has_many :domain_blocks, class_name: 'AccountDomainBlock', dependent: :destroy
- end
-
- def follow!(other_account, reblogs: nil)
- reblogs = true if reblogs.nil?
- rel = active_relationships.create_with(show_reblogs: reblogs).find_or_create_by!(target_account: other_account)
- rel.update!(show_reblogs: reblogs)
-
- rel
- end
-
- def block!(other_account)
- block_relationships.find_or_create_by!(target_account: other_account)
- end
-
- def mute!(other_account, notifications: nil)
- notifications = true if notifications.nil?
- mute = mute_relationships.create_with(hide_notifications: notifications).find_or_create_by!(target_account: other_account)
- # When toggling a mute between hiding and allowing notifications, the mute will already exist, so the find_or_create_by! call will return the existing Mute without updating the hide_notifications attribute. Therefore, we check that hide_notifications? is what we want and set it if it isn't.
- if mute.hide_notifications? != notifications
- mute.update!(hide_notifications: notifications)
- end
- mute
- 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 muting_notifications?(other_account)
- mute_relationships.where(target_account: other_account, hide_notifications: true).exists?
- end
-
- def muting_reblogs?(other_account)
- active_relationships.where(target_account: other_account, show_reblogs: false).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 bookmarked?(status)
- status.proper.bookmarks.where(account: self).exists?
- end
-
- def reblogged?(status)
- status.proper.reblogs.where(account: self).exists?
- end
-
- def pinned?(status)
- status_pins.where(status: status).exists?
- end
- end
|