update
This commit is contained in:
@@ -8550,6 +8550,53 @@ async def empfang_delete(msg_id: str, request: Request):
|
||||
# TASKS (practice-scoped, server-side)
|
||||
# =====================================================================
|
||||
|
||||
|
||||
def _practice_user_by_id(practice_id: str, user_id: str) -> dict | None:
|
||||
uid = (user_id or "").strip()
|
||||
if not uid:
|
||||
return None
|
||||
for u in _practice_users(practice_id):
|
||||
if str(u.get("user_id") or "").strip() == uid:
|
||||
return u
|
||||
return None
|
||||
|
||||
|
||||
def _apply_task_assignee_from_body(
|
||||
target: dict, body: dict, practice_id: str, *, allow_legacy_name: bool = False
|
||||
) -> None:
|
||||
"""Zuweisung nur über stabile user_id; assignee-Anzeigename wird serverseitig gesetzt."""
|
||||
pid = (practice_id or "").strip()
|
||||
if "assignee_user_id" in body:
|
||||
uid = (body.get("assignee_user_id") or "").strip()
|
||||
if not uid:
|
||||
target["assignee_user_id"] = ""
|
||||
target["assignee"] = ""
|
||||
return
|
||||
u = _practice_user_by_id(pid, uid)
|
||||
if not u:
|
||||
raise HTTPException(
|
||||
status_code=400,
|
||||
detail="Empfänger nicht gefunden oder nicht in dieser Praxis",
|
||||
)
|
||||
target["assignee_user_id"] = uid
|
||||
target["assignee"] = (u.get("display_name") or "").strip()
|
||||
return
|
||||
if "assignee" in body and allow_legacy_name:
|
||||
name = (body.get("assignee") or "").strip()
|
||||
target["assignee"] = name
|
||||
matched = None
|
||||
if name:
|
||||
nl = name.lower()
|
||||
for u in _practice_users(pid):
|
||||
dn = (u.get("display_name") or "").strip()
|
||||
if dn.lower() == nl:
|
||||
matched = u
|
||||
break
|
||||
target["assignee_user_id"] = (
|
||||
str(matched.get("user_id") or "").strip() if matched else ""
|
||||
)
|
||||
|
||||
|
||||
@router.get("/tasks")
|
||||
async def empfang_tasks_list(request: Request):
|
||||
pid = _resolve_practice_id(request)
|
||||
@@ -8593,13 +8640,17 @@ async def empfang_tasks_create(request: Request):
|
||||
"source_peer": peer_opt or "",
|
||||
"source_thread_id": stid_opt or "",
|
||||
"done": False,
|
||||
"assignee": (body.get("assignee") or "").strip(),
|
||||
"assignee": "",
|
||||
"assignee_user_id": "",
|
||||
"created_by": (s or {}).get("display_name", "") if s else "",
|
||||
"created": time.strftime("%Y-%m-%d %H:%M:%S"),
|
||||
"source_msg_id": (body.get("source_msg_id") or "").strip(),
|
||||
"source_attachment_ids": att_ids,
|
||||
"item_kind": item_kind,
|
||||
}
|
||||
_apply_task_assignee_from_body(
|
||||
task, body, pid, allow_legacy_name=bool((body.get("assignee") or "").strip())
|
||||
)
|
||||
tasks = _load_tasks()
|
||||
tasks.insert(0, task)
|
||||
_save_tasks(tasks)
|
||||
@@ -8608,6 +8659,7 @@ async def empfang_tasks_create(request: Request):
|
||||
|
||||
@router.post("/tasks/{task_id}/update")
|
||||
async def empfang_tasks_update(task_id: str, request: Request):
|
||||
pid = _resolve_practice_id(request)
|
||||
try:
|
||||
body = await request.json()
|
||||
except Exception:
|
||||
@@ -8616,14 +8668,22 @@ async def empfang_tasks_update(task_id: str, request: Request):
|
||||
target = next((t for t in tasks if t.get("task_id") == task_id), None)
|
||||
if not target:
|
||||
raise HTTPException(status_code=404, detail="Aufgabe nicht gefunden")
|
||||
task_pid = (target.get("practice_id") or "").strip()
|
||||
if pid and task_pid and pid != task_pid:
|
||||
raise HTTPException(status_code=403, detail="Aufgabe gehört nicht zu dieser Praxis")
|
||||
if "done" in body:
|
||||
target["done"] = bool(body["done"])
|
||||
if "text" in body:
|
||||
target["text"] = (body["text"] or "").strip() or target["text"]
|
||||
if "title" in body:
|
||||
target["title"] = (body.get("title") or "").strip()
|
||||
if "assignee" in body:
|
||||
target["assignee"] = (body.get("assignee") or "").strip()
|
||||
if "assignee_user_id" in body:
|
||||
_apply_task_assignee_from_body(target, body, task_pid or pid or "")
|
||||
elif "assignee" in body:
|
||||
raise HTTPException(
|
||||
status_code=400,
|
||||
detail="Zuweisung nur über assignee_user_id (Empfänger aus Liste wählen)",
|
||||
)
|
||||
if "source_meta" in body:
|
||||
target["source_meta"] = (body.get("source_meta") or "").strip()
|
||||
_save_tasks(tasks)
|
||||
@@ -9604,6 +9664,8 @@ async def empfang_shell_context_me(request: Request):
|
||||
"dm_open_external_peer_user_id": "",
|
||||
"dm_open_external_link_id": "",
|
||||
"dm_open_external_display_name": "",
|
||||
"nav_open_kind": "",
|
||||
"nav_open_assignee": "",
|
||||
},
|
||||
headers={"Cache-Control": "no-store, no-cache, must-revalidate"},
|
||||
)
|
||||
@@ -9623,6 +9685,8 @@ async def empfang_shell_context_me(request: Request):
|
||||
dm_ext_uid_out = str(rec.get("dm_open_external_peer_user_id") or "")
|
||||
dm_ext_lid_out = str(rec.get("dm_open_external_link_id") or "")
|
||||
dm_ext_dn_out = str(rec.get("dm_open_external_display_name") or "")
|
||||
nav_kind_out = str(rec.get("nav_open_kind") or "")
|
||||
nav_assignee_out = str(rec.get("nav_open_assignee") or "")
|
||||
# Einmalige Auslieferung: dm_open-Felder (intern wie extern) nach dem Lesen leeren.
|
||||
if dm_uid_out or dm_ext_uid_out:
|
||||
rec["dm_open_peer_user_id"] = ""
|
||||
@@ -9633,6 +9697,10 @@ async def empfang_shell_context_me(request: Request):
|
||||
rec["dm_open_external_link_id"] = ""
|
||||
rec["dm_open_external_display_name"] = ""
|
||||
_desktop_shell_latest_context_by_user[(pid, uid)] = rec
|
||||
if nav_kind_out:
|
||||
rec["nav_open_kind"] = ""
|
||||
rec["nav_open_assignee"] = ""
|
||||
_desktop_shell_latest_context_by_user[(pid, uid)] = rec
|
||||
|
||||
return JSONResponse(
|
||||
content={
|
||||
@@ -9649,6 +9717,8 @@ async def empfang_shell_context_me(request: Request):
|
||||
"dm_open_external_peer_user_id": dm_ext_uid_out,
|
||||
"dm_open_external_link_id": dm_ext_lid_out,
|
||||
"dm_open_external_display_name": dm_ext_dn_out,
|
||||
"nav_open_kind": nav_kind_out,
|
||||
"nav_open_assignee": nav_assignee_out,
|
||||
},
|
||||
headers={"Cache-Control": "no-store, no-cache, must-revalidate"},
|
||||
)
|
||||
@@ -9745,6 +9815,61 @@ async def empfang_shell_dm_open(request: Request):
|
||||
)
|
||||
|
||||
|
||||
@router.post("/shell/nav-open")
|
||||
async def empfang_shell_nav_open(request: Request):
|
||||
"""Kontakt-Panel: Aufgaben-/Briefe-Badge oeffnet Ansicht in der Chat-Huelle.
|
||||
|
||||
Reine Wiederverwendung des Shell-Context-Stores (wie dm-open). Keine Inhalte loggen.
|
||||
"""
|
||||
_desktop_shell_context_cleanup()
|
||||
s = _require_session(request)
|
||||
pid = (s.get("practice_id") or "").strip()
|
||||
uid = (s.get("user_id") or "").strip()
|
||||
if not pid or not uid:
|
||||
raise HTTPException(status_code=400, detail="practice_id/user_id fehlen in der Session")
|
||||
|
||||
try:
|
||||
body_raw = await request.json()
|
||||
body = body_raw if isinstance(body_raw, dict) else {}
|
||||
except Exception:
|
||||
body = {}
|
||||
|
||||
nav_kind = str(body.get("nav_open_kind") or "").strip().lower()
|
||||
if nav_kind not in ("task", "letter"):
|
||||
raise HTTPException(status_code=400, detail="nav_open_kind muss task oder letter sein")
|
||||
nav_assignee = str(body.get("nav_open_assignee") or "").strip()[:200]
|
||||
|
||||
now = time.time()
|
||||
expires_at = now + float(_DESKTOP_SHELL_CONTEXT_TTL_SECONDS)
|
||||
rec = _desktop_shell_latest_context_by_user.get((pid, uid))
|
||||
if not isinstance(rec, dict) or float(rec.get("expires_at", 0)) < now:
|
||||
rec = {
|
||||
"context_id": "ctx_" + secrets.token_urlsafe(24),
|
||||
"practice_id": pid,
|
||||
"user_id": uid,
|
||||
"therapy_text": "",
|
||||
"procedure_text": "",
|
||||
"therapy_autocopy": False,
|
||||
"procedure_autocopy": False,
|
||||
}
|
||||
rec["nav_open_kind"] = nav_kind
|
||||
rec["nav_open_assignee"] = nav_assignee
|
||||
rec["expires_at"] = expires_at
|
||||
rec["updated_at"] = now
|
||||
_desktop_shell_latest_context_by_user[(pid, uid)] = rec
|
||||
|
||||
_log.info(
|
||||
"DESKTOP_SHELL_NAV_OPEN_SET practice=%s user=%s kind=%s",
|
||||
pid,
|
||||
uid,
|
||||
nav_kind,
|
||||
)
|
||||
return JSONResponse(
|
||||
content={"success": True},
|
||||
headers={"Cache-Control": "no-store, no-cache, must-revalidate"},
|
||||
)
|
||||
|
||||
|
||||
@router.post("/shell/consume")
|
||||
async def empfang_shell_consume(request: Request):
|
||||
"""Tauscht shell_token gegen aza_session (HttpOnly Cookie). Einmal-Verbrauch."""
|
||||
|
||||
Reference in New Issue
Block a user