149 lines
4.9 KiB
TypeScript
149 lines
4.9 KiB
TypeScript
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<DataSchedulingUpdatedEvent>
|
|
{
|
|
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 = `<p><b>${editorName}</b> has updated schedule for <b>${itemName}</b>.`;
|
|
|
|
if (Object.keys(changingData.old).length > 0) {
|
|
description += ` Change details:<ul>`;
|
|
for (const key in changingData.old) {
|
|
if (Object.prototype.hasOwnProperty.call(changingData.old, key)) {
|
|
const label = this.labelMap[key] || key;
|
|
let oldValue = changingData.old[key] || 'empty';
|
|
let newValue = changingData.new[key] || 'empty';
|
|
|
|
// Add '%' suffix if the key is 'indexing_key'
|
|
if (key === 'indexing_key') {
|
|
oldValue = `${oldValue}%`;
|
|
newValue = `${newValue}%`;
|
|
}
|
|
|
|
description += `<li><b>${label}</b> changed from <i>${oldValue}</i> to <i>${newValue}</i>.</li>`;
|
|
}
|
|
}
|
|
description += `</ul></p>`;
|
|
} else {
|
|
description += ` No significant data detail changes.</p>`;
|
|
}
|
|
|
|
return description;
|
|
}
|
|
}
|