Files
plantillas-proyectos/backend/api/v1/modules/a76/audit_log/router.py

94 lines
3.0 KiB
Python

"""
Audit Log Router
"""
from typing import List, Optional
from datetime import date
from fastapi import APIRouter, Depends, Query, HTTPException
from sqlalchemy.orm import Session
from sqlalchemy import or_, desc, distinct
from core.database import get_core_db
from core.security import get_current_user # Assuming this exists
from .models import AuditLog
from .schemas import AuditLogListResponse, AuditLogResponse, AuditLogDetailResponse
router = APIRouter()
@router.get("/bitacora", response_model=AuditLogListResponse)
async def get_bitacora(
page: int = Query(1, ge=1),
page_size: int = Query(50, ge=1, le=100),
search: Optional[str] = None,
username: Optional[str] = None,
procedure: Optional[str] = None,
reference: Optional[str] = None,
date_from: Optional[date] = None,
date_to: Optional[date] = None,
db: Session = Depends(get_core_db)
):
"""
Get legacy audit log (Bitácora)
"""
query = db.query(AuditLog)
# Filters
if date_from:
query = query.filter(AuditLog.date >= date_from)
if date_to:
query = query.filter(AuditLog.date <= date_to)
if username:
query = query.filter(AuditLog.username.ilike(f"%{username}%"))
if procedure:
# Exact match for dropdown filter usually better, but let's allow partial if manual
# Legacy UI sends exact strings usually
query = query.filter(AuditLog.procedure == procedure)
if reference:
query = query.filter(AuditLog.reference.ilike(f"%{reference}%"))
if search:
# General search across main columns
search_filter = or_(
AuditLog.reference.ilike(f"%{search}%"),
AuditLog.procedure.ilike(f"%{search}%"),
AuditLog.movement.ilike(f"%{search}%"),
AuditLog.username.ilike(f"%{search}%")
)
query = query.filter(search_filter)
total = query.count()
# Sort by ID desc (newest first) -> Legacy usually shows newest first or spec_id desc
logs = query.order_by(desc(AuditLog.spec_id))\
.offset((page - 1) * page_size)\
.limit(page_size)\
.all()
return {
"data": logs,
"total": total,
"page": page,
"page_size": page_size
}
@router.get("/bitacora/procedimientos", response_model=List[str])
async def get_procedures(db: Session = Depends(get_core_db)):
"""
Get distinct list of procedures for filters
"""
results = db.query(distinct(AuditLog.procedure))\
.order_by(AuditLog.procedure)\
.all()
# verify if result is tuple
return [r[0] for r in results if r[0]]
@router.get("/bitacora/{spec_id}/detalle", response_model=AuditLogDetailResponse)
async def get_audit_detail(spec_id: int, db: Session = Depends(get_core_db)):
"""
Get full detail of a log entry
"""
log = db.query(AuditLog).filter(AuditLog.spec_id == spec_id).first()
if not log:
raise HTTPException(status_code=404, detail="Log entry not found")
return log