Files
aza/AzA march 2026/empfang_routes.py
2026-04-19 20:41:37 +02:00

217 lines
6.6 KiB
Python

# -*- coding: utf-8 -*-
"""
AZA Empfang - Backend-Routen fuer Empfangs-/Rezeptionsnachrichten.
V2: Thread-Support fuer echten bidirektionalen Chat.
"""
import json
import os
import time
import uuid
from pathlib import Path
from fastapi import APIRouter, HTTPException, Request
from fastapi.responses import HTMLResponse, JSONResponse
from pydantic import BaseModel, Field
router = APIRouter()
_DATA_DIR = Path(__file__).resolve().parent / "data"
_EMPFANG_FILE = _DATA_DIR / "empfang_nachrichten.json"
def _ensure_data_dir():
_DATA_DIR.mkdir(parents=True, exist_ok=True)
def _load_messages() -> list[dict]:
if not _EMPFANG_FILE.is_file():
return []
try:
with open(_EMPFANG_FILE, "r", encoding="utf-8") as f:
data = json.load(f)
return data if isinstance(data, list) else []
except Exception:
return []
def _save_messages(messages: list[dict]):
_ensure_data_dir()
tmp = str(_EMPFANG_FILE) + ".tmp"
with open(tmp, "w", encoding="utf-8") as f:
json.dump(messages, f, indent=2, ensure_ascii=False)
os.replace(tmp, str(_EMPFANG_FILE))
class EmpfangMessage(BaseModel):
medikamente: str = ""
therapieplan: str = ""
procedere: str = ""
kommentar: str = ""
patient: str = ""
absender: str = ""
zeitstempel: str = ""
extras: dict = Field(default_factory=dict)
@router.post("/send")
async def empfang_send(msg: EmpfangMessage):
msg_id = uuid.uuid4().hex[:12]
messages = _load_messages()
thread_id = msg_id
reply_to = (msg.extras or {}).get("reply_to", "")
if reply_to:
for m in messages:
if m.get("id") == reply_to:
thread_id = m.get("thread_id", reply_to)
break
else:
thread_id = reply_to
entry = {
"id": msg_id,
"thread_id": thread_id,
"medikamente": msg.medikamente.strip(),
"therapieplan": msg.therapieplan.strip(),
"procedere": msg.procedere.strip(),
"kommentar": msg.kommentar.strip(),
"patient": msg.patient.strip(),
"absender": msg.absender.strip(),
"zeitstempel": msg.zeitstempel.strip() or time.strftime("%Y-%m-%d %H:%M:%S"),
"empfangen": time.strftime("%Y-%m-%d %H:%M:%S"),
"status": "offen",
}
if msg.extras:
entry["extras"] = msg.extras
messages.insert(0, entry)
_save_messages(messages)
return JSONResponse(content={"success": True, "id": msg_id, "thread_id": thread_id})
@router.get("/messages")
async def empfang_list():
messages = _load_messages()
return JSONResponse(content={"success": True, "messages": messages})
@router.get("/thread/{thread_id}")
async def empfang_thread(thread_id: str):
messages = _load_messages()
thread = [m for m in messages if m.get("thread_id") == thread_id]
thread.sort(key=lambda m: m.get("empfangen", ""))
return JSONResponse(content={"success": True, "messages": thread})
@router.post("/messages/{msg_id}/done")
async def empfang_done(msg_id: str):
messages = _load_messages()
target = next((m for m in messages if m.get("id") == msg_id), None)
if not target:
raise HTTPException(status_code=404, detail="Nachricht nicht gefunden")
tid = target.get("thread_id", msg_id)
for m in messages:
if m.get("thread_id") == tid:
m["status"] = "erledigt"
_save_messages(messages)
return JSONResponse(content={"success": True})
@router.delete("/messages/{msg_id}")
async def empfang_delete(msg_id: str):
messages = _load_messages()
target = next((m for m in messages if m.get("id") == msg_id), None)
if not target:
raise HTTPException(status_code=404, detail="Nachricht nicht gefunden")
tid = target.get("thread_id", msg_id)
if tid == msg_id:
new = [m for m in messages
if m.get("thread_id", m.get("id")) != msg_id and m.get("id") != msg_id]
else:
new = [m for m in messages if m.get("id") != msg_id]
_save_messages(new)
return JSONResponse(content={"success": True})
_USERS_FILE = _DATA_DIR / "empfang_users.json"
def _load_users() -> list[str]:
if not _USERS_FILE.is_file():
return []
try:
with open(_USERS_FILE, "r", encoding="utf-8") as f:
data = json.load(f)
return data if isinstance(data, list) else []
except Exception:
return []
def _save_users(users: list[str]):
_ensure_data_dir()
with open(str(_USERS_FILE), "w", encoding="utf-8") as f:
json.dump(sorted(set(users)), f, ensure_ascii=False)
@router.get("/users")
async def empfang_users():
return JSONResponse(content={"users": _load_users()})
@router.post("/users")
async def empfang_register_user(request: Request):
try:
body = await request.json()
except Exception:
body = {}
name = (body.get("name") or "").strip()
action = (body.get("action") or "add").strip()
if not name:
return JSONResponse(content={"success": False})
users = _load_users()
if action == "delete":
users = [u for u in users if u != name]
_save_users(users)
elif action == "rename":
new_name = (body.get("new_name") or "").strip()
if new_name:
users = [new_name if u == name else u for u in users]
_save_users(users)
else:
if name not in users:
users.append(name)
_save_users(users)
return JSONResponse(content={"success": True, "users": _load_users()})
@router.post("/cleanup")
async def empfang_cleanup(request: Request):
"""Delete messages older than max_age_days (default 30)."""
try:
body = await request.json()
except Exception:
body = {}
max_days = int(body.get("max_age_days", 30))
cutoff = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(time.time() - max_days * 86400))
messages = _load_messages()
before = len(messages)
kept = [m for m in messages if (m.get("empfangen") or m.get("zeitstempel", "")) >= cutoff]
removed = before - len(kept)
if removed > 0:
_save_messages(kept)
return JSONResponse(content={"success": True, "removed": removed, "remaining": len(kept)})
@router.get("/", response_class=HTMLResponse)
async def empfang_page(request: Request):
html_path = Path(__file__).resolve().parent / "web" / "empfang.html"
if html_path.is_file():
return HTMLResponse(
content=html_path.read_text(encoding="utf-8"),
headers={"Cache-Control": "no-cache, no-store, must-revalidate",
"Pragma": "no-cache", "Expires": "0"},
)
return HTMLResponse(content="<h1>empfang.html nicht gefunden</h1>", status_code=404)