mirror of
https://github.com/DrizzleTime/Foxel.git
synced 2026-05-10 17:43:35 +08:00
125 lines
3.5 KiB
Python
125 lines
3.5 KiB
Python
from typing import Any, Dict, Optional
|
|
|
|
from models.database import AuditLog
|
|
|
|
from .types import AuditAction
|
|
|
|
|
|
class AuditService:
|
|
@classmethod
|
|
async def log(
|
|
cls,
|
|
*,
|
|
action: AuditAction | str,
|
|
description: Optional[str],
|
|
user_id: Optional[int],
|
|
username: Optional[str],
|
|
client_ip: Optional[str],
|
|
method: str,
|
|
path: str,
|
|
status_code: int,
|
|
duration_ms: Optional[float],
|
|
success: bool,
|
|
request_params: Optional[Dict[str, Any]] = None,
|
|
request_body: Optional[Dict[str, Any]] = None,
|
|
error: Optional[str] = None,
|
|
) -> None:
|
|
await AuditLog.create(
|
|
action=str(action),
|
|
description=description,
|
|
user_id=user_id,
|
|
username=username,
|
|
client_ip=client_ip,
|
|
method=method,
|
|
path=path,
|
|
status_code=status_code,
|
|
duration_ms=duration_ms,
|
|
success=success,
|
|
request_params=request_params,
|
|
request_body=request_body,
|
|
error=error,
|
|
)
|
|
|
|
@classmethod
|
|
def _serialize(cls, log: AuditLog) -> Dict[str, Any]:
|
|
return {
|
|
"id": log.id,
|
|
"created_at": log.created_at.isoformat() if log.created_at else None,
|
|
"action": log.action,
|
|
"description": log.description,
|
|
"user_id": log.user_id,
|
|
"username": log.username,
|
|
"client_ip": log.client_ip,
|
|
"method": log.method,
|
|
"path": log.path,
|
|
"status_code": log.status_code,
|
|
"duration_ms": log.duration_ms,
|
|
"success": log.success,
|
|
"request_params": log.request_params,
|
|
"request_body": log.request_body,
|
|
"error": log.error,
|
|
}
|
|
|
|
@classmethod
|
|
def _apply_filters(
|
|
cls,
|
|
*,
|
|
action: str | None = None,
|
|
success: bool | None = None,
|
|
username: str | None = None,
|
|
path: str | None = None,
|
|
start_time=None,
|
|
end_time=None,
|
|
):
|
|
qs = AuditLog.all()
|
|
if action:
|
|
qs = qs.filter(action=action)
|
|
if success is not None:
|
|
qs = qs.filter(success=success)
|
|
if username:
|
|
qs = qs.filter(username__icontains=username)
|
|
if path:
|
|
qs = qs.filter(path__icontains=path)
|
|
if start_time:
|
|
qs = qs.filter(created_at__gte=start_time)
|
|
if end_time:
|
|
qs = qs.filter(created_at__lte=end_time)
|
|
return qs
|
|
|
|
@classmethod
|
|
async def list_logs(
|
|
cls,
|
|
*,
|
|
page: int,
|
|
page_size: int,
|
|
action: str | None = None,
|
|
success: bool | None = None,
|
|
username: str | None = None,
|
|
path: str | None = None,
|
|
start_time=None,
|
|
end_time=None,
|
|
):
|
|
qs = cls._apply_filters(
|
|
action=action,
|
|
success=success,
|
|
username=username,
|
|
path=path,
|
|
start_time=start_time,
|
|
end_time=end_time,
|
|
)
|
|
total = await qs.count()
|
|
offset = (page - 1) * page_size
|
|
items = await qs.order_by("-created_at").offset(offset).limit(page_size)
|
|
return [cls._serialize(log) for log in items], total
|
|
|
|
@classmethod
|
|
async def clear_logs(
|
|
cls,
|
|
*,
|
|
start_time=None,
|
|
end_time=None,
|
|
) -> int:
|
|
qs = cls._apply_filters(start_time=start_time, end_time=end_time)
|
|
deleted_count = await qs.delete()
|
|
return deleted_count
|