diff --git a/packages/nodes-base/nodes/Sms77/GenericFunctions.ts b/packages/nodes-base/nodes/Sms77/GenericFunctions.ts index 78dcb81184..000b8f6805 100644 --- a/packages/nodes-base/nodes/Sms77/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Sms77/GenericFunctions.ts @@ -4,57 +4,51 @@ import { } from 'n8n-core'; import { - ICredentialDataDecryptedObject, IDataObject, NodeApiError, NodeOperationError, } from 'n8n-workflow'; +import { + OptionsWithUri, +} from 'request'; + /** - * Make an API request to MSG91 + * Make an API request to Sms77 * * @param {IHookFunctions | IExecuteFunctions} this * @param {string} method - * @param {string} endpoint - * @param {object} form - * @param {object | undefined} qs + * @param {Endpoint} endpoint + * @param {object | undefined} data * @returns {Promise} */ -export async function sms77ApiRequest(this: IHookFunctions | IExecuteFunctions, method: string, endpoint: string, form: IDataObject, qs?: IDataObject): Promise { // tslint:disable-line:no-any +export async function sms77ApiRequest(this: IHookFunctions | IExecuteFunctions, method: string, endpoint: string, body: IDataObject, qs: IDataObject = {}): Promise { // tslint:disable-line:no-any const credentials = await this.getCredentials('sms77Api'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); } - if ('GET' === method) { - qs = setPayload(credentials, qs); - } else { - form = setPayload(credentials, form); - } - const response = await this.helpers.request({ - form, + const options: OptionsWithUri = { + headers: { + SentWith: 'n8n', + 'X-Api-Key': credentials.apiKey, + }, + qs, + uri: `https://gateway.sms77.io/api${endpoint}`, json: true, method, - qs, - uri: `https://gateway.sms77.io/api/${endpoint}`, - }); + }; - if ('100' !== response.success) { + if (Object.keys(body).length) { + options.form = body; + body.json = 1; + } + + const response = await this.helpers.request(options); + + if (response.success !== '100') { throw new NodeApiError(this.getNode(), response, { message: 'Invalid sms77 credentials or API error!' }); } return response; } - - -function setPayload(credentials: ICredentialDataDecryptedObject, o?: IDataObject) { - if (!o) { - o = {}; - } - - o.p = credentials!.apiKey as string; - o.json = 1; - o.sendwith = 'n8n'; - - return o; -} diff --git a/packages/nodes-base/nodes/Sms77/Sms77.node.ts b/packages/nodes-base/nodes/Sms77/Sms77.node.ts index 75909cdc38..e9cf274461 100644 --- a/packages/nodes-base/nodes/Sms77/Sms77.node.ts +++ b/packages/nodes-base/nodes/Sms77/Sms77.node.ts @@ -1,6 +1,18 @@ -import {IExecuteFunctions,} from 'n8n-core'; -import {IDataObject, INodeExecutionData, INodeType, INodeTypeDescription, NodeOperationError,} from 'n8n-workflow'; -import {sms77ApiRequest} from './GenericFunctions'; +import { + IExecuteFunctions, +} from 'n8n-core'; + +import { + IDataObject, + INodeExecutionData, + INodeType, + INodeTypeDescription, + NodeOperationError, +} from 'n8n-workflow'; + +import { + sms77ApiRequest, +} from './GenericFunctions'; export class Sms77 implements INodeType { description: INodeTypeDescription = { @@ -10,10 +22,10 @@ export class Sms77 implements INodeType { group: ['transform'], version: 1, subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}', - description: 'Send SMS', + description: 'Send SMS and make text-to-speech calls', defaults: { name: 'Sms77', - color: '#18D46A', + color: '#00d46a', }, inputs: ['main'], outputs: ['main'], @@ -33,10 +45,16 @@ export class Sms77 implements INodeType { name: 'SMS', value: 'sms', }, + { + name: 'Voice Call', + value: 'voice', + }, ], default: 'sms', description: 'The resource to operate on.', }, + + // operations { displayName: 'Operation', name: 'operation', @@ -56,7 +74,28 @@ export class Sms77 implements INodeType { }, ], default: 'send', - description: 'The operation to perform.', + description: 'The operation to perform', + }, + { + displayName: 'Operation', + name: 'operation', + type: 'options', + displayOptions: { + show: { + resource: [ + 'voice', + ], + }, + }, + options: [ + { + name: 'Send', + value: 'send', + description: 'Converts text to voice and calls a given number', + }, + ], + default: 'send', + description: 'The operation to perform', }, { displayName: 'From', @@ -75,14 +114,14 @@ export class Sms77 implements INodeType { ], }, }, - description: 'The number from which to send the message.', + description: 'The caller ID displayed in the receivers display. Max 16 numeric or 11 alphanumeric characters', }, { displayName: 'To', name: 'to', type: 'string', default: '', - placeholder: '+49876543210', + placeholder: '+49876543210, MyGroup', required: true, displayOptions: { show: { @@ -91,10 +130,11 @@ export class Sms77 implements INodeType { ], resource: [ 'sms', + 'voice', ], }, }, - description: 'The number, with coutry code, to which to send the message.', + description: 'The number of your recipient(s) separated by comma. Can be regular numbers or contact/groups from Sms77', }, { displayName: 'Message', @@ -102,6 +142,28 @@ export class Sms77 implements INodeType { type: 'string', default: '', required: true, + typeOptions: { + alwaysOpenEditWindow: true, + }, + displayOptions: { + show: { + operation: [ + 'send', + ], + resource: [ + 'sms', + 'voice', + ], + }, + }, + description: 'The message to send. Max. 1520 characters', + }, + { + displayName: 'Options', + name: 'options', + type: 'collection', + placeholder: 'Add Opton', + default: {}, displayOptions: { show: { operation: [ @@ -112,7 +174,110 @@ export class Sms77 implements INodeType { ], }, }, - description: 'The message to send', + options: [ + { + displayName: 'Debug', + name: 'debug', + type: 'boolean', + default: false, + description: 'If enabled, the API returns fake responses like in a sandbox', + }, + { + displayName: 'Delay', + name: 'delay', + type: 'dateTime', + default: '', + description: 'Pick a date for time delayed dispatch', + }, + { + displayName: 'Foreign ID', + name: 'foreign_id', + type: 'string', + default: '', + placeholder: 'MyCustomForeignID', + description: 'Custom foreign ID returned in DLR callbacks', + }, + { + displayName: 'Flash', + name: 'flash', + type: 'boolean', + default: false, + description: 'Send as flash message being displayed directly the receiver\'s display', + }, + { + displayName: 'Label', + name: 'label', + type: 'string', + default: '', + placeholder: 'MyCustomLabel', + description: 'Custom label used to group analytics', + }, + { + displayName: 'No Reload', + name: 'no_reload', + type: 'boolean', + default: false, + description: 'Disable reload lock to allow sending duplicate messages', + }, + { + displayName: 'Performance Tracking', + name: 'performance_tracking', + type: 'boolean', + default: false, + description: 'Enable performance tracking for URLs found in the message text', + }, + { + displayName: 'TTL', + name: 'ttl', + type: 'number', + default: 2880, + typeOptions: { + minValue: 1, + }, + description: 'Custom time to live specifying the validity period of a message in minutes', + }, + ], + }, + { + displayName: 'Options', + name: 'options', + type: 'collection', + placeholder: 'Add Opton', + default: {}, + displayOptions: { + show: { + operation: [ + 'send', + ], + resource: [ + 'voice', + ], + }, + }, + options: [ + { + displayName: 'Debug', + name: 'debug', + type: 'boolean', + default: false, + description: 'If enabled, the API returns fake responses like in a sandbox', + }, + { + displayName: 'From', + name: 'from', + type: 'string', + default: '', + placeholder: '+4901234567890', + description: 'The caller ID. Please use only verified sender IDs, one of your virtual inbound numbers or one of our shared virtual numbers', + }, + { + displayName: 'XML', + name: 'xml', + type: 'boolean', + default: false, + description: 'Enable if text is of XML format', + }, + ], }, ], }; @@ -122,23 +287,54 @@ export class Sms77 implements INodeType { for (let i = 0; i < this.getInputData().length; i++) { const resource = this.getNodeParameter('resource', i); - if ('sms' !== resource) { - throw new NodeOperationError(this.getNode(), `The resource "${resource}" is not known!`); - } - const operation = this.getNodeParameter('operation', i); - if ('send' !== operation) { - throw new NodeOperationError(this.getNode(), `The operation "${operation}" is not known!`); + let responseData; + try { + if (resource === 'sms') { + if (operation === 'send') { + const from = this.getNodeParameter('from', i) as string; + const to = this.getNodeParameter('to', i) as string; + const text = this.getNodeParameter('message', i) as string; + const options = this.getNodeParameter('options', i) as IDataObject; + const body = { + from, + to, + text, + ...options, + }; + responseData = await sms77ApiRequest.call(this, 'POST', '/sms', body); + } + } + + if (resource === 'voice') { + if (operation === 'send') { + const to = this.getNodeParameter('to', i) as string; + const text = this.getNodeParameter('message', i) as string; + const options = this.getNodeParameter('options', i) as IDataObject; + const body = { + to, + text, + ...options, + }; + responseData = await sms77ApiRequest.call(this, 'POST', '/voice', body); + } + } + + if (Array.isArray(responseData)) { + returnData.push.apply(returnData, responseData as IDataObject[]); + } else if (responseData !== undefined) { + returnData.push(responseData as IDataObject); + } + + } catch (error) { + if (this.continueOnFail()) { + returnData.push({ error: error.message }); + continue; + } + throw error; } - - const responseData = await sms77ApiRequest.call(this, 'POST', 'sms', {}, { - from: this.getNodeParameter('from', i), - to: this.getNodeParameter('to', i), - text: this.getNodeParameter('message', i), - }); - - returnData.push(responseData); } + return [this.helpers.returnJsonArray(returnData)]; } }