93 lines
6.1 KiB
Python
93 lines
6.1 KiB
Python
from fastapi import APIRouter, Depends, HTTPException, status, Query
|
|
from sqlalchemy.orm import Session
|
|
from sqlalchemy import desc, or_, func
|
|
from typing import Optional
|
|
from datetime import datetime
|
|
from ..config.database import get_db
|
|
from ..middleware.auth import get_current_user, authorize_roles
|
|
from ..models.user import User
|
|
from ..models.audit_log import AuditLog
|
|
router = APIRouter(prefix='/audit-logs', tags=['audit-logs'])
|
|
|
|
@router.get('/')
|
|
async def get_audit_logs(action: Optional[str]=Query(None, description='Filter by action'), resource_type: Optional[str]=Query(None, description='Filter by resource type'), user_id: Optional[int]=Query(None, description='Filter by user ID'), status_filter: Optional[str]=Query(None, alias='status', description='Filter by status'), search: Optional[str]=Query(None, description='Search in action, resource_type, or details'), start_date: Optional[str]=Query(None, description='Start date (YYYY-MM-DD)'), end_date: Optional[str]=Query(None, description='End date (YYYY-MM-DD)'), page: int=Query(1, ge=1, description='Page number'), limit: int=Query(20, ge=1, le=100, description='Items per page'), current_user: User=Depends(authorize_roles('admin')), db: Session=Depends(get_db)):
|
|
try:
|
|
query = db.query(AuditLog)
|
|
if action:
|
|
query = query.filter(AuditLog.action.like(f'%{action}%'))
|
|
if resource_type:
|
|
query = query.filter(AuditLog.resource_type == resource_type)
|
|
if user_id:
|
|
query = query.filter(AuditLog.user_id == user_id)
|
|
if status_filter:
|
|
query = query.filter(AuditLog.status == status_filter)
|
|
if search:
|
|
search_filter = or_(AuditLog.action.like(f'%{search}%'), AuditLog.resource_type.like(f'%{search}%'), AuditLog.ip_address.like(f'%{search}%'))
|
|
query = query.filter(search_filter)
|
|
if start_date:
|
|
try:
|
|
start = datetime.strptime(start_date, '%Y-%m-%d')
|
|
query = query.filter(AuditLog.created_at >= start)
|
|
except ValueError:
|
|
pass
|
|
if end_date:
|
|
try:
|
|
end = datetime.strptime(end_date, '%Y-%m-%d')
|
|
end = end.replace(hour=23, minute=59, second=59)
|
|
query = query.filter(AuditLog.created_at <= end)
|
|
except ValueError:
|
|
pass
|
|
total = query.count()
|
|
offset = (page - 1) * limit
|
|
logs = query.order_by(desc(AuditLog.created_at)).offset(offset).limit(limit).all()
|
|
result = []
|
|
for log in logs:
|
|
log_dict = {'id': log.id, 'user_id': log.user_id, 'action': log.action, 'resource_type': log.resource_type, 'resource_id': log.resource_id, 'ip_address': log.ip_address, 'user_agent': log.user_agent, 'request_id': log.request_id, 'details': log.details, 'status': log.status, 'error_message': log.error_message, 'created_at': log.created_at.isoformat() if log.created_at else None}
|
|
if log.user:
|
|
log_dict['user'] = {'id': log.user.id, 'full_name': log.user.full_name, 'email': log.user.email}
|
|
result.append(log_dict)
|
|
return {'status': 'success', 'data': {'logs': result, 'pagination': {'total': total, 'page': page, 'limit': limit, 'totalPages': (total + limit - 1) // limit}}}
|
|
except Exception as e:
|
|
raise HTTPException(status_code=500, detail=str(e))
|
|
|
|
@router.get('/stats')
|
|
async def get_audit_stats(start_date: Optional[str]=Query(None, description='Start date (YYYY-MM-DD)'), end_date: Optional[str]=Query(None, description='End date (YYYY-MM-DD)'), current_user: User=Depends(authorize_roles('admin')), db: Session=Depends(get_db)):
|
|
try:
|
|
query = db.query(AuditLog)
|
|
if start_date:
|
|
try:
|
|
start = datetime.strptime(start_date, '%Y-%m-%d')
|
|
query = query.filter(AuditLog.created_at >= start)
|
|
except ValueError:
|
|
pass
|
|
if end_date:
|
|
try:
|
|
end = datetime.strptime(end_date, '%Y-%m-%d')
|
|
end = end.replace(hour=23, minute=59, second=59)
|
|
query = query.filter(AuditLog.created_at <= end)
|
|
except ValueError:
|
|
pass
|
|
total_logs = query.count()
|
|
success_count = query.filter(AuditLog.status == 'success').count()
|
|
failed_count = query.filter(AuditLog.status == 'failed').count()
|
|
error_count = query.filter(AuditLog.status == 'error').count()
|
|
top_actions = db.query(AuditLog.action, func.count(AuditLog.id).label('count')).group_by(AuditLog.action).order_by(desc('count')).limit(10).all()
|
|
top_resource_types = db.query(AuditLog.resource_type, func.count(AuditLog.id).label('count')).group_by(AuditLog.resource_type).order_by(desc('count')).limit(10).all()
|
|
return {'status': 'success', 'data': {'total': total_logs, 'by_status': {'success': success_count, 'failed': failed_count, 'error': error_count}, 'top_actions': [{'action': action, 'count': count} for action, count in top_actions], 'top_resource_types': [{'resource_type': rt, 'count': count} for rt, count in top_resource_types]}}
|
|
except Exception as e:
|
|
raise HTTPException(status_code=500, detail=str(e))
|
|
|
|
@router.get('/{id}')
|
|
async def get_audit_log_by_id(id: int, current_user: User=Depends(authorize_roles('admin')), db: Session=Depends(get_db)):
|
|
try:
|
|
log = db.query(AuditLog).filter(AuditLog.id == id).first()
|
|
if not log:
|
|
raise HTTPException(status_code=404, detail='Audit log not found')
|
|
log_dict = {'id': log.id, 'user_id': log.user_id, 'action': log.action, 'resource_type': log.resource_type, 'resource_id': log.resource_id, 'ip_address': log.ip_address, 'user_agent': log.user_agent, 'request_id': log.request_id, 'details': log.details, 'status': log.status, 'error_message': log.error_message, 'created_at': log.created_at.isoformat() if log.created_at else None}
|
|
if log.user:
|
|
log_dict['user'] = {'id': log.user.id, 'full_name': log.user.full_name, 'email': log.user.email}
|
|
return {'status': 'success', 'data': {'log': log_dict}}
|
|
except HTTPException:
|
|
raise
|
|
except Exception as e:
|
|
raise HTTPException(status_code=500, detail=str(e)) |