2022-11-25 20:57:07 +01:00
|
|
|
import * as actions from "../../automations/actions"
|
|
|
|
import * as triggers from "../../automations/triggers"
|
2022-11-22 17:52:25 +01:00
|
|
|
import {
|
2022-06-22 21:23:18 +02:00
|
|
|
getAutomationParams,
|
|
|
|
generateAutomationID,
|
2022-08-11 14:50:05 +02:00
|
|
|
DocumentType,
|
2022-11-22 17:52:25 +01:00
|
|
|
} from "../../db/utils"
|
|
|
|
import {
|
2021-09-10 14:52:41 +02:00
|
|
|
checkForWebhooks,
|
|
|
|
updateTestHistory,
|
2021-12-14 18:59:02 +01:00
|
|
|
removeDeprecated,
|
2022-11-22 17:52:25 +01:00
|
|
|
} from "../../automations/utils"
|
|
|
|
import { deleteEntityMetadata } from "../../utilities"
|
|
|
|
import { MetadataTypes } from "../../constants"
|
|
|
|
import { setTestFlag, clearTestFlag } from "../../utilities/redis"
|
|
|
|
import { context, cache, events } from "@budibase/backend-core"
|
|
|
|
import { automations } from "@budibase/pro"
|
2023-05-09 13:10:20 +02:00
|
|
|
import {
|
|
|
|
Automation,
|
|
|
|
AutomationActionStepId,
|
|
|
|
AutomationResults,
|
|
|
|
BBContext,
|
|
|
|
} from "@budibase/types"
|
2023-04-11 00:48:54 +02:00
|
|
|
import { getActionDefinitions as actionDefs } from "../../automations/actions"
|
2023-05-16 17:05:37 +02:00
|
|
|
import sdk from "../../sdk"
|
2021-05-18 17:37:54 +02:00
|
|
|
|
2023-04-11 00:48:54 +02:00
|
|
|
async function getActionDefinitions() {
|
|
|
|
return removeDeprecated(await actionDefs())
|
|
|
|
}
|
|
|
|
|
|
|
|
function getTriggerDefinitions() {
|
|
|
|
return removeDeprecated(triggers.TRIGGER_DEFINITIONS)
|
|
|
|
}
|
2021-12-14 18:59:02 +01:00
|
|
|
|
2020-09-10 12:06:13 +02:00
|
|
|
/*************************
|
|
|
|
* *
|
|
|
|
* BUILDER FUNCTIONS *
|
|
|
|
* *
|
|
|
|
*************************/
|
2020-05-20 18:02:46 +02:00
|
|
|
|
2022-11-22 17:52:25 +01:00
|
|
|
async function cleanupAutomationMetadata(automationId: string) {
|
2022-01-28 01:05:39 +01:00
|
|
|
await deleteEntityMetadata(MetadataTypes.AUTOMATION_TEST_INPUT, automationId)
|
2021-09-13 19:03:09 +02:00
|
|
|
await deleteEntityMetadata(
|
|
|
|
MetadataTypes.AUTOMATION_TEST_HISTORY,
|
|
|
|
automationId
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2022-11-22 17:52:25 +01:00
|
|
|
function cleanAutomationInputs(automation: Automation) {
|
2020-09-21 14:49:34 +02:00
|
|
|
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]
|
2021-09-08 20:29:28 +02:00
|
|
|
// live is not a property used anymore
|
|
|
|
if (automation.live != null) {
|
|
|
|
delete automation.live
|
|
|
|
}
|
2020-09-18 15:34:14 +02:00
|
|
|
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
|
|
|
}
|
|
|
|
|
2022-11-22 17:52:25 +01:00
|
|
|
export async function create(ctx: BBContext) {
|
|
|
|
const db = context.getAppDB()
|
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) {
|
2023-02-23 14:55:18 +01:00
|
|
|
await update(ctx)
|
|
|
|
return
|
2021-03-10 12:47:39 +01:00
|
|
|
}
|
|
|
|
|
2023-02-23 14:55:18 +01:00
|
|
|
// Respect existing IDs if recreating a deleted automation
|
|
|
|
if (!automation._id) {
|
|
|
|
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({
|
|
|
|
newAuto: automation,
|
|
|
|
})
|
2020-10-22 18:48:32 +02:00
|
|
|
const response = await db.put(automation)
|
2022-05-30 22:46:08 +02:00
|
|
|
await events.automation.created(automation)
|
2022-04-06 14:54:57 +02:00
|
|
|
for (let step of automation.definition.steps) {
|
2022-05-30 22:46:08 +02:00
|
|
|
await events.automation.stepCreated(automation, step)
|
2022-04-06 14:54:57 +02:00
|
|
|
}
|
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
|
|
|
}
|
|
|
|
|
2022-11-22 17:52:25 +01:00
|
|
|
export function getNewSteps(oldAutomation: Automation, automation: Automation) {
|
2022-04-06 14:54:57 +02:00
|
|
|
const oldStepIds = oldAutomation.definition.steps.map(s => s.id)
|
|
|
|
return automation.definition.steps.filter(s => !oldStepIds.includes(s.id))
|
|
|
|
}
|
|
|
|
|
2022-11-22 17:52:25 +01:00
|
|
|
export function getDeletedSteps(
|
|
|
|
oldAutomation: Automation,
|
|
|
|
automation: Automation
|
|
|
|
) {
|
2022-04-06 14:54:57 +02:00
|
|
|
const stepIds = automation.definition.steps.map(s => s.id)
|
|
|
|
return oldAutomation.definition.steps.filter(s => !stepIds.includes(s.id))
|
|
|
|
}
|
|
|
|
|
2022-11-22 17:52:25 +01:00
|
|
|
export async function handleStepEvents(
|
|
|
|
oldAutomation: Automation,
|
|
|
|
automation: Automation
|
|
|
|
) {
|
2022-04-06 14:54:57 +02:00
|
|
|
// new steps
|
|
|
|
const newSteps = getNewSteps(oldAutomation, automation)
|
|
|
|
for (let step of newSteps) {
|
2022-05-31 22:04:41 +02:00
|
|
|
await events.automation.stepCreated(automation, step)
|
2022-04-06 14:54:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// old steps
|
|
|
|
const deletedSteps = getDeletedSteps(oldAutomation, automation)
|
|
|
|
for (let step of deletedSteps) {
|
2022-05-31 22:04:41 +02:00
|
|
|
await events.automation.stepDeleted(automation, step)
|
2022-04-06 14:54:57 +02:00
|
|
|
}
|
|
|
|
}
|
2022-05-23 23:14:44 +02:00
|
|
|
|
2022-11-22 17:52:25 +01:00
|
|
|
export async function update(ctx: BBContext) {
|
|
|
|
const db = context.getAppDB()
|
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
|
2023-02-23 14:55:18 +01:00
|
|
|
|
|
|
|
// Call through to create if it doesn't exist
|
|
|
|
if (!automation._id || !automation._rev) {
|
|
|
|
await create(ctx)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
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({
|
|
|
|
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
|
|
|
|
2021-09-13 19:03:09 +02:00
|
|
|
const oldAutoTrigger =
|
|
|
|
oldAutomation && oldAutomation.definition.trigger
|
|
|
|
? oldAutomation.definition.trigger
|
2022-04-06 14:54:57 +02:00
|
|
|
: undefined
|
2021-09-13 19:03:09 +02:00
|
|
|
const newAutoTrigger =
|
|
|
|
automation && automation.definition.trigger
|
|
|
|
? automation.definition.trigger
|
|
|
|
: {}
|
|
|
|
// trigger has been updated, remove the test inputs
|
2022-04-06 14:54:57 +02:00
|
|
|
if (oldAutoTrigger && oldAutoTrigger.id !== newAutoTrigger.id) {
|
2022-05-31 22:04:41 +02:00
|
|
|
await events.automation.triggerUpdated(automation)
|
2021-09-13 19:03:09 +02:00
|
|
|
await deleteEntityMetadata(
|
|
|
|
MetadataTypes.AUTOMATION_TEST_INPUT,
|
2022-11-22 17:52:25 +01:00
|
|
|
automation._id!
|
2021-09-13 19:03:09 +02:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2022-05-23 23:14:44 +02:00
|
|
|
await handleStepEvents(oldAutomation, automation)
|
2022-04-06 14:54:57 +02:00
|
|
|
|
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
|
|
|
}
|
|
|
|
|
2022-11-22 17:52:25 +01:00
|
|
|
export async function fetch(ctx: BBContext) {
|
|
|
|
const db = context.getAppDB()
|
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
|
|
|
}
|
|
|
|
|
2022-11-22 17:52:25 +01:00
|
|
|
export async function find(ctx: BBContext) {
|
|
|
|
const db = context.getAppDB()
|
2020-05-20 18:02:46 +02:00
|
|
|
ctx.body = await db.get(ctx.params.id)
|
|
|
|
}
|
|
|
|
|
2022-11-22 17:52:25 +01:00
|
|
|
export async function destroy(ctx: BBContext) {
|
|
|
|
const db = context.getAppDB()
|
2021-09-13 19:03:09 +02:00
|
|
|
const automationId = ctx.params.id
|
|
|
|
const oldAutomation = await db.get(automationId)
|
2021-03-29 18:32:05 +02:00
|
|
|
await checkForWebhooks({
|
2021-05-18 22:03:26 +02:00
|
|
|
oldAuto: oldAutomation,
|
|
|
|
})
|
2021-09-13 19:03:09 +02:00
|
|
|
// delete metadata first
|
2022-01-28 01:05:39 +01:00
|
|
|
await cleanupAutomationMetadata(automationId)
|
2021-09-13 19:03:09 +02:00
|
|
|
ctx.body = await db.remove(automationId, ctx.params.rev)
|
2022-05-31 22:04:41 +02:00
|
|
|
await events.automation.deleted(oldAutomation)
|
2020-09-10 12:06:13 +02:00
|
|
|
}
|
|
|
|
|
2022-11-22 17:52:25 +01:00
|
|
|
export async function logSearch(ctx: BBContext) {
|
2022-07-04 16:44:47 +02:00
|
|
|
ctx.body = await automations.logs.logSearch(ctx.request.body)
|
2022-06-01 17:01:06 +02:00
|
|
|
}
|
|
|
|
|
2022-11-22 17:52:25 +01:00
|
|
|
export async function clearLogError(ctx: BBContext) {
|
2022-06-22 21:23:18 +02:00
|
|
|
const { automationId, appId } = ctx.request.body
|
2022-11-22 17:52:25 +01:00
|
|
|
await context.doInAppContext(appId, async () => {
|
|
|
|
const db = context.getProdAppDB()
|
2022-08-11 14:50:05 +02:00
|
|
|
const metadata = await db.get(DocumentType.APP_METADATA)
|
2022-06-22 21:23:18 +02:00
|
|
|
if (!automationId) {
|
|
|
|
delete metadata.automationErrors
|
|
|
|
} else if (
|
|
|
|
metadata.automationErrors &&
|
|
|
|
metadata.automationErrors[automationId]
|
|
|
|
) {
|
|
|
|
delete metadata.automationErrors[automationId]
|
|
|
|
}
|
|
|
|
await db.put(metadata)
|
2022-11-22 17:52:25 +01:00
|
|
|
await cache.app.invalidateAppMetadata(metadata.appId, metadata)
|
2022-06-22 21:23:18 +02:00
|
|
|
ctx.body = { message: `Error logs cleared.` }
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2022-11-22 17:52:25 +01:00
|
|
|
export async function getActionList(ctx: BBContext) {
|
2023-04-11 00:48:54 +02:00
|
|
|
ctx.body = await getActionDefinitions()
|
2020-05-26 22:34:01 +02:00
|
|
|
}
|
|
|
|
|
2022-11-22 17:52:25 +01:00
|
|
|
export async function getTriggerList(ctx: BBContext) {
|
2023-04-11 00:48:54 +02:00
|
|
|
ctx.body = getTriggerDefinitions()
|
2020-09-10 12:06:13 +02:00
|
|
|
}
|
|
|
|
|
2022-11-22 17:52:25 +01:00
|
|
|
export async function getDefinitionList(ctx: BBContext) {
|
2020-09-14 16:34:09 +02:00
|
|
|
ctx.body = {
|
2023-04-11 00:48:54 +02:00
|
|
|
trigger: getTriggerDefinitions(),
|
|
|
|
action: await getActionDefinitions(),
|
2020-09-14 16:34:09 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-10 12:06:13 +02:00
|
|
|
/*********************
|
|
|
|
* *
|
|
|
|
* API FUNCTIONS *
|
|
|
|
* *
|
|
|
|
*********************/
|
|
|
|
|
2022-11-22 17:52:25 +01:00
|
|
|
export async function trigger(ctx: BBContext) {
|
|
|
|
const db = context.getAppDB()
|
2020-09-21 14:49:34 +02:00
|
|
|
let automation = await db.get(ctx.params.id)
|
2021-09-07 14:58:53 +02:00
|
|
|
|
2023-05-16 10:29:40 +02:00
|
|
|
let hasCollectStep = sdk.automations.utils.checkForCollectStep(automation)
|
|
|
|
|
|
|
|
if (hasCollectStep) {
|
2023-05-12 16:56:24 +02:00
|
|
|
const response: AutomationResults = await triggers.externalTrigger(
|
|
|
|
automation,
|
|
|
|
{
|
|
|
|
fields: ctx.request.body.fields,
|
2023-05-15 15:48:34 +02:00
|
|
|
timeout: ctx.request.body.timeout * 1000 || 120000,
|
2023-05-12 16:56:24 +02:00
|
|
|
},
|
|
|
|
{ getResponses: true }
|
|
|
|
)
|
2023-05-09 13:10:20 +02:00
|
|
|
|
2023-05-12 16:56:24 +02:00
|
|
|
let collectedValue = response.steps.find(
|
|
|
|
step => step.stepId === AutomationActionStepId.COLLECT
|
|
|
|
)
|
|
|
|
ctx.body = collectedValue?.outputs
|
|
|
|
} else {
|
|
|
|
await triggers.externalTrigger(automation, {
|
|
|
|
...ctx.request.body,
|
|
|
|
appId: ctx.appId,
|
|
|
|
})
|
|
|
|
ctx.body = {
|
|
|
|
message: `Automation ${automation._id} has been triggered.`,
|
|
|
|
automation,
|
|
|
|
}
|
|
|
|
}
|
2023-05-09 13:10:20 +02:00
|
|
|
}
|
|
|
|
|
2022-11-22 17:52:25 +01:00
|
|
|
function prepareTestInput(input: any) {
|
2021-09-17 18:18:52 +02:00
|
|
|
// prepare the test parameters
|
|
|
|
if (input.id && input.row) {
|
|
|
|
input.row._id = input.id
|
|
|
|
}
|
|
|
|
if (input.revision && input.row) {
|
|
|
|
input.row._rev = input.revision
|
|
|
|
}
|
|
|
|
return input
|
|
|
|
}
|
|
|
|
|
2022-11-22 17:52:25 +01:00
|
|
|
export async function test(ctx: BBContext) {
|
|
|
|
const db = context.getAppDB()
|
2021-09-07 20:06:20 +02:00
|
|
|
let automation = await db.get(ctx.params.id)
|
2021-09-10 15:37:34 +02:00
|
|
|
await setTestFlag(automation._id)
|
2021-09-17 18:18:52 +02:00
|
|
|
const testInput = prepareTestInput(ctx.request.body)
|
2021-09-08 20:29:28 +02:00
|
|
|
const response = await triggers.externalTrigger(
|
2021-09-07 20:06:20 +02:00
|
|
|
automation,
|
2021-09-08 15:08:22 +02:00
|
|
|
{
|
2021-09-17 18:18:52 +02:00
|
|
|
...testInput,
|
2022-01-28 01:05:39 +01:00
|
|
|
appId: ctx.appId,
|
2021-09-08 15:08:22 +02:00
|
|
|
},
|
|
|
|
{ getResponses: true }
|
|
|
|
)
|
2021-09-08 20:29:28 +02:00
|
|
|
// save a test history run
|
2021-09-10 14:52:41 +02:00
|
|
|
await updateTestHistory(ctx.appId, automation, {
|
|
|
|
...ctx.request.body,
|
2021-09-14 17:54:42 +02:00
|
|
|
occurredAt: new Date().getTime(),
|
2021-09-10 14:52:41 +02:00
|
|
|
})
|
2021-09-10 15:37:34 +02:00
|
|
|
await clearTestFlag(automation._id)
|
2021-09-08 20:29:28 +02:00
|
|
|
ctx.body = response
|
2022-05-31 22:04:41 +02:00
|
|
|
await events.automation.tested(automation)
|
2021-09-07 14:59:58 +02:00
|
|
|
}
|