trymeapp/tests/test_favourites_and_admin.py

123 lines
4.3 KiB
Python
Raw Normal View History

2026-11-11 22:06:26 +00:00
from __future__ import annotations
from pathlib import Path
from fastapi.testclient import TestClient
from sqlalchemy.orm import Session, sessionmaker
from app.config import Settings, get_settings
from app.database import Base, build_engine, get_db
from app.main import app
from tests.conftest import create_onboarded_student
def test_favourites_add_reorder_and_delete(client: TestClient) -> None:
token, _ = create_onboarded_student(client, "fav_tiger", "tiger", "avatar-3")
headers = {"Authorization": f"Bearer {token}"}
quiz_ids: list[int] = []
for title in ("Quiz Alpha", "Quiz Beta", "Quiz Gamma"):
r = client.post(
"/api/v1/quizzes",
headers=headers,
json={"title": title, "is_public": True, "questions": []},
)
assert r.status_code == 201
quiz_ids.append(r.json()["id"])
for qid in quiz_ids:
add_r = client.post("/api/v1/favourites", headers=headers, json={"quiz_id": qid})
assert add_r.status_code == 201
# Reorder to Gamma, Alpha, Beta
reordered = [quiz_ids[2], quiz_ids[0], quiz_ids[1]]
put_r = client.put(
"/api/v1/favourites/reorder",
headers=headers,
json={"quiz_ids": reordered},
)
assert put_r.status_code == 200
assert [item["quiz"]["id"] for item in put_r.json()] == reordered
# Delete Alpha (simulating recycle bin drop)
del_r = client.delete(f"/api/v1/favourites/{quiz_ids[0]}", headers=headers)
assert del_r.status_code == 200
assert [item["quiz"]["id"] for item in del_r.json()] == [quiz_ids[2], quiz_ids[1]]
def test_moderator_claim_ban_and_remove_quiz(client: TestClient) -> None:
mod_token, _ = create_onboarded_student(client, "chief_mod", "bear", "avatar-6")
mod_headers = {"Authorization": f"Bearer {mod_token}"}
bad_token, bad_user = create_onboarded_student(client, "spammer_99", "frog", "avatar-7")
bad_headers = {"Authorization": f"Bearer {bad_token}"}
quiz_r = client.post(
"/api/v1/quizzes",
headers=bad_headers,
json={"title": "Unwanted Quiz", "is_public": True, "questions": []},
)
assert quiz_r.status_code == 201
quiz_id = quiz_r.json()["id"]
# Claim initial moderator when ADMIN_USER env var is unset
claim_r = client.post("/api/v1/admin/claim", headers=mod_headers)
assert claim_r.status_code == 200
assert claim_r.json()["is_admin"] is True
# Second claim must fail with 409
second_claim = client.post("/api/v1/admin/claim", headers=bad_headers)
assert second_claim.status_code == 409
# Moderator removes quiz
rem_r = client.delete(f"/api/v1/admin/quizzes/{quiz_id}", headers=mod_headers)
assert rem_r.status_code == 204
assert client.get(f"/api/v1/quizzes/{quiz_id}").status_code == 404
# Moderator bans spammer
ban_r = client.post(
f"/api/v1/admin/users/{bad_user['id']}/ban",
headers=mod_headers,
json={"reason": "Posting spam quizzes"},
)
assert ban_r.status_code == 200
assert ban_r.json()["is_banned"] is True
# Banned user cannot create quizzes
blocked = client.post(
"/api/v1/quizzes",
headers=bad_headers,
json={"title": "Blocked Quiz", "is_public": True, "questions": []},
)
assert blocked.status_code == 403
def test_admin_user_container_env_var(tmp_path: Path) -> None:
env_settings = Settings(
database_url=f"sqlite:///{(tmp_path / 'env_admin.db').as_posix()}",
dev_auth_enabled=True,
admin_user="launch_moderator",
session_secret="env-admin-secret",
)
eng = build_engine(env_settings.database_url)
Base.metadata.create_all(bind=eng)
LocalSession = sessionmaker(bind=eng, autoflush=False, autocommit=False, expire_on_commit=False)
def _override_db():
db: Session = LocalSession()
try:
yield db
finally:
db.close()
app.dependency_overrides[get_db] = _override_db
app.dependency_overrides[get_settings] = lambda: env_settings
try:
with TestClient(app) as c:
login_r = c.post("/api/v1/auth/dev-login", json={"nickname": "launch_moderator"})
assert login_r.status_code == 200
assert login_r.json()["user"]["is_admin"] is True
finally:
app.dependency_overrides.clear()
eng.dispose()