from fastapi import APIRouter, HTTPException, Request, status from app.config import settings from app.schemas.booking import BookingCaptchaChallenge, BookingRequestCreate, BookingRequestResponse from app.services.booking_security import ( create_captcha_challenge, get_client_ip, is_rate_limited, new_request_id, verify_captcha, write_booking_audit_event, ) from app.services.mailer import MailConfigurationError, send_booking_request_email router = APIRouter(prefix="/api", tags=["booking"]) @router.get("/booking-captcha", response_model=BookingCaptchaChallenge) def get_booking_captcha() -> BookingCaptchaChallenge: return create_captcha_challenge() @router.post("/booking-request", response_model=BookingRequestResponse) def create_booking_request(request: Request, payload: BookingRequestCreate) -> BookingRequestResponse: request_id = new_request_id() write_booking_audit_event("received", request_id=request_id, request=request, payload=payload) if not settings.booking_form_enabled: write_booking_audit_event("blocked_form_disabled", request_id=request_id, request=request, payload=payload) raise HTTPException( status_code=status.HTTP_503_SERVICE_UNAVAILABLE, detail="Form in aggiornamento.", ) if payload.website: write_booking_audit_event("blocked_honeypot", request_id=request_id, request=request, payload=payload) return BookingRequestResponse( message="La richiesta è stata inviata correttamente e sarà presa in carico al più presto dal team.", ) client_ip = get_client_ip(request) if is_rate_limited(client_ip): write_booking_audit_event("blocked_rate_limit", request_id=request_id, request=request, payload=payload) raise HTTPException( status_code=status.HTTP_429_TOO_MANY_REQUESTS, detail="Sono state inviate troppe richieste. Riprova più tardi.", ) if not verify_captcha(payload.captcha_id, payload.captcha_answer): write_booking_audit_event("blocked_captcha", request_id=request_id, request=request, payload=payload) raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="Verifica anti-spam non valida. Ricarica il codice e riprova.", ) try: send_booking_request_email(payload) except MailConfigurationError as exc: write_booking_audit_event( "failed_configuration", request_id=request_id, request=request, payload=payload, error=exc, ) raise HTTPException( status_code=status.HTTP_503_SERVICE_UNAVAILABLE, detail="Il servizio email non è ancora configurato.", ) from exc except Exception as exc: # pragma: no cover - mail delivery path write_booking_audit_event( "failed_delivery", request_id=request_id, request=request, payload=payload, error=exc, ) raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail="Si è verificato un problema durante l'invio della richiesta.", ) from exc write_booking_audit_event("sent", request_id=request_id, request=request, payload=payload) return BookingRequestResponse( message="La richiesta è stata inviata correttamente e sarà presa in carico al più presto dal team.", )