bugfix: escape destroyed objects on workers (#9719)
# This PR - Fixes #9358 @FelixMalfait please check this workaround --------- Co-authored-by: Félix Malfait <felix@twenty.com>
This commit is contained in:
@ -1,17 +1,21 @@
|
|||||||
import { Injectable } from '@nestjs/common';
|
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 { ObjectRecordCreateEvent } from 'src/engine/core-modules/event-emitter/types/object-record-create.event';
|
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 { ObjectRecordEvent } from 'src/engine/core-modules/event-emitter/types/object-record-event.event';
|
||||||
|
import { ObjectRecordNonDestructiveEvent } from 'src/engine/core-modules/event-emitter/types/object-record-non-destructive-event';
|
||||||
|
import { ObjectRecordRestoreEvent } from 'src/engine/core-modules/event-emitter/types/object-record-restore.event';
|
||||||
import { ObjectRecordUpdateEvent } from 'src/engine/core-modules/event-emitter/types/object-record-update.event';
|
import { ObjectRecordUpdateEvent } from 'src/engine/core-modules/event-emitter/types/object-record-update.event';
|
||||||
import { ObjectRecordBaseEvent } from 'src/engine/core-modules/event-emitter/types/object-record.base.event';
|
|
||||||
import { InjectMessageQueue } from 'src/engine/core-modules/message-queue/decorators/message-queue.decorator';
|
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 { 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 { 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 { 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 { 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 { UpsertTimelineActivityFromInternalEvent } from 'src/modules/timeline/jobs/upsert-timeline-activity-from-internal-event.job';
|
||||||
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 { CallWebhookJobsJob } from 'src/modules/webhook/jobs/call-webhook-jobs.job';
|
||||||
import { DatabaseEventAction } from 'src/engine/api/graphql/graphql-query-runner/enums/database-event-action';
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class EntityEventsToDbListener {
|
export class EntityEventsToDbListener {
|
||||||
@ -24,47 +28,66 @@ export class EntityEventsToDbListener {
|
|||||||
|
|
||||||
@OnDatabaseBatchEvent('*', DatabaseEventAction.CREATED)
|
@OnDatabaseBatchEvent('*', DatabaseEventAction.CREATED)
|
||||||
async handleCreate(batchEvent: WorkspaceEventBatch<ObjectRecordCreateEvent>) {
|
async handleCreate(batchEvent: WorkspaceEventBatch<ObjectRecordCreateEvent>) {
|
||||||
return this.handle(batchEvent);
|
return this.handleEvent(batchEvent, DatabaseEventAction.CREATED);
|
||||||
}
|
}
|
||||||
|
|
||||||
@OnDatabaseBatchEvent('*', DatabaseEventAction.UPDATED)
|
@OnDatabaseBatchEvent('*', DatabaseEventAction.UPDATED)
|
||||||
async handleUpdate(batchEvent: WorkspaceEventBatch<ObjectRecordUpdateEvent>) {
|
async handleUpdate(batchEvent: WorkspaceEventBatch<ObjectRecordUpdateEvent>) {
|
||||||
return this.handle(batchEvent);
|
return this.handleEvent(batchEvent, DatabaseEventAction.UPDATED);
|
||||||
}
|
}
|
||||||
|
|
||||||
@OnDatabaseBatchEvent('*', DatabaseEventAction.DELETED)
|
@OnDatabaseBatchEvent('*', DatabaseEventAction.DELETED)
|
||||||
async handleDelete(batchEvent: WorkspaceEventBatch<ObjectRecordUpdateEvent>) {
|
async handleDelete(batchEvent: WorkspaceEventBatch<ObjectRecordDeleteEvent>) {
|
||||||
return this.handle(batchEvent);
|
return this.handleEvent(batchEvent, DatabaseEventAction.DELETED);
|
||||||
|
}
|
||||||
|
|
||||||
|
@OnDatabaseBatchEvent('*', DatabaseEventAction.RESTORED)
|
||||||
|
async handleRestore(
|
||||||
|
batchEvent: WorkspaceEventBatch<ObjectRecordRestoreEvent>,
|
||||||
|
) {
|
||||||
|
return this.handleEvent(batchEvent, DatabaseEventAction.RESTORED);
|
||||||
}
|
}
|
||||||
|
|
||||||
@OnDatabaseBatchEvent('*', DatabaseEventAction.DESTROYED)
|
@OnDatabaseBatchEvent('*', DatabaseEventAction.DESTROYED)
|
||||||
async handleDestroy(
|
async handleDestroy(
|
||||||
batchEvent: WorkspaceEventBatch<ObjectRecordUpdateEvent>,
|
batchEvent: WorkspaceEventBatch<ObjectRecordDestroyEvent>,
|
||||||
) {
|
) {
|
||||||
return this.handle(batchEvent);
|
return this.handleEvent(batchEvent, DatabaseEventAction.DESTROYED);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async handle(batchEvent: WorkspaceEventBatch<ObjectRecordBaseEvent>) {
|
private async handleEvent<T extends ObjectRecordEvent>(
|
||||||
|
batchEvent: WorkspaceEventBatch<T>,
|
||||||
|
action: DatabaseEventAction,
|
||||||
|
) {
|
||||||
const filteredEvents = batchEvent.events.filter(
|
const filteredEvents = batchEvent.events.filter(
|
||||||
(event) => event.objectMetadata?.isAuditLogged,
|
(event) => event.objectMetadata?.isAuditLogged,
|
||||||
);
|
);
|
||||||
|
|
||||||
await this.entityEventsToDbQueueService.add<
|
await Promise.all([
|
||||||
WorkspaceEventBatch<ObjectRecordBaseEvent>
|
this.webhookQueueService.add<WorkspaceEventBatch<T>>(
|
||||||
>(CreateAuditLogFromInternalEvent.name, {
|
CallWebhookJobsJob.name,
|
||||||
...batchEvent,
|
batchEvent,
|
||||||
events: filteredEvents,
|
{
|
||||||
});
|
retryLimit: 3,
|
||||||
|
},
|
||||||
await this.entityEventsToDbQueueService.add<
|
),
|
||||||
WorkspaceEventBatch<ObjectRecordBaseEvent>
|
this.entityEventsToDbQueueService.add<WorkspaceEventBatch<T>>(
|
||||||
>(UpsertTimelineActivityFromInternalEvent.name, {
|
CreateAuditLogFromInternalEvent.name,
|
||||||
...batchEvent,
|
{
|
||||||
events: filteredEvents,
|
...batchEvent,
|
||||||
});
|
events: filteredEvents,
|
||||||
|
},
|
||||||
await this.webhookQueueService.add<
|
),
|
||||||
WorkspaceEventBatch<ObjectRecordBaseEvent>
|
...(action !== DatabaseEventAction.DESTROYED
|
||||||
>(CallWebhookJobsJob.name, batchEvent, { retryLimit: 3 });
|
? [
|
||||||
|
this.entityEventsToDbQueueService.add<
|
||||||
|
WorkspaceEventBatch<ObjectRecordNonDestructiveEvent>
|
||||||
|
>(UpsertTimelineActivityFromInternalEvent.name, {
|
||||||
|
...batchEvent,
|
||||||
|
events: filteredEvents,
|
||||||
|
}),
|
||||||
|
]
|
||||||
|
: []),
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,6 +17,7 @@ import { MicrosoftAPIsService } from 'src/engine/core-modules/auth/services/micr
|
|||||||
// import { OAuthService } from 'src/engine/core-modules/auth/services/oauth.service';
|
// import { OAuthService } from 'src/engine/core-modules/auth/services/oauth.service';
|
||||||
import { ResetPasswordService } from 'src/engine/core-modules/auth/services/reset-password.service';
|
import { ResetPasswordService } from 'src/engine/core-modules/auth/services/reset-password.service';
|
||||||
import { SignInUpService } from 'src/engine/core-modules/auth/services/sign-in-up.service';
|
import { SignInUpService } from 'src/engine/core-modules/auth/services/sign-in-up.service';
|
||||||
|
import { SocialSsoService } from 'src/engine/core-modules/auth/services/social-sso.service';
|
||||||
import { SamlAuthStrategy } from 'src/engine/core-modules/auth/strategies/saml.auth.strategy';
|
import { SamlAuthStrategy } from 'src/engine/core-modules/auth/strategies/saml.auth.strategy';
|
||||||
import { AccessTokenService } from 'src/engine/core-modules/auth/token/services/access-token.service';
|
import { AccessTokenService } from 'src/engine/core-modules/auth/token/services/access-token.service';
|
||||||
import { LoginTokenService } from 'src/engine/core-modules/auth/token/services/login-token.service';
|
import { LoginTokenService } from 'src/engine/core-modules/auth/token/services/login-token.service';
|
||||||
@ -43,7 +44,6 @@ import { DataSourceModule } from 'src/engine/metadata-modules/data-source/data-s
|
|||||||
import { WorkspaceDataSourceModule } from 'src/engine/workspace-datasource/workspace-datasource.module';
|
import { WorkspaceDataSourceModule } from 'src/engine/workspace-datasource/workspace-datasource.module';
|
||||||
import { WorkspaceManagerModule } from 'src/engine/workspace-manager/workspace-manager.module';
|
import { WorkspaceManagerModule } from 'src/engine/workspace-manager/workspace-manager.module';
|
||||||
import { ConnectedAccountModule } from 'src/modules/connected-account/connected-account.module';
|
import { ConnectedAccountModule } from 'src/modules/connected-account/connected-account.module';
|
||||||
import { SocialSsoService } from 'src/engine/core-modules/auth/services/social-sso.service';
|
|
||||||
|
|
||||||
import { AuthResolver } from './auth.resolver';
|
import { AuthResolver } from './auth.resolver';
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,12 @@
|
|||||||
|
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 { ObjectRecordRestoreEvent } from 'src/engine/core-modules/event-emitter/types/object-record-restore.event';
|
||||||
|
import { ObjectRecordUpdateEvent } from 'src/engine/core-modules/event-emitter/types/object-record-update.event';
|
||||||
|
|
||||||
|
export type ObjectRecordEvent<T = object> =
|
||||||
|
| ObjectRecordUpdateEvent<T>
|
||||||
|
| ObjectRecordDeleteEvent<T>
|
||||||
|
| ObjectRecordCreateEvent<T>
|
||||||
|
| ObjectRecordDestroyEvent<T>
|
||||||
|
| ObjectRecordRestoreEvent<T>;
|
||||||
@ -0,0 +1,10 @@
|
|||||||
|
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 { ObjectRecordRestoreEvent } from 'src/engine/core-modules/event-emitter/types/object-record-restore.event';
|
||||||
|
import { ObjectRecordUpdateEvent } from 'src/engine/core-modules/event-emitter/types/object-record-update.event';
|
||||||
|
|
||||||
|
export type ObjectRecordNonDestructiveEvent =
|
||||||
|
| ObjectRecordCreateEvent
|
||||||
|
| ObjectRecordUpdateEvent
|
||||||
|
| ObjectRecordDeleteEvent
|
||||||
|
| ObjectRecordRestoreEvent;
|
||||||
@ -1,9 +1,9 @@
|
|||||||
import { ObjectRecordBaseEvent } from 'src/engine/core-modules/event-emitter/types/object-record.base.event';
|
import { ObjectRecordCreateEvent } from 'src/engine/core-modules/event-emitter/types/object-record-create.event';
|
||||||
|
|
||||||
export class ObjectRecordRestoreEvent<
|
export class ObjectRecordRestoreEvent<
|
||||||
T = object,
|
T = object,
|
||||||
> extends ObjectRecordBaseEvent<T> {
|
> extends ObjectRecordCreateEvent<T> {
|
||||||
properties: {
|
properties: {
|
||||||
before: T;
|
after: T;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,13 +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';
|
import { ObjectRecordDiff } from 'src/engine/core-modules/event-emitter/types/object-record-diff';
|
||||||
|
import { ObjectRecordBaseEvent } from 'src/engine/core-modules/event-emitter/types/object-record.base.event';
|
||||||
|
|
||||||
export class ObjectRecordUpdateEvent<
|
export class ObjectRecordUpdateEvent<
|
||||||
T = object,
|
T = object,
|
||||||
> extends ObjectRecordBaseEvent<T> {
|
> extends ObjectRecordBaseEvent<T> {
|
||||||
properties: {
|
properties: {
|
||||||
updatedFields?: string[];
|
updatedFields?: string[];
|
||||||
|
diff?: Partial<ObjectRecordDiff<T>>;
|
||||||
before: T;
|
before: T;
|
||||||
after: T;
|
after: T;
|
||||||
diff?: Partial<ObjectRecordDiff<T>>;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
import { Injectable } from '@nestjs/common';
|
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 { ObjectRecordCreateEvent } from 'src/engine/core-modules/event-emitter/types/object-record-create.event';
|
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 { ObjectRecordUpdateEvent } from 'src/engine/core-modules/event-emitter/types/object-record-update.event';
|
||||||
import { objectRecordChangedProperties as objectRecordUpdateEventChangedProperties } from 'src/engine/core-modules/event-emitter/utils/object-record-changed-properties.util';
|
import { objectRecordChangedProperties as objectRecordUpdateEventChangedProperties } from 'src/engine/core-modules/event-emitter/utils/object-record-changed-properties.util';
|
||||||
@ -16,8 +18,6 @@ import {
|
|||||||
MessageParticipantUnmatchParticipantJobData,
|
MessageParticipantUnmatchParticipantJobData,
|
||||||
} from 'src/modules/messaging/message-participant-manager/jobs/message-participant-unmatch-participant.job';
|
} 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 { PersonWorkspaceEntity } from 'src/modules/person/standard-objects/person.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()
|
@Injectable()
|
||||||
export class MessageParticipantPersonListener {
|
export class MessageParticipantPersonListener {
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { ObjectRecordBaseEvent } from 'src/engine/core-modules/event-emitter/types/object-record.base.event';
|
import { ObjectRecordEvent } from 'src/engine/core-modules/event-emitter/types/object-record-event.event';
|
||||||
import { Process } from 'src/engine/core-modules/message-queue/decorators/process.decorator';
|
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 { Processor } from 'src/engine/core-modules/message-queue/decorators/processor.decorator';
|
||||||
import { MessageQueue } from 'src/engine/core-modules/message-queue/message-queue.constants';
|
import { MessageQueue } from 'src/engine/core-modules/message-queue/message-queue.constants';
|
||||||
@ -20,7 +20,7 @@ export class CreateAuditLogFromInternalEvent {
|
|||||||
|
|
||||||
@Process(CreateAuditLogFromInternalEvent.name)
|
@Process(CreateAuditLogFromInternalEvent.name)
|
||||||
async handle(
|
async handle(
|
||||||
workspaceEventBatch: WorkspaceEventBatch<ObjectRecordBaseEvent>,
|
workspaceEventBatch: WorkspaceEventBatch<ObjectRecordEvent>,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
for (const eventData of workspaceEventBatch.events) {
|
for (const eventData of workspaceEventBatch.events) {
|
||||||
let workspaceMemberId: string | null = null;
|
let workspaceMemberId: string | null = null;
|
||||||
@ -34,16 +34,14 @@ export class CreateAuditLogFromInternalEvent {
|
|||||||
workspaceMemberId = workspaceMember.id;
|
workspaceMemberId = workspaceMember.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (eventData.properties.diff) {
|
|
||||||
// we remove "before" and "after" property for a cleaner/slimmer event payload
|
|
||||||
eventData.properties = {
|
|
||||||
diff: eventData.properties.diff,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
await this.auditLogRepository.insert(
|
await this.auditLogRepository.insert(
|
||||||
workspaceEventBatch.name,
|
workspaceEventBatch.name,
|
||||||
eventData.properties,
|
'diff' in eventData.properties
|
||||||
|
? {
|
||||||
|
// we remove "before" and "after" property for a cleaner/slimmer event payload
|
||||||
|
diff: eventData.properties.diff,
|
||||||
|
}
|
||||||
|
: eventData.properties,
|
||||||
workspaceMemberId,
|
workspaceMemberId,
|
||||||
workspaceEventBatch.name.split('.')[0],
|
workspaceEventBatch.name.split('.')[0],
|
||||||
eventData.objectMetadata.id,
|
eventData.objectMetadata.id,
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { ObjectRecordBaseEvent } from 'src/engine/core-modules/event-emitter/types/object-record.base.event';
|
import { ObjectRecordNonDestructiveEvent } from 'src/engine/core-modules/event-emitter/types/object-record-non-destructive-event';
|
||||||
import { Process } from 'src/engine/core-modules/message-queue/decorators/process.decorator';
|
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 { Processor } from 'src/engine/core-modules/message-queue/decorators/processor.decorator';
|
||||||
import { MessageQueue } from 'src/engine/core-modules/message-queue/message-queue.constants';
|
import { MessageQueue } from 'src/engine/core-modules/message-queue/message-queue.constants';
|
||||||
@ -7,7 +7,6 @@ import { WorkspaceEventBatch } from 'src/engine/workspace-event-emitter/types/wo
|
|||||||
import { TimelineActivityService } from 'src/modules/timeline/services/timeline-activity.service';
|
import { TimelineActivityService } from 'src/modules/timeline/services/timeline-activity.service';
|
||||||
import { WorkspaceMemberRepository } from 'src/modules/workspace-member/repositories/workspace-member.repository';
|
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 { 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)
|
@Processor(MessageQueue.entityEventsToDbQueue)
|
||||||
export class UpsertTimelineActivityFromInternalEvent {
|
export class UpsertTimelineActivityFromInternalEvent {
|
||||||
@ -19,9 +18,7 @@ export class UpsertTimelineActivityFromInternalEvent {
|
|||||||
|
|
||||||
@Process(UpsertTimelineActivityFromInternalEvent.name)
|
@Process(UpsertTimelineActivityFromInternalEvent.name)
|
||||||
async handle(
|
async handle(
|
||||||
workspaceEventBatch: WorkspaceEventBatch<
|
workspaceEventBatch: WorkspaceEventBatch<ObjectRecordNonDestructiveEvent>,
|
||||||
ObjectRecordBaseEvent<TimelineActivityWorkspaceEntity>
|
|
||||||
>,
|
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
for (const eventData of workspaceEventBatch.events) {
|
for (const eventData of workspaceEventBatch.events) {
|
||||||
if (eventData.userId) {
|
if (eventData.userId) {
|
||||||
@ -33,13 +30,6 @@ export class UpsertTimelineActivityFromInternalEvent {
|
|||||||
eventData.workspaceMemberId = workspaceMember.id;
|
eventData.workspaceMemberId = workspaceMember.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (eventData.properties.diff) {
|
|
||||||
// we remove "before" and "after" property for a cleaner/slimmer event payload
|
|
||||||
eventData.properties = {
|
|
||||||
diff: eventData.properties.diff,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Temporary
|
// Temporary
|
||||||
// We ignore every that is not a LinkedObject or a Business Object
|
// We ignore every that is not a LinkedObject or a Business Object
|
||||||
if (
|
if (
|
||||||
@ -51,7 +41,16 @@ export class UpsertTimelineActivityFromInternalEvent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
await this.timelineActivityService.upsertEvent({
|
await this.timelineActivityService.upsertEvent({
|
||||||
event: eventData,
|
event:
|
||||||
|
// we remove "before" and "after" property for a cleaner/slimmer event payload
|
||||||
|
'diff' in eventData.properties && eventData.properties.diff
|
||||||
|
? {
|
||||||
|
...eventData,
|
||||||
|
properties: {
|
||||||
|
diff: eventData.properties.diff,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
: eventData,
|
||||||
eventName: workspaceEventBatch.name,
|
eventName: workspaceEventBatch.name,
|
||||||
workspaceId: workspaceEventBatch.workspaceId,
|
workspaceId: workspaceEventBatch.workspaceId,
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,19 +1,20 @@
|
|||||||
import { Injectable } from '@nestjs/common';
|
import { Injectable } from '@nestjs/common';
|
||||||
|
|
||||||
|
import { ObjectRecordNonDestructiveEvent } from 'src/engine/core-modules/event-emitter/types/object-record-non-destructive-event';
|
||||||
import { ObjectRecordBaseEvent } from 'src/engine/core-modules/event-emitter/types/object-record.base.event';
|
import { ObjectRecordBaseEvent } from 'src/engine/core-modules/event-emitter/types/object-record.base.event';
|
||||||
import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator';
|
import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator';
|
||||||
import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service';
|
import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service';
|
||||||
import { TimelineActivityRepository } from 'src/modules/timeline/repositiories/timeline-activity.repository';
|
import { TimelineActivityRepository } from 'src/modules/timeline/repositiories/timeline-activity.repository';
|
||||||
import { TimelineActivityWorkspaceEntity } from 'src/modules/timeline/standard-objects/timeline-activity.workspace-entity';
|
import { TimelineActivityWorkspaceEntity } from 'src/modules/timeline/standard-objects/timeline-activity.workspace-entity';
|
||||||
|
|
||||||
type TimelineActivity =
|
type TimelineActivity = Omit<ObjectRecordNonDestructiveEvent, 'properties'> & {
|
||||||
ObjectRecordBaseEvent<TimelineActivityWorkspaceEntity> & {
|
name: string;
|
||||||
name: string;
|
objectName?: string;
|
||||||
objectName?: string;
|
linkedRecordCachedName?: string;
|
||||||
linkedRecordCachedName?: string;
|
linkedRecordId?: string;
|
||||||
linkedRecordId?: string;
|
linkedObjectMetadataId?: string;
|
||||||
linkedObjectMetadataId?: string;
|
properties: Record<string, any>; // more relaxed conditions than for internal events
|
||||||
};
|
};
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class TimelineActivityService {
|
export class TimelineActivityService {
|
||||||
@ -33,7 +34,7 @@ export class TimelineActivityService {
|
|||||||
eventName,
|
eventName,
|
||||||
workspaceId,
|
workspaceId,
|
||||||
}: {
|
}: {
|
||||||
event: ObjectRecordBaseEvent<TimelineActivityWorkspaceEntity>;
|
event: ObjectRecordBaseEvent;
|
||||||
eventName: string;
|
eventName: string;
|
||||||
workspaceId: string;
|
workspaceId: string;
|
||||||
}) {
|
}) {
|
||||||
@ -65,7 +66,7 @@ export class TimelineActivityService {
|
|||||||
workspaceId,
|
workspaceId,
|
||||||
eventName,
|
eventName,
|
||||||
}: {
|
}: {
|
||||||
event: ObjectRecordBaseEvent<TimelineActivityWorkspaceEntity>;
|
event: ObjectRecordBaseEvent;
|
||||||
workspaceId: string;
|
workspaceId: string;
|
||||||
eventName: string;
|
eventName: string;
|
||||||
}): Promise<TimelineActivity[] | undefined> {
|
}): Promise<TimelineActivity[] | undefined> {
|
||||||
@ -78,7 +79,10 @@ export class TimelineActivityService {
|
|||||||
|
|
||||||
// 2 timelines, one for the linked object and one for the task/note
|
// 2 timelines, one for the linked object and one for the task/note
|
||||||
if (linkedTimelineActivities && linkedTimelineActivities?.length > 0)
|
if (linkedTimelineActivities && linkedTimelineActivities?.length > 0)
|
||||||
return [...linkedTimelineActivities, { ...event, name: eventName }];
|
return [
|
||||||
|
...linkedTimelineActivities,
|
||||||
|
{ ...event, name: eventName },
|
||||||
|
] satisfies TimelineActivity[];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
@ -93,7 +97,7 @@ export class TimelineActivityService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return [{ ...event, name: eventName }];
|
return [{ ...event, name: eventName }] satisfies TimelineActivity[];
|
||||||
}
|
}
|
||||||
|
|
||||||
private async getLinkedTimelineActivities({
|
private async getLinkedTimelineActivities({
|
||||||
@ -101,7 +105,7 @@ export class TimelineActivityService {
|
|||||||
workspaceId,
|
workspaceId,
|
||||||
eventName,
|
eventName,
|
||||||
}: {
|
}: {
|
||||||
event: ObjectRecordBaseEvent<TimelineActivityWorkspaceEntity>;
|
event: ObjectRecordBaseEvent;
|
||||||
workspaceId: string;
|
workspaceId: string;
|
||||||
eventName: string;
|
eventName: string;
|
||||||
}): Promise<TimelineActivity[] | undefined> {
|
}): Promise<TimelineActivity[] | undefined> {
|
||||||
@ -146,7 +150,7 @@ export class TimelineActivityService {
|
|||||||
eventName,
|
eventName,
|
||||||
workspaceId,
|
workspaceId,
|
||||||
}: {
|
}: {
|
||||||
event: ObjectRecordBaseEvent<TimelineActivityWorkspaceEntity>;
|
event: ObjectRecordBaseEvent;
|
||||||
dataSourceSchema: string;
|
dataSourceSchema: string;
|
||||||
activityType: string;
|
activityType: string;
|
||||||
eventName: string;
|
eventName: string;
|
||||||
@ -195,7 +199,7 @@ export class TimelineActivityService {
|
|||||||
linkedRecordCachedName: activity[0].title,
|
linkedRecordCachedName: activity[0].title,
|
||||||
linkedRecordId: activity[0].id,
|
linkedRecordId: activity[0].id,
|
||||||
linkedObjectMetadataId: event.objectMetadata.id,
|
linkedObjectMetadataId: event.objectMetadata.id,
|
||||||
} as TimelineActivity;
|
} satisfies TimelineActivity;
|
||||||
})
|
})
|
||||||
.filter((event): event is TimelineActivity => event !== undefined);
|
.filter((event): event is TimelineActivity => event !== undefined);
|
||||||
}
|
}
|
||||||
@ -207,7 +211,7 @@ export class TimelineActivityService {
|
|||||||
eventName,
|
eventName,
|
||||||
workspaceId,
|
workspaceId,
|
||||||
}: {
|
}: {
|
||||||
event: ObjectRecordBaseEvent<TimelineActivityWorkspaceEntity>;
|
event: ObjectRecordBaseEvent;
|
||||||
dataSourceSchema: string;
|
dataSourceSchema: string;
|
||||||
activityType: string;
|
activityType: string;
|
||||||
eventName: string;
|
eventName: string;
|
||||||
@ -258,7 +262,7 @@ export class TimelineActivityService {
|
|||||||
linkedRecordCachedName: activity[0].title,
|
linkedRecordCachedName: activity[0].title,
|
||||||
linkedRecordId: activity[0].id,
|
linkedRecordId: activity[0].id,
|
||||||
linkedObjectMetadataId: activityObjectMetadataId,
|
linkedObjectMetadataId: activityObjectMetadataId,
|
||||||
} as TimelineActivity,
|
} satisfies TimelineActivity,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,19 +2,19 @@ import { Logger } from '@nestjs/common';
|
|||||||
|
|
||||||
import { ArrayContains } from 'typeorm';
|
import { ArrayContains } from 'typeorm';
|
||||||
|
|
||||||
|
import { ObjectRecordEvent } from 'src/engine/core-modules/event-emitter/types/object-record-event.event';
|
||||||
import { InjectMessageQueue } from 'src/engine/core-modules/message-queue/decorators/message-queue.decorator';
|
import { InjectMessageQueue } from 'src/engine/core-modules/message-queue/decorators/message-queue.decorator';
|
||||||
import { Process } from 'src/engine/core-modules/message-queue/decorators/process.decorator';
|
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 { Processor } from 'src/engine/core-modules/message-queue/decorators/processor.decorator';
|
||||||
import { MessageQueue } from 'src/engine/core-modules/message-queue/message-queue.constants';
|
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 { MessageQueueService } from 'src/engine/core-modules/message-queue/services/message-queue.service';
|
||||||
import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager';
|
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/types/workspace-event.type';
|
import { WorkspaceEventBatch } from 'src/engine/workspace-event-emitter/types/workspace-event.type';
|
||||||
import {
|
import {
|
||||||
CallWebhookJob,
|
CallWebhookJob,
|
||||||
CallWebhookJobData,
|
CallWebhookJobData,
|
||||||
} from 'src/modules/webhook/jobs/call-webhook.job';
|
} from 'src/modules/webhook/jobs/call-webhook.job';
|
||||||
|
import { WebhookWorkspaceEntity } from 'src/modules/webhook/standard-objects/webhook.workspace-entity';
|
||||||
import { removeSecretFromWebhookRecord } from 'src/utils/remove-secret-from-webhook-record';
|
import { removeSecretFromWebhookRecord } from 'src/utils/remove-secret-from-webhook-record';
|
||||||
|
|
||||||
@Processor(MessageQueue.webhookQueue)
|
@Processor(MessageQueue.webhookQueue)
|
||||||
@ -29,7 +29,7 @@ export class CallWebhookJobsJob {
|
|||||||
|
|
||||||
@Process(CallWebhookJobsJob.name)
|
@Process(CallWebhookJobsJob.name)
|
||||||
async handle(
|
async handle(
|
||||||
workspaceEventBatch: WorkspaceEventBatch<ObjectRecordBaseEvent>,
|
workspaceEventBatch: WorkspaceEventBatch<ObjectRecordEvent>,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
// If you change that function, double check it does not break Zapier
|
// If you change that function, double check it does not break Zapier
|
||||||
// trigger in packages/twenty-zapier/src/triggers/trigger_record.ts
|
// trigger in packages/twenty-zapier/src/triggers/trigger_record.ts
|
||||||
@ -60,8 +60,16 @@ export class CallWebhookJobsJob {
|
|||||||
nameSingular: eventData.objectMetadata.nameSingular,
|
nameSingular: eventData.objectMetadata.nameSingular,
|
||||||
};
|
};
|
||||||
const workspaceId = workspaceEventBatch.workspaceId;
|
const workspaceId = workspaceEventBatch.workspaceId;
|
||||||
const record = eventData.properties.after || eventData.properties.before;
|
const record =
|
||||||
const updatedFields = eventData.properties.updatedFields;
|
'after' in eventData.properties
|
||||||
|
? eventData.properties.after
|
||||||
|
: 'before' in eventData.properties
|
||||||
|
? eventData.properties.before
|
||||||
|
: {};
|
||||||
|
const updatedFields =
|
||||||
|
'updatedFields' in eventData.properties
|
||||||
|
? eventData.properties.updatedFields
|
||||||
|
: undefined;
|
||||||
|
|
||||||
const isWebhookEvent = nameSingular === 'webhook';
|
const isWebhookEvent = nameSingular === 'webhook';
|
||||||
const sanitizedRecord = removeSecretFromWebhookRecord(
|
const sanitizedRecord = removeSecretFromWebhookRecord(
|
||||||
|
|||||||
Reference in New Issue
Block a user