From ecb8e6657c9aca9fd8a1cf9be759e80afa3df57c Mon Sep 17 00:00:00 2001 From: Joshua Laymon Date: Fri, 22 Aug 2025 03:00:03 +0000 Subject: [PATCH] Update web/core/views.py --- web/core/views.py | 133 ++++++++++++++++++++-------------------------- 1 file changed, 59 insertions(+), 74 deletions(-) diff --git a/web/core/views.py b/web/core/views.py index 07196f1..130dcfe 100644 --- a/web/core/views.py +++ b/web/core/views.py @@ -329,92 +329,77 @@ def entry_delete(request, entry_id): @login_required @user_passes_test(is_admin) def import_wizard(request): - # Safety: use global EXPECTED_HEADERS if present; otherwise fall back locally - _EXPECTED_HEADERS = globals().get("EXPECTED_HEADERS", [ - "Subject", - "Illustration", - "Application", - "Scripture", - "Source", - "Talk Title", - "Talk Number", - "Code", - "Date", - "Date Edited", - ]) + # Safety: expected header list + _EXPECTED_HEADERS = [ + "Subject", "Illustration", "Application", "Scripture", "Source", + "Talk Title", "Talk Number", "Code", "Date", "Date Edited", + ] if request.method == "POST": - form = ImportForm(request.POST, request.FILES) + form = ImportForm(request.POST, request.FILES) if form.is_valid(): - try: - raw = form.cleaned_data["file"].read() - - # --- super‑defensive header peek (never raises) --- - import io, csv as _csv - sio = io.StringIO(raw.decode("utf-8-sig", errors="replace")) - - header_ok = False try: - rdr = _csv.reader(sio) - first_row = next(rdr, []) + raw = form.cleaned_data["file"].read() - def _clean(s): - s = "" if s is None else str(s) - # strip quotes and odd prefixes like r:"Talk Title" - s = s.strip().strip("'").strip('"') - if s.lower().startswith("r:"): - s = s[2:].lstrip() - return s.strip().lower() + # --- super-defensive header peek (never raises) --- + import io, csv as _csv + sio = io.StringIO(raw.decode("utf-8-sig", errors="replace")) - norm = [_clean(c) for c in first_row] - - # Pull expected headers from globals if defined, else use defaults - expected = ( - globals().get("_EXPECTED_HEADERS") - or globals().get("EXPECTED_HEADERS") - or [ - "Subject", "Illustration", "Application", "Scripture", "Source", - "Talk Title", "Talk Number", "Code", "Date", "Date Edited", - ] - ) - expected_norm = [h.strip().lower() for h in expected] - header_ok = (norm == expected_norm) - except Exception: header_ok = False - finally: - # Rewind so the real importer reads the full file - sio.seek(0) + try: + rdr = _csv.reader(sio) + first_row = next(rdr, []) - # Make sure the utils module also knows the expected headers - from . import utils as core_utils - if not hasattr(core_utils, "EXPECTED_HEADERS"): - core_utils.EXPECTED_HEADERS = expected + def _clean(s): + s = "" if s is None else str(s) + # strip quotes and odd prefixes like r:"Talk Title" + s = s.strip().strip("'").strip('"') + if s.lower().startswith("r:"): + s = s[2:].lstrip() + return s.strip().lower() - # Hand off to your robust importer - report = import_csv_bytes( - raw, - dry_run=form.cleaned_data["dry_run"], - ) + norm = [_clean(c) for c in first_row] - # Attach header check info for the result template - report = report or {} - report["header_ok"] = header_ok - if not header_ok: - messages.warning( - request, - "The first row does not match the expected header; assuming the file has no header." + expected = [h.strip().lower() for h in _EXPECTED_HEADERS] + header_ok = (norm == expected) + except Exception: + header_ok = False + finally: + # Rewind so the real importer reads the full file + sio.seek(0) + + # Make sure utils knows the expected headers + from . import utils as core_utils + if not hasattr(core_utils, "EXPECTED_HEADERS"): + core_utils.EXPECTED_HEADERS = _EXPECTED_HEADERS + + # Hand off to your robust importer + report = import_csv_bytes( + raw, + dry_run=form.cleaned_data["dry_run"], ) - return render( - request, - "import_result.html", - {"report": report, "dry_run": form.cleaned_data["dry_run"]}, - ) - except Exception as e: - messages.error(request, f"Import failed: {e}") -else: - form = ImportForm() -return render(request, "import_wizard.html", {"form": form}) + # Attach header check info + report = report or {} + report["header_ok"] = header_ok + if not header_ok: + messages.warning( + request, + "The first row does not match the expected header; assuming the file has no header." + ) + + return render( + request, + "import_result.html", + {"report": report, "dry_run": form.cleaned_data["dry_run"]}, + ) + except Exception as e: + messages.error(request, f"Import failed: {e}") + else: + form = ImportForm() + + # 👇 stays inside the function + return render(request, "import_wizard.html", {"form": form}) @login_required