@apidaze/node-red-contrib-apidaze
Version:
Node-RED module for Apidaze
180 lines (146 loc) • 5.19 kB
JavaScript
module.exports = function (RED) {
'use strict';
const jsonata = require('jsonata');
const callsDb = require('../../helpers/call-store');
const operations = {
contains: (value1, value2) => value1.toString().includes(value2.toString()),
notContains: (value1, value2) =>
!value1.toString().includes(value2.toString()),
equal: (value1, value2) => value1 === value2,
notEqual: (value1, value2) => value1 !== value2,
regex: (value1, value2) => {
const regexMatch = value2
.toString()
.match(new RegExp('^/(.*?)/([gimy]*)$'));
let regex;
if (!regexMatch) {
regex = new RegExp(value2.toString());
} else if (regexMatch.length === 1) {
regex = new RegExp(regexMatch[1]);
} else {
regex = new RegExp(regexMatch[1], regexMatch[2]);
}
return !!value1.toString().match(regex);
},
};
function MessageProcessor(config) {
RED.nodes.createNode(this, config);
this.callUuid = config.callUuid;
this.matches = config.matches;
let allConditionsMatch = true;
this.on('input', async (msg, send, done) => {
const { payload } = msg;
const { hookType, body } = payload;
if (hookType !== 'message') return null;
try {
const calls = await callsDb.fetch(this.callUuid);
if (calls && calls[0]) {
msg.payload.call = calls[0];
}
} catch (err) {
console.error('An error has occured.', payload, err);
}
msg.payload.message = body;
const tempMessage = { ...msg.payload.message };
let hasUpdates = false;
for (const match of this.matches) {
const conditions = match.conditions;
const properties = match.properties;
const allCaseConditionsMatch = conditions.every((condition) => {
const {
property,
propertyValueExp,
operation,
value,
action,
} = condition;
const operationFunc = operations[operation];
const isPropertyMessage = property === 'text';
const isPropertyCustomString = property === 'custom_string';
const data = (() => {
if (isPropertyMessage) {
return tempMessage.text;
} else if (isPropertyCustomString) {
try {
return jsonata(propertyValueExp).evaluate(msg);
} catch (err) {
console.error(
'An error has occured with jsonata.',
payload,
err
);
return '';
}
}
return msg.payload.call[property];
})();
const operationResult = operationFunc(data, value);
if (isPropertyMessage && operationResult) {
if (action === 'removeMessage') {
tempMessage.text = '';
} else if (action === 'removeMatch') {
if (operation === 'equal') {
tempMessage.text = '';
} else if (operation === 'regex') {
tempMessage.text = tempMessage.text.replace(value, '');
} else if (operation === 'contains') {
const regex = new RegExp(value, 'gi');
tempMessage.text = tempMessage.text.replace(regex, '');
}
}
}
return operationResult;
});
if (allCaseConditionsMatch) {
msg.payload.message = tempMessage;
properties.forEach((property) => {
const { key, value } = property;
msg.payload.call.custom[key] = value;
});
if (properties.length) {
hasUpdates = true;
}
} else {
allConditionsMatch = false;
}
}
const destinationNumber = msg.payload.message.destination_number;
const flowContext = this.context().flow;
const addressBook = flowContext.get('addressBook');
const contact = addressBook && (addressBook[destinationNumber] || addressBook.default);
const messageStore = flowContext.get('messageStore');
if (contact) {
const messageEntryKey = `${contact.mobileDestination}-${destinationNumber}`;
const messageEntry = messageStore[messageEntryKey];
const associatedCallUuid = messageEntry && messageEntry.call_uuid;
if (associatedCallUuid) {
const calls = await callsDb.fetch(associatedCallUuid);
if (calls && calls[0]) {
const associatedCall = calls[0];
msg.payload.call = {
...msg.payload.call,
...associatedCall,
};
}
}
}
if (contact) {
msg.payload.call.custom = {
...msg.payload.call.custom,
...contact,
};
hasUpdates = true;
}
if (hasUpdates) {
await callsDb.update(this.callsUuid, msg.payload.call);
}
if (allConditionsMatch) {
send(msg);
} else {
send(null);
}
done();
});
}
RED.nodes.registerType('message-processor', MessageProcessor);
};