import { Injectable } from '@nestjs/common'; import { buildPaginatedResponse } from '../../common/utils/pagination.util'; import { resolveMongoSortDirection } from '../../common/utils/sort.util'; import { AuditRepository } from './audit.repository'; import { escapeRegex } from '../../common/utils/regex.util'; import { AuditQueryDto } from './dto/audit-query.dto'; @Injectable() export class AuditService { constructor(private readonly auditRepository: AuditRepository) {} async logSuperAdminAction( actorIdentifier: string, action: string, targetType: string, targetId?: string, metadata?: Record, ): Promise { await this.auditRepository.create({ actorType: 'superadmin', actorIdentifier, action, targetType, targetId, metadata, }); } async listSuperAdminLogs(query: AuditQueryDto) { const page = query.page ?? 1; const limit = query.limit ?? 20; const skip = (page - 1) * limit; const filter: Record = {}; if (query.q?.trim()) { filter.$or = [ { action: { $regex: escapeRegex(query.q.trim()), $options: 'i' } }, { targetType: { $regex: escapeRegex(query.q.trim()), $options: 'i' } }, { targetId: { $regex: escapeRegex(query.q.trim()), $options: 'i' } }, { actorIdentifier: { $regex: escapeRegex(query.q.trim()), $options: 'i' } }, ]; } if (query.actorType) { filter.actorType = query.actorType; } if (query.targetType?.trim()) { filter.targetType = query.targetType.trim(); } const sort = { createdAt: resolveMongoSortDirection(query.sortOrder) } as Record; const [items, total] = await Promise.all([ this.auditRepository.findMany(filter, skip, limit, sort), this.auditRepository.count(filter), ]); return buildPaginatedResponse(items, { page, limit, total, offset: skip, }); } }