91 lines
2.9 KiB
Python
91 lines
2.9 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")
|
|
|
|
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:
|
|
raise HTTPException(status_code=400, detail=str(e))
|
|
|
|
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
|
|
supabase_admin.table("users").upsert(
|
|
{
|
|
"id": str(auth_user.id),
|
|
"email": body.email,
|
|
"phone": body.phone,
|
|
"role": body.role,
|
|
}
|
|
).execute()
|
|
|
|
# Si no hubo sesión (email confirmation pendiente) devolvemos token vacío con aviso
|
|
if not resp.session:
|
|
raise HTTPException(
|
|
status_code=202,
|
|
detail="Cuenta creada. Confirma 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,
|
|
)
|