From c86c2b40962b2d8e6f98c25c1f58e699cc8ca147 Mon Sep 17 00:00:00 2001 From: Peter Clement Date: Fri, 12 May 2023 15:57:34 +0100 Subject: [PATCH] add synchronous webhook functionality --- .../tests/core/utilities/mocks/licenses.ts | 4 ++ .../FlowChart/ActionModal.svelte | 27 ++++++++++- .../FlowChart/FlowItem.svelte | 2 +- .../src/constants/backend/automations.js | 1 + .../builder/src/stores/portal/licensing.js | 4 ++ packages/frontend-core/src/constants.js | 1 + .../server/src/api/controllers/webhook.ts | 45 +++++++++++++++---- packages/types/src/sdk/licensing/feature.ts | 1 + 8 files changed, 73 insertions(+), 12 deletions(-) diff --git a/packages/backend-core/tests/core/utilities/mocks/licenses.ts b/packages/backend-core/tests/core/utilities/mocks/licenses.ts index 839b22e5f9..6e74294417 100644 --- a/packages/backend-core/tests/core/utilities/mocks/licenses.ts +++ b/packages/backend-core/tests/core/utilities/mocks/licenses.ts @@ -90,6 +90,10 @@ export const useScimIntegration = () => { return useFeature(Feature.SCIM) } +export const useSyncWebhook = () => { + return useFeature(Feature.SYNC_WEBHOOKS) +} + // QUOTAS export const setAutomationLogsQuota = (value: number) => { diff --git a/packages/builder/src/components/automation/AutomationBuilder/FlowChart/ActionModal.svelte b/packages/builder/src/components/automation/AutomationBuilder/FlowChart/ActionModal.svelte index 162c4c5618..e4ebd7f20f 100644 --- a/packages/builder/src/components/automation/AutomationBuilder/FlowChart/ActionModal.svelte +++ b/packages/builder/src/components/automation/AutomationBuilder/FlowChart/ActionModal.svelte @@ -7,17 +7,40 @@ Icon, notifications, } from "@budibase/bbui" - import { automationStore } from "builderStore" - import { admin } from "stores/portal" + import { automationStore, selectedAutomation } from "builderStore" + import { admin, licensing } from "stores/portal" import { externalActions } from "./ExternalActions" + import { TriggerStepID, ActionStepID } from "constants/backend/automations" export let blockIdx + export let lastStep + let syncWebhooksEnabled = $licensing.syncWebhooksEnabled + let collectBlockAllowedSteps = [TriggerStepID.APP, TriggerStepID.WEBHOOK] + let collectBlockExists = $selectedAutomation.definition.steps.some( + step => step.stepId === ActionStepID.COLLECT + ) + $: console.log($licensing) + $: console.log(syncWebhooksEnabled) const disabled = { SEND_EMAIL_SMTP: { disabled: !$admin.checklist.smtp.checked, message: "Please configure SMTP", }, + COLLECT: { + disabled: + !collectBlockAllowedSteps.includes( + $selectedAutomation.definition.trigger.stepId + ) || + !lastStep || + !syncWebhooksEnabled || + collectBlockExists, + message: !collectBlockAllowedSteps.includes( + $selectedAutomation.definition.trigger.stepId + ) + ? "Only available for App Action or Webhook triggers" + : "Only available as the last step", + }, } let selectedAction diff --git a/packages/builder/src/components/automation/AutomationBuilder/FlowChart/FlowItem.svelte b/packages/builder/src/components/automation/AutomationBuilder/FlowChart/FlowItem.svelte index 9730c03ef3..99cbab52af 100644 --- a/packages/builder/src/components/automation/AutomationBuilder/FlowChart/FlowItem.svelte +++ b/packages/builder/src/components/automation/AutomationBuilder/FlowChart/FlowItem.svelte @@ -226,7 +226,7 @@ {/if} - + diff --git a/packages/builder/src/constants/backend/automations.js b/packages/builder/src/constants/backend/automations.js index e0cd5b6405..6c58ed8620 100644 --- a/packages/builder/src/constants/backend/automations.js +++ b/packages/builder/src/constants/backend/automations.js @@ -20,6 +20,7 @@ export const ActionStepID = { FILTER: "FILTER", QUERY_ROWS: "QUERY_ROWS", LOOP: "LOOP", + COLLECT: "COLLECT", // these used to be lowercase step IDs, maintain for backwards compat discord: "discord", slack: "slack", diff --git a/packages/builder/src/stores/portal/licensing.js b/packages/builder/src/stores/portal/licensing.js index e6056f1993..24589307b7 100644 --- a/packages/builder/src/stores/portal/licensing.js +++ b/packages/builder/src/stores/portal/licensing.js @@ -103,6 +103,9 @@ export const createLicensingStore = () => { const auditLogsEnabled = license.features.includes( Constants.Features.AUDIT_LOGS ) + const syncWebhooksEnabled = license.features.includes( + Constants.Features.SYNC_WEBHOOKS + ) store.update(state => { return { ...state, @@ -117,6 +120,7 @@ export const createLicensingStore = () => { environmentVariablesEnabled, auditLogsEnabled, enforceableSSO, + syncWebhooksEnabled, } }) }, diff --git a/packages/frontend-core/src/constants.js b/packages/frontend-core/src/constants.js index 42b561d48d..f1f4cf1d7f 100644 --- a/packages/frontend-core/src/constants.js +++ b/packages/frontend-core/src/constants.js @@ -70,6 +70,7 @@ export const Features = { ENFORCEABLE_SSO: "enforceableSSO", BRANDING: "branding", SCIM: "scim", + SYNC_WEBHOOKS: "syncWebhooks", } // Role IDs diff --git a/packages/server/src/api/controllers/webhook.ts b/packages/server/src/api/controllers/webhook.ts index c3fc3892d3..066b1e534d 100644 --- a/packages/server/src/api/controllers/webhook.ts +++ b/packages/server/src/api/controllers/webhook.ts @@ -6,8 +6,11 @@ import { WebhookActionType, BBContext, Automation, + AutomationActionStepId, } from "@budibase/types" import sdk from "../../sdk" +import * as pro from "@budibase/pro" + const toJsonSchema = require("to-json-schema") const validate = require("jsonschema").validate @@ -78,15 +81,39 @@ export async function trigger(ctx: BBContext) { if (webhook.action.type === WebhookActionType.AUTOMATION) { // trigger with both the pure request and then expand it // incase the user has produced a schema to bind to - await triggers.externalTrigger(target, { - body: ctx.request.body, - ...ctx.request.body, - appId: prodAppId, - }) - } - ctx.status = 200 - ctx.body = { - message: "Webhook trigger fired successfully", + + let hasCollectBlock = target.definition.steps.some( + (step: any) => step.stepId === AutomationActionStepId.COLLECT + ) + + if (hasCollectBlock && (await pro.features.isSyncWebhookEnabled())) { + const response = await triggers.externalTrigger( + target, + { + body: ctx.request.body, + ...ctx.request.body, + appId: prodAppId, + }, + { getResponses: true } + ) + + let collectedValue = response.steps.find( + (step: any) => step.stepId === AutomationActionStepId.COLLECT + ) + + ctx.status = 200 + ctx.body = collectedValue.outputs + } else { + await triggers.externalTrigger(target, { + body: ctx.request.body, + ...ctx.request.body, + appId: prodAppId, + }) + ctx.status = 200 + ctx.body = { + message: "Webhook trigger fired successfully", + } + } } } catch (err: any) { if (err.status === 404) { diff --git a/packages/types/src/sdk/licensing/feature.ts b/packages/types/src/sdk/licensing/feature.ts index 97fbd36224..d5b5fe6e24 100644 --- a/packages/types/src/sdk/licensing/feature.ts +++ b/packages/types/src/sdk/licensing/feature.ts @@ -8,6 +8,7 @@ export enum Feature { ENFORCEABLE_SSO = "enforceableSSO", BRANDING = "branding", SCIM = "scim", + SYNC_WEBHOOKS = "syncWebhooks", } export type PlanFeatures = { [key in PlanType]: Feature[] | undefined }