217 lines
6.6 KiB
Python
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)
|