Files
SIB/backend/app/main.py

164 lines
6.4 KiB
Python

"""FastAPI application entry point."""
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from fastapi.staticfiles import StaticFiles
import os
from app.core.config import settings
from app.core.database import init_db, engine
from sqlmodel import Session, select
from app.models.taxi import Taxi
from app.models.shuttle import Shuttle
from app.models.business import Business
from app.models.coupon import Coupon
from app.api.routes import router as routes_router
from app.api.bus_stops import router as bus_stops_router
from app.api.schedules import router as schedules_router
from app.api.coupons import router as coupons_router
from app.api.taxis import router as taxis_router
from app.api.auth import router as auth_router
from app.api.users import router as users_router
from app.api.favorites import router as favorites_router
from app.api.telemetry import router as telemetry_router
from app.api.businesses import router as businesses_router
from app.api.analytics import router as analytics_router
from app.api.reports import router as reports_router
from app.api.shuttles import router as shuttles_router
from contextlib import asynccontextmanager
from alembic.config import Config
from alembic import command
import random
from datetime import datetime, timedelta
@asynccontextmanager
async def lifespan(app: FastAPI):
# Run migrations
try:
alembic_cfg = Config("alembic.ini")
command.upgrade(alembic_cfg, "head")
print("DEBUG: Database migrations completed successfully")
except Exception as e:
print(f"WARNING: Database migrations failed: {e}")
# Fallback to init_db if alembic fails or isn't configured
try:
init_db()
except:
pass
# Seed sample data if empty
with Session(engine) as session:
# 1. Taxis
taxi_count = session.exec(select(Taxi)).first()
if not taxi_count:
sample_taxis = [
Taxi(
owner_name="Don José (Sibu Demo)",
phone_number="+507 6000-0001",
license_plate="T-001-SIBU",
corregimiento="Boquete",
shift="dia",
rating=4.9,
english_speaking=True
),
Taxi(
owner_name="María C. (Sibu Demo)",
phone_number="+507 6000-0002",
license_plate="T-002-SIBU",
corregimiento="Boquete",
shift="tarde",
rating=5.0,
english_speaking=False
)
]
session.add_all(sample_taxis)
session.commit()
# 2. Shuttles
shuttle_count = session.exec(select(Shuttle)).first()
if not shuttle_count:
shuttles_data = [
{'route_name': 'Boquete > Santa Catalina', 'origin': 'Boquete', 'destination': 'Santa Catalina', 'vehicle_type': 'Mini Van', 'company_name': 'Chiriqui Transfers', 'trip_type': 'one_way', 'price_per_person': 35.0, 'estimated_duration': '4.5 horas', 'departure_times': '8:00 AM', 'contact_whatsapp': '+50760000000', 'is_active': True},
{'route_name': 'Boquete > Bocas del Toro', 'origin': 'Boquete', 'destination': 'Bocas del Toro', 'vehicle_type': 'Van + Bote', 'company_name': 'Hello Panama', 'trip_type': 'one_way', 'price_per_person': 30.0, 'estimated_duration': '3.5 horas', 'departure_times': '8:00 AM', 'contact_whatsapp': '+50760000000', 'is_active': True}
]
for data in shuttles_data:
session.add(Shuttle(**data))
session.commit()
# 3. Businesses & Coupons (Tourist spots)
biz_count = session.exec(select(Business)).first()
if not biz_count:
tourist_spots = [
{"name": "Finca El Explorador", "area": "Boquete", "lat": 8.7845, "lng": -82.4350},
{"name": "Cascada San Ramón", "area": "Boquete", "lat": 8.8120, "lng": -82.4650}
]
for spot in tourist_spots:
biz = Business(name=spot["name"], address=f"Sector {spot['area']}", phone="6000-0000", category="Area Turistica", area=spot["area"], latitude=spot["lat"], longitude=spot["lng"])
session.add(biz)
session.flush()
coupon = Coupon(title=f"Oferta en {biz.name}", description=f"Descuento especial en {biz.name}", business_id=biz.id, business_name=biz.name, business_address=biz.address, business_phone=biz.phone, category=biz.category, discount_percentage=15, valid_from=datetime.now().isoformat(), valid_until=(datetime.now() + timedelta(days=30)).isoformat(), is_active=True)
session.add(coupon)
session.commit()
yield
app = FastAPI(
title="SIBU Transportation API",
description="API for SIBU public transportation system",
version="1.0.0",
debug=settings.debug,
lifespan=lifespan
)
# CORS middleware
origins = [
"http://localhost:5173",
"http://127.0.0.1:5173",
"https://sibu-frontend.vercel.app",
"https://sibu-transport.web.app",
"https://sibu2-0-transport-2026.firebaseapp.com",
"https://sibu2-0-transport-2026.web.app",
]
app.add_middleware(
CORSMiddleware,
allow_origins=origins,
allow_origin_regex="https://.*sibu.*\.vercel\.app", # Permitir subdominios de vercel con 'sibu'
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# Ensure upload directories exist
for sub in ["profiles", "vehicles", "businesses"]:
os.makedirs(os.path.join("uploads", sub), exist_ok=True)
# Mount static files
app.mount("/uploads", StaticFiles(directory="uploads"), name="uploads")
# Include routers
app.include_router(routes_router)
app.include_router(bus_stops_router)
app.include_router(schedules_router)
app.include_router(coupons_router)
app.include_router(taxis_router)
app.include_router(auth_router)
app.include_router(users_router)
app.include_router(favorites_router)
app.include_router(telemetry_router)
app.include_router(businesses_router)
app.include_router(analytics_router, prefix="/api/analytics", tags=["analytics"])
app.include_router(reports_router)
app.include_router(shuttles_router)
@app.get("/")
async def root():
"""Root endpoint."""
return {"message": "SIBU Transportation API", "version": "1.0.0"}
@app.get("/health")
async def health():
"""Health check endpoint."""
return {"status": "healthy", "environment": settings.environment}