feat(signalwire): add add-voice-xml-node and respond-with-voice-xml actions

This commit is contained in:
Ali BARIN
2024-12-13 19:26:22 +00:00
parent 0056940fa2
commit 661a5b24b2
9 changed files with 295 additions and 8 deletions

View File

@@ -0,0 +1,130 @@
import { XMLBuilder } from 'fast-xml-parser';
import defineAction from '../../../../helpers/define-action.js';
export default defineAction({
name: 'Add voice XML node',
key: 'addVoiceXmlNode',
description: 'Add a voice XML node in the XML document',
arguments: [
{
label: 'Node name',
key: 'nodeName',
type: 'string',
required: false,
description: 'The name of the node to be added.',
variables: true,
},
{
label: 'Node value',
key: 'nodeValue',
type: 'string',
required: false,
description: 'The value of the node to be added.',
variables: true,
},
{
label: 'Attributes',
key: 'attributes',
type: 'dynamic',
required: false,
description: 'Add or remove attributes for the node as needed',
value: [
{
key: '',
value: '',
},
],
fields: [
{
label: 'Attribute name',
key: 'key',
type: 'string',
required: false,
variables: true,
},
{
label: 'Attribute value',
key: 'value',
type: 'string',
required: false,
variables: true,
},
],
},
{
label: 'Add children node',
key: 'hasChildrenNodes',
type: 'dropdown',
required: true,
description: 'Add a nested node to the main node',
value: false,
options: [
{ label: 'Yes', value: true },
{ label: 'No', value: false },
],
additionalFields: {
type: 'query',
name: 'getDynamicFields',
arguments: [
{
name: 'key',
value: 'listNodeFields',
},
{
name: 'nodeIndex',
value: 0,
},
{
name: 'parameters.hasChildrenNodes',
value: '{parameters.hasChildrenNodes}',
},
],
},
},
],
async run($) {
const nodeName = $.step.parameters.nodeName;
const nodeValue = $.step.parameters.nodeValue;
const attributes = $.step.parameters.attributes;
const childrenNodes = $.step.parameters.childrenNodes;
const hasChildrenNodes = $.step.parameters.hasChildrenNodes;
const builder = new XMLBuilder({
ignoreAttributes: false,
suppressEmptyNode: true,
preserveOrder: true,
});
const computeAttributes = (attributes) =>
attributes
.filter((attribute) => attribute.key || attribute.value)
.reduce(
(result, attribute) => ({
...result,
[`@_${attribute.key}`]: attribute.value,
}),
{}
);
const computeTextNode = (nodeValue) => ({
'#text': nodeValue,
});
const computedChildrenNodes = hasChildrenNodes
? childrenNodes.map((childNode) => ({
[childNode.nodeName]: [computeTextNode(childNode.nodeValue)],
':@': computeAttributes(childNode.attributes),
}))
: [];
const xmlObject = {
[nodeName]: [computeTextNode(nodeValue), ...computedChildrenNodes],
':@': computeAttributes(attributes),
};
const xmlString = builder.build([xmlObject]);
$.setActionItem({ raw: { stringNode: xmlString } });
},
});

View File

@@ -1,3 +1,5 @@
import sendSms from './send-sms/index.js';
import addVoiceXmlNode from './add-voice-xml-node/index.js';
import respondWithVoiceXml from './respond-with-voice-xml/index.js';
export default [sendSms];
export default [addVoiceXmlNode, respondWithVoiceXml, sendSms];

View File

@@ -0,0 +1,65 @@
import { XMLParser, XMLBuilder } from 'fast-xml-parser';
import defineAction from '../../../../helpers/define-action.js';
export default defineAction({
name: 'Respond with voice XML',
key: 'respondWithVoiceXml',
description: 'Respond with defined voice XML document',
arguments: [
{
label: 'Nodes',
key: 'nodes',
type: 'dynamic',
required: false,
description: 'Add or remove nodes for the XML document as needed',
value: [
{
nodeString: '',
},
],
fields: [
{
label: 'Node',
key: 'nodeString',
type: 'string',
required: true,
variables: true,
},
],
},
],
async run($) {
const builder = new XMLBuilder({
ignoreAttributes: false,
suppressEmptyNode: true,
preserveOrder: true,
});
const parser = new XMLParser({
ignoreAttributes: false,
preserveOrder: true,
parseTagValue: false,
});
const nodes = $.step.parameters.nodes;
const computedNodes = nodes.map((node) => node.nodeString);
const parsedNodes = computedNodes.flatMap((computedNode) =>
parser.parse(computedNode)
);
const xmlString = builder.build([
{
Response: parsedNodes,
},
]);
$.setActionItem({
raw: {
body: xmlString,
statusCode: 200,
headers: { 'content-type': 'text/xml' },
},
});
},
});

View File

@@ -0,0 +1,3 @@
import listNodeFields from './list-node-fields/index.js';
export default [listNodeFields];

View File

@@ -0,0 +1,75 @@
export default {
name: 'List node fields',
key: 'listNodeFields',
async run($) {
const hasChildrenNodes = $.step.parameters.hasChildrenNodes;
if (!hasChildrenNodes) {
return [];
}
return [
{
label: 'Children nodes',
key: 'childrenNodes',
type: 'dynamic',
required: false,
description: 'Add or remove nested node as needed',
value: [
{
key: 'Content-Type',
value: 'application/json',
},
],
fields: [
{
label: 'Node name',
key: 'nodeName',
type: 'string',
required: false,
description: 'The name of the node to be added.',
variables: true,
},
{
label: 'Node value',
key: 'nodeValue',
type: 'string',
required: false,
description: 'The value of the node to be added.',
variables: true,
},
{
label: 'Attributes',
key: 'attributes',
type: 'dynamic',
required: false,
description: 'Add or remove attributes for the node as needed',
value: [
{
key: '',
value: '',
},
],
fields: [
{
label: 'Attribute name',
key: 'key',
type: 'string',
required: false,
variables: true,
},
{
label: 'Attribute value',
key: 'value',
type: 'string',
required: false,
variables: true,
},
],
},
],
},
];
},
};

View File

@@ -4,6 +4,7 @@ import auth from './auth/index.js';
import triggers from './triggers/index.js';
import actions from './actions/index.js';
import dynamicData from './dynamic-data/index.js';
import dynamicFields from './dynamic-fields/index.js';
export default defineApp({
name: 'SignalWire',
@@ -19,4 +20,5 @@ export default defineApp({
triggers,
actions,
dynamicData,
dynamicFields,
});