import { Injectable, Inject, Logger, Optional } from '@nestjs/common'; import { REQUEST } from '@nestjs/core'; import { PrismaService } from './prisma.service'; @Injectable() export class AuditService { private readonly logger = new Logger(AuditService.name); constructor( private prisma: PrismaService, @Optional() @Inject(REQUEST) private request?: any, ) {} async log(input: { userId?: string; action: 'CREATE' | 'UPDATE' | 'DELETE' | 'LOGIN' | 'LOGOUT' | 'VERIFY' | string; entityType: string; entityId?: string; oldData?: any; newData?: any; }) { try { const ipAddress = this.getIpAddress(); const userAgent = this.getUserAgent(); await this.prisma.auditLog.create({ data: { iamUserId: input.userId, action: input.action, entityType: input.entityType, entityId: input.entityId, oldData: input.oldData, newData: input.newData, ipAddress, userAgent, }, }); } catch (error) { this.logger.error('Failed to log audit event:', error); // Don't throw - audit logging should not break main operations } } private getIpAddress(): string { if (!this.request) return ''; return ( this.request.headers['x-forwarded-for']?.split(',')[0].trim() || this.request.headers['x-real-ip'] || this.request.connection?.remoteAddress || this.request.socket?.remoteAddress || this.request.ip || '' ); } private getUserAgent(): string { return this.request?.headers?.['user-agent'] || ''; } async getLogs(filters: any = {}) { const where: any = {}; if (filters.search) { where.OR = [ { entityId: { contains: filters.search, mode: 'insensitive' } }, { iamUserId: { contains: filters.search, mode: 'insensitive' } }, ]; } if (filters.action) { where.action = filters.action; } if (filters.entityType) { where.entityType = filters.entityType; } const limit = Math.min(filters.limit ?? 50, 200); const offset = filters.offset ?? 0; const [data, total] = await Promise.all([ this.prisma.auditLog.findMany({ where, orderBy: { createdAt: 'desc' }, take: limit, skip: offset, }), this.prisma.auditLog.count({ where }), ]); return { data, total, limit, offset }; } async getLog(id: string) { return this.prisma.auditLog.findUnique({ where: { id } }); } }