Files
planer2/backend/routes.py
2026-07-29 15:19:41 +02:00

211 lines
5.8 KiB
Python

"""Alle API-Routen. Fachlogik wirft ValueError/FileNotFoundError,
hier wird auf 400/404/409 gemappt."""
from fastapi import APIRouter, HTTPException
import agents
import chat
import features
import projekte
import planung
import pruefung
router = APIRouter(prefix="/api")
@router.get("/health")
async def health():
return {"ok": True}
@router.get("/projekte")
async def projekte_liste():
return projekte.liste()
@router.post("/projekte")
async def projekt_anlegen(body: dict):
name = (body.get("name") or "").strip()
try:
projekte.anlegen(name)
except ValueError as e:
raise HTTPException(409 if "existiert" in str(e) else 400, str(e))
return {"name": name}
@router.put("/projekte/{name}")
async def projekt_umbenennen(name: str, body: dict):
neu = (body.get("name") or "").strip()
try:
projekte.umbenennen(name, neu)
except FileNotFoundError as e:
raise HTTPException(404, str(e))
except ValueError as e:
raise HTTPException(409 if "existiert" in str(e) else 400, str(e))
return {"name": neu}
@router.delete("/projekte/{name}")
async def projekt_loeschen(name: str):
try:
projekte.loeschen(name)
except FileNotFoundError as e:
raise HTTPException(404, str(e))
except ValueError as e:
raise HTTPException(400, str(e))
return {"ok": True}
@router.get("/projekte/{name}/features")
async def features_liste(name: str, sicht: str = "planung"):
"""`sicht=uebersicht` liest den Projektstand, sonst die Arbeitskopie.
Ohne laufende Planung sind beide dasselbe Verzeichnis.
"""
try:
return features.liste(name, nur_stand=sicht == "uebersicht")
except (FileNotFoundError, ValueError) as e:
raise HTTPException(404, str(e))
@router.post("/projekte/{name}/features")
async def feature_anlegen(name: str, body: dict):
try:
return features.anlegen(name, body.get("roh") or "")
except FileNotFoundError as e:
raise HTTPException(404, str(e))
except ValueError as e:
raise HTTPException(400, str(e))
@router.put("/projekte/{name}/features/{id}")
async def feature_speichern(name: str, id: str, body: dict):
try:
return features.speichern(name, id, body.get("roh") or "")
except FileNotFoundError as e:
raise HTTPException(404, str(e))
except ValueError as e:
raise HTTPException(400, str(e))
@router.post("/projekte/{name}/pruefung")
async def pruefung_starten(name: str, body: dict | None = None):
art = (body or {}).get("art") or "stil"
try:
return await pruefung.starte(name, art)
except FileNotFoundError as e:
raise HTTPException(404, str(e))
except pruefung.LaeuftBereits as e:
raise HTTPException(409, str(e)) # 409 heißt genau das und sonst nichts
except ValueError as e:
raise HTTPException(400, str(e))
@router.get("/projekte/{name}/pruefung")
async def pruefung_status(name: str):
return pruefung.status(name)
@router.get("/projekte/{name}/planung")
async def planung_stand(name: str):
try:
return planung.stand(name)
except FileNotFoundError as e:
raise HTTPException(404, str(e))
@router.post("/projekte/{name}/planung")
async def planung_starten(name: str):
try:
planung.starte(name)
except FileNotFoundError as e:
raise HTTPException(404, str(e))
except ValueError as e:
raise HTTPException(409, str(e))
return planung.stand(name)
@router.post("/projekte/{name}/planung/umsetzen")
async def planung_umsetzen(name: str):
try:
planung.setze_um(name)
except FileNotFoundError as e:
raise HTTPException(404, str(e))
except ValueError as e:
raise HTTPException(409, str(e))
return {"ok": True}
@router.delete("/projekte/{name}/planung")
async def planung_abbrechen(name: str):
try:
planung.brich_ab(name)
except FileNotFoundError as e:
raise HTTPException(404, str(e))
return {"ok": True}
@router.post("/projekte/{name}/planung/zuruecksetzen")
async def planung_zuruecksetzen(name: str, body: dict):
try:
planung.zuruecksetzen(name, (body or {}).get("titel") or "")
except FileNotFoundError as e:
raise HTTPException(404, str(e))
except ValueError as e:
raise HTTPException(409, str(e))
return planung.stand(name)
@router.delete("/projekte/{name}/pruefung")
async def pruefung_beenden(name: str):
pruefung.beende(name)
return {"ok": True}
@router.delete("/projekte/{name}/features/{id}")
async def feature_loeschen(name: str, id: str):
try:
features.loeschen(name, id)
except (FileNotFoundError, ValueError) as e:
raise HTTPException(404, str(e))
return {"ok": True}
@router.put("/projekte/{name}/features/{id}/projekt")
async def feature_verschieben(name: str, id: str, body: dict):
try:
return features.verschieben(name, id, (body.get("ziel") or "").strip())
except FileNotFoundError as e:
raise HTTPException(404, str(e))
except ValueError as e:
raise HTTPException(400, str(e))
@router.get("/projekte/{name}/chat")
async def chat_verlauf(name: str):
try:
return {"verlauf": chat.verlauf(name)}
except FileNotFoundError as e:
raise HTTPException(404, str(e))
@router.post("/projekte/{name}/chat")
async def chat_frage(name: str, body: dict):
try:
return await chat.frage(name, body.get("text") or "")
except FileNotFoundError as e:
raise HTTPException(404, str(e))
except agents.NichtKonfiguriert as e:
raise HTTPException(400, str(e))
except ValueError as e:
raise HTTPException(400, str(e))
@router.delete("/projekte/{name}/chat")
async def chat_leeren(name: str):
try:
chat.leeren(name)
except FileNotFoundError as e:
raise HTTPException(404, str(e))
return {"ok": True}