class DataImportsController < ApplicationController before_action :require_admin! before_action :set_data_import, only: [:show, :destroy, :progress] def index @data_imports = DataImport.all # Apply filters @data_imports = @data_imports.where(import_type: params[:import_type]) if params[:import_type].present? @data_imports = @data_imports.where(status: params[:status]) if params[:status].present? @data_imports = @data_imports.where("filename ILIKE ?", "%#{params[:filename]}%") if params[:filename].present? @pagy, @data_imports = pagy(@data_imports.order(created_at: :desc)) end def new @data_import = DataImport.new end def create # Save uploaded file and queue import job uploaded_file = params[:data_import][:file] if uploaded_file.nil? @data_import = DataImport.new flash.now[:alert] = "Please select a file to import" render :new, status: :unprocessable_entity return end # Validate file type unless valid_file?(uploaded_file) @data_import = DataImport.new flash.now[:alert] = "Invalid file type. Please upload a .csv or .zip file." render :new, status: :unprocessable_entity return end # Determine import type based on filename import_type = detect_import_type_from_filename(uploaded_file.original_filename) # Create the DataImport record with the attached file @data_import = DataImport.create!( import_type: import_type, filename: uploaded_file.original_filename, status: 'pending' ) # Attach the file using Active Storage @data_import.file.attach(uploaded_file) # Queue appropriate import job - pass the entire DataImport object if import_type == 'asn' GeoliteAsnImportJob.perform_later(@data_import) else GeoliteCountryImportJob.perform_later(@data_import) end redirect_to @data_import, notice: "Import has been queued and will begin processing shortly." rescue => e Rails.logger.error "Error creating import: #{e.message}" Rails.logger.error e.backtrace.join("\n") @data_import = DataImport.new if @data_import.nil? flash.now[:alert] = "Error processing file: #{e.message}" render :new, status: :unprocessable_entity end def show # Show will display import details and progress end def progress # JSON endpoint for real-time progress updates render json: { id: @data_import.id, status: @data_import.status, progress_percentage: @data_import.progress_percentage, processed_records: @data_import.processed_records, total_records: @data_import.total_records, failed_records: @data_import.failed_records, duration: @data_import.duration, records_per_second: @data_import.records_per_second, import_stats: @data_import.import_stats, error_message: @data_import.error_message, started_at: @data_import.started_at, completed_at: @data_import.completed_at } end def destroy if @data_import.processing? redirect_to @data_import, alert: "Cannot delete an import that is currently processing." else @data_import.destroy redirect_to data_imports_path, notice: "Import was successfully deleted." end end private def set_data_import @data_import = DataImport.find(params[:id]) end def data_import_params # No parameters needed since we detect everything automatically {} end def valid_file?(uploaded_file) return false unless uploaded_file.respond_to?(:original_filename) filename = uploaded_file.original_filename.downcase filename.end_with?('.csv', '.zip') end def detect_import_type_from_filename(filename) # Try to detect based on filename first if filename.downcase.include?('asn') 'asn' elsif filename.downcase.include?('country') 'country' else 'country' # Default fallback end end def require_admin! redirect_to root_path, alert: "Access denied. Admin privileges required." unless current_user&.admin? end end