Portal FastAPI + 5 endpoints REST para Bootcamp Agentic AI con watsonx Orchestrate (FactorIT). Single container, Coolify-ready. - Landing brandeado FIT con formulario de registro (honeypot anti-bot) - Tokens itsdangerous para descargas (24h expiry) - 5 endpoints API: historical/available procedures, member-insights, schedule, generate-report (Jinja2 + Plotly) - SQLite con upsert-on-email para leads + log de descargas - Admin endpoints (HTTP Basic): leads.json, leads.csv, stats - 23 tests pytest pasando - Dockerfile listo para Coolify con volúmenes persistentes (/app/leads.db, /app/app/data/reports_output, /app/material) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
57 lines
1.8 KiB
Python
57 lines
1.8 KiB
Python
import base64
|
||
|
||
|
||
def _auth_header(user: str = "testadmin", password: str = "testpass") -> dict:
|
||
token = base64.b64encode(f"{user}:{password}".encode()).decode()
|
||
return {"Authorization": f"Basic {token}"}
|
||
|
||
|
||
def test_admin_leads_requires_auth(client):
|
||
response = client.get("/admin/leads.json")
|
||
assert response.status_code == 401
|
||
|
||
|
||
def test_admin_leads_with_bad_credentials_rejected(client):
|
||
response = client.get("/admin/leads.json", headers=_auth_header(password="wrong"))
|
||
assert response.status_code == 401
|
||
|
||
|
||
def test_admin_leads_json_returns_list(client):
|
||
client.post(
|
||
"/register",
|
||
data={"nombre": "Ana", "email": "a@a.com", "empresa": "ACo", "consentimiento": "on"},
|
||
)
|
||
response = client.get("/admin/leads.json", headers=_auth_header())
|
||
assert response.status_code == 200
|
||
body = response.json()
|
||
assert isinstance(body, list)
|
||
assert any(l["email"] == "a@a.com" for l in body)
|
||
|
||
|
||
def test_admin_leads_csv_returns_csv(client):
|
||
client.post(
|
||
"/register",
|
||
data={"nombre": "Beto", "email": "b@b.com", "empresa": "BCo", "consentimiento": "on"},
|
||
)
|
||
response = client.get("/admin/leads.csv", headers=_auth_header())
|
||
assert response.status_code == 200
|
||
assert "text/csv" in response.headers["content-type"]
|
||
body = response.text
|
||
assert body.startswith("")
|
||
assert "b@b.com" in body
|
||
|
||
|
||
def test_admin_stats_returns_counts(client):
|
||
client.post(
|
||
"/register",
|
||
data={"nombre": "Carla", "email": "c@c.com", "empresa": "CCo", "consentimiento": "on"},
|
||
)
|
||
response = client.get("/admin/stats", headers=_auth_header())
|
||
assert response.status_code == 200
|
||
body = response.json()
|
||
assert "total_leads" in body
|
||
assert "total_downloads" in body
|
||
assert "downloads_por_archivo" in body
|
||
assert "top_5_empresas" in body
|
||
assert body["total_leads"] >= 1
|