From 39373b4a28e59cd99ee17e12a1a4dcadf4beff4d Mon Sep 17 00:00:00 2001 From: martmull Date: Thu, 21 Nov 2024 17:09:36 +0100 Subject: [PATCH] 8643 fix sentry error (#8644) - fixes missing data in event payload when adding a new workspaceMember - add strong typing to database event emitters --- .../on-custom-batch-event.decorator.ts | 13 +++ ...s => on-database-batch-event.decorator.ts} | 2 +- .../services/api-event-emitter.service.ts | 44 +++++----- .../user-signup-event-name.constants.ts | 1 + .../jobs/record-position-backfill.job.ts | 5 +- .../listeners/entity-events-to-db.listener.ts | 44 +++++----- .../listeners/telemetry.listener.ts | 21 +++-- .../billing-workspace-member.listener.ts | 8 +- .../types/object-record-create.event.ts | 4 +- .../types/object-record-delete.event.ts | 4 +- .../types/object-record-destroy.event.ts | 4 +- .../event-emitter/types/object-record-diff.ts | 3 + .../types/object-record-update.event.ts | 11 ++- .../types/object-record.base.event.ts | 13 ++- .../user-workspace/user-workspace.module.ts | 2 + .../user-workspace/user-workspace.service.ts | 45 ++++++---- .../services/__tests__/user.service.spec.ts | 5 ++ .../user/services/user.service.ts | 36 +++++--- .../engine/core-modules/user/user.module.ts | 2 + .../workspace-workspace-member.listener.ts | 8 +- .../serverless-function-published.ts | 2 +- ...erverless-function-publication.listener.ts | 12 +-- .../serverless-function.service.ts | 2 +- .../types/custom-event-name.type.ts | 1 + .../{ => types}/workspace-event.type.ts | 0 .../workspace-event-emitter.ts | 48 ++++++++++- ...ocklist-item-delete-calendar-events.job.ts | 2 +- .../blocklist-reimport-calendar-events.job.ts | 2 +- .../listeners/calendar-blocklist.listener.ts | 10 +-- ...vent-cleaner-connected-account.listener.ts | 6 +- ...endar-event-participant-person.listener.ts | 8 +- ...t-participant-workspace-member.listener.ts | 8 +- .../calendar-event-participant.listener.ts | 12 +-- .../listeners/connected-account.listener.ts | 6 +- ...ected-account-delete-one.pre-query.hook.ts | 39 ++++++--- .../connected-account-query-hook.module.ts | 7 +- ...acts-creation-calendar-channel.listener.ts | 6 +- ...tacts-creation-message-channel.listener.ts | 6 +- .../create-company-and-contact.service.ts | 27 +++--- .../listeners/favorite-folder.listener.ts | 7 +- .../match-participant.service.ts | 10 +-- ...ging-blocklist-item-delete-messages.job.ts | 2 +- ...ssaging-blocklist-reimport-messages.job.ts | 2 +- .../listeners/messaging-blocklist.listener.ts | 10 +-- ...sage-cleaner-connected-account.listener.ts | 6 +- ...import-manager-message-channel.listener.ts | 6 +- .../message-participant-person.listener.ts | 8 +- ...e-participant-workspace-member.listener.ts | 8 +- .../listeners/message-participant.listener.ts | 18 ++-- .../create-audit-log-from-internal-event.ts | 2 +- ...meline-activity-from-internal-event.job.ts | 7 +- .../repositiories/audit-log.repository.ts | 2 +- .../services/timeline-activity.service.ts | 25 +++--- .../webhook/jobs/call-webhook-jobs.job.ts | 2 +- .../workflow-create-many.post-query.hook.ts | 14 +-- .../workflow-create-one.post-query.hook.ts | 14 +-- ...rkflow-version-status-updated.constants.ts | 2 + .../workflow-version-status.listener.ts | 30 ++++--- .../database-event-trigger.listener.ts | 28 +++--- .../workflow-trigger.module.ts | 4 + .../workflow-trigger.workspace-service.ts | 85 ++++++++++++------- 61 files changed, 460 insertions(+), 311 deletions(-) create mode 100644 packages/twenty-server/src/engine/api/graphql/graphql-query-runner/decorators/on-custom-batch-event.decorator.ts rename packages/twenty-server/src/engine/api/graphql/graphql-query-runner/decorators/{on-database-event.decorator.ts => on-database-batch-event.decorator.ts} (91%) create mode 100644 packages/twenty-server/src/engine/api/graphql/workspace-query-runner/constants/user-signup-event-name.constants.ts create mode 100644 packages/twenty-server/src/engine/core-modules/event-emitter/types/object-record-diff.ts create mode 100644 packages/twenty-server/src/engine/workspace-event-emitter/types/custom-event-name.type.ts rename packages/twenty-server/src/engine/workspace-event-emitter/{ => types}/workspace-event.type.ts (100%) create mode 100644 packages/twenty-server/src/modules/workflow/workflow-status/constants/workflow-version-status-updated.constants.ts diff --git a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/decorators/on-custom-batch-event.decorator.ts b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/decorators/on-custom-batch-event.decorator.ts new file mode 100644 index 000000000..98a6339fb --- /dev/null +++ b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/decorators/on-custom-batch-event.decorator.ts @@ -0,0 +1,13 @@ +import { OnEvent } from '@nestjs/event-emitter'; + +import { CustomEventName } from 'src/engine/workspace-event-emitter/types/custom-event-name.type'; + +export function OnCustomBatchEvent(event: CustomEventName): MethodDecorator { + return ( + target: object, + propertyKey: string, + descriptor: PropertyDescriptor, + ) => { + OnEvent(event)(target, propertyKey, descriptor); + }; +} diff --git a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/decorators/on-database-event.decorator.ts b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/decorators/on-database-batch-event.decorator.ts similarity index 91% rename from packages/twenty-server/src/engine/api/graphql/graphql-query-runner/decorators/on-database-event.decorator.ts rename to packages/twenty-server/src/engine/api/graphql/graphql-query-runner/decorators/on-database-batch-event.decorator.ts index b874ac8f3..fd5bfdf8c 100644 --- a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/decorators/on-database-event.decorator.ts +++ b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/decorators/on-database-batch-event.decorator.ts @@ -2,7 +2,7 @@ import { OnEvent } from '@nestjs/event-emitter'; import { DatabaseEventAction } from 'src/engine/api/graphql/graphql-query-runner/enums/database-event-action'; -export function OnDatabaseEvent( +export function OnDatabaseBatchEvent( object: string, action: DatabaseEventAction, ): MethodDecorator { diff --git a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/services/api-event-emitter.service.ts b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/services/api-event-emitter.service.ts index 1f5c96fd9..98f7adbd9 100644 --- a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/services/api-event-emitter.service.ts +++ b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/services/api-event-emitter.service.ts @@ -17,9 +17,10 @@ export class ApiEventEmitterService { authContext: AuthContext, objectMetadataItem: ObjectMetadataInterface, ): void { - this.workspaceEventEmitter.emit( - `${objectMetadataItem.nameSingular}.${DatabaseEventAction.CREATED}`, - records.map((record) => ({ + this.workspaceEventEmitter.emitDatabaseBatchEvent({ + objectMetadataNameSingular: objectMetadataItem.nameSingular, + action: DatabaseEventAction.CREATED, + events: records.map((record) => ({ userId: authContext.user?.id, recordId: record.id, objectMetadata: objectMetadataItem, @@ -28,8 +29,8 @@ export class ApiEventEmitterService { after: this.removeGraphQLAndNestedProperties(record), }, })), - authContext.workspace.id, - ); + workspaceId: authContext.workspace.id, + }); } public emitUpdateEvents( @@ -47,9 +48,10 @@ export class ApiEventEmitterService { {}, ); - this.workspaceEventEmitter.emit( - `${objectMetadataItem.nameSingular}.${DatabaseEventAction.UPDATED}`, - records.map((record) => { + this.workspaceEventEmitter.emitDatabaseBatchEvent({ + objectMetadataNameSingular: objectMetadataItem.nameSingular, + action: DatabaseEventAction.UPDATED, + events: records.map((record) => { const before = this.removeGraphQLAndNestedProperties( mappedExistingRecords[record.id], ); @@ -73,8 +75,8 @@ export class ApiEventEmitterService { }, }; }), - authContext.workspace.id, - ); + workspaceId: authContext.workspace.id, + }); } public emitDeletedEvents( @@ -82,9 +84,10 @@ export class ApiEventEmitterService { authContext: AuthContext, objectMetadataItem: ObjectMetadataInterface, ): void { - this.workspaceEventEmitter.emit( - `${objectMetadataItem.nameSingular}.${DatabaseEventAction.DELETED}`, - records.map((record) => { + this.workspaceEventEmitter.emitDatabaseBatchEvent({ + objectMetadataNameSingular: objectMetadataItem.nameSingular, + action: DatabaseEventAction.DELETED, + events: records.map((record) => { return { userId: authContext.user?.id, recordId: record.id, @@ -95,8 +98,8 @@ export class ApiEventEmitterService { }, }; }), - authContext.workspace.id, - ); + workspaceId: authContext.workspace.id, + }); } public emitDestroyEvents( @@ -104,9 +107,10 @@ export class ApiEventEmitterService { authContext: AuthContext, objectMetadataItem: ObjectMetadataInterface, ): void { - this.workspaceEventEmitter.emit( - `${objectMetadataItem.nameSingular}.${DatabaseEventAction.DESTROYED}`, - records.map((record) => { + this.workspaceEventEmitter.emitDatabaseBatchEvent({ + objectMetadataNameSingular: objectMetadataItem.nameSingular, + action: DatabaseEventAction.DESTROYED, + events: records.map((record) => { return { userId: authContext.user?.id, recordId: record.id, @@ -117,8 +121,8 @@ export class ApiEventEmitterService { }, }; }), - authContext.workspace.id, - ); + workspaceId: authContext.workspace.id, + }); } private removeGraphQLAndNestedProperties(record: T) { diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/constants/user-signup-event-name.constants.ts b/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/constants/user-signup-event-name.constants.ts new file mode 100644 index 000000000..cc817accd --- /dev/null +++ b/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/constants/user-signup-event-name.constants.ts @@ -0,0 +1 @@ +export const USER_SIGNUP_EVENT_NAME = 'user_signup'; diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/jobs/record-position-backfill.job.ts b/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/jobs/record-position-backfill.job.ts index 67cf1dd55..bdf90fd7b 100644 --- a/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/jobs/record-position-backfill.job.ts +++ b/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/jobs/record-position-backfill.job.ts @@ -16,6 +16,9 @@ export class RecordPositionBackfillJob { @Process(RecordPositionBackfillJob.name) async handle(data: RecordPositionBackfillJobData): Promise { - this.recordPositionBackfillService.backfill(data.workspaceId, data.dryRun); + await this.recordPositionBackfillService.backfill( + data.workspaceId, + data.dryRun, + ); } } diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/listeners/entity-events-to-db.listener.ts b/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/listeners/entity-events-to-db.listener.ts index f278e2565..1b7e6fb7c 100644 --- a/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/listeners/entity-events-to-db.listener.ts +++ b/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/listeners/entity-events-to-db.listener.ts @@ -6,10 +6,10 @@ import { ObjectRecordBaseEvent } from 'src/engine/core-modules/event-emitter/typ import { InjectMessageQueue } from 'src/engine/core-modules/message-queue/decorators/message-queue.decorator'; import { MessageQueue } from 'src/engine/core-modules/message-queue/message-queue.constants'; import { MessageQueueService } from 'src/engine/core-modules/message-queue/services/message-queue.service'; -import { WorkspaceEventBatch } from 'src/engine/workspace-event-emitter/workspace-event.type'; +import { WorkspaceEventBatch } from 'src/engine/workspace-event-emitter/types/workspace-event.type'; import { CreateAuditLogFromInternalEvent } from 'src/modules/timeline/jobs/create-audit-log-from-internal-event'; import { UpsertTimelineActivityFromInternalEvent } from 'src/modules/timeline/jobs/upsert-timeline-activity-from-internal-event.job'; -import { OnDatabaseEvent } from 'src/engine/api/graphql/graphql-query-runner/decorators/on-database-event.decorator'; +import { OnDatabaseBatchEvent } from 'src/engine/api/graphql/graphql-query-runner/decorators/on-database-batch-event.decorator'; import { CallWebhookJobsJob } from 'src/modules/webhook/jobs/call-webhook-jobs.job'; import { DatabaseEventAction } from 'src/engine/api/graphql/graphql-query-runner/enums/database-event-action'; @@ -22,55 +22,49 @@ export class EntityEventsToDbListener { private readonly webhookQueueService: MessageQueueService, ) {} - @OnDatabaseEvent('*', DatabaseEventAction.CREATED) - async handleCreate( - payload: WorkspaceEventBatch>, - ) { - return this.handle(payload); + @OnDatabaseBatchEvent('*', DatabaseEventAction.CREATED) + async handleCreate(batchEvent: WorkspaceEventBatch) { + return this.handle(batchEvent); } - @OnDatabaseEvent('*', DatabaseEventAction.UPDATED) - async handleUpdate( - payload: WorkspaceEventBatch>, - ) { - return this.handle(payload); + @OnDatabaseBatchEvent('*', DatabaseEventAction.UPDATED) + async handleUpdate(batchEvent: WorkspaceEventBatch) { + return this.handle(batchEvent); } - @OnDatabaseEvent('*', DatabaseEventAction.DELETED) - async handleDelete( - payload: WorkspaceEventBatch>, - ) { - return this.handle(payload); + @OnDatabaseBatchEvent('*', DatabaseEventAction.DELETED) + async handleDelete(batchEvent: WorkspaceEventBatch) { + return this.handle(batchEvent); } - @OnDatabaseEvent('*', DatabaseEventAction.DESTROYED) + @OnDatabaseBatchEvent('*', DatabaseEventAction.DESTROYED) async handleDestroy( - payload: WorkspaceEventBatch>, + batchEvent: WorkspaceEventBatch, ) { - return this.handle(payload); + return this.handle(batchEvent); } - private async handle(payload: WorkspaceEventBatch) { - const filteredEvents = payload.events.filter( + private async handle(batchEvent: WorkspaceEventBatch) { + const filteredEvents = batchEvent.events.filter( (event) => event.objectMetadata?.isAuditLogged, ); await this.entityEventsToDbQueueService.add< WorkspaceEventBatch >(CreateAuditLogFromInternalEvent.name, { - ...payload, + ...batchEvent, events: filteredEvents, }); await this.entityEventsToDbQueueService.add< WorkspaceEventBatch >(UpsertTimelineActivityFromInternalEvent.name, { - ...payload, + ...batchEvent, events: filteredEvents, }); await this.webhookQueueService.add< WorkspaceEventBatch - >(CallWebhookJobsJob.name, payload, { retryLimit: 3 }); + >(CallWebhookJobsJob.name, batchEvent, { retryLimit: 3 }); } } diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/listeners/telemetry.listener.ts b/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/listeners/telemetry.listener.ts index df7d19671..304d78114 100644 --- a/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/listeners/telemetry.listener.ts +++ b/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/listeners/telemetry.listener.ts @@ -1,12 +1,13 @@ import { Injectable } from '@nestjs/common'; -import { OnEvent } from '@nestjs/event-emitter'; -import { OnDatabaseEvent } from 'src/engine/api/graphql/graphql-query-runner/decorators/on-database-event.decorator'; +import { OnDatabaseBatchEvent } from 'src/engine/api/graphql/graphql-query-runner/decorators/on-database-batch-event.decorator'; import { DatabaseEventAction } from 'src/engine/api/graphql/graphql-query-runner/enums/database-event-action'; import { AnalyticsService } from 'src/engine/core-modules/analytics/analytics.service'; import { ObjectRecordCreateEvent } from 'src/engine/core-modules/event-emitter/types/object-record-create.event'; import { TelemetryService } from 'src/engine/core-modules/telemetry/telemetry.service'; -import { WorkspaceEventBatch } from 'src/engine/workspace-event-emitter/workspace-event.type'; +import { WorkspaceEventBatch } from 'src/engine/workspace-event-emitter/types/workspace-event.type'; +import { USER_SIGNUP_EVENT_NAME } from 'src/engine/api/graphql/workspace-query-runner/constants/user-signup-event-name.constants'; +import { OnCustomBatchEvent } from 'src/engine/api/graphql/graphql-query-runner/decorators/on-custom-batch-event.decorator'; @Injectable() export class TelemetryListener { @@ -15,10 +16,8 @@ export class TelemetryListener { private readonly telemetryService: TelemetryService, ) {} - @OnDatabaseEvent('*', DatabaseEventAction.CREATED) - async handleAllCreate( - payload: WorkspaceEventBatch>, - ) { + @OnDatabaseBatchEvent('*', DatabaseEventAction.CREATED) + async handleAllCreate(payload: WorkspaceEventBatch) { await Promise.all( payload.events.map((eventPayload) => this.analyticsService.create( @@ -33,15 +32,15 @@ export class TelemetryListener { ); } - @OnEvent('user.signup') + @OnCustomBatchEvent(USER_SIGNUP_EVENT_NAME) async handleUserSignup( - payload: WorkspaceEventBatch>, + payload: WorkspaceEventBatch, ) { await Promise.all( payload.events.map(async (eventPayload) => { this.analyticsService.create( { - action: 'user.signup', + action: USER_SIGNUP_EVENT_NAME, payload: {}, }, eventPayload.userId, @@ -50,7 +49,7 @@ export class TelemetryListener { this.telemetryService.create( { - action: 'user.signup', + action: USER_SIGNUP_EVENT_NAME, payload: { payload, userId: undefined, diff --git a/packages/twenty-server/src/engine/core-modules/billing/listeners/billing-workspace-member.listener.ts b/packages/twenty-server/src/engine/core-modules/billing/listeners/billing-workspace-member.listener.ts index 4ca381bd2..9911bec57 100644 --- a/packages/twenty-server/src/engine/core-modules/billing/listeners/billing-workspace-member.listener.ts +++ b/packages/twenty-server/src/engine/core-modules/billing/listeners/billing-workspace-member.listener.ts @@ -9,9 +9,9 @@ import { ObjectRecordCreateEvent } from 'src/engine/core-modules/event-emitter/t import { InjectMessageQueue } from 'src/engine/core-modules/message-queue/decorators/message-queue.decorator'; import { MessageQueue } from 'src/engine/core-modules/message-queue/message-queue.constants'; import { MessageQueueService } from 'src/engine/core-modules/message-queue/services/message-queue.service'; -import { WorkspaceEventBatch } from 'src/engine/workspace-event-emitter/workspace-event.type'; +import { WorkspaceEventBatch } from 'src/engine/workspace-event-emitter/types/workspace-event.type'; import { WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/standard-objects/workspace-member.workspace-entity'; -import { OnDatabaseEvent } from 'src/engine/api/graphql/graphql-query-runner/decorators/on-database-event.decorator'; +import { OnDatabaseBatchEvent } from 'src/engine/api/graphql/graphql-query-runner/decorators/on-database-batch-event.decorator'; import { DatabaseEventAction } from 'src/engine/api/graphql/graphql-query-runner/enums/database-event-action'; @Injectable() @@ -22,8 +22,8 @@ export class BillingWorkspaceMemberListener { private readonly environmentService: EnvironmentService, ) {} - @OnDatabaseEvent('workspaceMember', DatabaseEventAction.CREATED) - @OnDatabaseEvent('workspaceMember', DatabaseEventAction.DELETED) + @OnDatabaseBatchEvent('workspaceMember', DatabaseEventAction.CREATED) + @OnDatabaseBatchEvent('workspaceMember', DatabaseEventAction.DELETED) async handleCreateOrDeleteEvent( payload: WorkspaceEventBatch< ObjectRecordCreateEvent diff --git a/packages/twenty-server/src/engine/core-modules/event-emitter/types/object-record-create.event.ts b/packages/twenty-server/src/engine/core-modules/event-emitter/types/object-record-create.event.ts index 62221beaa..45c4f68dc 100644 --- a/packages/twenty-server/src/engine/core-modules/event-emitter/types/object-record-create.event.ts +++ b/packages/twenty-server/src/engine/core-modules/event-emitter/types/object-record-create.event.ts @@ -1,6 +1,8 @@ import { ObjectRecordBaseEvent } from 'src/engine/core-modules/event-emitter/types/object-record.base.event'; -export class ObjectRecordCreateEvent extends ObjectRecordBaseEvent { +export class ObjectRecordCreateEvent< + T = object, +> extends ObjectRecordBaseEvent { properties: { after: T; }; diff --git a/packages/twenty-server/src/engine/core-modules/event-emitter/types/object-record-delete.event.ts b/packages/twenty-server/src/engine/core-modules/event-emitter/types/object-record-delete.event.ts index 644ab0658..b9717ba13 100644 --- a/packages/twenty-server/src/engine/core-modules/event-emitter/types/object-record-delete.event.ts +++ b/packages/twenty-server/src/engine/core-modules/event-emitter/types/object-record-delete.event.ts @@ -1,6 +1,8 @@ import { ObjectRecordBaseEvent } from 'src/engine/core-modules/event-emitter/types/object-record.base.event'; -export class ObjectRecordDeleteEvent extends ObjectRecordBaseEvent { +export class ObjectRecordDeleteEvent< + T = object, +> extends ObjectRecordBaseEvent { properties: { before: T; }; diff --git a/packages/twenty-server/src/engine/core-modules/event-emitter/types/object-record-destroy.event.ts b/packages/twenty-server/src/engine/core-modules/event-emitter/types/object-record-destroy.event.ts index f12b1e175..6f1ae908e 100644 --- a/packages/twenty-server/src/engine/core-modules/event-emitter/types/object-record-destroy.event.ts +++ b/packages/twenty-server/src/engine/core-modules/event-emitter/types/object-record-destroy.event.ts @@ -1,6 +1,8 @@ import { ObjectRecordBaseEvent } from 'src/engine/core-modules/event-emitter/types/object-record.base.event'; -export class ObjectRecordDestroyEvent extends ObjectRecordBaseEvent { +export class ObjectRecordDestroyEvent< + T = object, +> extends ObjectRecordBaseEvent { properties: { before: T; }; diff --git a/packages/twenty-server/src/engine/core-modules/event-emitter/types/object-record-diff.ts b/packages/twenty-server/src/engine/core-modules/event-emitter/types/object-record-diff.ts new file mode 100644 index 000000000..bee7bef1f --- /dev/null +++ b/packages/twenty-server/src/engine/core-modules/event-emitter/types/object-record-diff.ts @@ -0,0 +1,3 @@ +export type ObjectRecordDiff = { + [K in keyof T]: { before: T[K]; after: T[K] }; +}; diff --git a/packages/twenty-server/src/engine/core-modules/event-emitter/types/object-record-update.event.ts b/packages/twenty-server/src/engine/core-modules/event-emitter/types/object-record-update.event.ts index a6fb5938b..ba80ea332 100644 --- a/packages/twenty-server/src/engine/core-modules/event-emitter/types/object-record-update.event.ts +++ b/packages/twenty-server/src/engine/core-modules/event-emitter/types/object-record-update.event.ts @@ -1,14 +1,13 @@ import { ObjectRecordBaseEvent } from 'src/engine/core-modules/event-emitter/types/object-record.base.event'; +import { ObjectRecordDiff } from 'src/engine/core-modules/event-emitter/types/object-record-diff'; -type Diff = { - [K in keyof T]: { before: T[K]; after: T[K] }; -}; - -export class ObjectRecordUpdateEvent extends ObjectRecordBaseEvent { +export class ObjectRecordUpdateEvent< + T = object, +> extends ObjectRecordBaseEvent { properties: { updatedFields?: string[]; before: T; after: T; - diff?: Partial>; + diff?: Partial>; }; } diff --git a/packages/twenty-server/src/engine/core-modules/event-emitter/types/object-record.base.event.ts b/packages/twenty-server/src/engine/core-modules/event-emitter/types/object-record.base.event.ts index 0295724e8..fa9a4a89e 100644 --- a/packages/twenty-server/src/engine/core-modules/event-emitter/types/object-record.base.event.ts +++ b/packages/twenty-server/src/engine/core-modules/event-emitter/types/object-record.base.event.ts @@ -1,9 +1,18 @@ import { ObjectMetadataInterface } from 'src/engine/metadata-modules/field-metadata/interfaces/object-metadata.interface'; -export class ObjectRecordBaseEvent { +import { ObjectRecordDiff } from 'src/engine/core-modules/event-emitter/types/object-record-diff'; + +type Properties = { + updatedFields?: string[]; + before?: T; + after?: T; + diff?: Partial>; +}; + +export class ObjectRecordBaseEvent { recordId: string; userId?: string; workspaceMemberId?: string; objectMetadata: ObjectMetadataInterface; - properties: any; + properties: Properties; } diff --git a/packages/twenty-server/src/engine/core-modules/user-workspace/user-workspace.module.ts b/packages/twenty-server/src/engine/core-modules/user-workspace/user-workspace.module.ts index c7967cd63..c192cd11d 100644 --- a/packages/twenty-server/src/engine/core-modules/user-workspace/user-workspace.module.ts +++ b/packages/twenty-server/src/engine/core-modules/user-workspace/user-workspace.module.ts @@ -11,6 +11,7 @@ import { WorkspaceDataSourceModule } from 'src/engine/workspace-datasource/works import { User } from 'src/engine/core-modules/user/user.entity'; import { AppToken } from 'src/engine/core-modules/app-token/app-token.entity'; import { WorkspaceInvitationModule } from 'src/engine/core-modules/workspace-invitation/workspace-invitation.module'; +import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; @Module({ imports: [ @@ -20,6 +21,7 @@ import { WorkspaceInvitationModule } from 'src/engine/core-modules/workspace-inv [User, UserWorkspace, AppToken], 'core', ), + NestjsQueryTypeOrmModule.forFeature([ObjectMetadataEntity], 'metadata'), TypeORMModule, DataSourceModule, WorkspaceDataSourceModule, diff --git a/packages/twenty-server/src/engine/core-modules/user-workspace/user-workspace.service.ts b/packages/twenty-server/src/engine/core-modules/user-workspace/user-workspace.service.ts index 0590033fb..8fa5f815e 100644 --- a/packages/twenty-server/src/engine/core-modules/user-workspace/user-workspace.service.ts +++ b/packages/twenty-server/src/engine/core-modules/user-workspace/user-workspace.service.ts @@ -9,16 +9,16 @@ import { AppToken, AppTokenType, } from 'src/engine/core-modules/app-token/app-token.entity'; -import { ObjectRecordCreateEvent } from 'src/engine/core-modules/event-emitter/types/object-record-create.event'; import { UserWorkspace } from 'src/engine/core-modules/user-workspace/user-workspace.entity'; import { User } from 'src/engine/core-modules/user/user.entity'; import { WorkspaceInvitationService } from 'src/engine/core-modules/workspace-invitation/services/workspace-invitation.service'; import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity'; import { DataSourceService } from 'src/engine/metadata-modules/data-source/data-source.service'; import { WorkspaceEventEmitter } from 'src/engine/workspace-event-emitter/workspace-event-emitter'; -import { WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/standard-objects/workspace-member.workspace-entity'; import { assert } from 'src/utils/assert'; import { DatabaseEventAction } from 'src/engine/api/graphql/graphql-query-runner/enums/database-event-action'; +import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; +import { USER_SIGNUP_EVENT_NAME } from 'src/engine/api/graphql/workspace-query-runner/constants/user-signup-event-name.constants'; export class UserWorkspaceService extends TypeOrmQueryService { constructor( @@ -28,6 +28,8 @@ export class UserWorkspaceService extends TypeOrmQueryService { private readonly userRepository: Repository, @InjectRepository(AppToken, 'core') private readonly appTokenRepository: Repository, + @InjectRepository(ObjectMetadataEntity, 'metadata') + private readonly objectMetadataRepository: Repository, private readonly dataSourceService: DataSourceService, private readonly typeORMService: TypeORMService, private readonly workspaceInvitationService: WorkspaceInvitationService, @@ -42,11 +44,11 @@ export class UserWorkspaceService extends TypeOrmQueryService { workspaceId, }); - const payload = new ObjectRecordCreateEvent(); - - payload.userId = userId; - - this.workspaceEventEmitter.emit('user.signup', [payload], workspaceId); + this.workspaceEventEmitter.emitCustomBatchEvent( + USER_SIGNUP_EVENT_NAME, + [{ userId }], + workspaceId, + ); return this.userWorkspaceRepository.save(userWorkspace); } @@ -80,19 +82,26 @@ export class UserWorkspaceService extends TypeOrmQueryService { workspaceMember.length === 1, `Error while creating workspace member ${user.email} on workspace ${workspaceId}`, ); - const payload = - new ObjectRecordCreateEvent(); + const objectMetadata = await this.objectMetadataRepository.findOneOrFail({ + where: { + nameSingular: 'workspaceMember', + }, + }); - payload.properties = { - after: workspaceMember[0], - }; - payload.recordId = workspaceMember[0].id; - - this.workspaceEventEmitter.emit( - `workspaceMember.${DatabaseEventAction.CREATED}`, - [payload], + this.workspaceEventEmitter.emitDatabaseBatchEvent({ + objectMetadataNameSingular: 'workspaceMember', + action: DatabaseEventAction.CREATED, + events: [ + { + recordId: workspaceMember[0].id, + objectMetadata, + properties: { + after: workspaceMember[0], + }, + }, + ], workspaceId, - ); + }); } async addUserToWorkspace(user: User, workspace: Workspace) { diff --git a/packages/twenty-server/src/engine/core-modules/user/services/__tests__/user.service.spec.ts b/packages/twenty-server/src/engine/core-modules/user/services/__tests__/user.service.spec.ts index 24b5b23bf..1dc841451 100644 --- a/packages/twenty-server/src/engine/core-modules/user/services/__tests__/user.service.spec.ts +++ b/packages/twenty-server/src/engine/core-modules/user/services/__tests__/user.service.spec.ts @@ -9,6 +9,7 @@ import { WorkspaceService } from 'src/engine/core-modules/workspace/services/wor import { DataSourceService } from 'src/engine/metadata-modules/data-source/data-source.service'; import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager'; import { WorkspaceEventEmitter } from 'src/engine/workspace-event-emitter/workspace-event-emitter'; +import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; describe('UserService', () => { let service: UserService; @@ -25,6 +26,10 @@ describe('UserService', () => { provide: getRepositoryToken(UserWorkspace, 'core'), useValue: {}, }, + { + provide: getRepositoryToken(ObjectMetadataEntity, 'metadata'), + useValue: {}, + }, { provide: DataSourceService, useValue: {}, diff --git a/packages/twenty-server/src/engine/core-modules/user/services/user.service.ts b/packages/twenty-server/src/engine/core-modules/user/services/user.service.ts index a27dc91f9..6bbc6e5fd 100644 --- a/packages/twenty-server/src/engine/core-modules/user/services/user.service.ts +++ b/packages/twenty-server/src/engine/core-modules/user/services/user.service.ts @@ -6,7 +6,6 @@ import { TypeOrmQueryService } from '@ptc-org/nestjs-query-typeorm'; import { Repository } from 'typeorm'; import { TypeORMService } from 'src/database/typeorm/typeorm.service'; -import { ObjectRecordDeleteEvent } from 'src/engine/core-modules/event-emitter/types/object-record-delete.event'; import { User } from 'src/engine/core-modules/user/user.entity'; import { WorkspaceService } from 'src/engine/core-modules/workspace/services/workspace.service'; import { @@ -18,12 +17,15 @@ import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global. import { WorkspaceEventEmitter } from 'src/engine/workspace-event-emitter/workspace-event-emitter'; import { WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/standard-objects/workspace-member.workspace-entity'; import { DatabaseEventAction } from 'src/engine/api/graphql/graphql-query-runner/enums/database-event-action'; +import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; // eslint-disable-next-line @nx/workspace-inject-workspace-repository export class UserService extends TypeOrmQueryService { constructor( @InjectRepository(User, 'core') private readonly userRepository: Repository, + @InjectRepository(ObjectMetadataEntity, 'metadata') + private readonly objectMetadataRepository: Repository, private readonly dataSourceService: DataSourceService, private readonly typeORMService: TypeORMService, private readonly workspaceEventEmitter: WorkspaceEventEmitter, @@ -44,13 +46,11 @@ export class UserService extends TypeOrmQueryService { 'workspaceMember', ); - const workspaceMember = await workspaceMemberRepository.findOne({ + return await workspaceMemberRepository.findOne({ where: { userId: user.id, }, }); - - return workspaceMember; } async loadWorkspaceMembers(workspace: Workspace) { @@ -107,19 +107,27 @@ export class UserService extends TypeOrmQueryService { await workspaceDataSource?.query( `DELETE FROM ${dataSourceMetadata.schema}."workspaceMember" WHERE "userId" = '${userId}'`, ); - const payload = - new ObjectRecordDeleteEvent(); - payload.properties = { - before: workspaceMember, - }; - payload.recordId = workspaceMember.id; + const objectMetadata = await this.objectMetadataRepository.findOneOrFail({ + where: { + nameSingular: 'workspaceMember', + }, + }); - this.workspaceEventEmitter.emit( - `workspaceMember.${DatabaseEventAction.DELETED}`, - [payload], + this.workspaceEventEmitter.emitDatabaseBatchEvent({ + objectMetadataNameSingular: 'workspaceMember', + action: DatabaseEventAction.DELETED, + events: [ + { + recordId: workspaceMember.id, + objectMetadata, + properties: { + before: workspaceMember, + }, + }, + ], workspaceId, - ); + }); return user; } diff --git a/packages/twenty-server/src/engine/core-modules/user/user.module.ts b/packages/twenty-server/src/engine/core-modules/user/user.module.ts index 57ea2140c..98b8b3afa 100644 --- a/packages/twenty-server/src/engine/core-modules/user/user.module.ts +++ b/packages/twenty-server/src/engine/core-modules/user/user.module.ts @@ -17,6 +17,7 @@ import { User } from 'src/engine/core-modules/user/user.entity'; import { UserResolver } from 'src/engine/core-modules/user/user.resolver'; import { WorkspaceModule } from 'src/engine/core-modules/workspace/workspace.module'; import { DataSourceModule } from 'src/engine/metadata-modules/data-source/data-source.module'; +import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; import { userAutoResolverOpts } from './user.auto-resolver-opts'; @@ -32,6 +33,7 @@ import { UserService } from './services/user.service'; ], resolvers: userAutoResolverOpts, }), + NestjsQueryTypeOrmModule.forFeature([ObjectMetadataEntity], 'metadata'), DataSourceModule, FileUploadModule, WorkspaceModule, diff --git a/packages/twenty-server/src/engine/core-modules/workspace/workspace-workspace-member.listener.ts b/packages/twenty-server/src/engine/core-modules/workspace/workspace-workspace-member.listener.ts index 6edfa356b..4949d7fb4 100644 --- a/packages/twenty-server/src/engine/core-modules/workspace/workspace-workspace-member.listener.ts +++ b/packages/twenty-server/src/engine/core-modules/workspace/workspace-workspace-member.listener.ts @@ -10,9 +10,9 @@ import { ObjectRecordUpdateEvent } from 'src/engine/core-modules/event-emitter/t import { InjectMessageQueue } from 'src/engine/core-modules/message-queue/decorators/message-queue.decorator'; import { MessageQueue } from 'src/engine/core-modules/message-queue/message-queue.constants'; import { MessageQueueService } from 'src/engine/core-modules/message-queue/services/message-queue.service'; -import { WorkspaceEventBatch } from 'src/engine/workspace-event-emitter/workspace-event.type'; +import { WorkspaceEventBatch } from 'src/engine/workspace-event-emitter/types/workspace-event.type'; import { WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/standard-objects/workspace-member.workspace-entity'; -import { OnDatabaseEvent } from 'src/engine/api/graphql/graphql-query-runner/decorators/on-database-event.decorator'; +import { OnDatabaseBatchEvent } from 'src/engine/api/graphql/graphql-query-runner/decorators/on-database-batch-event.decorator'; import { DatabaseEventAction } from 'src/engine/api/graphql/graphql-query-runner/enums/database-event-action'; @Injectable() @@ -23,7 +23,7 @@ export class WorkspaceWorkspaceMemberListener { private readonly messageQueueService: MessageQueueService, ) {} - @OnDatabaseEvent('workspaceMember', DatabaseEventAction.UPDATED) + @OnDatabaseBatchEvent('workspaceMember', DatabaseEventAction.UPDATED) async handleUpdateEvent( payload: WorkspaceEventBatch< ObjectRecordUpdateEvent @@ -51,7 +51,7 @@ export class WorkspaceWorkspaceMemberListener { ); } - @OnDatabaseEvent('workspaceMember', DatabaseEventAction.DELETED) + @OnDatabaseBatchEvent('workspaceMember', DatabaseEventAction.DELETED) async handleDeleteEvent( payload: WorkspaceEventBatch< ObjectRecordDeleteEvent diff --git a/packages/twenty-server/src/engine/metadata-modules/serverless-function/constants/serverless-function-published.ts b/packages/twenty-server/src/engine/metadata-modules/serverless-function/constants/serverless-function-published.ts index f95a071d7..d84ae37e0 100644 --- a/packages/twenty-server/src/engine/metadata-modules/serverless-function/constants/serverless-function-published.ts +++ b/packages/twenty-server/src/engine/metadata-modules/serverless-function/constants/serverless-function-published.ts @@ -1 +1 @@ -export const SERVERLESS_FUNCTION_PUBLISHED = 'serverlessFunction.published'; +export const SERVERLESS_FUNCTION_PUBLISHED = 'serverless_function_published'; diff --git a/packages/twenty-server/src/engine/metadata-modules/serverless-function/listeners/serverless-function-publication.listener.ts b/packages/twenty-server/src/engine/metadata-modules/serverless-function/listeners/serverless-function-publication.listener.ts index 8eb1d8851..86935b599 100644 --- a/packages/twenty-server/src/engine/metadata-modules/serverless-function/listeners/serverless-function-publication.listener.ts +++ b/packages/twenty-server/src/engine/metadata-modules/serverless-function/listeners/serverless-function-publication.listener.ts @@ -1,5 +1,4 @@ import { Injectable } from '@nestjs/common'; -import { OnEvent } from '@nestjs/event-emitter'; import { InjectRepository } from '@nestjs/typeorm'; import { join } from 'path'; @@ -10,8 +9,9 @@ import { INDEX_FILE_NAME } from 'src/engine/core-modules/serverless/drivers/cons import { SERVERLESS_FUNCTION_PUBLISHED } from 'src/engine/metadata-modules/serverless-function/constants/serverless-function-published'; import { ServerlessFunctionEntity } from 'src/engine/metadata-modules/serverless-function/serverless-function.entity'; import { ServerlessFunctionService } from 'src/engine/metadata-modules/serverless-function/serverless-function.service'; -import { WorkspaceEventBatch } from 'src/engine/workspace-event-emitter/workspace-event.type'; +import { WorkspaceEventBatch } from 'src/engine/workspace-event-emitter/types/workspace-event.type'; import { CodeIntrospectionService } from 'src/modules/code-introspection/code-introspection.service'; +import { OnCustomBatchEvent } from 'src/engine/api/graphql/graphql-query-runner/decorators/on-custom-batch-event.decorator'; @Injectable() export class ServerlessFunctionPublicationListener { @@ -22,17 +22,17 @@ export class ServerlessFunctionPublicationListener { private readonly serverlessFunctionRepository: Repository, ) {} - @OnEvent(SERVERLESS_FUNCTION_PUBLISHED) + @OnCustomBatchEvent(SERVERLESS_FUNCTION_PUBLISHED) async handle( - payload: WorkspaceEventBatch<{ + batchEvent: WorkspaceEventBatch<{ serverlessFunctionId: string; serverlessFunctionVersion: string; }>, ): Promise { - for (const event of payload.events) { + for (const event of batchEvent.events) { const sourceCode = await this.serverlessFunctionService.getServerlessFunctionSourceCode( - payload.workspaceId, + batchEvent.workspaceId, event.serverlessFunctionId, event.serverlessFunctionVersion, ); diff --git a/packages/twenty-server/src/engine/metadata-modules/serverless-function/serverless-function.service.ts b/packages/twenty-server/src/engine/metadata-modules/serverless-function/serverless-function.service.ts index 04c43224d..20e01b5b6 100644 --- a/packages/twenty-server/src/engine/metadata-modules/serverless-function/serverless-function.service.ts +++ b/packages/twenty-server/src/engine/metadata-modules/serverless-function/serverless-function.service.ts @@ -194,7 +194,7 @@ export class ServerlessFunctionService { }, ); - this.workspaceEventEmitter.emit( + this.workspaceEventEmitter.emitCustomBatchEvent( SERVERLESS_FUNCTION_PUBLISHED, [ { diff --git a/packages/twenty-server/src/engine/workspace-event-emitter/types/custom-event-name.type.ts b/packages/twenty-server/src/engine/workspace-event-emitter/types/custom-event-name.type.ts new file mode 100644 index 000000000..01a839267 --- /dev/null +++ b/packages/twenty-server/src/engine/workspace-event-emitter/types/custom-event-name.type.ts @@ -0,0 +1 @@ +export type CustomEventName = `${string}_${string}`; diff --git a/packages/twenty-server/src/engine/workspace-event-emitter/workspace-event.type.ts b/packages/twenty-server/src/engine/workspace-event-emitter/types/workspace-event.type.ts similarity index 100% rename from packages/twenty-server/src/engine/workspace-event-emitter/workspace-event.type.ts rename to packages/twenty-server/src/engine/workspace-event-emitter/types/workspace-event.type.ts diff --git a/packages/twenty-server/src/engine/workspace-event-emitter/workspace-event-emitter.ts b/packages/twenty-server/src/engine/workspace-event-emitter/workspace-event-emitter.ts index 374bc07c5..ee2e9be59 100644 --- a/packages/twenty-server/src/engine/workspace-event-emitter/workspace-event-emitter.ts +++ b/packages/twenty-server/src/engine/workspace-event-emitter/workspace-event-emitter.ts @@ -1,21 +1,61 @@ import { Injectable } from '@nestjs/common'; import { EventEmitter2 } from '@nestjs/event-emitter'; -import { WorkspaceEventBatch } from 'src/engine/workspace-event-emitter/workspace-event.type'; +import { ObjectRecordCreateEvent } from 'src/engine/core-modules/event-emitter/types/object-record-create.event'; +import { ObjectRecordUpdateEvent } from 'src/engine/core-modules/event-emitter/types/object-record-update.event'; +import { ObjectRecordDeleteEvent } from 'src/engine/core-modules/event-emitter/types/object-record-delete.event'; +import { ObjectRecordDestroyEvent } from 'src/engine/core-modules/event-emitter/types/object-record-destroy.event'; +import { DatabaseEventAction } from 'src/engine/api/graphql/graphql-query-runner/enums/database-event-action'; +import { CustomEventName } from 'src/engine/workspace-event-emitter/types/custom-event-name.type'; + +type ActionEventMap = { + [DatabaseEventAction.CREATED]: ObjectRecordCreateEvent; + [DatabaseEventAction.UPDATED]: ObjectRecordUpdateEvent; + [DatabaseEventAction.DELETED]: ObjectRecordDeleteEvent; + [DatabaseEventAction.DESTROYED]: ObjectRecordDestroyEvent; +}; @Injectable() export class WorkspaceEventEmitter { constructor(private readonly eventEmitter: EventEmitter2) {} - public emit(eventName: string, events: any[], workspaceId: string) { + public emitDatabaseBatchEvent>({ + objectMetadataNameSingular, + action, + events, + workspaceId, + }: { + objectMetadataNameSingular: string; + action: A; + events: ActionEventMap[A][]; + workspaceId: string; + }) { if (!events.length) { return; } - return this.eventEmitter.emit(eventName, { + const eventName = `${objectMetadataNameSingular}.${action}`; + + this.eventEmitter.emit(eventName, { name: eventName, workspaceId, events, - } satisfies WorkspaceEventBatch); + }); + } + + public emitCustomBatchEvent( + eventName: CustomEventName, + events: object[], + workspaceId: string, + ) { + if (!events.length) { + return; + } + + this.eventEmitter.emit(eventName, { + name: eventName, + workspaceId, + events, + }); } } diff --git a/packages/twenty-server/src/modules/calendar/blocklist-manager/jobs/blocklist-item-delete-calendar-events.job.ts b/packages/twenty-server/src/modules/calendar/blocklist-manager/jobs/blocklist-item-delete-calendar-events.job.ts index f21e87d76..0968fe601 100644 --- a/packages/twenty-server/src/modules/calendar/blocklist-manager/jobs/blocklist-item-delete-calendar-events.job.ts +++ b/packages/twenty-server/src/modules/calendar/blocklist-manager/jobs/blocklist-item-delete-calendar-events.job.ts @@ -7,7 +7,7 @@ import { Process } from 'src/engine/core-modules/message-queue/decorators/proces import { Processor } from 'src/engine/core-modules/message-queue/decorators/processor.decorator'; import { MessageQueue } from 'src/engine/core-modules/message-queue/message-queue.constants'; import { TwentyORMManager } from 'src/engine/twenty-orm/twenty-orm.manager'; -import { WorkspaceEventBatch } from 'src/engine/workspace-event-emitter/workspace-event.type'; +import { WorkspaceEventBatch } from 'src/engine/workspace-event-emitter/types/workspace-event.type'; import { BlocklistWorkspaceEntity } from 'src/modules/blocklist/standard-objects/blocklist.workspace-entity'; import { CalendarEventCleanerService } from 'src/modules/calendar/calendar-event-cleaner/services/calendar-event-cleaner.service'; import { CalendarChannelEventAssociationWorkspaceEntity } from 'src/modules/calendar/common/standard-objects/calendar-channel-event-association.workspace-entity'; diff --git a/packages/twenty-server/src/modules/calendar/blocklist-manager/jobs/blocklist-reimport-calendar-events.job.ts b/packages/twenty-server/src/modules/calendar/blocklist-manager/jobs/blocklist-reimport-calendar-events.job.ts index 434a6aa53..10e060fe8 100644 --- a/packages/twenty-server/src/modules/calendar/blocklist-manager/jobs/blocklist-reimport-calendar-events.job.ts +++ b/packages/twenty-server/src/modules/calendar/blocklist-manager/jobs/blocklist-reimport-calendar-events.job.ts @@ -7,7 +7,7 @@ import { Process } from 'src/engine/core-modules/message-queue/decorators/proces import { Processor } from 'src/engine/core-modules/message-queue/decorators/processor.decorator'; import { MessageQueue } from 'src/engine/core-modules/message-queue/message-queue.constants'; import { TwentyORMManager } from 'src/engine/twenty-orm/twenty-orm.manager'; -import { WorkspaceEventBatch } from 'src/engine/workspace-event-emitter/workspace-event.type'; +import { WorkspaceEventBatch } from 'src/engine/workspace-event-emitter/types/workspace-event.type'; import { BlocklistWorkspaceEntity } from 'src/modules/blocklist/standard-objects/blocklist.workspace-entity'; import { CalendarChannelSyncStatusService } from 'src/modules/calendar/common/services/calendar-channel-sync-status.service'; import { diff --git a/packages/twenty-server/src/modules/calendar/blocklist-manager/listeners/calendar-blocklist.listener.ts b/packages/twenty-server/src/modules/calendar/blocklist-manager/listeners/calendar-blocklist.listener.ts index 665acb577..b18681e54 100644 --- a/packages/twenty-server/src/modules/calendar/blocklist-manager/listeners/calendar-blocklist.listener.ts +++ b/packages/twenty-server/src/modules/calendar/blocklist-manager/listeners/calendar-blocklist.listener.ts @@ -6,7 +6,7 @@ import { ObjectRecordUpdateEvent } from 'src/engine/core-modules/event-emitter/t import { InjectMessageQueue } from 'src/engine/core-modules/message-queue/decorators/message-queue.decorator'; import { MessageQueue } from 'src/engine/core-modules/message-queue/message-queue.constants'; import { MessageQueueService } from 'src/engine/core-modules/message-queue/services/message-queue.service'; -import { WorkspaceEventBatch } from 'src/engine/workspace-event-emitter/workspace-event.type'; +import { WorkspaceEventBatch } from 'src/engine/workspace-event-emitter/types/workspace-event.type'; import { BlocklistWorkspaceEntity } from 'src/modules/blocklist/standard-objects/blocklist.workspace-entity'; import { BlocklistItemDeleteCalendarEventsJob, @@ -16,7 +16,7 @@ import { BlocklistReimportCalendarEventsJob, BlocklistReimportCalendarEventsJobData, } from 'src/modules/calendar/blocklist-manager/jobs/blocklist-reimport-calendar-events.job'; -import { OnDatabaseEvent } from 'src/engine/api/graphql/graphql-query-runner/decorators/on-database-event.decorator'; +import { OnDatabaseBatchEvent } from 'src/engine/api/graphql/graphql-query-runner/decorators/on-database-batch-event.decorator'; import { DatabaseEventAction } from 'src/engine/api/graphql/graphql-query-runner/enums/database-event-action'; @Injectable() @@ -26,7 +26,7 @@ export class CalendarBlocklistListener { private readonly messageQueueService: MessageQueueService, ) {} - @OnDatabaseEvent('blocklist', DatabaseEventAction.CREATED) + @OnDatabaseBatchEvent('blocklist', DatabaseEventAction.CREATED) async handleCreatedEvent( payload: WorkspaceEventBatch< ObjectRecordCreateEvent @@ -38,7 +38,7 @@ export class CalendarBlocklistListener { ); } - @OnDatabaseEvent('blocklist', DatabaseEventAction.DELETED) + @OnDatabaseBatchEvent('blocklist', DatabaseEventAction.DELETED) async handleDeletedEvent( payload: WorkspaceEventBatch< ObjectRecordDeleteEvent @@ -50,7 +50,7 @@ export class CalendarBlocklistListener { ); } - @OnDatabaseEvent('blocklist', DatabaseEventAction.UPDATED) + @OnDatabaseBatchEvent('blocklist', DatabaseEventAction.UPDATED) async handleUpdatedEvent( payload: WorkspaceEventBatch< ObjectRecordUpdateEvent diff --git a/packages/twenty-server/src/modules/calendar/calendar-event-cleaner/listeners/calendar-event-cleaner-connected-account.listener.ts b/packages/twenty-server/src/modules/calendar/calendar-event-cleaner/listeners/calendar-event-cleaner-connected-account.listener.ts index dac22ff35..28825970b 100644 --- a/packages/twenty-server/src/modules/calendar/calendar-event-cleaner/listeners/calendar-event-cleaner-connected-account.listener.ts +++ b/packages/twenty-server/src/modules/calendar/calendar-event-cleaner/listeners/calendar-event-cleaner-connected-account.listener.ts @@ -4,13 +4,13 @@ import { ObjectRecordDeleteEvent } from 'src/engine/core-modules/event-emitter/t import { InjectMessageQueue } from 'src/engine/core-modules/message-queue/decorators/message-queue.decorator'; import { MessageQueue } from 'src/engine/core-modules/message-queue/message-queue.constants'; import { MessageQueueService } from 'src/engine/core-modules/message-queue/services/message-queue.service'; -import { WorkspaceEventBatch } from 'src/engine/workspace-event-emitter/workspace-event.type'; +import { WorkspaceEventBatch } from 'src/engine/workspace-event-emitter/types/workspace-event.type'; import { DeleteConnectedAccountAssociatedCalendarDataJob, DeleteConnectedAccountAssociatedCalendarDataJobData, } from 'src/modules/calendar/calendar-event-cleaner/jobs/delete-connected-account-associated-calendar-data.job'; import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity'; -import { OnDatabaseEvent } from 'src/engine/api/graphql/graphql-query-runner/decorators/on-database-event.decorator'; +import { OnDatabaseBatchEvent } from 'src/engine/api/graphql/graphql-query-runner/decorators/on-database-batch-event.decorator'; import { DatabaseEventAction } from 'src/engine/api/graphql/graphql-query-runner/enums/database-event-action'; @Injectable() @@ -20,7 +20,7 @@ export class CalendarEventCleanerConnectedAccountListener { private readonly calendarQueueService: MessageQueueService, ) {} - @OnDatabaseEvent('connectedAccount', DatabaseEventAction.DESTROYED) + @OnDatabaseBatchEvent('connectedAccount', DatabaseEventAction.DESTROYED) async handleDestroyedEvent( payload: WorkspaceEventBatch< ObjectRecordDeleteEvent diff --git a/packages/twenty-server/src/modules/calendar/calendar-event-participant-manager/listeners/calendar-event-participant-person.listener.ts b/packages/twenty-server/src/modules/calendar/calendar-event-participant-manager/listeners/calendar-event-participant-person.listener.ts index 369de49c7..345e939bf 100644 --- a/packages/twenty-server/src/modules/calendar/calendar-event-participant-manager/listeners/calendar-event-participant-person.listener.ts +++ b/packages/twenty-server/src/modules/calendar/calendar-event-participant-manager/listeners/calendar-event-participant-person.listener.ts @@ -6,7 +6,7 @@ import { objectRecordChangedProperties as objectRecordUpdateEventChangedProperti import { InjectMessageQueue } from 'src/engine/core-modules/message-queue/decorators/message-queue.decorator'; import { MessageQueue } from 'src/engine/core-modules/message-queue/message-queue.constants'; import { MessageQueueService } from 'src/engine/core-modules/message-queue/services/message-queue.service'; -import { WorkspaceEventBatch } from 'src/engine/workspace-event-emitter/workspace-event.type'; +import { WorkspaceEventBatch } from 'src/engine/workspace-event-emitter/types/workspace-event.type'; import { CalendarEventParticipantMatchParticipantJob, CalendarEventParticipantMatchParticipantJobData, @@ -16,7 +16,7 @@ import { CalendarEventParticipantUnmatchParticipantJobData, } from 'src/modules/calendar/calendar-event-participant-manager/jobs/calendar-event-participant-unmatch-participant.job'; import { PersonWorkspaceEntity } from 'src/modules/person/standard-objects/person.workspace-entity'; -import { OnDatabaseEvent } from 'src/engine/api/graphql/graphql-query-runner/decorators/on-database-event.decorator'; +import { OnDatabaseBatchEvent } from 'src/engine/api/graphql/graphql-query-runner/decorators/on-database-batch-event.decorator'; import { DatabaseEventAction } from 'src/engine/api/graphql/graphql-query-runner/enums/database-event-action'; @Injectable() @@ -26,7 +26,7 @@ export class CalendarEventParticipantPersonListener { private readonly messageQueueService: MessageQueueService, ) {} - @OnDatabaseEvent('person', DatabaseEventAction.CREATED) + @OnDatabaseBatchEvent('person', DatabaseEventAction.CREATED) async handleCreatedEvent( payload: WorkspaceEventBatch< ObjectRecordCreateEvent @@ -49,7 +49,7 @@ export class CalendarEventParticipantPersonListener { } } - @OnDatabaseEvent('person', DatabaseEventAction.UPDATED) + @OnDatabaseBatchEvent('person', DatabaseEventAction.UPDATED) async handleUpdatedEvent( payload: WorkspaceEventBatch< ObjectRecordUpdateEvent diff --git a/packages/twenty-server/src/modules/calendar/calendar-event-participant-manager/listeners/calendar-event-participant-workspace-member.listener.ts b/packages/twenty-server/src/modules/calendar/calendar-event-participant-manager/listeners/calendar-event-participant-workspace-member.listener.ts index dabca70ef..74c06fff8 100644 --- a/packages/twenty-server/src/modules/calendar/calendar-event-participant-manager/listeners/calendar-event-participant-workspace-member.listener.ts +++ b/packages/twenty-server/src/modules/calendar/calendar-event-participant-manager/listeners/calendar-event-participant-workspace-member.listener.ts @@ -6,7 +6,7 @@ import { objectRecordChangedProperties as objectRecordUpdateEventChangedProperti import { InjectMessageQueue } from 'src/engine/core-modules/message-queue/decorators/message-queue.decorator'; import { MessageQueue } from 'src/engine/core-modules/message-queue/message-queue.constants'; import { MessageQueueService } from 'src/engine/core-modules/message-queue/services/message-queue.service'; -import { WorkspaceEventBatch } from 'src/engine/workspace-event-emitter/workspace-event.type'; +import { WorkspaceEventBatch } from 'src/engine/workspace-event-emitter/types/workspace-event.type'; import { CalendarEventParticipantMatchParticipantJob, CalendarEventParticipantMatchParticipantJobData, @@ -16,7 +16,7 @@ import { CalendarEventParticipantUnmatchParticipantJobData, } from 'src/modules/calendar/calendar-event-participant-manager/jobs/calendar-event-participant-unmatch-participant.job'; import { WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/standard-objects/workspace-member.workspace-entity'; -import { OnDatabaseEvent } from 'src/engine/api/graphql/graphql-query-runner/decorators/on-database-event.decorator'; +import { OnDatabaseBatchEvent } from 'src/engine/api/graphql/graphql-query-runner/decorators/on-database-batch-event.decorator'; import { DatabaseEventAction } from 'src/engine/api/graphql/graphql-query-runner/enums/database-event-action'; @Injectable() @@ -26,7 +26,7 @@ export class CalendarEventParticipantWorkspaceMemberListener { private readonly messageQueueService: MessageQueueService, ) {} - @OnDatabaseEvent('workspaceMember', DatabaseEventAction.CREATED) + @OnDatabaseBatchEvent('workspaceMember', DatabaseEventAction.CREATED) async handleCreatedEvent( payload: WorkspaceEventBatch< ObjectRecordCreateEvent @@ -48,7 +48,7 @@ export class CalendarEventParticipantWorkspaceMemberListener { } } - @OnDatabaseEvent('workspaceMember', DatabaseEventAction.UPDATED) + @OnDatabaseBatchEvent('workspaceMember', DatabaseEventAction.UPDATED) async handleUpdatedEvent( payload: WorkspaceEventBatch< ObjectRecordUpdateEvent diff --git a/packages/twenty-server/src/modules/calendar/calendar-event-participant-manager/listeners/calendar-event-participant.listener.ts b/packages/twenty-server/src/modules/calendar/calendar-event-participant-manager/listeners/calendar-event-participant.listener.ts index 72152cdc3..4997804b0 100644 --- a/packages/twenty-server/src/modules/calendar/calendar-event-participant-manager/listeners/calendar-event-participant.listener.ts +++ b/packages/twenty-server/src/modules/calendar/calendar-event-participant-manager/listeners/calendar-event-participant.listener.ts @@ -1,5 +1,4 @@ import { Injectable } from '@nestjs/common'; -import { OnEvent } from '@nestjs/event-emitter'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; @@ -7,10 +6,11 @@ import { Repository } from 'typeorm'; import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator'; import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service'; -import { WorkspaceEventBatch } from 'src/engine/workspace-event-emitter/workspace-event.type'; +import { WorkspaceEventBatch } from 'src/engine/workspace-event-emitter/types/workspace-event.type'; import { CalendarEventParticipantWorkspaceEntity } from 'src/modules/calendar/common/standard-objects/calendar-event-participant.workspace-entity'; import { TimelineActivityRepository } from 'src/modules/timeline/repositiories/timeline-activity.repository'; import { TimelineActivityWorkspaceEntity } from 'src/modules/timeline/standard-objects/timeline-activity.workspace-entity'; +import { OnCustomBatchEvent } from 'src/engine/api/graphql/graphql-query-runner/decorators/on-custom-batch-event.decorator'; @Injectable() export class CalendarEventParticipantListener { @@ -22,17 +22,17 @@ export class CalendarEventParticipantListener { private readonly objectMetadataRepository: Repository, ) {} - @OnEvent('calendarEventParticipant.matched') + @OnCustomBatchEvent('calendarEventParticipant_matched') public async handleCalendarEventParticipantMatchedEvent( - payload: WorkspaceEventBatch<{ + batchEvent: WorkspaceEventBatch<{ workspaceMemberId: string; participants: CalendarEventParticipantWorkspaceEntity[]; }>, ): Promise { - const workspaceId = payload.workspaceId; + const workspaceId = batchEvent.workspaceId; // TODO: Refactor to insertTimelineActivitiesForObject once - for (const eventPayload of payload.events) { + for (const eventPayload of batchEvent.events) { const calendarEventParticipants = eventPayload.participants; const workspaceMemberId = eventPayload.workspaceMemberId; diff --git a/packages/twenty-server/src/modules/connected-account/listeners/connected-account.listener.ts b/packages/twenty-server/src/modules/connected-account/listeners/connected-account.listener.ts index 073735e7d..323bc8edd 100644 --- a/packages/twenty-server/src/modules/connected-account/listeners/connected-account.listener.ts +++ b/packages/twenty-server/src/modules/connected-account/listeners/connected-account.listener.ts @@ -2,11 +2,11 @@ import { Injectable } from '@nestjs/common'; import { ObjectRecordDeleteEvent } from 'src/engine/core-modules/event-emitter/types/object-record-delete.event'; import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager'; -import { WorkspaceEventBatch } from 'src/engine/workspace-event-emitter/workspace-event.type'; +import { WorkspaceEventBatch } from 'src/engine/workspace-event-emitter/types/workspace-event.type'; import { AccountsToReconnectService } from 'src/modules/connected-account/services/accounts-to-reconnect.service'; import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity'; import { WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/standard-objects/workspace-member.workspace-entity'; -import { OnDatabaseEvent } from 'src/engine/api/graphql/graphql-query-runner/decorators/on-database-event.decorator'; +import { OnDatabaseBatchEvent } from 'src/engine/api/graphql/graphql-query-runner/decorators/on-database-batch-event.decorator'; import { DatabaseEventAction } from 'src/engine/api/graphql/graphql-query-runner/enums/database-event-action'; @Injectable() @@ -16,7 +16,7 @@ export class ConnectedAccountListener { private readonly accountsToReconnectService: AccountsToReconnectService, ) {} - @OnDatabaseEvent('connectedAccount', DatabaseEventAction.DESTROYED) + @OnDatabaseBatchEvent('connectedAccount', DatabaseEventAction.DESTROYED) async handleDestroyedEvent( payload: WorkspaceEventBatch< ObjectRecordDeleteEvent diff --git a/packages/twenty-server/src/modules/connected-account/query-hooks/connected-account-delete-one.pre-query.hook.ts b/packages/twenty-server/src/modules/connected-account/query-hooks/connected-account-delete-one.pre-query.hook.ts index 037a43e8f..a2a6fefc8 100644 --- a/packages/twenty-server/src/modules/connected-account/query-hooks/connected-account-delete-one.pre-query.hook.ts +++ b/packages/twenty-server/src/modules/connected-account/query-hooks/connected-account-delete-one.pre-query.hook.ts @@ -1,13 +1,17 @@ +import { InjectRepository } from '@nestjs/typeorm'; + +import { Repository } from 'typeorm'; + import { WorkspaceQueryHookInstance } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/interfaces/workspace-query-hook.interface'; import { DeleteOneResolverArgs } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface'; import { WorkspaceQueryHook } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/decorators/workspace-query-hook.decorator'; import { AuthContext } from 'src/engine/core-modules/auth/types/auth-context.type'; -import { ObjectRecordDeleteEvent } from 'src/engine/core-modules/event-emitter/types/object-record-delete.event'; import { TwentyORMManager } from 'src/engine/twenty-orm/twenty-orm.manager'; import { WorkspaceEventEmitter } from 'src/engine/workspace-event-emitter/workspace-event-emitter'; import { MessageChannelWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-channel.workspace-entity'; import { DatabaseEventAction } from 'src/engine/api/graphql/graphql-query-runner/enums/database-event-action'; +import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; @WorkspaceQueryHook(`connectedAccount.destroyOne`) export class ConnectedAccountDeleteOnePreQueryHook @@ -16,6 +20,8 @@ export class ConnectedAccountDeleteOnePreQueryHook constructor( private readonly twentyORMManager: TwentyORMManager, private readonly workspaceEventEmitter: WorkspaceEventEmitter, + @InjectRepository(ObjectMetadataEntity, 'metadata') + private readonly objectMetadataRepository: Repository, ) {} async execute( @@ -34,19 +40,24 @@ export class ConnectedAccountDeleteOnePreQueryHook connectedAccountId, }); - this.workspaceEventEmitter.emit( - `messageChannel.${DatabaseEventAction.DESTROYED}`, - messageChannels.map( - (messageChannel) => - ({ - recordId: messageChannel.id, - }) satisfies Pick< - ObjectRecordDeleteEvent, - 'recordId' - >, - ), - authContext.workspace.id, - ); + const objectMetadata = await this.objectMetadataRepository.findOneOrFail({ + where: { + nameSingular: 'messageChannel', + }, + }); + + this.workspaceEventEmitter.emitDatabaseBatchEvent({ + objectMetadataNameSingular: 'messageChannel', + action: DatabaseEventAction.DESTROYED, + events: messageChannels.map((messageChannel) => ({ + recordId: messageChannel.id, + objectMetadata, + properties: { + before: messageChannel, + }, + })), + workspaceId: authContext.workspace.id, + }); return payload; } diff --git a/packages/twenty-server/src/modules/connected-account/query-hooks/connected-account-query-hook.module.ts b/packages/twenty-server/src/modules/connected-account/query-hooks/connected-account-query-hook.module.ts index 225a1c3be..a82e51459 100644 --- a/packages/twenty-server/src/modules/connected-account/query-hooks/connected-account-query-hook.module.ts +++ b/packages/twenty-server/src/modules/connected-account/query-hooks/connected-account-query-hook.module.ts @@ -1,9 +1,14 @@ import { Module } from '@nestjs/common'; +import { NestjsQueryTypeOrmModule } from '@ptc-org/nestjs-query-typeorm'; + import { ConnectedAccountDeleteOnePreQueryHook } from 'src/modules/connected-account/query-hooks/connected-account-delete-one.pre-query.hook'; +import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; @Module({ - imports: [], + imports: [ + NestjsQueryTypeOrmModule.forFeature([ObjectMetadataEntity], 'metadata'), + ], providers: [ConnectedAccountDeleteOnePreQueryHook], }) export class ConnectedAccountQueryHookModule {} diff --git a/packages/twenty-server/src/modules/contact-creation-manager/listeners/auto-companies-and-contacts-creation-calendar-channel.listener.ts b/packages/twenty-server/src/modules/contact-creation-manager/listeners/auto-companies-and-contacts-creation-calendar-channel.listener.ts index 076c3dadb..d420f124d 100644 --- a/packages/twenty-server/src/modules/contact-creation-manager/listeners/auto-companies-and-contacts-creation-calendar-channel.listener.ts +++ b/packages/twenty-server/src/modules/contact-creation-manager/listeners/auto-companies-and-contacts-creation-calendar-channel.listener.ts @@ -5,13 +5,13 @@ import { objectRecordChangedProperties } from 'src/engine/core-modules/event-emi import { InjectMessageQueue } from 'src/engine/core-modules/message-queue/decorators/message-queue.decorator'; import { MessageQueue } from 'src/engine/core-modules/message-queue/message-queue.constants'; import { MessageQueueService } from 'src/engine/core-modules/message-queue/services/message-queue.service'; -import { WorkspaceEventBatch } from 'src/engine/workspace-event-emitter/workspace-event.type'; +import { WorkspaceEventBatch } from 'src/engine/workspace-event-emitter/types/workspace-event.type'; import { CalendarCreateCompanyAndContactAfterSyncJob, CalendarCreateCompanyAndContactAfterSyncJobData, } from 'src/modules/calendar/calendar-event-participant-manager/jobs/calendar-create-company-and-contact-after-sync.job'; import { MessageChannelWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-channel.workspace-entity'; -import { OnDatabaseEvent } from 'src/engine/api/graphql/graphql-query-runner/decorators/on-database-event.decorator'; +import { OnDatabaseBatchEvent } from 'src/engine/api/graphql/graphql-query-runner/decorators/on-database-batch-event.decorator'; import { DatabaseEventAction } from 'src/engine/api/graphql/graphql-query-runner/enums/database-event-action'; @Injectable() @@ -21,7 +21,7 @@ export class AutoCompaniesAndContactsCreationCalendarChannelListener { private readonly messageQueueService: MessageQueueService, ) {} - @OnDatabaseEvent('calendarChannel', DatabaseEventAction.UPDATED) + @OnDatabaseBatchEvent('calendarChannel', DatabaseEventAction.UPDATED) async handleUpdatedEvent( payload: WorkspaceEventBatch< ObjectRecordUpdateEvent diff --git a/packages/twenty-server/src/modules/contact-creation-manager/listeners/auto-companies-and-contacts-creation-message-channel.listener.ts b/packages/twenty-server/src/modules/contact-creation-manager/listeners/auto-companies-and-contacts-creation-message-channel.listener.ts index 60a394190..c97dcfda3 100644 --- a/packages/twenty-server/src/modules/contact-creation-manager/listeners/auto-companies-and-contacts-creation-message-channel.listener.ts +++ b/packages/twenty-server/src/modules/contact-creation-manager/listeners/auto-companies-and-contacts-creation-message-channel.listener.ts @@ -5,13 +5,13 @@ import { objectRecordChangedProperties } from 'src/engine/core-modules/event-emi import { InjectMessageQueue } from 'src/engine/core-modules/message-queue/decorators/message-queue.decorator'; import { MessageQueue } from 'src/engine/core-modules/message-queue/message-queue.constants'; import { MessageQueueService } from 'src/engine/core-modules/message-queue/services/message-queue.service'; -import { WorkspaceEventBatch } from 'src/engine/workspace-event-emitter/workspace-event.type'; +import { WorkspaceEventBatch } from 'src/engine/workspace-event-emitter/types/workspace-event.type'; import { MessageChannelWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-channel.workspace-entity'; import { MessagingCreateCompanyAndContactAfterSyncJob, MessagingCreateCompanyAndContactAfterSyncJobData, } from 'src/modules/messaging/message-participant-manager/jobs/messaging-create-company-and-contact-after-sync.job'; -import { OnDatabaseEvent } from 'src/engine/api/graphql/graphql-query-runner/decorators/on-database-event.decorator'; +import { OnDatabaseBatchEvent } from 'src/engine/api/graphql/graphql-query-runner/decorators/on-database-batch-event.decorator'; import { DatabaseEventAction } from 'src/engine/api/graphql/graphql-query-runner/enums/database-event-action'; @Injectable() @@ -21,7 +21,7 @@ export class AutoCompaniesAndContactsCreationMessageChannelListener { private readonly messageQueueService: MessageQueueService, ) {} - @OnDatabaseEvent('messageChannel', DatabaseEventAction.UPDATED) + @OnDatabaseBatchEvent('messageChannel', DatabaseEventAction.UPDATED) async handleUpdatedEvent( payload: WorkspaceEventBatch< ObjectRecordUpdateEvent diff --git a/packages/twenty-server/src/modules/contact-creation-manager/services/create-company-and-contact.service.ts b/packages/twenty-server/src/modules/contact-creation-manager/services/create-company-and-contact.service.ts index 712de3cc7..0d3b68024 100644 --- a/packages/twenty-server/src/modules/contact-creation-manager/services/create-company-and-contact.service.ts +++ b/packages/twenty-server/src/modules/contact-creation-manager/services/create-company-and-contact.service.ts @@ -5,7 +5,6 @@ import chunk from 'lodash.chunk'; import compact from 'lodash.compact'; import { Any, EntityManager, Repository } from 'typeorm'; -import { ObjectRecordCreateEvent } from 'src/engine/core-modules/event-emitter/types/object-record-create.event'; import { FieldActorSource } from 'src/engine/metadata-modules/field-metadata/composite-types/actor.composite-type'; import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity'; import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; @@ -195,21 +194,19 @@ export class CreateCompanyAndContactService { source, ); - this.workspaceEventEmitter.emit( - `person.${DatabaseEventAction.CREATED}`, - createdPeople.map( - (createdPerson) => - ({ - // FixMe: TypeORM typing issue... id is always returned when using save - recordId: createdPerson.id as string, - objectMetadata, - properties: { - after: createdPerson, - }, - }) satisfies ObjectRecordCreateEvent, - ), + this.workspaceEventEmitter.emitDatabaseBatchEvent({ + objectMetadataNameSingular: 'person', + action: DatabaseEventAction.CREATED, + events: createdPeople.map((createdPerson) => ({ + // Fix ' as string': TypeORM typing issue... id is always returned when using save + recordId: createdPerson.id as string, + objectMetadata, + properties: { + after: createdPerson, + }, + })), workspaceId, - ); + }); } } } diff --git a/packages/twenty-server/src/modules/favorite-folder/listeners/favorite-folder.listener.ts b/packages/twenty-server/src/modules/favorite-folder/listeners/favorite-folder.listener.ts index 0ec2990ed..cdae9d280 100644 --- a/packages/twenty-server/src/modules/favorite-folder/listeners/favorite-folder.listener.ts +++ b/packages/twenty-server/src/modules/favorite-folder/listeners/favorite-folder.listener.ts @@ -1,13 +1,14 @@ import { Injectable } from '@nestjs/common'; -import { OnEvent } from '@nestjs/event-emitter'; import { ObjectRecordDeleteEvent } from 'src/engine/core-modules/event-emitter/types/object-record-delete.event'; import { FeatureFlagKey } from 'src/engine/core-modules/feature-flag/enums/feature-flag-key.enum'; import { FeatureFlagService } from 'src/engine/core-modules/feature-flag/services/feature-flag.service'; import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager'; -import { WorkspaceEventBatch } from 'src/engine/workspace-event-emitter/workspace-event.type'; +import { WorkspaceEventBatch } from 'src/engine/workspace-event-emitter/types/workspace-event.type'; import { FavoriteFolderWorkspaceEntity } from 'src/modules/favorite-folder/standard-objects/favorite-folder.workspace-entity'; import { FavoriteWorkspaceEntity } from 'src/modules/favorite/standard-objects/favorite.workspace-entity'; +import { OnDatabaseBatchEvent } from 'src/engine/api/graphql/graphql-query-runner/decorators/on-database-batch-event.decorator'; +import { DatabaseEventAction } from 'src/engine/api/graphql/graphql-query-runner/enums/database-event-action'; @Injectable() export class FavoriteFolderDeletionListener { @@ -16,7 +17,7 @@ export class FavoriteFolderDeletionListener { private readonly featureFlagService: FeatureFlagService, ) {} - @OnEvent('favoriteFolder.deleted') + @OnDatabaseBatchEvent('favoriteFolder', DatabaseEventAction.DELETED) async handleDelete( payload: WorkspaceEventBatch< ObjectRecordDeleteEvent diff --git a/packages/twenty-server/src/modules/match-participant/match-participant.service.ts b/packages/twenty-server/src/modules/match-participant/match-participant.service.ts index e0dc0dd6e..eeed43ce0 100644 --- a/packages/twenty-server/src/modules/match-participant/match-participant.service.ts +++ b/packages/twenty-server/src/modules/match-participant/match-participant.service.ts @@ -119,8 +119,8 @@ export class MatchParticipantService< transactionManager, ); - this.workspaceEventEmitter.emit( - `${objectMetadataName}.matched`, + this.workspaceEventEmitter.emitCustomBatchEvent( + `${objectMetadataName}_matched`, [ { workspaceMemberId: null, @@ -174,12 +174,12 @@ export class MatchParticipantService< }, }); - this.workspaceEventEmitter.emit( - `${objectMetadataName}.matched`, + this.workspaceEventEmitter.emitCustomBatchEvent( + `${objectMetadataName}_matched`, [ { workspaceId, - name: `${objectMetadataName}.matched`, + name: `${objectMetadataName}_matched`, workspaceMemberId: null, participants: updatedParticipants, }, diff --git a/packages/twenty-server/src/modules/messaging/blocklist-manager/jobs/messaging-blocklist-item-delete-messages.job.ts b/packages/twenty-server/src/modules/messaging/blocklist-manager/jobs/messaging-blocklist-item-delete-messages.job.ts index 8fedb4c73..fedeb9a2f 100644 --- a/packages/twenty-server/src/modules/messaging/blocklist-manager/jobs/messaging-blocklist-item-delete-messages.job.ts +++ b/packages/twenty-server/src/modules/messaging/blocklist-manager/jobs/messaging-blocklist-item-delete-messages.job.ts @@ -7,7 +7,7 @@ import { Process } from 'src/engine/core-modules/message-queue/decorators/proces import { Processor } from 'src/engine/core-modules/message-queue/decorators/processor.decorator'; import { MessageQueue } from 'src/engine/core-modules/message-queue/message-queue.constants'; import { TwentyORMManager } from 'src/engine/twenty-orm/twenty-orm.manager'; -import { WorkspaceEventBatch } from 'src/engine/workspace-event-emitter/workspace-event.type'; +import { WorkspaceEventBatch } from 'src/engine/workspace-event-emitter/types/workspace-event.type'; import { BlocklistWorkspaceEntity } from 'src/modules/blocklist/standard-objects/blocklist.workspace-entity'; import { MessageChannelMessageAssociationWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-channel-message-association.workspace-entity'; import { MessageChannelWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-channel.workspace-entity'; diff --git a/packages/twenty-server/src/modules/messaging/blocklist-manager/jobs/messaging-blocklist-reimport-messages.job.ts b/packages/twenty-server/src/modules/messaging/blocklist-manager/jobs/messaging-blocklist-reimport-messages.job.ts index 0b84b473c..c21ee8a2c 100644 --- a/packages/twenty-server/src/modules/messaging/blocklist-manager/jobs/messaging-blocklist-reimport-messages.job.ts +++ b/packages/twenty-server/src/modules/messaging/blocklist-manager/jobs/messaging-blocklist-reimport-messages.job.ts @@ -7,7 +7,7 @@ import { Process } from 'src/engine/core-modules/message-queue/decorators/proces import { Processor } from 'src/engine/core-modules/message-queue/decorators/processor.decorator'; import { MessageQueue } from 'src/engine/core-modules/message-queue/message-queue.constants'; import { TwentyORMManager } from 'src/engine/twenty-orm/twenty-orm.manager'; -import { WorkspaceEventBatch } from 'src/engine/workspace-event-emitter/workspace-event.type'; +import { WorkspaceEventBatch } from 'src/engine/workspace-event-emitter/types/workspace-event.type'; import { BlocklistWorkspaceEntity } from 'src/modules/blocklist/standard-objects/blocklist.workspace-entity'; import { MessageChannelSyncStatusService } from 'src/modules/messaging/common/services/message-channel-sync-status.service'; import { diff --git a/packages/twenty-server/src/modules/messaging/blocklist-manager/listeners/messaging-blocklist.listener.ts b/packages/twenty-server/src/modules/messaging/blocklist-manager/listeners/messaging-blocklist.listener.ts index c038f62fb..28f901979 100644 --- a/packages/twenty-server/src/modules/messaging/blocklist-manager/listeners/messaging-blocklist.listener.ts +++ b/packages/twenty-server/src/modules/messaging/blocklist-manager/listeners/messaging-blocklist.listener.ts @@ -6,7 +6,7 @@ import { ObjectRecordUpdateEvent } from 'src/engine/core-modules/event-emitter/t import { InjectMessageQueue } from 'src/engine/core-modules/message-queue/decorators/message-queue.decorator'; import { MessageQueue } from 'src/engine/core-modules/message-queue/message-queue.constants'; import { MessageQueueService } from 'src/engine/core-modules/message-queue/services/message-queue.service'; -import { WorkspaceEventBatch } from 'src/engine/workspace-event-emitter/workspace-event.type'; +import { WorkspaceEventBatch } from 'src/engine/workspace-event-emitter/types/workspace-event.type'; import { BlocklistWorkspaceEntity } from 'src/modules/blocklist/standard-objects/blocklist.workspace-entity'; import { BlocklistItemDeleteMessagesJob, @@ -16,7 +16,7 @@ import { BlocklistReimportMessagesJob, BlocklistReimportMessagesJobData, } from 'src/modules/messaging/blocklist-manager/jobs/messaging-blocklist-reimport-messages.job'; -import { OnDatabaseEvent } from 'src/engine/api/graphql/graphql-query-runner/decorators/on-database-event.decorator'; +import { OnDatabaseBatchEvent } from 'src/engine/api/graphql/graphql-query-runner/decorators/on-database-batch-event.decorator'; import { DatabaseEventAction } from 'src/engine/api/graphql/graphql-query-runner/enums/database-event-action'; @Injectable({ scope: Scope.REQUEST }) @@ -26,7 +26,7 @@ export class MessagingBlocklistListener { private readonly messageQueueService: MessageQueueService, ) {} - @OnDatabaseEvent('blocklist', DatabaseEventAction.CREATED) + @OnDatabaseBatchEvent('blocklist', DatabaseEventAction.CREATED) async handleCreatedEvent( payload: WorkspaceEventBatch< ObjectRecordCreateEvent @@ -38,7 +38,7 @@ export class MessagingBlocklistListener { ); } - @OnDatabaseEvent('blocklist', DatabaseEventAction.CREATED) + @OnDatabaseBatchEvent('blocklist', DatabaseEventAction.CREATED) async handleDeletedEvent( payload: WorkspaceEventBatch< ObjectRecordDeleteEvent @@ -50,7 +50,7 @@ export class MessagingBlocklistListener { ); } - @OnDatabaseEvent('blocklist', DatabaseEventAction.UPDATED) + @OnDatabaseBatchEvent('blocklist', DatabaseEventAction.UPDATED) async handleUpdatedEvent( payload: WorkspaceEventBatch< ObjectRecordUpdateEvent diff --git a/packages/twenty-server/src/modules/messaging/message-cleaner/listeners/messaging-message-cleaner-connected-account.listener.ts b/packages/twenty-server/src/modules/messaging/message-cleaner/listeners/messaging-message-cleaner-connected-account.listener.ts index 5127f2f66..ff99a95ed 100644 --- a/packages/twenty-server/src/modules/messaging/message-cleaner/listeners/messaging-message-cleaner-connected-account.listener.ts +++ b/packages/twenty-server/src/modules/messaging/message-cleaner/listeners/messaging-message-cleaner-connected-account.listener.ts @@ -4,13 +4,13 @@ import { ObjectRecordDeleteEvent } from 'src/engine/core-modules/event-emitter/t import { InjectMessageQueue } from 'src/engine/core-modules/message-queue/decorators/message-queue.decorator'; import { MessageQueue } from 'src/engine/core-modules/message-queue/message-queue.constants'; import { MessageQueueService } from 'src/engine/core-modules/message-queue/services/message-queue.service'; -import { WorkspaceEventBatch } from 'src/engine/workspace-event-emitter/workspace-event.type'; +import { WorkspaceEventBatch } from 'src/engine/workspace-event-emitter/types/workspace-event.type'; import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity'; import { MessagingConnectedAccountDeletionCleanupJob, MessagingConnectedAccountDeletionCleanupJobData, } from 'src/modules/messaging/message-cleaner/jobs/messaging-connected-account-deletion-cleanup.job'; -import { OnDatabaseEvent } from 'src/engine/api/graphql/graphql-query-runner/decorators/on-database-event.decorator'; +import { OnDatabaseBatchEvent } from 'src/engine/api/graphql/graphql-query-runner/decorators/on-database-batch-event.decorator'; import { DatabaseEventAction } from 'src/engine/api/graphql/graphql-query-runner/enums/database-event-action'; @Injectable() @@ -20,7 +20,7 @@ export class MessagingMessageCleanerConnectedAccountListener { private readonly messageQueueService: MessageQueueService, ) {} - @OnDatabaseEvent('connectedAccount', DatabaseEventAction.DESTROYED) + @OnDatabaseBatchEvent('connectedAccount', DatabaseEventAction.DESTROYED) async handleDestroyedEvent( payload: WorkspaceEventBatch< ObjectRecordDeleteEvent diff --git a/packages/twenty-server/src/modules/messaging/message-import-manager/listeners/messaging-import-manager-message-channel.listener.ts b/packages/twenty-server/src/modules/messaging/message-import-manager/listeners/messaging-import-manager-message-channel.listener.ts index 859ff9dd2..fd313caf3 100644 --- a/packages/twenty-server/src/modules/messaging/message-import-manager/listeners/messaging-import-manager-message-channel.listener.ts +++ b/packages/twenty-server/src/modules/messaging/message-import-manager/listeners/messaging-import-manager-message-channel.listener.ts @@ -4,13 +4,13 @@ import { ObjectRecordDeleteEvent } from 'src/engine/core-modules/event-emitter/t import { InjectMessageQueue } from 'src/engine/core-modules/message-queue/decorators/message-queue.decorator'; import { MessageQueue } from 'src/engine/core-modules/message-queue/message-queue.constants'; import { MessageQueueService } from 'src/engine/core-modules/message-queue/services/message-queue.service'; -import { WorkspaceEventBatch } from 'src/engine/workspace-event-emitter/workspace-event.type'; +import { WorkspaceEventBatch } from 'src/engine/workspace-event-emitter/types/workspace-event.type'; import { MessageChannelWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-channel.workspace-entity'; import { MessagingCleanCacheJob, MessagingCleanCacheJobData, } from 'src/modules/messaging/message-import-manager/jobs/messaging-clean-cache'; -import { OnDatabaseEvent } from 'src/engine/api/graphql/graphql-query-runner/decorators/on-database-event.decorator'; +import { OnDatabaseBatchEvent } from 'src/engine/api/graphql/graphql-query-runner/decorators/on-database-batch-event.decorator'; import { DatabaseEventAction } from 'src/engine/api/graphql/graphql-query-runner/enums/database-event-action'; @Injectable() @@ -20,7 +20,7 @@ export class MessagingMessageImportManagerMessageChannelListener { private readonly messageQueueService: MessageQueueService, ) {} - @OnDatabaseEvent('messageChannel', DatabaseEventAction.DESTROYED) + @OnDatabaseBatchEvent('messageChannel', DatabaseEventAction.DESTROYED) async handleDestroyedEvent( payload: WorkspaceEventBatch< ObjectRecordDeleteEvent diff --git a/packages/twenty-server/src/modules/messaging/message-participant-manager/listeners/message-participant-person.listener.ts b/packages/twenty-server/src/modules/messaging/message-participant-manager/listeners/message-participant-person.listener.ts index 434d174d2..e12f96c77 100644 --- a/packages/twenty-server/src/modules/messaging/message-participant-manager/listeners/message-participant-person.listener.ts +++ b/packages/twenty-server/src/modules/messaging/message-participant-manager/listeners/message-participant-person.listener.ts @@ -6,7 +6,7 @@ import { objectRecordChangedProperties as objectRecordUpdateEventChangedProperti import { InjectMessageQueue } from 'src/engine/core-modules/message-queue/decorators/message-queue.decorator'; import { MessageQueue } from 'src/engine/core-modules/message-queue/message-queue.constants'; import { MessageQueueService } from 'src/engine/core-modules/message-queue/services/message-queue.service'; -import { WorkspaceEventBatch } from 'src/engine/workspace-event-emitter/workspace-event.type'; +import { WorkspaceEventBatch } from 'src/engine/workspace-event-emitter/types/workspace-event.type'; import { MessageParticipantMatchParticipantJob, MessageParticipantMatchParticipantJobData, @@ -16,7 +16,7 @@ import { MessageParticipantUnmatchParticipantJobData, } from 'src/modules/messaging/message-participant-manager/jobs/message-participant-unmatch-participant.job'; import { PersonWorkspaceEntity } from 'src/modules/person/standard-objects/person.workspace-entity'; -import { OnDatabaseEvent } from 'src/engine/api/graphql/graphql-query-runner/decorators/on-database-event.decorator'; +import { OnDatabaseBatchEvent } from 'src/engine/api/graphql/graphql-query-runner/decorators/on-database-batch-event.decorator'; import { DatabaseEventAction } from 'src/engine/api/graphql/graphql-query-runner/enums/database-event-action'; @Injectable() @@ -26,7 +26,7 @@ export class MessageParticipantPersonListener { private readonly messageQueueService: MessageQueueService, ) {} - @OnDatabaseEvent('person', DatabaseEventAction.CREATED) + @OnDatabaseBatchEvent('person', DatabaseEventAction.CREATED) async handleCreatedEvent( payload: WorkspaceEventBatch< ObjectRecordCreateEvent @@ -48,7 +48,7 @@ export class MessageParticipantPersonListener { } } - @OnDatabaseEvent('person', DatabaseEventAction.UPDATED) + @OnDatabaseBatchEvent('person', DatabaseEventAction.UPDATED) async handleUpdatedEvent( payload: WorkspaceEventBatch< ObjectRecordUpdateEvent diff --git a/packages/twenty-server/src/modules/messaging/message-participant-manager/listeners/message-participant-workspace-member.listener.ts b/packages/twenty-server/src/modules/messaging/message-participant-manager/listeners/message-participant-workspace-member.listener.ts index 0b7f44886..e3655c9b2 100644 --- a/packages/twenty-server/src/modules/messaging/message-participant-manager/listeners/message-participant-workspace-member.listener.ts +++ b/packages/twenty-server/src/modules/messaging/message-participant-manager/listeners/message-participant-workspace-member.listener.ts @@ -13,7 +13,7 @@ import { objectRecordChangedProperties as objectRecordUpdateEventChangedProperti import { InjectMessageQueue } from 'src/engine/core-modules/message-queue/decorators/message-queue.decorator'; import { MessageQueue } from 'src/engine/core-modules/message-queue/message-queue.constants'; import { MessageQueueService } from 'src/engine/core-modules/message-queue/services/message-queue.service'; -import { WorkspaceEventBatch } from 'src/engine/workspace-event-emitter/workspace-event.type'; +import { WorkspaceEventBatch } from 'src/engine/workspace-event-emitter/types/workspace-event.type'; import { MessageParticipantMatchParticipantJob, MessageParticipantMatchParticipantJobData, @@ -23,7 +23,7 @@ import { MessageParticipantUnmatchParticipantJobData, } from 'src/modules/messaging/message-participant-manager/jobs/message-participant-unmatch-participant.job'; import { WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/standard-objects/workspace-member.workspace-entity'; -import { OnDatabaseEvent } from 'src/engine/api/graphql/graphql-query-runner/decorators/on-database-event.decorator'; +import { OnDatabaseBatchEvent } from 'src/engine/api/graphql/graphql-query-runner/decorators/on-database-batch-event.decorator'; import { DatabaseEventAction } from 'src/engine/api/graphql/graphql-query-runner/enums/database-event-action'; @Injectable() @@ -35,7 +35,7 @@ export class MessageParticipantWorkspaceMemberListener { private readonly workspaceRepository: Repository, ) {} - @OnDatabaseEvent('workspaceMember', DatabaseEventAction.CREATED) + @OnDatabaseBatchEvent('workspaceMember', DatabaseEventAction.CREATED) async handleCreatedEvent( payload: WorkspaceEventBatch< ObjectRecordCreateEvent @@ -68,7 +68,7 @@ export class MessageParticipantWorkspaceMemberListener { } } - @OnDatabaseEvent('workspaceMember', DatabaseEventAction.UPDATED) + @OnDatabaseBatchEvent('workspaceMember', DatabaseEventAction.UPDATED) async handleUpdatedEvent( payload: WorkspaceEventBatch< ObjectRecordUpdateEvent diff --git a/packages/twenty-server/src/modules/messaging/message-participant-manager/listeners/message-participant.listener.ts b/packages/twenty-server/src/modules/messaging/message-participant-manager/listeners/message-participant.listener.ts index d57ebdc4d..f55fc4d99 100644 --- a/packages/twenty-server/src/modules/messaging/message-participant-manager/listeners/message-participant.listener.ts +++ b/packages/twenty-server/src/modules/messaging/message-participant-manager/listeners/message-participant.listener.ts @@ -1,5 +1,4 @@ import { Injectable } from '@nestjs/common'; -import { OnEvent } from '@nestjs/event-emitter'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; @@ -7,10 +6,11 @@ import { Repository } from 'typeorm'; import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator'; import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service'; -import { WorkspaceEventBatch } from 'src/engine/workspace-event-emitter/workspace-event.type'; +import { WorkspaceEventBatch } from 'src/engine/workspace-event-emitter/types/workspace-event.type'; import { MessageParticipantWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-participant.workspace-entity'; import { TimelineActivityRepository } from 'src/modules/timeline/repositiories/timeline-activity.repository'; import { TimelineActivityWorkspaceEntity } from 'src/modules/timeline/standard-objects/timeline-activity.workspace-entity'; +import { OnCustomBatchEvent } from 'src/engine/api/graphql/graphql-query-runner/decorators/on-custom-batch-event.decorator'; @Injectable() export class MessageParticipantListener { @@ -22,28 +22,28 @@ export class MessageParticipantListener { private readonly objectMetadataRepository: Repository, ) {} - @OnEvent('messageParticipant.matched') + @OnCustomBatchEvent('messageParticipant_matched') public async handleMessageParticipantMatched( - payload: WorkspaceEventBatch<{ + batchEvent: WorkspaceEventBatch<{ workspaceMemberId: string; participants: MessageParticipantWorkspaceEntity[]; }>, ): Promise { // TODO: Refactor to insertTimelineActivitiesForObject once - for (const eventPayload of payload.events) { + for (const eventPayload of batchEvent.events) { const messageParticipants = eventPayload.participants ?? []; // TODO: move to a job? const dataSourceSchema = this.workspaceDataSourceService.getSchemaName( - payload.workspaceId, + batchEvent.workspaceId, ); const messageObjectMetadata = await this.objectMetadataRepository.findOneOrFail({ where: { nameSingular: 'message', - workspaceId: payload.workspaceId, + workspaceId: batchEvent.workspaceId, }, }); @@ -64,12 +64,12 @@ export class MessageParticipantListener { objectName: 'message', recordId: participant.personId, workspaceMemberId: eventPayload.workspaceMemberId, - workspaceId: payload.workspaceId, + workspaceId: batchEvent.workspaceId, linkedObjectMetadataId: messageObjectMetadata.id, linkedRecordId: participant.messageId, linkedRecordCachedName: '', })), - payload.workspaceId, + batchEvent.workspaceId, ); } } diff --git a/packages/twenty-server/src/modules/timeline/jobs/create-audit-log-from-internal-event.ts b/packages/twenty-server/src/modules/timeline/jobs/create-audit-log-from-internal-event.ts index cbe755b91..e94f29318 100644 --- a/packages/twenty-server/src/modules/timeline/jobs/create-audit-log-from-internal-event.ts +++ b/packages/twenty-server/src/modules/timeline/jobs/create-audit-log-from-internal-event.ts @@ -3,7 +3,7 @@ import { Process } from 'src/engine/core-modules/message-queue/decorators/proces import { Processor } from 'src/engine/core-modules/message-queue/decorators/processor.decorator'; import { MessageQueue } from 'src/engine/core-modules/message-queue/message-queue.constants'; import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator'; -import { WorkspaceEventBatch } from 'src/engine/workspace-event-emitter/workspace-event.type'; +import { WorkspaceEventBatch } from 'src/engine/workspace-event-emitter/types/workspace-event.type'; import { AuditLogRepository } from 'src/modules/timeline/repositiories/audit-log.repository'; import { AuditLogWorkspaceEntity } from 'src/modules/timeline/standard-objects/audit-log.workspace-entity'; import { WorkspaceMemberRepository } from 'src/modules/workspace-member/repositories/workspace-member.repository'; diff --git a/packages/twenty-server/src/modules/timeline/jobs/upsert-timeline-activity-from-internal-event.job.ts b/packages/twenty-server/src/modules/timeline/jobs/upsert-timeline-activity-from-internal-event.job.ts index fb35fa903..b321ff02c 100644 --- a/packages/twenty-server/src/modules/timeline/jobs/upsert-timeline-activity-from-internal-event.job.ts +++ b/packages/twenty-server/src/modules/timeline/jobs/upsert-timeline-activity-from-internal-event.job.ts @@ -3,10 +3,11 @@ import { Process } from 'src/engine/core-modules/message-queue/decorators/proces import { Processor } from 'src/engine/core-modules/message-queue/decorators/processor.decorator'; import { MessageQueue } from 'src/engine/core-modules/message-queue/message-queue.constants'; import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator'; -import { WorkspaceEventBatch } from 'src/engine/workspace-event-emitter/workspace-event.type'; +import { WorkspaceEventBatch } from 'src/engine/workspace-event-emitter/types/workspace-event.type'; import { TimelineActivityService } from 'src/modules/timeline/services/timeline-activity.service'; import { WorkspaceMemberRepository } from 'src/modules/workspace-member/repositories/workspace-member.repository'; import { WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/standard-objects/workspace-member.workspace-entity'; +import { TimelineActivityWorkspaceEntity } from 'src/modules/timeline/standard-objects/timeline-activity.workspace-entity'; @Processor(MessageQueue.entityEventsToDbQueue) export class UpsertTimelineActivityFromInternalEvent { @@ -18,7 +19,9 @@ export class UpsertTimelineActivityFromInternalEvent { @Process(UpsertTimelineActivityFromInternalEvent.name) async handle( - workspaceEventBatch: WorkspaceEventBatch, + workspaceEventBatch: WorkspaceEventBatch< + ObjectRecordBaseEvent + >, ): Promise { for (const eventData of workspaceEventBatch.events) { if (eventData.userId) { diff --git a/packages/twenty-server/src/modules/timeline/repositiories/audit-log.repository.ts b/packages/twenty-server/src/modules/timeline/repositiories/audit-log.repository.ts index 001ecb751..867f6be55 100644 --- a/packages/twenty-server/src/modules/timeline/repositiories/audit-log.repository.ts +++ b/packages/twenty-server/src/modules/timeline/repositiories/audit-log.repository.ts @@ -10,7 +10,7 @@ export class AuditLogRepository { public async insert( name: string, - properties: string, + properties: object | null, workspaceMemberId: string | null, objectName: string, objectMetadataId: string, diff --git a/packages/twenty-server/src/modules/timeline/services/timeline-activity.service.ts b/packages/twenty-server/src/modules/timeline/services/timeline-activity.service.ts index ecd6005c4..001516dc4 100644 --- a/packages/twenty-server/src/modules/timeline/services/timeline-activity.service.ts +++ b/packages/twenty-server/src/modules/timeline/services/timeline-activity.service.ts @@ -6,13 +6,14 @@ import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/work import { TimelineActivityRepository } from 'src/modules/timeline/repositiories/timeline-activity.repository'; import { TimelineActivityWorkspaceEntity } from 'src/modules/timeline/standard-objects/timeline-activity.workspace-entity'; -type TimelineActivity = ObjectRecordBaseEvent & { - name: string; - objectName?: string; - linkedRecordCachedName?: string; - linkedRecordId?: string; - linkedObjectMetadataId?: string; -}; +type TimelineActivity = + ObjectRecordBaseEvent & { + name: string; + objectName?: string; + linkedRecordCachedName?: string; + linkedRecordId?: string; + linkedObjectMetadataId?: string; + }; @Injectable() export class TimelineActivityService { @@ -32,7 +33,7 @@ export class TimelineActivityService { eventName, workspaceId, }: { - event: ObjectRecordBaseEvent; + event: ObjectRecordBaseEvent; eventName: string; workspaceId: string; }) { @@ -64,7 +65,7 @@ export class TimelineActivityService { workspaceId, eventName, }: { - event: ObjectRecordBaseEvent; + event: ObjectRecordBaseEvent; workspaceId: string; eventName: string; }): Promise { @@ -100,7 +101,7 @@ export class TimelineActivityService { workspaceId, eventName, }: { - event: ObjectRecordBaseEvent; + event: ObjectRecordBaseEvent; workspaceId: string; eventName: string; }): Promise { @@ -145,7 +146,7 @@ export class TimelineActivityService { eventName, workspaceId, }: { - event: ObjectRecordBaseEvent; + event: ObjectRecordBaseEvent; dataSourceSchema: string; activityType: string; eventName: string; @@ -206,7 +207,7 @@ export class TimelineActivityService { eventName, workspaceId, }: { - event: ObjectRecordBaseEvent; + event: ObjectRecordBaseEvent; dataSourceSchema: string; activityType: string; eventName: string; diff --git a/packages/twenty-server/src/modules/webhook/jobs/call-webhook-jobs.job.ts b/packages/twenty-server/src/modules/webhook/jobs/call-webhook-jobs.job.ts index 8efcec254..a20855be5 100644 --- a/packages/twenty-server/src/modules/webhook/jobs/call-webhook-jobs.job.ts +++ b/packages/twenty-server/src/modules/webhook/jobs/call-webhook-jobs.job.ts @@ -10,7 +10,7 @@ import { MessageQueueService } from 'src/engine/core-modules/message-queue/servi import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager'; import { WebhookWorkspaceEntity } from 'src/modules/webhook/standard-objects/webhook.workspace-entity'; import { ObjectRecordBaseEvent } from 'src/engine/core-modules/event-emitter/types/object-record.base.event'; -import { WorkspaceEventBatch } from 'src/engine/workspace-event-emitter/workspace-event.type'; +import { WorkspaceEventBatch } from 'src/engine/workspace-event-emitter/types/workspace-event.type'; import { CallWebhookJob, CallWebhookJobData, diff --git a/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-create-many.post-query.hook.ts b/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-create-many.post-query.hook.ts index dbc7c63be..461d9088c 100644 --- a/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-create-many.post-query.hook.ts +++ b/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-create-many.post-query.hook.ts @@ -7,7 +7,6 @@ import { WorkspaceQueryPostHookInstance } from 'src/engine/api/graphql/workspace import { WorkspaceQueryHook } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/decorators/workspace-query-hook.decorator'; import { WorkspaceQueryHookType } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/types/workspace-query-hook.type'; import { AuthContext } from 'src/engine/core-modules/auth/types/auth-context.type'; -import { ObjectRecordCreateEvent } from 'src/engine/core-modules/event-emitter/types/object-record-create.event'; import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; import { TwentyORMManager } from 'src/engine/twenty-orm/twenty-orm.manager'; import { WorkspaceEventEmitter } from 'src/engine/workspace-event-emitter/workspace-event-emitter'; @@ -62,9 +61,10 @@ export class WorkflowCreateManyPostQueryHook }, }); - this.workspaceEventEmitter.emit( - `workflowVersion.${DatabaseEventAction.CREATED}`, - workflowVersionsToCreate.map((workflowVersionToCreate) => { + this.workspaceEventEmitter.emitDatabaseBatchEvent({ + objectMetadataNameSingular: 'workflowVersion', + action: DatabaseEventAction.CREATED, + events: workflowVersionsToCreate.map((workflowVersionToCreate) => { return { userId: authContext.user?.id, recordId: workflowVersionToCreate.id, @@ -72,9 +72,9 @@ export class WorkflowCreateManyPostQueryHook properties: { after: workflowVersionToCreate, }, - } satisfies ObjectRecordCreateEvent; + }; }), - authContext.workspace.id, - ); + workspaceId: authContext.workspace.id, + }); } } diff --git a/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-create-one.post-query.hook.ts b/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-create-one.post-query.hook.ts index 36df3f290..052148d04 100644 --- a/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-create-one.post-query.hook.ts +++ b/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-create-one.post-query.hook.ts @@ -7,7 +7,6 @@ import { WorkspaceQueryPostHookInstance } from 'src/engine/api/graphql/workspace import { WorkspaceQueryHook } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/decorators/workspace-query-hook.decorator'; import { WorkspaceQueryHookType } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/types/workspace-query-hook.type'; import { AuthContext } from 'src/engine/core-modules/auth/types/auth-context.type'; -import { ObjectRecordCreateEvent } from 'src/engine/core-modules/event-emitter/types/object-record-create.event'; import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; import { TwentyORMManager } from 'src/engine/twenty-orm/twenty-orm.manager'; import { WorkspaceEventEmitter } from 'src/engine/workspace-event-emitter/workspace-event-emitter'; @@ -58,9 +57,10 @@ export class WorkflowCreateOnePostQueryHook }, }); - this.workspaceEventEmitter.emit( - `workflowVersion.${DatabaseEventAction.CREATED}`, - [ + this.workspaceEventEmitter.emitDatabaseBatchEvent({ + objectMetadataNameSingular: 'workflowVersion', + action: DatabaseEventAction.CREATED, + events: [ { userId: authContext.user?.id, recordId: workflowVersionToCreate.id, @@ -68,9 +68,9 @@ export class WorkflowCreateOnePostQueryHook properties: { after: workflowVersionToCreate, }, - } satisfies ObjectRecordCreateEvent, + }, ], - authContext.workspace.id, - ); + workspaceId: authContext.workspace.id, + }); } } diff --git a/packages/twenty-server/src/modules/workflow/workflow-status/constants/workflow-version-status-updated.constants.ts b/packages/twenty-server/src/modules/workflow/workflow-status/constants/workflow-version-status-updated.constants.ts new file mode 100644 index 000000000..071451cff --- /dev/null +++ b/packages/twenty-server/src/modules/workflow/workflow-status/constants/workflow-version-status-updated.constants.ts @@ -0,0 +1,2 @@ +export const WORKFLOW_VERSION_STATUS_UPDATED = + 'workflow_version_status_updated'; diff --git a/packages/twenty-server/src/modules/workflow/workflow-status/listeners/workflow-version-status.listener.ts b/packages/twenty-server/src/modules/workflow/workflow-status/listeners/workflow-version-status.listener.ts index 948e7f5f1..d1d54fef0 100644 --- a/packages/twenty-server/src/modules/workflow/workflow-status/listeners/workflow-version-status.listener.ts +++ b/packages/twenty-server/src/modules/workflow/workflow-status/listeners/workflow-version-status.listener.ts @@ -5,7 +5,7 @@ import { ObjectRecordDeleteEvent } from 'src/engine/core-modules/event-emitter/t import { InjectMessageQueue } from 'src/engine/core-modules/message-queue/decorators/message-queue.decorator'; import { MessageQueue } from 'src/engine/core-modules/message-queue/message-queue.constants'; import { MessageQueueService } from 'src/engine/core-modules/message-queue/services/message-queue.service'; -import { WorkspaceEventBatch } from 'src/engine/workspace-event-emitter/workspace-event.type'; +import { WorkspaceEventBatch } from 'src/engine/workspace-event-emitter/types/workspace-event.type'; import { WorkflowVersionStatus, WorkflowVersionWorkspaceEntity, @@ -16,8 +16,10 @@ import { WorkflowVersionEventType, WorkflowVersionStatusUpdate, } from 'src/modules/workflow/workflow-status/jobs/workflow-statuses-update.job'; -import { OnDatabaseEvent } from 'src/engine/api/graphql/graphql-query-runner/decorators/on-database-event.decorator'; +import { OnDatabaseBatchEvent } from 'src/engine/api/graphql/graphql-query-runner/decorators/on-database-batch-event.decorator'; import { DatabaseEventAction } from 'src/engine/api/graphql/graphql-query-runner/enums/database-event-action'; +import { WORKFLOW_VERSION_STATUS_UPDATED } from 'src/modules/workflow/workflow-status/constants/workflow-version-status-updated.constants'; +import { OnCustomBatchEvent } from 'src/engine/api/graphql/graphql-query-runner/decorators/on-custom-batch-event.decorator'; @Injectable() export class WorkflowVersionStatusListener { @@ -26,13 +28,13 @@ export class WorkflowVersionStatusListener { private readonly messageQueueService: MessageQueueService, ) {} - @OnDatabaseEvent('workflowVersion', DatabaseEventAction.CREATED) + @OnDatabaseBatchEvent('workflowVersion', DatabaseEventAction.CREATED) async handleWorkflowVersionCreated( - payload: WorkspaceEventBatch< + batchEvent: WorkspaceEventBatch< ObjectRecordCreateEvent >, ): Promise { - const workflowIds = payload.events + const workflowIds = batchEvent.events .filter( (event) => !event.properties.after.status || @@ -48,33 +50,33 @@ export class WorkflowVersionStatusListener { WorkflowStatusesUpdateJob.name, { type: WorkflowVersionEventType.CREATE, - workspaceId: payload.workspaceId, + workspaceId: batchEvent.workspaceId, workflowIds, }, ); } - @OnDatabaseEvent('workflowVersion', DatabaseEventAction.UPDATED) + @OnCustomBatchEvent(WORKFLOW_VERSION_STATUS_UPDATED) async handleWorkflowVersionUpdated( - payload: WorkspaceEventBatch, + batchEvent: WorkspaceEventBatch, ): Promise { await this.messageQueueService.add( WorkflowStatusesUpdateJob.name, { type: WorkflowVersionEventType.STATUS_UPDATE, - workspaceId: payload.workspaceId, - statusUpdates: payload.events, + workspaceId: batchEvent.workspaceId, + statusUpdates: batchEvent.events, }, ); } - @OnDatabaseEvent('workflowVersion', DatabaseEventAction.DELETED) + @OnDatabaseBatchEvent('workflowVersion', DatabaseEventAction.DELETED) async handleWorkflowVersionDeleted( - payload: WorkspaceEventBatch< + batchEvent: WorkspaceEventBatch< ObjectRecordDeleteEvent >, ): Promise { - const workflowIds = payload.events + const workflowIds = batchEvent.events .filter( (event) => event.properties.before.status === WorkflowVersionStatus.DRAFT, @@ -89,7 +91,7 @@ export class WorkflowVersionStatusListener { WorkflowStatusesUpdateJob.name, { type: WorkflowVersionEventType.DELETE, - workspaceId: payload.workspaceId, + workspaceId: batchEvent.workspaceId, workflowIds, }, ); diff --git a/packages/twenty-server/src/modules/workflow/workflow-trigger/database-event-trigger/listeners/database-event-trigger.listener.ts b/packages/twenty-server/src/modules/workflow/workflow-trigger/database-event-trigger/listeners/database-event-trigger.listener.ts index b0faa2061..ca4b54362 100644 --- a/packages/twenty-server/src/modules/workflow/workflow-trigger/database-event-trigger/listeners/database-event-trigger.listener.ts +++ b/packages/twenty-server/src/modules/workflow/workflow-trigger/database-event-trigger/listeners/database-event-trigger.listener.ts @@ -10,13 +10,13 @@ import { InjectMessageQueue } from 'src/engine/core-modules/message-queue/decora import { MessageQueue } from 'src/engine/core-modules/message-queue/message-queue.constants'; import { MessageQueueService } from 'src/engine/core-modules/message-queue/services/message-queue.service'; import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager'; -import { WorkspaceEventBatch } from 'src/engine/workspace-event-emitter/workspace-event.type'; +import { WorkspaceEventBatch } from 'src/engine/workspace-event-emitter/types/workspace-event.type'; import { WorkflowEventListenerWorkspaceEntity } from 'src/modules/workflow/common/standard-objects/workflow-event-listener.workspace-entity'; import { WorkflowEventTriggerJob, WorkflowEventTriggerJobData, } from 'src/modules/workflow/workflow-trigger/jobs/workflow-event-trigger.job'; -import { OnDatabaseEvent } from 'src/engine/api/graphql/graphql-query-runner/decorators/on-database-event.decorator'; +import { OnDatabaseBatchEvent } from 'src/engine/api/graphql/graphql-query-runner/decorators/on-database-batch-event.decorator'; import { DatabaseEventAction } from 'src/engine/api/graphql/graphql-query-runner/enums/database-event-action'; @Injectable() @@ -30,40 +30,40 @@ export class DatabaseEventTriggerListener { private readonly isFeatureFlagEnabledService: FeatureFlagService, ) {} - @OnDatabaseEvent('*', DatabaseEventAction.CREATED) + @OnDatabaseBatchEvent('*', DatabaseEventAction.CREATED) async handleObjectRecordCreateEvent( - payload: WorkspaceEventBatch>, + payload: WorkspaceEventBatch, ) { await this.handleEvent(payload); } - @OnDatabaseEvent('*', DatabaseEventAction.UPDATED) + @OnDatabaseBatchEvent('*', DatabaseEventAction.UPDATED) async handleObjectRecordUpdateEvent( - payload: WorkspaceEventBatch>, + payload: WorkspaceEventBatch, ) { await this.handleEvent(payload); } - @OnDatabaseEvent('*', DatabaseEventAction.DELETED) + @OnDatabaseBatchEvent('*', DatabaseEventAction.DELETED) async handleObjectRecordDeleteEvent( - payload: WorkspaceEventBatch>, + payload: WorkspaceEventBatch, ) { await this.handleEvent(payload); } - @OnDatabaseEvent('*', DatabaseEventAction.DESTROYED) + @OnDatabaseBatchEvent('*', DatabaseEventAction.DESTROYED) async handleObjectRecordDestroyEvent( - payload: WorkspaceEventBatch>, + payload: WorkspaceEventBatch, ) { await this.handleEvent(payload); } private async handleEvent( payload: WorkspaceEventBatch< - | ObjectRecordCreateEvent - | ObjectRecordUpdateEvent - | ObjectRecordDeleteEvent - | ObjectRecordDestroyEvent + | ObjectRecordCreateEvent + | ObjectRecordUpdateEvent + | ObjectRecordDeleteEvent + | ObjectRecordDestroyEvent >, ) { const workspaceId = payload.workspaceId; diff --git a/packages/twenty-server/src/modules/workflow/workflow-trigger/workflow-trigger.module.ts b/packages/twenty-server/src/modules/workflow/workflow-trigger/workflow-trigger.module.ts index ecd72856d..9aa43a080 100644 --- a/packages/twenty-server/src/modules/workflow/workflow-trigger/workflow-trigger.module.ts +++ b/packages/twenty-server/src/modules/workflow/workflow-trigger/workflow-trigger.module.ts @@ -1,17 +1,21 @@ import { Module } from '@nestjs/common'; +import { NestjsQueryTypeOrmModule } from '@ptc-org/nestjs-query-typeorm'; + import { ScopedWorkspaceContextFactory } from 'src/engine/twenty-orm/factories/scoped-workspace-context.factory'; import { WorkflowCommonModule } from 'src/modules/workflow/common/workflow-common.module'; import { WorkflowRunnerModule } from 'src/modules/workflow/workflow-runner/workflow-runner.module'; import { DatabaseEventTriggerModule } from 'src/modules/workflow/workflow-trigger/database-event-trigger/database-event-trigger.module'; import { WorkflowEventTriggerJob } from 'src/modules/workflow/workflow-trigger/jobs/workflow-event-trigger.job'; import { WorkflowTriggerWorkspaceService } from 'src/modules/workflow/workflow-trigger/workspace-services/workflow-trigger.workspace-service'; +import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; @Module({ imports: [ WorkflowCommonModule, WorkflowRunnerModule, DatabaseEventTriggerModule, + NestjsQueryTypeOrmModule.forFeature([ObjectMetadataEntity], 'metadata'), ], providers: [ WorkflowTriggerWorkspaceService, diff --git a/packages/twenty-server/src/modules/workflow/workflow-trigger/workspace-services/workflow-trigger.workspace-service.ts b/packages/twenty-server/src/modules/workflow/workflow-trigger/workspace-services/workflow-trigger.workspace-service.ts index eeea06b1a..7f19f639c 100644 --- a/packages/twenty-server/src/modules/workflow/workflow-trigger/workspace-services/workflow-trigger.workspace-service.ts +++ b/packages/twenty-server/src/modules/workflow/workflow-trigger/workspace-services/workflow-trigger.workspace-service.ts @@ -1,6 +1,7 @@ import { Injectable } from '@nestjs/common'; +import { InjectRepository } from '@nestjs/typeorm'; -import { EntityManager } from 'typeorm'; +import { EntityManager, Repository } from 'typeorm'; import { buildCreatedByFromWorkspaceMember } from 'src/engine/core-modules/actor/utils/build-created-by-from-workspace-member.util'; import { User } from 'src/engine/core-modules/user/user.entity'; @@ -16,7 +17,6 @@ import { WorkflowWorkspaceEntity } from 'src/modules/workflow/common/standard-ob import { assertWorkflowVersionTriggerIsDefined } from 'src/modules/workflow/common/utils/assert-workflow-version-trigger-is-defined.util'; import { WorkflowCommonWorkspaceService } from 'src/modules/workflow/common/workspace-services/workflow-common.workspace-service'; import { WorkflowRunnerWorkspaceService } from 'src/modules/workflow/workflow-runner/workspace-services/workflow-runner.workspace-service'; -import { WorkflowVersionStatusUpdate } from 'src/modules/workflow/workflow-status/jobs/workflow-statuses-update.job'; import { DatabaseEventTriggerService } from 'src/modules/workflow/workflow-trigger/database-event-trigger/database-event-trigger.service'; import { WorkflowTriggerException, @@ -26,6 +26,8 @@ import { WorkflowTriggerType } from 'src/modules/workflow/workflow-trigger/types import { assertVersionCanBeActivated } from 'src/modules/workflow/workflow-trigger/utils/assert-version-can-be-activated.util'; import { assertNever } from 'src/utils/assert'; import { DatabaseEventAction } from 'src/engine/api/graphql/graphql-query-runner/enums/database-event-action'; +import { WORKFLOW_VERSION_STATUS_UPDATED } from 'src/modules/workflow/workflow-status/constants/workflow-version-status-updated.constants'; +import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; @Injectable() export class WorkflowTriggerWorkspaceService { @@ -36,14 +38,11 @@ export class WorkflowTriggerWorkspaceService { private readonly workflowRunnerWorkspaceService: WorkflowRunnerWorkspaceService, private readonly databaseEventTriggerService: DatabaseEventTriggerService, private readonly workspaceEventEmitter: WorkspaceEventEmitter, + @InjectRepository(ObjectMetadataEntity, 'metadata') + private readonly objectMetadataRepository: Repository, ) {} - async runWorkflowVersion( - workflowVersionId: string, - payload: object, - workspaceMemberId: string, - user: User, - ) { + private getWorkspaceId() { const workspaceId = this.scopedWorkspaceContextFactory.create().workspaceId; if (!workspaceId) { @@ -53,12 +52,21 @@ export class WorkflowTriggerWorkspaceService { ); } + return workspaceId; + } + + async runWorkflowVersion( + workflowVersionId: string, + payload: object, + workspaceMemberId: string, + user: User, + ) { await this.workflowCommonWorkspaceService.getWorkflowVersionOrFail( workflowVersionId, ); return await this.workflowRunnerWorkspaceService.run( - workspaceId, + this.getWorkspaceId(), workflowVersionId, payload, buildCreatedByFromWorkspaceMember(workspaceMemberId, user), @@ -246,10 +254,10 @@ export class WorkflowTriggerWorkspaceService { manager, ); - this.emitStatusUpdateEventOrThrow( - workflowVersion.workflowId, - workflowVersion.status, + await this.emitStatusUpdateEvents( + workflowVersion, WorkflowVersionStatus.ACTIVE, + this.getWorkspaceId(), ); } @@ -271,10 +279,10 @@ export class WorkflowTriggerWorkspaceService { manager, ); - this.emitStatusUpdateEventOrThrow( - workflowVersion.workflowId, - workflowVersion.status, + await this.emitStatusUpdateEvents( + workflowVersion, WorkflowVersionStatus.DEACTIVATED, + this.getWorkspaceId(), ); } @@ -348,28 +356,45 @@ export class WorkflowTriggerWorkspaceService { } } - private emitStatusUpdateEventOrThrow( - workflowId: string, - previousStatus: WorkflowVersionStatus, + private async emitStatusUpdateEvents( + workflowVersion: WorkflowVersionWorkspaceEntity, newStatus: WorkflowVersionStatus, + workspaceId: string, ) { - const workspaceId = this.scopedWorkspaceContextFactory.create().workspaceId; + const objectMetadata = await this.objectMetadataRepository.findOneOrFail({ + where: { + nameSingular: 'workflowVersion', + }, + }); - if (!workspaceId) { - throw new WorkflowTriggerException( - 'No workspace id found', - WorkflowTriggerExceptionCode.INTERNAL_ERROR, - ); - } + this.workspaceEventEmitter.emitDatabaseBatchEvent({ + objectMetadataNameSingular: 'workflowVersion', + action: DatabaseEventAction.UPDATED, + events: [ + { + recordId: workflowVersion.id, + objectMetadata, + properties: { + before: workflowVersion, + after: { ...workflowVersion, status: newStatus }, + updatedFields: ['status'], + diff: { + status: { before: workflowVersion.status, after: newStatus }, + }, + }, + }, + ], + workspaceId, + }); - this.workspaceEventEmitter.emit( - `workflowVersion.${DatabaseEventAction.UPDATED}`, + this.workspaceEventEmitter.emitCustomBatchEvent( + WORKFLOW_VERSION_STATUS_UPDATED, [ { - workflowId, - previousStatus, + workflowId: workflowVersion.workflowId, + previousStatus: workflowVersion.status, newStatus, - } satisfies WorkflowVersionStatusUpdate, + }, ], workspaceId, );