from datetime import datetime from typing import Optional, List from uuid import UUID from sqlalchemy import func, select from sqlalchemy.ext.asyncio import AsyncSession from app.domain.schemas.audit import AuditLogResponse from app.infra.db.metadata import models class AuditRepository: """审计日志数据访问层(system_hub)""" def __init__(self, session: AsyncSession): self.session = session async def create_log( self, action: str, user_id: Optional[UUID] = None, project_id: Optional[UUID] = None, resource_type: Optional[str] = None, resource_id: Optional[str] = None, ip_address: Optional[str] = None, request_method: Optional[str] = None, request_path: Optional[str] = None, request_data: Optional[dict] = None, response_status: Optional[int] = None, ) -> AuditLogResponse: log = models.AuditLog( user_id=user_id, project_id=project_id, action=action, resource_type=resource_type, resource_id=resource_id, ip_address=ip_address, request_method=request_method, request_path=request_path, request_data=request_data, response_status=response_status, timestamp=datetime.utcnow(), ) self.session.add(log) await self.session.commit() await self.session.refresh(log) return AuditLogResponse.model_validate(log) async def get_logs( self, user_id: Optional[UUID] = None, project_id: Optional[UUID] = None, action: Optional[str] = None, resource_type: Optional[str] = None, start_time: Optional[datetime] = None, end_time: Optional[datetime] = None, skip: int = 0, limit: int = 100, ) -> List[AuditLogResponse]: conditions = [] if user_id is not None: conditions.append(models.AuditLog.user_id == user_id) if project_id is not None: conditions.append(models.AuditLog.project_id == project_id) if action: conditions.append(models.AuditLog.action == action) if resource_type: conditions.append(models.AuditLog.resource_type == resource_type) if start_time: conditions.append(models.AuditLog.timestamp >= start_time) if end_time: conditions.append(models.AuditLog.timestamp <= end_time) stmt = ( select(models.AuditLog) .where(*conditions) .order_by(models.AuditLog.timestamp.desc()) .offset(skip) .limit(limit) ) result = await self.session.execute(stmt) return [ AuditLogResponse.model_validate(log) for log in result.scalars().all() ] async def get_log_count( self, user_id: Optional[UUID] = None, project_id: Optional[UUID] = None, action: Optional[str] = None, resource_type: Optional[str] = None, start_time: Optional[datetime] = None, end_time: Optional[datetime] = None, ) -> int: conditions = [] if user_id is not None: conditions.append(models.AuditLog.user_id == user_id) if project_id is not None: conditions.append(models.AuditLog.project_id == project_id) if action: conditions.append(models.AuditLog.action == action) if resource_type: conditions.append(models.AuditLog.resource_type == resource_type) if start_time: conditions.append(models.AuditLog.timestamp >= start_time) if end_time: conditions.append(models.AuditLog.timestamp <= end_time) stmt = select(func.count()).select_from(models.AuditLog).where(*conditions) result = await self.session.execute(stmt) return int(result.scalar() or 0)