2022-11-25 20:57:07 +01:00
|
|
|
import emitter from "../events/index"
|
|
|
|
import { getAutomationParams } from "../db/utils"
|
|
|
|
import { coerce } from "../utilities/rowProcessor"
|
|
|
|
import { definitions } from "./triggerInfo"
|
|
|
|
import { isDevAppID } from "../db/utils"
|
2021-09-07 20:06:20 +02:00
|
|
|
// need this to call directly, so we can get a response
|
2022-11-25 20:57:07 +01:00
|
|
|
import { automationQueue } from "./bullboard"
|
|
|
|
import { checkTestFlag } from "../utilities/redis"
|
|
|
|
import * as utils from "./utils"
|
|
|
|
import env from "../environment"
|
|
|
|
import { context, db as dbCore } from "@budibase/backend-core"
|
|
|
|
import { Automation, Row } from "@budibase/types"
|
2021-03-26 15:56:34 +01:00
|
|
|
|
2022-11-25 20:57:07 +01:00
|
|
|
export const TRIGGER_DEFINITIONS = definitions
|
2021-11-16 20:02:55 +01:00
|
|
|
const JOB_OPTS = {
|
|
|
|
removeOnComplete: true,
|
|
|
|
removeOnFail: true,
|
|
|
|
}
|
2020-09-16 15:00:04 +02:00
|
|
|
|
2022-09-07 18:05:17 +02:00
|
|
|
async function getAllAutomations() {
|
2022-11-22 20:49:59 +01:00
|
|
|
const db = context.getAppDB()
|
2022-09-07 18:05:17 +02:00
|
|
|
let automations = await db.allDocs(
|
|
|
|
getAutomationParams(null, { include_docs: true })
|
|
|
|
)
|
|
|
|
return automations.rows.map(row => row.doc)
|
|
|
|
}
|
|
|
|
|
2022-11-25 20:57:07 +01:00
|
|
|
async function queueRelevantRowAutomations(
|
|
|
|
event: { appId: string; row: Row },
|
|
|
|
eventType: string
|
|
|
|
) {
|
2020-10-29 11:28:27 +01:00
|
|
|
if (event.appId == null) {
|
|
|
|
throw `No appId specified for ${eventType} - check event emitters.`
|
2020-09-14 11:30:35 +02:00
|
|
|
}
|
2021-09-10 15:37:34 +02:00
|
|
|
|
2022-11-25 20:57:07 +01:00
|
|
|
await context.doInAppContext(event.appId, async () => {
|
2022-09-07 18:05:17 +02:00
|
|
|
let automations = await getAllAutomations()
|
2020-09-10 16:00:21 +02:00
|
|
|
|
2022-01-28 01:05:39 +01:00
|
|
|
// filter down to the correct event type
|
2022-09-07 18:05:17 +02:00
|
|
|
automations = automations.filter(automation => {
|
|
|
|
const trigger = automation.definition.trigger
|
|
|
|
return trigger && trigger.event === eventType
|
|
|
|
})
|
2020-10-02 13:37:46 +02:00
|
|
|
|
2022-01-28 01:05:39 +01:00
|
|
|
for (let automation of automations) {
|
|
|
|
let automationDef = automation.definition
|
|
|
|
let automationTrigger = automationDef ? automationDef.trigger : {}
|
|
|
|
// don't queue events which are for dev apps, only way to test automations is
|
|
|
|
// running tests on them, in production the test flag will never
|
|
|
|
// be checked due to lazy evaluation (first always false)
|
|
|
|
if (
|
|
|
|
!env.ALLOW_DEV_AUTOMATIONS &&
|
|
|
|
isDevAppID(event.appId) &&
|
|
|
|
!(await checkTestFlag(automation._id))
|
|
|
|
) {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
if (
|
|
|
|
automationTrigger.inputs &&
|
|
|
|
automationTrigger.inputs.tableId === event.row.tableId
|
|
|
|
) {
|
2022-10-13 18:39:26 +02:00
|
|
|
await automationQueue.add({ automation, event }, JOB_OPTS)
|
2022-01-28 01:05:39 +01:00
|
|
|
}
|
2020-09-11 19:47:22 +02:00
|
|
|
}
|
2022-01-28 01:05:39 +01:00
|
|
|
})
|
2020-09-10 16:00:21 +02:00
|
|
|
}
|
|
|
|
|
2021-05-03 09:31:09 +02:00
|
|
|
emitter.on("row:save", async function (event) {
|
2021-03-15 15:11:13 +01:00
|
|
|
/* istanbul ignore next */
|
2020-10-09 20:10:28 +02:00
|
|
|
if (!event || !event.row || !event.row.tableId) {
|
2020-09-18 14:51:56 +02:00
|
|
|
return
|
|
|
|
}
|
2020-10-09 20:10:28 +02:00
|
|
|
await queueRelevantRowAutomations(event, "row:save")
|
2021-02-23 15:07:19 +01:00
|
|
|
})
|
|
|
|
|
2021-05-03 09:31:09 +02:00
|
|
|
emitter.on("row:update", async function (event) {
|
2021-03-15 15:11:13 +01:00
|
|
|
/* istanbul ignore next */
|
2021-02-23 15:07:19 +01:00
|
|
|
if (!event || !event.row || !event.row.tableId) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
await queueRelevantRowAutomations(event, "row:update")
|
2020-09-10 16:00:21 +02:00
|
|
|
})
|
|
|
|
|
2021-05-03 09:31:09 +02:00
|
|
|
emitter.on("row:delete", async function (event) {
|
2021-03-15 15:11:13 +01:00
|
|
|
/* istanbul ignore next */
|
2020-10-09 20:10:28 +02:00
|
|
|
if (!event || !event.row || !event.row.tableId) {
|
2020-09-18 14:51:56 +02:00
|
|
|
return
|
|
|
|
}
|
2020-10-09 20:10:28 +02:00
|
|
|
await queueRelevantRowAutomations(event, "row:delete")
|
2020-09-10 16:00:21 +02:00
|
|
|
})
|
|
|
|
|
2022-11-25 20:57:07 +01:00
|
|
|
export async function externalTrigger(
|
|
|
|
automation: Automation,
|
|
|
|
params: { fields: Record<string, any> },
|
|
|
|
{ getResponses }: { getResponses?: boolean } = {}
|
2021-09-07 20:06:20 +02:00
|
|
|
) {
|
2021-10-11 20:38:43 +02:00
|
|
|
if (
|
|
|
|
automation.definition != null &&
|
|
|
|
automation.definition.trigger != null &&
|
|
|
|
automation.definition.trigger.stepId === definitions.APP.stepId &&
|
2021-10-12 12:00:49 +02:00
|
|
|
automation.definition.trigger.stepId === "APP" &&
|
2022-11-25 20:57:07 +01:00
|
|
|
!(await checkTestFlag(automation._id!))
|
2021-10-11 20:38:43 +02:00
|
|
|
) {
|
|
|
|
// values are likely to be submitted as strings, so we shall convert to correct type
|
2022-11-25 20:57:07 +01:00
|
|
|
const coercedFields: any = {}
|
2021-10-11 20:38:43 +02:00
|
|
|
const fields = automation.definition.trigger.inputs.fields
|
2022-06-13 11:56:50 +02:00
|
|
|
for (let key of Object.keys(fields || {})) {
|
2021-10-11 20:38:43 +02:00
|
|
|
coercedFields[key] = coerce(params.fields[key], fields[key])
|
2021-01-08 18:25:06 +01:00
|
|
|
}
|
2021-10-11 20:38:43 +02:00
|
|
|
params.fields = coercedFields
|
2020-09-17 16:14:08 +02:00
|
|
|
}
|
2021-09-07 20:06:20 +02:00
|
|
|
const data = { automation, event: params }
|
|
|
|
if (getResponses) {
|
2021-09-13 18:43:53 +02:00
|
|
|
return utils.processEvent({ data })
|
2021-09-07 20:06:20 +02:00
|
|
|
} else {
|
2022-10-13 18:39:26 +02:00
|
|
|
return automationQueue.add(data, JOB_OPTS)
|
2021-09-07 20:06:20 +02:00
|
|
|
}
|
2020-09-10 16:00:21 +02:00
|
|
|
}
|
|
|
|
|
2022-11-25 20:57:07 +01:00
|
|
|
export async function rebootTrigger() {
|
2022-09-07 18:05:17 +02:00
|
|
|
// reboot cron option is only available on the main thread at
|
2022-10-25 14:37:26 +02:00
|
|
|
// startup and only usable in self host and single tenant environments
|
|
|
|
if (env.isInThread() || !env.SELF_HOSTED || env.MULTI_TENANCY) {
|
2022-09-07 18:05:17 +02:00
|
|
|
return
|
|
|
|
}
|
|
|
|
// iterate through all production apps, find the reboot crons
|
|
|
|
// and trigger events for them
|
2022-11-25 20:57:07 +01:00
|
|
|
const appIds = (await dbCore.getAllApps({
|
|
|
|
dev: false,
|
|
|
|
idsOnly: true,
|
|
|
|
})) as string[]
|
2022-09-07 18:05:17 +02:00
|
|
|
for (let prodAppId of appIds) {
|
2022-11-22 20:49:59 +01:00
|
|
|
await context.doInAppContext(prodAppId, async () => {
|
2022-09-07 18:05:17 +02:00
|
|
|
let automations = await getAllAutomations()
|
|
|
|
let rebootEvents = []
|
|
|
|
for (let automation of automations) {
|
|
|
|
if (utils.isRebootTrigger(automation)) {
|
|
|
|
const job = {
|
|
|
|
automation,
|
|
|
|
event: {
|
|
|
|
appId: prodAppId,
|
|
|
|
timestamp: Date.now(),
|
|
|
|
},
|
|
|
|
}
|
2022-10-13 18:39:26 +02:00
|
|
|
rebootEvents.push(automationQueue.add(job, JOB_OPTS))
|
2022-09-07 18:05:17 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
await Promise.all(rebootEvents)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|