Sprint 14: Multi-Fix-Batch — SW by-v428, APP_VER 407
KI/Symptom-Check: JSON-Code-Fence stripping in ki.py, Dringlichkeit-Map mit Phosphor-Icons
Gewicht-Sync: health.js aktualisiert appState.activeDog.gewicht_kg auch bei Bearbeitung
Giftköder: icon:'check-circle' → UI.icon('check-circle') in emptyState-Call
Forum-Pills: overflow:hidden + text-overflow:ellipsis auf Desktop und Mobile
Moderation: Admins für Moderatoren unsichtbar, keine Aktions-Buttons auf Admins
Notizblock: Filter-Chips wrap 2-zeilig auf Desktop (min-width:1024px)
Tagebuch: Datenschutz-Hinweis "nur du kannst sie sehen", Sitter sieht keine bestehenden Einträge
diary.py: Sitter-Zugriff gibt leere Liste zurück (GET), Erstellen bleibt erlaubt
This commit is contained in:
parent
02120bb532
commit
016eb52d83
12 changed files with 111 additions and 33 deletions
|
|
@ -214,6 +214,18 @@ async def list_diary(dog_id: int, limit: int = 20, offset: int = 0,
|
|||
user=Depends(get_current_user)):
|
||||
with db() as conn:
|
||||
_can_read_dog(dog_id, user["id"], conn)
|
||||
# Sitter darf keine bestehenden Einträge lesen
|
||||
dog = conn.execute("SELECT user_id FROM dogs WHERE id=?", (dog_id,)).fetchone()
|
||||
is_owner = dog and dog["user_id"] == user["id"]
|
||||
if not is_owner:
|
||||
# Prüfen ob geteilter Hund (dog_shares) — darf lesen
|
||||
shared = conn.execute(
|
||||
"""SELECT 1 FROM dog_shares WHERE dog_id=? AND shared_with_id=? AND accepted_at IS NOT NULL""",
|
||||
(dog_id, user["id"])
|
||||
).fetchone()
|
||||
if not shared:
|
||||
# Weder Besitzer noch geteilter Nutzer → Sitter → leere Liste
|
||||
return []
|
||||
extra = "AND (d.is_milestone=1 OR d.typ='meilenstein')" if milestone else ""
|
||||
if q:
|
||||
pattern = f"%{q}%"
|
||||
|
|
|
|||
|
|
@ -105,6 +105,8 @@ async def mod_users(
|
|||
offset: int = 0,
|
||||
user=Depends(require_moderator),
|
||||
):
|
||||
is_admin = user["rolle"] == "admin"
|
||||
|
||||
with db() as conn:
|
||||
where = "WHERE 1=1"
|
||||
params = []
|
||||
|
|
@ -114,8 +116,12 @@ async def mod_users(
|
|||
if banned:
|
||||
where += " AND is_banned=1"
|
||||
|
||||
# Moderatoren sehen keine Admins
|
||||
if not is_admin:
|
||||
where += " AND rolle != 'admin' AND COALESCE(is_admin, 0) = 0"
|
||||
|
||||
# E-Mail nur für Admins; Moderatoren sehen maskierte Version
|
||||
email_col = "email" if user["rolle"] == "admin" else \
|
||||
email_col = "email" if is_admin else \
|
||||
"SUBSTR(email,1,2)||'***@'||SUBSTR(email,INSTR(email,'@')+1) AS email"
|
||||
|
||||
rows = conn.execute(f"""
|
||||
|
|
@ -145,12 +151,15 @@ async def mod_patch_user(uid: int, data: dict, user=Depends(require_moderator)):
|
|||
|
||||
with db() as conn:
|
||||
target = conn.execute(
|
||||
"SELECT id, rolle, name FROM users WHERE id=?", (uid,)
|
||||
"SELECT id, rolle, is_admin, name FROM users WHERE id=?", (uid,)
|
||||
).fetchone()
|
||||
if not target:
|
||||
raise HTTPException(404, "User nicht gefunden.")
|
||||
if target["rolle"] == "admin" and user["rolle"] != "admin":
|
||||
raise HTTPException(403, "Admins können nur von Admins verwaltet werden.")
|
||||
# Moderatoren dürfen keine Admins bearbeiten
|
||||
if user["rolle"] != "admin" and (
|
||||
target["rolle"] == "admin" or target["is_admin"]
|
||||
):
|
||||
raise HTTPException(403, "Admins können nicht von Moderatoren bearbeitet werden.")
|
||||
|
||||
cols = ", ".join(f"{k}=?" for k in updates)
|
||||
conn.execute(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue