nas/app/services/process_references_service.rb
2023-07-06 19:57:42 +09:00

88 lines
2.3 KiB
Ruby

# frozen_string_literal: true
class ProcessReferencesService < BaseService
include Payloadable
DOMAIN = ENV['WEB_DOMAIN'] || ENV.fetch('LOCAL_DOMAIN', nil)
REFURL_EXP = /(RT|QT|BT|RN|RE)((:|;)?\s+|:|;)(#{URI::DEFAULT_PARSER.make_regexp(%w(http https))})/
def call(status, reference_parameters, save_records: true, urls: nil)
@status = status
@reference_parameters = reference_parameters || []
@save_records = save_records
@urls = urls || []
old_references
return unless added_references.size.positive? || removed_references.size.positive?
StatusReference.transaction do
remove_old_references
add_references
@status.save! if @save_records
create_notifications!
end
end
private
def references
@references = @reference_parameters + scan_text!
end
def old_references
@old_references = @status.references.pluck(:id)
end
def added_references
(references - old_references).uniq
end
def removed_references
(old_references - references).uniq
end
def scan_text!
text = @status.account.local? ? @status.text : @status.text.gsub(%r{</?[^>]*>}, '')
@scan_text = fetch_statuses!(text.scan(REFURL_EXP).pluck(3).uniq).map(&:id).uniq.filter { |status_id| !status_id.zero? }
end
def fetch_statuses!(urls)
(urls + @urls)
.map { |url| ResolveURLService.new.call(url) }
.filter { |status| status }
end
def add_references
return if added_references.empty?
@added_objects = []
statuses = Status.where(id: added_references)
statuses.each do |status|
@added_objects << @status.reference_objects.new(target_status: status)
status.increment_count!(:status_referred_by_count)
end
end
def create_notifications!
local_reference_objects = @added_objects.filter { |ref| ref.target_status.account.local? }
return if local_reference_objects.empty?
LocalNotificationWorker.push_bulk(local_reference_objects) do |ref|
[ref.target_status.account_id, ref.id, 'StatusReference', 'status_reference']
end
end
def remove_old_references
return if removed_references.empty?
statuses = Status.where(id: removed_references)
@status.reference_objects.where(target_status: statuses).destroy_all
statuses.each do |status|
status.decrement_count!(:status_referred_by_count)
end
end
end