Introduce webhook v2 (#17456)

Migrate webhook to v2 entity
This commit is contained in:
Charles Bochet
2026-01-27 16:32:33 +01:00
committed by GitHub
parent 27e5b9797b
commit bc7791871f
83 changed files with 1574 additions and 975 deletions
@@ -0,0 +1,41 @@
import { trimAndRemoveDuplicatedWhitespacesFromObjectStringProperties } from 'twenty-shared/utils';
import { v4 } from 'uuid';
import { type FlatWebhook } from 'src/engine/metadata-modules/flat-webhook/types/flat-webhook.type';
import { type CreateWebhookInput } from 'src/engine/metadata-modules/webhook/dtos/create-webhook.input';
import { generateWebhookSecret } from 'src/engine/metadata-modules/webhook/utils/generate-webhook-secret.util';
export const fromCreateWebhookInputToFlatWebhookToCreate = ({
createWebhookInput,
workspaceId,
applicationId,
}: {
createWebhookInput: CreateWebhookInput;
workspaceId: string;
applicationId: string;
}): FlatWebhook => {
const now = new Date().toISOString();
const { targetUrl, description } =
trimAndRemoveDuplicatedWhitespacesFromObjectStringProperties(
createWebhookInput,
['targetUrl', 'description'],
);
const id = createWebhookInput.id ?? v4();
const secret = createWebhookInput.secret ?? generateWebhookSecret();
return {
id,
targetUrl,
operations: createWebhookInput.operations,
description: description ?? null,
secret,
workspaceId,
createdAt: now,
updatedAt: now,
deletedAt: null,
universalIdentifier: id,
applicationId,
};
};
@@ -0,0 +1,31 @@
import { isDefined } from 'twenty-shared/utils';
import { type FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type';
import { findFlatEntityByIdInFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps.util';
import { type FlatWebhook } from 'src/engine/metadata-modules/flat-webhook/types/flat-webhook.type';
import {
WebhookException,
WebhookExceptionCode,
} from 'src/engine/metadata-modules/webhook/webhook.exception';
export const fromDeleteWebhookInputToFlatWebhookOrThrow = ({
flatWebhookMaps,
webhookId,
}: {
flatWebhookMaps: FlatEntityMaps<FlatWebhook>;
webhookId: string;
}): FlatWebhook => {
const existingFlatWebhook = findFlatEntityByIdInFlatEntityMaps({
flatEntityId: webhookId,
flatEntityMaps: flatWebhookMaps,
});
if (!isDefined(existingFlatWebhook)) {
throw new WebhookException(
'Webhook not found',
WebhookExceptionCode.WEBHOOK_NOT_FOUND,
);
}
return existingFlatWebhook;
};
@@ -0,0 +1,17 @@
import { type FlatWebhook } from 'src/engine/metadata-modules/flat-webhook/types/flat-webhook.type';
import { type WebhookDTO } from 'src/engine/metadata-modules/webhook/dtos/webhook.dto';
export const fromFlatWebhookToWebhookDto = (
flatWebhook: FlatWebhook,
): WebhookDTO => ({
id: flatWebhook.id,
targetUrl: flatWebhook.targetUrl,
operations: flatWebhook.operations,
description: flatWebhook.description,
secret: flatWebhook.secret,
workspaceId: flatWebhook.workspaceId,
applicationId: flatWebhook.applicationId,
createdAt: new Date(flatWebhook.createdAt),
updatedAt: new Date(flatWebhook.updatedAt),
deletedAt: flatWebhook.deletedAt ? new Date(flatWebhook.deletedAt) : null,
});
@@ -0,0 +1,41 @@
import { isDefined } from 'twenty-shared/utils';
import { type FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type';
import { findFlatEntityByIdInFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps.util';
import { FLAT_WEBHOOK_EDITABLE_PROPERTIES } from 'src/engine/metadata-modules/flat-webhook/constants/flat-webhook-editable-properties.constant';
import { type FlatWebhook } from 'src/engine/metadata-modules/flat-webhook/types/flat-webhook.type';
import { type UpdateWebhookInput } from 'src/engine/metadata-modules/webhook/dtos/update-webhook.input';
import {
WebhookException,
WebhookExceptionCode,
} from 'src/engine/metadata-modules/webhook/webhook.exception';
import { mergeUpdateInExistingRecord } from 'src/utils/merge-update-in-existing-record.util';
export const fromUpdateWebhookInputToFlatWebhookToUpdateOrThrow = ({
flatWebhookMaps,
updateWebhookInput,
}: {
flatWebhookMaps: FlatEntityMaps<FlatWebhook>;
updateWebhookInput: UpdateWebhookInput;
}): FlatWebhook => {
const existingFlatWebhook = findFlatEntityByIdInFlatEntityMaps({
flatEntityId: updateWebhookInput.id,
flatEntityMaps: flatWebhookMaps,
});
if (!isDefined(existingFlatWebhook)) {
throw new WebhookException(
'Webhook not found',
WebhookExceptionCode.WEBHOOK_NOT_FOUND,
);
}
return {
...mergeUpdateInExistingRecord({
existing: existingFlatWebhook,
properties: [...FLAT_WEBHOOK_EDITABLE_PROPERTIES],
update: updateWebhookInput.update,
}),
updatedAt: new Date().toISOString(),
};
};
@@ -0,0 +1,20 @@
import { type FlatWebhook } from 'src/engine/metadata-modules/flat-webhook/types/flat-webhook.type';
import { type WebhookEntity } from 'src/engine/metadata-modules/webhook/entities/webhook.entity';
export const fromWebhookEntityToFlatWebhook = (
webhookEntity: WebhookEntity,
): FlatWebhook => {
return {
id: webhookEntity.id,
targetUrl: webhookEntity.targetUrl,
operations: webhookEntity.operations,
description: webhookEntity.description,
secret: webhookEntity.secret,
workspaceId: webhookEntity.workspaceId,
universalIdentifier: webhookEntity.universalIdentifier,
applicationId: webhookEntity.applicationId,
createdAt: webhookEntity.createdAt.toISOString(),
updatedAt: webhookEntity.updatedAt.toISOString(),
deletedAt: webhookEntity.deletedAt?.toISOString() ?? null,
};
};