Bug: Frontend prüfte nur istAdmin, Materialverantwortliche und Leitungs- verantwortliche sahen exakt dieselbe UI wie Mitarbeiter - obwohl das Backend längst granular unterscheidet (require_roles je Endpunkt). - AuthContext gibt volle Rollenliste + istVerantwortlich/istMaterial- verantwortlich/istLeitungsverantwortlich weiter. - /admin-Route für alle drei Rollen offen, AdminPage filtert Tabs nach Rolle (Material/Leitung: Objekte-Pflege, Kontrollverantwortung, Änderungslog; nur Administration: Stammdaten/Benutzer/Eskalation/ Zuständigkeit). - ObjektSection blendet Anlegen/Duplizieren/Kopplung für Nicht-Admins aus (waren admin-only im Backend, hätten 403 geworfen). - Promise.allSettled statt Promise.all beim Laden, damit ein admin-only Endpunkt (z.B. /benutzer) nicht die ganze Seite für niedrigere Rollen blockiert. - Backend: GET /benutzer jetzt auch für Material-/Leitungsverantwortliche lesbar (für Kontrollverantwortung-Auswahl im Frontend nötig), Schreiben bleibt admin-only. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CVgbozhYmuEhiEJHffRXCV
94 lines
3.3 KiB
Python
94 lines
3.3 KiB
Python
import pytest
|
|
|
|
from tests.conftest import auth_header, login
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_admin_can_create_benutzer_with_rollen(client, admin_user):
|
|
token = await login(client, "admin1")
|
|
response = await client.post(
|
|
"/api/v1/benutzer",
|
|
json={
|
|
"name": "Neue Kollegin",
|
|
"login": "neu1",
|
|
"passwort": "sicheres-passwort",
|
|
"rollen": ["mitarbeiter", "materialverantwortlicher"],
|
|
},
|
|
headers=auth_header(token),
|
|
)
|
|
assert response.status_code == 201
|
|
body = response.json()
|
|
assert body["login"] == "neu1"
|
|
assert set(body["rollen"]) == {"mitarbeiter", "materialverantwortlicher"}
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_duplicate_login_conflict(client, admin_user):
|
|
token = await login(client, "admin1")
|
|
payload = {
|
|
"name": "Doppelt",
|
|
"login": "doppelt1",
|
|
"passwort": "sicheres-passwort",
|
|
"rollen": [],
|
|
}
|
|
first = await client.post("/api/v1/benutzer", json=payload, headers=auth_header(token))
|
|
assert first.status_code == 201
|
|
second = await client.post("/api/v1/benutzer", json=payload, headers=auth_header(token))
|
|
assert second.status_code == 409
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_mitarbeiter_cannot_manage_benutzer(client, mitarbeiter_user):
|
|
token = await login(client, "mitarbeiter1")
|
|
response = await client.get("/api/v1/benutzer", headers=auth_header(token))
|
|
assert response.status_code == 403
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_admin_can_update_rollen(client, admin_user, mitarbeiter_user):
|
|
token = await login(client, "admin1")
|
|
response = await client.patch(
|
|
f"/api/v1/benutzer/{mitarbeiter_user.id}",
|
|
json={"rollen": ["leitungsverantwortlicher"]},
|
|
headers=auth_header(token),
|
|
)
|
|
assert response.status_code == 200
|
|
assert response.json()["rollen"] == ["leitungsverantwortlicher"]
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_materialverantwortlicher_darf_benutzer_lesen_nicht_anlegen(
|
|
client, materialverantwortlicher_user
|
|
):
|
|
"""Rollen-Vorgabe: Material-/Leitungsverantwortliche brauchen die Liste
|
|
lesend (z.B. Kontrollverantwortung-Auswahl im Frontend), aber kein
|
|
Schreibrecht - anders als Administration."""
|
|
token = await login(client, "materialverantwortlicher1")
|
|
gelesen = await client.get("/api/v1/benutzer", headers=auth_header(token))
|
|
assert gelesen.status_code == 200
|
|
|
|
angelegt = await client.post(
|
|
"/api/v1/benutzer",
|
|
json={"name": "X", "login": "x1", "passwort": "sicheres-passwort", "rollen": ["mitarbeiter"]},
|
|
headers=auth_header(token),
|
|
)
|
|
assert angelegt.status_code == 403
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_leitungsverantwortlicher_darf_benutzer_lesen(client, db_session):
|
|
from app.core.security import hash_password
|
|
from app.models.auth import Benutzer, BenutzerRolle, RolleTyp
|
|
|
|
benutzer = Benutzer(
|
|
name="Test Leitung", login="leitung1", passwort_hash=hash_password("test-passwort-123"), aktiv=True
|
|
)
|
|
db_session.add(benutzer)
|
|
await db_session.flush()
|
|
db_session.add(BenutzerRolle(benutzer_id=benutzer.id, rolle=RolleTyp.leitungsverantwortlicher))
|
|
await db_session.flush()
|
|
|
|
token = await login(client, "leitung1")
|
|
response = await client.get("/api/v1/benutzer", headers=auth_header(token))
|
|
assert response.status_code == 200
|