mirror of
https://github.com/Freika/dawarich.git
synced 2026-01-10 01:01:39 -05:00
153 lines
4.9 KiB
Ruby
153 lines
4.9 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
class Users::ImportData::Imports
|
|
def initialize(user, imports_data, files_directory)
|
|
@user = user
|
|
@imports_data = imports_data
|
|
@files_directory = files_directory
|
|
end
|
|
|
|
def call
|
|
return [0, 0] unless imports_data.is_a?(Array)
|
|
|
|
Rails.logger.info "Importing #{imports_data.size} imports for user: #{user.email}"
|
|
|
|
imports_created = 0
|
|
files_restored = 0
|
|
|
|
# Preload existing imports to avoid N+1 queries
|
|
@existing_imports_cache = load_existing_imports
|
|
|
|
imports_data.each do |import_data|
|
|
next unless import_data.is_a?(Hash)
|
|
|
|
# Normalize created_at for consistent cache key lookup
|
|
created_at_normalized = normalize_created_at(import_data['created_at'])
|
|
cache_key = import_cache_key(import_data['name'], import_data['source'], created_at_normalized)
|
|
existing_import = @existing_imports_cache[cache_key]
|
|
|
|
if existing_import
|
|
Rails.logger.debug "Import already exists: #{import_data['name']}"
|
|
next
|
|
end
|
|
|
|
import_record = create_import_record(import_data)
|
|
next unless import_record # Skip if creation failed
|
|
|
|
imports_created += 1
|
|
|
|
files_restored += 1 if import_data['file_name'] && restore_import_file(import_record, import_data)
|
|
end
|
|
|
|
Rails.logger.info "Imports import completed. Created: #{imports_created}, Files restored: #{files_restored}"
|
|
[imports_created, files_restored]
|
|
end
|
|
|
|
private
|
|
|
|
attr_reader :user, :imports_data, :files_directory
|
|
|
|
def load_existing_imports
|
|
# Extract import identifiers from imports_data and normalize created_at
|
|
import_keys = imports_data.select { |id| id.is_a?(Hash) && id['name'].present? && id['source'].present? }
|
|
.map do |id|
|
|
# Normalize created_at to string for consistent comparison
|
|
created_at_normalized = normalize_created_at(id['created_at'])
|
|
{ name: id['name'], source: id['source'], created_at: created_at_normalized }
|
|
end
|
|
|
|
return {} if import_keys.empty?
|
|
|
|
# Build a hash for quick lookup
|
|
cache = {}
|
|
|
|
# Build OR conditions using Arel to fetch all matching imports in a single query
|
|
arel_table = Import.arel_table
|
|
conditions = import_keys.map do |key|
|
|
condition = arel_table[:user_id].eq(user.id)
|
|
.and(arel_table[:name].eq(key[:name]))
|
|
.and(arel_table[:source].eq(key[:source]))
|
|
|
|
# Handle created_at being nil
|
|
if key[:created_at].nil?
|
|
condition.and(arel_table[:created_at].eq(nil))
|
|
else
|
|
# Parse the string back to Time for querying
|
|
condition.and(arel_table[:created_at].eq(Time.zone.parse(key[:created_at])))
|
|
end
|
|
end.reduce { |result, condition| result.or(condition) }
|
|
|
|
# Fetch all matching imports in a single query
|
|
Import.where(conditions).find_each do |import|
|
|
# Normalize created_at from database for cache key
|
|
created_at_normalized = normalize_created_at(import.created_at)
|
|
cache_key = import_cache_key(import.name, import.source, created_at_normalized)
|
|
cache[cache_key] = import
|
|
end
|
|
|
|
cache
|
|
end
|
|
|
|
def normalize_created_at(created_at)
|
|
return nil if created_at.nil?
|
|
|
|
# Convert to string in ISO8601 format for consistent comparison
|
|
time = created_at.is_a?(String) ? Time.zone.parse(created_at) : created_at
|
|
time&.iso8601
|
|
end
|
|
|
|
def import_cache_key(name, source, created_at)
|
|
"#{name}_#{source}_#{created_at}"
|
|
end
|
|
|
|
def create_import_record(import_data)
|
|
import_attributes = prepare_import_attributes(import_data)
|
|
|
|
begin
|
|
import_record = user.imports.build(import_attributes)
|
|
import_record.skip_background_processing = true
|
|
import_record.save!
|
|
Rails.logger.debug "Created import: #{import_record.name}"
|
|
import_record
|
|
rescue ActiveRecord::RecordInvalid => e
|
|
Rails.logger.error "Failed to create import: #{e.message}"
|
|
nil
|
|
end
|
|
end
|
|
|
|
def prepare_import_attributes(import_data)
|
|
import_data.except(
|
|
'file_name',
|
|
'original_filename',
|
|
'file_size',
|
|
'content_type',
|
|
'file_error',
|
|
'updated_at'
|
|
).merge(user: user)
|
|
end
|
|
|
|
def restore_import_file(import_record, import_data)
|
|
file_path = files_directory.join(import_data['file_name'])
|
|
|
|
unless File.exist?(file_path)
|
|
Rails.logger.warn "Import file not found: #{import_data['file_name']}"
|
|
return false
|
|
end
|
|
|
|
begin
|
|
import_record.file.attach(
|
|
io: File.open(file_path),
|
|
filename: import_data['original_filename'] || import_data['file_name'],
|
|
content_type: import_data['content_type'] || 'application/octet-stream'
|
|
)
|
|
|
|
Rails.logger.debug "Restored file for import: #{import_record.name}"
|
|
|
|
true
|
|
rescue StandardError => e
|
|
ExceptionReporter.call(e, 'Import file restoration failed')
|
|
|
|
false
|
|
end
|
|
end
|
|
end
|