Skip to content

Commit

Permalink
feat(Twilio Node): Add ability to make a voice call using TTS (#3467)
Browse files Browse the repository at this point in the history
* Add ability to make a voice call on Twilio using TTS

* ⚡ Small improvement

Co-authored-by: ricardo <ricardoespinoza105@gmail.com>
  • Loading branch information
simshaun and RicardoE105 authored Jun 14, 2022
1 parent b8e3bcc commit eff97e8
Show file tree
Hide file tree
Showing 3 changed files with 109 additions and 4 deletions.
14 changes: 14 additions & 0 deletions packages/nodes-base/nodes/Twilio/GenericFunctions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,3 +59,17 @@ export async function twilioApiRequest(this: IHookFunctions | IExecuteFunctions,
throw new NodeApiError(this.getNode(), error);
}
}

const XML_CHAR_MAP: { [key: string]: string } = {
'<': '&lt;',
'>': '&gt;',
'&': '&amp;',
'"': '&quot;',
"'": '&apos;'
};

export function escapeXml(str: string) {
return str.replace(/[<>&"']/g, function (ch: string) {
return XML_CHAR_MAP[ch];
});
}
6 changes: 4 additions & 2 deletions packages/nodes-base/nodes/Twilio/Twilio.node.json
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@
]
},
"alias": [
"SMS"
"SMS",
"Phone",
"Voice"
]
}
}
93 changes: 91 additions & 2 deletions packages/nodes-base/nodes/Twilio/Twilio.node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {

import {
twilioApiRequest,
escapeXml,
} from './GenericFunctions';

export class Twilio implements INodeType {
Expand Down Expand Up @@ -44,6 +45,11 @@ export class Twilio implements INodeType {
name: 'SMS',
value: 'sms',
},
{
// eslint-disable-next-line n8n-nodes-base/node-param-resource-with-plural-option
name: 'Call',
value: 'call',
},
],
default: 'sms',
},
Expand All @@ -70,13 +76,34 @@ export class Twilio implements INodeType {
default: 'send',
},

{
displayName: 'Operation',
name: 'operation',
type: 'options',
noDataExpression: true,
displayOptions: {
show: {
resource: [
'call',
],
},
},
options: [
{
name: 'Make',
value: 'make',
},
],
default: 'make',
},


// ----------------------------------
// sms
// sms / call
// ----------------------------------

// ----------------------------------
// sms:send
// sms:send / call:make
// ----------------------------------
{
displayName: 'From',
Expand All @@ -89,9 +116,11 @@ export class Twilio implements INodeType {
show: {
operation: [
'send',
'make',
],
resource: [
'sms',
'call',
],
},
},
Expand All @@ -108,9 +137,11 @@ export class Twilio implements INodeType {
show: {
operation: [
'send',
'make',
],
resource: [
'sms',
'call',
],
},
},
Expand Down Expand Up @@ -151,6 +182,40 @@ export class Twilio implements INodeType {
},
description: 'The message to send',
},
{
displayName: 'Use TwiML',
name: 'twiml',
type: 'boolean',
default: false,
displayOptions: {
show: {
operation: [
'make',
],
resource: [
'call',
],
},
},
description: 'Whether to use the <a href="https://www.twilio.com/docs/voice/twiml">Twilio Markup Language</a> in the message',
},
{
displayName: 'Message',
name: 'message',
type: 'string',
default: '',
required: true,
displayOptions: {
show: {
operation: [
'make',
],
resource: [
'call',
],
},
},
},
{
displayName: 'Options',
name: 'options',
Expand Down Expand Up @@ -218,6 +283,30 @@ export class Twilio implements INodeType {
} else {
throw new NodeOperationError(this.getNode(), `The operation "${operation}" is not known!`);
}
} else if (resource === 'call') {
if (operation === 'make') {
// ----------------------------------
// call:make
// ----------------------------------

requestMethod = 'POST';
endpoint = '/Calls.json';

const message = this.getNodeParameter('message', i) as string;
const useTwiml = this.getNodeParameter('twiml', i) as boolean;
body.From = this.getNodeParameter('from', i) as string;
body.To = this.getNodeParameter('to', i) as string;

if (useTwiml) {
body.Twiml = message;
} else {
body.Twiml = `<Response><Say>${escapeXml(message)}</Say></Response>`;
}

body.StatusCallback = this.getNodeParameter('options.statusCallback', i, '') as string;
} else {
throw new NodeOperationError(this.getNode(), `The operation "${operation}" is not known!`);
}
} else {
throw new NodeOperationError(this.getNode(), `The resource "${resource}" is not known!`);
}
Expand Down

0 comments on commit eff97e8

Please sign in to comment.