You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
130 lines
3.9 KiB
130 lines
3.9 KiB
# frozen_string_literal: true |
|
# == Schema Information |
|
# |
|
# Table name: account_conversations |
|
# |
|
# id :bigint(8) not null, primary key |
|
# account_id :bigint(8) |
|
# conversation_id :bigint(8) |
|
# participant_account_ids :bigint(8) default([]), not null, is an Array |
|
# status_ids :bigint(8) default([]), not null, is an Array |
|
# last_status_id :bigint(8) |
|
# lock_version :integer default(0), not null |
|
# unread :boolean default(FALSE), not null |
|
# |
|
|
|
class AccountConversation < ApplicationRecord |
|
include Redisable |
|
|
|
attr_writer :participant_accounts |
|
|
|
before_validation :set_last_status |
|
after_commit :push_to_streaming_api |
|
|
|
belongs_to :account |
|
belongs_to :conversation |
|
belongs_to :last_status, class_name: 'Status' |
|
|
|
def participant_account_ids=(arr) |
|
self[:participant_account_ids] = arr.sort |
|
@participant_accounts = nil |
|
end |
|
|
|
def participant_accounts |
|
@participant_accounts ||= Account.where(id: participant_account_ids).to_a |
|
@participant_accounts.presence || [account] |
|
end |
|
|
|
class << self |
|
def to_a_paginated_by_id(limit, options = {}) |
|
array = begin |
|
if options[:min_id] |
|
paginate_by_min_id(limit, options[:min_id], options[:max_id]).reverse |
|
else |
|
paginate_by_max_id(limit, options[:max_id], options[:since_id]).to_a |
|
end |
|
end |
|
|
|
# Preload participants |
|
participant_ids = array.flat_map(&:participant_account_ids) |
|
accounts_by_id = Account.where(id: participant_ids).index_by(&:id) |
|
|
|
array.each do |conversation| |
|
conversation.participant_accounts = conversation.participant_account_ids.filter_map { |id| accounts_by_id[id] } |
|
end |
|
|
|
array |
|
end |
|
|
|
def paginate_by_min_id(limit, min_id = nil, max_id = nil) |
|
query = order(arel_table[:last_status_id].asc).limit(limit) |
|
query = query.where(arel_table[:last_status_id].gt(min_id)) if min_id.present? |
|
query = query.where(arel_table[:last_status_id].lt(max_id)) if max_id.present? |
|
query |
|
end |
|
|
|
def paginate_by_max_id(limit, max_id = nil, since_id = nil) |
|
query = order(arel_table[:last_status_id].desc).limit(limit) |
|
query = query.where(arel_table[:last_status_id].lt(max_id)) if max_id.present? |
|
query = query.where(arel_table[:last_status_id].gt(since_id)) if since_id.present? |
|
query |
|
end |
|
|
|
def add_status(recipient, status) |
|
conversation = find_or_initialize_by(account: recipient, conversation_id: status.conversation_id, participant_account_ids: participants_from_status(recipient, status)) |
|
|
|
return conversation if conversation.status_ids.include?(status.id) |
|
|
|
conversation.status_ids << status.id |
|
conversation.unread = status.account_id != recipient.id |
|
conversation.save |
|
conversation |
|
rescue ActiveRecord::StaleObjectError |
|
retry |
|
end |
|
|
|
def remove_status(recipient, status) |
|
conversation = find_by(account: recipient, conversation_id: status.conversation_id, participant_account_ids: participants_from_status(recipient, status)) |
|
|
|
return if conversation.nil? |
|
|
|
conversation.status_ids.delete(status.id) |
|
|
|
if conversation.status_ids.empty? |
|
conversation.destroy |
|
else |
|
conversation.save |
|
end |
|
|
|
conversation |
|
rescue ActiveRecord::StaleObjectError |
|
retry |
|
end |
|
|
|
private |
|
|
|
def participants_from_status(recipient, status) |
|
((status.active_mentions.pluck(:account_id) + [status.account_id]).uniq - [recipient.id]).sort |
|
end |
|
end |
|
|
|
private |
|
|
|
def set_last_status |
|
self.status_ids = status_ids.sort |
|
self.last_status_id = status_ids.last |
|
end |
|
|
|
def push_to_streaming_api |
|
return if destroyed? || !subscribed_to_timeline? |
|
PushConversationWorker.perform_async(id) |
|
end |
|
|
|
def subscribed_to_timeline? |
|
redis.exists?("subscribed:#{streaming_channel}") |
|
end |
|
|
|
def streaming_channel |
|
"timeline:direct:#{account_id}" |
|
end |
|
end
|
|
|