feat: Integrar AuditService en todos los endpoints críticos

- Auth: login, logout, login_failed con registro automático
- Tickets: create, update, delete, assign con old/new values
- Users: create, update, delete con sanitización de passwords
- Stats: implementar top_users con JOIN a tabla users
- Schema: agregar índices compuestos para mejor performance
- Frontend: limpiar logs de debug en viewDetail
- Manejo de errores: audit logs no afectan flujo principal
This commit is contained in:
2026-02-16 09:08:03 -07:00
parent 2cb8b58808
commit 87e094b668
7 changed files with 288 additions and 17 deletions

View File

@@ -18,6 +18,7 @@ from app.core.security import security
from app.core.config import get_settings
from app.models.user import User
from app.models.tenant import Tenant
from app.services.audit_service import AuditService
router = APIRouter()
logger = structlog.get_logger(__name__)
@@ -99,6 +100,23 @@ async def login(
"Login failed - invalid credentials",
email=login_data.email
)
# Registrar intento fallido en auditoría (si el usuario existe)
if user:
try:
await AuditService.log(
db=db,
tenant_id=user.tenant_id,
user_id=None, # Login fallido = sin user_id
action="user.login_failed",
resource_type="user",
resource_id=user.id,
metadata={"email": login_data.email, "reason": "invalid_password"}
)
await db.commit()
except Exception as e:
logger.warning("Failed to log audit entry", error=str(e))
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Credenciales inválidas"
@@ -126,6 +144,21 @@ async def login(
access_token = security.create_access_token(token_data)
refresh_token = security.create_refresh_token(token_data)
# Registrar login exitoso en auditoría
try:
await AuditService.log(
db=db,
tenant_id=user.tenant_id,
user_id=user.id,
action="user.login",
resource_type="user",
resource_id=user.id,
metadata={"email": user.email, "success": True}
)
await db.commit()
except Exception as e:
logger.warning("Failed to log audit entry", error=str(e))
logger.info(
"Login successful",
email=login_data.email,
@@ -227,6 +260,25 @@ async def logout(
# TODO: Revoke refresh token in database
# Registrar logout en auditoría
try:
import uuid
user_id = uuid.UUID(payload["sub"])
tenant_id = uuid.UUID(payload["tenant_id"])
await AuditService.log(
db=db,
tenant_id=tenant_id,
user_id=user_id,
action="user.logout",
resource_type="user",
resource_id=user_id,
metadata={"email": payload.get("email")}
)
await db.commit()
except Exception as e:
logger.warning("Failed to log audit entry", error=str(e))
logger.info("Logout successful", user_id=payload["sub"])
return {"message": "Successfully logged out"}