from flask import Blueprint, request, render_template, redirect, session, flash from definitions.models import Asset, db from functions.process_csv import get_csv_data from functions.validate_values import validate_values from config import item_attributes from functions.auth import login_required from config import BrandingConfig upload_bp = Blueprint('uploadcsv', __name__) def _process_csv_file(file, mode): """ Helper function to process CSV file and separate entries based on mode. mode: 'import' or 'edit' """ # Extract CSV data csvdata = get_csv_data(file) # Validate each row of data errors = [] for i, row in enumerate(csvdata, start=1): error = validate_values(row) if error: errors.append(f"Row {i}: {error}") if errors: return None, errors # Separate entries based on mode primary_attrib = next((attrib for attrib in item_attributes if attrib.primary), None) if not primary_attrib: return None, ["Primary attribute not defined in configuration."] new_entries = [] existing_entries = [] invalid_entries = [] for row in csvdata: primary_value = row[primary_attrib.attrib_name] asset_exists = Asset.query.filter_by(**{primary_attrib.attrib_name: primary_value}).first() if mode == 'import': if asset_exists: invalid_entries.append(row) # Existing entries are invalid for import else: new_entries.append(row) elif mode == 'edit': if asset_exists: existing_entries.append(row) # Existing entries are valid for edit else: invalid_entries.append(row) # Non-existing entries are invalid for edit return { 'new_entries': new_entries, 'existing_entries': existing_entries, 'invalid_entries': invalid_entries }, None @upload_bp.route('/import_from_csv/', methods=['GET', 'POST']) @login_required def import_from_csv(): session['csv_mode'] = 'import' # Store mode in session if request.method == 'POST': # Check if a file was uploaded if 'file' not in request.files: flash("No file uploaded.", "error") return redirect(request.url) file = request.files['file'] # Check if the file is a CSV if file.filename == '' or not file.filename.endswith('.csv'): flash("Please upload a valid CSV file.", "error") return redirect(request.url) # Process the CSV file result, errors = _process_csv_file(file, mode='import') if errors: for error in errors: flash(error, "error") return redirect(request.url) # Store entries in session for further processing session['new_entries'] = result['new_entries'] session['invalid_entries'] = result['invalid_entries'] # Redirect to preview page return render_template( 'csv_preview.html', mode='import', new_entries=result['new_entries'], invalid_entries=result['invalid_entries'], item_attributes=item_attributes, brandingconfig=BrandingConfig ) # Render the upload page for GET requests return render_template('upload.html', mode="import", brandingconfig=BrandingConfig) @upload_bp.route('/edit_using_csv/', methods=['GET', 'POST']) @login_required def edit_using_csv(): session['csv_mode'] = 'edit' # Store mode in session if request.method == 'POST': # Check if a file was uploaded if 'file' not in request.files: flash("No file uploaded.", "error") return redirect(request.url) file = request.files['file'] # Check if the file is a CSV if file.filename == '' or not file.filename.endswith('.csv'): flash("Please upload a valid CSV file.", "error") return redirect(request.url) # Process the CSV file result, errors = _process_csv_file(file, mode='edit') if errors: for error in errors: flash(error, "error") return redirect(request.url) # Store entries in session for further processing session['existing_entries'] = result['existing_entries'] session['invalid_entries'] = result['invalid_entries'] # Redirect to preview page return render_template( 'csv_preview.html', mode='edit', existing_entries=result['existing_entries'], invalid_entries=result['invalid_entries'], item_attributes=item_attributes, brandingconfig=BrandingConfig ) # Render the upload page for GET requests return render_template('upload.html', mode="edit", brandingconfig=BrandingConfig)