"""Shared API helpers: DB dependency, serialization, filename sanitization.""" from __future__ import annotations import json import re from datetime import date, datetime from fastapi import Depends, HTTPException from sqlalchemy.orm import Session as OrmSession from ..db.database import get_db from ..db import models def db_dep() -> OrmSession: # thin alias so routes read cleanly yield from get_db() def get_session_or_404(session_id: int, db: OrmSession) -> models.Session: s = db.get(models.Session, session_id) if s is None: raise HTTPException(status_code=404, detail=f"Session {session_id} not found") return s _SAFE = re.compile(r"[^A-Za-z0-9 ._,()\-]+") def sanitize_filename(name: str) -> str: name = name.replace("\\", "/").split("/")[-1] # strip any path name = _SAFE.sub("_", name).strip() or "upload.xlsx" return name[:200] def to_dict(obj, fields: list[str]) -> dict: out = {} for f in fields: v = getattr(obj, f, None) if isinstance(v, (date, datetime)): v = v.isoformat() out[f] = v return out def session_dict(s: models.Session) -> dict: d = to_dict(s, [ "id", "name", "reporting_month", "month_end_date", "reporting_currency", "clearing_lag_days", "rounding_tolerance", "allowance_for_returns", "manual_adjustment", "manual_adjustment_note", "status", "progress_stage", "progress_pct", "progress_rows_done", "progress_rows_total", "eta_seconds", "opening_mode", "opening_source_session_id", "error", "created_at", "updated_at", ]) return d def file_dict(f: models.SessionFile) -> dict: d = to_dict(f, [ "id", "filename", "size_bytes", "sha256", "data_sheet", "imported_rows", "min_date", "max_date", "currency", "marketplace", "status", "message", ]) try: d["worksheets"] = json.loads(f.worksheets) if f.worksheets else [] except Exception: d["worksheets"] = [] return d