Files
2026-07-06 19:25:38 +02:00

145 lines
4.3 KiB
Python

from fastapi import APIRouter, Depends, HTTPException, Query
from sqlalchemy import text
from sqlalchemy.orm import Session
from typing import Any
from app.database import get_session
from app.auth import get_current_user
router = APIRouter()
def _row(r) -> dict:
return dict(r._mapping)
@router.get("")
def list_checklists(
session: Session = Depends(get_session),
_: str = Depends(get_current_user),
) -> list[dict]:
rows = session.execute(text("SELECT * FROM checklists ORDER BY name")).fetchall()
return [_row(r) for r in rows]
@router.post("", status_code=201)
def create_checklist(
body: dict[str, Any],
session: Session = Depends(get_session),
_: str = Depends(get_current_user),
) -> dict:
row = session.execute(text("""
INSERT INTO checklists (name, scope) VALUES (:name, :scope) RETURNING *
"""), {"name": body.get("name"), "scope": body.get("scope", "colony")}).fetchone()
session.commit()
return _row(row)
@router.delete("/{id}", status_code=204)
def delete_checklist(
id: int,
session: Session = Depends(get_session),
_: str = Depends(get_current_user),
):
session.execute(text("DELETE FROM checklists WHERE id = :id"), {"id": id})
session.commit()
@router.get("/{id}/items")
def list_items(
id: int,
session: Session = Depends(get_session),
_: str = Depends(get_current_user),
) -> list[dict]:
rows = session.execute(text("""
SELECT * FROM checklist_items WHERE checklist_id = :id ORDER BY position
"""), {"id": id}).fetchall()
return [_row(r) for r in rows]
@router.post("/{id}/items", status_code=201)
def create_item(
id: int,
body: dict[str, Any],
session: Session = Depends(get_session),
_: str = Depends(get_current_user),
) -> dict:
row = session.execute(text("""
INSERT INTO checklist_items (checklist_id, text, position)
VALUES (:checklist_id, :text, :position) RETURNING *
"""), {
"checklist_id": id,
"text": body.get("text"),
"position": body.get("position", 0),
}).fetchone()
session.commit()
return _row(row)
@router.delete("/items/{item_id}", status_code=204)
def delete_item(
item_id: int,
session: Session = Depends(get_session),
_: str = Depends(get_current_user),
):
session.execute(text("DELETE FROM checklist_items WHERE id = :id"), {"id": item_id})
session.commit()
@router.get("/{id}/completions")
def list_completions(
id: int,
scope_id: int = Query(...),
session: Session = Depends(get_session),
_: str = Depends(get_current_user),
) -> list[dict]:
rows = session.execute(text("""
SELECT cc.*, ci.text, ci.position
FROM checklist_completions cc
JOIN checklist_items ci ON ci.id = cc.item_id
WHERE cc.checklist_id = :checklist_id AND cc.scope_id = :scope_id
ORDER BY ci.position
"""), {"checklist_id": id, "scope_id": scope_id}).fetchall()
return [_row(r) for r in rows]
@router.post("/{id}/completions/toggle")
def toggle_completion(
id: int,
body: dict[str, Any],
session: Session = Depends(get_session),
_: str = Depends(get_current_user),
) -> dict:
item_id = body.get("item_id")
scope_id = body.get("scope_id")
date = body.get("date")
completed_by = body.get("completed_by")
notes = body.get("notes")
existing = session.execute(text("""
SELECT id FROM checklist_completions
WHERE checklist_id = :checklist_id AND item_id = :item_id AND scope_id = :scope_id
"""), {"checklist_id": id, "item_id": item_id, "scope_id": scope_id}).fetchone()
if existing is not None:
session.execute(
text("DELETE FROM checklist_completions WHERE id = :id"),
{"id": existing._mapping["id"]},
)
session.commit()
return {"toggled": False}
else:
session.execute(text("""
INSERT INTO checklist_completions (checklist_id, item_id, scope_id, date, completed_by, notes)
VALUES (:checklist_id, :item_id, :scope_id, :date, :completed_by, :notes)
"""), {
"checklist_id": id,
"item_id": item_id,
"scope_id": scope_id,
"date": date,
"completed_by": completed_by,
"notes": notes,
})
session.commit()
return {"toggled": True}