2020-09-16 15:00:04 +02:00
|
|
|
const CouchDB = require("../../db")
|
2020-09-21 14:49:34 +02:00
|
|
|
const actions = require("../../automations/actions")
|
|
|
|
const logic = require("../../automations/logic")
|
|
|
|
const triggers = require("../../automations/triggers")
|
2020-10-22 18:48:32 +02:00
|
|
|
const webhooks = require("./webhook")
|
2020-10-01 18:22:08 +02:00
|
|
|
const { getAutomationParams, generateAutomationID } = require("../../db/utils")
|
2020-09-10 12:06:13 +02:00
|
|
|
|
2020-10-22 18:48:32 +02:00
|
|
|
const WH_STEP_ID = triggers.BUILTIN_DEFINITIONS.WEBHOOK.stepId
|
2021-05-18 17:37:54 +02:00
|
|
|
const CRON_STEP_ID = triggers.BUILTIN_DEFINITIONS.CRON.stepId
|
|
|
|
|
2020-09-10 12:06:13 +02:00
|
|
|
/*************************
|
|
|
|
* *
|
|
|
|
* BUILDER FUNCTIONS *
|
|
|
|
* *
|
|
|
|
*************************/
|
2020-05-20 18:02:46 +02:00
|
|
|
|
2020-09-21 14:49:34 +02:00
|
|
|
function cleanAutomationInputs(automation) {
|
|
|
|
if (automation == null) {
|
|
|
|
return automation
|
2020-09-18 15:34:14 +02:00
|
|
|
}
|
2020-09-21 14:49:34 +02:00
|
|
|
let steps = automation.definition.steps
|
|
|
|
let trigger = automation.definition.trigger
|
2020-09-18 15:34:14 +02:00
|
|
|
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]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-09-21 14:49:34 +02:00
|
|
|
return automation
|
2020-09-18 15:34:14 +02:00
|
|
|
}
|
|
|
|
|
2021-05-18 17:37:54 +02: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
|
|
|
|
* @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 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-18 22:03:26 +02:00
|
|
|
const cronTriggerRemoved =
|
|
|
|
isCronTrigger(oldAuto) && !isCronTrigger(newAuto) && oldTrigger.cronJobId
|
|
|
|
const cronTriggerAdded = !isCronTrigger(oldAuto) && isCronTrigger(newAuto)
|
2021-05-18 17:37:54 +02:00
|
|
|
|
2021-05-18 22:03:26 +02:00
|
|
|
if (cronTriggerRemoved) {
|
|
|
|
await triggers.automationQueue.removeRepeatableByKey(oldTrigger.cronJobId)
|
2021-05-18 17:37:54 +02:00
|
|
|
}
|
|
|
|
// need to create cron job
|
2021-05-18 22:03:26 +02:00
|
|
|
else if (cronTriggerAdded) {
|
|
|
|
const job = await triggers.automationQueue.add(
|
|
|
|
{ automation: newAuto, event: { appId } },
|
|
|
|
{ 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-18 17:37:54 +02:00
|
|
|
}
|
|
|
|
return newAuto
|
|
|
|
}
|
|
|
|
|
2020-10-22 18:48:32 +02:00
|
|
|
/**
|
|
|
|
* This function handles checking if any webhooks need to be created or deleted for automations.
|
2021-03-29 18:32:05 +02:00
|
|
|
* @param {string} appId The ID of the app in which we are checking for webhooks
|
2020-10-22 18:48:32 +02:00
|
|
|
* @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).
|
|
|
|
*/
|
2021-04-13 21:25:43 +02:00
|
|
|
async function checkForWebhooks({ appId, oldAuto, newAuto }) {
|
2020-10-23 18:17:53 +02:00
|
|
|
const oldTrigger = oldAuto ? oldAuto.definition.trigger : null
|
|
|
|
const newTrigger = newAuto ? newAuto.definition.trigger : null
|
2020-10-22 18:48:32 +02:00
|
|
|
function isWebhookTrigger(auto) {
|
|
|
|
return (
|
|
|
|
auto &&
|
|
|
|
auto.definition.trigger &&
|
|
|
|
auto.definition.trigger.stepId === WH_STEP_ID
|
|
|
|
)
|
|
|
|
}
|
|
|
|
// need to delete webhook
|
|
|
|
if (
|
|
|
|
isWebhookTrigger(oldAuto) &&
|
|
|
|
!isWebhookTrigger(newAuto) &&
|
2020-10-23 18:17:53 +02:00
|
|
|
oldTrigger.webhookId
|
2020-10-22 18:48:32 +02:00
|
|
|
) {
|
2021-03-29 18:32:05 +02:00
|
|
|
let db = new CouchDB(appId)
|
2020-10-23 18:17:53 +02:00
|
|
|
// need to get the webhook to get the rev
|
|
|
|
const webhook = await db.get(oldTrigger.webhookId)
|
2020-10-22 18:48:32 +02:00
|
|
|
const ctx = {
|
2021-04-13 21:25:43 +02:00
|
|
|
appId,
|
2020-10-23 18:17:53 +02:00
|
|
|
params: { id: webhook._id, rev: webhook._rev },
|
2020-10-22 18:48:32 +02:00
|
|
|
}
|
2020-10-23 18:17:53 +02:00
|
|
|
// might be updating - reset the inputs to remove the URLs
|
|
|
|
if (newTrigger) {
|
|
|
|
delete newTrigger.webhookId
|
|
|
|
newTrigger.inputs = {}
|
2020-10-22 18:48:32 +02:00
|
|
|
}
|
|
|
|
await webhooks.destroy(ctx)
|
|
|
|
}
|
|
|
|
// need to create webhook
|
|
|
|
else if (!isWebhookTrigger(oldAuto) && isWebhookTrigger(newAuto)) {
|
|
|
|
const ctx = {
|
2021-04-13 21:25:43 +02:00
|
|
|
appId,
|
2020-10-22 18:48:32 +02:00
|
|
|
request: {
|
|
|
|
body: new webhooks.Webhook(
|
|
|
|
"Automation webhook",
|
|
|
|
webhooks.WebhookType.AUTOMATION,
|
|
|
|
newAuto._id
|
|
|
|
),
|
|
|
|
},
|
|
|
|
}
|
|
|
|
await webhooks.save(ctx)
|
2020-10-23 18:17:53 +02:00
|
|
|
const id = ctx.body.webhook._id
|
|
|
|
newTrigger.webhookId = id
|
|
|
|
newTrigger.inputs = {
|
2021-03-29 18:32:05 +02:00
|
|
|
schemaUrl: `api/webhooks/schema/${appId}/${id}`,
|
|
|
|
triggerUrl: `api/webhooks/trigger/${appId}/${id}`,
|
2020-10-22 18:48:32 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return newAuto
|
|
|
|
}
|
|
|
|
|
2021-05-03 09:31:09 +02:00
|
|
|
exports.create = async function (ctx) {
|
2021-03-29 18:32:05 +02:00
|
|
|
const db = new CouchDB(ctx.appId)
|
2020-09-21 14:49:34 +02:00
|
|
|
let automation = ctx.request.body
|
2021-03-29 18:32:05 +02:00
|
|
|
automation.appId = ctx.appId
|
2020-05-20 18:02:46 +02:00
|
|
|
|
2021-03-10 12:47:39 +01:00
|
|
|
// call through to update if already exists
|
|
|
|
if (automation._id && automation._rev) {
|
|
|
|
return exports.update(ctx)
|
|
|
|
}
|
|
|
|
|
2020-10-02 13:37:46 +02:00
|
|
|
automation._id = generateAutomationID()
|
2020-05-20 18:02:46 +02:00
|
|
|
|
2020-09-21 14:49:34 +02:00
|
|
|
automation.type = "automation"
|
|
|
|
automation = cleanAutomationInputs(automation)
|
2021-03-29 18:32:05 +02:00
|
|
|
automation = await checkForWebhooks({
|
|
|
|
appId: ctx.appId,
|
|
|
|
newAuto: automation,
|
|
|
|
})
|
2021-05-18 17:37:54 +02:00
|
|
|
automation = await checkForCronTriggers({
|
|
|
|
appId: ctx.appId,
|
|
|
|
newAuto: automation,
|
|
|
|
})
|
2020-10-22 18:48:32 +02:00
|
|
|
const response = await db.put(automation)
|
2020-09-21 14:49:34 +02:00
|
|
|
automation._rev = response.rev
|
2020-05-20 18:02:46 +02:00
|
|
|
|
|
|
|
ctx.status = 200
|
|
|
|
ctx.body = {
|
2020-09-21 14:49:34 +02:00
|
|
|
message: "Automation created successfully",
|
|
|
|
automation: {
|
|
|
|
...automation,
|
2020-05-27 13:51:19 +02:00
|
|
|
...response,
|
2020-05-28 21:20:03 +02:00
|
|
|
},
|
|
|
|
}
|
2020-05-20 18:02:46 +02:00
|
|
|
}
|
|
|
|
|
2021-05-03 09:31:09 +02:00
|
|
|
exports.update = async function (ctx) {
|
2021-03-29 18:32:05 +02:00
|
|
|
const db = new CouchDB(ctx.appId)
|
2020-09-21 14:49:34 +02:00
|
|
|
let automation = ctx.request.body
|
2021-03-29 18:32:05 +02:00
|
|
|
automation.appId = ctx.appId
|
2020-10-22 18:48:32 +02:00
|
|
|
const oldAutomation = await db.get(automation._id)
|
2020-09-21 14:49:34 +02:00
|
|
|
automation = cleanAutomationInputs(automation)
|
2020-10-22 18:48:32 +02:00
|
|
|
automation = await checkForWebhooks({
|
2021-03-29 18:32:05 +02:00
|
|
|
appId: ctx.appId,
|
2020-10-22 18:48:32 +02:00
|
|
|
oldAuto: oldAutomation,
|
|
|
|
newAuto: automation,
|
|
|
|
})
|
2021-05-18 17:37:54 +02:00
|
|
|
automation = await checkForCronTriggers({
|
|
|
|
appId: ctx.appId,
|
|
|
|
oldAuto: oldAutomation,
|
|
|
|
newAuto: automation,
|
|
|
|
})
|
2020-09-21 14:49:34 +02:00
|
|
|
const response = await db.put(automation)
|
|
|
|
automation._rev = response.rev
|
2020-05-22 17:32:23 +02:00
|
|
|
|
|
|
|
ctx.status = 200
|
|
|
|
ctx.body = {
|
2020-09-21 14:49:34 +02:00
|
|
|
message: `Automation ${automation._id} updated successfully.`,
|
|
|
|
automation: {
|
|
|
|
...automation,
|
2020-05-22 17:32:23 +02:00
|
|
|
_rev: response.rev,
|
2020-05-28 21:20:03 +02:00
|
|
|
_id: response.id,
|
2020-05-22 17:32:23 +02:00
|
|
|
},
|
|
|
|
}
|
2020-05-20 18:02:46 +02:00
|
|
|
}
|
|
|
|
|
2021-05-03 09:31:09 +02:00
|
|
|
exports.fetch = async function (ctx) {
|
2021-03-29 18:32:05 +02:00
|
|
|
const db = new CouchDB(ctx.appId)
|
2020-10-01 18:22:08 +02:00
|
|
|
const response = await db.allDocs(
|
|
|
|
getAutomationParams(null, {
|
|
|
|
include_docs: true,
|
|
|
|
})
|
|
|
|
)
|
2021-05-04 12:32:22 +02:00
|
|
|
ctx.body = response.rows.map(row => row.doc)
|
2020-05-20 18:02:46 +02:00
|
|
|
}
|
|
|
|
|
2021-05-03 09:31:09 +02:00
|
|
|
exports.find = async function (ctx) {
|
2021-03-29 18:32:05 +02:00
|
|
|
const db = new CouchDB(ctx.appId)
|
2020-05-20 18:02:46 +02:00
|
|
|
ctx.body = await db.get(ctx.params.id)
|
|
|
|
}
|
|
|
|
|
2021-05-03 09:31:09 +02:00
|
|
|
exports.destroy = async function (ctx) {
|
2021-03-29 18:32:05 +02:00
|
|
|
const db = new CouchDB(ctx.appId)
|
2020-10-22 18:48:32 +02:00
|
|
|
const oldAutomation = await db.get(ctx.params.id)
|
2021-03-29 18:32:05 +02:00
|
|
|
await checkForWebhooks({
|
|
|
|
appId: ctx.appId,
|
2021-05-18 22:03:26 +02:00
|
|
|
oldAuto: oldAutomation,
|
|
|
|
})
|
|
|
|
await checkForCronTriggers({
|
|
|
|
appId: ctx.appId,
|
2021-03-29 18:32:05 +02:00
|
|
|
oldAuto: oldAutomation,
|
|
|
|
})
|
2020-09-10 12:06:13 +02:00
|
|
|
ctx.body = await db.remove(ctx.params.id, ctx.params.rev)
|
|
|
|
}
|
|
|
|
|
2021-05-03 09:31:09 +02:00
|
|
|
exports.getActionList = async function (ctx) {
|
2020-09-18 17:50:52 +02:00
|
|
|
ctx.body = actions.DEFINITIONS
|
2020-05-26 22:34:01 +02:00
|
|
|
}
|
|
|
|
|
2021-05-03 09:31:09 +02:00
|
|
|
exports.getTriggerList = async function (ctx) {
|
2020-09-16 15:00:04 +02:00
|
|
|
ctx.body = triggers.BUILTIN_DEFINITIONS
|
2020-09-10 12:06:13 +02:00
|
|
|
}
|
|
|
|
|
2021-05-03 09:31:09 +02:00
|
|
|
exports.getLogicList = async function (ctx) {
|
2020-09-16 15:00:04 +02:00
|
|
|
ctx.body = logic.BUILTIN_DEFINITIONS
|
2020-09-10 12:06:13 +02:00
|
|
|
}
|
|
|
|
|
2021-05-03 09:31:09 +02:00
|
|
|
module.exports.getDefinitionList = async function (ctx) {
|
2020-09-14 16:34:09 +02:00
|
|
|
ctx.body = {
|
2020-09-16 15:00:04 +02:00
|
|
|
logic: logic.BUILTIN_DEFINITIONS,
|
|
|
|
trigger: triggers.BUILTIN_DEFINITIONS,
|
2020-09-18 17:50:52 +02:00
|
|
|
action: actions.DEFINITIONS,
|
2020-09-14 16:34:09 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-10 12:06:13 +02:00
|
|
|
/*********************
|
|
|
|
* *
|
|
|
|
* API FUNCTIONS *
|
|
|
|
* *
|
|
|
|
*********************/
|
|
|
|
|
2021-05-03 09:31:09 +02:00
|
|
|
exports.trigger = async function (ctx) {
|
2021-03-29 18:32:05 +02:00
|
|
|
const db = new CouchDB(ctx.appId)
|
2020-09-21 14:49:34 +02:00
|
|
|
let automation = await db.get(ctx.params.id)
|
|
|
|
await triggers.externalTrigger(automation, {
|
2020-09-14 10:12:17 +02:00
|
|
|
...ctx.request.body,
|
2021-03-29 18:32:05 +02:00
|
|
|
appId: ctx.appId,
|
2020-09-14 10:12:17 +02:00
|
|
|
})
|
2020-09-14 11:30:35 +02:00
|
|
|
ctx.status = 200
|
|
|
|
ctx.body = {
|
2020-09-21 14:49:34 +02:00
|
|
|
message: `Automation ${automation._id} has been triggered.`,
|
|
|
|
automation,
|
2020-09-14 11:30:35 +02:00
|
|
|
}
|
2020-05-20 18:02:46 +02:00
|
|
|
}
|