import { EventsHandler, IEventHandler } from '@nestjs/cqrs'; import { DataSchedulingUpdatedEvent } from '../../entities/event/data-scheduling-updated.event'; import { DataSchedulingLogEntity, SCHEDULING_LOG_ACTION_ENUM, SCHEDULING_LOG_TYPE_ENUM, } from '../../entities/data-scheduling.entity'; import { decryptionTotal, encryptionTotal, } from '../../../infrastructure/helpers'; import { Logger } from '@nestjs/common'; import { DataSchedulingLogDataService } from '../../../data/services/data-scheduling-log-data.service'; @EventsHandler(DataSchedulingUpdatedEvent) export class DataSchedulingUpdatedHandler implements IEventHandler { private readonly logger = new Logger(DataSchedulingUpdatedHandler.name); constructor(private service: DataSchedulingLogDataService) {} // Map for readable labels private readonly labelMap: { [key: string]: string } = { name: 'Name', indexing_key: 'Total Data', schedule_date_from: 'Start Date', schedule_date_to: 'End Date', }; // Relevant keys for comparing changes private readonly keysToCompare: string[] = [ 'name', 'indexing_key', 'schedule_date_from', 'schedule_date_to', ]; async handle(event: DataSchedulingUpdatedEvent) { const oldData = event?.data?.old; // Decrypt oldData.indexing_key here before comparison if (oldData?.indexing_key !== undefined && oldData?.indexing_key !== null) { oldData.indexing_key = decryptionTotal(oldData.indexing_key); } const newData = event?.data?.data; // Decrypt newData.indexing_key here before comparison if (newData?.indexing_key !== undefined && newData?.indexing_key !== null) { newData.indexing_key = decryptionTotal(newData.indexing_key); } const changingData = this.getChangingData(oldData, newData); const description = this.generateDescription( oldData, newData, changingData, ); const payload: DataSchedulingLogEntity = { type: SCHEDULING_LOG_TYPE_ENUM.DATA_SCHEDULING, action: SCHEDULING_LOG_ACTION_ENUM.UPDATE, log_created_at: new Date().getTime(), data_id: newData?.id, name: newData?.name, indexing_key: encryptionTotal(newData?.indexing_key), schedule_date_from: newData?.schedule_date_from, schedule_date_to: newData?.schedule_date_to, status: newData?.status, creator_id: newData?.creator_id, creator_name: newData?.creator_name, editor_id: newData?.editor_id, editor_name: newData?.editor_name, created_at: newData?.created_at, updated_at: newData?.updated_at, description: description, }; await this.service.create(payload as any); this.logger.verbose( `[SCHEDULING LOG] Update data for ID: ${payload.data_id}`, ); } /** * Compares old and new data to find changes. * @param oldData Data before the change. * @param newData Data after the change. * @returns An object containing the old and new changed data. */ private getChangingData(oldData: any, newData: any): { old: any; new: any } { const changingData: { old: any; new: any } = { old: {}, new: {} }; this.keysToCompare.forEach((key) => { // Ensure comparisons are made on decrypted values if decryption happens before this if (oldData?.[key] !== newData?.[key]) { changingData.old[key] = oldData?.[key]; changingData.new[key] = newData?.[key]; } }); return changingData; } /** * Generates an HTML description string based on data changes. * Includes the name from oldData for identification. * @param oldData Old data, used to get the name of the item. * @param newData New data containing editor information. * @param changingData An object containing the changed data. * @returns The HTML string of the change description. */ private generateDescription( oldData: any, newData: any, changingData: { old: any; new: any }, ): string { const editorName = newData.editor_name || 'System'; const itemName = oldData?.name || 'an item'; let description = `

${editorName} has updated schedule for ${itemName}.`; if (Object.keys(changingData.old).length > 0) { description += ` Change details:

`; } else { description += ` No significant data detail changes.

`; } return description; } }