mirror of
http://88.130.71.182:3000/BlitTech/contexta_be.git
synced 2026-06-12 23:23:21 +00:00
151 lines
5.1 KiB
Python
151 lines
5.1 KiB
Python
from fastapi import APIRouter, HTTPException, Depends, Query
|
|
from fastapi.responses import StreamingResponse
|
|
from app.database import get_supabase
|
|
from app.dependencies import get_current_user
|
|
from app.models import LeadCreate, LeadResponse
|
|
from typing import List, Optional
|
|
import uuid
|
|
import csv
|
|
import io
|
|
import logging
|
|
|
|
logger = logging.getLogger(__name__)
|
|
router = APIRouter(prefix="/leads", tags=["Leads"])
|
|
|
|
|
|
def _get_user_company_id(user_id: str, supabase) -> str:
|
|
result = supabase.table("companies").select("id").eq("owner_id", user_id).execute()
|
|
if not result.data:
|
|
raise HTTPException(status_code=404, detail="Company not found")
|
|
return result.data[0]["id"]
|
|
|
|
|
|
def _check_leads_access(user_id: str, supabase):
|
|
sub = supabase.table("subscriptions").select("plan").eq("user_id", user_id).eq("status", "active").execute()
|
|
plan = sub.data[0]["plan"] if sub.data else "free"
|
|
if plan not in ("starter", "business", "agency", "enterprise"):
|
|
raise HTTPException(status_code=402, detail="Lead capture requires Starter plan or higher")
|
|
return plan
|
|
|
|
|
|
@router.get("", response_model=List[LeadResponse])
|
|
async def list_leads(
|
|
chatbot_id: Optional[str] = Query(None),
|
|
page: int = Query(1, ge=1),
|
|
limit: int = Query(50, ge=1, le=200),
|
|
user=Depends(get_current_user),
|
|
):
|
|
"""List leads for the user's chatbots."""
|
|
supabase = get_supabase()
|
|
_check_leads_access(user.id, supabase)
|
|
company_id = _get_user_company_id(user.id, supabase)
|
|
|
|
# Get owned chatbot IDs
|
|
chatbots_q = supabase.table("chatbots").select("id").eq("company_id", company_id)
|
|
if chatbot_id:
|
|
chatbots_q = chatbots_q.eq("id", chatbot_id)
|
|
chatbots = chatbots_q.execute()
|
|
chatbot_ids = [c["id"] for c in (chatbots.data or [])]
|
|
|
|
if not chatbot_ids:
|
|
return []
|
|
|
|
offset = (page - 1) * limit
|
|
result = supabase.table("leads").select("*") \
|
|
.in_("chatbot_id", chatbot_ids) \
|
|
.order("created_at", desc=True) \
|
|
.range(offset, offset + limit - 1) \
|
|
.execute()
|
|
|
|
return [LeadResponse(**lead) for lead in (result.data or [])]
|
|
|
|
|
|
@router.get("/export")
|
|
async def export_leads_csv(
|
|
chatbot_id: Optional[str] = Query(None),
|
|
user=Depends(get_current_user),
|
|
):
|
|
"""Export leads as CSV file."""
|
|
supabase = get_supabase()
|
|
_check_leads_access(user.id, supabase)
|
|
company_id = _get_user_company_id(user.id, supabase)
|
|
|
|
chatbots_q = supabase.table("chatbots").select("id").eq("company_id", company_id)
|
|
if chatbot_id:
|
|
chatbots_q = chatbots_q.eq("id", chatbot_id)
|
|
chatbots = chatbots_q.execute()
|
|
chatbot_ids = [c["id"] for c in (chatbots.data or [])]
|
|
|
|
if not chatbot_ids:
|
|
leads_data = []
|
|
else:
|
|
result = supabase.table("leads").select("*") \
|
|
.in_("chatbot_id", chatbot_ids) \
|
|
.order("created_at", desc=True) \
|
|
.execute()
|
|
leads_data = result.data or []
|
|
|
|
# Build CSV
|
|
output = io.StringIO()
|
|
writer = csv.DictWriter(output, fieldnames=["id", "chatbot_id", "email", "name", "phone", "company", "created_at"])
|
|
writer.writeheader()
|
|
for lead in leads_data:
|
|
writer.writerow({
|
|
"id": lead.get("id", ""),
|
|
"chatbot_id": lead.get("chatbot_id", ""),
|
|
"email": lead.get("email", ""),
|
|
"name": lead.get("name", ""),
|
|
"phone": lead.get("phone", ""),
|
|
"company": lead.get("company", ""),
|
|
"created_at": lead.get("created_at", ""),
|
|
})
|
|
|
|
csv_bytes = output.getvalue().encode("utf-8")
|
|
return StreamingResponse(
|
|
iter([csv_bytes]),
|
|
media_type="text/csv",
|
|
headers={"Content-Disposition": "attachment; filename=leads.csv"},
|
|
)
|
|
|
|
|
|
# Public endpoint — no auth required
|
|
leads_public_router = APIRouter(tags=["Leads"])
|
|
|
|
|
|
@leads_public_router.post("/chatbots/{chatbot_id}/leads", response_model=LeadResponse, status_code=201)
|
|
async def submit_lead(chatbot_id: str, data: LeadCreate):
|
|
"""Submit a lead for a chatbot (public endpoint, no auth required)."""
|
|
supabase = get_supabase()
|
|
|
|
# Verify chatbot exists
|
|
chatbot = supabase.table("chatbots").select("id, lead_capture_enabled").eq("id", chatbot_id).execute()
|
|
if not chatbot.data:
|
|
raise HTTPException(status_code=404, detail="Chatbot not found")
|
|
if not chatbot.data[0].get("lead_capture_enabled", False):
|
|
raise HTTPException(status_code=400, detail="Lead capture not enabled for this chatbot")
|
|
|
|
# Deduplicate by email+chatbot_id
|
|
if data.email:
|
|
existing = supabase.table("leads").select("*") \
|
|
.eq("chatbot_id", chatbot_id) \
|
|
.eq("email", data.email) \
|
|
.execute()
|
|
if existing.data:
|
|
return LeadResponse(**existing.data[0])
|
|
|
|
lead_data = {
|
|
"id": str(uuid.uuid4()),
|
|
"chatbot_id": chatbot_id,
|
|
"conversation_id": data.conversation_id,
|
|
"email": data.email,
|
|
"name": data.name,
|
|
"phone": data.phone,
|
|
"company": data.company,
|
|
}
|
|
|
|
result = supabase.table("leads").insert(lead_data).execute()
|
|
if not result.data:
|
|
raise HTTPException(status_code=500, detail="Failed to save lead")
|
|
|
|
return LeadResponse(**result.data[0])
|