1
0
Fork 0
mirror of synced 2024-06-27 18:40:42 +12:00
budibase/packages/server/src/api/controllers/automation.js

287 lines
8.1 KiB
JavaScript
Raw Normal View History

const CouchDB = require("../../db")
const actions = require("../../automations/actions")
const logic = require("../../automations/logic")
const triggers = require("../../automations/triggers")
const webhooks = require("./webhook")
const { getAutomationParams, generateAutomationID } = require("../../db/utils")
const WH_STEP_ID = triggers.TRIGGER_DEFINITIONS.WEBHOOK.stepId
const CRON_STEP_ID = triggers.TRIGGER_DEFINITIONS.CRON.stepId
2021-05-19 03:37:54 +12:00
/*************************
* *
* BUILDER FUNCTIONS *
* *
*************************/
2020-05-21 04:02:46 +12:00
function cleanAutomationInputs(automation) {
if (automation == null) {
return automation
}
let steps = automation.definition.steps
let trigger = automation.definition.trigger
let allSteps = [...steps, trigger]
for (let step of allSteps) {
if (step == null) {
continue
}
for (let inputName of Object.keys(step.inputs)) {
if (!step.inputs[inputName] || step.inputs[inputName] === "") {
delete step.inputs[inputName]
}
}
}
return automation
}
2021-05-19 03:37:54 +12:00
/**
* This function handles checking of any cron jobs need to be created or deleted for automations.
* @param {string} appId The ID of the app in which we are checking for webhooks
* @param {object|undefined} oldAuto The old automation object if updating/deleting
* @param {object|undefined} newAuto The new automation object if creating/updating
*/
async function checkForCronTriggers({ appId, oldAuto, newAuto }) {
const oldTrigger = oldAuto ? oldAuto.definition.trigger : null
const newTrigger = newAuto ? newAuto.definition.trigger : null
function isCronTrigger(auto) {
return (
auto &&
auto.definition.trigger &&
auto.definition.trigger.stepId === CRON_STEP_ID
)
}
2021-05-19 21:46:47 +12:00
const isLive = auto => auto && auto.live
2021-05-19 08:03:26 +12:00
const cronTriggerRemoved =
isCronTrigger(oldAuto) && !isCronTrigger(newAuto) && oldTrigger.cronJobId
2021-05-19 21:46:47 +12:00
const cronTriggerDeactivated = !isLive(newAuto) && isLive(oldAuto)
2021-05-19 03:37:54 +12:00
2021-05-19 21:46:47 +12:00
const cronTriggerActivated = isLive(newAuto) && !isLive(oldAuto)
2021-05-19 09:20:41 +12:00
if (cronTriggerRemoved || (cronTriggerDeactivated && oldTrigger.cronJobId)) {
2021-05-19 08:03:26 +12:00
await triggers.automationQueue.removeRepeatableByKey(oldTrigger.cronJobId)
2021-05-19 03:37:54 +12:00
}
// need to create cron job
2021-05-19 09:20:41 +12:00
else if (isCronTrigger(newAuto) && cronTriggerActivated) {
2021-05-19 08:03:26 +12:00
const job = await triggers.automationQueue.add(
2021-05-26 00:39:30 +12:00
{
automation: newAuto,
event: { appId, timestamp: Date.now() },
},
2021-05-19 08:03:26 +12:00
{ repeat: { cron: newTrigger.inputs.cron } }
)
// Assign cron job ID from bull so we can remove it later if the cron trigger is removed
newTrigger.cronJobId = job.id
2021-05-19 03:37:54 +12:00
}
return newAuto
}
/**
* This function handles checking if any webhooks need to be created or deleted for automations.
* @param {string} appId The ID of the app in which we are checking for webhooks
* @param {object|undefined} oldAuto The old automation object if updating/deleting
* @param {object|undefined} newAuto The new automation object if creating/updating
* @returns {Promise<object|undefined>} After this is complete the new automation object may have been updated and should be
* written to DB (this does not write to DB as it would be wasteful to repeat).
*/
async function checkForWebhooks({ appId, oldAuto, newAuto }) {
const oldTrigger = oldAuto ? oldAuto.definition.trigger : null
const newTrigger = newAuto ? newAuto.definition.trigger : null
const triggerChanged =
oldTrigger && newTrigger && oldTrigger.id !== newTrigger.id
function isWebhookTrigger(auto) {
return (
auto &&
auto.definition.trigger &&
auto.definition.trigger.stepId === WH_STEP_ID
)
}
// need to delete webhook
if (
isWebhookTrigger(oldAuto) &&
(!isWebhookTrigger(newAuto) || triggerChanged) &&
oldTrigger.webhookId
) {
try {
let db = new CouchDB(appId)
// need to get the webhook to get the rev
const webhook = await db.get(oldTrigger.webhookId)
const ctx = {
appId,
params: { id: webhook._id, rev: webhook._rev },
}
// might be updating - reset the inputs to remove the URLs
if (newTrigger) {
delete newTrigger.webhookId
newTrigger.inputs = {}
}
await webhooks.destroy(ctx)
} catch (err) {
// don't worry about not being able to delete, if it doesn't exist all good
}
}
// need to create webhook
if (
(!isWebhookTrigger(oldAuto) || triggerChanged) &&
isWebhookTrigger(newAuto)
) {
const ctx = {
appId,
request: {
body: new webhooks.Webhook(
"Automation webhook",
webhooks.WebhookType.AUTOMATION,
newAuto._id
),
},
}
await webhooks.save(ctx)
const id = ctx.body.webhook._id
newTrigger.webhookId = id
newTrigger.inputs = {
schemaUrl: `api/webhooks/schema/${appId}/${id}`,
triggerUrl: `api/webhooks/trigger/${appId}/${id}`,
}
}
return newAuto
}
2021-05-03 19:31:09 +12:00
exports.create = async function (ctx) {
const db = new CouchDB(ctx.appId)
let automation = ctx.request.body
automation.appId = ctx.appId
2020-05-21 04:02:46 +12:00
// call through to update if already exists
if (automation._id && automation._rev) {
return exports.update(ctx)
}
automation._id = generateAutomationID()
2020-05-21 04:02:46 +12:00
automation.type = "automation"
automation = cleanAutomationInputs(automation)
automation = await checkForWebhooks({
appId: ctx.appId,
newAuto: automation,
})
2021-05-19 03:37:54 +12:00
automation = await checkForCronTriggers({
appId: ctx.appId,
newAuto: automation,
})
const response = await db.put(automation)
automation._rev = response.rev
2020-05-21 04:02:46 +12:00
ctx.status = 200
ctx.body = {
message: "Automation created successfully",
automation: {
...automation,
2020-05-27 23:51:19 +12:00
...response,
},
}
2020-05-21 04:02:46 +12:00
}
2021-05-03 19:31:09 +12:00
exports.update = async function (ctx) {
const db = new CouchDB(ctx.appId)
let automation = ctx.request.body
automation.appId = ctx.appId
const oldAutomation = await db.get(automation._id)
automation = cleanAutomationInputs(automation)
automation = await checkForWebhooks({
appId: ctx.appId,
oldAuto: oldAutomation,
newAuto: automation,
})
2021-05-19 03:37:54 +12:00
automation = await checkForCronTriggers({
appId: ctx.appId,
oldAuto: oldAutomation,
newAuto: automation,
})
const response = await db.put(automation)
automation._rev = response.rev
2020-05-23 03:32:23 +12:00
ctx.status = 200
ctx.body = {
message: `Automation ${automation._id} updated successfully.`,
automation: {
...automation,
2020-05-23 03:32:23 +12:00
_rev: response.rev,
_id: response.id,
2020-05-23 03:32:23 +12:00
},
}
2020-05-21 04:02:46 +12:00
}
2021-05-03 19:31:09 +12:00
exports.fetch = async function (ctx) {
const db = new CouchDB(ctx.appId)
const response = await db.allDocs(
getAutomationParams(null, {
include_docs: true,
})
)
2021-05-04 22:32:22 +12:00
ctx.body = response.rows.map(row => row.doc)
2020-05-21 04:02:46 +12:00
}
2021-05-03 19:31:09 +12:00
exports.find = async function (ctx) {
const db = new CouchDB(ctx.appId)
2020-05-21 04:02:46 +12:00
ctx.body = await db.get(ctx.params.id)
}
2021-05-03 19:31:09 +12:00
exports.destroy = async function (ctx) {
const db = new CouchDB(ctx.appId)
const oldAutomation = await db.get(ctx.params.id)
await checkForWebhooks({
appId: ctx.appId,
2021-05-19 08:03:26 +12:00
oldAuto: oldAutomation,
})
await checkForCronTriggers({
appId: ctx.appId,
oldAuto: oldAutomation,
})
ctx.body = await db.remove(ctx.params.id, ctx.params.rev)
}
2021-05-03 19:31:09 +12:00
exports.getActionList = async function (ctx) {
ctx.body = actions.ACTION_DEFINITIONS
2020-05-27 08:34:01 +12:00
}
2021-05-03 19:31:09 +12:00
exports.getTriggerList = async function (ctx) {
ctx.body = triggers.TRIGGER_DEFINITIONS
}
2021-05-03 19:31:09 +12:00
exports.getLogicList = async function (ctx) {
ctx.body = logic.LOGIC_DEFINITIONS
}
2021-05-03 19:31:09 +12:00
module.exports.getDefinitionList = async function (ctx) {
ctx.body = {
logic: logic.LOGIC_DEFINITIONS,
trigger: triggers.TRIGGER_DEFINITIONS,
action: actions.ACTION_DEFINITIONS,
}
}
/*********************
* *
* API FUNCTIONS *
* *
*********************/
2021-05-03 19:31:09 +12:00
exports.trigger = async function (ctx) {
const db = new CouchDB(ctx.appId)
let automation = await db.get(ctx.params.id)
await triggers.externalTrigger(automation, {
...ctx.request.body,
appId: ctx.appId,
})
ctx.status = 200
ctx.body = {
message: `Automation ${automation._id} has been triggered.`,
automation,
}
2020-05-21 04:02:46 +12:00
}
2021-09-08 00:58:53 +12:00
2021-09-08 00:59:58 +12:00
exports.test = async function (ctx) {
ctx.body = {}
}