"""Integration tests for message reporting and moderation queue: - POST /api/chat/messages/{message_id}/report - GET /api/moderation/reports - POST /api/moderation/reports/{id}/resolve """ import pytest from fastapi.testclient import TestClient from app.main import app def _register(client: TestClient, username: str) -> dict: resp = client.post( "/api/auth/register", json={ "username": username, "email": f"{username}@example.com", "password": "secret123", "date_of_birth": "1990-01-01", }, ) assert resp.status_code == 201, resp.text token = resp.json()["access_token"] headers = {"Authorization": f"Bearer {token}"} me = client.get("/api/users/me", headers=headers) assert me.status_code == 200, me.text return {"headers": headers, "id": me.json()["id"], "username": username} def _send_dm(client: TestClient, sender: dict, recipient: dict, text: str = "hello") -> int: resp = client.post( f"/api/chat/dm/{recipient['id']}/messages", headers=sender["headers"], json={"body": text}, ) assert resp.status_code == 201, resp.text return resp.json()["id"] class TestReportMessage: def test_report_message_success(self): client = TestClient(app) alice = _register(client, "rep_alice1") bob = _register(client, "rep_bob1") msg_id = _send_dm(client, alice, bob, "spam message") resp = client.post( f"/api/chat/messages/{msg_id}/report", headers=bob["headers"], json={"reason": "Contains spam", "category": "spam"}, ) assert resp.status_code == 201, resp.text data = resp.json() assert data["message_id"] == msg_id assert data["reporter_id"] == bob["id"] assert data["status"] == "open" assert "[spam] Contains spam" in data["reason"] def test_duplicate_report_rejected(self): client = TestClient(app) alice = _register(client, "rep_alice2") bob = _register(client, "rep_bob2") msg_id = _send_dm(client, alice, bob, "bad message") resp1 = client.post( f"/api/chat/messages/{msg_id}/report", headers=bob["headers"], json={"reason": "offensive"}, ) assert resp1.status_code == 201 resp2 = client.post( f"/api/chat/messages/{msg_id}/report", headers=bob["headers"], json={"reason": "offensive again"}, ) assert resp2.status_code == 409 def test_report_nonexistent_message_404(self): client = TestClient(app) bob = _register(client, "rep_bob3") resp = client.post( "/api/chat/messages/999999/report", headers=bob["headers"], json={"reason": "ghost"}, ) assert resp.status_code == 404 def test_report_requires_auth(self): client = TestClient(app) resp = client.post("/api/chat/messages/1/report", json={"reason": "no auth"}) assert resp.status_code == 401 class TestModerationQueue: def test_non_moderator_cannot_access_queue(self): client = TestClient(app) regular_user = _register(client, "rep_regular1") resp = client.get("/api/moderation/reports", headers=regular_user["headers"]) assert resp.status_code == 403 def test_moderator_can_list_reports(self): client = TestClient(app) alice = _register(client, "rep_alice4") bob = _register(client, "rep_bob4") admin = _register(client, "admin_list") msg_id = _send_dm(client, alice, bob, "something to report") client.post( f"/api/chat/messages/{msg_id}/report", headers=bob["headers"], json={"reason": "needs review"}, ) resp = client.get("/api/moderation/reports", headers=admin["headers"]) assert resp.status_code == 200, resp.text reports = resp.json() assert len(reports) >= 1 assert any(r["message_id"] == msg_id for r in reports) def test_moderator_resolve_dismiss(self): client = TestClient(app) alice = _register(client, "rep_alice5") bob = _register(client, "rep_bob5") admin = _register(client, "admin_dismiss") msg_id = _send_dm(client, alice, bob, "benign message") rep_resp = client.post( f"/api/chat/messages/{msg_id}/report", headers=bob["headers"], json={"reason": "false alarm"}, ) report_id = rep_resp.json()["id"] resolve_resp = client.post( f"/api/moderation/reports/{report_id}/resolve", headers=admin["headers"], json={"action": "dismiss", "notes": "No violation found"}, ) assert resolve_resp.status_code == 200, resolve_resp.text data = resolve_resp.json() assert data["report_id"] == report_id assert data["status"] == "dismissed" assert data["action_taken"] == "dismiss" assert data["moderator_id"] == admin["id"] def test_moderator_resolve_remove(self): client = TestClient(app) alice = _register(client, "rep_alice6") bob = _register(client, "rep_bob6") admin = _register(client, "admin_remove") msg_id = _send_dm(client, alice, bob, "offensive content") rep_resp = client.post( f"/api/chat/messages/{msg_id}/report", headers=bob["headers"], json={"reason": "hate speech"}, ) report_id = rep_resp.json()["id"] resolve_resp = client.post( f"/api/moderation/reports/{report_id}/resolve", headers=admin["headers"], json={"action": "remove", "notes": "Content removed"}, ) assert resolve_resp.status_code == 200 assert resolve_resp.json()["status"] == "resolved" # The message is removed from conversation history hist = client.get(f"/api/chat/dm/{bob['id']}/messages", headers=alice["headers"]) assert all(m["id"] != msg_id for m in hist.json()["messages"]) def test_moderator_resolve_ban(self): client = TestClient(app) bad_user = _register(client, "bad_actor") victim = _register(client, "rep_victim") admin_auth = _register(client, "admin_ban") msg_id = _send_dm(client, bad_user, victim, "terrible violation") rep_resp = client.post( f"/api/chat/messages/{msg_id}/report", headers=victim["headers"], json={"reason": "malicious user"}, ) report_id = rep_resp.json()["id"] resolve_resp = client.post( f"/api/moderation/reports/{report_id}/resolve", headers=admin_auth["headers"], json={"action": "ban", "notes": "Banned malicious user"}, ) assert resolve_resp.status_code == 200 # Attempting to use bad_user's token fails with 403 inactive account bad_me = client.get("/api/users/me", headers=bad_user["headers"]) assert bad_me.status_code == 403