From 2531d9a6818793fc7e47aecb5ecce683602cb4ee Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Mon, 6 Sep 2021 17:53:02 +0100 Subject: [PATCH] Cleanup, prepping for automation history, some refactoring to get rid of concept of builtin. --- .../server/src/api/controllers/automation.js | 16 +- .../src/api/routes/tests/automation.spec.js | 2 +- packages/server/src/automations/actions.js | 14 +- packages/server/src/automations/logic.js | 12 +- packages/server/src/automations/steps/bash.js | 4 +- .../server/src/automations/steps/createRow.js | 4 +- .../server/src/automations/steps/delay.js | 4 +- .../server/src/automations/steps/deleteRow.js | 4 +- .../server/src/automations/steps/discord.js | 4 +- .../src/automations/steps/executeQuery.js | 4 +- .../src/automations/steps/executeScript.js | 4 +- .../server/src/automations/steps/filter.js | 8 +- .../src/automations/steps/integromat.js | 4 +- .../src/automations/steps/outgoingWebhook.js | 4 +- .../src/automations/steps/sendSmtpEmail.js | 4 +- .../src/automations/steps/sendgridEmail.js | 4 +- .../server/src/automations/steps/serverLog.js | 4 +- .../server/src/automations/steps/updateRow.js | 4 +- .../server/src/automations/steps/zapier.js | 4 +- .../src/automations/tests/utilities/index.js | 4 +- packages/server/src/automations/thread.js | 2 +- .../server/src/automations/triggerInfo/app.js | 31 ++ .../src/automations/triggerInfo/cron.js | 31 ++ .../src/automations/triggerInfo/index.js | 15 + .../src/automations/triggerInfo/rowDeleted.js | 32 ++ .../src/automations/triggerInfo/rowSaved.js | 40 +++ .../src/automations/triggerInfo/rowUpdated.js | 40 +++ .../src/automations/triggerInfo/webhook.js | 36 +++ packages/server/src/automations/triggers.js | 280 +----------------- packages/server/src/middleware/usageQuota.js | 2 +- 30 files changed, 290 insertions(+), 331 deletions(-) create mode 100644 packages/server/src/automations/triggerInfo/app.js create mode 100644 packages/server/src/automations/triggerInfo/cron.js create mode 100644 packages/server/src/automations/triggerInfo/index.js create mode 100644 packages/server/src/automations/triggerInfo/rowDeleted.js create mode 100644 packages/server/src/automations/triggerInfo/rowSaved.js create mode 100644 packages/server/src/automations/triggerInfo/rowUpdated.js create mode 100644 packages/server/src/automations/triggerInfo/webhook.js diff --git a/packages/server/src/api/controllers/automation.js b/packages/server/src/api/controllers/automation.js index 2d164b415d..8a3bbd93ec 100644 --- a/packages/server/src/api/controllers/automation.js +++ b/packages/server/src/api/controllers/automation.js @@ -5,8 +5,8 @@ const triggers = require("../../automations/triggers") const webhooks = require("./webhook") const { getAutomationParams, generateAutomationID } = require("../../db/utils") -const WH_STEP_ID = triggers.BUILTIN_DEFINITIONS.WEBHOOK.stepId -const CRON_STEP_ID = triggers.BUILTIN_DEFINITIONS.CRON.stepId +const WH_STEP_ID = triggers.TRIGGER_DEFINITIONS.WEBHOOK.stepId +const CRON_STEP_ID = triggers.TRIGGER_DEFINITIONS.CRON.stepId /************************* * * @@ -242,22 +242,22 @@ exports.destroy = async function (ctx) { } exports.getActionList = async function (ctx) { - ctx.body = actions.DEFINITIONS + ctx.body = actions.ACTION_DEFINITIONS } exports.getTriggerList = async function (ctx) { - ctx.body = triggers.BUILTIN_DEFINITIONS + ctx.body = triggers.TRIGGER_DEFINITIONS } exports.getLogicList = async function (ctx) { - ctx.body = logic.BUILTIN_DEFINITIONS + ctx.body = logic.LOGIC_DEFINITIONS } module.exports.getDefinitionList = async function (ctx) { ctx.body = { - logic: logic.BUILTIN_DEFINITIONS, - trigger: triggers.BUILTIN_DEFINITIONS, - action: actions.DEFINITIONS, + logic: logic.LOGIC_DEFINITIONS, + trigger: triggers.TRIGGER_DEFINITIONS, + action: actions.ACTION_DEFINITIONS, } } diff --git a/packages/server/src/api/routes/tests/automation.spec.js b/packages/server/src/api/routes/tests/automation.spec.js index 5654c14c17..09e8747813 100644 --- a/packages/server/src/api/routes/tests/automation.spec.js +++ b/packages/server/src/api/routes/tests/automation.spec.js @@ -44,7 +44,7 @@ describe("/automations", () => { ACTION_DEFINITIONS = res.body }) - it("returns a list of definitions for triggers", async () => { + it("returns a list of definitions for triggerInfo", async () => { const res = await request .get(`/api/automations/trigger/list`) .set(config.defaultHeaders()) diff --git a/packages/server/src/automations/actions.js b/packages/server/src/automations/actions.js index 4577eccbaa..767f1120d4 100644 --- a/packages/server/src/automations/actions.js +++ b/packages/server/src/automations/actions.js @@ -13,7 +13,7 @@ const discord = require("./steps/discord") const zapier = require("./steps/zapier") const integromat = require("./steps/integromat") -const BUILTIN_ACTIONS = { +const ACTION_IMPLS = { SEND_EMAIL: sendgridEmail.run, SEND_EMAIL_SMTP: sendSmtpEmail.run, CREATE_ROW: createRow.run, @@ -29,7 +29,7 @@ const BUILTIN_ACTIONS = { zapier: zapier.run, integromat: integromat.run, } -const BUILTIN_DEFINITIONS = { +const ACTION_DEFINITIONS = { SEND_EMAIL: sendgridEmail.definition, SEND_EMAIL_SMTP: sendSmtpEmail.definition, CREATE_ROW: createRow.definition, @@ -47,12 +47,10 @@ const BUILTIN_DEFINITIONS = { } /* istanbul ignore next */ -module.exports.getAction = async function (actionName) { - if (BUILTIN_ACTIONS[actionName] != null) { - return BUILTIN_ACTIONS[actionName] +exports.getAction = async function (actionName) { + if (ACTION_IMPLS[actionName] != null) { + return ACTION_IMPLS[actionName] } } -// definitions will have downloaded ones added to it, while builtin won't -module.exports.DEFINITIONS = BUILTIN_DEFINITIONS -module.exports.BUILTIN_DEFINITIONS = BUILTIN_DEFINITIONS +exports.ACTION_DEFINITIONS = ACTION_DEFINITIONS diff --git a/packages/server/src/automations/logic.js b/packages/server/src/automations/logic.js index cbd3d42430..52ee51252b 100644 --- a/packages/server/src/automations/logic.js +++ b/packages/server/src/automations/logic.js @@ -1,20 +1,20 @@ let filter = require("./steps/filter") let delay = require("./steps/delay") -let BUILTIN_LOGIC = { +let LOGIC_IMPLS = { DELAY: delay.run, FILTER: filter.run, } -let BUILTIN_DEFINITIONS = { +let LOGIC_DEFINITIONS = { DELAY: delay.definition, FILTER: filter.definition, } -module.exports.getLogic = function (logicName) { - if (BUILTIN_LOGIC[logicName] != null) { - return BUILTIN_LOGIC[logicName] +exports.getLogic = function (logicName) { + if (LOGIC_IMPLS[logicName] != null) { + return LOGIC_IMPLS[logicName] } } -module.exports.BUILTIN_DEFINITIONS = BUILTIN_DEFINITIONS +exports.LOGIC_DEFINITIONS = LOGIC_DEFINITIONS diff --git a/packages/server/src/automations/steps/bash.js b/packages/server/src/automations/steps/bash.js index 76d6713c5b..f2d98ce944 100644 --- a/packages/server/src/automations/steps/bash.js +++ b/packages/server/src/automations/steps/bash.js @@ -1,7 +1,7 @@ const { execSync } = require("child_process") const { processStringSync } = require("@budibase/string-templates") -module.exports.definition = { +exports.definition = { name: "Bash Scripting", tagline: "Execute a bash command", icon: "ri-terminal-box-line", @@ -32,7 +32,7 @@ module.exports.definition = { }, } -module.exports.run = async function ({ inputs, context }) { +exports.run = async function ({ inputs, context }) { if (inputs.code == null) { return { stdout: "Budibase bash automation failed: Invalid inputs", diff --git a/packages/server/src/automations/steps/createRow.js b/packages/server/src/automations/steps/createRow.js index 889f7e98b9..a08adfb000 100644 --- a/packages/server/src/automations/steps/createRow.js +++ b/packages/server/src/automations/steps/createRow.js @@ -3,7 +3,7 @@ const automationUtils = require("../automationUtils") const env = require("../../environment") const usage = require("../../utilities/usageQuota") -module.exports.definition = { +exports.definition = { name: "Create Row", tagline: "Create a {{inputs.enriched.table.name}} row", icon: "ri-save-3-line", @@ -58,7 +58,7 @@ module.exports.definition = { }, } -module.exports.run = async function ({ inputs, appId, apiKey, emitter }) { +exports.run = async function ({ inputs, appId, apiKey, emitter }) { if (inputs.row == null || inputs.row.tableId == null) { return { success: false, diff --git a/packages/server/src/automations/steps/delay.js b/packages/server/src/automations/steps/delay.js index f653d0a980..b79d28e92d 100644 --- a/packages/server/src/automations/steps/delay.js +++ b/packages/server/src/automations/steps/delay.js @@ -1,6 +1,6 @@ let { wait } = require("../../utilities") -module.exports.definition = { +exports.definition = { name: "Delay", icon: "ri-time-line", tagline: "Delay for {{inputs.time}} milliseconds", @@ -21,6 +21,6 @@ module.exports.definition = { type: "LOGIC", } -module.exports.run = async function delay({ inputs }) { +exports.run = async function delay({ inputs }) { await wait(inputs.time) } diff --git a/packages/server/src/automations/steps/deleteRow.js b/packages/server/src/automations/steps/deleteRow.js index 94243fa03a..83e5969381 100644 --- a/packages/server/src/automations/steps/deleteRow.js +++ b/packages/server/src/automations/steps/deleteRow.js @@ -2,7 +2,7 @@ const rowController = require("../../api/controllers/row") const env = require("../../environment") const usage = require("../../utilities/usageQuota") -module.exports.definition = { +exports.definition = { description: "Delete a row from your database", icon: "ri-delete-bin-line", name: "Delete Row", @@ -50,7 +50,7 @@ module.exports.definition = { }, } -module.exports.run = async function ({ inputs, appId, apiKey, emitter }) { +exports.run = async function ({ inputs, appId, apiKey, emitter }) { if (inputs.id == null || inputs.revision == null) { return { success: false, diff --git a/packages/server/src/automations/steps/discord.js b/packages/server/src/automations/steps/discord.js index 36406da5ce..2fefc92916 100644 --- a/packages/server/src/automations/steps/discord.js +++ b/packages/server/src/automations/steps/discord.js @@ -1,6 +1,6 @@ const fetch = require("node-fetch") -module.exports.definition = { +exports.definition = { name: "Discord Message", tagline: "Send a message to a Discord server", description: "Send a message to a Discord server", @@ -44,7 +44,7 @@ module.exports.definition = { }, } -module.exports.run = async function ({ inputs }) { +exports.run = async function ({ inputs }) { const { url, username, avatar_url, content } = inputs const response = await fetch(url, { diff --git a/packages/server/src/automations/steps/executeQuery.js b/packages/server/src/automations/steps/executeQuery.js index d045a75544..474b03766e 100644 --- a/packages/server/src/automations/steps/executeQuery.js +++ b/packages/server/src/automations/steps/executeQuery.js @@ -1,6 +1,6 @@ const queryController = require("../../api/controllers/query") -module.exports.definition = { +exports.definition = { name: "External Data Connector", tagline: "Execute Data Connector", icon: "ri-database-2-line", @@ -42,7 +42,7 @@ module.exports.definition = { }, } -module.exports.run = async function ({ inputs, appId, emitter }) { +exports.run = async function ({ inputs, appId, emitter }) { if (inputs.query == null) { return { success: false, diff --git a/packages/server/src/automations/steps/executeScript.js b/packages/server/src/automations/steps/executeScript.js index 33ffd3ee8e..6eca4f4244 100644 --- a/packages/server/src/automations/steps/executeScript.js +++ b/packages/server/src/automations/steps/executeScript.js @@ -1,6 +1,6 @@ const scriptController = require("../../api/controllers/script") -module.exports.definition = { +exports.definition = { name: "JS Scripting", tagline: "Execute JavaScript Code", icon: "ri-terminal-box-line", @@ -36,7 +36,7 @@ module.exports.definition = { }, } -module.exports.run = async function ({ inputs, appId, context, emitter }) { +exports.run = async function ({ inputs, appId, context, emitter }) { if (inputs.code == null) { return { success: false, diff --git a/packages/server/src/automations/steps/filter.js b/packages/server/src/automations/steps/filter.js index 586e424cc4..e15722e8d0 100644 --- a/packages/server/src/automations/steps/filter.js +++ b/packages/server/src/automations/steps/filter.js @@ -12,10 +12,10 @@ const PrettyLogicConditions = { [LogicConditions.LESS_THAN]: "Less than", } -module.exports.LogicConditions = LogicConditions -module.exports.PrettyLogicConditions = PrettyLogicConditions +exports.LogicConditions = LogicConditions +exports.PrettyLogicConditions = PrettyLogicConditions -module.exports.definition = { +exports.definition = { name: "Filter", tagline: "{{inputs.field}} {{inputs.condition}} {{inputs.value}}", icon: "ri-git-branch-line", @@ -57,7 +57,7 @@ module.exports.definition = { }, } -module.exports.run = async function filter({ inputs }) { +exports.run = async function filter({ inputs }) { let { field, condition, value } = inputs // coerce types so that we can use them if (!isNaN(value) && !isNaN(field)) { diff --git a/packages/server/src/automations/steps/integromat.js b/packages/server/src/automations/steps/integromat.js index 2f610d6852..ef9d551286 100644 --- a/packages/server/src/automations/steps/integromat.js +++ b/packages/server/src/automations/steps/integromat.js @@ -1,6 +1,6 @@ const fetch = require("node-fetch") -module.exports.definition = { +exports.definition = { name: "Integromat Integration", tagline: "Trigger an Integromat scenario", description: @@ -55,7 +55,7 @@ module.exports.definition = { }, } -module.exports.run = async function ({ inputs }) { +exports.run = async function ({ inputs }) { const { url, value1, value2, value3, value4, value5 } = inputs const response = await fetch(url, { diff --git a/packages/server/src/automations/steps/outgoingWebhook.js b/packages/server/src/automations/steps/outgoingWebhook.js index c1edde7b4e..317f8967f5 100644 --- a/packages/server/src/automations/steps/outgoingWebhook.js +++ b/packages/server/src/automations/steps/outgoingWebhook.js @@ -16,7 +16,7 @@ const BODY_REQUESTS = [RequestType.POST, RequestType.PUT, RequestType.PATCH] * GET/DELETE requests cannot handle body elements so they will not be sent if configured. */ -module.exports.definition = { +exports.definition = { name: "Outgoing webhook", tagline: "Send a {{inputs.requestMethod}} request", icon: "ri-send-plane-line", @@ -70,7 +70,7 @@ module.exports.definition = { }, } -module.exports.run = async function ({ inputs }) { +exports.run = async function ({ inputs }) { let { requestMethod, url, requestBody, headers } = inputs if (!url.startsWith("http")) { url = `http://${url}` diff --git a/packages/server/src/automations/steps/sendSmtpEmail.js b/packages/server/src/automations/steps/sendSmtpEmail.js index 764972b402..8b8d9b6db9 100644 --- a/packages/server/src/automations/steps/sendSmtpEmail.js +++ b/packages/server/src/automations/steps/sendSmtpEmail.js @@ -1,6 +1,6 @@ const { sendSmtpEmail } = require("../../utilities/workerRequests") -module.exports.definition = { +exports.definition = { description: "Send an email using SMTP", tagline: "Send SMTP email to {{inputs.to}}", icon: "ri-mail-open-line", @@ -46,7 +46,7 @@ module.exports.definition = { }, } -module.exports.run = async function ({ inputs }) { +exports.run = async function ({ inputs }) { let { to, from, subject, contents } = inputs if (!contents) { contents = "

No content

" diff --git a/packages/server/src/automations/steps/sendgridEmail.js b/packages/server/src/automations/steps/sendgridEmail.js index 5485116e89..bde5f96e4f 100644 --- a/packages/server/src/automations/steps/sendgridEmail.js +++ b/packages/server/src/automations/steps/sendgridEmail.js @@ -1,4 +1,4 @@ -module.exports.definition = { +exports.definition = { description: "Send an email using SendGrid", tagline: "Send email to {{inputs.to}}", icon: "ri-mail-open-line", @@ -48,7 +48,7 @@ module.exports.definition = { }, } -module.exports.run = async function ({ inputs }) { +exports.run = async function ({ inputs }) { const sgMail = require("@sendgrid/mail") sgMail.setApiKey(inputs.apiKey) const msg = { diff --git a/packages/server/src/automations/steps/serverLog.js b/packages/server/src/automations/steps/serverLog.js index 7389b65f54..7183ff89fd 100644 --- a/packages/server/src/automations/steps/serverLog.js +++ b/packages/server/src/automations/steps/serverLog.js @@ -4,7 +4,7 @@ * GET/DELETE requests cannot handle body elements so they will not be sent if configured. */ -module.exports.definition = { +exports.definition = { name: "Backend log", tagline: "Console log a value in the backend", icon: "ri-server-line", @@ -36,6 +36,6 @@ module.exports.definition = { }, } -module.exports.run = async function ({ inputs, appId }) { +exports.run = async function ({ inputs, appId }) { console.log(`App ${appId} - ${inputs.text}`) } diff --git a/packages/server/src/automations/steps/updateRow.js b/packages/server/src/automations/steps/updateRow.js index 206e429efa..898869959e 100644 --- a/packages/server/src/automations/steps/updateRow.js +++ b/packages/server/src/automations/steps/updateRow.js @@ -1,7 +1,7 @@ const rowController = require("../../api/controllers/row") const automationUtils = require("../automationUtils") -module.exports.definition = { +exports.definition = { name: "Update Row", tagline: "Update a {{inputs.enriched.table.name}} row", icon: "ri-refresh-line", @@ -53,7 +53,7 @@ module.exports.definition = { }, } -module.exports.run = async function ({ inputs, appId, emitter }) { +exports.run = async function ({ inputs, appId, emitter }) { if (inputs.rowId == null || inputs.row == null) { return { success: false, diff --git a/packages/server/src/automations/steps/zapier.js b/packages/server/src/automations/steps/zapier.js index 676286e236..0a7362cede 100644 --- a/packages/server/src/automations/steps/zapier.js +++ b/packages/server/src/automations/steps/zapier.js @@ -1,6 +1,6 @@ const fetch = require("node-fetch") -module.exports.definition = { +exports.definition = { name: "Zapier Webhook", stepId: "zapier", type: "ACTION", @@ -52,7 +52,7 @@ module.exports.definition = { }, } -module.exports.run = async function ({ inputs }) { +exports.run = async function ({ inputs }) { const { url, value1, value2, value3, value4, value5 } = inputs // send the platform to make sure zaps always work, even diff --git a/packages/server/src/automations/tests/utilities/index.js b/packages/server/src/automations/tests/utilities/index.js index ab9de55430..516463091d 100644 --- a/packages/server/src/automations/tests/utilities/index.js +++ b/packages/server/src/automations/tests/utilities/index.js @@ -56,5 +56,5 @@ exports.runStep = async function runStep(stepId, inputs) { exports.apiKey = "test" -exports.actions = actions.BUILTIN_DEFINITIONS -exports.logic = logic.BUILTIN_DEFINITIONS +exports.actions = actions.ACTION_DEFINITIONS +exports.logic = logic.LOGIC_DEFINITIONS diff --git a/packages/server/src/automations/thread.js b/packages/server/src/automations/thread.js index aada0ca0ca..87d3f98d16 100644 --- a/packages/server/src/automations/thread.js +++ b/packages/server/src/automations/thread.js @@ -8,7 +8,7 @@ const CouchDB = require("../db") const { DocumentTypes } = require("../db/utils") const { doInTenant } = require("@budibase/auth/tenancy") -const FILTER_STEP_ID = logic.BUILTIN_DEFINITIONS.FILTER.stepId +const FILTER_STEP_ID = logic.LOGIC_DEFINITIONS.FILTER.stepId /** * The automation orchestrator is a class responsible for executing automations. diff --git a/packages/server/src/automations/triggerInfo/app.js b/packages/server/src/automations/triggerInfo/app.js new file mode 100644 index 0000000000..1c64795cf3 --- /dev/null +++ b/packages/server/src/automations/triggerInfo/app.js @@ -0,0 +1,31 @@ +exports.definition = { + name: "App Action", + event: "app:trigger", + icon: "ri-window-fill", + tagline: "Automation fired from the frontend", + description: "Trigger an automation from an action inside your app", + stepId: "APP", + inputs: {}, + schema: { + inputs: { + properties: { + fields: { + type: "object", + customType: "triggerSchema", + title: "Fields", + }, + }, + required: [], + }, + outputs: { + properties: { + fields: { + type: "object", + description: "Fields submitted from the app frontend", + }, + }, + required: ["fields"], + }, + }, + type: "TRIGGER", +} diff --git a/packages/server/src/automations/triggerInfo/cron.js b/packages/server/src/automations/triggerInfo/cron.js new file mode 100644 index 0000000000..9ef4649b95 --- /dev/null +++ b/packages/server/src/automations/triggerInfo/cron.js @@ -0,0 +1,31 @@ +exports.defintion = { + name: "Cron Trigger", + event: "cron:trigger", + icon: "ri-timer-line", + tagline: "Cron Trigger ({{inputs.cron}})", + description: "Triggers automation on a cron schedule.", + stepId: "CRON", + inputs: {}, + schema: { + inputs: { + properties: { + cron: { + type: "string", + customType: "cron", + title: "Expression", + }, + }, + required: ["cron"], + }, + outputs: { + properties: { + timestamp: { + type: "number", + description: "Timestamp the cron was executed", + }, + }, + required: ["timestamp"], + }, + }, + type: "TRIGGER", +} diff --git a/packages/server/src/automations/triggerInfo/index.js b/packages/server/src/automations/triggerInfo/index.js new file mode 100644 index 0000000000..476d37d54c --- /dev/null +++ b/packages/server/src/automations/triggerInfo/index.js @@ -0,0 +1,15 @@ +const app = require("./app") +const cron = require("./cron") +const rowDeleted = require("./rowDeleted") +const rowSaved = require("./rowSaved") +const rowUpdated = require("./rowUpdated") +const webhook = require("./webhook") + +exports.definitions = { + ROW_SAVED: rowSaved.definition, + ROW_UPDATED: rowUpdated.definition, + ROW_DELETED: rowDeleted.definition, + WEBHOOK: webhook.definition, + APP: app.definition, + CRON: cron.defintion, +} diff --git a/packages/server/src/automations/triggerInfo/rowDeleted.js b/packages/server/src/automations/triggerInfo/rowDeleted.js new file mode 100644 index 0000000000..c7ead1fec4 --- /dev/null +++ b/packages/server/src/automations/triggerInfo/rowDeleted.js @@ -0,0 +1,32 @@ +exports.definition = { + name: "Row Deleted", + event: "row:delete", + icon: "ri-delete-bin-line", + tagline: "Row is deleted from {{inputs.enriched.table.name}}", + description: "Fired when a row is deleted from your database", + stepId: "ROW_DELETED", + inputs: {}, + schema: { + inputs: { + properties: { + tableId: { + type: "string", + customType: "table", + title: "Table", + }, + }, + required: ["tableId"], + }, + outputs: { + properties: { + row: { + type: "object", + customType: "row", + description: "The row that was deleted", + }, + }, + required: ["row"], + }, + }, + type: "TRIGGER", +} diff --git a/packages/server/src/automations/triggerInfo/rowSaved.js b/packages/server/src/automations/triggerInfo/rowSaved.js new file mode 100644 index 0000000000..3a21a26878 --- /dev/null +++ b/packages/server/src/automations/triggerInfo/rowSaved.js @@ -0,0 +1,40 @@ +exports.definition = { + name: "Row Created", + event: "row:save", + icon: "ri-save-line", + tagline: "Row is added to {{inputs.enriched.table.name}}", + description: "Fired when a row is added to your database", + stepId: "ROW_SAVED", + inputs: {}, + schema: { + inputs: { + properties: { + tableId: { + type: "string", + customType: "table", + title: "Table", + }, + }, + required: ["tableId"], + }, + outputs: { + properties: { + row: { + type: "object", + customType: "row", + description: "The new row that was created", + }, + id: { + type: "string", + description: "Row ID - can be used for updating", + }, + revision: { + type: "string", + description: "Revision of row", + }, + }, + required: ["row", "id"], + }, + }, + type: "TRIGGER", +} diff --git a/packages/server/src/automations/triggerInfo/rowUpdated.js b/packages/server/src/automations/triggerInfo/rowUpdated.js new file mode 100644 index 0000000000..099ce0a6b2 --- /dev/null +++ b/packages/server/src/automations/triggerInfo/rowUpdated.js @@ -0,0 +1,40 @@ +exports.definition = { + name: "Row Updated", + event: "row:update", + icon: "ri-refresh-line", + tagline: "Row is updated in {{inputs.enriched.table.name}}", + description: "Fired when a row is updated in your database", + stepId: "ROW_UPDATED", + inputs: {}, + schema: { + inputs: { + properties: { + tableId: { + type: "string", + customType: "table", + title: "Table", + }, + }, + required: ["tableId"], + }, + outputs: { + properties: { + row: { + type: "object", + customType: "row", + description: "The row that was updated", + }, + id: { + type: "string", + description: "Row ID - can be used for updating", + }, + revision: { + type: "string", + description: "Revision of row", + }, + }, + required: ["row", "id"], + }, + }, + type: "TRIGGER", +} diff --git a/packages/server/src/automations/triggerInfo/webhook.js b/packages/server/src/automations/triggerInfo/webhook.js new file mode 100644 index 0000000000..dd83031d8f --- /dev/null +++ b/packages/server/src/automations/triggerInfo/webhook.js @@ -0,0 +1,36 @@ +exports.definition = { + name: "Webhook", + event: "web:trigger", + icon: "ri-global-line", + tagline: "Webhook endpoint is hit", + description: "Trigger an automation when a HTTP POST webhook is hit", + stepId: "WEBHOOK", + inputs: {}, + schema: { + inputs: { + properties: { + schemaUrl: { + type: "string", + customType: "webhookUrl", + title: "Schema URL", + }, + triggerUrl: { + type: "string", + customType: "webhookUrl", + title: "Trigger URL", + }, + }, + required: ["schemaUrl", "triggerUrl"], + }, + outputs: { + properties: { + body: { + type: "object", + description: "Body of the request which hit the webhook", + }, + }, + required: ["body"], + }, + }, + type: "TRIGGER", +} diff --git a/packages/server/src/automations/triggers.js b/packages/server/src/automations/triggers.js index 2a2d68ecb1..3ce09e15fd 100644 --- a/packages/server/src/automations/triggers.js +++ b/packages/server/src/automations/triggers.js @@ -8,232 +8,12 @@ const { getAutomationParams } = require("../db/utils") const { coerce } = require("../utilities/rowProcessor") const { utils } = require("@budibase/auth/redis") const { JobQueues } = require("../constants") -const { - isExternalTable, - breakExternalTableId, -} = require("../integrations/utils") -const { getExternalTable } = require("../api/controllers/table/utils") +const { definitions } = require("./triggerInfo") const { opts } = utils.getRedisOptions() let automationQueue = new Queue(JobQueues.AUTOMATIONS, { redis: opts }) -const FAKE_STRING = "TEST" -const FAKE_BOOL = false -const FAKE_NUMBER = 1 -const FAKE_DATETIME = "1970-01-01T00:00:00.000Z" - -const BUILTIN_DEFINITIONS = { - ROW_SAVED: { - name: "Row Created", - event: "row:save", - icon: "ri-save-line", - tagline: "Row is added to {{inputs.enriched.table.name}}", - description: "Fired when a row is added to your database", - stepId: "ROW_SAVED", - inputs: {}, - schema: { - inputs: { - properties: { - tableId: { - type: "string", - customType: "table", - title: "Table", - }, - }, - required: ["tableId"], - }, - outputs: { - properties: { - row: { - type: "object", - customType: "row", - description: "The new row that was created", - }, - id: { - type: "string", - description: "Row ID - can be used for updating", - }, - revision: { - type: "string", - description: "Revision of row", - }, - }, - required: ["row", "id"], - }, - }, - type: "TRIGGER", - }, - ROW_UPDATED: { - name: "Row Updated", - event: "row:update", - icon: "ri-refresh-line", - tagline: "Row is updated in {{inputs.enriched.table.name}}", - description: "Fired when a row is updated in your database", - stepId: "ROW_UPDATED", - inputs: {}, - schema: { - inputs: { - properties: { - tableId: { - type: "string", - customType: "table", - title: "Table", - }, - }, - required: ["tableId"], - }, - outputs: { - properties: { - row: { - type: "object", - customType: "row", - description: "The row that was updated", - }, - id: { - type: "string", - description: "Row ID - can be used for updating", - }, - revision: { - type: "string", - description: "Revision of row", - }, - }, - required: ["row", "id"], - }, - }, - type: "TRIGGER", - }, - ROW_DELETED: { - name: "Row Deleted", - event: "row:delete", - icon: "ri-delete-bin-line", - tagline: "Row is deleted from {{inputs.enriched.table.name}}", - description: "Fired when a row is deleted from your database", - stepId: "ROW_DELETED", - inputs: {}, - schema: { - inputs: { - properties: { - tableId: { - type: "string", - customType: "table", - title: "Table", - }, - }, - required: ["tableId"], - }, - outputs: { - properties: { - row: { - type: "object", - customType: "row", - description: "The row that was deleted", - }, - }, - required: ["row"], - }, - }, - type: "TRIGGER", - }, - WEBHOOK: { - name: "Webhook", - event: "web:trigger", - icon: "ri-global-line", - tagline: "Webhook endpoint is hit", - description: "Trigger an automation when a HTTP POST webhook is hit", - stepId: "WEBHOOK", - inputs: {}, - schema: { - inputs: { - properties: { - schemaUrl: { - type: "string", - customType: "webhookUrl", - title: "Schema URL", - }, - triggerUrl: { - type: "string", - customType: "webhookUrl", - title: "Trigger URL", - }, - }, - required: ["schemaUrl", "triggerUrl"], - }, - outputs: { - properties: { - body: { - type: "object", - description: "Body of the request which hit the webhook", - }, - }, - required: ["body"], - }, - }, - type: "TRIGGER", - }, - APP: { - name: "App Action", - event: "app:trigger", - icon: "ri-window-fill", - tagline: "Automation fired from the frontend", - description: "Trigger an automation from an action inside your app", - stepId: "APP", - inputs: {}, - schema: { - inputs: { - properties: { - fields: { - type: "object", - customType: "triggerSchema", - title: "Fields", - }, - }, - required: [], - }, - outputs: { - properties: { - fields: { - type: "object", - description: "Fields submitted from the app frontend", - }, - }, - required: ["fields"], - }, - }, - type: "TRIGGER", - }, - CRON: { - name: "Cron Trigger", - event: "cron:trigger", - icon: "ri-timer-line", - tagline: "Cron Trigger ({{inputs.cron}})", - description: "Triggers automation on a cron schedule.", - stepId: "CRON", - inputs: {}, - schema: { - inputs: { - properties: { - cron: { - type: "string", - customType: "cron", - title: "Expression", - }, - }, - required: ["cron"], - }, - outputs: { - properties: { - timestamp: { - type: "number", - description: "Timestamp the cron was executed", - }, - }, - required: ["timestamp"], - }, - }, - type: "TRIGGER", - }, -} +const TRIGGER_DEFINITIONS = definitions async function queueRelevantRowAutomations(event, eventType) { if (event.appId == null) { @@ -262,7 +42,7 @@ async function queueRelevantRowAutomations(event, eventType) { ) { continue } - automationQueue.add({ automation, event }) + await automationQueue.add({ automation, event }) } } @@ -290,51 +70,8 @@ emitter.on("row:delete", async function (event) { await queueRelevantRowAutomations(event, "row:delete") }) -async function fillRowOutput(automation, params) { - let triggerSchema = automation.definition.trigger - let tableId = triggerSchema.inputs.tableId - try { - let table - if (!isExternalTable(tableId)) { - const db = new CouchDB(params.appId) - table = await db.get(tableId) - } else { - const { datasourceId, tableName } = breakExternalTableId(tableId) - table = await getExternalTable(params.appId, datasourceId, tableName) - } - let row = {} - for (let schemaKey of Object.keys(table.schema)) { - const paramValue = params[schemaKey] - let propSchema = table.schema[schemaKey] - switch (propSchema.constraints.type) { - case "string": - row[schemaKey] = paramValue || FAKE_STRING - break - case "boolean": - row[schemaKey] = paramValue || FAKE_BOOL - break - case "number": - row[schemaKey] = paramValue || FAKE_NUMBER - break - case "datetime": - row[schemaKey] = paramValue || FAKE_DATETIME - break - } - } - params.row = row - } catch (err) { - /* istanbul ignore next */ - throw "Failed to find table for trigger" - } - return params -} - -module.exports.externalTrigger = async function (automation, params) { - // TODO: replace this with allowing user in builder to input values in future +exports.externalTrigger = async function (automation, params) { if (automation.definition != null && automation.definition.trigger != null) { - if (automation.definition.trigger.inputs.tableId != null) { - params = await fillRowOutput(automation, params) - } if (automation.definition.trigger.stepId === "APP") { // values are likely to be submitted as strings, so we shall convert to correct type const coercedFields = {} @@ -346,13 +83,12 @@ module.exports.externalTrigger = async function (automation, params) { } } - automationQueue.add({ automation, event: params }) + await automationQueue.add({ automation, event: params }) } -module.exports.getQueues = () => { +exports.getQueues = () => { return [automationQueue] } -module.exports.fillRowOutput = fillRowOutput -module.exports.automationQueue = automationQueue +exports.automationQueue = automationQueue -module.exports.BUILTIN_DEFINITIONS = BUILTIN_DEFINITIONS +exports.TRIGGER_DEFINITIONS = TRIGGER_DEFINITIONS diff --git a/packages/server/src/middleware/usageQuota.js b/packages/server/src/middleware/usageQuota.js index ac8336e769..4647878721 100644 --- a/packages/server/src/middleware/usageQuota.js +++ b/packages/server/src/middleware/usageQuota.js @@ -14,7 +14,7 @@ const DOMAIN_MAP = { views: usageQuota.Properties.VIEW, users: usageQuota.Properties.USER, // this will not be updated by endpoint calls - // instead it will be updated by triggers + // instead it will be updated by triggerInfo automationRuns: usageQuota.Properties.AUTOMATION, }