venorly-api / api.py
tarikmenguc
Update api.py
83e22df
Raw History Blame Contribute Delete
5.68 kB
"""
Venorly - FastAPI Entry Point
"""
import logging
import os
from fastapi import FastAPI, Response, Depends
from fastapi.middleware.cors import CORSMiddleware
from lib.supabase_client import supabase
from lib.pdf_generator import generate_report_pdf
from lib.landing_page_generator import generate_landing_page
from lib.pitch_deck_generator import generate_pitch_deck
from lib.auth_middleware import verify_user_token
logger = logging.getLogger(__name__)
app = FastAPI(title="Venorly API")
raw_origins = os.getenv("ALLOWED_ORIGINS", "http://localhost:3000")
ALLOWED_ORIGINS = [o.strip() for o in raw_origins.split(",") if o.strip()]
allow_all = "*" in ALLOWED_ORIGINS
if allow_all:
ALLOWED_ORIGINS = ["*"]
app.add_middleware(
CORSMiddleware,
allow_origins=ALLOWED_ORIGINS,
allow_credentials=not allow_all,
allow_methods=["*"],
allow_headers=["*"],
)
from routers.scan import router as scan_router
from routers.chat import router as chat_router
from routers.gallery import router as gallery_router
from routers.extension import router as extension_router
app.include_router(scan_router)
app.include_router(chat_router)
app.include_router(gallery_router)
app.include_router(extension_router)
def _get_scan_and_check_owner(scan_id: str, user: dict) -> dict:
"""
Scan'i cek ve caller'in sahibi oldugunu dogrula.
Eksik/yanlis sahiplik → 403.
Bulunamama → 404.
"""
res = supabase.table("scans").select("*").eq("id", scan_id).single().execute()
scan_data = res.data
if not scan_data:
return None # 404
owner_id = scan_data.get("user_id")
caller_id = user.get("sub") or user.get("id")
# Dev modunda veya owner_id henuz yazilmadiysa gecis ver
if user.get("dev_mode") or not owner_id:
return scan_data
if caller_id and owner_id != caller_id:
return False # 403
return scan_data
@app.get("/api/health")
async def health_check():
return {"status": "ok", "message": "Backend is running"}
@app.get("/api/scans/{scan_id}/pdf")
async def get_scan_pdf(
scan_id: str,
user: dict = Depends(verify_user_token),
):
try:
scan_data = _get_scan_and_check_owner(scan_id, user)
if scan_data is None:
return Response(content="Not found", status_code=404)
if scan_data is False:
return Response(content="Forbidden", status_code=403)
pdf_bytes = generate_report_pdf(scan_data)
filename = "Report_" + scan_data.get("category", "Analysis").replace(" ", "_") + ".pdf"
return Response(
content=pdf_bytes,
media_type="application/pdf",
headers={"Content-Disposition": "attachment; filename=" + filename},
)
except Exception as e:
logger.error("PDF generation failed for scan %s: %s", scan_id, e, exc_info=True)
return Response(
content='{"error": "Rapor olusturulamadi. Lutfen tekrar deneyin."}',
media_type="application/json",
status_code=500,
)
@app.get("/api/scans/{scan_id}/landing-page")
async def get_landing_page(
scan_id: str,
user: dict = Depends(verify_user_token),
):
try:
scan_data = _get_scan_and_check_owner(scan_id, user)
if scan_data is None:
return Response(content="Not found", status_code=404)
if scan_data is False:
return Response(content="Forbidden", status_code=403)
full = scan_data.get("full_report") or {}
rj = (full.get("report_json") if isinstance(full, dict) else None) or {}
if not rj:
return Response(content="report_json bulunamadi", status_code=422)
html = generate_landing_page(rj)
category = scan_data.get("category", "landing").replace(" ", "_")
return Response(
content=html,
media_type="text/html",
headers={"Content-Disposition": "attachment; filename=" + category + "_landing.html"},
)
except Exception as e:
logger.error("Landing page failed for scan %s: %s", scan_id, e, exc_info=True)
return Response(
content='{"error": "Landing page olusturulamadi."}',
media_type="application/json",
status_code=500,
)
@app.get("/api/scans/{scan_id}/pitch-deck")
async def get_pitch_deck(
scan_id: str,
user: dict = Depends(verify_user_token),
):
try:
scan_data = _get_scan_and_check_owner(scan_id, user)
if scan_data is None:
return Response(content="Not found", status_code=404)
if scan_data is False:
return Response(content="Forbidden", status_code=403)
full = scan_data.get("full_report") or {}
rj = (full.get("report_json") if isinstance(full, dict) else None) or {}
if not rj:
return Response(content="report_json bulunamadi", status_code=422)
pptx_bytes = generate_pitch_deck(rj)
category = scan_data.get("category", "pitch").replace(" ", "_")
return Response(
content=pptx_bytes,
media_type="application/vnd.openxmlformats-officedocument.presentationml.presentation",
headers={"Content-Disposition": "attachment; filename=" + category + "_pitch.pptx"},
)
except Exception as e:
logger.error("Pitch deck failed for scan %s: %s", scan_id, e, exc_info=True)
return Response(
content='{"error": "Pitch deck olusturulamadi."}',
media_type="application/json",
status_code=500,
)
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8000)