Files
hackathon-innovaflow5.0-cdf…/backend/app/api/auth.py
shinra32 c91b6e2091 Co-authored-by: MENDOZA BALLARDO GAEL RICARDO <gael-meb123@users.noreply.github.com>
Co-authored-by: Azareth-Tr <Azareth-Tr@users.noreply.github.com>
Co-authored-by: eddgranados12 <eddgranados12@users.noreply.github.com>

implementacion de login, vistas, correcion de errores en vista registro, domicilios
2026-05-22 23:07:24 -06:00

102 lines
3.8 KiB
Python

from fastapi import APIRouter, HTTPException, status
from app.schemas.auth import RegisterRequest, LoginRequest, TokenResponse
from app.core.supabase_client import supabase, supabase_admin
router = APIRouter(prefix="/auth", tags=["auth"])
def _fetch_role(user_id: str) -> str:
result = (
supabase_admin.table("users")
.select("role")
.eq("id", user_id)
.maybe_single()
.execute()
)
return result.data["role"] if result.data else "citizen"
@router.post("/register", response_model=TokenResponse, status_code=status.HTTP_201_CREATED)
def register(body: RegisterRequest):
"""
Registro por email o teléfono.
- Email: flujo estándar Supabase email+password.
- Teléfono: requiere que Supabase tenga configurado un proveedor SMS (Twilio).
"""
if not body.email and not body.phone:
raise HTTPException(status_code=400, detail="Se requiere email o teléfono")
if len(body.password) < 6:
raise HTTPException(status_code=400, detail="La contraseña debe tener al menos 6 caracteres.")
try:
if body.email:
resp = supabase.auth.sign_up({"email": body.email, "password": body.password})
else:
resp = supabase.auth.sign_up({"phone": body.phone, "password": body.password})
except Exception as e:
error_msg = str(e)
if "already registered" in error_msg.lower() or "user already exists" in error_msg.lower():
raise HTTPException(status_code=400, detail="El usuario ya está registrado en el sistema de autenticación.")
if "signups are disabled" in error_msg.lower():
raise HTTPException(status_code=400, detail="El registro de nuevos usuarios está deshabilitado temporalmente.")
if "rate limit" in error_msg.lower():
raise HTTPException(status_code=400, detail="Límite de registros excedido por seguridad. Desactiva la confirmación de correos en Supabase o intenta más tarde.")
raise HTTPException(status_code=400, detail=error_msg)
auth_user = resp.user
if not auth_user:
raise HTTPException(status_code=400, detail="No se pudo crear el usuario en Supabase Auth")
# Crear entrada en public.users con el rol elegido
try:
supabase_admin.table("users").upsert(
{
"id": str(auth_user.id),
"role": body.role,
}
).execute()
except Exception as e:
raise HTTPException(status_code=500, detail=f"Error al guardar el usuario: {e}")
# Si no hubo sesión (email confirmation pendiente)
if not resp.session:
raise HTTPException(
status_code=400,
detail="Cuenta creada. Revisa tu correo para confirmar tu email antes de iniciar sesión.",
)
return TokenResponse(
access_token=resp.session.access_token,
user_id=str(auth_user.id),
role=body.role,
)
@router.post("/login", response_model=TokenResponse)
def login(body: LoginRequest):
"""Login por email o teléfono; devuelve JWT de Supabase."""
if not body.email and not body.phone:
raise HTTPException(status_code=400, detail="Se requiere email o teléfono")
try:
if body.email:
resp = supabase.auth.sign_in_with_password(
{"email": body.email, "password": body.password}
)
else:
resp = supabase.auth.sign_in_with_password(
{"phone": body.phone, "password": body.password}
)
except Exception:
raise HTTPException(status_code=401, detail="Credenciales inválidas")
auth_user = resp.user
role = _fetch_role(str(auth_user.id))
return TokenResponse(
access_token=resp.session.access_token,
user_id=str(auth_user.id),
role=role,
)