FastAPI + Celery + Next.js + Postgres/Redis app with company monitoring, source collection, LLM-based change analysis, enrichment, and account security (Turnstile, escalating lockout, email verification).
92 lines
3.2 KiB
Python
92 lines
3.2 KiB
Python
"""Reports API: ownership isolation, manual generation, and the raw
|
|
markdown/json export endpoints."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import uuid
|
|
|
|
|
|
def _register_and_login(client) -> dict[str, str]:
|
|
email = f"user-{uuid.uuid4().hex[:12]}@example.com"
|
|
client.post(
|
|
"/api/v1/auth/register",
|
|
json={"email": email, "password": "correct-horse-1", "display_name": "Test User"},
|
|
)
|
|
tokens = client.post(
|
|
"/api/v1/auth/login", json={"email": email, "password": "correct-horse-1"}
|
|
).json()
|
|
return {"Authorization": f"Bearer {tokens['access_token']}"}
|
|
|
|
|
|
def _create_company(client, headers):
|
|
return client.post(
|
|
"/api/v1/companies",
|
|
json={"name": f"Report Co {uuid.uuid4().hex[:6]}", "frequency_type": "weekly"},
|
|
headers=headers,
|
|
).json()
|
|
|
|
|
|
def test_generate_report_creates_and_returns_report(client):
|
|
headers = _register_and_login(client)
|
|
company = _create_company(client, headers)
|
|
|
|
resp = client.post(f"/api/v1/companies/{company['id']}/reports/generate", headers=headers)
|
|
assert resp.status_code == 201
|
|
body = resp.json()
|
|
assert body["report_type"] == "manual"
|
|
assert body["model_provider"] == "mock"
|
|
assert company["name"] in body["executive_summary"]
|
|
|
|
|
|
def test_list_reports_and_get_detail(client):
|
|
headers = _register_and_login(client)
|
|
company = _create_company(client, headers)
|
|
created = client.post(
|
|
f"/api/v1/companies/{company['id']}/reports/generate", headers=headers
|
|
).json()
|
|
|
|
listing = client.get(f"/api/v1/companies/{company['id']}/reports", headers=headers).json()
|
|
assert any(r["id"] == created["id"] for r in listing)
|
|
|
|
detail = client.get(f"/api/v1/reports/{created['id']}", headers=headers)
|
|
assert detail.status_code == 200
|
|
assert detail.json()["structured_report"]["executive_summary"]
|
|
|
|
|
|
def test_report_markdown_and_json_export(client):
|
|
headers = _register_and_login(client)
|
|
company = _create_company(client, headers)
|
|
created = client.post(
|
|
f"/api/v1/companies/{company['id']}/reports/generate", headers=headers
|
|
).json()
|
|
|
|
md_resp = client.get(f"/api/v1/reports/{created['id']}/markdown", headers=headers)
|
|
assert md_resp.status_code == 200
|
|
assert md_resp.headers["content-type"].startswith("text/markdown")
|
|
assert "# Competitive Intelligence Report" in md_resp.text
|
|
|
|
json_resp = client.get(f"/api/v1/reports/{created['id']}/json", headers=headers)
|
|
assert json_resp.status_code == 200
|
|
assert "executive_summary" in json_resp.json()
|
|
|
|
|
|
def test_reports_scoped_to_owner(client):
|
|
owner_headers = _register_and_login(client)
|
|
other_headers = _register_and_login(client)
|
|
company = _create_company(client, owner_headers)
|
|
created = client.post(
|
|
f"/api/v1/companies/{company['id']}/reports/generate", headers=owner_headers
|
|
).json()
|
|
|
|
assert (
|
|
client.get(f"/api/v1/companies/{company['id']}/reports", headers=other_headers).status_code
|
|
== 404
|
|
)
|
|
assert client.get(f"/api/v1/reports/{created['id']}", headers=other_headers).status_code == 404
|
|
assert (
|
|
client.post(
|
|
f"/api/v1/companies/{company['id']}/reports/generate", headers=other_headers
|
|
).status_code
|
|
== 404
|
|
)
|