# tests/test_operator_users.py import uuid from tests.conftest import wire_operator_auth from backend.operator_auth import create_operator, make_operator_cookie, COOKIE_NAME from backend.models import OperatorUser def _login_as(client, user): client.cookies.set(COOKIE_NAME, make_operator_cookie(user.id)) def test_admin_cannot_reach_user_management(client, db_session, monkeypatch): admin, _ = create_operator(db_session, "admin@x.com", "Admin", "admin", password="pw-123456") wire_operator_auth(monkeypatch, db_session, enabled=True) _login_as(client, admin) assert client.get("/admin/users", follow_redirects=False).status_code == 403 def test_superadmin_sees_user_management(client, db_session, monkeypatch): su, _ = create_operator(db_session, "su@x.com", "Su", "superadmin", password="pw-123456") wire_operator_auth(monkeypatch, db_session, enabled=True) _login_as(client, su) assert client.get("/admin/users", follow_redirects=False).status_code == 200 def test_superadmin_lists_users_json(client, db_session, monkeypatch): su, _ = create_operator(db_session, "su@x.com", "Su", "superadmin", password="pw-123456") wire_operator_auth(monkeypatch, db_session, enabled=True) _login_as(client, su) r = client.get("/api/admin/users") assert r.status_code == 200 emails = [u["email"] for u in r.json()["users"]] assert "su@x.com" in emails assert all("password_hash" not in u for u in r.json()["users"]) # never leak hashes def test_create_user_returns_temp_once(client, db_session, monkeypatch): su, _ = create_operator(db_session, "su@x.com", "Su", "superadmin", password="pw-123456") wire_operator_auth(monkeypatch, db_session, enabled=True) _login_as(client, su) r = client.post("/api/admin/users", json={"email": "dad@x.com", "name": "Dad", "role": "admin"}) assert r.status_code == 200 assert len(r.json()["password"]) >= 12 made = db_session.query(OperatorUser).filter_by(email="dad@x.com").first() assert made.must_change_password is True def test_reset_password_returns_temp_once(client, db_session, monkeypatch): su, _ = create_operator(db_session, "su@x.com", "Su", "superadmin", password="pw-123456") target, _ = create_operator(db_session, "t@x.com", "T", "admin", password="pw-123456") wire_operator_auth(monkeypatch, db_session, enabled=True) _login_as(client, su) r = client.post(f"/api/admin/users/{target.id}/reset-password") assert r.status_code == 200 and len(r.json()["password"]) >= 12 db_session.refresh(target) assert target.must_change_password is True def test_disable_and_enable(client, db_session, monkeypatch): su, _ = create_operator(db_session, "su@x.com", "Su", "superadmin", password="pw-123456") target, _ = create_operator(db_session, "t@x.com", "T", "admin", password="pw-123456") wire_operator_auth(monkeypatch, db_session, enabled=True) _login_as(client, su) assert client.post(f"/api/admin/users/{target.id}/disable").status_code == 200 db_session.refresh(target); assert target.active is False assert client.post(f"/api/admin/users/{target.id}/enable").status_code == 200 db_session.refresh(target); assert target.active is True def test_change_role(client, db_session, monkeypatch): su, _ = create_operator(db_session, "su@x.com", "Su", "superadmin", password="pw-123456") target, _ = create_operator(db_session, "t@x.com", "T", "admin", password="pw-123456") wire_operator_auth(monkeypatch, db_session, enabled=True) _login_as(client, su) r = client.post(f"/api/admin/users/{target.id}/role", json={"role": "superadmin"}) assert r.status_code == 200 db_session.refresh(target); assert target.role == "superadmin" def test_admin_cannot_reach_json_endpoints(client, db_session, monkeypatch): admin, _ = create_operator(db_session, "a@x.com", "A", "admin", password="pw-123456") target, _ = create_operator(db_session, "t@x.com", "T", "admin", password="pw-123456") wire_operator_auth(monkeypatch, db_session, enabled=True) _login_as(client, admin) assert client.get("/api/admin/users").status_code == 403 assert client.post("/api/admin/users", json={"email": "x@x.com", "name": "X", "role": "admin"}).status_code == 403 assert client.post(f"/api/admin/users/{target.id}/reset-password").status_code == 403 assert client.post(f"/api/admin/users/{target.id}/disable").status_code == 403 assert client.post(f"/api/admin/users/{target.id}/enable").status_code == 403 assert client.post(f"/api/admin/users/{target.id}/role", json={"role": "superadmin"}).status_code == 403 def test_cannot_disable_own_account(client, db_session, monkeypatch): su, _ = create_operator(db_session, "su@x.com", "Su", "superadmin", password="pw-123456") wire_operator_auth(monkeypatch, db_session, enabled=True) _login_as(client, su) r = client.post(f"/api/admin/users/{su.id}/disable") assert r.status_code == 400 db_session.refresh(su) assert su.active is True def test_cannot_change_own_role(client, db_session, monkeypatch): su, _ = create_operator(db_session, "su@x.com", "Su", "superadmin", password="pw-123456") wire_operator_auth(monkeypatch, db_session, enabled=True) _login_as(client, su) r = client.post(f"/api/admin/users/{su.id}/role", json={"role": "admin"}) assert r.status_code == 400 db_session.refresh(su) assert su.role == "superadmin" def test_deferred_operator_role_rejected_by_api(client, db_session, monkeypatch): su, _ = create_operator(db_session, "su@x.com", "Su", "superadmin", password="pw-123456") target, _ = create_operator(db_session, "t@x.com", "T", "admin", password="pw-123456") wire_operator_auth(monkeypatch, db_session, enabled=True) _login_as(client, su) assert client.post("/api/admin/users", json={"email": "op@x.com", "name": "Op", "role": "operator"}).status_code == 400 assert client.post(f"/api/admin/users/{target.id}/role", json={"role": "operator"}).status_code == 400 def test_admin_surface_404s_when_flag_off(client, db_session, monkeypatch): su, _ = create_operator(db_session, "su@x.com", "Su", "superadmin", password="pw-123456") wire_operator_auth(monkeypatch, db_session, enabled=False) _login_as(client, su) # With operator auth OFF, the management surface must not exist (404), even # though require_role passes through — otherwise it'd be world-open. assert client.get("/admin/users").status_code == 404 assert client.get("/api/admin/users").status_code == 404 assert client.post("/api/admin/users", json={"email": "x@x.com", "name": "X", "role": "admin"}).status_code == 404