system-prompts-and-models-o.../dealix/api/routers/public.py
2026-05-01 14:03:52 +03:00

153 lines
5.0 KiB
Python

"""
Public endpoints — no auth, CORS-open. Used by the landing page.
Routes:
POST /api/v1/public/demo-request — landing form submission
Body: {name, company, email, phone, sector?, size?, message?, consent, website(honeypot)}
Returns: {ok: true, calendly_url: "...", lead_id?: "..."}
"""
from __future__ import annotations
import logging
import os
from typing import Any
from fastapi import APIRouter, HTTPException, Request
from dealix.analytics import FUNNEL_EVENTS, capture_event
log = logging.getLogger(__name__)
router = APIRouter(prefix="/api/v1/public", tags=["public"])
CALENDLY_URL = os.getenv(
"CALENDLY_URL",
"https://calendly.com/sami-assiri11/dealix-demo",
)
@router.post("/demo-request")
async def demo_request(req: Request) -> dict[str, Any]:
"""Public landing form — captures demo request and returns Calendly booking URL."""
try:
body = await req.json()
except Exception as e:
raise HTTPException(status_code=400, detail="invalid_json") from e
# Honeypot: if "website" field is filled, silently drop
if body.get("website"):
log.info("demo_request_honeypot_triggered")
return {"ok": True, "calendly_url": CALENDLY_URL}
name = str(body.get("name") or "").strip()
company = str(body.get("company") or "").strip()
email = str(body.get("email") or "").strip()
phone = str(body.get("phone") or "").strip()
sector = str(body.get("sector") or "").strip()
size = str(body.get("size") or "").strip()
message = str(body.get("message") or "").strip()
consent = bool(body.get("consent"))
if not name or not company or "@" not in email or not phone:
raise HTTPException(status_code=422, detail="missing_required_fields")
if not consent:
raise HTTPException(status_code=422, detail="consent_required")
# Fire PostHog event (fire-and-forget — never blocks response)
try:
await capture_event(
(
FUNNEL_EVENTS.DEMO_REQUESTED
if hasattr(FUNNEL_EVENTS, "DEMO_REQUESTED")
else "demo_requested"
),
distinct_id=email,
properties={
"name": name,
"company": company,
"email": email,
"phone": phone,
"sector": sector,
"size": size,
"message_len": len(message),
"source": "landing.demo_form",
},
)
except Exception:
log.exception("posthog_capture_failed")
# TODO: once AcquisitionPipeline is DI-wired here, route through pipeline.run()
# For now, minimal path: accept + return Calendly URL. Lead is still in PostHog.
log.info(
"demo_request_accepted email=%s company=%s sector=%s",
email,
company,
sector,
)
return {
"ok": True,
"calendly_url": CALENDLY_URL,
"message": "تم استلام طلبك — سنتواصل خلال 4 ساعات عمل",
}
@router.get("/health")
async def public_health() -> dict[str, Any]:
"""Unauthenticated health probe for landing page to show live status."""
return {"ok": True, "service": "dealix-api"}
@router.post("/partner-application")
async def partner_application(req: Request) -> dict[str, Any]:
"""Public partner signup — for agencies/freelancers/consultants."""
try:
body = await req.json()
except Exception:
# Also accept form-urlencoded submissions from Formspree-style forms
form = await req.form()
body = dict(form)
name = str(body.get("name") or "").strip()
company = str(body.get("company") or "").strip()
email = str(body.get("email") or "").strip()
phone = str(body.get("phone") or "").strip()
ptype = str(body.get("partnership_type") or body.get("type") or "referral").strip()
services = str(body.get("services") or "").strip()
active_clients = str(body.get("active_clients") or body.get("clients") or "0")
why = str(body.get("why") or "").strip()
if not name or not company or "@" not in email:
raise HTTPException(status_code=422, detail="missing_required_fields")
log.info(
"partner_application_received company=%s type=%s clients=%s",
company,
ptype,
active_clients,
)
try:
await capture_event(
"partner_application_submitted",
distinct_id=email or company or "anonymous",
properties={
"company": company,
"partnership_type": ptype,
"active_clients": active_clients,
"has_phone": bool(phone),
"has_services": bool(services),
"has_why": bool(why),
"source": "dealix.partners_page",
},
)
except Exception:
log.warning("posthog_capture_failed", exc_info=True)
return {
"ok": True,
"message": "وصلنا طلبك. سنتواصل خلال 48 ساعة.",
"next_step": "email_review",
}