Update web/core/views.py

This commit is contained in:
Joshua Laymon 2025-08-22 03:00:03 +00:00
parent 8fbc0c5e29
commit ecb8e6657c

View File

@ -329,92 +329,77 @@ def entry_delete(request, entry_id):
@login_required @login_required
@user_passes_test(is_admin) @user_passes_test(is_admin)
def import_wizard(request): def import_wizard(request):
# Safety: use global EXPECTED_HEADERS if present; otherwise fall back locally # Safety: expected header list
_EXPECTED_HEADERS = globals().get("EXPECTED_HEADERS", [ _EXPECTED_HEADERS = [
"Subject", "Subject", "Illustration", "Application", "Scripture", "Source",
"Illustration", "Talk Title", "Talk Number", "Code", "Date", "Date Edited",
"Application", ]
"Scripture",
"Source",
"Talk Title",
"Talk Number",
"Code",
"Date",
"Date Edited",
])
if request.method == "POST": if request.method == "POST":
form = ImportForm(request.POST, request.FILES) form = ImportForm(request.POST, request.FILES)
if form.is_valid(): if form.is_valid():
try:
raw = form.cleaned_data["file"].read()
# --- superdefensive header peek (never raises) ---
import io, csv as _csv
sio = io.StringIO(raw.decode("utf-8-sig", errors="replace"))
header_ok = False
try: try:
rdr = _csv.reader(sio) raw = form.cleaned_data["file"].read()
first_row = next(rdr, [])
def _clean(s): # --- super-defensive header peek (never raises) ---
s = "" if s is None else str(s) import io, csv as _csv
# strip quotes and odd prefixes like r:"Talk Title" sio = io.StringIO(raw.decode("utf-8-sig", errors="replace"))
s = s.strip().strip("'").strip('"')
if s.lower().startswith("r:"):
s = s[2:].lstrip()
return s.strip().lower()
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 header_ok = False
finally: try:
# Rewind so the real importer reads the full file rdr = _csv.reader(sio)
sio.seek(0) first_row = next(rdr, [])
# Make sure the utils module also knows the expected headers def _clean(s):
from . import utils as core_utils s = "" if s is None else str(s)
if not hasattr(core_utils, "EXPECTED_HEADERS"): # strip quotes and odd prefixes like r:"Talk Title"
core_utils.EXPECTED_HEADERS = expected s = s.strip().strip("'").strip('"')
if s.lower().startswith("r:"):
s = s[2:].lstrip()
return s.strip().lower()
# Hand off to your robust importer norm = [_clean(c) for c in first_row]
report = import_csv_bytes(
raw,
dry_run=form.cleaned_data["dry_run"],
)
# Attach header check info for the result template expected = [h.strip().lower() for h in _EXPECTED_HEADERS]
report = report or {} header_ok = (norm == expected)
report["header_ok"] = header_ok except Exception:
if not header_ok: header_ok = False
messages.warning( finally:
request, # Rewind so the real importer reads the full file
"The first row does not match the expected header; assuming the file has no header." 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( # Attach header check info
request, report = report or {}
"import_result.html", report["header_ok"] = header_ok
{"report": report, "dry_run": form.cleaned_data["dry_run"]}, if not header_ok:
) messages.warning(
except Exception as e: request,
messages.error(request, f"Import failed: {e}") "The first row does not match the expected header; assuming the file has no header."
else: )
form = ImportForm()
return render(request, "import_wizard.html", {"form": form}) 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 @login_required