Primi files backend

This commit is contained in:
2026-04-28 17:17:51 +02:00
parent 1ede1d14ab
commit 19bf96d534
12 changed files with 426 additions and 0 deletions
View File
+17
View File
@@ -0,0 +1,17 @@
from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession, async_sessionmaker
from sqlalchemy.orm import DeclarativeBase
from app.core.config import settings
engine = create_async_engine(settings.database_url, echo=False)
AsyncSessionLocal = async_sessionmaker(
bind=engine,
class_=AsyncSession,
expire_on_commit=False,
autocommit=False,
autoflush=False,
)
class Base(DeclarativeBase):
pass
+56
View File
@@ -0,0 +1,56 @@
from typing import AsyncGenerator
from fastapi import Depends, HTTPException, status
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select
from app.core.database import AsyncSessionLocal
from app.core.security import decode_token
bearer_scheme = HTTPBearer()
async def get_db() -> AsyncGenerator[AsyncSession, None]:
async with AsyncSessionLocal() as session:
try:
yield session
finally:
await session.close()
async def get_current_user(
credentials: HTTPAuthorizationCredentials = Depends(bearer_scheme),
db: AsyncSession = Depends(get_db),
):
from app.models.user import User
token = credentials.credentials
payload = decode_token(token)
if not payload or payload.get("type") != "access":
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Token non valido o scaduto",
)
user_id = payload.get("sub")
result = await db.execute(select(User).where(User.id == int(user_id)))
user = result.scalar_one_or_none()
if not user or not user.is_active:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Utente non trovato o disabilitato",
)
return user
def require_roles(*roles: str):
async def checker(current_user=Depends(get_current_user)):
if current_user.role not in roles:
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="Permessi insufficienti",
)
return current_user
return checker
+55
View File
@@ -0,0 +1,55 @@
from contextlib import asynccontextmanager
from fastapi import FastAPI, Request
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import JSONResponse
import structlog
from app.api import auth, health, vehicles, valuations
from app.core.database import engine
from app.core import database as db_module
logger = structlog.get_logger()
@asynccontextmanager
async def lifespan(app: FastAPI):
logger.info("Avvio GMG Smart Quote backend")
yield
await engine.dispose()
logger.info("Shutdown completo")
app = FastAPI(
title="GMG Smart Quote API",
version="1.0.0",
lifespan=lifespan,
)
app.add_middleware(
CORSMiddleware,
allow_origins=[
"http://localhost:3000",
"http://localhost:3001",
"http://localhost:5173",
"http://127.0.0.1:3000",
"http://127.0.0.1:3001",
],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
@app.exception_handler(Exception)
async def global_exception_handler(request: Request, exc: Exception):
logger.error("Unhandled exception", path=request.url.path, error=str(exc))
return JSONResponse(
status_code=500,
content={"detail": "Errore interno del server"},
)
app.include_router(auth.router, prefix="/api/auth", tags=["auth"])
app.include_router(health.router, prefix="/api", tags=["health"])
app.include_router(vehicles.router, prefix="/api/vehicles", tags=["vehicles"])
app.include_router(valuations.router, prefix="/api/valuations", tags=["valuations"])