From 58a4da9bb1e00f015dde6c12a14f88db073782cb Mon Sep 17 00:00:00 2001 From: GloireMutaliko21 Date: Thu, 17 Oct 2024 09:18:14 +0200 Subject: [PATCH 1/8] fix: activity log event use generic method --- .../src/activity-log/activity-log.helper.ts | 108 +++++++++++++++++- .../organization-project-module.service.ts | 67 ++++------- .../organization-sprint.service.ts | 68 ++++------- .../resource-link/resource-link.service.ts | 73 ++++-------- .../handlers/automation-task.sync.handler.ts | 46 +++++++- .../commands/handlers/task-create.handler.ts | 44 ++----- packages/core/src/tasks/task.service.ts | 42 +++---- packages/core/src/tasks/views/view.service.ts | 81 +++++-------- 8 files changed, 260 insertions(+), 269 deletions(-) diff --git a/packages/core/src/activity-log/activity-log.helper.ts b/packages/core/src/activity-log/activity-log.helper.ts index d4825c47c6..58da51d5de 100644 --- a/packages/core/src/activity-log/activity-log.helper.ts +++ b/packages/core/src/activity-log/activity-log.helper.ts @@ -1,4 +1,6 @@ -import { ActionTypeEnum, BaseEntityEnum, IActivityLogUpdatedValues } from '@gauzy/contracts'; +import { EventBus } from '@nestjs/cqrs'; +import { ActionTypeEnum, ActorTypeEnum, BaseEntityEnum, IActivityLogUpdatedValues, ID } from '@gauzy/contracts'; +import { ActivityLogEvent } from './events'; const ActivityTemplates = { [ActionTypeEnum.Created]: `{action} a new {entity} called "{entityName}"`, @@ -36,21 +38,119 @@ export function generateActivityLogDescription( }); } -export function activityLogUpdatedFieldsAndValues(original: T, updated: Partial) { +/** + * @description Log updated field names, old and new values for Activity Log Updated Actions + * @template T + * @param {T} originalValues - Old values before update + * @param {Partial} updated - Updated values + * @returns An object with updated fields, their old and new values + */ +export function activityLogUpdatedFieldsAndValues(originalValues: T, updated: Partial) { const updatedFields: string[] = []; const previousValues: IActivityLogUpdatedValues[] = []; const updatedValues: IActivityLogUpdatedValues[] = []; for (const key of Object.keys(updated)) { - if (original[key] !== updated[key]) { + if (originalValues[key] !== updated[key]) { // Add updated field updatedFields.push(key); // Add old and new values - previousValues.push({ [key]: original[key] }); + previousValues.push({ [key]: originalValues[key] }); updatedValues.push({ [key]: updated[key] }); } } return { updatedFields, previousValues, updatedValues }; } + +/** + * @description Create activity log for Action "Created" + * @template T + * @param {EventBus} eventBus - CQRS event to log activity + * @param {BaseEntityEnum} entityType - Entity type for whom creating activity log (E.g : Task, OrganizationProject, etc.) + * @param {string} entityName - Name or Title of created entity + * @param {ActorTypeEnum} actor - The actor type perfomed action (User or System) + * @param {ID} organizationId + * @param {ID} tenantId + * @param {T} data - Created entity data + */ +export function activityLogCreateAction( + eventBus: EventBus, + entityType: BaseEntityEnum, + entityName: string, + actor: ActorTypeEnum, + organizationId: ID, + tenantId: ID, + data: T +) { + // Generate the activity log description + const description = generateActivityLogDescription(ActionTypeEnum.Created, entityType, entityName); + + console.log(`Generating activity log description: ${description}`); + + // Emit an event to log the activity + return eventBus.publish( + new ActivityLogEvent({ + entity: entityType, + entityId: data['id'], + action: ActionTypeEnum.Created, + actorType: actor, + description, + data, + organizationId, + tenantId + }) + ); +} + +/** + * @description Create Activity Log for Action "Updated" + * @template T + * @param {EventBus} eventBus - CQRS event to log activity + * @param {BaseEntityEnum} entityType - Entity type for whom creating activity log (E.g : Task, OrganizationProject, etc.) + * @param {string} entityName - Name or Title of created entity + * @param {ActorTypeEnum} actor - The actor type perfomed action (User or System) + * @param {ID} organizationId + * @param {ID} tenantId + * @param {Partial} originalValues - entity data before update + * @param {Partial} newValues - entity upated data per field + * @param {T} data - Updated entity data += */ +export function activityLogUpdateAction( + eventBus: EventBus, + entityType: BaseEntityEnum, + entityName: string, + actor: ActorTypeEnum, + organizationId: ID, + tenantId: ID, + originalValues: Partial, + newValues: Partial, + data: T +) { + // Generate the activity log description + const description = generateActivityLogDescription(ActionTypeEnum.Updated, entityType, entityName); + + // Retrieve updated fields, their old and new values + const { updatedFields, previousValues, updatedValues } = activityLogUpdatedFieldsAndValues( + originalValues, + newValues + ); + + // Emit an event to log the activity + return eventBus.publish( + new ActivityLogEvent({ + entity: entityType, + entityId: data['id'], + action: ActionTypeEnum.Updated, + actorType: actor, + description, + updatedFields, + updatedValues, + previousValues, + data, + organizationId, + tenantId + }) + ); +} diff --git a/packages/core/src/organization-project-module/organization-project-module.service.ts b/packages/core/src/organization-project-module/organization-project-module.service.ts index c6cf041e4c..5c3cef49cb 100644 --- a/packages/core/src/organization-project-module/organization-project-module.service.ts +++ b/packages/core/src/organization-project-module/organization-project-module.service.ts @@ -2,7 +2,6 @@ import { BadRequestException, HttpException, HttpStatus, Injectable } from '@nes import { EventBus } from '@nestjs/cqrs'; import { Brackets, FindManyOptions, SelectQueryBuilder, UpdateResult, WhereExpressionBuilder } from 'typeorm'; import { - ActionTypeEnum, BaseEntityEnum, ActorTypeEnum, ID, @@ -18,8 +17,7 @@ import { isEmpty, isNotEmpty } from '@gauzy/common'; import { isPostgres } from '@gauzy/config'; import { PaginationParams, TenantAwareCrudService } from './../core/crud'; import { RequestContext } from '../core/context'; -import { ActivityLogEvent } from '../activity-log/events'; -import { activityLogUpdatedFieldsAndValues, generateActivityLogDescription } from '../activity-log/activity-log.helper'; +import { activityLogCreateAction, activityLogUpdateAction } from '../activity-log/activity-log.helper'; import { OrganizationProjectModule } from './organization-project-module.entity'; import { prepareSQLQuery as p } from './../database/database.helper'; import { TypeOrmOrganizationProjectModuleRepository } from './repository/type-orm-organization-project-module.repository'; @@ -51,25 +49,15 @@ export class OrganizationProjectModuleService extends TenantAwareCrudService { creatorId: user.id }); - // Generate the activity log description. - const description = generateActivityLogDescription( - ActionTypeEnum.Created, + // Generate the activity log + activityLogCreateAction( + this._eventBus, BaseEntityEnum.ResourceLink, - `${resourceLink.title} for ${resourceLink.entity}` + resourceLink.title, + ActorTypeEnum.User, + resourceLink.organizationId, + tenantId, + resourceLink ); - this.logActivity(ActionTypeEnum.Created, resourceLink, description); return resourceLink; } catch (error) { @@ -89,27 +90,18 @@ export class ResourceLinkService extends TenantAwareCrudService { id }); - // Compare values before and after update then add updates to fields - const { updatedFields, previousValues, updatedValues } = activityLogUpdatedFieldsAndValues( - updatedResourceLink, - input - ); - - // Generate the activity log description. - const description = generateActivityLogDescription( - ActionTypeEnum.Updated, + // Generate the activity log + const { organizationId, tenantId } = updatedResourceLink; + activityLogUpdateAction( + this._eventBus, BaseEntityEnum.ResourceLink, - `${resourceLink.title} for ${resourceLink.entity}` - ); - - //Log activity - this.logActivity( - ActionTypeEnum.Updated, - updatedResourceLink, - description, - updatedFields, - previousValues, - updatedValues + `${resourceLink.title} for ${resourceLink.entity}`, + ActorTypeEnum.User, + organizationId, + tenantId, + resourceLink, + input, + updatedResourceLink ); // return updated Resource Link @@ -119,29 +111,4 @@ export class ResourceLinkService extends TenantAwareCrudService { throw new BadRequestException('Resource Link update failed', error); } } - - private logActivity( - action: ActionTypeEnum, - resourceLink: ResourceLink, - description: string, - updatedFields?: string[], - previousValues?: any, - updatedValues?: any - ) { - this._eventBus.publish( - new ActivityLogEvent({ - entity: BaseEntityEnum.ResourceLink, - entityId: resourceLink.id, - action, - actorType: ActorTypeEnum.User, - description, - updatedFields, - updatedValues, - previousValues, - data: resourceLink, - organizationId: resourceLink.organizationId, - tenantId: resourceLink.tenantId - }) - ); - } } diff --git a/packages/core/src/tasks/commands/handlers/automation-task.sync.handler.ts b/packages/core/src/tasks/commands/handlers/automation-task.sync.handler.ts index 0559acc301..e3a525ac83 100644 --- a/packages/core/src/tasks/commands/handlers/automation-task.sync.handler.ts +++ b/packages/core/src/tasks/commands/handlers/automation-task.sync.handler.ts @@ -1,7 +1,15 @@ -import { ICommandHandler, CommandHandler } from '@nestjs/cqrs'; +import { ICommandHandler, CommandHandler, EventBus } from '@nestjs/cqrs'; import { InjectRepository } from '@nestjs/typeorm'; import * as chalk from 'chalk'; -import { ID, IIntegrationMap, ITask, ITaskCreateInput, ITaskUpdateInput } from '@gauzy/contracts'; +import { + ActorTypeEnum, + BaseEntityEnum, + ID, + IIntegrationMap, + ITask, + ITaskCreateInput, + ITaskUpdateInput +} from '@gauzy/contracts'; import { RequestContext } from '../../../core/context'; import { IntegrationMap, TaskStatus } from '../../../core/entities/internal'; import { AutomationTaskSyncCommand } from './../automation-task.sync.command'; @@ -10,6 +18,7 @@ import { Task } from './../../task.entity'; import { TypeOrmIntegrationMapRepository } from '../../../integration-map/repository/type-orm-integration-map.repository'; import { TypeOrmTaskStatusRepository } from '../../statuses/repository/type-orm-task-status.repository'; import { TypeOrmTaskRepository } from '../../repository/type-orm-task.repository'; +import { activityLogCreateAction, activityLogUpdateAction } from '../../../activity-log/activity-log.helper'; @CommandHandler(AutomationTaskSyncCommand) export class AutomationTaskSyncHandler implements ICommandHandler { @@ -23,7 +32,9 @@ export class AutomationTaskSyncHandler implements ICommandHandler { this._eventBus.publish(new TaskEvent(ctx, task, BaseEntityEventTypeEnum.CREATED, input)); // Publish the event using EventBus } - // Generate the activity log description - const description = generateActivityLogDescription(ActionTypeEnum.Created, BaseEntityEnum.Task, task.title); - - console.log(`Generating activity log description: ${description}`); - - // Emit an event to log the activity - this._cqrsEventBus.publish( - new ActivityLogEvent({ - entity: BaseEntityEnum.Task, - entityId: task.id, - action: ActionTypeEnum.Created, - actorType: ActorTypeEnum.User, // TODO : Since we have Github Integration, make sure we can also store "System" for actor - description, - data: task, - organizationId, - tenantId - }) - ); - - console.log( - `Task created with ID: ${task.id} with activity log: ${JSON.stringify({ - entity: BaseEntityEnum.Task, - entityId: task.id, - action: ActionTypeEnum.Created, - actorType: ActorTypeEnum.User, // TODO : Since we have Github Integration, make sure we can also store "System" for actor - description, - data: task, - organizationId, - tenantId - })}` + // Generate the activity log + activityLogCreateAction( + this._cqrsEventBus, + BaseEntityEnum.Task, + task.title, + ActorTypeEnum.User, // TODO : Since we have Github Integration, make sure we can also store "System" for actor + organizationId, + tenantId, + task ); return task; // Return the created task diff --git a/packages/core/src/tasks/task.service.ts b/packages/core/src/tasks/task.service.ts index e478ab1d6a..f657513f2f 100644 --- a/packages/core/src/tasks/task.service.ts +++ b/packages/core/src/tasks/task.service.ts @@ -13,7 +13,6 @@ import { } from 'typeorm'; import { isBoolean, isUUID } from 'class-validator'; import { - ActionTypeEnum, BaseEntityEnum, ActorTypeEnum, ID, @@ -29,8 +28,7 @@ import { isEmpty, isNotEmpty } from '@gauzy/common'; import { isPostgres, isSqlite } from '@gauzy/config'; import { PaginationParams, TenantAwareCrudService } from './../core/crud'; import { RequestContext } from '../core/context'; -import { ActivityLogEvent } from '../activity-log/events'; -import { activityLogUpdatedFieldsAndValues, generateActivityLogDescription } from '../activity-log/activity-log.helper'; +import { activityLogUpdateAction } from '../activity-log/activity-log.helper'; import { TaskViewService } from './views/view.service'; import { Task } from './task.entity'; import { TypeOrmOrganizationSprintTaskHistoryRepository } from './../organization-sprint/repository/type-orm-organization-sprint-task-history.repository'; @@ -101,35 +99,21 @@ export class TaskService extends TenantAwareCrudService { }); } - // Generate the activity log description - const description = generateActivityLogDescription( - ActionTypeEnum.Updated, + // Generate the activity log + const { organizationId } = updatedTask; + activityLogUpdateAction( + this._eventBus, BaseEntityEnum.Task, - updatedTask.title - ); - - const { updatedFields, previousValues, updatedValues } = activityLogUpdatedFieldsAndValues( - updatedTask, - input - ); - - // Emit an event to log the activity - this._eventBus.publish( - new ActivityLogEvent({ - entity: BaseEntityEnum.Task, - entityId: updatedTask.id, - action: ActionTypeEnum.Updated, - actorType: ActorTypeEnum.User, // TODO : Since we have Github Integration, make sure we can also store "System" for actor - description, - updatedFields, - updatedValues, - previousValues, - data: updatedTask, - organizationId: updatedTask.organizationId, - tenantId - }) + updatedTask.title, + ActorTypeEnum.User, // TODO : Since we have Github Integration, make sure we can also store "System" for actor + organizationId, + tenantId, + task, + input, + updatedTask ); + // Return the updated Task return updatedTask; } catch (error) { console.error(`Error while updating task: ${error.message}`, error.message); diff --git a/packages/core/src/tasks/views/view.service.ts b/packages/core/src/tasks/views/view.service.ts index 749c3bd590..8eff55b8bc 100644 --- a/packages/core/src/tasks/views/view.service.ts +++ b/packages/core/src/tasks/views/view.service.ts @@ -1,8 +1,7 @@ import { EventBus } from '@nestjs/cqrs'; -import { HttpException, HttpStatus, Injectable } from '@nestjs/common'; +import { BadRequestException, HttpException, HttpStatus, Injectable } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { - ActionTypeEnum, ActorTypeEnum, BaseEntityEnum, ID, @@ -13,11 +12,7 @@ import { import { FavoriteService } from '../../core/decorators'; import { TenantAwareCrudService } from '../../core/crud'; import { RequestContext } from '../../core/context'; -import { ActivityLogEvent } from '../../activity-log/events'; -import { - activityLogUpdatedFieldsAndValues, - generateActivityLogDescription -} from '../../activity-log/activity-log.helper'; +import { activityLogCreateAction, activityLogUpdateAction } from '../../activity-log/activity-log.helper'; import { TaskView } from './view.entity'; import { TypeOrmTaskViewRepository } from './repository/type-orm-task-view.repository'; import { MikroOrmTaskViewRepository } from './repository/mikro-orm-task-view.repository'; @@ -49,27 +44,18 @@ export class TaskViewService extends TenantAwareCrudService { try { const view = await super.create({ ...entity, tenantId }); - // Generate the activity log description. - const description = generateActivityLogDescription( - ActionTypeEnum.Created, + // Generate the activity log + activityLogCreateAction( + this._eventBus, BaseEntityEnum.TaskView, - view.name - ); - - // Emit an event to log the activity - this._eventBus.publish( - new ActivityLogEvent({ - entity: BaseEntityEnum.TaskView, - entityId: view.id, - action: ActionTypeEnum.Created, - actorType: ActorTypeEnum.User, - description, - data: view, - organizationId, - tenantId - }) + view.name, + ActorTypeEnum.User, + organizationId, + tenantId, + view ); + // return the created view return view; } catch (error) { // Handle errors and return an appropriate error response @@ -89,40 +75,31 @@ export class TaskViewService extends TenantAwareCrudService { const tenantId = RequestContext.currentTenantId() || input.tenantId; try { + // Retrieve existing view. + const existingView = await this.findOneByIdString(id); + + if (!existingView) { + throw new BadRequestException('View not found'); + } + const updatedTaskView = await super.create({ ...input, tenantId, id }); - // Generate the activity log description. - const description = generateActivityLogDescription( - ActionTypeEnum.Updated, + // Generate the activity log + const { organizationId } = updatedTaskView; + activityLogUpdateAction( + this._eventBus, BaseEntityEnum.TaskView, - updatedTaskView.name - ); - - // Compare values before and after update then add updates to fields - const { updatedFields, previousValues, updatedValues } = activityLogUpdatedFieldsAndValues( - updatedTaskView, - input - ); - - // Emit event to log activity - this._eventBus.publish( - new ActivityLogEvent({ - entity: BaseEntityEnum.TaskView, - entityId: updatedTaskView.id, - action: ActionTypeEnum.Updated, - actorType: ActorTypeEnum.User, - description, - updatedFields, - updatedValues, - previousValues, - data: updatedTaskView, - organizationId: updatedTaskView.organizationId, - tenantId - }) + updatedTaskView.name, + ActorTypeEnum.User, + organizationId, + tenantId, + existingView, + input, + updatedTaskView ); // return updated view From 290f558aa87b3f4024108fa386d2ad00589d615d Mon Sep 17 00:00:00 2001 From: GloireMutaliko21 Date: Thu, 17 Oct 2024 09:23:02 +0200 Subject: [PATCH 2/8] fix(typos) --- packages/core/src/activity-log/activity-log.helper.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/core/src/activity-log/activity-log.helper.ts b/packages/core/src/activity-log/activity-log.helper.ts index 58da51d5de..2079f1c1c4 100644 --- a/packages/core/src/activity-log/activity-log.helper.ts +++ b/packages/core/src/activity-log/activity-log.helper.ts @@ -70,7 +70,7 @@ export function activityLogUpdatedFieldsAndValues(originalValues: T, updated: * @param {EventBus} eventBus - CQRS event to log activity * @param {BaseEntityEnum} entityType - Entity type for whom creating activity log (E.g : Task, OrganizationProject, etc.) * @param {string} entityName - Name or Title of created entity - * @param {ActorTypeEnum} actor - The actor type perfomed action (User or System) + * @param {ActorTypeEnum} actor - The actor type performed action (User or System) * @param {ID} organizationId * @param {ID} tenantId * @param {T} data - Created entity data @@ -110,11 +110,11 @@ export function activityLogCreateAction( * @param {EventBus} eventBus - CQRS event to log activity * @param {BaseEntityEnum} entityType - Entity type for whom creating activity log (E.g : Task, OrganizationProject, etc.) * @param {string} entityName - Name or Title of created entity - * @param {ActorTypeEnum} actor - The actor type perfomed action (User or System) + * @param {ActorTypeEnum} actor - The actor type performed action (User or System) * @param {ID} organizationId * @param {ID} tenantId * @param {Partial} originalValues - entity data before update - * @param {Partial} newValues - entity upated data per field + * @param {Partial} newValues - entity updated data per field * @param {T} data - Updated entity data = */ export function activityLogUpdateAction( From 6eca1d284cf25072898c66ebcf8fed9cb77dc1a4 Mon Sep 17 00:00:00 2001 From: GloireMutaliko21 Date: Thu, 17 Oct 2024 13:04:03 +0200 Subject: [PATCH 3/8] fix: activity log using global service method --- .../src/activity-log/activity-log.module.ts | 3 +- .../src/activity-log/activity-log.service.ts | 74 ++++++++++++++++++- .../events/handlers/activity-log.handler.ts | 2 +- .../organization-project-module.service.ts | 20 ++--- .../organization-project.service.ts | 33 +++------ .../organization-sprint.service.ts | 20 ++--- .../resource-link/resource-link.service.ts | 20 ++--- .../handlers/automation-task.sync.handler.ts | 20 ++--- packages/core/src/tasks/task.service.ts | 16 ++-- packages/core/src/tasks/views/view.service.ts | 18 ++--- 10 files changed, 142 insertions(+), 84 deletions(-) diff --git a/packages/core/src/activity-log/activity-log.module.ts b/packages/core/src/activity-log/activity-log.module.ts index 26bf823dfe..42505f1b37 100644 --- a/packages/core/src/activity-log/activity-log.module.ts +++ b/packages/core/src/activity-log/activity-log.module.ts @@ -1,5 +1,5 @@ import { CqrsModule } from '@nestjs/cqrs'; -import { Module } from '@nestjs/common'; +import { Global, Module } from '@nestjs/common'; import { MikroOrmModule } from '@mikro-orm/nestjs'; import { TypeOrmModule } from '@nestjs/typeorm'; import { RolePermissionModule } from '../role-permission/role-permission.module'; @@ -9,6 +9,7 @@ import { ActivityLogService } from './activity-log.service'; import { EventHandlers } from './events/handlers'; import { TypeOrmActivityLogRepository } from './repository/type-orm-activity-log.repository'; +@Global() @Module({ imports: [ TypeOrmModule.forFeature([ActivityLog]), diff --git a/packages/core/src/activity-log/activity-log.service.ts b/packages/core/src/activity-log/activity-log.service.ts index f432686703..05fbbc0ec9 100644 --- a/packages/core/src/activity-log/activity-log.service.ts +++ b/packages/core/src/activity-log/activity-log.service.ts @@ -1,18 +1,30 @@ import { BadRequestException, Injectable } from '@nestjs/common'; import { FindManyOptions, FindOptionsOrder, FindOptionsWhere } from 'typeorm'; -import { IActivityLog, IActivityLogInput, IPagination } from '@gauzy/contracts'; +import { + ActionTypeEnum, + ActorTypeEnum, + BaseEntityEnum, + IActivityLog, + IActivityLogInput, + ID, + IPagination +} from '@gauzy/contracts'; import { isNotNullOrUndefined } from '@gauzy/common'; import { TenantAwareCrudService } from './../core/crud'; import { RequestContext } from '../core/context'; import { GetActivityLogsDTO, allowedOrderDirections, allowedOrderFields } from './dto/get-activity-logs.dto'; import { ActivityLog } from './activity-log.entity'; import { MikroOrmActivityLogRepository, TypeOrmActivityLogRepository } from './repository'; +import { EventBus } from '@nestjs/cqrs'; +import { activityLogUpdatedFieldsAndValues, generateActivityLogDescription } from './activity-log.helper'; +import { ActivityLogEvent } from './events'; @Injectable() export class ActivityLogService extends TenantAwareCrudService { constructor( readonly typeOrmActivityLogRepository: TypeOrmActivityLogRepository, - readonly mikroOrmActivityLogRepository: MikroOrmActivityLogRepository + readonly mikroOrmActivityLogRepository: MikroOrmActivityLogRepository, + private readonly _eventBus: EventBus ) { super(typeOrmActivityLogRepository, mikroOrmActivityLogRepository); } @@ -67,7 +79,7 @@ export class ActivityLogService extends TenantAwareCrudService { const take = filters.take ? filters.take : 100; // Default take value if not provided // Pagination: ensure `filters.skip` is a positive integer starting from 1 - const skip = (filters.skip && Number.isInteger(filters.skip) && filters.skip > 0) ? filters.skip : 1; + const skip = filters.skip && Number.isInteger(filters.skip) && filters.skip > 0 ? filters.skip : 1; // Ensure that filters are properly defined const queryOptions: FindManyOptions = { @@ -91,7 +103,7 @@ export class ActivityLogService extends TenantAwareCrudService { * @returns The created activity log entry. * @throws BadRequestException when the log creation fails. */ - async logActivity(input: IActivityLogInput): Promise { + async create(input: IActivityLogInput): Promise { try { const creatorId = RequestContext.currentUserId(); // Retrieve the current user's ID from the request context // Create the activity log entry using the provided input along with the tenantId and creatorId @@ -101,4 +113,58 @@ export class ActivityLogService extends TenantAwareCrudService { throw new BadRequestException('Error while creating activity log', error); } } + + /** + * @description Create or Update Activity Log + * @template T + * @param {BaseEntityEnum} entityType - Entity type for whom creating activity log (E.g : Task, OrganizationProject, etc.) + * @param {string} entityName - Name or Title of the entity + * @param {ActorTypeEnum} actor - The actor type performing the action (User or System) + * @param {ID} organizationId + * @param {ID} tenantId + * @param {ActionTypeEnum} actionType - Action performed (Created or Updated) + * @param {T} data - Entity data (for Created action) or Updated entity data (for Updated action) + * @param {Partial} [originalValues] - Entity data before update (optional for Update action) + * @param {Partial} [newValues] - Entity updated data per field (optional for Update action) + */ + logActivity( + entityType: BaseEntityEnum, + entityName: string, + actor: ActorTypeEnum, + organizationId: ID, + tenantId: ID, + actionType: ActionTypeEnum, + data: T, + originalValues?: Partial, + newValues?: Partial + ) { + // Generate the activity log description based on action type + const description = generateActivityLogDescription(actionType, entityType, entityName); + + // Initialize log event payload + const logPayload: IActivityLog = { + entity: entityType, + entityId: data['id'], + action: actionType, + actorType: actor, + description, + data, + organizationId, + tenantId + }; + + // If it's an update action, add updated fields and values + if (actionType === ActionTypeEnum.Updated && originalValues && newValues) { + const { updatedFields, previousValues, updatedValues } = activityLogUpdatedFieldsAndValues( + originalValues, + newValues + ); + + // Add updated fields and values to the log + Object.assign(logPayload, { updatedFields, previousValues, updatedValues }); + } + + // Emit the event to log the activity + return this._eventBus.publish(new ActivityLogEvent(logPayload)); + } } diff --git a/packages/core/src/activity-log/events/handlers/activity-log.handler.ts b/packages/core/src/activity-log/events/handlers/activity-log.handler.ts index cd1d8c6cea..cde3bb5574 100644 --- a/packages/core/src/activity-log/events/handlers/activity-log.handler.ts +++ b/packages/core/src/activity-log/events/handlers/activity-log.handler.ts @@ -15,6 +15,6 @@ export class ActivityLogEventHandler implements IEventHandler */ async handle(event: ActivityLogEvent) { // Extract the input from the event and create a new activity log entry - return await this.activityLogService.logActivity(event.input); + return await this.activityLogService.create(event.input); } } diff --git a/packages/core/src/organization-project-module/organization-project-module.service.ts b/packages/core/src/organization-project-module/organization-project-module.service.ts index 5c3cef49cb..55abd99a47 100644 --- a/packages/core/src/organization-project-module/organization-project-module.service.ts +++ b/packages/core/src/organization-project-module/organization-project-module.service.ts @@ -1,5 +1,4 @@ import { BadRequestException, HttpException, HttpStatus, Injectable } from '@nestjs/common'; -import { EventBus } from '@nestjs/cqrs'; import { Brackets, FindManyOptions, SelectQueryBuilder, UpdateResult, WhereExpressionBuilder } from 'typeorm'; import { BaseEntityEnum, @@ -11,15 +10,16 @@ import { IOrganizationProjectModuleUpdateInput, IPagination, PermissionsEnum, - ProjectModuleStatusEnum + ProjectModuleStatusEnum, + ActionTypeEnum } from '@gauzy/contracts'; import { isEmpty, isNotEmpty } from '@gauzy/common'; import { isPostgres } from '@gauzy/config'; import { PaginationParams, TenantAwareCrudService } from './../core/crud'; import { RequestContext } from '../core/context'; -import { activityLogCreateAction, activityLogUpdateAction } from '../activity-log/activity-log.helper'; import { OrganizationProjectModule } from './organization-project-module.entity'; import { prepareSQLQuery as p } from './../database/database.helper'; +import { ActivityLogService } from '../activity-log/activity-log.service'; import { TypeOrmOrganizationProjectModuleRepository } from './repository/type-orm-organization-project-module.repository'; import { MikroOrmOrganizationProjectModuleRepository } from './repository/mikro-orm-organization-project-module.repository'; @@ -28,7 +28,7 @@ export class OrganizationProjectModuleService extends TenantAwareCrudService { readonly typeOrmResourceLinkRepository: TypeOrmResourceLinkRepository, readonly mikroOrmResourceLinkRepository: MikroOrmResourceLinkRepository, private readonly userService: UserService, - private readonly _eventBus: EventBus + private readonly activityLogService: ActivityLogService ) { super(typeOrmResourceLinkRepository, mikroOrmResourceLinkRepository); } @@ -54,13 +54,13 @@ export class ResourceLinkService extends TenantAwareCrudService { }); // Generate the activity log - activityLogCreateAction( - this._eventBus, + this.activityLogService.logActivity( BaseEntityEnum.ResourceLink, resourceLink.title, ActorTypeEnum.User, resourceLink.organizationId, tenantId, + ActionTypeEnum.Created, resourceLink ); @@ -92,16 +92,16 @@ export class ResourceLinkService extends TenantAwareCrudService { // Generate the activity log const { organizationId, tenantId } = updatedResourceLink; - activityLogUpdateAction( - this._eventBus, + this.activityLogService.logActivity( BaseEntityEnum.ResourceLink, `${resourceLink.title} for ${resourceLink.entity}`, ActorTypeEnum.User, organizationId, tenantId, + ActionTypeEnum.Updated, + updatedResourceLink, resourceLink, - input, - updatedResourceLink + input ); // return updated Resource Link diff --git a/packages/core/src/tasks/commands/handlers/automation-task.sync.handler.ts b/packages/core/src/tasks/commands/handlers/automation-task.sync.handler.ts index e3a525ac83..2f93d78ded 100644 --- a/packages/core/src/tasks/commands/handlers/automation-task.sync.handler.ts +++ b/packages/core/src/tasks/commands/handlers/automation-task.sync.handler.ts @@ -1,7 +1,8 @@ -import { ICommandHandler, CommandHandler, EventBus } from '@nestjs/cqrs'; +import { ICommandHandler, CommandHandler } from '@nestjs/cqrs'; import { InjectRepository } from '@nestjs/typeorm'; import * as chalk from 'chalk'; import { + ActionTypeEnum, ActorTypeEnum, BaseEntityEnum, ID, @@ -14,11 +15,11 @@ import { RequestContext } from '../../../core/context'; import { IntegrationMap, TaskStatus } from '../../../core/entities/internal'; import { AutomationTaskSyncCommand } from './../automation-task.sync.command'; import { TaskService } from './../../task.service'; +import { ActivityLogService } from '../../../activity-log/activity-log.service'; import { Task } from './../../task.entity'; import { TypeOrmIntegrationMapRepository } from '../../../integration-map/repository/type-orm-integration-map.repository'; import { TypeOrmTaskStatusRepository } from '../../statuses/repository/type-orm-task-status.repository'; import { TypeOrmTaskRepository } from '../../repository/type-orm-task.repository'; -import { activityLogCreateAction, activityLogUpdateAction } from '../../../activity-log/activity-log.helper'; @CommandHandler(AutomationTaskSyncCommand) export class AutomationTaskSyncHandler implements ICommandHandler { @@ -34,7 +35,7 @@ export class AutomationTaskSyncHandler implements ICommandHandler { readonly mikroOrmTaskRepository: MikroOrmTaskRepository, readonly typeOrmOrganizationSprintTaskHistoryRepository: TypeOrmOrganizationSprintTaskHistoryRepository, private readonly taskViewService: TaskViewService, - private readonly _eventBus: EventBus + private readonly activityLogService: ActivityLogService ) { super(typeOrmTaskRepository, mikroOrmTaskRepository); } @@ -101,16 +101,16 @@ export class TaskService extends TenantAwareCrudService { // Generate the activity log const { organizationId } = updatedTask; - activityLogUpdateAction( - this._eventBus, + this.activityLogService.logActivity( BaseEntityEnum.Task, updatedTask.title, ActorTypeEnum.User, // TODO : Since we have Github Integration, make sure we can also store "System" for actor organizationId, tenantId, + ActionTypeEnum.Updated, + updatedTask, task, - input, - updatedTask + input ); // Return the updated Task diff --git a/packages/core/src/tasks/views/view.service.ts b/packages/core/src/tasks/views/view.service.ts index 8eff55b8bc..e21a3fcec0 100644 --- a/packages/core/src/tasks/views/view.service.ts +++ b/packages/core/src/tasks/views/view.service.ts @@ -1,7 +1,7 @@ -import { EventBus } from '@nestjs/cqrs'; import { BadRequestException, HttpException, HttpStatus, Injectable } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { + ActionTypeEnum, ActorTypeEnum, BaseEntityEnum, ID, @@ -12,7 +12,7 @@ import { import { FavoriteService } from '../../core/decorators'; import { TenantAwareCrudService } from '../../core/crud'; import { RequestContext } from '../../core/context'; -import { activityLogCreateAction, activityLogUpdateAction } from '../../activity-log/activity-log.helper'; +import { ActivityLogService } from '../../activity-log/activity-log.service'; import { TaskView } from './view.entity'; import { TypeOrmTaskViewRepository } from './repository/type-orm-task-view.repository'; import { MikroOrmTaskViewRepository } from './repository/mikro-orm-task-view.repository'; @@ -26,7 +26,7 @@ export class TaskViewService extends TenantAwareCrudService { mikroOrmTaskViewRepository: MikroOrmTaskViewRepository, - private readonly _eventBus: EventBus + private readonly activityLogService: ActivityLogService ) { super(typeOrmTaskViewRepository, mikroOrmTaskViewRepository); } @@ -45,13 +45,13 @@ export class TaskViewService extends TenantAwareCrudService { const view = await super.create({ ...entity, tenantId }); // Generate the activity log - activityLogCreateAction( - this._eventBus, + this.activityLogService.logActivity( BaseEntityEnum.TaskView, view.name, ActorTypeEnum.User, organizationId, tenantId, + ActionTypeEnum.Created, view ); @@ -90,16 +90,16 @@ export class TaskViewService extends TenantAwareCrudService { // Generate the activity log const { organizationId } = updatedTaskView; - activityLogUpdateAction( - this._eventBus, + this.activityLogService.logActivity( BaseEntityEnum.TaskView, updatedTaskView.name, ActorTypeEnum.User, organizationId, tenantId, + ActionTypeEnum.Updated, + updatedTaskView, existingView, - input, - updatedTaskView + input ); // return updated view From 045a18aaf52bc1d48f7064eae3ec780907c3a104 Mon Sep 17 00:00:00 2001 From: GloireMutaliko21 Date: Thu, 17 Oct 2024 13:12:52 +0200 Subject: [PATCH 4/8] fix: task create handler activity log --- .../src/activity-log/activity-log.helper.ts | 95 +------------------ .../commands/handlers/task-create.handler.ts | 15 ++- 2 files changed, 8 insertions(+), 102 deletions(-) diff --git a/packages/core/src/activity-log/activity-log.helper.ts b/packages/core/src/activity-log/activity-log.helper.ts index 2079f1c1c4..b9ef57e8c7 100644 --- a/packages/core/src/activity-log/activity-log.helper.ts +++ b/packages/core/src/activity-log/activity-log.helper.ts @@ -1,6 +1,4 @@ -import { EventBus } from '@nestjs/cqrs'; -import { ActionTypeEnum, ActorTypeEnum, BaseEntityEnum, IActivityLogUpdatedValues, ID } from '@gauzy/contracts'; -import { ActivityLogEvent } from './events'; +import { ActionTypeEnum, BaseEntityEnum, IActivityLogUpdatedValues } from '@gauzy/contracts'; const ActivityTemplates = { [ActionTypeEnum.Created]: `{action} a new {entity} called "{entityName}"`, @@ -63,94 +61,3 @@ export function activityLogUpdatedFieldsAndValues(originalValues: T, updated: return { updatedFields, previousValues, updatedValues }; } - -/** - * @description Create activity log for Action "Created" - * @template T - * @param {EventBus} eventBus - CQRS event to log activity - * @param {BaseEntityEnum} entityType - Entity type for whom creating activity log (E.g : Task, OrganizationProject, etc.) - * @param {string} entityName - Name or Title of created entity - * @param {ActorTypeEnum} actor - The actor type performed action (User or System) - * @param {ID} organizationId - * @param {ID} tenantId - * @param {T} data - Created entity data - */ -export function activityLogCreateAction( - eventBus: EventBus, - entityType: BaseEntityEnum, - entityName: string, - actor: ActorTypeEnum, - organizationId: ID, - tenantId: ID, - data: T -) { - // Generate the activity log description - const description = generateActivityLogDescription(ActionTypeEnum.Created, entityType, entityName); - - console.log(`Generating activity log description: ${description}`); - - // Emit an event to log the activity - return eventBus.publish( - new ActivityLogEvent({ - entity: entityType, - entityId: data['id'], - action: ActionTypeEnum.Created, - actorType: actor, - description, - data, - organizationId, - tenantId - }) - ); -} - -/** - * @description Create Activity Log for Action "Updated" - * @template T - * @param {EventBus} eventBus - CQRS event to log activity - * @param {BaseEntityEnum} entityType - Entity type for whom creating activity log (E.g : Task, OrganizationProject, etc.) - * @param {string} entityName - Name or Title of created entity - * @param {ActorTypeEnum} actor - The actor type performed action (User or System) - * @param {ID} organizationId - * @param {ID} tenantId - * @param {Partial} originalValues - entity data before update - * @param {Partial} newValues - entity updated data per field - * @param {T} data - Updated entity data -= */ -export function activityLogUpdateAction( - eventBus: EventBus, - entityType: BaseEntityEnum, - entityName: string, - actor: ActorTypeEnum, - organizationId: ID, - tenantId: ID, - originalValues: Partial, - newValues: Partial, - data: T -) { - // Generate the activity log description - const description = generateActivityLogDescription(ActionTypeEnum.Updated, entityType, entityName); - - // Retrieve updated fields, their old and new values - const { updatedFields, previousValues, updatedValues } = activityLogUpdatedFieldsAndValues( - originalValues, - newValues - ); - - // Emit an event to log the activity - return eventBus.publish( - new ActivityLogEvent({ - entity: entityType, - entityId: data['id'], - action: ActionTypeEnum.Updated, - actorType: actor, - description, - updatedFields, - updatedValues, - previousValues, - data, - organizationId, - tenantId - }) - ); -} diff --git a/packages/core/src/tasks/commands/handlers/task-create.handler.ts b/packages/core/src/tasks/commands/handlers/task-create.handler.ts index 50ce29e953..0918581caa 100644 --- a/packages/core/src/tasks/commands/handlers/task-create.handler.ts +++ b/packages/core/src/tasks/commands/handlers/task-create.handler.ts @@ -1,7 +1,6 @@ -import { CommandHandler, ICommandHandler, EventBus as CqrsEventBus } from '@nestjs/cqrs'; +import { CommandHandler, ICommandHandler } from '@nestjs/cqrs'; import { HttpException, HttpStatus, Logger } from '@nestjs/common'; -import { BaseEntityEnum, ActorTypeEnum, ITask } from '@gauzy/contracts'; -import { activityLogCreateAction } from '../../../activity-log/activity-log.helper'; +import { BaseEntityEnum, ActorTypeEnum, ITask, ActionTypeEnum } from '@gauzy/contracts'; import { EventBus } from '../../../event-bus'; import { TaskEvent } from '../../../event-bus/events'; import { BaseEntityEventTypeEnum } from '../../../event-bus/base-entity-event'; @@ -9,17 +8,17 @@ import { RequestContext } from './../../../core/context'; import { OrganizationProjectService } from './../../../organization-project/organization-project.service'; import { TaskCreateCommand } from './../task-create.command'; import { TaskService } from '../../task.service'; +import { ActivityLogService } from '../../../activity-log/activity-log.service'; @CommandHandler(TaskCreateCommand) export class TaskCreateHandler implements ICommandHandler { private readonly logger = new Logger('TaskCreateCommand'); constructor( - // TODO : use only one event bus type private readonly _eventBus: EventBus, - private readonly _cqrsEventBus: CqrsEventBus, private readonly _taskService: TaskService, - private readonly _organizationProjectService: OrganizationProjectService + private readonly _organizationProjectService: OrganizationProjectService, + private readonly activityLogService: ActivityLogService ) {} /** @@ -74,13 +73,13 @@ export class TaskCreateHandler implements ICommandHandler { } // Generate the activity log - activityLogCreateAction( - this._cqrsEventBus, + this.activityLogService.logActivity( BaseEntityEnum.Task, task.title, ActorTypeEnum.User, // TODO : Since we have Github Integration, make sure we can also store "System" for actor organizationId, tenantId, + ActionTypeEnum.Created, task ); From 2d9b156ff33bdfd9b0d8c1824bcbf27a3588e633 Mon Sep 17 00:00:00 2001 From: GloireMutaliko21 Date: Thu, 17 Oct 2024 13:16:10 +0200 Subject: [PATCH 5/8] fix: logActivity method return instruction --- packages/core/src/activity-log/activity-log.service.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/src/activity-log/activity-log.service.ts b/packages/core/src/activity-log/activity-log.service.ts index 05fbbc0ec9..f1ee2e5080 100644 --- a/packages/core/src/activity-log/activity-log.service.ts +++ b/packages/core/src/activity-log/activity-log.service.ts @@ -165,6 +165,6 @@ export class ActivityLogService extends TenantAwareCrudService { } // Emit the event to log the activity - return this._eventBus.publish(new ActivityLogEvent(logPayload)); + this._eventBus.publish(new ActivityLogEvent(logPayload)); } } From ccc6d003a6d9e7666d11d5e9f87a1edf4b5e06a2 Mon Sep 17 00:00:00 2001 From: GloireMutaliko21 Date: Thu, 17 Oct 2024 13:28:50 +0200 Subject: [PATCH 6/8] fix: CodeRabbit exception type --- packages/core/src/tasks/views/view.service.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/core/src/tasks/views/view.service.ts b/packages/core/src/tasks/views/view.service.ts index e21a3fcec0..8c81b4c8b0 100644 --- a/packages/core/src/tasks/views/view.service.ts +++ b/packages/core/src/tasks/views/view.service.ts @@ -1,4 +1,4 @@ -import { BadRequestException, HttpException, HttpStatus, Injectable } from '@nestjs/common'; +import { HttpException, HttpStatus, Injectable, NotFoundException } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { ActionTypeEnum, @@ -67,7 +67,8 @@ export class TaskViewService extends TenantAwareCrudService { * @description Update a Task View * @param {ID} id - The ID of the Task View to be updated * @param {ITaskViewUpdateInput} input - The updated information for the Task View - * @throws BadRequestException if there's an error during the update process. + * @throws NotFoundException if there's an error if requested update view was not found. + * @throws BadRequest if there's an error during the update process. * @returns {Promise} A Promise resolving to the updated Task View * @memberof TaskViewService */ @@ -79,7 +80,7 @@ export class TaskViewService extends TenantAwareCrudService { const existingView = await this.findOneByIdString(id); if (!existingView) { - throw new BadRequestException('View not found'); + throw new NotFoundException('View not found'); } const updatedTaskView = await super.create({ From 09f5e1d3b94ab47ee756fa5b0e08d2428face419 Mon Sep 17 00:00:00 2001 From: "Rahul R." Date: Thu, 17 Oct 2024 18:17:34 +0530 Subject: [PATCH 7/8] fix: updated entityId for log activity --- .../src/activity-log/activity-log.service.ts | 65 ++++++++++--------- .../organization-project-module.service.ts | 25 +++---- .../organization-project.service.ts | 3 +- .../organization-sprint.service.ts | 6 +- .../resource-link/resource-link.service.ts | 6 +- .../handlers/automation-task.sync.handler.ts | 6 +- .../commands/handlers/task-create.handler.ts | 4 +- packages/core/src/tasks/task.service.ts | 3 +- packages/core/src/tasks/views/view.service.ts | 16 +++-- 9 files changed, 76 insertions(+), 58 deletions(-) diff --git a/packages/core/src/activity-log/activity-log.service.ts b/packages/core/src/activity-log/activity-log.service.ts index f1ee2e5080..28dbd48bb3 100644 --- a/packages/core/src/activity-log/activity-log.service.ts +++ b/packages/core/src/activity-log/activity-log.service.ts @@ -1,4 +1,5 @@ import { BadRequestException, Injectable } from '@nestjs/common'; +import { EventBus } from '@nestjs/cqrs'; import { FindManyOptions, FindOptionsOrder, FindOptionsWhere } from 'typeorm'; import { ActionTypeEnum, @@ -12,12 +13,11 @@ import { import { isNotNullOrUndefined } from '@gauzy/common'; import { TenantAwareCrudService } from './../core/crud'; import { RequestContext } from '../core/context'; +import { activityLogUpdatedFieldsAndValues, generateActivityLogDescription } from './activity-log.helper'; +import { ActivityLogEvent } from './events/activity-log.event'; import { GetActivityLogsDTO, allowedOrderDirections, allowedOrderFields } from './dto/get-activity-logs.dto'; import { ActivityLog } from './activity-log.entity'; import { MikroOrmActivityLogRepository, TypeOrmActivityLogRepository } from './repository'; -import { EventBus } from '@nestjs/cqrs'; -import { activityLogUpdatedFieldsAndValues, generateActivityLogDescription } from './activity-log.helper'; -import { ActivityLogEvent } from './events'; @Injectable() export class ActivityLogService extends TenantAwareCrudService { @@ -29,6 +29,29 @@ export class ActivityLogService extends TenantAwareCrudService { super(typeOrmActivityLogRepository, mikroOrmActivityLogRepository); } + /** + * Creates a new activity log entry with the provided input, while associating it with the current user and tenant. + * + * @param input - The data required to create an activity log entry. + * @returns The created activity log entry. + * @throws BadRequestException when the log creation fails. + */ + async create(input: IActivityLogInput): Promise { + try { + // Retrieve the current user's ID from the request context + const creatorId = RequestContext.currentUserId(); + + // Retrieve the current tenant ID from the request context or use the provided tenantId + const tenantId = RequestContext.currentTenantId() || input.tenantId; + + // Create the activity log entry using the provided input along with the tenantId and creatorId + return await super.create({ ...input, tenantId, creatorId }); + } catch (error) { + console.log('Error while creating activity log:', error); + throw new BadRequestException('Error while creating activity log', error); + } + } + /** * Finds and retrieves activity logs based on the given filters criteria. * @@ -96,24 +119,6 @@ export class ActivityLogService extends TenantAwareCrudService { return await super.findAll(queryOptions); } - /** - * Creates a new activity log entry with the provided input, while associating it with the current user and tenant. - * - * @param input - The data required to create an activity log entry. - * @returns The created activity log entry. - * @throws BadRequestException when the log creation fails. - */ - async create(input: IActivityLogInput): Promise { - try { - const creatorId = RequestContext.currentUserId(); // Retrieve the current user's ID from the request context - // Create the activity log entry using the provided input along with the tenantId and creatorId - return await super.create({ ...input, creatorId }); - } catch (error) { - console.log('Error while creating activity log:', error); - throw new BadRequestException('Error while creating activity log', error); - } - } - /** * @description Create or Update Activity Log * @template T @@ -128,8 +133,9 @@ export class ActivityLogService extends TenantAwareCrudService { * @param {Partial} [newValues] - Entity updated data per field (optional for Update action) */ logActivity( - entityType: BaseEntityEnum, + entity: BaseEntityEnum, entityName: string, + entityId: ID, actor: ActorTypeEnum, organizationId: ID, tenantId: ID, @@ -138,16 +144,13 @@ export class ActivityLogService extends TenantAwareCrudService { originalValues?: Partial, newValues?: Partial ) { - // Generate the activity log description based on action type - const description = generateActivityLogDescription(actionType, entityType, entityName); - // Initialize log event payload - const logPayload: IActivityLog = { - entity: entityType, - entityId: data['id'], + const activityLog: IActivityLog = { + entity, + entityId, action: actionType, actorType: actor, - description, + description: generateActivityLogDescription(actionType, entity, entityName), data, organizationId, tenantId @@ -161,10 +164,10 @@ export class ActivityLogService extends TenantAwareCrudService { ); // Add updated fields and values to the log - Object.assign(logPayload, { updatedFields, previousValues, updatedValues }); + Object.assign(activityLog, { updatedFields, previousValues, updatedValues }); } // Emit the event to log the activity - this._eventBus.publish(new ActivityLogEvent(logPayload)); + this._eventBus.publish(new ActivityLogEvent(activityLog)); } } diff --git a/packages/core/src/organization-project-module/organization-project-module.service.ts b/packages/core/src/organization-project-module/organization-project-module.service.ts index 55abd99a47..880298e286 100644 --- a/packages/core/src/organization-project-module/organization-project-module.service.ts +++ b/packages/core/src/organization-project-module/organization-project-module.service.ts @@ -44,23 +44,24 @@ export class OrganizationProjectModuleService extends TenantAwareCrudService( BaseEntityEnum.OrganizationProjectModule, - module.name, + projectModule.name, + projectModule.id, ActorTypeEnum.User, organizationId, tenantId, ActionTypeEnum.Created, - module + projectModule ); - return module; + return projectModule; } catch (error) { throw new BadRequestException(error); } @@ -93,27 +94,29 @@ export class OrganizationProjectModuleService extends TenantAwareCrudService( BaseEntityEnum.OrganizationProjectModule, - updatedModule.name, + updatedProjectModule.name, + updatedProjectModule.id, ActorTypeEnum.User, organizationId, tenantId, ActionTypeEnum.Updated, - updatedModule, + updatedProjectModule, existingModule, entity ); // return updated Module - return updatedModule; + return updatedProjectModule; } catch (error) { throw new BadRequestException(error); } diff --git a/packages/core/src/organization-project/organization-project.service.ts b/packages/core/src/organization-project/organization-project.service.ts index f791b3db2f..3e296a5d44 100644 --- a/packages/core/src/organization-project/organization-project.service.ts +++ b/packages/core/src/organization-project/organization-project.service.ts @@ -123,9 +123,10 @@ export class OrganizationProjectService extends TenantAwareCrudService( BaseEntityEnum.OrganizationProject, project.name, + project.id, ActorTypeEnum.User, organizationId, tenantId, diff --git a/packages/core/src/organization-sprint/organization-sprint.service.ts b/packages/core/src/organization-sprint/organization-sprint.service.ts index 8e157f95f3..13be4a2682 100644 --- a/packages/core/src/organization-sprint/organization-sprint.service.ts +++ b/packages/core/src/organization-sprint/organization-sprint.service.ts @@ -114,9 +114,10 @@ export class OrganizationSprintService extends TenantAwareCrudService( BaseEntityEnum.OrganizationSprint, sprint.name, + sprint.id, ActorTypeEnum.User, organizationId, tenantId, @@ -181,9 +182,10 @@ export class OrganizationSprintService extends TenantAwareCrudService( BaseEntityEnum.OrganizationSprint, updatedSprint.name, + updatedSprint.id, ActorTypeEnum.User, organizationId, tenantId, diff --git a/packages/core/src/resource-link/resource-link.service.ts b/packages/core/src/resource-link/resource-link.service.ts index ba20ef1623..cf5f08920d 100644 --- a/packages/core/src/resource-link/resource-link.service.ts +++ b/packages/core/src/resource-link/resource-link.service.ts @@ -54,9 +54,10 @@ export class ResourceLinkService extends TenantAwareCrudService { }); // Generate the activity log - this.activityLogService.logActivity( + this.activityLogService.logActivity( BaseEntityEnum.ResourceLink, resourceLink.title, + resourceLink.id, ActorTypeEnum.User, resourceLink.organizationId, tenantId, @@ -92,9 +93,10 @@ export class ResourceLinkService extends TenantAwareCrudService { // Generate the activity log const { organizationId, tenantId } = updatedResourceLink; - this.activityLogService.logActivity( + this.activityLogService.logActivity( BaseEntityEnum.ResourceLink, `${resourceLink.title} for ${resourceLink.entity}`, + resourceLink.id, ActorTypeEnum.User, organizationId, tenantId, diff --git a/packages/core/src/tasks/commands/handlers/automation-task.sync.handler.ts b/packages/core/src/tasks/commands/handlers/automation-task.sync.handler.ts index 2f93d78ded..baa35460f0 100644 --- a/packages/core/src/tasks/commands/handlers/automation-task.sync.handler.ts +++ b/packages/core/src/tasks/commands/handlers/automation-task.sync.handler.ts @@ -147,9 +147,10 @@ export class AutomationTaskSyncHandler implements ICommandHandler( BaseEntityEnum.Task, createdTask.title, + createdTask.id, ActorTypeEnum.System, organizationId, tenantId, @@ -188,9 +189,10 @@ export class AutomationTaskSyncHandler implements ICommandHandler( BaseEntityEnum.Task, updatedTask.title, + updatedTask.id, ActorTypeEnum.System, organizationId, tenantId, diff --git a/packages/core/src/tasks/commands/handlers/task-create.handler.ts b/packages/core/src/tasks/commands/handlers/task-create.handler.ts index 0918581caa..415ae74ea2 100644 --- a/packages/core/src/tasks/commands/handlers/task-create.handler.ts +++ b/packages/core/src/tasks/commands/handlers/task-create.handler.ts @@ -8,6 +8,7 @@ import { RequestContext } from './../../../core/context'; import { OrganizationProjectService } from './../../../organization-project/organization-project.service'; import { TaskCreateCommand } from './../task-create.command'; import { TaskService } from '../../task.service'; +import { Task } from './../../task.entity'; import { ActivityLogService } from '../../../activity-log/activity-log.service'; @CommandHandler(TaskCreateCommand) @@ -73,9 +74,10 @@ export class TaskCreateHandler implements ICommandHandler { } // Generate the activity log - this.activityLogService.logActivity( + this.activityLogService.logActivity( BaseEntityEnum.Task, task.title, + task.id, ActorTypeEnum.User, // TODO : Since we have Github Integration, make sure we can also store "System" for actor organizationId, tenantId, diff --git a/packages/core/src/tasks/task.service.ts b/packages/core/src/tasks/task.service.ts index 33c481e1df..1628abad69 100644 --- a/packages/core/src/tasks/task.service.ts +++ b/packages/core/src/tasks/task.service.ts @@ -101,9 +101,10 @@ export class TaskService extends TenantAwareCrudService { // Generate the activity log const { organizationId } = updatedTask; - this.activityLogService.logActivity( + this.activityLogService.logActivity( BaseEntityEnum.Task, updatedTask.title, + updatedTask.id, ActorTypeEnum.User, // TODO : Since we have Github Integration, make sure we can also store "System" for actor organizationId, tenantId, diff --git a/packages/core/src/tasks/views/view.service.ts b/packages/core/src/tasks/views/view.service.ts index 8c81b4c8b0..0b7738d8f5 100644 --- a/packages/core/src/tasks/views/view.service.ts +++ b/packages/core/src/tasks/views/view.service.ts @@ -42,21 +42,22 @@ export class TaskViewService extends TenantAwareCrudService { const tenantId = RequestContext.currentTenantId() || entity.tenantId; const { organizationId } = entity; try { - const view = await super.create({ ...entity, tenantId }); + const taskView = await super.create({ ...entity, tenantId }); // Generate the activity log - this.activityLogService.logActivity( + this.activityLogService.logActivity( BaseEntityEnum.TaskView, - view.name, + taskView.name, + taskView.id, ActorTypeEnum.User, organizationId, tenantId, ActionTypeEnum.Created, - view + taskView ); - // return the created view - return view; + // return the created task view + return taskView; } catch (error) { // Handle errors and return an appropriate error response throw new HttpException(`Failed to create view : ${error.message}`, HttpStatus.BAD_REQUEST); @@ -91,9 +92,10 @@ export class TaskViewService extends TenantAwareCrudService { // Generate the activity log const { organizationId } = updatedTaskView; - this.activityLogService.logActivity( + this.activityLogService.logActivity( BaseEntityEnum.TaskView, updatedTaskView.name, + updatedTaskView.id, ActorTypeEnum.User, organizationId, tenantId, From ec297abc418a2753bb1874fde1f9a04f1817c3cc Mon Sep 17 00:00:00 2001 From: GloireMutaliko21 Date: Thu, 17 Oct 2024 15:32:08 +0200 Subject: [PATCH 8/8] fix: improve code activity log parameters --- .../src/activity-log/activity-log.service.ts | 36 ++++++++++--------- .../organization-project-module.service.ts | 24 ++++++------- .../organization-project.service.ts | 28 +++++++++++---- .../organization-sprint.service.ts | 18 +++++----- .../resource-link/resource-link.service.ts | 18 +++++----- .../handlers/automation-task.sync.handler.ts | 18 +++++----- .../commands/handlers/task-create.handler.ts | 10 +++--- packages/core/src/tasks/task.service.ts | 8 ++--- packages/core/src/tasks/views/view.service.ts | 24 ++++++------- 9 files changed, 101 insertions(+), 83 deletions(-) diff --git a/packages/core/src/activity-log/activity-log.service.ts b/packages/core/src/activity-log/activity-log.service.ts index 28dbd48bb3..fa18e7334a 100644 --- a/packages/core/src/activity-log/activity-log.service.ts +++ b/packages/core/src/activity-log/activity-log.service.ts @@ -134,27 +134,17 @@ export class ActivityLogService extends TenantAwareCrudService { */ logActivity( entity: BaseEntityEnum, - entityName: string, - entityId: ID, + actionType: ActionTypeEnum, actor: ActorTypeEnum, + entityId: ID, + entityName: string, + data: T, organizationId: ID, tenantId: ID, - actionType: ActionTypeEnum, - data: T, originalValues?: Partial, newValues?: Partial ) { - // Initialize log event payload - const activityLog: IActivityLog = { - entity, - entityId, - action: actionType, - actorType: actor, - description: generateActivityLogDescription(actionType, entity, entityName), - data, - organizationId, - tenantId - }; + let jsonFields: Record = new Object(); // If it's an update action, add updated fields and values if (actionType === ActionTypeEnum.Updated && originalValues && newValues) { @@ -164,10 +154,22 @@ export class ActivityLogService extends TenantAwareCrudService { ); // Add updated fields and values to the log - Object.assign(activityLog, { updatedFields, previousValues, updatedValues }); + jsonFields = Object.assign({}, { updatedFields, previousValues, updatedValues }); } // Emit the event to log the activity - this._eventBus.publish(new ActivityLogEvent(activityLog)); + this._eventBus.publish( + new ActivityLogEvent({ + entity, + entityId, + action: actionType, + actorType: actor, + description: generateActivityLogDescription(actionType, entity, entityName), + data, + organizationId, + tenantId, + ...jsonFields + }) + ); } } diff --git a/packages/core/src/organization-project-module/organization-project-module.service.ts b/packages/core/src/organization-project-module/organization-project-module.service.ts index 880298e286..6b7698de7c 100644 --- a/packages/core/src/organization-project-module/organization-project-module.service.ts +++ b/packages/core/src/organization-project-module/organization-project-module.service.ts @@ -52,13 +52,13 @@ export class OrganizationProjectModuleService extends TenantAwareCrudService( BaseEntityEnum.OrganizationProjectModule, - projectModule.name, - projectModule.id, + ActionTypeEnum.Created, ActorTypeEnum.User, + projectModule.id, + projectModule.name, + projectModule, organizationId, - tenantId, - ActionTypeEnum.Created, - projectModule + tenantId ); return projectModule; @@ -82,14 +82,14 @@ export class OrganizationProjectModuleService extends TenantAwareCrudService( BaseEntityEnum.OrganizationProjectModule, - updatedProjectModule.name, - updatedProjectModule.id, + ActionTypeEnum.Updated, ActorTypeEnum.User, + updatedProjectModule.id, + updatedProjectModule.name, + updatedProjectModule, organizationId, tenantId, - ActionTypeEnum.Updated, - updatedProjectModule, - existingModule, + existingProjectModule, entity ); diff --git a/packages/core/src/organization-project/organization-project.service.ts b/packages/core/src/organization-project/organization-project.service.ts index 3e296a5d44..334353c9a4 100644 --- a/packages/core/src/organization-project/organization-project.service.ts +++ b/packages/core/src/organization-project/organization-project.service.ts @@ -125,13 +125,13 @@ export class OrganizationProjectService extends TenantAwareCrudService( BaseEntityEnum.OrganizationProject, - project.name, - project.id, + ActionTypeEnum.Created, ActorTypeEnum.User, + project.id, + project.name, + project, organizationId, - tenantId, - ActionTypeEnum.Created, - project + tenantId ); // Return the created project @@ -177,12 +177,28 @@ export class OrganizationProjectService extends TenantAwareCrudService( + BaseEntityEnum.OrganizationProject, + ActionTypeEnum.Updated, + ActorTypeEnum.User, + updatedProject.id, + updatedProject.name, + updatedProject, + organizationId, + tenantId, + organizationProject, + input + ); + + return updatedProject; } catch (error) { // Handle errors and return an appropriate error response throw new HttpException(`Failed to update organization project: ${error.message}`, HttpStatus.BAD_REQUEST); diff --git a/packages/core/src/organization-sprint/organization-sprint.service.ts b/packages/core/src/organization-sprint/organization-sprint.service.ts index 13be4a2682..4b3600239c 100644 --- a/packages/core/src/organization-sprint/organization-sprint.service.ts +++ b/packages/core/src/organization-sprint/organization-sprint.service.ts @@ -116,13 +116,13 @@ export class OrganizationSprintService extends TenantAwareCrudService( BaseEntityEnum.OrganizationSprint, - sprint.name, - sprint.id, + ActionTypeEnum.Created, ActorTypeEnum.User, + sprint.id, + sprint.name, + sprint, organizationId, - tenantId, - ActionTypeEnum.Created, - sprint + tenantId ); return sprint; @@ -184,13 +184,13 @@ export class OrganizationSprintService extends TenantAwareCrudService( BaseEntityEnum.OrganizationSprint, - updatedSprint.name, - updatedSprint.id, + ActionTypeEnum.Updated, ActorTypeEnum.User, + updatedSprint.id, + updatedSprint.name, + updatedSprint, organizationId, tenantId, - ActionTypeEnum.Updated, - updatedSprint, organizationSprint, input ); diff --git a/packages/core/src/resource-link/resource-link.service.ts b/packages/core/src/resource-link/resource-link.service.ts index cf5f08920d..a4f43eb916 100644 --- a/packages/core/src/resource-link/resource-link.service.ts +++ b/packages/core/src/resource-link/resource-link.service.ts @@ -56,13 +56,13 @@ export class ResourceLinkService extends TenantAwareCrudService { // Generate the activity log this.activityLogService.logActivity( BaseEntityEnum.ResourceLink, - resourceLink.title, - resourceLink.id, + ActionTypeEnum.Created, ActorTypeEnum.User, + resourceLink.id, + resourceLink.title, + resourceLink, resourceLink.organizationId, - tenantId, - ActionTypeEnum.Created, - resourceLink + tenantId ); return resourceLink; @@ -95,13 +95,13 @@ export class ResourceLinkService extends TenantAwareCrudService { const { organizationId, tenantId } = updatedResourceLink; this.activityLogService.logActivity( BaseEntityEnum.ResourceLink, - `${resourceLink.title} for ${resourceLink.entity}`, - resourceLink.id, + ActionTypeEnum.Updated, ActorTypeEnum.User, + resourceLink.id, + `${resourceLink.title} for ${resourceLink.entity}`, + updatedResourceLink, organizationId, tenantId, - ActionTypeEnum.Updated, - updatedResourceLink, resourceLink, input ); diff --git a/packages/core/src/tasks/commands/handlers/automation-task.sync.handler.ts b/packages/core/src/tasks/commands/handlers/automation-task.sync.handler.ts index baa35460f0..05c4ee02e5 100644 --- a/packages/core/src/tasks/commands/handlers/automation-task.sync.handler.ts +++ b/packages/core/src/tasks/commands/handlers/automation-task.sync.handler.ts @@ -149,13 +149,13 @@ export class AutomationTaskSyncHandler implements ICommandHandler( BaseEntityEnum.Task, - createdTask.title, - createdTask.id, + ActionTypeEnum.Created, ActorTypeEnum.System, + createdTask.id, + createdTask.title, + createdTask, organizationId, - tenantId, - ActionTypeEnum.Created, - createdTask + tenantId ); // Return the created Task @@ -191,13 +191,13 @@ export class AutomationTaskSyncHandler implements ICommandHandler( BaseEntityEnum.Task, - updatedTask.title, - updatedTask.id, + ActionTypeEnum.Updated, ActorTypeEnum.System, + updatedTask.id, + updatedTask.title, + updatedTask, organizationId, tenantId, - ActionTypeEnum.Updated, - updatedTask, existingTask, entity ); diff --git a/packages/core/src/tasks/commands/handlers/task-create.handler.ts b/packages/core/src/tasks/commands/handlers/task-create.handler.ts index 415ae74ea2..494f14a5d1 100644 --- a/packages/core/src/tasks/commands/handlers/task-create.handler.ts +++ b/packages/core/src/tasks/commands/handlers/task-create.handler.ts @@ -76,13 +76,13 @@ export class TaskCreateHandler implements ICommandHandler { // Generate the activity log this.activityLogService.logActivity( BaseEntityEnum.Task, - task.title, - task.id, + ActionTypeEnum.Created, ActorTypeEnum.User, // TODO : Since we have Github Integration, make sure we can also store "System" for actor + task.id, + task.title, + task, organizationId, - tenantId, - ActionTypeEnum.Created, - task + tenantId ); return task; // Return the created task diff --git a/packages/core/src/tasks/task.service.ts b/packages/core/src/tasks/task.service.ts index 1628abad69..61cca69169 100644 --- a/packages/core/src/tasks/task.service.ts +++ b/packages/core/src/tasks/task.service.ts @@ -103,13 +103,13 @@ export class TaskService extends TenantAwareCrudService { const { organizationId } = updatedTask; this.activityLogService.logActivity( BaseEntityEnum.Task, - updatedTask.title, - updatedTask.id, + ActionTypeEnum.Updated, ActorTypeEnum.User, // TODO : Since we have Github Integration, make sure we can also store "System" for actor + updatedTask.id, + updatedTask.title, + updatedTask, organizationId, tenantId, - ActionTypeEnum.Updated, - updatedTask, task, input ); diff --git a/packages/core/src/tasks/views/view.service.ts b/packages/core/src/tasks/views/view.service.ts index 0b7738d8f5..76428ebb86 100644 --- a/packages/core/src/tasks/views/view.service.ts +++ b/packages/core/src/tasks/views/view.service.ts @@ -47,13 +47,13 @@ export class TaskViewService extends TenantAwareCrudService { // Generate the activity log this.activityLogService.logActivity( BaseEntityEnum.TaskView, - taskView.name, - taskView.id, + ActionTypeEnum.Created, ActorTypeEnum.User, + taskView.id, + taskView.name, + taskView, organizationId, - tenantId, - ActionTypeEnum.Created, - taskView + tenantId ); // return the created task view @@ -78,9 +78,9 @@ export class TaskViewService extends TenantAwareCrudService { try { // Retrieve existing view. - const existingView = await this.findOneByIdString(id); + const existingTaskView = await this.findOneByIdString(id); - if (!existingView) { + if (!existingTaskView) { throw new NotFoundException('View not found'); } @@ -94,14 +94,14 @@ export class TaskViewService extends TenantAwareCrudService { const { organizationId } = updatedTaskView; this.activityLogService.logActivity( BaseEntityEnum.TaskView, - updatedTaskView.name, - updatedTaskView.id, + ActionTypeEnum.Updated, ActorTypeEnum.User, + updatedTaskView.id, + updatedTaskView.name, + updatedTaskView, organizationId, tenantId, - ActionTypeEnum.Updated, - updatedTaskView, - existingView, + existingTaskView, input );