diff --git a/packages/server/src/automations/automationUtils.js b/packages/server/src/automations/automationUtils.js new file mode 100644 index 0000000000..7b05c1eaf5 --- /dev/null +++ b/packages/server/src/automations/automationUtils.js @@ -0,0 +1,71 @@ +const CouchDB = require("../db") + +module.exports.cleanMustache = string => { + let charToReplace = { + "[": ".", + "]": "", + } + let regex = new RegExp(/{{[^}}]*}}/g) + let matches = string.match(regex) + if (matches == null) { + return string + } + for (let match of matches) { + let baseIdx = string.indexOf(match) + for (let key of Object.keys(charToReplace)) { + let idxChar = match.indexOf(key) + if (idxChar !== -1) { + string = + string.slice(baseIdx, baseIdx + idxChar) + + charToReplace[key] + + string.slice(baseIdx + idxChar + 1) + } + } + } + return string +} + +module.exports.cleanInputValues = (inputs, schema) => { + if (schema == null) { + return inputs + } + for (let inputKey of Object.keys(inputs)) { + let input = inputs[inputKey] + if (typeof input !== "string") { + continue + } + let propSchema = schema.properties[inputKey] + if (!propSchema) { + continue + } + if (propSchema.type === "boolean") { + let lcInput = input.toLowerCase() + if (lcInput === "true") { + inputs[inputKey] = true + } + if (lcInput === "false") { + inputs[inputKey] = false + } + } + if (propSchema.type === "number") { + let floatInput = parseFloat(input) + if (!isNaN(floatInput)) { + inputs[inputKey] = floatInput + } + } + } + return inputs +} + +module.exports.cleanUpRecord = async (instanceId, modelId, record) => { + const db = new CouchDB(instanceId) + const model = await db.get(modelId) + + return module.exports.cleanInputValues(record, { properties: model.schema }) +} + +module.exports.cleanUpRecordById = async (instanceId, recordId, record) => { + const db = new CouchDB(instanceId) + const foundRecord = await db.get(recordId) + return module.exports.cleanUpRecord(instanceId, foundRecord.modelId, record) +} diff --git a/packages/server/src/automations/steps/saveRecord.js b/packages/server/src/automations/steps/saveRecord.js index 7c571e5678..ae99511a7c 100644 --- a/packages/server/src/automations/steps/saveRecord.js +++ b/packages/server/src/automations/steps/saveRecord.js @@ -1,4 +1,5 @@ const recordController = require("../../api/controllers/record") +const automationUtils = require("../automationUtils") module.exports.definition = { name: "Save Record", @@ -60,6 +61,11 @@ module.exports.run = async function({ inputs, instanceId }) { if (inputs.record == null || inputs.record.modelId == null) { return } + inputs.record = await automationUtils.cleanUpRecord( + instanceId, + inputs.record.modelId, + inputs.record + ) // have to clean up the record, remove the model from it const ctx = { params: { diff --git a/packages/server/src/automations/steps/updateRecord.js b/packages/server/src/automations/steps/updateRecord.js index 5afe2b7f5d..c6608f0726 100644 --- a/packages/server/src/automations/steps/updateRecord.js +++ b/packages/server/src/automations/steps/updateRecord.js @@ -1,4 +1,5 @@ const recordController = require("../../api/controllers/record") +const automationUtils = require("../automationUtils") module.exports.definition = { name: "Update Record", @@ -57,6 +58,11 @@ module.exports.run = async function({ inputs, instanceId }) { return } + inputs.record = await automationUtils.cleanUpRecordById( + instanceId, + inputs.recordId, + inputs.record + ) // clear any falsy properties so that they aren't updated for (let propKey of Object.keys(inputs.record)) { if (!inputs.record[propKey] || inputs.record[propKey] === "") { diff --git a/packages/server/src/automations/thread.js b/packages/server/src/automations/thread.js index e4fef62211..fa826afbe9 100644 --- a/packages/server/src/automations/thread.js +++ b/packages/server/src/automations/thread.js @@ -1,69 +1,15 @@ const mustache = require("mustache") const actions = require("./actions") const logic = require("./logic") +const automationUtils = require("./automationUtils") const FILTER_STEP_ID = logic.BUILTIN_DEFINITIONS.FILTER.stepId -function cleanMustache(string) { - let charToReplace = { - "[": ".", - "]": "", - } - let regex = new RegExp(/{{[^}}]*}}/g) - let matches = string.match(regex) - if (matches == null) { - return string - } - for (let match of matches) { - let baseIdx = string.indexOf(match) - for (let key of Object.keys(charToReplace)) { - let idxChar = match.indexOf(key) - if (idxChar !== -1) { - string = - string.slice(baseIdx, baseIdx + idxChar) + - charToReplace[key] + - string.slice(baseIdx + idxChar + 1) - } - } - } - return string -} - -// looks for inputs that need cleanup to the correct type -function cleanInputValue(inputs, schema) { - if (schema == null) { - return inputs - } - for (let inputKey of Object.keys(inputs)) { - let input = inputs[inputKey] - if (typeof input !== "string") { - continue - } - let propSchema = schema.properties[inputKey] - if (propSchema.type === "boolean") { - let lcInput = input.toLowerCase() - if (lcInput === "true") { - inputs[inputKey] = true - } - if (lcInput === "false") { - inputs[inputKey] = false - } - } - if (propSchema.type === "number") { - let floatInput = parseFloat(input) - if (!isNaN(floatInput)) { - inputs[inputKey] = floatInput - } - } - } - return inputs -} - function recurseMustache(inputs, context) { for (let key of Object.keys(inputs)) { let val = inputs[key] if (typeof val === "string") { - val = cleanMustache(inputs[key]) + val = automationUtils.cleanMustache(inputs[key]) inputs[key] = mustache.render(val, context) } // this covers objects and arrays @@ -107,7 +53,10 @@ class Orchestrator { for (let step of automation.definition.steps) { let stepFn = await this.getStepFunctionality(step.type, step.stepId) step.inputs = recurseMustache(step.inputs, this._context) - step.inputs = cleanInputValue(step.inputs, step.schema.inputs) + step.inputs = automationUtils.cleanInputValues( + step.inputs, + step.schema.inputs + ) // instanceId is always passed try { const outputs = await stepFn({