diff --git a/CHANGELOG.md b/CHANGELOG.md index 1052162..5c82c33 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,15 @@ # Change Log +## [4.16.0](https://github.com/plivo/plivo-node/releases/tag/v4.16.0)(2021-04-19) +- Added SDK support for Voice MultiPartyCall APIs and XML + +## [4.15.0](https://github.com/plivo/plivo-node/releases/tag/v4.15.0)(2021-04-19) +- Add support for Regulatory Compliance APIs. +- Add "npanxx" and "local_calling_area" support for Search Phone Number. + +## [4.14.3](https://github.com/plivo/plivo-node/releases/tag/v4.14.3)(2021-03-26) +- Fix bug on stopRecording and all voice API flows post Typescript changes. + ## [4.14.2](https://github.com/plivo/plivo-node/releases/tag/v4.14.2)(2021-02-17) - Fix duplicate call issue for make call API. diff --git a/README.md b/README.md index 6e86df8..9befb13 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,9 @@ -# plivo-node -The Node.js SDK makes it simpler to integrate communications into your Node.js applications using the Plivo REST API. Using the SDK, you will be able to make voice calls, send SMS and generate Plivo XML to control your call flows. +# Plivo Node.js library + +[![Version](https://img.shields.io/npm/v/plivo.svg)](https://www.npmjs.org/package/plivo) +[![Build Status](https://api.travis-ci.org/plivo/plivo-node.svg?branch=master)](https://travis-ci.org/github/plivo/plivo-node) + +The Node.js SDK simplifies the integration of communications into your Node.js applications through the Plivo REST API. You will be able to use the SDK to make voice calls, send SMS, and generate Plivo XML to manage your call flows. ## Installation Install the SDK using [npm](https://www.npmjs.com/package/plivo) @@ -15,7 +19,7 @@ For features in beta, use the beta branch: ## Getting started ### Authentication -To make the API requests, you need to create a `Client` and provide it with authentication credentials (which can be found at [https://manage.plivo.com/dashboard/](https://manage.plivo.com/dashboard/)). +To make the API requests, you need to create a `Client` and provide it with authentication credentials (which can be found at [https://console.plivo.com/dashboard/](https://console.plivo.com/dashboard/)). We recommend that you store your credentials in the `PLIVO_AUTH_ID` and the `PLIVO_AUTH_TOKEN` environment variables, so as to avoid the possibility of accidentally committing them to source control. If you do this, you can initialise the client with no arguments and it will automatically fetch them from the environment variables: @@ -27,7 +31,7 @@ Alternatively, you can specifiy the authentication credentials while initializin ```javascript let plivo = require('plivo'); -let client = new plivo.Client('your_auth_id', 'your_auth_token'); +let client = new plivo.Client('', ''); ``` ### The basics @@ -52,13 +56,12 @@ let plivo = require('plivo'); let client = new plivo.Client(); client.messages.create( - 'your_source_number', - 'your_destination_number', + '+14156667778', + '+14156667777', 'Hello, world!' -).then(function(message_created) { - console.log(message_created) +).then(function(response) { + console.log(response) }); - ``` ### Make a call @@ -68,27 +71,23 @@ let plivo = require('plivo'); let client = new plivo.Client(); client.calls.create( - 'your_source_number', - 'your_destination_number', + '+14156667778', + '+14156667777', 'http://answer.url' -).then(function(call_created) { - console.log(call_created) +).then(function(response) { + console.log(response) }); - ``` ### Lookup a number ```javascript let plivo = require('plivo'); -let client = new plivo.Client('AUTH_ID', 'AUTH_TOKEN'); +let client = new plivo.Client('', ''); -client.lookup.get( - "" -).then(function(response) { +client.lookup.get('') +.then(function(response) { console.log(response); -}).catch(function(error) { - console.log(error); }); ``` @@ -114,25 +113,18 @@ This generates the following XML: ### Run a PHLO ```javascript -var plivo = require('../dist/rest/client.js'); +let plivo = require('plivo'); var PhloClient = plivo.PhloClient; - -var authId = 'auth-id'; -var authToken = 'auth-token'; -var phloId = 'PHLO_ID'; var phloClient = phlo = null; -// Run phlo -phloClient = new PhloClient(authId, authToken); -phloClient.phlo(phloId).run().then(function (result) { +phloClient = new PhloClient('', ''); +phloClient.phlo('').run().then(function (result) { console.log('Phlo run result', result); -}).catch(function (err) { -console.error('Phlo run failed', err); }); ``` ### More examples -Refer to the [Plivo API Reference](https://api-reference.plivo.com/latest/node/introduction/overview) for more examples. Also refer to the [guide to setting up dev environment](https://developers.plivo.com/getting-started/setting-up-dev-environment/) on [Plivo Developers Portal](https://developers.plivo.com) to setup an Express server & use it to test out your integration in under 5 minutes. +More examples are available [here](https://github.com/plivo/plivo-examples-node). Also refer to the [guides for configuring the Express server to run various scenarios](https://www.plivo.com/docs/sms/quickstart/node-expressjs/) & use it to test out your integration in under 5 minutes. ## Reporting issues Report any feedback or problems with this version by [opening an issue on Github](https://github.com/plivo/plivo-node/issues). diff --git a/examples/complianceApplications.js b/examples/complianceApplications.js new file mode 100644 index 0000000..9efebe6 --- /dev/null +++ b/examples/complianceApplications.js @@ -0,0 +1,45 @@ +var Plivo = require('../dist/rest/client.js'); +var client = new Plivo.Client(); + +var createParams = { + countryIso2: "US", + numberType: "local", + endUserType: "individual" +}; + +var listParams = { + countryIso2: "US", + numberType: "local", + endUserType: "individual", + limit: 10, + offset: 5 +}; + +var updateParams = { + documentIds: [ "test-1", "test-2"], +}; + +client.complianceApplications.create(createParams) + .then(function(complianceApplication) { + console.log("\n============ created ===========\n", complianceApplication) + return client.complianceApplications.update(complianceApplication.id, updateParams); + }) + .then(function(complianceApplication) { + console.log("\n============ updated ===========\n", complianceApplication) + return client.complianceApplications.get(complianceApplication.id); + }) + .then(function(complianceApplication){ + console.log("\n============ list with id ===========\n", complianceApplication) + return complianceApplications.delete(complianceApplication.id); + }) + .then(function(result){ + console.log("\n============ deleted ===========\n", result) + return client.complianceApplications.list(listParams) + }) + .then(function(complianceApplications){ + console.log("\n============ list all ===========\n", complianceApplications) + }) + .catch(function(response) { + console.log("\n============ Error :: ===========\n", response); + }); + diff --git a/examples/complianceDocumentTypes.js b/examples/complianceDocumentTypes.js new file mode 100644 index 0000000..288eb6d --- /dev/null +++ b/examples/complianceDocumentTypes.js @@ -0,0 +1,21 @@ +var Plivo = require('../dist/rest/client.js'); +var client = new Plivo.Client(); + +var listParams = { + documentName: "Test", + proofRequired: "passport" +}; + +client.complianceDocumentTypes.get("some-fake-id") + .then(function(complianceDocumentType) { + console.log("\n============ Fetch by ID ===========\n", complianceDocumentType) + return client.complianceDocumentTypes.list(listParams); + }) + .then(function(complianceDocumentTypes) { + console.log("\n============ list all ===========\n", complianceDocumentTypes) + }) + .catch(function(response) { + console.log("\n============ Error :: ===========\n", response); + }); + + \ No newline at end of file diff --git a/examples/complianceDocuments.js b/examples/complianceDocuments.js new file mode 100644 index 0000000..fab3008 --- /dev/null +++ b/examples/complianceDocuments.js @@ -0,0 +1,34 @@ +var Plivo = require('../dist/rest/client.js'); +var client = new Plivo.Client(); + +var createParams = { + alias: "testing", + documentTypeId: "testing", + complianceDocumentId: "test", + metaInformation: "test meta", + file: "test path to file" +}; + +var updateDocument = { + alias: "alias update" +}; + +client.complianceDocuments.create(createParams) + .then(function(complianceDocument) { + console.log("\n============ created ===========\n", complianceDocument) + return client.complianceDocuments.update(complianceDocument.id, updateDocument); + }) + .then(function(complianceDocument){ + return complianceDocuments.delete(); + }) + .then(function(result){ + console.log("\n============ deleted ===========\n", result) + return client.complianceDocuments.list() + }) + .then(function(complianceDocuments){ + console.log("\n============ list all ===========\n", complianceDocuments) + }) + .catch(function(response) { + console.log("\n============ Error :: ===========\n", response); + }); + diff --git a/examples/complianceRequirements.js b/examples/complianceRequirements.js new file mode 100644 index 0000000..fb72f3b --- /dev/null +++ b/examples/complianceRequirements.js @@ -0,0 +1,22 @@ +var Plivo = require('../dist/rest/client.js'); +var client = new Plivo.Client(); + +var listParams = { + countryIso2: "US", + numberType: "local", + endUserType: "individual" +}; + +client.complianceRequirements.get("some-fake-id") + .then(function(complianceRequirement) { + console.log("\n============ Fetch by ID ===========\n", complianceRequirement) + return client.complianceRequirements.list(listParams); + }) + .then(function(complianceRequirements) { + console.log("\n============ list all ===========\n", complianceRequirements) + }) + .catch(function(response) { + console.log("\n============ Error :: ===========\n", response); + }); + + \ No newline at end of file diff --git a/examples/endUsers.js b/examples/endUsers.js new file mode 100644 index 0000000..eb9a152 --- /dev/null +++ b/examples/endUsers.js @@ -0,0 +1,37 @@ +var Plivo = require('../dist/rest/client.js'); +var client = new Plivo.Client(); + +var createParams = { + name: "testing name", + lastName: "testing lastname", + endUserType: "business" +}; + +var updateParams = { + endUserType: "individual" +}; + +client.endUsers.create(createParams) + .then(function(endUser) { + console.log("\n============ created ===========\n", endUser) + return client.endUsers.update(endUser.id, updateParams); + }) + .then(function(endUser) { + console.log("\n============ updated ===========\n", endUser) + return client.endUsers.get(endUser.id); + }) + .then(function(endUser){ + console.log("\n============ list with id ===========\n", endUser) + return endUsers.delete(); + }) + .then(function(result){ + console.log("\n============ deleted ===========\n", result) + return client.endUsers.list() + }) + .then(function(endUsers){ + console.log("\n============ list all ===========\n", endUsers) + }) + .catch(function(response) { + console.log("\n============ Error :: ===========\n", response); + }); + diff --git a/lib/base.js b/lib/base.js index 3ed6040..d6ba0d7 100644 --- a/lib/base.js +++ b/lib/base.js @@ -4,6 +4,9 @@ let actionKey = Symbol('api action'); let klassKey = Symbol('constructor'); let idKey = Symbol('id filed'); let clientKey = Symbol('make api call'); +let secondaryActionKey = Symbol('api action'); +let secondaryKlassKey = Symbol('constructor'); +let secondaryIdKey = Symbol('id filed'); export class PlivoGenericResponse { constructor(params, idString) { @@ -123,6 +126,36 @@ export class PlivoResource { } } +export class PlivoSecondaryResource { + constructor(action, klass, idField, secondaryAction, secondaryKlass, secondaryIdField, request) { + this[actionKey] = action; + this[klassKey] = klass; + this[idKey] = idField; + this[clientKey] = request; + this[secondaryActionKey] = secondaryAction; + this[secondaryKlassKey] = secondaryKlass; + this[secondaryIdKey] = secondaryIdField; + } + + executeAction(task = '', secondaryTask = '', method = 'GET', params = {}, action, secondaryAction) { + let client = this[clientKey]; + action = action == null ? this[actionKey] : action; + let idField = this[idKey]; + secondaryAction = secondaryAction == null ? this[secondaryActionKey] : secondaryAction; + let secondaryIdField = this[secondaryIdKey] + + return new Promise((resolve, reject) => { + client(method, action + task + '/' + secondaryAction + secondaryTask + '/', params) + .then(response => { + resolve(new PlivoGenericResponse(response.body, secondaryIdField)); + }) + .catch(error => { + reject(error); + }); + }); + } +} + export class PlivoResourceInterface { constructor(action, klass, idField, request) { this[actionKey] = action; diff --git a/lib/resources/applications.js b/lib/resources/applications.js index d8895dd..8f01b3a 100644 --- a/lib/resources/applications.js +++ b/lib/resources/applications.js @@ -143,6 +143,7 @@ export class Application extends PlivoResource { */ delete(params, id) { let client = this[clientKey]; + params.isVoiceRequest = 'true'; return new Promise((resolve, reject) => { client('DELETE', action + id + '/', params) .then(() => { @@ -205,6 +206,7 @@ export class ApplicationInterface extends PlivoResourceInterface { */ list(params = {}) { let client = this[clientKey]; + params.isVoiceRequest = true; return new Promise((resolve, reject) => { client('GET', action, params) .then(response => { @@ -258,6 +260,7 @@ export class ApplicationInterface extends PlivoResourceInterface { return errors; } params.app_name = appName; + params.isVoiceRequest = 'true'; let client = this[clientKey]; return new Promise((resolve, reject) => { console.log(action, params) @@ -324,4 +327,4 @@ export class ApplicationInterface extends PlivoResourceInterface { id: id }).delete(params, id); } -} \ No newline at end of file +} diff --git a/lib/resources/call.js b/lib/resources/call.js index fc9a324..625c375 100644 --- a/lib/resources/call.js +++ b/lib/resources/call.js @@ -232,7 +232,8 @@ export class Call extends PlivoResource { * @promise {object} return PlivoGenericResponse Object * @fail {Error} return Error */ - record(params) { + record(params= {}) { + params.isVoiceRequest = 'true'; return this.startRecording(params); } @@ -262,7 +263,7 @@ export class Call extends PlivoResource { * @promise {object} return PlivoGenericResponse Object * @fail {Error} return Error */ - stopRecording(params) { + stopRecording(params= {}) { params.isVoiceRequest = 'true'; return super.executeAction(this.id + '/Record/', 'DELETE', params); } @@ -642,7 +643,7 @@ export class CallInterface extends PlivoResourceInterface { * @promise {object} returns PlivoGenericResponse Object * @fail {Error} returns Error */ - record(callUUID, optionalParams) { + record(callUUID, optionalParams = {}) { let errors = validate([{ field: 'call_uuid', value: callUUID, @@ -665,7 +666,7 @@ export class CallInterface extends PlivoResourceInterface { * @promise {object} returns PlivoGenericResponse Object * @fail {Error} returns Error */ - stopRecording(callUUID, optionalParams) { + stopRecording(callUUID, optionalParams= {}) { let errors = validate([{ field: 'call_uuid', value: callUUID, @@ -916,8 +917,7 @@ class LiveCallInterface extends PlivoResourceInterface { if (action !== '' && !id) { reject(new Error(this[idKey] + ' must be set')); } - client('GET', action + (id ? id + '/' : ''), { - status: 'live', + client('GET', action + (id ? id + '/?status=live' : '') , { isVoiceRequest: 'true' }) .then(response => { @@ -936,9 +936,9 @@ class LiveCallInterface extends PlivoResourceInterface { params = {} } params.status = 'live' - params.isVoiceRequest = 'true' + params.isVoiceRequest = 'true'; return new Promise((resolve, reject) => { - client('GET', action, params) + client('GET', action+'?status=live', params) .then(response => { let calls = []; response.body.calls.forEach(callUuid => { @@ -946,7 +946,7 @@ class LiveCallInterface extends PlivoResourceInterface { callUuid: callUuid })); }); - resolve(new ListAllLiveCallResponse(calls[0])); + resolve(calls); }) .catch(error => { reject(error); @@ -994,8 +994,7 @@ class QueuedCallInterface extends PlivoResourceInterface { reject(new Error(this[idKey] + ' must be set')); } - client('GET', action + (id ? id + '/' : ''), { - status: 'queued', + client('GET', action + (id ? id + '/?status=queued' : ''), { isVoiceRequest: 'true' }) .then(response => { @@ -1013,8 +1012,7 @@ class QueuedCallInterface extends PlivoResourceInterface { let client = this[clientKey]; return new Promise((resolve, reject) => { - client('GET', action, { - status: 'queued', + client('GET', action+'?status=queued', { isVoiceRequest: 'true' }) .then(response => { @@ -1024,7 +1022,7 @@ class QueuedCallInterface extends PlivoResourceInterface { callUuid: callUuid })); }); - resolve(new ListAllQueuedCalls(calls[0])); + resolve(calls); }) .catch(error => { reject(error); diff --git a/lib/resources/complianceApplications.js b/lib/resources/complianceApplications.js new file mode 100644 index 0000000..14c16b8 --- /dev/null +++ b/lib/resources/complianceApplications.js @@ -0,0 +1,281 @@ +import { + PlivoResource, + PlivoResourceInterface +} from '../base'; +import { + extend, + validate +} from '../utils/common.js'; + +const clientKey = Symbol(); +const action = 'ComplianceApplication/'; +const idField = 'complianceApplicationId'; + +export class ComplianceApplicationResponse { + constructor(params) { + params = params || {}; + this.apiId = params.apiId; + this.complianceApplicationId = params.complianceApplicationId; + this.alias = params.alias; + this.status = params.status; + this.endUserType = params.endUserType; + this.endUserId = params.endUserId; + this.countryIso2 = params.countryIso2; + this.numberType = params.numberType; + this.complianceRequirementId= params.complianceRequirementId; + this.documents = params.documents; + this.createdAt = params.createdAt; + } +} + +export class CreateComplianceApplicationResponse { + constructor(params) { + params = params || {}; + this.apiId = params.apiId; + this.complianceApplicationId = params.complianceApplicationId; + this.alias = params.alias; + this.status = params.status; + this.endUserType = params.endUserType; + this.endUserId = params.endUserId; + this.countryIso2 = params.countryIso2; + this.numberType = params.numberType; + this.message = params.message; + this.complianceRequirementId= params.complianceRequirementId; + this.documents = params.documents; + this.createdAt = params.createdAt; + } +} + +export class ListComplianceApplicationResponse { + constructor(params) { + params = params || {}; + this.apiId = params.apiId; + this.meta = params.meta; + this.objects = params.objects; + } +} + +export class UpdateComplianceApplicationResponse { + constructor(params) { + params = params || {}; + this.apiId = params.apiId; + this.message = params.message; + } +} + +export class ComplianceApplication extends PlivoResource { + constructor(client, data = {}) { + super(action, ComplianceApplication, idField, client); + if (idField in data) { + this.id = data[idField]; + } + this[clientKey] = client; + extend(this, data); + } + + /** + * update ComplianceApplication + * @method + * @param {string} id - id to update + * @param {object} params + * @param {string} [params.documentIds] - Document IDs + * @promise {object} return {@link ComplianceApplication} object if success + * @fail {Error} return Error + */ + update(params, id) { + let client = this[clientKey]; + let that = this; + return new Promise((resolve, reject) => { + client('POST', action + id + '/', params) + .then(response => { + extend(that, response.body); + extend(that, params); + resolve(new UpdateComplianceApplicationResponse(that)); + }) + .catch(error => { + reject(error); + }); + }); + + } + + /** + * delete an Compliance application + * @method + * @param {string} id - id to delete + * @promise {boolean} return true if success + * @fail {Error} return Error + */ + delete() { + let client = this[clientKey]; + let id = this.id; + + return new Promise((resolve, reject) => { + client('DELETE', action + id + '/') + .then(() => { + resolve(true); + }) + .catch(error => { + reject(error); + }); + }); + } +} + +/** + * Represents a Compliance Application interface + * @constructor + * @param {function} client - make api call + * @param {object} [data] - data of call + */ +export class ComplianceApplicationInterface extends PlivoResourceInterface { + + constructor(client, data = {}) { + super(action, ComplianceApplication, idField, client); + extend(this, data); + this[clientKey] = client; + } + + /** + * get application by given id + * @method + * @param {string} id - id of application + * @promise {object} return {@link EndUser} object + * @fail {Error} return Error + */ + get(id) { + let client = this[clientKey]; + + return new Promise((resolve, reject) => { + if (action !== '' && !id) { + reject(new Error(this[idKey] + ' must be set')); + } + client('GET', action + (id ? id + '/' : '')) + .then(response => { + resolve(new ComplianceApplicationResponse(response.body, client)); + }) + .catch(error => { + reject(error); + }); + }); + } + + /** + * list all applications + * @method + * @param {object} params - params to list endusers + * @param {string} [params.status] - Status of the application + * @param {string} [params.endUserId] - End user ID related to application + * @param {string} [params.numberType] -Number Type related to application + * @param {integer} [params.offset] - No of value items by which results should be offset + * @param {integer} [params.limit] - No of value items by which results should be offset + */ + list(params = {}) { + let client = this[clientKey]; + return new Promise((resolve, reject) => { + client('GET', action, params) + .then(response => { + resolve(new ListComplianceApplicationResponse(response.body, client)); + }) + .catch(error => { + reject(error); + }); + }); + } + + /** + * Create a complaince application + * @method + * @param {object} params + * @param {string} [params.complianceRequirementId] - compliance requirement ID. + * @param {string} [params.endUserId] - End user ID. + * @param {string} [params.alias] - Alias + * @param {string} [params.documentIds] - Document IDs + * @param {string} [params.endUserType] - End user type + * @param {string} [params.countryIso2] - CountryISo2 + * @param {string} [params.numberType] - Number Type + * @fail {Error} return Error + */ + create(params = {}) { + let client = this[clientKey]; + return new Promise((resolve, reject) => { + client('POST', action, params) + .then(response => { + resolve(new CreateComplianceApplicationResponse(response.body, idField)); + }) + .catch(error => { + reject(error); + }); + }) + } + + /** + * update ComplianceApplication + * @method + * @param {string} id - id to update + * @param {object} params + * @param {string} [params.documentIds] - Document IDs + * @promise {object} return {@link ComplianceApplication} object if success + * @fail {Error} return Error + */ + update(id, params) { + let errors = validate([{ + field: 'id', + value: id, + validators: ['isRequired'] + }]); + + if (errors) { + return errors; + } + return new ComplianceApplication(this[clientKey], { + id: id + }).update(params, id); + } + + /** + * delete ComplianceApplication + * @method + * @param {string} id - id to delete + * @promise {boolean} return true if success + * @fail {Error} return Error + */ + delete(id) { + let errors = validate([{ + field: 'id', + value: id, + validators: ['isRequired'] + }]); + + if (errors) { + return errors; + } + return new ComplianceApplication(this[clientKey], { + id: id + }).delete(); + } + + /** + * submit an application by given id + * @method + * @param {string} id - id of application + * @fail {Error} return Error + */ + submit(id) { + let client = this[clientKey]; + + return new Promise((resolve, reject) => { + if (action !== '' && !id) { + reject(new Error(this[idKey] + ' must be set')); + } + + client('POST', action + (id ? id + '/Submit/' : '')) + .then(response => { + resolve(new ComplianceApplicationResponse(response.body, client)); + }) + .catch(error => { + reject(error); + }); + }); + } +} \ No newline at end of file diff --git a/lib/resources/complianceDocumentTypes.js b/lib/resources/complianceDocumentTypes.js new file mode 100644 index 0000000..5324e5c --- /dev/null +++ b/lib/resources/complianceDocumentTypes.js @@ -0,0 +1,110 @@ +import { + PlivoResource, + PlivoResourceInterface +} from '../base'; +import { + extend, + validate +} from '../utils/common.js'; + +const clientKey = Symbol(); +const action = 'ComplianceDocumentType/'; +const idField = 'documentTypeID'; + +export class ComplianceDocumentTypeResponse { + constructor(params) { + params = params || {}; + this.apiId = params.apiId; + this.documentTypeId = params.documentTypeId; + this.documentName = params.documentName; + this.description = params.description; + this.information = params.information; + this.proofRequired = params.proofRequired; + this.createdAt = params.createdAt; + } +} + +export class ListComplianceDocumentTypeResponse { + constructor(params) { + params = params || {}; + this.apiId = params.apiId; + this.meta = params.meta; + this.objects = params.objects; + } +} + +export class ComplianceDocumentType extends PlivoResource { + constructor(client, data = {}) { + super(action, ComplianceDocumentType, idField, client); + if (idField in data) { + this.id = data[idField]; + } + this[clientKey] = client; + extend(this, data); + } +} + +/** + * Represents a Compliance Document Type interface + * @constructor + * @param {function} client - make api call + * @param {object} [data] - data of call + */ +export class ComplianceDocumentTypeInterface extends PlivoResourceInterface { + + constructor(client, data = {}) { + super(action, ComplianceDocumentType, idField, client); + extend(this, data); + this[clientKey] = client; + } + + /** + * get compliance document types by id + * @method + * @param {string} id - id of the compliane document type. + * @promise {object} return {@link ComplianceDocumentType} object + * @fail {Error} return Error + */ + get(id) { + let params = {} + params.isVoiceRequest = 'false' + let client = this[clientKey]; + + return new Promise((resolve, reject) => { + if (action !== '' && !id) { + reject(new Error(this[idKey] + ' must be set')); + } + + client('GET', action + (id ? id + '/' : '')) + .then(response => { + resolve(new ComplianceDocumentTypeResponse(response.body, client)); + }) + .catch(error => { + reject(error); + }); + }); + } + + /** + * list compliance document types + * @method + * @param {object} params - params to list endusers + * @param {string} [params.documentTypeID] - Document Type ID of the document id. + * @param {string} [params.documentName] - Document name of the document if present. + * @param {string} [params.description] - Description of the document type. + * @param {string} [params.information] - Information about the document type. + * @param {string} [params.proofRequired] - Proofs required for the document. + */ + list(params = {}) { + let client = this[clientKey]; + return new Promise((resolve, reject) => { + client('GET', action, params) + .then(response => { + resolve(new ListComplianceDocumentTypeResponse(response.body, client)); + }) + .catch(error => { + reject(error); + }); + }); + } +} \ No newline at end of file diff --git a/lib/resources/complianceDocuments.js b/lib/resources/complianceDocuments.js new file mode 100644 index 0000000..8235554 --- /dev/null +++ b/lib/resources/complianceDocuments.js @@ -0,0 +1,264 @@ +import { + PlivoResource, + PlivoResourceInterface +} from '../base'; +import { + extend, + validate +} from '../utils/common.js'; + +const clientKey = Symbol(); +const action = 'ComplianceDocument/'; +const idField = 'complianceDocumentId'; + +export class ComplianceDocumentResponse { + constructor(params) { + params = params || {}; + this.apiId = params.apiId; + this.documentTypeId = params.documentTypeId; + this.documentId = params.documentId; + this.endUserId = params.endUserId; + this.alias = params.alias; + this.metaInformation = params.metaInformation; + this.fileName = params.fileName, + this.createdAt = params.createdAt; + } +} + +export class CreateComplianceDocumentResponse { + constructor(params) { + params = params || {}; + this.apiId = params.apiId; + this.documentTypeId = params.documentTypeId; + this.documentId = params.documentId; + this.endUserId = params.endUserId; + this.alias = params.alias; + this.message = params.message; + this.metaInformation = params.metaInformation; + this.fileName = params.fileName, + this.createdAt = params.createdAt; + } +} + +export class ListComplianceDocumentsResponse { + constructor(params) { + params = params || {}; + this.apiId = params.apiId; + this.meta = params.meta; + this.objects = params.objects; + } +} + +export class UpdateComplianceDocumentResponse { + constructor(params) { + params = params || {}; + this.apiId = params.apiId; + this.message = params.message; + } +} + +export class ComplianceDocument extends PlivoResource { + constructor(client, data = {}) { + super(action, ComplianceDocument, idField, client); + if (idField in data) { + this.id = data[idField]; + } + this[clientKey] = client; + extend(this, data); + } + + /** + * update Compliance Document + * @method + * @param {string} id - compliance document id of the document. + * @param {object} params - optional params array of updated values + * @promise {object} return {@link ComplianceDocument} object if success + * @fail {Error} return Error + */ + update(params, id) { + let client = this[clientKey]; + let that = this; + return new Promise((resolve, reject) => { + if ((params.file) != 'undefined') { + params.multipart = true; + } + + client('POST', action + id + '/', params) + .then(response => { + extend(that, response.body); + extend(that, params); + resolve(new UpdateComplianceDocumentResponse(that)); + }) + .catch(error => { + reject(error); + }); + }); + + } + + /** + * delete an Compliance Document + * @method + * @param {string} id - id to delete + * @promise {boolean} return true if success + * @fail {Error} return Error + */ + delete() { + let client = this[clientKey]; + let id = this.id; + return new Promise((resolve, reject) => { + client('DELETE', action + id + '/') + .then(() => { + resolve(true); + }) + .catch(error => { + reject(error); + }); + }); + } +} + +/** + * Represents a Compliance Application interface + * @constructor + * @param {function} client - make api call + * @param {object} [data] - data of call + */ +export class ComplianceDocumentInterface extends PlivoResourceInterface { + constructor(client, data = {}) { + super(action, ComplianceDocument, idField, client); + extend(this, data); + this[clientKey] = client; + } + + /** + * get compliance document by given id + * @method + * @param {string} id - id of the document + * @promise {object} return {@link ComplianceDocument} object + * @fail {Error} return Error + */ + get(id) { + let client = this[clientKey]; + return new Promise((resolve, reject) => { + if (action !== '' && !id) { + reject(new Error(this[idKey] + ' must be set')); + } + client('GET', action + (id ? id + '/' : '')) + .then(response => { + let object = new ComplianceDocumentResponse(response.body, client); + Object.keys(object).forEach(key => object[key] === undefined && delete object[key]); + resolve(object); + }) + .catch(error => { + reject(error); + }); + }); + } + + /** + * list all documents + * @method + * @param {object} params - params containing options to list compliance documents by. + */ + list(params = {}) { + let client = this[clientKey]; + return new Promise((resolve, reject) => { + client('GET', action, params) + .then(response => { + resolve(new ListComplianceDocumentsResponse(response.body, idField)); + }) + .catch(error => { + reject(error); + }); + }); + } + + /** + * Create a complaince document + * @method + * @param {object} params + * @param {string} [params.complianceRequirementId] - compliance requirement ID. + * @param {string} [params.endUserId] - End user ID. + * @param {string} [params.alias] - Alias + * @param {string} [params.documentTypeId] - Document Type ID + * @param {string} [params.file] - File array of the files to be uploaded + * @fail {Error} return Error + */ + create(params = {}) { + let client = this[clientKey]; + let errors = validate([ + { field: 'endUserId', value: params.endUserId, validators: ['isRequired', 'isString'] } + ]); + + errors = validate([ + { field: 'documentTypeId', value: params.documentTypeId, validators: ['isRequired', 'isString'] } + ]); + + errors = validate([ + { field: 'alias', value: params.alias, validators: ['isRequired', 'isString'] } + ]); + + if (errors) { + return errors; + } + + return new Promise((resolve, reject) => { + params.multipart = true; + client('POST', action, params) + .then(response => { + let object = new CreateComplianceDocumentResponse(response.body, idField); + Object.keys(object).forEach(key => object[key] === undefined && delete object[key]); + resolve(object); + }) + .catch(error => { + reject(error); + }); + }) + } + + /** + * update Compliance Document + * @method + * @param {string} id - compliance document id of the document. + * @param {object} params - optional params array of updated values + * @promise {object} return {@link ComplianceDocument} object if success + * @fail {Error} return Error + */ + update(id, params) { + let errors = validate([{ + field: 'id', + value: id, + validators: ['isRequired'] + }]); + + if (errors) { + return errors; + } + return new ComplianceDocument(this[clientKey], { + id: id + }).update(params, id); + } + + /** + * delete a Compliance Document + * @method + * @param {string} id - id to delete + * @promise {boolean} return true if success + * @fail {Error} return Error + */ + delete(id) { + let errors = validate([{ + field: 'id', + value: id, + validators: ['isRequired'] + }]); + + if (errors) { + return errors; + } + return new ComplianceDocument(this[clientKey], { + id: id + }).delete(); + } +} diff --git a/lib/resources/complianceRequirements.js b/lib/resources/complianceRequirements.js new file mode 100644 index 0000000..aa6a259 --- /dev/null +++ b/lib/resources/complianceRequirements.js @@ -0,0 +1,100 @@ +import { + PlivoResource, + PlivoResourceInterface +} from '../base'; +import { + extend, + validate +} from '../utils/common.js'; + +const clientKey = Symbol(); +const action = 'ComplianceRequirement/'; +const idField = 'ComplianceRequirementId'; + + +export class ComplianceRequirementResponse { + constructor(params) { + params = params || {}; + this.apiId = params.apiId; + this.complianceRequirementId = params.complianceRequirementId; + this.countryIso2 = params.countryIso2; + this.numberType = params.numberType; + this.endUserType = params.endUserType; + this.acceptableDocumentTypes = params.acceptableDocumentTypes; + } +} + +export class ComplianceRequirement extends PlivoResource { + constructor(client, data = {}) { + super(action, ComplianceRequirement, idField, client); + if (idField in data) { + this.id = data[idField]; + } + this[clientKey] = client; + extend(this, data); + } +} + +/** + * Represents a Compliance Requirement + * @constructor + * @param {function} client - make api call + * @param {object} [data] - data of call + */ +export class ComplianceRequirementInterface extends PlivoResourceInterface { + + constructor(client, data = {}) { + super(action, ComplianceRequirement, idField, client); + extend(this, data); + this[clientKey] = client; + } + + /** + * get compliance requirement by given id + * @method + * @param {string} id - id of the compliance requirement + * @promise {object} return {@link ComplianceRequirement} object + * @fail {Error} return Error + */ + get(id) { + let client = this[clientKey]; + + return new Promise((resolve, reject) => { + if (action !== '' && !id) { + reject(new Error(this[idKey] + ' must be set')); + } + client('GET', action + (id ? id + '/' : '')) + .then(response => { + resolve(new ComplianceRequirementResponse(response.body, client)); + }) + .catch(error => { + reject(error); + }); + }); + } + + /** + * list compliance requirements + * @method + * @param {object} params - params to list endusers + * @param {string} [params.countryIso2] - Document Type ID of the document id. + * @param {string} [params.numberType] - Document name of the document if present. + * @param {string} [params.phoneNumber] - Description of the document type. + * @param {string} [params.endUserType] - Information about the document type. + * A combination of countryIso2, numberType, endUserType OR + * phoneNumber, endUserType can be used to fetch compliance requirements. + */ + list(params = {}) { + let client = this[clientKey]; + + return new Promise((resolve, reject) => { + client('GET', action, params) + .then(response => { + resolve(new ComplianceRequirementResponse(response.body, client)); + }) + .catch(error => { + reject(error); + }); + }); + } +} \ No newline at end of file diff --git a/lib/resources/endUsers.js b/lib/resources/endUsers.js new file mode 100644 index 0000000..0bd77d8 --- /dev/null +++ b/lib/resources/endUsers.js @@ -0,0 +1,254 @@ +import { + PlivoResource, + PlivoResourceInterface +} from '../base'; +import { + extend, + validate +} from '../utils/common.js'; + +const clientKey = Symbol(); +const action = 'EndUser/'; +const idField = 'endUserId'; + +export class EndUsersResponse { + constructor(params) { + params = params || {}; + this.apiId = params.apiId; + this.endUserId = params.endUserId; + this.endUserType = params.endUserType; + this.name = params.name; + this.lastName = params.lastName; + this.createdAt = params.createdAt; + } +} + +export class CreateEndUsersResponse { + constructor(params) { + params = params || {}; + this.apiId = params.apiId; + this.endUserId = params.endUserId; + this.endUserType = params.endUserType; + this.name = params.name; + this.lastName = params.lastName; + this.message = params.message; + this.createdAt = params.createdAt; + } +} + +export class ListEndUsersResponse { + constructor(params) { + params = params || {}; + this.apiId = params.apiId; + this.meta = params.meta; + this.objects = params.objects; + } +} + +export class UpdateEndUsersResponse { + constructor(params) { + params = params || {}; + this.apiId = params.apiId; + this.message = params.message; + } +} + +export class EndUser extends PlivoResource { + constructor(client, data = {}) { + super(action, EndUser, idField, client); + if (idField in data) { + this.id = data[idField]; + } + this[clientKey] = client; + extend(this, data); + } + + /** + * update end user + * @method + * @param {object} params - to update end user + * @param {string} [params.name] - Name of the endUser if present. + * @param {string} [params.last_name] - Last name of the endUser if present. + * @param {string} [params.end_user_type] - Type of the end user. + * @fail {Error} return Error + */ + update(params, id) { + let client = this[clientKey]; + let that = this; + + return new Promise((resolve, reject) => { + client('POST', action + id + '/', params) + .then(response => { + extend(that, response.body); + extend(that, params); + resolve(new UpdateEndUsersResponse(that)); + }) + .catch(error => { + reject(error); + }); + }); + + } + + /** + * delete an EndUser + * @method + * @param {string} id - id to delete + * @promise {boolean} return true if success + * @fail {Error} return Error + */ + delete() { + let client = this[clientKey]; + let id = this.id; + + return new Promise((resolve, reject) => { + client('DELETE', action + id + '/') + .then(() => { + resolve(true); + }) + .catch(error => { + reject(error); + }); + }); + } +} + +/** + * Represents a End Users interface + * @constructor + * @param {function} client - make api call + * @param {object} [data] - data of call + */ +export class EndUserInterface extends PlivoResourceInterface { + + constructor(client, data = {}) { + super(action, EndUser, idField, client); + extend(this, data); + this[clientKey] = client; + } + + /** + * get an enduser by given id + * @method + * @param {string} id - id of the endUser + * @promise {object} return {@link EndUser} object + * @fail {Error} return Error + */ + get(id) { + let errors = validate([ + {field: 'id', value: id, validators: ['isRequired']} + ]); + + if (errors) { + return errors; + } + + let client = this[clientKey]; + + return new Promise((resolve, reject) => { + if (action !== '' && !id) { + reject(new Error(this[idKey] + ' must be set')); + } + client('GET', action + (id ? id + '/' : '')) + .then(response => { + resolve(new EndUsersResponse(response.body, client)); + }) + .catch(error => { + reject(error); + }); + }); + } + + /** + * list EndUsers + * @method + * @param {object} params - params to list endusers + * @param {string} [params.name] - Name of the endUser, if present. + * @param {string} [params.lastName] - Last name of the endUser, if present. + * @param {string} [params.endUserType] - Type of an end user. + * @param {integer} [params.offset] - No of value items by which results should be offset + * @param {integer} [params.limit] - No of value items by which results should be offset + */ + list(params = {}) { + let client = this[clientKey]; + return new Promise((resolve, reject) => { + client('GET', action, params) + .then(response => { + resolve(new ListEndUsersResponse(response.body, client)); + }) + .catch(error => { + reject(error); + }); + }); + } + + /** + * Create end user + * @method + * @param {object} params - to update end user + * @param {string} [params.name] - Name of the endUser if present. + * @param {string} [params.lastName] - Last name of the endUser if present. + * @param {string} [params.endUserType] - Type of the end user. + * @fail {Error} return Error + */ + create(params = {}) { + let client = this[clientKey]; + return new Promise((resolve, reject) => { + client('POST', action, params) + .then(response => { + resolve(new CreateEndUsersResponse(response.body, idField)); + }) + .catch(error => { + reject(error); + }); + }) + } + + /** + * update end user + * @method + * @param {object} params - to update end user + * @param {string} [params.name] - Name of the endUser if present. + * @param {string} [params.lastName] - Last name of the endUser if present. + * @param {string} [params.endUserType] - Type of the end user. + * @fail {Error} return Error + */ + update(id, params) { + let errors = validate([{ + field: 'id', + value: id, + validators: ['isRequired'] + }]); + + if (errors) { + return errors; + } + + return new EndUser(this[clientKey], { + id: id + }).update(params, id); + } + + /** + * delete EndUser + * @method + * @param {string} id - id to delete an enduser with + * @promise {boolean} return true if success + * @fail {Error} return Error + */ + delete(id) { + let errors = validate([{ + field: 'id', + value: id, + validators: ['isRequired'] + }]); + + if (errors) { + return errors; + } + + return new EndUser(this[clientKey], { + id: id + }).delete(); + } +} \ No newline at end of file diff --git a/lib/resources/multiPartyCall.js b/lib/resources/multiPartyCall.js new file mode 100644 index 0000000..0ffe665 --- /dev/null +++ b/lib/resources/multiPartyCall.js @@ -0,0 +1,592 @@ +import {extend, validate} from '../utils/common.js'; +import {PlivoResource, PlivoResourceInterface, PlivoSecondaryResource} from '../base'; +import { + validSubAccount, + validUrl, + validParam, + validDateFormat, + validRange, + validMultipleDestinationNos, + isOneAmongStringUrl, multiValidParam +} from '../rest/utils.js' + +const clientKey = Symbol(); +const action = 'MultiPartyCall/'; +const idField = 'mpcUuid'; +const secondaryAction = 'Participant/'; +const secondaryIdField = 'participantUuid'; + +export class MPCError extends Error { } + +export class MultiPartyCall extends PlivoResource{ + constructor(client, data = {}) { + super(action, MultiPartyCall, idField, client); + + if (idField in data) { + this.id = data[idField]; + } + + extend(this, data); + this[clientKey] = client; + } + + get(params = {}){ + params.isVoiceRequest = 'true'; + return super.executeAction(this.id, 'GET', params); + } + + addParticipant(params){ + if((params.from && params.to) && (params.callUuid)){ + throw new MPCError('cannot specify callUuid when (from, to) is provided') + } + if((!params.from && !params.to) && !params.callUuid){ + throw new MPCError('specify either callUuid or (from, to)') + } + if((!params.callUuid) && (!params.from || !params.to)){ + throw new MPCError('specify (from, to) when not adding an existing callUuid to multi party participant') + } + + validParam('role', params.role.toLowerCase(), [String], true, ['agent', 'supervisor', 'customer']) + + if(params.from){ + validParam('from', params.from, [String], false) + } + + if(params.to){ + validParam('to', params.to, [String], false) + validMultipleDestinationNos('to', params.to, {role: params.role, delimiter: '<', agentLimit: 20}) + } + + if(params.callUuid){ + validParam('callUuid', params.callUuid, [String], false) + } + + if(params.callStatusCallbackUrl){ + validUrl('callStatusCallbackUrl', params.callStatusCallbackUrl, false) + } + + if(params.callStatusCallbackMethod){ + validParam('callStatusCallbackMethod', params.callStatusCallbackMethod.toUpperCase(), [String], false, ['GET', 'POST']) + } + else{ + params.callStatusCallbackMethod = 'POST' + } + + if(params.sipHeaders){ + validParam('sipHeaders', params.sipHeaders, [String], false) + } + + if(params.confirmKey){ + validParam('confirmKey', params.confirmKey, [String], false, ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '#', '*']) + } + + if(params.confirmKeySoundUrl){ + validUrl('confirmKeySoundUrl', params.confirmKeySoundUrl, false) + } + + if(params.confirmKeySoundMethod){ + validParam('confirmKeySoundMethod)', params.confirmKeySoundMethod.toUpperCase(), [String], false, ['GET', 'POST']) + } + else{ + params.confirmKeySoundMethod = 'GET' + } + + if(params.dialMusic){ + isOneAmongStringUrl('dialMusic', params.dialMusic, false, ['real', 'none']) + } + else { + params.dialMusic = 'Real' + } + + if(params.ringTimeout || params.ringTimeout === 0){ + validRange('ringTimeout', params.ringTimeout, false, 15, 120) + } + else { + params.ringTimeout = 45 + } + + if(params.maxDuration || params.maxDuration === 0){ + validRange('maxDuration', params.maxDuration, false, 300, 28800) + } + else { + params.maxDuration = 14400 + } + + if(params.maxParticipants || params.maxParticipants === 0){ + validRange('maxParticipants', params.maxParticipants, false, 2, 10) + } + else { + params.maxParticipants = 10 + } + + if(params.waitMusicUrl){ + validUrl('waitMusicUrl', params.waitMusicUrl, false) + } + + if(params.waitMusicMethod){ + validParam('waitMusicMethod', params.waitMusicMethod.toUpperCase(), [String], false, ['GET', 'POST']) + } + else { + params.waitMusicMethod = 'GET' + } + + if(params.agentHoldMusicUrl){ + validUrl('agentHoldMusicUrl', params.agentHoldMusicUrl, false) + } + + if(params.agentHoldMusicMethod){ + validParam('agentHoldMusicMethod', params.agentHoldMusicMethod.toUpperCase(), [String], false, ['GET', 'POST']) + } + else { + params.agentHoldMusicMethod = 'GET' + } + + if(params.customerHoldMusicUrl){ + validUrl('customerHoldMusicUrl', params.customerHoldMusicUrl, false) + } + + if(params.customerHoldMusicMethod){ + validParam('customerHoldMusicMethod', params.customerHoldMusicMethod.toUpperCase(), [String], false, ['GET', 'POST']) + } + else { + params.customerHoldMusicMethod = 'GET' + } + + if(params.recordingCallbackUrl){ + validUrl('recordingCallbackUrl', params.recordingCallbackUrl, false) + } + + if(params.recordingCallbackMethod){ + validParam('recordingCallbackMethod', params.recordingCallbackMethod.toUpperCase(), [String], false, ['GET', 'POST']) + } + else { + params.recordingCallbackMethod = 'GET' + } + + if(params.statusCallbackUrl){ + validUrl('statusCallbackUrl', params.statusCallbackUrl, false) + } + + if(params.statusCallbackMethod){ + validParam('statusCallbackMethod', params.statusCallbackMethod.toUpperCase(), [String], false, ['GET', 'POST']) + } + else { + params.statusCallbackMethod = 'GET' + } + + if(params.onExitActionUrl){ + validUrl('onExitActionUrl', params.onExitActionUrl, false) + } + + if(params.onExitActionMethod){ + validParam('statusCallbackMethod', params.statusCallbackMethod.toUpperCase(), [String], false, ['GET', 'POST']) + } + else { + params.onExitActionMethod = 'POST' + } + + if(params.record){ + validParam('record', params.record, [Boolean, String], false) + } + else { + params.record = 'false' + } + + if(params.recordFileFormat){ + validParam('recordFileFormat', params.recordFileFormat.toLowerCase(), [String], false, ['mp3', 'wav']) + } + else { + params.recordFileFormat = 'mp3' + } + + if(params.statusCallbackEvents){ + multiValidParam('statusCallbackEvents', params.statusCallbackEvents.toLowerCase(), [String], false, ['mpc-state-changes', 'participant-state-changes', 'participant-speak-events', 'participant-digit-input-events', 'add-participant-api-events'], true,',') + } + else { + params.statusCallbackEvents = 'mpc-state-changes,participant-state-changes' + } + + if(params.stayAlone){ + validParam('stayAlone', params.stayAlone, [Boolean, String], false) + } + else { + params.stayAlone = 'false' + } + + if(params.coachMode){ + validParam('coachMode', params.coachMode, [Boolean, String], false) + } + else { + params.coachMode = 'true' + } + + if(params.mute){ + validParam('mute', params.mute, [Boolean, String], false) + } + else { + params.mute = 'false' + } + + if(params.hold){ + validParam('hold', params.hold, [Boolean, String], false) + } + else { + params.hold = 'false' + } + + if(params.startMpcOnEnter){ + validParam('startMpcOnEnter', params.startMpcOnEnter, [Boolean, String], false) + } + else { + params.startMpcOnEnter = 'true' + } + + if(params.endMpcOnExit){ + validParam('endMpcOnExit', params.endMpcOnExit, [Boolean, String], false) + } + else { + params.endMpcOnExit = 'false' + } + + if(params.relayDTMFInputs){ + validParam('relayDTMFInputs', params.relayDTMFInputs, [Boolean, String], false) + } + else { + params.relayDTMFInputs = 'false' + } + + if(params.enterSound){ + isOneAmongStringUrl('enterSound', params.enterSound, false, ['beep:1', 'beep:2', 'none']) + } + else { + params.enterSound = 'beep:1' + } + + if(params.enterSoundMethod){ + validParam('enterSoundMethod', params.enterSoundMethod.toUpperCase(), [String], false, ['GET', 'POST']) + } + else { + params.enterSoundMethod = 'GET' + } + + if(params.exitSound){ + isOneAmongStringUrl('exitSound', params.exitSound, false, ['beep:1', 'beep:2', 'none']) + } + else { + params.exitSound = 'beep:2' + } + + if(params.exitSoundMethod){ + validParam('exitSoundMethod', params.exitSoundMethod.toUpperCase(), [String], false, ['GET', 'POST']) + } + else { + params.exitSoundMethod = 'GET' + } + params.isVoiceRequest = 'true'; + return super.executeAction(this.id + '/Participant/', 'POST', params) + } + + start(){ + return super.executeAction(this.id + '/', 'POST', {'status' : 'active', 'isVoiceRequest' : 'true'}) + } + + stop(){ + return super.delete({'isVoiceRequest' : 'true'}) + } + + startRecording(params = {}){ + if(params.fileFormat){ + validParam('fileFormat', params.fileFormat, [String], false, ['mp3', 'wav']) + } + else { + params.fileFormat = 'mp3' + } + + if(params.statusCallbackUrl){ + validUrl('statusCallbackUrl', params.statusCallbackUrl, false) + } + + if(params.statusCallbackMethod){ + validParam('statusCallbackMethod', params.statusCallbackMethod.toUpperCase(), [String], false, ['GET', 'POST']) + } + else { + params.statusCallbackMethod = 'POST' + } + params.isVoiceRequest = 'true'; + return super.executeAction(this.id + '/Record/', 'POST', params) + } + + stopRecording(){ + return super.executeAction(this.id + '/Record/', 'DELETE',{'isVoiceRequest' : 'true'}) + } + + pauseRecording(){ + return super.executeAction(this.id + '/Record/Pause/', 'POST',{'isVoiceRequest' : 'true'}) + } + + resumeRecording(){ + return super.executeAction(this.id + '/Record/Resume/', 'POST',{'isVoiceRequest' : 'true'}) + } + + listParticipants(params = {}){ + if(params.callUuid){ + validParam('callUuid', params.callUuid, [String], false) + } + params.isVoiceRequest = 'true'; + return super.executeAction(this.id + '/Participant/', 'GET', params) + } +} + +export class MultiPartyCallParticipant extends PlivoSecondaryResource{ + constructor(client, data = {}) { + super(action, MultiPartyCall, idField, secondaryAction, MultiPartyCallParticipant, secondaryIdField, client); + + if (idField in data) { + this.id = data[idField]; + } + + if(secondaryIdField in data){ + this.secondaryId = data[secondaryIdField]; + } + + extend(this, data); + this[clientKey] = client; + } + + updateParticipant(params = {}){ + if(params.coachMode){ + validParam('coachMode', params.coachMode, [Boolean, String], false) + } + + if(params.mute){ + validParam('mute', params.mute, [Boolean, String], false) + } + + if(params.hold){ + validParam('hold', params.hold, [Boolean, String], false) + } + params.isVoiceRequest = 'true'; + return super.executeAction(this.id, this.secondaryId, 'POST', params) + } + + kickParticipant(){ + return super.executeAction(this.id, this.secondaryId, 'DELETE',{'isVoiceRequest' : 'true'}) + } + + getParticipant(){ + return super.executeAction(this.id, this.secondaryId, 'GET',{'isVoiceRequest' : 'true'}) + } + +} + +export class MultiPartyCallInterface extends PlivoResourceInterface{ + constructor(client, data = {}) { + super(action, MultiPartyCall, idField, client); + extend(this, data); + + this[clientKey] = client; + } + + makeMpcId(uuid = null, friendlyName = null){ + if(!uuid && !friendlyName){ + throw new MPCError('Specify either multi party call friendly name or uuid') + } + if(uuid && friendlyName){ + throw new MPCError('Cannot specify both multi party call friendly name or uuid') + } + let identifier = '' + if(uuid){ + identifier = ['uuid_', uuid] + } + else{ + identifier = ['name_', friendlyName] + } + return identifier; + } + + list(params={}) { + if(params.subAccount){ + validSubAccount(params.subAccount); + } + if(params.friendlyName){ + validParam('friendlyName', params.friendlyName, [String], false) + } + if(params.status){ + validParam('status', params.status.toLowerCase(), [String], false, ['initialized', 'active', 'ended']) + } + if(params.terminationCauseCode){ + validParam('terminationCauseCode', params.terminationCauseCode, [Number, String], false) + } + if(params.end_time__gt){ + validDateFormat('end_time__gt', params.end_time__gt, false) + } + if(params.end_time__gte){ + validDateFormat('end_time__gte', params.end_time__gte, false) + } + if(params.end_time__lt){ + validDateFormat('end_time__lt', params.end_time__lt, false) + } + if(params.end_time__lte){ + validDateFormat('end_time__lte', params.end_time__lte, false) + } + if(params.creation_time__gt){ + validDateFormat('creation_time__gt', params.creation_time__gt, false) + } + if(params.creation_time__gte){ + validDateFormat('creation_time__gte', params.creation_time__gte, false) + } + if(params.creation_time__lt){ + validDateFormat('creation_time__lt', params.creation_time__lt, false) + } + if(params.creation_time__lte){ + validDateFormat('creation_time__lte', params.creation_time__lte, false) + } + if(params.limit){ + validRange('limit', params.limit, false, 1, 20) + } + if(params.offset){ + validRange('offset', params.offset, false, 0) + } + params.isVoiceRequest = 'true'; + return super.list(params); + } + + get(uuid = null, friendlyName = null){ + if(uuid){ + validParam('uuid', uuid, [String], false) + } + if(friendlyName){ + validParam('friendlyName', friendlyName, [String], false) + } + let mpcId = this.makeMpcId(uuid, friendlyName) + return new MultiPartyCall(this[clientKey], {id: mpcId[0] + mpcId[1]}).get(); + } + + addParticipant(role, params = {}){ + if(params.uuid){ + validParam('uuid', params.uuid, [String], false) + } + if(params.friendlyName){ + validParam('friendlyName', params.friendlyName, [String], false) + } + let mpcId = this.makeMpcId(params.uuid, params.friendlyName) + delete params.uuid + delete params.friendlyName + params.role = role + return new MultiPartyCall(this[clientKey], {id: mpcId[0] + mpcId[1]}).addParticipant(params) + } + + start(uuid = null, friendlyName = null){ + if(uuid){ + validParam('uuid', uuid, [String], false) + } + if(friendlyName){ + validParam('friendlyName', friendlyName, [String], false) + } + let mpcId = this.makeMpcId(uuid, friendlyName) + return new MultiPartyCall(this[clientKey], {id: mpcId[0] + mpcId[1]}).start() + } + + stop(uuid = null, friendlyName = null){ + if(uuid){ + validParam('uuid', uuid, [String], false) + } + if(friendlyName){ + validParam('friendlyName', friendlyName, [String], false) + } + let mpcId = this.makeMpcId(uuid, friendlyName) + return new MultiPartyCall(this[clientKey], {id: mpcId[0] + mpcId[1]}).stop() + } + + startRecording(uuid = null, friendlyName = null, params){ + if(uuid){ + validParam('uuid', uuid, [String], false) + } + if(friendlyName){ + validParam('friendlyName', friendlyName, [String], false) + } + let mpcId = this.makeMpcId(uuid, friendlyName) + return new MultiPartyCall(this[clientKey], {id: mpcId[0] + mpcId[1]}).startRecording(params) + } + + stopRecording(uuid = null, friendlyName = null){ + if(uuid){ + validParam('uuid', uuid, [String], false) + } + if(friendlyName){ + validParam('friendlyName', friendlyName, [String], false) + } + let mpcId = this.makeMpcId(uuid, friendlyName) + return new MultiPartyCall(this[clientKey], {id: mpcId[0] + mpcId[1]}).stopRecording() + } + + pauseRecording(uuid = null, friendlyName = null){ + if(uuid){ + validParam('uuid', uuid, [String], false) + } + if(friendlyName){ + validParam('friendlyName', friendlyName, [String], false) + } + let mpcId = this.makeMpcId(uuid, friendlyName) + return new MultiPartyCall(this[clientKey], {id: mpcId[0] + mpcId[1]}).pauseRecording() + } + + resumeRecording(uuid = null, friendlyName = null){ + if(uuid){ + validParam('uuid', uuid, [String], false) + } + if(friendlyName){ + validParam('friendlyName', friendlyName, [String], false) + } + let mpcId = this.makeMpcId(uuid, friendlyName) + return new MultiPartyCall(this[clientKey], {id: mpcId[0] + mpcId[1]}).resumeRecording() + } + + listParticipants(uuid = null, friendlyName = null, params){ + if(uuid){ + validParam('uuid', uuid, [String], false) + } + if(friendlyName){ + validParam('friendlyName', friendlyName, [String], false) + } + let mpcId = this.makeMpcId(uuid, friendlyName) + return new MultiPartyCall(this[clientKey], {id: mpcId[0] + mpcId[1]}).listParticipants(params) + } + + updateParticipant(participantId, uuid= null, friendlyName = null, params){ + validParam('participantId', participantId, [String, Number], true) + if(uuid){ + validParam('uuid', uuid, [String], false) + } + if(friendlyName){ + validParam('friendlyName', friendlyName, [String], false) + } + let mpcId = this.makeMpcId(uuid, friendlyName) + return new MultiPartyCallParticipant(this[clientKey], {id: mpcId[0] + mpcId[1], secondaryId: participantId}).updateParticipant(params) + } + + kickParticipant(participantId, uuid = null, friendlyName = null){ + validParam('participantId', participantId, [String, Number], true) + if(uuid){ + validParam('uuid', uuid, [String], false) + } + if(friendlyName){ + validParam('friendlyName', friendlyName, [String], false) + } + let mpcId = this.makeMpcId(uuid, friendlyName) + return new MultiPartyCallParticipant(this[clientKey], {id: mpcId[0] + mpcId[1], secondaryId: participantId}).kickParticipant() + } + + getParticipant(participantId, uuid = null, friendlyName = null){ + validParam('participantId', participantId, [String, Number], true) + if(uuid){ + validParam('uuid', uuid, [String], false) + } + if(friendlyName){ + validParam('friendlyName', friendlyName, [String], false) + } + let mpcId = this.makeMpcId(uuid, friendlyName) + return new MultiPartyCallParticipant(this[clientKey], {id: mpcId[0] + mpcId[1], secondaryId: participantId}).getParticipant() + } + +} diff --git a/lib/resources/numbers.js b/lib/resources/numbers.js index eae18c8..ccaec8b 100644 --- a/lib/resources/numbers.js +++ b/lib/resources/numbers.js @@ -295,7 +295,7 @@ export class NumberInterface extends PlivoResourceInterface { let params = optionalParams || {}; params.country_iso = countryISO; - return new PhoneNumberInterface(this[clientKey]).list(countryISO, params); + return new PhoneNumberInterface(this[clientKey]).list(params); } /** diff --git a/lib/resources/recordings.js b/lib/resources/recordings.js index 81dc158..f9294fe 100644 --- a/lib/resources/recordings.js +++ b/lib/resources/recordings.js @@ -73,9 +73,11 @@ export class Recording extends PlivoResource { * @fail {Error} return Error */ delete(id) { + let params = {}; + params.isVoiceRequest = 'true'; let client = this[clientKey]; return new Promise((resolve, reject) => { - client('DELETE', action + id + '/') + client('DELETE', action + id + '/', params) .then(() => { resolve(true); }) @@ -191,4 +193,4 @@ export class RecordingInterface extends PlivoResourceInterface { id: id }).delete(id); } -} \ No newline at end of file +} diff --git a/lib/rest/axios.js b/lib/rest/axios.js index 5c3879a..d323f07 100644 --- a/lib/rest/axios.js +++ b/lib/rest/axios.js @@ -30,6 +30,65 @@ export function Axios(config) { } return (method, action, params) => { + let configuration = config; + // Add support fot multipart requests. + if (typeof (params) != 'undefined' && params.multipart == true) { + return new Promise((resolve, reject) => { + delete params.multipart; + + var FormData = require('form-data'); + var multipartParams = new FormData(); + + for(const key in params) { + if (key != 'file') { + multipartParams.append(key, params[key]); + } else { + multipartParams.append(key, require('fs').createReadStream(params[key])); + } + } + + let headers = multipartParams.getHeaders(); + + var config = { + method: method, + url: configuration.url + '/' + action, + headers: { + 'Authorization': 'Basic ' + new Buffer(configuration.authId + ':' + configuration.authToken).toString('base64'), + 'User-Agent': configuration.userAgent, + 'content-type': headers['content-type'] + }, + data : multipartParams + }; + + axios(config).then(response => { + const exceptionClass = { + 400: Exceptions.InvalidRequestError, + 401: Exceptions.AuthenticationError, + 404: Exceptions.ResourceNotFoundError, + 405: Exceptions.InvalidRequestError, + 500: Exceptions.ServerError, + } [response.status] || Error; + + if (!_.inRange(response.status, 200, 300)) { + let body = response.data; + if (typeof body === 'object') { + reject(new exceptionClass(JSON.stringify(body))); + } + else { + reject(new exceptionClass(body)); + } + } + resolve({ + response: response, + body: response.data + }); + }) + .catch(function (error) { + reject(error.stack+ "\r\n" + JSON.stringify(error.response.data)); + }); + }) + } + if (typeof (params) != 'undefined' && typeof (params.file) != 'undefined') { let files = []; if (Array.isArray(params.file)) { @@ -41,6 +100,7 @@ export function Axios(config) { } params.file = files; } + let options = { url: config.url + '/' + action, method: method, diff --git a/lib/rest/client-test.js b/lib/rest/client-test.js index b8bd8cc..848c901 100644 --- a/lib/rest/client-test.js +++ b/lib/rest/client-test.js @@ -48,6 +48,7 @@ import { import { MediaInterface } from '../resources/media.js'; +import {MultiPartyCallInterface} from "../resources/multiPartyCall"; export class Client { constructor(authId, authToken, proxy) { @@ -90,6 +91,12 @@ export class Client { this.pricings = new PricingInterface(client); this.recordings = new RecordingInterface(client); this.media = new MediaInterface(client); + this.endUsers = new EndUserInterface(client); + this.complianceDocumentTypes = new ComplianceDocumentTypeInterface(client); + this.complianceDocuments = new ComplianceDocumentInterface(client); + this.complianceRequirements = new ComplianceRequirementInterface(client); + this.complianceApplications = new ComplianceApplicationInterface(client); + this.multiPartyCalls = new MultiPartyCallInterface(client); } } diff --git a/lib/rest/client.js b/lib/rest/client.js index be78627..492c32d 100644 --- a/lib/rest/client.js +++ b/lib/rest/client.js @@ -20,6 +20,12 @@ import { validateV3Signature } from "../utils/v3Security"; import { stringify } from "./../utils/jsonStrinfigier"; import { CallFeedbackInterface } from "../resources/callFeedback"; import { MediaInterface } from "../resources/media.js"; +import { EndUserInterface } from "../resources/endUsers"; +import { ComplianceDocumentTypeInterface } from "../resources/complianceDocumentTypes"; +import { ComplianceDocumentInterface} from "../resources/complianceDocuments"; +import { ComplianceRequirementInterface } from "../resources/complianceRequirements"; +import { ComplianceApplicationInterface } from "../resources/complianceApplications"; +import {MultiPartyCallInterface} from "../resources/multiPartyCall"; exports.Response = function() { return new Response(); @@ -82,6 +88,12 @@ export class Client { this.recordings = new RecordingInterface(client); this.callFeedback = new CallFeedbackInterface(client); this.media = new MediaInterface(client); + this.endUsers = new EndUserInterface(client); + this.complianceDocumentTypes = new ComplianceDocumentTypeInterface(client); + this.complianceDocuments = new ComplianceDocumentInterface(client); + this.complianceRequirements = new ComplianceRequirementInterface(client); + this.complianceApplications = new ComplianceApplicationInterface(client); + this.multiPartyCalls = new MultiPartyCallInterface(client); } toJSON() { diff --git a/lib/rest/request-test.js b/lib/rest/request-test.js index be2e21d..9f60e97 100644 --- a/lib/rest/request-test.js +++ b/lib/rest/request-test.js @@ -583,6 +583,306 @@ export function Request(config) { }); } + // ============= MultiPartyCalls =============== + else if (method === 'GET' && action === 'MultiPartyCall/'){ + resolve({ + response: {}, + body: { + "api_id": "d53ab14c-eddb-11ea-b02e-0242ac110003", + "meta": { + "count": 6, + "limit": 20, + "next": null, + "offset": 0, + "previous": null + }, + "objects": [ + { + "billed_amount": "0.00500", + "billed_duration": 60, + "creation_time": "2020-08-31 15:12:03+00:00", + "duration": 3, + "end_time": "2020-08-31 15:12:06+00:00", + "friendly_name": "TestMPC", + "mpc_uuid": "ca8e8a44-48e1-445d-afd5-1fcccdbccd9d", + "participants": "/v1/Account/MAMDJMMTEZOWY0ZMQWM2/MultiPartyCall/uuid_ca8e8a44-48e1-445d-afd5-1fcccdbccd9d/Participant/", + "recording": null, + "resource_uri": "/v1/Account/MAMDJMMTEZOWY0ZMQWM2/MultiPartyCall/uuid_ca8e8a44-48e1-445d-afd5-1fcccdbccd9d/", + "start_time": null, + "status": "Ended", + "stay_alone": false, + "sub_account": null, + "termination_cause": "No Active Participants", + "termination_cause_code": 1000 + }, + { + "billed_amount": "0.00500", + "billed_duration": 60, + "creation_time": "2020-08-31 14:32:40+00:00", + "duration": 5, + "end_time": "2020-08-31 14:32:45+00:00", + "friendly_name": "TestMPC", + "mpc_uuid": "9b531a1f-1692-4802-a7d6-3ef25bcfe3fc", + "participants": "/v1/Account/MAMDJMMTEZOWY0ZMQWM2/MultiPartyCall/uuid_9b531a1f-1692-4802-a7d6-3ef25bcfe3fc/Participant/", + "recording": null, + "resource_uri": "/v1/Account/MAMDJMMTEZOWY0ZMQWM2/MultiPartyCall/uuid_9b531a1f-1692-4802-a7d6-3ef25bcfe3fc/", + "start_time": null, + "status": "Ended", + "stay_alone": false, + "sub_account": null, + "termination_cause": "No Active Participants", + "termination_cause_code": 1000 + }, + { + "billed_amount": "0.01000", + "billed_duration": 120, + "creation_time": "2020-08-31 14:32:11+00:00", + "duration": 11, + "end_time": "2020-08-31 14:32:22+00:00", + "friendly_name": "TestMPC", + "mpc_uuid": "6f84d47c-ee82-4172-a155-c6e22f87d874", + "participants": "/v1/Account/MAMDJMMTEZOWY0ZMQWM2/MultiPartyCall/uuid_6f84d47c-ee82-4172-a155-c6e22f87d874/Participant/", + "recording": null, + "resource_uri": "/v1/Account/MAMDJMMTEZOWY0ZMQWM2/MultiPartyCall/uuid_6f84d47c-ee82-4172-a155-c6e22f87d874/", + "start_time": null, + "status": "Ended", + "stay_alone": false, + "sub_account": null, + "termination_cause": "Stay Alone Not Permitted", + "termination_cause_code": 1010 + }, + { + "billed_amount": "0.00500", + "billed_duration": 60, + "creation_time": "2020-08-31 14:31:20+00:00", + "duration": 3, + "end_time": "2020-08-31 14:31:23+00:00", + "friendly_name": "TestMPC", + "mpc_uuid": "0746f6c6-7447-4e0a-9013-186e4220aaf4", + "participants": "/v1/Account/MAMDJMMTEZOWY0ZMQWM2/MultiPartyCall/uuid_0746f6c6-7447-4e0a-9013-186e4220aaf4/Participant/", + "recording": null, + "resource_uri": "/v1/Account/MAMDJMMTEZOWY0ZMQWM2/MultiPartyCall/uuid_0746f6c6-7447-4e0a-9013-186e4220aaf4/", + "start_time": "2020-08-31 14:31:20+00:00", + "status": "Ended", + "stay_alone": false, + "sub_account": null, + "termination_cause": "No Active Participants", + "termination_cause_code": 1000 + }, + { + "billed_amount": "0.00500", + "billed_duration": 60, + "creation_time": "2020-08-31 06:42:50+00:00", + "duration": 36, + "end_time": "2020-08-31 06:43:26+00:00", + "friendly_name": "TestMPC", + "mpc_uuid": "b89150fd-0387-4bf8-bde7-a4fed39601ce", + "participants": "/v1/Account/MAMDJMMTEZOWY0ZMQWM2/MultiPartyCall/uuid_b89150fd-0387-4bf8-bde7-a4fed39601ce/Participant/", + "recording": null, + "resource_uri": "/v1/Account/MAMDJMMTEZOWY0ZMQWM2/MultiPartyCall/uuid_b89150fd-0387-4bf8-bde7-a4fed39601ce/", + "start_time": "2020-08-31 06:42:50+00:00", + "status": "Ended", + "stay_alone": false, + "sub_account": null, + "termination_cause": "No Active Participants", + "termination_cause_code": 1000 + }, + { + "billed_amount": "0.00500", + "billed_duration": 60, + "creation_time": "2020-08-28 17:30:10+00:00", + "duration": 2, + "end_time": "2020-08-28 17:30:12+00:00", + "friendly_name": "tank", + "mpc_uuid": "2999c70d-b635-420f-b6f2-2fd4421f0381", + "participants": "/v1/Account/MAMDJMMTEZOWY0ZMQWM2/MultiPartyCall/uuid_2999c70d-b635-420f-b6f2-2fd4421f0381/Participant/", + "recording": null, + "resource_uri": "/v1/Account/MAMDJMMTEZOWY0ZMQWM2/MultiPartyCall/uuid_2999c70d-b635-420f-b6f2-2fd4421f0381/", + "start_time": "2020-08-28 17:30:10+00:00", + "status": "Ended", + "stay_alone": true, + "sub_account": null, + "termination_cause": "No Active Participants", + "termination_cause_code": 1000 + } + ] + } + }); + } + + else if (method === 'GET' && action === 'MultiPartyCall/uuid_ca8e8a44-48e1-445d-afd5-1fcccdbccd9d'){ + resolve({ + response: {}, + body: { + "api_id": "8970c2b3-edfb-11ea-b02e-0242ac110003", + "billed_amount": "0.00500", + "billed_duration": 60, + "creation_time": "2020-08-31 15:12:03+00:00", + "duration": 3, + "end_time": "2020-08-31 15:12:06+00:00", + "friendly_name": "TestMPC", + "mpc_uuid": "ca8e8a44-48e1-445d-afd5-1fcccdbccd9d", + "participants": "/v1/Account/MAMDJMMTEZOWY0ZMQWM2/MultiPartyCall/uuid_ca8e8a44-48e1-445d-afd5-1fcccdbccd9d/Participant/", + "recording": null, + "resource_uri": "/v1/Account/MAMDJMMTEZOWY0ZMQWM2/MultiPartyCall/uuid_ca8e8a44-48e1-445d-afd5-1fcccdbccd9d/", + "start_time": null, + "status": "Ended", + "stay_alone": false, + "sub_account": null, + "termination_cause": "No Active Participants", + "termination_cause_code": 1000 + } + }); + } + + else if (method === 'POST' && action === 'MultiPartyCall/name_Voice/Participant/' && params.role === 'Agent' && params.from === '+919090909090' && params.to === '+918309866821'){ + resolve({ + response: {}, + body: { + "api_id": "1cebd713-ee00-11ea-b02e-0242ac110003", + "calls": [ + { + "to": "sip:koushikqa119062465586783372208@phone-qa.voice.plivodev.com", + "from": "918888888888", + "call_uuid": "c0267574-5c12-4861-8990-da9404c8cdf6" + } + ], + "message": "add participant action initiated", + "request_uuid": "c0267574-5c12-4861-8990-da9404c8cdf6" + } + }); + } + + else if (method === 'POST' && action === 'MultiPartyCall/name_Voice/' && params.status === 'active'){ + resolve({ + response: {}, + body: {} + }); + } + + else if (method === 'DELETE' && action === 'MultiPartyCall/name_Voice/'){ + resolve({ + response: {}, + body: {} + }); + } + + else if (method === 'POST' && action === 'MultiPartyCall/name_TestMPC/Record/'){ + resolve({ + response: {}, + body: { + "api_id" : "e9b9b0cf-ee0a-11ea-b02e-0242ac110003", + "message" : "MPC: TestMPC record started", + "recording_id" : "e9bd7634-ee0a-11ea-9ddf-06feebbe3347", + "recording_url" : "https://media-qa.voice.plivodev.com/v1/Account/MAMDJMMTEZOWY0ZMQWM2/Recording/e9bd7634-ee0a-11ea-9ddf-06feebbe3347.mp3" + } + }); + } + + else if (method === 'DELETE' && action === 'MultiPartyCall/name_TestMPC/Record/'){ + resolve({ + response: {}, + body: { + } + }); + } + + else if (method === 'POST' && action === 'MultiPartyCall/name_TestMPC/Record/Pause/'){ + resolve({ + response: {}, + body: { + } + }); + } + + else if (method === 'POST' && action === 'MultiPartyCall/name_TestMPC/Record/Resume/'){ + resolve({ + response: {}, + body: { + } + }); + } + + else if (method === 'GET' && action === 'MultiPartyCall/uuid_12345678-90123456/Participant/'){ + resolve({ + response: {}, + body: { + "api_id": "d53e6c49-ee0e-11ea-b02e-0242ac110003", + "meta": { + "count": 1, + "limit": 20, + "next": null, + "offset": 0, + "previous": null + }, + "objects": [ + { + "billed_amount": null, + "billed_duration": null, + "call_uuid": "426c1fb3-8f47-46e5-a916-51faa85ca90e", + "coach_mode": false, + "duration": null, + "end_mpc_on_exit": false, + "exit_cause": null, + "exit_time": null, + "hold": false, + "join_time": "2020-09-03 17:24:12+00:00", + "member_id": "2132", + "mpc_uuid": "7503f05f-2d6e-4ab3-b9e6-3b0d81ae9087", + "mute": false, + "resource_uri": "/v1/Account/MAMDJMMTEZOWY0ZMQWM2/MultiPartyCall/uuid_7503f05f-2d6e-4ab3-b9e6-3b0d81ae9087/Participant/2132/", + "role": "agent", + "start_mpc_on_enter": true + } + ] + } + }); + } + + else if (method === 'POST' && action === 'MultiPartyCall/uuid_12345678-90123456/Participant/10/'){ + resolve({ + response: {}, + body: { + "api_id" : "be5a333a-ee0f-11ea-b02e-0242ac110003", + "hold" : "MPC: TestMPC hold/unhold member(s) succeded", + "mute" : "MPC: TestMPC mute/unmute member(s) succeded" + } + }); + } + + else if (method === 'DELETE' && action === 'MultiPartyCall/uuid_12345678-90123456/Participant/10/'){ + resolve({ + response: {}, + body: { + } + }); + } + + else if (method === 'GET' && action === 'MultiPartyCall/uuid_7503f05f-2d6e-4ab3-b9e6-3b0d81ae9087/Participant/2132/'){ + resolve({ + response: {}, + body: { + "api_id": "7ca274bb-ee11-11ea-b02e-0242ac110003", + "billed_amount": null, + "billed_duration": null, + "call_uuid": "426c1fb3-8f47-46e5-a916-51faa85ca90e", + "coach_mode": false, + "duration": null, + "end_mpc_on_exit": false, + "exit_cause": null, + "exit_time": null, + "hold": false, + "join_time": "2020-09-03 17:24:12+00:00", + "member_id": "2132", + "mpc_uuid": "7503f05f-2d6e-4ab3-b9e6-3b0d81ae9087", + "mute": false, + "resource_uri": "/v1/Account/MAMDJMMTEZOWY0ZMQWM2/MultiPartyCall/uuid_7503f05f-2d6e-4ab3-b9e6-3b0d81ae9087/Participant/2132/", + "role": "agent", + "start_mpc_on_enter": true + } + }); + } + // ============= Numbers =================== else if (method == 'GET' && action == 'Number/+919999999990/') { resolve({ diff --git a/lib/rest/utils.js b/lib/rest/utils.js index d026b97..9facdc5 100644 --- a/lib/rest/utils.js +++ b/lib/rest/utils.js @@ -5,6 +5,8 @@ import _mapValues from 'lodash/mapValues'; import _map from 'lodash/map'; import { parseString } from 'xml2js'; +export class InvalidRequestError extends Error {} + function recursivelyRenameObject(object, renameFunc) { if (!(object instanceof Object)) { return object; @@ -50,7 +52,8 @@ export function camelCaseRequestWrapper(requestFunc) { .replace('_equals', '') .replace('priority_1', 'priority1') .replace('priority_2', 'priority2') - .replace('priority_3', 'priority3'); + .replace('priority_3', 'priority3') + .replace('country_iso_2', 'country_iso2'); }); return requestFunc(method, action, params).then(res => { @@ -81,3 +84,203 @@ export function validateSpeakAttributes(content, voice) { } } +export function validSubAccount(accountId){ + if(accountId.constructor !== String){ + throw new InvalidRequestError('Subaccount Id must be a string'); + } + + if(accountId.length !== 20){ + throw new InvalidRequestError('Subaccount Id should be of length 20'); + } + + if(accountId.substring(0,2) !== 'SA'){ + throw new InvalidRequestError("Subaccount Id should start with 'SA'"); + } + + return true; +} + +export function validMultipleDestinationNos(paramName, paramValue, options = {}){ + if(paramValue.split(options.delimiter).length > 1 && options.role.toLowerCase()!=='agent'){ + throw new InvalidRequestError('Multiple ' + paramName + ' values given for role ' + options.role) + } + else if (paramValue.split(options.delimiter).length >= options.agentLimit){ + throw new InvalidRequestError('No of ' + paramName + ' values provided should be lesser than ' + options.agentLimit) + } + else { + return true + } +} + +export function validParam(paramName, paramValue, expectedTypes = null, mandatory = false, expectedValues = null){ + if(mandatory && !paramValue){ + throw new InvalidRequestError(paramName + " is a required parameter"); + } + + if (!paramValue){ + return true; + } + + if(!expectedValues){ + return expectedType(paramName, expectedTypes, paramValue); + } + + if(expectedValue(paramName, expectedValues, paramValue)){ + return true; + } +} + +export function expectedType(paramName, expectedTypes, paramValue){ + if(!expectedTypes){ + return true; + } + + if(expectedTypes.indexOf(paramValue.constructor)===-1){ + throw new InvalidRequestError(paramName + ": Expected one of " + expectedTypes + " but received " + paramValue.constructor + " instead") + } + return true; +} + +export function expectedValue(paramName, expectedValues, paramValue){ + if(!expectedValues){ + return true; + } + + if(expectedValues.constructor === Array){ + if(expectedValues.indexOf(paramValue) === -1){ + throw new InvalidRequestError(paramName + ': Expected one of ' + expectedValues + ' but received ' + paramValue + ' instead'); + } + return true; + } + else{ + if(expectedValues !== paramValue){ + throw new InvalidRequestError(paramName + ': Expected ' + expectedValues + ' but received ' + paramValue + ' instead') + } + return true; + } +} + +export function multiValidParam(paramName, paramValue, expectedTypes = null, mandatory = false, expectedValues = null, makeLowerCase = false, seperator = ','){ + if(mandatory && !paramValue){ + throw new InvalidRequestError(paramName + 'is a required parameter'); + } + + if(!paramValue){ + return true; + } + + if(makeLowerCase){ + paramValue = paramValue.toLowerCase(); + } + else{ + paramValue = paramValue.toUpperCase(); + } + let values = paramValue.split(seperator) + if(expectedValues) { + for (let i = 0; i < values.length; i++) { + expectedValue(paramName, expectedValues, values[i].trim()); + } + } + return true; +} + +export function validUrl(paramName, paramValue, mandatory = false){ + if(mandatory && !paramValue){ + throw new InvalidRequestError(paramName + 'is a required parameter'); + } + + if(!paramValue){ + return true; + } + + let response = paramValue.match(/(http(s)?:\/\/.)?(www\.)?[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)/g); + if(response == null){ + throw new InvalidRequestError("Invalid URL : Doesn't satisfy the URL format") + } + else { + return true; + } +} + +export function isOneAmongStringUrl(paramName, paramValue, mandatory = false, expectedValues = null){ + if(mandatory && !paramValue){ + throw new InvalidRequestError(paramName + 'is a required parameter'); + } + + if(!paramValue){ + return true; + } + + if(!(expectedValues.indexOf(paramValue.toLowerCase()) === -1) || !(expectedValues.indexOf(paramValue.toUpperCase()) === -1)){ + return true; + } + else if (validUrl(paramName, paramValue)){ + return true; + } + else { + throw new InvalidRequestError(paramName + ' neither a valid URL nor in the expected values') + } +} + +export function validDateFormat(paramName, paramValue, mandatory = false){ + if(mandatory && !paramValue){ + throw new InvalidRequestError(paramName + " is a required parameter") + } + + if(!paramValue){ + return true; + } + + let response = paramValue.match(/^\d{4}\-\d{2}\-\d{2} \d{2}:\d{2}(:\d{2}(\.\d{1,6})?)?$/); + if(response == null){ + throw new InvalidRequestError("Invalid Date : Doesn't satisfy the date format") + } + else { + return true; + } +} + +export function validRange(paramName, paramValue, mandatory = false, lowerBound = null, upperBound = null){ + if(mandatory && !paramValue){ + throw new InvalidRequestError(paramName + " is a required parameter") + } + + if(!paramValue && paramValue !== 0){ + return true; + } + + if(!expectedType(paramName, [Number], paramValue)){ + throw new InvalidRequestError(paramName + ": Expected an Integer but received " + paramValue.constructor + " instead") + } + + if(lowerBound && upperBound){ + if(paramValue < lowerBound || paramValue > upperBound) { + throw new InvalidRequestError(paramName + " ranges between " + lowerBound + " and " + upperBound) + } + + if(paramValue >= lowerBound && paramValue <= upperBound){ + return true; + } + } + else if(lowerBound){ + if(paramValue < lowerBound){ + throw new InvalidRequestError(paramName + " should be greater than " + lowerBound) + } + + if(paramValue >= lowerBound){ + return true; + } + } + else if(upperBound){ + if(paramValue > upperBound){ + throw new InvalidRequestError(paramName + " should be lesser than " + upperBound) + } + + if(paramValue <= upperBound){ + return true; + } + } + else{ + throw new InvalidRequestError("Any one or both of lower and upper bound should be provided") + } +} diff --git a/lib/utils/plivoxml.js b/lib/utils/plivoxml.js index 577ce9f..f6a30b3 100644 --- a/lib/utils/plivoxml.js +++ b/lib/utils/plivoxml.js @@ -2,7 +2,6 @@ var qs = require('querystring'); var xmlBuilder = require('xmlbuilder'); var util = require('util'); var plivoUtils = require('./../rest/utils'); - import * as Exceptions from './exceptions'; var jsonStringifier = require('./jsonStrinfigier'); @@ -15,7 +14,7 @@ export class PlivoXMLError extends Error { } export function Response() { this.element = 'Response'; this.nestables = ['Speak', 'Play', 'GetDigits', 'GetInput', 'Record', 'Dial', 'Message', - 'Redirect', 'Wait', 'Hangup', 'PreAnswer', 'Conference', 'DTMF']; + 'Redirect', 'Wait', 'Hangup', 'PreAnswer', 'Conference', 'DTMF', 'MultiPartyCall']; this.valid_attributes = []; this.elem = xmlBuilder.begin().ele(this.element); } @@ -440,6 +439,234 @@ Response.prototype = { return this.add(new DTMF(Response), body, attributes); }, + /** + * Add a MultiPartyCall element + * @method + * @param {string} body + * @param {object} attributes + * @param {string} [attributes.role] + * @param {number} [attributes.maxDuration] + * @param {number} [attributes.maxParticipants] + * @param {string} [attributes.waitMusicMethod] + * @param {string} [attributes.agentHoldMusicMethod] + * @param {string} [attributes.customerHoldMusicMethod] + * @param {boolean} [attributes.record] + * @param {string} [attributes.recordFileFormat] + * @param {string} [attributes.recordingCallbackMethod] + * @param {string} [attributes.statusCallbackEvents] + * @param {string} [attributes.statusCallbackMethod] + * @param {boolean} [attributes.stayAlone] + * @param {boolean} [attributes.coachMode] + * @param {boolean} [attributes.mute] + * @param {boolean} [attributes.hold] + * @param {boolean} [attributes.startMpcOnEnter] + * @param {boolean} [attributes.endMpcOnExit] + * @param {string} [attributes.enterSound] + * @param {string} [attributes.enterSoundMethod] + * @param {string} [attributes.exitSound] + * @param {string} [attributes.exitSoundMethod] + * @param {string} [attributes.onExitActionMethod] + * @param {boolean} [attributes.relayDTMFInputs] + * @param {string} [attributes.waitMusicUrl] + * @param {string} [attributes.agentHoldMusicUrl] + * @param {string} [attributes.customerHoldMusicUrl] + * @param {string} [attributes.recordingCallbackUrl] + * @param {string} [attributes.statusCallbackUrl] + * @param {string} [attributes.customerHoldMusicUrl] + */ + addMultiPartyCall: function (body, attributes){ + const VALID_ROLE_VALUES = ['agent', 'supervisor', 'customer'] + const VALID_METHOD_VALUES = ['GET', 'POST'] + const VALID_BOOL_VALUES = [true, false] + const VALID_RECORD_FILE_FORMAT_VALUES = ['mp3', 'wav'] + + if(attributes.role && VALID_ROLE_VALUES.indexOf(attributes.role.toLowerCase())===-1){ + throw new PlivoXMLError('Invalid attribute value ' + attributes.role + ' for role') + } + else if (!attributes.role){ + throw new PlivoXMLError('role not mentioned : possible values - Agent / Supervisor / Customer') + } + + if(attributes.maxDuration && (attributes.maxDuration<300 || attributes.maxDuration>28800)){ + throw new PlivoXMLError('Invalid attribute value ' + attributes.maxDuration + ' for maxDuration') + } + else if(!attributes.maxDuration){ + attributes.maxDuration = 14400 + } + + if(attributes.maxParticipants && (attributes.maxParticipants<2 || attributes.maxParticipants>10)){ + throw new PlivoXMLError('Invalid attribute value ' + attributes.maxParticipants + ' for maxParticipants') + } + else if(!attributes.maxParticipants){ + attributes.maxParticipants = 10 + } + + if(attributes.waitMusicMethod && VALID_METHOD_VALUES.indexOf(attributes.waitMusicMethod.toUpperCase())===-1){ + throw new PlivoXMLError('Invalid attribute value ' + attributes.waitMusicMethod + ' for waitMusicMethod') + } + else if (!attributes.waitMusicMethod){ + attributes.waitMusicMethod = 'GET' + } + + if(attributes.agentHoldMusicMethod && VALID_METHOD_VALUES.indexOf(attributes.agentHoldMusicMethod.toUpperCase())===-1){ + throw new PlivoXMLError('Invalid attribute value ' + attributes.agentHoldMusicMethod + ' for agentHoldMusicMethod') + } + else if (!attributes.agentHoldMusicMethod){ + attributes.agentHoldMusicMethod = 'GET' + } + + if(attributes.customerHoldMusicMethod && VALID_METHOD_VALUES.indexOf(attributes.customerHoldMusicMethod.toUpperCase())===-1){ + throw new PlivoXMLError('Invalid attribute value ' + attributes.customerHoldMusicMethod + ' for customerHoldMusicMethod') + } + else if (!attributes.customerHoldMusicMethod){ + attributes.customerHoldMusicMethod = 'GET' + } + + if(attributes.record && VALID_BOOL_VALUES.indexOf(attributes.record)===-1){ + throw new PlivoXMLError('Invalid attribute value ' + attributes.record + ' for record') + } + else if (!attributes.record){ + attributes.record = false + } + + if(attributes.recordFileFormat && VALID_RECORD_FILE_FORMAT_VALUES.indexOf(attributes.recordFileFormat.toLowerCase())===-1){ + throw new PlivoXMLError('Invalid attribute value ' + attributes.recordFileFormat + ' for recordFileFormat') + } + else if (!attributes.recordFileFormat){ + attributes.recordFileFormat = 'mp3' + } + + if(attributes.recordingCallbackMethod && VALID_METHOD_VALUES.indexOf(attributes.recordingCallbackMethod.toUpperCase())===-1){ + throw new PlivoXMLError('Invalid attribute value ' + attributes.recordingCallbackMethod + ' for recordingCallbackMethod') + } + else if (!attributes.recordingCallbackMethod){ + attributes.recordingCallbackMethod = 'GET' + } + + if(attributes.statusCallbackEvents && !plivoUtils.multiValidParam('statusCallbackEvents', attributes.statusCallbackEvents, String, false, ['mpc-state-changes', 'participant-state-changes', 'participant-speak-events', 'participant-digit-input-events', 'add-participant-api-events'], true, ',')){ + throw new PlivoXMLError('Invalid attribute value ' + attributes.statusCallbackEvents + ' for statusCallbackEvents') + } + else if(!attributes.statusCallbackEvents){ + attributes.statusCallbackEvents = 'mpc-state-changes,participant-state-changes' + } + + if(attributes.statusCallbackMethod && VALID_METHOD_VALUES.indexOf(attributes.statusCallbackMethod.toUpperCase())===-1){ + throw new PlivoXMLError('Invalid attribute value ' + attributes.statusCallbackMethod + ' for statusCallbackMethod') + } + else if (!attributes.statusCallbackMethod){ + attributes.statusCallbackMethod = 'POST' + } + + if(attributes.stayAlone && VALID_BOOL_VALUES.indexOf(attributes.stayAlone)===-1){ + throw new PlivoXMLError('Invalid attribute value ' + attributes.stayAlone + ' for stayAlone') + } + else if (!attributes.stayAlone){ + attributes.stayAlone = false + } + + if(attributes.coachMode && VALID_BOOL_VALUES.indexOf(attributes.coachMode)===-1){ + throw new PlivoXMLError('Invalid attribute value ' + attributes.coachMode + ' for coachMode') + } + else if (!attributes.coachMode){ + attributes.coachMode = true + } + + if(attributes.mute && VALID_BOOL_VALUES.indexOf(attributes.mute)===-1){ + throw new PlivoXMLError('Invalid attribute value ' + attributes.mute + ' for mute') + } + else if (!attributes.mute){ + attributes.mute = false + } + + if(attributes.hold && VALID_BOOL_VALUES.indexOf(attributes.hold)===-1){ + throw new PlivoXMLError('Invalid attribute value ' + attributes.hold + ' for hold') + } + else if (!attributes.hold){ + attributes.hold = false + } + + if(attributes.startMpcOnEnter && VALID_BOOL_VALUES.indexOf(attributes.startMpcOnEnter)===-1){ + throw new PlivoXMLError('Invalid attribute value ' + attributes.startMpcOnEnter + ' for startMpcOnEnter') + } + else if (!attributes.startMpcOnEnter){ + attributes.startMpcOnEnter = true + } + + if(attributes.endMpcOnExit && VALID_BOOL_VALUES.indexOf(attributes.endMpcOnExit)===-1){ + throw new PlivoXMLError('Invalid attribute value ' + attributes.endMpcOnExit + ' for endMpcOnExit') + } + else if (!attributes.endMpcOnExit){ + attributes.endMpcOnExit = false + } + + if(attributes.enterSound && !plivoUtils.isOneAmongStringUrl('enterSound', attributes.enterSound, false, ['beep:1', 'beep:2', 'none'])){ + throw new PlivoXMLError('Invalid attribute value ' + attributes.enterSound + ' for enterSound') + } + else if(!attributes.enterSound){ + attributes.enterSound = 'beep:1' + } + + if(attributes.enterSoundMethod && VALID_METHOD_VALUES.indexOf(attributes.enterSoundMethod.toUpperCase())===-1){ + throw new PlivoXMLError('Invalid attribute value ' + attributes.enterSoundMethod + ' for enterSoundMethod') + } + else if (!attributes.enterSoundMethod){ + attributes.enterSoundMethod = 'GET' + } + + if(attributes.exitSound && !plivoUtils.isOneAmongStringUrl('exitSound', attributes.exitSound, false, ['beep:1', 'beep:2', 'none'])){ + throw new PlivoXMLError('Invalid attribute value ' + attributes.exitSound + ' for exitSound') + } + else if(!attributes.exitSound){ + attributes.exitSound = 'beep:2' + } + + if(attributes.exitSoundMethod && VALID_METHOD_VALUES.indexOf(attributes.exitSoundMethod.toUpperCase())===-1){ + throw new PlivoXMLError('Invalid attribute value ' + attributes.exitSoundMethod + ' for exitSoundMethod') + } + else if (!attributes.exitSoundMethod){ + attributes.exitSoundMethod = 'GET' + } + + if(attributes.onExitActionMethod && VALID_METHOD_VALUES.indexOf(attributes.onExitActionMethod.toUpperCase())===-1){ + throw new PlivoXMLError('Invalid attribute value ' + attributes.onExitActionMethod + ' for onExitActionMethod') + } + else if (!attributes.onExitActionMethod){ + attributes.onExitActionMethod = 'POST' + } + + if(attributes.relayDTMFInputs && VALID_BOOL_VALUES.indexOf(attributes.relayDTMFInputs)===-1){ + throw new PlivoXMLError('Invalid attribute value ' + attributes.relayDTMFInputs + ' for relayDTMFInputs') + } + else if (!attributes.relayDTMFInputs){ + attributes.relayDTMFInputs = false + } + + if(attributes.waitMusicUrl && !plivoUtils.validUrl('waitMusicUrl', attributes.waitMusicUrl, false)){ + throw new PlivoXMLError('Invalid attribute value ' + attributes.waitMusicUrl + ' for waitMusicUrl') + } + + if(attributes.agentHoldMusicUrl && !plivoUtils.validUrl('agentHoldMusicUrl', attributes.agentHoldMusicUrl, false)){ + throw new PlivoXMLError('Invalid attribute value ' + attributes.agentHoldMusicUrl + ' for agentHoldMusicUrl') + } + + if(attributes.customerHoldMusicUrl && !plivoUtils.validUrl('customerHoldMusicUrl', attributes.customerHoldMusicUrl, false)){ + throw new PlivoXMLError('Invalid attribute value ' + attributes.customerHoldMusicUrl + ' for customerHoldMusicUrl') + } + + if(attributes.recordingCallbackUrl && !plivoUtils.validUrl('recordingCallbackUrl', attributes.recordingCallbackUrl, false)){ + throw new PlivoXMLError('Invalid attribute value ' + attributes.recordingCallbackUrl + ' for recordingCallbackUrl') + } + + if(attributes.statusCallbackUrl && !plivoUtils.validUrl('statusCallbackUrl', attributes.statusCallbackUrl, false)){ + throw new PlivoXMLError('Invalid attribute value ' + attributes.statusCallbackUrl + ' for statusCallbackUrl') + } + + if(attributes.customerHoldMusicUrl && !plivoUtils.validUrl('customerHoldMusicUrl', attributes.customerHoldMusicUrl, false)){ + throw new PlivoXMLError('Invalid attribute value ' + attributes.customerHoldMusicUrl + ' for customerHoldMusicUrl') + } + return this.add(new MultiPartyCall(Response), body, attributes); + }, + toXML: function () { return this.elem.toString(); }, @@ -521,7 +748,7 @@ function GetInput(Response) { this.element = 'GetInput'; this.valid_attributes = ['action', 'method', 'inputType', 'executionTimeout', 'digitEndTimeout', 'speechEndTimeout', 'finishOnKey', 'numDigits', - 'speechModel', 'hints','language', 'interimSpeechResultsCallback', + 'speechModel', 'hints','language', 'interimSpeechResultsCallback', 'interimSpeechResultsCallbackMethod', 'log', 'redirect', 'profanityFilter']; this.nestables = ['Speak', 'Play', 'Wait']; } @@ -741,4 +968,22 @@ function DTMF(Response) { this.valid_attributes = ['digits', 'async']; } -util.inherits(DTMF, Response); \ No newline at end of file +util.inherits(DTMF, Response); + +/** + * MultiPartyCall element + * @constructor + */ +function MultiPartyCall(Response){ + this.element = 'MultiPartyCall'; + this.nestables = []; + this.valid_attributes = ['role', 'maxDuration', 'maxParticipants', 'waitMusicUrl', + 'waitMusicMethod', 'agentHoldMusicUrl', 'agentHoldMusicMethod', + 'customerHoldMusicUrl', 'customerHoldMusicMethod', 'record', + 'recordFileFormat', 'recordingCallbackUrl', 'recordingCallbackMethod', + 'statusCallbackEvents', 'statusCallbackUrl', 'statusCallbackMethod', + 'stayAlone', 'coachMode', 'mute', 'hold', 'startMpcOnEnter', 'endMpcOnExit', + 'enterSound', 'enterSoundMethod', 'exitSound', 'exitSoundMethod', + 'onExitActionUrl', 'onExitActionMethod', 'relayDTMFInputs']; +} +util.inherits(MultiPartyCall, Response); diff --git a/package.json b/package.json index c4d3189..7df55cd 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "plivo", - "version": "4.14.2", + "version": "4.16.0", "description": "A Node.js SDK to make voice calls and send SMS using Plivo and to generate Plivo XML", "homepage": "https://github.com/plivo/plivo-node", "files": [ @@ -62,6 +62,7 @@ "axios": "^0.19.2", "base-64": "^0.1.0", "build-url": "^1.0.10", + "form-data": "^4.0.0", "jsonwebtoken": "^8.5.1", "lodash": "^4.17.4", "querystring": "^0.2.0", diff --git a/test/calls.js b/test/calls.js index f60efee..4e623a6 100644 --- a/test/calls.js +++ b/test/calls.js @@ -68,6 +68,7 @@ describe('calls', function () { client.calls.get(1) .then(function(call){ return call.transfer() + done() }) .then(function(call) { assert.equal(call.id, 5) diff --git a/test/multiPartyCalls.js b/test/multiPartyCalls.js new file mode 100644 index 0000000..c5887bc --- /dev/null +++ b/test/multiPartyCalls.js @@ -0,0 +1,95 @@ +import assert from 'assert'; +import sinon from 'sinon'; +import {Client} from '../lib/rest/client-test'; +import {PlivoGenericResponse} from '../lib/base.js'; +import {MultiPartyCall} from "../lib/resources/multiPartyCall"; + +let client = new Client('sampleid', 'sammpletoken', 'sampleproxy'); + +describe('multiPartyCalls', function (){ + it('should list all MultiPartyCalls', function (){ + return client.multiPartyCalls.list().then(function (response){ + for(let i=0; i< response.length;i++) { + assert(response[i] instanceof MultiPartyCall) + } + }) + }); + + it('should get details of a MultiPartyCall', function (){ + return client.multiPartyCalls.get('ca8e8a44-48e1-445d-afd5-1fcccdbccd9d').then(function (response){ + assert(response instanceof PlivoGenericResponse) + assert.equal(response.id, 'ca8e8a44-48e1-445d-afd5-1fcccdbccd9d') + assert.equal(response.resourceUri, '/v1/Account/MAMDJMMTEZOWY0ZMQWM2/MultiPartyCall/uuid_ca8e8a44-48e1-445d-afd5-1fcccdbccd9d/') + }) + }); + + it('should add a Participant', function (){ + return client.multiPartyCalls.addParticipant('Agent', {'friendlyName' : 'Voice', 'from' : '+919090909090', 'to' : '+918309866821'}).then(function (response){ + assert(response instanceof PlivoGenericResponse) + assert.equal(response.message, 'add participant action initiated') + }) + }); + + it('should start an MPC', function (){ + return client.multiPartyCalls.start(null, 'Voice').then(function (response){ + assert(response instanceof PlivoGenericResponse) + }) + }); + + it('should end an MPC', function (){ + return client.multiPartyCalls.stop(null, 'Voice').then(function (response){ + assert(response, true) + }) + }); + + it('should start MPC Recording', function (){ + return client.multiPartyCalls.startRecording(null, 'TestMPC').then(function (response){ + assert(response.message, "MPC: TestMPC record started") + }) + }); + + it('should stop MPC Recording', function (){ + return client.multiPartyCalls.stopRecording(null, 'TestMPC').then(function (response){ + assert(response instanceof PlivoGenericResponse) + }) + }); + + it('should pause MPC Recording', function (){ + return client.multiPartyCalls.pauseRecording(null, 'TestMPC').then(function (response){ + assert(response instanceof PlivoGenericResponse) + }) + }); + + it('should resume MPC Recording', function (){ + return client.multiPartyCalls.resumeRecording(null, 'TestMPC').then(function (response){ + assert(response instanceof PlivoGenericResponse) + }) + }); + + it('should list MPC Participants', function (){ + return client.multiPartyCalls.listParticipants('12345678-90123456', null).then(function (response){ + assert(response instanceof PlivoGenericResponse) + }) + }); + + it('should update MPC Participant', function (){ + return client.multiPartyCalls.updateParticipant(10, '12345678-90123456', null).then(function (response){ + assert(response instanceof PlivoGenericResponse) + assert.equal(response.hold, 'MPC: TestMPC hold/unhold member(s) succeded') + assert.equal(response.mute, 'MPC: TestMPC mute/unmute member(s) succeded') + }) + }); + + it('should kick MPC Participant', function (){ + return client.multiPartyCalls.kickParticipant(10, '12345678-90123456', null).then(function (response){ + assert(response instanceof PlivoGenericResponse) + }) + }); + + it('should get MPC Participant', function (){ + return client.multiPartyCalls.getParticipant(2132, '7503f05f-2d6e-4ab3-b9e6-3b0d81ae9087', null).then(function (response){ + assert(response instanceof PlivoGenericResponse) + assert.equal(response.resourceUri, '/v1/Account/MAMDJMMTEZOWY0ZMQWM2/MultiPartyCall/uuid_7503f05f-2d6e-4ab3-b9e6-3b0d81ae9087/Participant/2132/') + }) + }); +}) diff --git a/test/xml.js b/test/xml.js index efb2b60..b2ce224 100644 --- a/test/xml.js +++ b/test/xml.js @@ -29,4 +29,15 @@ describe('PlivoXML', function () { done("Failed to test Plivo Xml due to unknown error"); }); }); + + it('tests MultiPartyCall', function (done){ + const mpcResponse = new Response(); + mpcResponse.addMultiPartyCall('Nairobi',{ + role: 'Agent', + maxDuration: 1000, + statusCallbackEvents: 'participant-speak-events, participant-digit-input-events, add-participant-api-events, participant-state-changes, mpc-state-changes' + }); + assert.equal('Nairobi',mpcResponse.toXML()); + done(); + }) }); diff --git a/types/resources/complianceApplications.d.ts b/types/resources/complianceApplications.d.ts new file mode 100644 index 0000000..37b3a7d --- /dev/null +++ b/types/resources/complianceApplications.d.ts @@ -0,0 +1,146 @@ +export class ComplianceApplicationResponse { + constructor(params: object); + apiId: string; + complianceApplicationId: string; + endUserID: string; + endUserType: string; + alias: string; + status: string; + countryIso2: string; + numberType: string; + complianceRequirementId: string; + documents: Array; + createdAt: string; +} + +export class CreateComplianceApplicationResponse { + constructor(params: object); + apiId: string; + complianceApplicationId: string; + endUserID: string; + endUserType: string; + alias: string; + status: string; + countryIso2: string; + numberType: string; + complianceRequirementId: string; + documents: Array; + createdAt: string; + message: string; +} + +export class UpdateComplianceApplicationResponse { + constructor(params: object); + apiId: string; + message: string; +} + +export class ListComplianceApplicationResponse { + constructor(params: object); + apiId: string; + meta: Object; + objects: Array; +} + +/** +* Represents a ComplianceApplication +* @constructor +* @param {function} client - make api call +* @param {object} [data] - data of call +*/ +export class ComplianceApplication extends PlivoResource { + constructor(client: Function, data?: {}); + id: string; + + /** + * update ComplianceApplication + * @method + * @param {string} id - id to update + * @param {object} params + * @param {string} [params.documentIds] - Document IDs + * @promise {object} return {@link ComplianceApplication} object if success + * @fail {Error} return Error + */ + update(params: object, id: string): Promise; + + /** + * delete an Compliance application + * @method + * @param {string} id - id to delete + * @promise {boolean} return true if success + * @fail {Error} return Error + */ + delete(): Promise; + [clientKey]: symbol; +} + +/** +* Represents a ComplianceApplication Interface +* @constructor +* @param {function} client - make api call +* @param {object} [data] - data of call +*/ +export class ComplianceApplicationInterface extends PlivoResourceInterface { + constructor(client: Function, data?: {}); + /** + * get application by given id + * @method + * @param {string} id - id of application + * @promise {object} return {@link EndUser} object + * @fail {Error} return Error + */ + get(id: string): Promise; + + /** + * list all applications + * @method + * @param {object} params - params to list endusers + * @param {string} [params.status] - Status of the application + * @param {string} [params.endUserId] - End user ID related to application + * @param {string} [params.numberType] -Number Type related to application + * @param {integer} [params.offset] - No of value items by which results should be offset + * @param {integer} [params.limit] - No of value items by which results should be offset + */ + list(params: object): Promise; + + /** + * Create a complaince application + * @method + * @param {object} params + * @param {string} [params.complianceRequirementId] - compliance requirement ID. + * @param {string} [params.endUserId] - End user ID. + * @param {string} [params.alias] - Alias + * @param {string} [params.documentIds] - Document IDs + * @param {string} [params.endUserType] - End user type + * @param {string} [params.countryIso2] - CountryISo2 + * @param {string} [params.numberType] - Number Type + * @fail {Error} return Error + */ + create(params: object): Promise; + + /** + * update ComplianceApplication + * @method + * @param {string} id - id to update + * @param {object} params + * @param {string} [params.documentIds] - Document IDs + * @promise {object} return {@link ComplianceApplication} object if success + * @fail {Error} return Error + */ + update(id: string, params: object): Promise; + + /** + * delete a ComplianceApplication + * @method + * @param {string} id - id to delete + * @promise {boolean} return true if success + * @fail {Error} return Error + */ + delete(id: string): any; + [clientKey]: symbol; +} + +import { PlivoResource } from "../base"; +declare const clientKey: unique symbol; +import { PlivoResourceInterface } from "../base"; +export {}; diff --git a/types/resources/complianceDocumentTypes.d.ts b/types/resources/complianceDocumentTypes.d.ts new file mode 100644 index 0000000..2f30b50 --- /dev/null +++ b/types/resources/complianceDocumentTypes.d.ts @@ -0,0 +1,65 @@ +export class ComplianceDocumentTypeResponse { + constructor(params: object); + apiId: string; + documentTypeID: string; + documentName: string; + description: string; + information: object; + proofRequired: string; + createdAt: string; +} + +export class ListComplianceDocumentTypeResponse { + constructor(params: object); + apiId: string; + objects: Array; + meta: Object; +} + +/** +* Represents a Compliance Document Type. +* @constructor +* @param {function} client - make api call +* @param {object} [data] - data of call +*/ +export class ComplianceDocumentType extends PlivoResource { + constructor(client: Function, data?: {}); + [clientKey]: symbol; +} + +/** +* Represents a ComplianceDocumentTypeInterface Interface +* @constructor +* @param {function} client - make api call +* @param {object} [data] - data of call +*/ +export class ComplianceDocumentTypeInterface extends PlivoResourceInterface { + constructor(client: Function, data?: {}); + + /** + * get compliance document types by id + * @method + * @param {string} id - id of the compliane document type. + * @promise {object} return {@link ComplianceDocumentType} object + * @fail {Error} return Error + */ + get(id: string): Promise; + + + /** + * list compliance document types + * @method + * @param {object} params - params to list endusers + * @param {string} [params.documentTypeID] - Document Type ID of the document id. + * @param {string} [params.documentName] - Document name of the document if present. + * @param {string} [params.description] - Description of the document type. + * @param {string} [params.information] - Information about the document type. + * @param {string} [params.proofRequired] - Proofs required for the document. + */ + list(params: object): Promise; +} + +import { PlivoResource } from "../base"; +declare const clientKey: unique symbol; +import { PlivoResourceInterface } from "../base"; +export {}; diff --git a/types/resources/complianceDocuments.d.ts b/types/resources/complianceDocuments.d.ts new file mode 100644 index 0000000..cb2b8ee --- /dev/null +++ b/types/resources/complianceDocuments.d.ts @@ -0,0 +1,134 @@ +export class ComplianceDocumentResponse { + constructor(params: object); + apiId: string; + documentTypeId: string; + complianceDocumentId: string; + documentId: string; + alias: string; + metaInformation: string; + file: string; + fileName: string; + createdAt: string; +} + +export class CreateComplianceDocumentResponse { + constructor(params: object); + apiId: string; + documentTypeId: string; + complianceDocumentId: string; + documentId: string; + endUserId: string; + alias: string; + message: string; + metaInformation: string; + fileName: string; + createdAt: string; +} + +export class ListComplianceDocumentResponse { + constructor(params: object); + apiId: string; + meta: Object; + objects: Array; +} + +export class UpdateComplianceDocumentResponse { + constructor(params: object); + apiId: string; + message: string; +} +/** +* Represents a Compliance Document +* @constructor +* @param {function} client - make api call +* @param {object} [data] - data of call +*/ +export class ComplianceDocument extends PlivoResource { + constructor(client: Function, data?: {}); + id: string; + + /** + * update Compliance Document + * @method + * @param {string} id - compliance document id of the document. + * @param {object} params - optional params array of updated values + * @promise {object} return {@link ComplianceDocument} object if success + * @fail {Error} return Error + */ + update(params: object, id: string): Promise; + + /** + * delete an Compliance Document + * @method + * @param {string} id - id to delete + * @promise {boolean} return true if success + * @fail {Error} return Error + */ + delete(): Promise; + [clientKey]: symbol; +} + +/** +* Represents a ComplianceDocument Interface +* @constructor +* @param {function} client - make api call +* @param {object} [data] - data of call +*/ +export class ComplianceDocumentInterface extends PlivoResourceInterface { + constructor(client: Function, data?: {}); + + /** + * get compliance document by given id + * @method + * @param {string} id - id of the document + * @promise {object} return {@link ComplianceDocument} object + * @fail {Error} return Error + */ + get(id: string): Promise; + + + /** + * list all documents + * @method + * @param {object} params - params containing options to list compliance documents by. + */ + list(params: object): Promise; + + /** + * Create a complaince document + * @method + * @param {object} params + * @param {string} [params.complianceRequirementId] - compliance requirement ID. + * @param {string} [params.endUserId] - End user ID. + * @param {string} [params.alias] - Alias + * @param {string} [params.documentTypeId] - Document Type ID + * @param {string} [params.file] - File array of the files to be uploaded + * @fail {Error} return Error + */ + create(params: object): Promise; + + /** + * update Compliance Document + * @method + * @param {string} id - compliance document id of the document. + * @param {object} params - optional params array of updated values + * @promise {object} return {@link ComplianceDocument} object if success + * @fail {Error} return Error + */ + update(id: string, params: object): Promise; + + /** + * delete a Compliance Document + * @method + * @param {string} id - id to delete + * @promise {boolean} return true if success + * @fail {Error} return Error + */ + delete(id: string): any; + [clientKey]: symbol; +} + +import { PlivoResource } from "../base"; +declare const clientKey: unique symbol; +import { PlivoResourceInterface } from "../base"; +export {}; diff --git a/types/resources/complianceRequirements.d.ts b/types/resources/complianceRequirements.d.ts new file mode 100644 index 0000000..c60b44f --- /dev/null +++ b/types/resources/complianceRequirements.d.ts @@ -0,0 +1,58 @@ +export class ComplianceRequirementResponse { + constructor(params: object); + apiId: string; + ComplianceRequirementId: string; + countryIso2: string; + numberType: string; + endUserType: object; + acceptableDocumentTypes: string; +} + +/** +* Represents a Compliance Requirement +* @constructor +* @param {function} client - make api call +* @param {object} [data] - data of call +*/ +export class ComplianceRequirement extends PlivoResource { + constructor(client: Function, data?: {}); + [clientKey]: symbol; +} + +/** + * Represents a Compliance Requirement + * @constructor + * @param {function} client - make api call + * @param {object} [data] - data of call + */ +export class ComplianceRequirementInterface extends PlivoResourceInterface { + constructor(client: Function, data?: {}); + + /** + * get compliance requirement by given id + * @method + * @param {string} id - id of the compliance requirement + * @promise {object} return {@link ComplianceRequirement} object + * @fail {Error} return Error + */ + get(id: string): Promise; + + + /** + * list compliance requirements + * @method + * @param {object} params - params to list endusers + * @param {string} [params.countryIso2] - Document Type ID of the document id. + * @param {string} [params.numberType] - Document name of the document if present. + * @param {string} [params.phoneNumber] - Description of the document type. + * @param {string} [params.endUserType] - Information about the document type. + * A combination of country_iso2, number_type, end_user_type OR + * phone_number, end_user_type can be used to fetch compliance requirements. + */ + list(params: object): Promise; +} + +import { PlivoResource } from "../base"; +declare const clientKey: unique symbol; +import { PlivoResourceInterface } from "../base"; +export {}; diff --git a/types/resources/endUsers.d.ts b/types/resources/endUsers.d.ts new file mode 100644 index 0000000..fbdca55 --- /dev/null +++ b/types/resources/endUsers.d.ts @@ -0,0 +1,131 @@ +export class EndUsersResponse { + constructor(params: object); + apiId: string; + endUserId: string; + endUserType: string; + name: string; + lastName: string; + createdAt: string; +} + +export class CreateEndUsersResponse { + constructor(params: object); + apiId: string; + endUserId: string; + endUserType: string; + name: string; + lastName: string; + createdAt: string; + message: string; +} + +export class UpdateEndUsersResponse { + constructor(params: object); + apiId: string; + message: string; +} + +export class ListEndUsersResponse { + constructor(params: object); + apiId: string; + meta: Object; + objects: Array; +} + +/** +* Represents an EndUser +* @constructor +* @param {function} client - make api call +* @param {object} [data] - data of call +*/ +export class EndUser extends PlivoResource { + constructor(client: Function, data?: {}); + id: string; + /** + * update end user + * @method + * @param {object} params - to update end user + * @param {string} [params.name] - Name of the endUser if present. + * @param {string} [params.last_name] - Last name of the endUser if present. + * @param {string} [params.end_user_type] - Type of the end user. + * @fail {Error} return Error + */ + + update(params: object, id: string): Promise; + /** + * delete EndUser + * @method + * @promise {boolean} return true if success + * @fail {Error} return Error + */ + delete(): Promise; + [clientKey]: symbol; +} + +/** +* Represents a EndUser Interface +* @constructor +* @param {function} client - make api call +* @param {object} [data] - data of call +*/ +export class EndUserInterface extends PlivoResourceInterface { + constructor(client: Function, data?: {}); + /** + * get EndUser by given id + * @method + * @param {string} id - id of the end user. + * @promise {object} return {@link EndUser} object + * @fail {Error} return Error + */ + get(id: string): Promise; + + + /** + * list endUsers + * @method + * @param {object} params - params to list endusers + * @param {string} [params.name] - Name of the endUser if present. + * @param {string} [params.last_name] - Last name of the endUser if present. + * @param {string} [params.end_user_type] - Type of the end user. + * @param {integer} [params.offset] - No of value items by which results should be offset + * @param {integer} [params.limit] - No of value items by which results should be offset + */ + list(params: object): Promise; + + /** + * Create end user + * @method + * @param {object} params - to update end user + * @param {string} [params.name] - Name of the endUser if present. + * @param {string} [params.last_name] - Last name of the endUser if present. + * @param {string} [params.end_user_type] - Type of the end user. + * @fail {Error} return Error + */ + create(params: object): Promise; + + /** + * update end user + * @method + * @param {object} params - to update end user + * @param {string} [params.name] - Name of the endUser if present. + * @param {string} [params.last_name] - Last name of the endUser if present. + * @param {string} [params.end_user_type] - Type of the end user. + * @fail {Error} return Error + */ + update(id: string, params: object): Promise; + + /** + * delete an EndUser + * @method + * @param {string} id - id to delete + * @promise {boolean} return true if success + * @fail {Error} return Error + */ + delete(id: string): any; + [clientKey]: symbol; +} + +import { PlivoResource } from "../base"; +declare const clientKey: unique symbol; +import { PlivoResourceInterface } from "../base"; +export {}; diff --git a/types/rest/client.d.ts b/types/rest/client.d.ts index ced5bb3..641839b 100644 --- a/types/rest/client.d.ts +++ b/types/rest/client.d.ts @@ -23,6 +23,11 @@ export class Client { recordings: RecordingInterface; callFeedback: CallFeedbackInterface; media: MediaInterface; + endUsers: EndUserInterface; + complianceDocumentTypes: ComplianceDocumentTypeInterface; + complianceDocuments: ComplianceDocumentInterface; + complianceRequirements: ComplianceRequirementInterface; + complianceApplications: ComplianceApplicationInterface; toJSON(...args: any[]): any; } /**