feat(2-Schritt2): Login-Link + persistentes is_admin-Flag pro Nutzer

- Nutzerverwaltung zeigt beim Anlegen/„Link erneuern" jetzt den vollen
  Ein-Klick-Link (location.origin/?k=<token>) statt nur des Tokens.
- Neuer Admin-Schalter pro Nutzer (DB-Spalte users.is_admin + Migration).
  is_admin_user() honoriert das Flag ODER ADMIN_USERS (SSO). Dadurch zeigt
  /me den Admin-Button anhand des Flags — Grundlage für den nginx-Cutover.
- admin.py: PUT /admin/users/{id}/admin; list_users liefert is_admin.

Migration live verifiziert (Spalte vorhanden, bestehende Admins via
ADMIN_USERS weiterhin korrekt). app.js v=45. 219 passed.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Dieter Schlüter 2026-06-25 04:33:33 +02:00
commit bd55807a1c
8 changed files with 94 additions and 9 deletions

View file

@ -203,3 +203,15 @@ def test_admin_sets_user_allowed_languages():
users = client.get("/api/admin/users", headers=ADM_HDR).json()
entry = next(u for u in users if u["user_id"] == uid)
assert entry["allowed_languages"] == "de,en"
def test_admin_can_flag_user_as_admin():
created = client.post("/api/admin/users", headers=ADM_HDR,
json={"display_name": "Caregiver"}).json()
uid = created["user_id"]
users = client.get("/api/admin/users", headers=ADM_HDR).json()
assert next(u for u in users if u["user_id"] == uid)["is_admin"] is False
r = client.put(f"/api/admin/users/{uid}/admin", headers=ADM_HDR, json={"is_admin": True})
assert r.status_code == 200 and r.json()["is_admin"] is True
users = client.get("/api/admin/users", headers=ADM_HDR).json()
assert next(u for u in users if u["user_id"] == uid)["is_admin"] is True

View file

@ -46,3 +46,14 @@ def test_invalid_capability_link_does_not_set_cookie(monkeypatch):
# ungültiges Token -> kein Cookie, kein 303-Redirect auf bereinigte URL
assert "va_token=" not in r.headers.get("set-cookie", "")
client.cookies.clear()
def test_db_admin_flag_grants_admin_via_me(monkeypatch):
monkeypatch.setattr(settings, "auth_enabled", True)
store = deps.get_store()
user, token = store.create_user("Caregiver")
store.set_user_admin(user.id, True)
client.cookies.set("va_token", token)
me = client.get("/api/me").json()
assert me["is_admin"] is True
client.cookies.clear()