diff --git a/api/src/api/v1/audit.py b/api/src/api/v1/audit.py index b3b8885..447af00 100644 --- a/api/src/api/v1/audit.py +++ b/api/src/api/v1/audit.py @@ -5,7 +5,7 @@ from src.api.v1.deps import require_admin from src.db.session import get_db # from src.domain.models import Users from src.db.models.app_user import AppUser -from src.domain.schemas import AuditLogListResponse, AuditLogQueryParams +from src.domain.schemas import AuditLog, AuditLogQueryParams, BaseListResponse from src.services.auditlog_service import AuditLogService router = APIRouter(tags=["audit"]) @@ -13,7 +13,7 @@ router = APIRouter(tags=["audit"]) @router.get( "/audit-logs", - response_model=AuditLogListResponse, + response_model=BaseListResponse[AuditLog], status_code=status.HTTP_200_OK, summary="Получение журнала аудита", description="Возвращает список записей аудита с возможностью фильтрации. Доступно только администраторам.", @@ -26,7 +26,7 @@ async def get_audit_logs( offset = (params.page - 1) * params.limit audit_service = AuditLogService(db) - logs = await audit_service.get_all( + logs, count = await audit_service.get_all( user=current_user, limit=params.limit, offset=offset, @@ -39,4 +39,4 @@ async def get_audit_logs( date_to=params.date_to, ) result = [audit_service.orm_log_to_response(log) for log in logs] - return AuditLogListResponse(result=result) + return BaseListResponse(result=result, count=count) diff --git a/api/src/repository/auditlog_repository.py b/api/src/repository/auditlog_repository.py index 88ad73c..f001f7d 100644 --- a/api/src/repository/auditlog_repository.py +++ b/api/src/repository/auditlog_repository.py @@ -3,6 +3,7 @@ from typing import Iterable, Optional from sqlalchemy import select from sqlalchemy.ext.asyncio import AsyncSession +from sqlalchemy.sql.functions import func # from sqlalchemy.orm import selectinload # from app.domain.models import AuditLog @@ -38,24 +39,32 @@ class AuditLogRepository: event_type: str | None = None, date_from: datetime | None = None, date_to: datetime | None = None, - ) -> Iterable[AuditLog]: + ) -> (Iterable[AuditLog], int): """Получение всех записей аудита с опциональной фильтрацией.""" query = select(AuditLog) + query_count = select(func.count(AuditLog.id)) if user_id is not None: query = query.where(AuditLog.user_id == user_id) + query_count = query_count.where(AuditLog.user_id == user_id) if org_unit_id is not None: query = query.where(AuditLog.org_unit_id == org_unit_id) + query_count = query_count.where(AuditLog.org_unit_id == org_unit_id) if task_id is not None: query = query.where(AuditLog.task_id == task_id) + query_count = query_count.where(AuditLog.task_id == task_id) if form_id is not None: query = query.where(AuditLog.form_id == form_id) + query_count = query_count.where(AuditLog.form_id == form_id) if event_type is not None: query = query.where(AuditLog.event_type == event_type) + query_count = query_count.where(AuditLog.event_type == event_type) if date_from is not None: query = query.where(AuditLog.event_dt >= date_from) + query_count = query_count.where(AuditLog.event_dt >= date_from) if date_to is not None: query = query.where(AuditLog.event_dt <= date_to) + query_count = query_count.where(AuditLog.event_dt <= date_to) query = query.order_by(AuditLog.event_dt.desc()) @@ -64,5 +73,7 @@ class AuditLogRepository: if offset is not None: query = query.offset(offset) - return (await self.db.execute(query)).scalars().all() + return (await self.db.execute(query)).scalars().all(), ( + await self.db.execute(query_count) + ).scalar_one() diff --git a/api/src/services/auditlog_service.py b/api/src/services/auditlog_service.py index 4768813..bc203ef 100644 --- a/api/src/services/auditlog_service.py +++ b/api/src/services/auditlog_service.py @@ -43,7 +43,7 @@ class AuditLogService: event_type: str | None = None, date_from: datetime | None = None, date_to: datetime | None = None, - ) -> Iterable[AuditLog]: + ) -> (Iterable[AuditLog], int): """Получение всех записей аудита с опциональной фильтрацией.""" if not self._can_view_audit_logs(user): raise AccessDeniedException( @@ -66,7 +66,7 @@ class AuditLogService: """Проверяет, может ли пользователь просматривать журнал аудита.""" return user.role_id == UserRoleEnum.ADMIN.value - def orm_log_to_response(self, log: Any) -> AuditLogSchema: + 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. """