229 lines
6.8 KiB
Python
229 lines
6.8 KiB
Python
from fastapi import APIRouter, Depends, HTTPException, status
|
|
from sqlalchemy.orm import Session
|
|
from src.config.database import get_db
|
|
from src.models.models import User
|
|
from src.schemas.user import (
|
|
UserCreate,
|
|
UserResponse,
|
|
UserLogin,
|
|
TokenResponse,
|
|
ForgotPassword,
|
|
PasswordReset,
|
|
MessageResponse
|
|
)
|
|
from src.services.user_service import (
|
|
create_user,
|
|
verify_email,
|
|
resend_verification,
|
|
forgot_password,
|
|
reset_password
|
|
)
|
|
from src.services.auth_service import (
|
|
authenticate_user,
|
|
create_access_token,
|
|
get_current_admin_user
|
|
)
|
|
import logging
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
router = APIRouter(
|
|
prefix="/auth",
|
|
tags=["autenticação"],
|
|
responses={404: {"description": "Não encontrado"}},
|
|
)
|
|
|
|
@router.post("/register", response_model=UserResponse, status_code=status.HTTP_201_CREATED)
|
|
async def register_user(user_data: UserCreate, db: Session = Depends(get_db)):
|
|
"""
|
|
Registra um novo usuário (cliente) no sistema
|
|
|
|
Args:
|
|
user_data: Dados do usuário a ser registrado
|
|
db: Sessão do banco de dados
|
|
|
|
Returns:
|
|
UserResponse: Dados do usuário criado
|
|
|
|
Raises:
|
|
HTTPException: Se houver erro no registro
|
|
"""
|
|
user, message = create_user(db, user_data, is_admin=False)
|
|
if not user:
|
|
logger.error(f"Erro ao registrar usuário: {message}")
|
|
raise HTTPException(
|
|
status_code=status.HTTP_400_BAD_REQUEST,
|
|
detail=message
|
|
)
|
|
|
|
logger.info(f"Usuário registrado com sucesso: {user.email}")
|
|
return user
|
|
|
|
@router.post("/register-admin", response_model=UserResponse, status_code=status.HTTP_201_CREATED)
|
|
async def register_admin(
|
|
user_data: UserCreate,
|
|
db: Session = Depends(get_db),
|
|
current_admin: User = Depends(get_current_admin_user)
|
|
):
|
|
"""
|
|
Registra um novo administrador no sistema.
|
|
Apenas administradores existentes podem criar novos administradores.
|
|
|
|
Args:
|
|
user_data: Dados do administrador a ser registrado
|
|
db: Sessão do banco de dados
|
|
current_admin: Administrador atual (autenticado)
|
|
|
|
Returns:
|
|
UserResponse: Dados do administrador criado
|
|
|
|
Raises:
|
|
HTTPException: Se houver erro no registro
|
|
"""
|
|
user, message = create_user(db, user_data, is_admin=True)
|
|
if not user:
|
|
logger.error(f"Erro ao registrar administrador: {message}")
|
|
raise HTTPException(
|
|
status_code=status.HTTP_400_BAD_REQUEST,
|
|
detail=message
|
|
)
|
|
|
|
logger.info(f"Administrador registrado com sucesso: {user.email} (criado por {current_admin.email})")
|
|
return user
|
|
|
|
@router.get("/verify-email/{token}", response_model=MessageResponse)
|
|
async def verify_user_email(token: str, db: Session = Depends(get_db)):
|
|
"""
|
|
Verifica o email de um usuário usando o token fornecido
|
|
|
|
Args:
|
|
token: Token de verificação
|
|
db: Sessão do banco de dados
|
|
|
|
Returns:
|
|
MessageResponse: Mensagem de sucesso
|
|
|
|
Raises:
|
|
HTTPException: Se o token for inválido ou expirado
|
|
"""
|
|
success, message = verify_email(db, token)
|
|
if not success:
|
|
logger.warning(f"Falha na verificação de email: {message}")
|
|
raise HTTPException(
|
|
status_code=status.HTTP_400_BAD_REQUEST,
|
|
detail=message
|
|
)
|
|
|
|
logger.info(f"Email verificado com sucesso usando token: {token}")
|
|
return {"message": message}
|
|
|
|
@router.post("/resend-verification", response_model=MessageResponse)
|
|
async def resend_verification_email(
|
|
email_data: ForgotPassword,
|
|
db: Session = Depends(get_db)
|
|
):
|
|
"""
|
|
Reenvia o email de verificação para o usuário
|
|
|
|
Args:
|
|
email_data: Email do usuário
|
|
db: Sessão do banco de dados
|
|
|
|
Returns:
|
|
MessageResponse: Mensagem de sucesso
|
|
|
|
Raises:
|
|
HTTPException: Se houver erro no reenvio
|
|
"""
|
|
success, message = resend_verification(db, email_data.email)
|
|
if not success:
|
|
logger.warning(f"Falha no reenvio de verificação: {message}")
|
|
raise HTTPException(
|
|
status_code=status.HTTP_400_BAD_REQUEST,
|
|
detail=message
|
|
)
|
|
|
|
logger.info(f"Email de verificação reenviado com sucesso para: {email_data.email}")
|
|
return {"message": message}
|
|
|
|
@router.post("/login", response_model=TokenResponse)
|
|
async def login_for_access_token(
|
|
form_data: UserLogin,
|
|
db: Session = Depends(get_db)
|
|
):
|
|
"""
|
|
Realiza login e retorna um token de acesso JWT
|
|
|
|
Args:
|
|
form_data: Dados de login (email e senha)
|
|
db: Sessão do banco de dados
|
|
|
|
Returns:
|
|
TokenResponse: Token de acesso e tipo
|
|
|
|
Raises:
|
|
HTTPException: Se as credenciais forem inválidas
|
|
"""
|
|
user = authenticate_user(db, form_data.email, form_data.password)
|
|
if not user:
|
|
logger.warning(f"Tentativa de login com credenciais inválidas: {form_data.email}")
|
|
raise HTTPException(
|
|
status_code=status.HTTP_401_UNAUTHORIZED,
|
|
detail="Email ou senha incorretos",
|
|
headers={"WWW-Authenticate": "Bearer"},
|
|
)
|
|
|
|
access_token = create_access_token(user)
|
|
logger.info(f"Login realizado com sucesso para usuário: {user.email}")
|
|
return {"access_token": access_token, "token_type": "bearer"}
|
|
|
|
@router.post("/forgot-password", response_model=MessageResponse)
|
|
async def forgot_user_password(
|
|
email_data: ForgotPassword,
|
|
db: Session = Depends(get_db)
|
|
):
|
|
"""
|
|
Inicia o processo de recuperação de senha
|
|
|
|
Args:
|
|
email_data: Email do usuário
|
|
db: Sessão do banco de dados
|
|
|
|
Returns:
|
|
MessageResponse: Mensagem de sucesso
|
|
|
|
Raises:
|
|
HTTPException: Se houver erro no processo
|
|
"""
|
|
success, message = forgot_password(db, email_data.email)
|
|
# Sempre retornamos a mesma mensagem por segurança
|
|
return {"message": "Se o email estiver cadastrado, você receberá instruções para redefinir sua senha."}
|
|
|
|
@router.post("/reset-password", response_model=MessageResponse)
|
|
async def reset_user_password(
|
|
reset_data: PasswordReset,
|
|
db: Session = Depends(get_db)
|
|
):
|
|
"""
|
|
Redefine a senha do usuário usando o token fornecido
|
|
|
|
Args:
|
|
reset_data: Token e nova senha
|
|
db: Sessão do banco de dados
|
|
|
|
Returns:
|
|
MessageResponse: Mensagem de sucesso
|
|
|
|
Raises:
|
|
HTTPException: Se o token for inválido ou expirado
|
|
"""
|
|
success, message = reset_password(db, reset_data.token, reset_data.new_password)
|
|
if not success:
|
|
logger.warning(f"Falha na redefinição de senha: {message}")
|
|
raise HTTPException(
|
|
status_code=status.HTTP_400_BAD_REQUEST,
|
|
detail=message
|
|
)
|
|
|
|
logger.info("Senha redefinida com sucesso")
|
|
return {"message": message} |