97 lines
3.3 KiB
Python
97 lines
3.3 KiB
Python
|
|
from __future__ import annotations
|
||
|
|
|
||
|
|
from fastapi.testclient import TestClient
|
||
|
|
|
||
|
|
|
||
|
|
def test_profile_onboarding_consent_gender_age_no_birthday(client: TestClient) -> None:
|
||
|
|
login = client.post("/api/v1/auth/dev-login", json={"nickname": "koala_kid"})
|
||
|
|
assert login.status_code == 200
|
||
|
|
token = login.json()["access_token"]
|
||
|
|
headers = {"Authorization": f"Bearer {token}"}
|
||
|
|
|
||
|
|
# Without public_website_consent, creating a quiz is blocked
|
||
|
|
blocked = client.post(
|
||
|
|
"/api/v1/quizzes",
|
||
|
|
headers=headers,
|
||
|
|
json={"title": "Early Quiz", "description": "Test", "is_public": True, "questions": []},
|
||
|
|
)
|
||
|
|
assert blocked.status_code == 403
|
||
|
|
|
||
|
|
# Update profile with stylized animal, color, inclusive gender, age (no birthday) & consent
|
||
|
|
updated = client.patch(
|
||
|
|
"/api/v1/users/me",
|
||
|
|
headers=headers,
|
||
|
|
json={
|
||
|
|
"nickname": "koala_kid",
|
||
|
|
"first_name": "Sam",
|
||
|
|
"last_name": "Chen",
|
||
|
|
"age": 16,
|
||
|
|
"gender": "other",
|
||
|
|
"gender_custom": "Demiboy",
|
||
|
|
"avatar_animal": "koala",
|
||
|
|
"avatar_color": "avatar-5",
|
||
|
|
"public_website_consent": True,
|
||
|
|
},
|
||
|
|
)
|
||
|
|
assert updated.status_code == 200
|
||
|
|
profile = updated.json()
|
||
|
|
assert profile["onboarded"] is True
|
||
|
|
assert profile["age"] == 16
|
||
|
|
assert "birthday" not in profile
|
||
|
|
assert "birth_date" not in profile
|
||
|
|
assert profile["gender"] == "other"
|
||
|
|
assert profile["gender_custom"] == "Demiboy"
|
||
|
|
assert profile["avatar_animal"] == "koala"
|
||
|
|
assert profile["avatar_color"] == "avatar-5"
|
||
|
|
assert profile["public_website_consent"] is True
|
||
|
|
|
||
|
|
|
||
|
|
def test_api_key_lifecycle_and_expiration(client: TestClient) -> None:
|
||
|
|
login = client.post("/api/v1/auth/dev-login", json={"nickname": "key_tester"})
|
||
|
|
token = login.json()["access_token"]
|
||
|
|
headers = {"Authorization": f"Bearer {token}"}
|
||
|
|
|
||
|
|
client.patch(
|
||
|
|
"/api/v1/users/me",
|
||
|
|
headers=headers,
|
||
|
|
json={"public_website_consent": True},
|
||
|
|
)
|
||
|
|
|
||
|
|
# Create API key
|
||
|
|
create_resp = client.post(
|
||
|
|
"/api/v1/users/me/api-keys",
|
||
|
|
headers=headers,
|
||
|
|
json={"name": "CLI Study Bot", "expires_in_days": 30},
|
||
|
|
)
|
||
|
|
assert create_resp.status_code == 201
|
||
|
|
key_data = create_resp.json()
|
||
|
|
raw_key = key_data["raw_key"]
|
||
|
|
key_id = key_data["id"]
|
||
|
|
assert raw_key.startswith("tm_live_")
|
||
|
|
assert key_data["is_active"] is True
|
||
|
|
|
||
|
|
# Authenticate using X-API-Key header
|
||
|
|
me_via_key = client.get("/api/v1/users/me", headers={"X-API-Key": raw_key})
|
||
|
|
assert me_via_key.status_code == 200
|
||
|
|
assert me_via_key.json()["nickname"] == "key_tester"
|
||
|
|
|
||
|
|
# List keys should not leak raw_key
|
||
|
|
list_resp = client.get("/api/v1/users/me/api-keys", headers=headers)
|
||
|
|
assert list_resp.status_code == 200
|
||
|
|
listed = list_resp.json()
|
||
|
|
assert len(listed) == 1
|
||
|
|
assert "raw_key" not in listed[0]
|
||
|
|
assert listed[0]["last_used_at"] is not None
|
||
|
|
|
||
|
|
# Expire old key
|
||
|
|
expire_resp = client.post(
|
||
|
|
f"/api/v1/users/me/api-keys/{key_id}/expire",
|
||
|
|
headers=headers,
|
||
|
|
)
|
||
|
|
assert expire_resp.status_code == 200
|
||
|
|
assert expire_resp.json()["is_active"] is False
|
||
|
|
|
||
|
|
# Subsequent calls with the expired API key must fail with 401
|
||
|
|
revoked_check = client.get("/api/v1/users/me", headers={"X-API-Key": raw_key})
|
||
|
|
assert revoked_check.status_code == 401
|