From acc3aa6df56acb658214fb7493d1de29a6f06f22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Bosi?= <71827178+bosiraphael@users.noreply.github.com> Date: Thu, 9 Jan 2025 14:36:45 +0100 Subject: [PATCH] Destroy connected account when deleting workspace member (#9484) Closes #9114 --- .../connected-account.module.ts | 9 +++- ...workspace-member-connected-accounts.job.ts | 34 ++++++++++++++ ...ected-account-workspace-member.listener.ts | 44 +++++++++++++++++++ 3 files changed, 86 insertions(+), 1 deletion(-) create mode 100644 packages/twenty-server/src/modules/connected-account/jobs/delete-workspace-member-connected-accounts.job.ts create mode 100644 packages/twenty-server/src/modules/connected-account/listeners/connected-account-workspace-member.listener.ts diff --git a/packages/twenty-server/src/modules/connected-account/connected-account.module.ts b/packages/twenty-server/src/modules/connected-account/connected-account.module.ts index 319cce744..3888f9603 100644 --- a/packages/twenty-server/src/modules/connected-account/connected-account.module.ts +++ b/packages/twenty-server/src/modules/connected-account/connected-account.module.ts @@ -1,12 +1,19 @@ import { Module } from '@nestjs/common'; import { UserVarsModule } from 'src/engine/core-modules/user/user-vars/user-vars.module'; +import { DeleteWorkspaceMemberConnectedAccountsCleanupJob } from 'src/modules/connected-account/jobs/delete-workspace-member-connected-accounts.job'; +import { ConnectedAccountWorkspaceMemberListener } from 'src/modules/connected-account/listeners/connected-account-workspace-member.listener'; import { ConnectedAccountListener } from 'src/modules/connected-account/listeners/connected-account.listener'; import { AccountsToReconnectService } from 'src/modules/connected-account/services/accounts-to-reconnect.service'; @Module({ imports: [UserVarsModule], - providers: [AccountsToReconnectService, ConnectedAccountListener], + providers: [ + AccountsToReconnectService, + ConnectedAccountListener, + DeleteWorkspaceMemberConnectedAccountsCleanupJob, + ConnectedAccountWorkspaceMemberListener, + ], exports: [AccountsToReconnectService], }) export class ConnectedAccountModule {} diff --git a/packages/twenty-server/src/modules/connected-account/jobs/delete-workspace-member-connected-accounts.job.ts b/packages/twenty-server/src/modules/connected-account/jobs/delete-workspace-member-connected-accounts.job.ts new file mode 100644 index 000000000..43871804c --- /dev/null +++ b/packages/twenty-server/src/modules/connected-account/jobs/delete-workspace-member-connected-accounts.job.ts @@ -0,0 +1,34 @@ +import { Process } from 'src/engine/core-modules/message-queue/decorators/process.decorator'; +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 { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager'; +import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity'; + +export type DeleteWorkspaceMemberConnectedAccountsCleanupJobData = { + workspaceId: string; + workspaceMemberId: string; +}; + +@Processor(MessageQueue.deleteCascadeQueue) +export class DeleteWorkspaceMemberConnectedAccountsCleanupJob { + constructor( + private readonly twentyORMGlobalManager: TwentyORMGlobalManager, + ) {} + + @Process(DeleteWorkspaceMemberConnectedAccountsCleanupJob.name) + async handle( + data: DeleteWorkspaceMemberConnectedAccountsCleanupJobData, + ): Promise { + const { workspaceId, workspaceMemberId } = data; + + const connectedAccountRepository = + await this.twentyORMGlobalManager.getRepositoryForWorkspace( + workspaceId, + 'connectedAccount', + ); + + await connectedAccountRepository.delete({ + accountOwnerId: workspaceMemberId, + }); + } +} diff --git a/packages/twenty-server/src/modules/connected-account/listeners/connected-account-workspace-member.listener.ts b/packages/twenty-server/src/modules/connected-account/listeners/connected-account-workspace-member.listener.ts new file mode 100644 index 000000000..e0f540345 --- /dev/null +++ b/packages/twenty-server/src/modules/connected-account/listeners/connected-account-workspace-member.listener.ts @@ -0,0 +1,44 @@ +import { Injectable } from '@nestjs/common'; + +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 { 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 { 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/types/workspace-event.type'; +import { + DeleteWorkspaceMemberConnectedAccountsCleanupJob, + DeleteWorkspaceMemberConnectedAccountsCleanupJobData, +} from 'src/modules/connected-account/jobs/delete-workspace-member-connected-accounts.job'; +import { WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/standard-objects/workspace-member.workspace-entity'; + +@Injectable() +export class ConnectedAccountWorkspaceMemberListener { + constructor( + @InjectMessageQueue(MessageQueue.deleteCascadeQueue) + private readonly messageQueueService: MessageQueueService, + ) {} + + @OnDatabaseBatchEvent('workspaceMember', DatabaseEventAction.DESTROYED) + @OnDatabaseBatchEvent('workspaceMember', DatabaseEventAction.DELETED) + async handleWorkspaceMemberRemovalEvent( + payload: WorkspaceEventBatch< + | ObjectRecordDeleteEvent + | ObjectRecordDestroyEvent + >, + ) { + await Promise.all( + payload.events.map((eventPayload) => + this.messageQueueService.add( + DeleteWorkspaceMemberConnectedAccountsCleanupJob.name, + { + workspaceId: payload.workspaceId, + workspaceMemberId: eventPayload.recordId, + }, + ), + ), + ); + } +}