from datetime import datetime from typing import Any, Dict, Iterable, Optional from sqlalchemy.ext.asyncio import AsyncSession from src.core.errors import AccessDeniedException # from src.domain.models import AuditLog, UserRole, Users from src.db.models.audit_log import AuditLog from src.db.models.role import UserRoleEnum from src.db.models.app_user import AppUser from src.repository.auditlog_repository import AuditLogRepository from src.domain.schemas import AuditLog as AuditLogSchema class AuditLogService: """Сервис для работы с журналом аудита.""" def __init__(self, db: AsyncSession): self.db = db self.audit_repo = AuditLogRepository(db) async def get(self, audit_log_id: int, user: AppUser) -> Optional[AuditLog]: """Получение записи аудита по ID.""" if not self._can_view_audit_logs(user): raise AccessDeniedException( "Недостаточно прав для просмотра журнала аудита" ) return await self.audit_repo.get(audit_log_id) async def get_all( self, user: AppUser, limit: int | None = None, offset: int | None = None, user_id: int | None = None, org_unit_id: int | None = None, task_id: int | None = None, form_id: int | None = None, event_type: str | None = None, event: str | None = None, date_from: datetime | None = None, date_to: datetime | None = None, ) -> tuple[Iterable[AuditLog], int]: """Получение всех записей аудита с опциональной фильтрацией.""" if not self._can_view_audit_logs(user): raise AccessDeniedException( "Недостаточно прав для просмотра журнала аудита" ) return await self.audit_repo.get_all( limit=limit, offset=offset, user_id=user_id, org_unit_id=org_unit_id, task_id=task_id, form_id=form_id, event_type=event_type, date_from=date_from, date_to=date_to, event=event, ) def _can_view_audit_logs(self, user: AppUser) -> bool: """Проверяет, может ли пользователь просматривать журнал аудита.""" return user.role_id == UserRoleEnum.ADMIN.value def orm_log_to_response(self, log: AuditLog) -> AuditLogSchema: """Маппинг записи ORM audit_log в формат ответа API (entity, entity_id, action, at, payload_json). model_validate(orm) не подходит: в БД поля event_dt/event/event_type/event_data, в API — at/action/entity/entity_id; entity и entity_id из event_data JSON. """ event_data: Optional[Dict[str, Any]] = getattr(log, "event_data", None) or {} entity = ( event_data.get("entity_type") if isinstance(event_data, dict) else None ) or getattr(log, "event_type", "unknown") entity_id = ( event_data.get("entity_id") if isinstance(event_data, dict) else None ) if entity_id is not None and not isinstance(entity_id, int): try: entity_id = int(entity_id) except (TypeError, ValueError): entity_id = None action = getattr(log, "event", "") at = getattr(log, "event_dt", None) return AuditLogSchema( entity=entity, entity_id=entity_id, action=action, payload_json=event_data if isinstance(event_data, dict) else None, id=log.id, user_id=getattr(log, "user_id", None), at=at, user=getattr(log, "user", None), )