Skip to content

Commit

Permalink
7154 deleted event is not emitted when calling destroyone (#7159)
Browse files Browse the repository at this point in the history
Closes #7154
  • Loading branch information
bosiraphael authored Sep 27, 2024
1 parent ca906bb commit c9c2f32
Show file tree
Hide file tree
Showing 12 changed files with 128 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import {
} from 'src/engine/api/graphql/workspace-query-runner/workspace-query-runner.exception';
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 { ObjectRecordDeleteEvent } from 'src/engine/core-modules/event-emitter/types/object-record-delete.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';
Expand Down Expand Up @@ -284,10 +285,94 @@ export class GraphqlQueryRunnerService {
async destroyOne<ObjectRecord extends IRecord = IRecord>(
args: DestroyOneResolverArgs,
options: WorkspaceQueryRunnerOptions,
): Promise<ObjectRecord> {
): Promise<ObjectRecord | undefined> {
const graphqlQueryDestroyOneResolverService =
new GraphqlQueryDestroyOneResolverService(this.twentyORMGlobalManager);

return graphqlQueryDestroyOneResolverService.destroyOne(args, options);
const { authContext, objectMetadataItem } = options;

assertMutationNotOnRemoteObject(objectMetadataItem);
assertIsValidUuid(args.id);

const hookedArgs =
await this.workspaceQueryHookService.executePreQueryHooks(
authContext,
objectMetadataItem.nameSingular,
'destroyOne',
args,
);

const computedArgs = (await this.queryRunnerArgsFactory.create(
hookedArgs,
options,
ResolverArgsType.DestroyOne,
)) as DestroyOneResolverArgs;

const result = (await graphqlQueryDestroyOneResolverService.destroyOne(
computedArgs,
options,
)) as ObjectRecord;

await this.workspaceQueryHookService.executePostQueryHooks(
authContext,
objectMetadataItem.nameSingular,
'destroyOne',
[result],
);

await this.triggerWebhooks<IRecord>(
[result],
CallWebhookJobsJobOperation.destroy,
options,
);

this.emitDestroyEvents<IRecord>([result], authContext, objectMetadataItem);

return result;
}

private emitDestroyEvents<BaseRecord extends IRecord = IRecord>(
records: BaseRecord[],
authContext: AuthContext,
objectMetadataItem: ObjectMetadataInterface,
) {
this.workspaceEventEmitter.emit(
`${objectMetadataItem.nameSingular}.destroyed`,
records.map((record) => {
return {
userId: authContext.user?.id,
recordId: record.id,
objectMetadata: objectMetadataItem,
properties: {
before: this.removeNestedProperties(record),
},
} satisfies ObjectRecordDeleteEvent<any>;
}),
authContext.workspace.id,
);
}

private removeNestedProperties<Record extends IRecord = IRecord>(
record: Record,
) {
if (!record) {
return;
}

const sanitizedRecord = {};

for (const [key, value] of Object.entries(record)) {
if (value && typeof value === 'object' && value['edges']) {
continue;
}

if (key === '__typename') {
continue;
}

sanitizedRecord[key] = value;
}

return sanitizedRecord;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export enum CallWebhookJobsJobOperation {
create = 'create',
update = 'update',
delete = 'delete',
destroy = 'destroy',
}

export type CallWebhookJobsJobData = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,13 @@ export class EntityEventsToDbListener {
return this.handle(payload);
}

@OnEvent('*.destroyed')
async handleDestroy(
payload: WorkspaceEventBatch<ObjectRecordUpdateEvent<any>>,
) {
return this.handle(payload);
}

private async handle(payload: WorkspaceEventBatch<ObjectRecordBaseEvent>) {
const filteredEvents = payload.events.filter(
(event) => event.objectMetadata?.isAuditLogged,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
DeleteManyResolverArgs,
DeleteOneResolverArgs,
DestroyManyResolverArgs,
DestroyOneResolverArgs,
FindDuplicatesResolverArgs,
FindManyResolverArgs,
FindOneResolverArgs,
Expand Down Expand Up @@ -39,4 +40,6 @@ export type WorkspacePreQueryHookPayload<T> = T extends 'createMany'
? RestoreManyResolverArgs
: T extends 'destroyMany'
? DestroyManyResolverArgs
: never;
: T extends 'destroyOne'
? DestroyOneResolverArgs
: never;
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export enum ResolverArgsType {
DeleteMany = 'DeleteMany',
RestoreMany = 'RestoreMany',
DestroyMany = 'DestroyMany',
DestroyOne = 'DestroyOne',
}

export interface FindManyResolverArgs<
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { ObjectRecordBaseEvent } from 'src/engine/core-modules/event-emitter/types/object-record.base.event';

export class ObjectRecordDestroyEvent<T> extends ObjectRecordBaseEvent {
properties: {
before: T;
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ export class CalendarEventCleanerConnectedAccountListener {
private readonly calendarQueueService: MessageQueueService,
) {}

@OnEvent('connectedAccount.deleted')
async handleDeletedEvent(
@OnEvent('connectedAccount.destroyed')
async handleDestroyedEvent(
payload: WorkspaceEventBatch<
ObjectRecordDeleteEvent<ConnectedAccountWorkspaceEntity>
>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ export class ConnectedAccountListener {
private readonly accountsToReconnectService: AccountsToReconnectService,
) {}

@OnEvent('connectedAccount.deleted')
async handleDeletedEvent(
@OnEvent('connectedAccount.destroyed')
async handleDestroyedEvent(
payload: WorkspaceEventBatch<
ObjectRecordDeleteEvent<ConnectedAccountWorkspaceEntity>
>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ 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';

@WorkspaceQueryHook(`connectedAccount.deleteOne`)
@WorkspaceQueryHook(`connectedAccount.destroyOne`)
export class ConnectedAccountDeleteOnePreQueryHook
implements WorkspaceQueryHookInstance
{
Expand All @@ -34,7 +34,7 @@ export class ConnectedAccountDeleteOnePreQueryHook
});

this.workspaceEventEmitter.emit(
'messageChannel.deleted',
'messageChannel.destroyed',
messageChannels.map(
(messageChannel) =>
({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ export class MessagingMessageCleanerConnectedAccountListener {
private readonly messageQueueService: MessageQueueService,
) {}

@OnEvent('connectedAccount.deleted')
async handleDeletedEvent(
@OnEvent('connectedAccount.destroyed')
async handleDestroyedEvent(
payload: WorkspaceEventBatch<
ObjectRecordDeleteEvent<ConnectedAccountWorkspaceEntity>
>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ export class MessagingMessageImportManagerMessageChannelListener {
private readonly messageQueueService: MessageQueueService,
) {}

@OnEvent('messageChannel.deleted')
async handleDeletedEvent(
@OnEvent('messageChannel.destroyed')
async handleDestroyedEvent(
payload: WorkspaceEventBatch<
ObjectRecordDeleteEvent<MessageChannelWorkspaceEntity>
>,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { Injectable, Logger } from '@nestjs/common';
import { OnEvent } from '@nestjs/event-emitter';

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 { ObjectRecordCreateEvent } from 'src/engine/core-modules/event-emitter/types/object-record-create.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 { ObjectRecordUpdateEvent } from 'src/engine/core-modules/event-emitter/types/object-record-update.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 { 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';
Expand Down Expand Up @@ -49,11 +50,19 @@ export class DatabaseEventTriggerListener {
await this.handleEvent(payload);
}

@OnEvent('*.destroyed')
async handleObjectRecordDestroyEvent(
payload: WorkspaceEventBatch<ObjectRecordDestroyEvent<any>>,
) {
await this.handleEvent(payload);
}

private async handleEvent(
payload: WorkspaceEventBatch<
| ObjectRecordCreateEvent<any>
| ObjectRecordUpdateEvent<any>
| ObjectRecordDeleteEvent<any>
| ObjectRecordDestroyEvent<any>
>,
) {
const workspaceId = payload.workspaceId;
Expand Down

0 comments on commit c9c2f32

Please sign in to comment.