from pathlib import Path from fastapi import APIRouter, Depends, Form, Request from fastapi.responses import HTMLResponse, RedirectResponse from fastapi.templating import Jinja2Templates from sqlalchemy.orm import Session from app.db.deps import get_db from app.models.document_preset import DocumentPreset router = APIRouter(prefix="/presets", tags=["presets"]) BASE_DIR = Path(__file__).resolve().parent.parent templates = Jinja2Templates(directory=str(BASE_DIR / "templates")) def _parse_people_list(value: str) -> list[str]: return [part.strip() for part in value.split(",") if part.strip()] def _format_people_list(value: list | None) -> str: if not value: return "" return ", ".join(str(x).strip() for x in value if str(x).strip()) def _preset_form_values(preset: DocumentPreset | None = None) -> dict: if preset is None: return { "name": "", "owner_primary": "", "owner_secondary": "", "paid_by_person": "", "covered_people": "", "attendees": "", "occasion_note": "", "is_shared_expense": False, "reimbursement_expected_from": "", "reimbursement_paid_by": "", "reimbursement_paid_to": "", "reimbursement_note": "", } return { "name": preset.name or "", "owner_primary": preset.owner_primary or "", "owner_secondary": preset.owner_secondary or "", "paid_by_person": preset.paid_by_person or "", "covered_people": _format_people_list(preset.covered_people), "attendees": _format_people_list(preset.attendees), "occasion_note": preset.occasion_note or "", "is_shared_expense": bool(preset.is_shared_expense), "reimbursement_expected_from": _format_people_list(preset.reimbursement_expected_from), "reimbursement_paid_by": preset.reimbursement_paid_by or "", "reimbursement_paid_to": preset.reimbursement_paid_to or "", "reimbursement_note": preset.reimbursement_note or "", } @router.get("/", response_class=HTMLResponse) def list_presets(request: Request, edit_id: int | None = None, db: Session = Depends(get_db)): presets = db.query(DocumentPreset).order_by(DocumentPreset.name.asc()).all() editing = None if edit_id is not None: editing = db.query(DocumentPreset).filter(DocumentPreset.id == edit_id).first() return templates.TemplateResponse( request=request, name="presets/index.html", context={ "request": request, "presets": presets, "editing": editing, "form_values": _preset_form_values(editing), "active_page": "presets", }, ) @router.post("/create", response_class=RedirectResponse) def create_preset( name: str = Form(...), owner_primary: str = Form(""), owner_secondary: str = Form(""), paid_by_person: str = Form(""), covered_people: str = Form(""), attendees: str = Form(""), occasion_note: str = Form(""), is_shared_expense: str | None = Form(None), reimbursement_expected_from: str = Form(""), reimbursement_paid_by: str = Form(""), reimbursement_paid_to: str = Form(""), reimbursement_note: str = Form(""), db: Session = Depends(get_db), ): preset = DocumentPreset( name=name.strip(), owner_primary=owner_primary.strip() or None, owner_secondary=owner_secondary.strip() or None, paid_by_person=paid_by_person.strip() or None, covered_people=_parse_people_list(covered_people), attendees=_parse_people_list(attendees), occasion_note=occasion_note.strip() or None, is_shared_expense=bool(is_shared_expense), reimbursement_expected_from=_parse_people_list(reimbursement_expected_from), reimbursement_paid_by=reimbursement_paid_by.strip() or None, reimbursement_paid_to=reimbursement_paid_to.strip() or None, reimbursement_note=reimbursement_note.strip() or None, ) db.add(preset) db.commit() return RedirectResponse(url="/presets/", status_code=303) @router.post("/{preset_id}/update", response_class=RedirectResponse) def update_preset( preset_id: int, name: str = Form(...), owner_primary: str = Form(""), owner_secondary: str = Form(""), paid_by_person: str = Form(""), covered_people: str = Form(""), attendees: str = Form(""), occasion_note: str = Form(""), is_shared_expense: str | None = Form(None), reimbursement_expected_from: str = Form(""), reimbursement_paid_by: str = Form(""), reimbursement_paid_to: str = Form(""), reimbursement_note: str = Form(""), db: Session = Depends(get_db), ): preset = db.query(DocumentPreset).filter(DocumentPreset.id == preset_id).first() if preset is None: return RedirectResponse(url="/presets/", status_code=303) preset.name = name.strip() preset.owner_primary = owner_primary.strip() or None preset.owner_secondary = owner_secondary.strip() or None preset.paid_by_person = paid_by_person.strip() or None preset.covered_people = _parse_people_list(covered_people) preset.attendees = _parse_people_list(attendees) preset.occasion_note = occasion_note.strip() or None preset.is_shared_expense = bool(is_shared_expense) preset.reimbursement_expected_from = _parse_people_list(reimbursement_expected_from) preset.reimbursement_paid_by = reimbursement_paid_by.strip() or None preset.reimbursement_paid_to = reimbursement_paid_to.strip() or None preset.reimbursement_note = reimbursement_note.strip() or None db.commit() return RedirectResponse(url="/presets/", status_code=303) @router.post("/{preset_id}/delete", response_class=RedirectResponse) def delete_preset(preset_id: int, db: Session = Depends(get_db)): preset = db.query(DocumentPreset).filter(DocumentPreset.id == preset_id).first() if preset is not None: db.delete(preset) db.commit() return RedirectResponse(url="/presets/", status_code=303)