From 7507a1ab1e1ff9d0c7d9633e49068e7809e65e2e Mon Sep 17 00:00:00 2001 From: Baptiste Arnaud Date: Fri, 13 May 2022 06:46:17 -0700 Subject: [PATCH] =?UTF-8?q?fix:=20=F0=9F=90=9B=20Webhook=20duplication?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/builder/services/typebots/typebots.ts | 169 ++++++++++++--------- apps/builder/services/webhook.ts | 9 +- 2 files changed, 101 insertions(+), 77 deletions(-) diff --git a/apps/builder/services/typebots/typebots.ts b/apps/builder/services/typebots/typebots.ts index a19ecf635..7fb072bdb 100644 --- a/apps/builder/services/typebots/typebots.ts +++ b/apps/builder/services/typebots/typebots.ts @@ -101,96 +101,119 @@ export const createTypebot = async ({ } export const importTypebot = async (typebot: Typebot, userPlan: Plan) => { - return sendRequest({ + const { typebot: newTypebot, webhookIdsMapping } = duplicateTypebot( + typebot, + userPlan + ) + const { data, error } = await sendRequest({ url: `/api/typebots`, method: 'POST', - body: await duplicateTypebot(typebot, userPlan), + body: newTypebot, }) + if (!data) return { data, error } + const webhookSteps = typebot.blocks + .flatMap((b) => b.steps) + .filter(isWebhookStep) + await Promise.all( + webhookSteps.map((s) => + duplicateWebhook( + newTypebot.id, + s.webhookId, + webhookIdsMapping.get(s.webhookId) as string + ) + ) + ) + return { data, error } } -const duplicateTypebot = async ( +const duplicateTypebot = ( typebot: Typebot, userPlan: Plan -): Promise => { +): { typebot: Typebot; webhookIdsMapping: Map } => { const blockIdsMapping = generateOldNewIdsMapping(typebot.blocks) const edgeIdsMapping = generateOldNewIdsMapping(typebot.edges) + const webhookIdsMapping = generateOldNewIdsMapping( + typebot.blocks + .flatMap((b) => b.steps) + .filter(isWebhookStep) + .map((s) => ({ id: s.webhookId })) + ) + const id = cuid() return { - ...typebot, - id: cuid(), - name: `${typebot.name} copy`, - publishedTypebotId: null, - publicId: null, - customDomain: null, - blocks: await Promise.all( - typebot.blocks.map(async (b) => ({ + typebot: { + ...typebot, + id, + name: `${typebot.name} copy`, + publishedTypebotId: null, + publicId: null, + customDomain: null, + blocks: typebot.blocks.map((b) => ({ ...b, id: blockIdsMapping.get(b.id) as string, - steps: await Promise.all( - b.steps.map(async (s) => { - const newIds = { - blockId: blockIdsMapping.get(s.blockId) as string, - outgoingEdgeId: s.outgoingEdgeId - ? edgeIdsMapping.get(s.outgoingEdgeId) - : undefined, - } - if ( - s.type === LogicStepType.TYPEBOT_LINK && - s.options.typebotId === 'current' && - isDefined(s.options.blockId) - ) - return { - ...s, - options: { - ...s.options, - blockId: blockIdsMapping.get(s.options.blockId as string), - }, - } - if (stepHasItems(s)) - return { - ...s, - items: s.items.map((item) => ({ - ...item, - outgoingEdgeId: item.outgoingEdgeId - ? (edgeIdsMapping.get(item.outgoingEdgeId) as string) - : undefined, - })), - ...newIds, - } as ChoiceInputStep | ConditionStep - if (isWebhookStep(s)) { - const newWebhook = await duplicateWebhook(s.webhookId) - return { - ...s, - webhookId: newWebhook ? newWebhook.id : cuid(), - ...newIds, - } - } + steps: b.steps.map((s) => { + const newIds = { + blockId: blockIdsMapping.get(s.blockId) as string, + outgoingEdgeId: s.outgoingEdgeId + ? edgeIdsMapping.get(s.outgoingEdgeId) + : undefined, + } + if ( + s.type === LogicStepType.TYPEBOT_LINK && + s.options.typebotId === 'current' && + isDefined(s.options.blockId) + ) return { ...s, + options: { + ...s.options, + blockId: blockIdsMapping.get(s.options.blockId as string), + }, + } + if (stepHasItems(s)) + return { + ...s, + items: s.items.map((item) => ({ + ...item, + outgoingEdgeId: item.outgoingEdgeId + ? (edgeIdsMapping.get(item.outgoingEdgeId) as string) + : undefined, + })), + ...newIds, + } as ChoiceInputStep | ConditionStep + if (isWebhookStep(s)) { + return { + ...s, + webhookId: webhookIdsMapping.get(s.webhookId) as string, ...newIds, } - }) - ), - })) - ), - edges: typebot.edges.map((e) => ({ - ...e, - id: edgeIdsMapping.get(e.id) as string, - from: { - ...e.from, - blockId: blockIdsMapping.get(e.from.blockId) as string, - }, - to: { ...e.to, blockId: blockIdsMapping.get(e.to.blockId) as string }, - })), - settings: - typebot.settings.general.isBrandingEnabled === false && - userPlan === Plan.FREE - ? { - ...typebot.settings, - general: { ...typebot.settings.general, isBrandingEnabled: true }, } - : typebot.settings, - createdAt: new Date().toISOString(), - updatedAt: new Date().toISOString(), + return { + ...s, + ...newIds, + } + }), + })), + edges: typebot.edges.map((e) => ({ + ...e, + id: edgeIdsMapping.get(e.id) as string, + from: { + ...e.from, + blockId: blockIdsMapping.get(e.from.blockId) as string, + }, + to: { ...e.to, blockId: blockIdsMapping.get(e.to.blockId) as string }, + })), + settings: + typebot.settings.general.isBrandingEnabled === false && + userPlan === Plan.FREE + ? { + ...typebot.settings, + general: { ...typebot.settings.general, isBrandingEnabled: true }, + } + : typebot.settings, + createdAt: new Date().toISOString(), + updatedAt: new Date().toISOString(), + }, + webhookIdsMapping, } } diff --git a/apps/builder/services/webhook.ts b/apps/builder/services/webhook.ts index 485b1f8d9..0a99b78ab 100644 --- a/apps/builder/services/webhook.ts +++ b/apps/builder/services/webhook.ts @@ -1,4 +1,3 @@ -import cuid from 'cuid' import { Webhook } from 'models' import { sendRequest } from 'utils' @@ -10,13 +9,15 @@ export const saveWebhook = (webhookId: string, webhook: Partial) => }) export const duplicateWebhook = async ( - webhookId: string + typebotId: string, + existingWebhookId: string, + newWebhookId: string ): Promise => { const { data } = await sendRequest<{ webhook: Webhook }>( - `/api/webhooks/${webhookId}` + `/api/webhooks/${existingWebhookId}` ) if (!data) return - const newWebhook = { ...data.webhook, id: cuid() } + const newWebhook = { ...data.webhook, id: newWebhookId, typebotId } await saveWebhook(newWebhook.id, newWebhook) return newWebhook }