class Account::Import < ApplicationRecord broadcasts_refreshes belongs_to :account belongs_to :identity has_one_attached :file, dependent: :purge_later enum :status, %w[ pending processing completed failed ].index_by(&:itself), default: :pending enum :failure_reason, %w[ conflict invalid_export ].index_by(&:itself), prefix: :failed_due_to, scopes: false scope :expired, -> { where(completed_at: ...24.hours.ago).or(where(status: :failed, created_at: ...7.days.ago)) } def self.cleanup expired.each(&:cleanup) end def process_later Account::DataImportJob.perform_later(self) end def check(start: nil, callback: nil) processing! ZipFile.read_from(file.blob) do |zip| Account::DataTransfer::Manifest.new(account).each_record_set(start: start) do |record_set, last_id| record_set.check(from: zip, start: last_id, callback: callback) end end rescue Account::DataTransfer::RecordSet::ConflictError => e mark_as_failed(:conflict) raise e rescue Account::DataTransfer::RecordSet::IntegrityError, ZipFile::InvalidFileError => e mark_as_failed(:invalid_export) raise e rescue => e mark_as_failed raise e end def process(start: nil, callback: nil) processing! ZipFile.read_from(file.blob) do |zip| Account::DataTransfer::Manifest.new(account).each_record_set(start: start) do |record_set, last_id| record_set.import(from: zip, start: last_id, callback: callback) end end add_importer_to_all_access_boards reconcile_cards_count reconcile_account_storage mark_completed rescue Account::DataTransfer::RecordSet::ConflictError => e mark_as_failed(:conflict) raise e rescue Account::DataTransfer::RecordSet::IntegrityError, ZipFile::InvalidFileError => e mark_as_failed(:invalid_export) raise e rescue => e mark_as_failed raise e end def cleanup destroy account.destroy if failed? end private def mark_completed update!(status: :completed, completed_at: Time.current) ImportMailer.completed(identity, account).deliver_later end def mark_as_failed(failure_reason = nil) update!(status: :failed, failure_reason: failure_reason) ImportMailer.failed(self).deliver_later end def reconcile_cards_count account.update_column :cards_count, [ account.cards_count, account.cards.maximum(:number).to_i ].max end def add_importer_to_all_access_boards importer = account.users.find_by!(identity: identity) account.boards.all_access.find_each do |board| board.accesses.grant_to(importer) end end def reconcile_account_storage account.boards.each(&:reconcile_storage) account.reconcile_storage account.materialize_storage end end