From a6aea858a1949cd5ab0a617bbcb964c3cc8020a0 Mon Sep 17 00:00:00 2001 From: Koushik-Ayila Date: Tue, 16 Mar 2021 15:47:41 +0530 Subject: [PATCH 01/35] Fixed bug on call stop Recording API --- lib/resources/call.js | 9 +++++---- lib/resources/recordings.js | 6 ++++-- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/lib/resources/call.js b/lib/resources/call.js index fc9a324..e046eb7 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, 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 +} From 7ee53ba63848a060a54c02afa3d3fe6b858825d2 Mon Sep 17 00:00:00 2001 From: huzaif Date: Wed, 24 Mar 2021 17:46:56 +0530 Subject: [PATCH 02/35] Fixed Isvoicerequest within voice api --- lib/resources/applications.js | 3 +++ lib/resources/call.js | 19 ++++++++----------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/lib/resources/applications.js b/lib/resources/applications.js index d8895dd..7d653f5 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) diff --git a/lib/resources/call.js b/lib/resources/call.js index e046eb7..625c375 100644 --- a/lib/resources/call.js +++ b/lib/resources/call.js @@ -233,7 +233,7 @@ export class Call extends PlivoResource { * @fail {Error} return Error */ record(params= {}) { - params.isVoiceRequest = true; + params.isVoiceRequest = 'true'; return this.startRecording(params); } @@ -917,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 => { @@ -937,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 => { @@ -947,7 +946,7 @@ class LiveCallInterface extends PlivoResourceInterface { callUuid: callUuid })); }); - resolve(new ListAllLiveCallResponse(calls[0])); + resolve(calls); }) .catch(error => { reject(error); @@ -995,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 => { @@ -1014,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 => { @@ -1025,7 +1022,7 @@ class QueuedCallInterface extends PlivoResourceInterface { callUuid: callUuid })); }); - resolve(new ListAllQueuedCalls(calls[0])); + resolve(calls); }) .catch(error => { reject(error); From 48a227bee1a48c9b196a826830c5f07cb407ae8b Mon Sep 17 00:00:00 2001 From: Koushik-Ayila Date: Fri, 26 Mar 2021 11:44:37 +0530 Subject: [PATCH 03/35] Updated SDK versioning --- CHANGELOG.md | 3 +++ package.json | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1052162..8a7c67c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ # Change Log +## [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/package.json b/package.json index c4d3189..d8ff1dd 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "plivo", - "version": "4.14.2", + "version": "4.14.3", "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": [ From 980634eb025bbcafb7611fd3fa1516cc4fefe82e Mon Sep 17 00:00:00 2001 From: gunjan01 Date: Thu, 11 Mar 2021 23:40:10 +0530 Subject: [PATCH 04/35] Integrate node apis for compliance --- examples/complianceApplications.js | 45 +++ examples/complianceDocumentTypes.js | 21 ++ examples/complianceDocuments.js | 34 +++ examples/complianceRequirements.js | 22 ++ examples/endUsers.js | 37 +++ lib/resources/complianceApplications.js | 281 +++++++++++++++++++ lib/resources/complianceDocumentTypes.js | 110 ++++++++ lib/resources/complianceDocuments.js | 262 +++++++++++++++++ lib/resources/complianceRequirements.js | 100 +++++++ lib/resources/endUsers.js | 254 +++++++++++++++++ lib/resources/numbers.js | 2 +- lib/rest/axios.js | 60 ++++ lib/rest/client.js | 10 + lib/rest/utils.js | 3 +- types/resources/complianceApplications.d.ts | 146 ++++++++++ types/resources/complianceDocumentTypes.d.ts | 65 +++++ types/resources/complianceDocuments.d.ts | 134 +++++++++ types/resources/complianceRequirements.d.ts | 58 ++++ types/resources/endUsers.d.ts | 131 +++++++++ types/rest/client.d.ts | 5 + 20 files changed, 1778 insertions(+), 2 deletions(-) create mode 100644 examples/complianceApplications.js create mode 100644 examples/complianceDocumentTypes.js create mode 100644 examples/complianceDocuments.js create mode 100644 examples/complianceRequirements.js create mode 100644 examples/endUsers.js create mode 100644 lib/resources/complianceApplications.js create mode 100644 lib/resources/complianceDocumentTypes.js create mode 100644 lib/resources/complianceDocuments.js create mode 100644 lib/resources/complianceRequirements.js create mode 100644 lib/resources/endUsers.js create mode 100644 types/resources/complianceApplications.d.ts create mode 100644 types/resources/complianceDocumentTypes.d.ts create mode 100644 types/resources/complianceDocuments.d.ts create mode 100644 types/resources/complianceRequirements.d.ts create mode 100644 types/resources/endUsers.d.ts 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/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..b50eddf --- /dev/null +++ b/lib/resources/complianceDocuments.js @@ -0,0 +1,262 @@ +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 => { + resolve(new CreateComplianceDocumentResponse(response.body, idField)); + }) + .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(); + } +} \ No newline at end of file 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/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/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.js b/lib/rest/client.js index be78627..60a8fce 100644 --- a/lib/rest/client.js +++ b/lib/rest/client.js @@ -20,6 +20,11 @@ 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"; exports.Response = function() { return new Response(); @@ -82,6 +87,11 @@ 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); } toJSON() { diff --git a/lib/rest/utils.js b/lib/rest/utils.js index 1ece32a..a456cae 100644 --- a/lib/rest/utils.js +++ b/lib/rest/utils.js @@ -47,7 +47,8 @@ export function camelCaseRequestWrapper(requestFunc) { .replace('_greater_or_equal', '__gte') .replace('_less_or_equal', '__lte') .replace('_equal', '') - .replace('_equals', ''); + .replace('_equals', '') + .replace('country_iso_2', 'country_iso2'); }); return requestFunc(method, action, params).then(res => { 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; } /** From e5e6478204f5efef54c38306a66490f3896682a0 Mon Sep 17 00:00:00 2001 From: gunjan01 Date: Fri, 16 Apr 2021 18:13:45 +0530 Subject: [PATCH 05/35] Remove empty keys from compliance create response --- lib/resources/complianceDocuments.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/resources/complianceDocuments.js b/lib/resources/complianceDocuments.js index b50eddf..8235554 100644 --- a/lib/resources/complianceDocuments.js +++ b/lib/resources/complianceDocuments.js @@ -207,7 +207,9 @@ export class ComplianceDocumentInterface extends PlivoResourceInterface { params.multipart = true; client('POST', action, params) .then(response => { - resolve(new CreateComplianceDocumentResponse(response.body, idField)); + let object = new CreateComplianceDocumentResponse(response.body, idField); + Object.keys(object).forEach(key => object[key] === undefined && delete object[key]); + resolve(object); }) .catch(error => { reject(error); @@ -259,4 +261,4 @@ export class ComplianceDocumentInterface extends PlivoResourceInterface { id: id }).delete(); } -} \ No newline at end of file +} From 4a880c98f000efffb3bd225b02e9a040cbd59119 Mon Sep 17 00:00:00 2001 From: gunjan01 Date: Fri, 16 Apr 2021 18:36:39 +0530 Subject: [PATCH 06/35] Add new dependency for multipart requests --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index d8ff1dd..f27332f 100644 --- a/package.json +++ b/package.json @@ -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", From cbf4617aa57a4787127b1d80bae7c9b7f0dc0732 Mon Sep 17 00:00:00 2001 From: gunjan01 Date: Fri, 16 Apr 2021 19:18:41 +0530 Subject: [PATCH 07/35] Add client tests --- lib/rest/client-test.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/rest/client-test.js b/lib/rest/client-test.js index b8bd8cc..bf709ed 100644 --- a/lib/rest/client-test.js +++ b/lib/rest/client-test.js @@ -90,6 +90,11 @@ 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); } } From e3e813a3706347899118fd45d63bbba6cc6786ae Mon Sep 17 00:00:00 2001 From: kalyan-plivo <49232630+kalyan-plivo@users.noreply.github.com> Date: Mon, 19 Apr 2021 11:08:30 +0530 Subject: [PATCH 08/35] bump version --- CHANGELOG.md | 4 ++++ package.json | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8a7c67c..e9fa7fd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Change Log +## [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. diff --git a/package.json b/package.json index f27332f..ddd9b7b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "plivo", - "version": "4.14.3", + "version": "4.15.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": [ From 957817f3057f608c22a26826ff46c70ad5a5673b Mon Sep 17 00:00:00 2001 From: Koushik-Ayila Date: Fri, 14 Aug 2020 16:54:31 +0530 Subject: [PATCH 09/35] XML changes for MPC along with UTs --- lib/rest/utils.js | 81 ++++++++++++++ lib/utils/plivoxml.js | 253 +++++++++++++++++++++++++++++++++++++++++- test/xml.js | 11 ++ 3 files changed, 341 insertions(+), 4 deletions(-) diff --git a/lib/rest/utils.js b/lib/rest/utils.js index a456cae..ae07f46 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; @@ -79,3 +81,82 @@ export function validateSpeakAttributes(content, voice) { } } +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') + } + } +} + +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 = paramName.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) === -1) || !(expectedValues.indexOf(paramValue) === -1)){ + return true; + } + else if (validUrl(paramName, paramValue)){ + return true; + } + else { + throw new InvalidRequestError(paramName + ' neither a valid URL nor in the expected values') + } +} diff --git a/lib/utils/plivoxml.js b/lib/utils/plivoxml.js index 577ce9f..d28595b 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/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(); + }) }); From 326831d98cd4000f27549628d903c0fedff5f558 Mon Sep 17 00:00:00 2001 From: Koushik-Ayila Date: Wed, 26 Aug 2020 11:31:13 +0530 Subject: [PATCH 10/35] MPC API - Under Development --- lib/base.js | 15 + lib/resources/multiPartyCall.js | 559 ++++++++++++++++++++++++++++++++ lib/rest/client.js | 2 + lib/rest/utils.js | 127 +++++++- 4 files changed, 700 insertions(+), 3 deletions(-) create mode 100644 lib/resources/multiPartyCall.js diff --git a/lib/base.js b/lib/base.js index 3ed6040..e374e7c 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,18 @@ 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; +// } +// } + export class PlivoResourceInterface { constructor(action, klass, idField, request) { this[actionKey] = action; diff --git a/lib/resources/multiPartyCall.js b/lib/resources/multiPartyCall.js new file mode 100644 index 0000000..6099bac --- /dev/null +++ b/lib/resources/multiPartyCall.js @@ -0,0 +1,559 @@ +import {extend, validate} from '../utils/common.js'; +import {PlivoResource, PlivoResourceInterface} 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(){ + return super.executeAction(this.id, 'GET'); + } + + 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') + } + + if(params.role){ + 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){ + validRange('ringTimeout', params.ringTimeout, false, 15, 120) + } + else { + params.ringTimeout = 45 + } + + if(params.maxDuration){ + validRange('maxDuration', params.maxDuration, false, 300, 28800) + } + else { + params.maxDuration = 14400 + } + + if(params.maxParticipants){ + 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], 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], false) + } + else { + params.stayAlone = false + } + + if(params.coachMode){ + validParam('coachMode', params.coachMode, [Boolean], false) + } + else { + params.coachMode = true + } + + if(params.mute){ + validParam('mute', params.mute, [Boolean], false) + } + else { + params.mute = false + } + + if(params.hold){ + validParam('hold', params.hold, [Boolean], false) + } + else { + params.hold = false + } + + if(params.startMpcOnEnter){ + validParam('startMpcOnEnter', params.startMpcOnEnter, [Boolean], false) + } + else { + params.startMpcOnEnter = false + } + + if(params.endMpcOnExit){ + validParam('endMpcOnExit', params.endMpcOnExit, [Boolean], false) + } + else { + params.endMpcOnExit = false + } + + if(params.relayDTMFInputs){ + validParam('relayDTMFInputs', params.relayDTMFInputs, [Boolean], 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' + } + + return super.executeAction(this.id + '/Participant', 'POST', params) + } + + start(){ + return super.executeAction(this.id, 'POST', {'status' : 'active'}) + } + + stop(){ + return super.delete() + } + + 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' + } + + return super.executeAction(this.id + '/Record', 'POST', params) + } + + stopRecording(){ + return super.executeAction(this.id + '/Record', 'DELETE') + } + + pauseRecording(){ + return super.executeAction(this.id + '/Record/Pause', 'POST') + } + + resumeRecording(){ + return super.executeAction(this.id + '/Record/Resume', 'POST') + } + + listParticipants(params = {}){ + if(params.callUuid){ + validParam('callUuid', params.callUuid, [String], false) + } + + 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; +// } +// +// } + +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 MultiPartyCalls + * @method + * @param {object} params + * @param {string} [params.subAccount] + * @param {string} [params.friendlyName] + * @param {string} [params.status] + * @param {number} [params.terminationCauseCode] + * @param {Date} [params.end_time__gt] + * @param {Date} [params.end_time__gte] + * @param {Date} [params.end_time__lt] + * @param {Date} [params.end_time__lte] + * @param {Date} [params.creation_time__gt] + * @param {Date} [params.creation_time__gte] + * @param {Date} [params.creation_time__lt] + * @param {Date} [params.creation_time__lte] + * @param {number} [params.limit] + * @param {number} [params.offset] + */ + 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], 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) + } + + 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 = {}){ + let errors = validate([ + {field: 'friendly_name', value: params.friendlyName, validators: ['isString']} + ]); + if (errors) { + return errors; + } + 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) + } + + +} diff --git a/lib/rest/client.js b/lib/rest/client.js index 60a8fce..492c32d 100644 --- a/lib/rest/client.js +++ b/lib/rest/client.js @@ -25,6 +25,7 @@ import { ComplianceDocumentTypeInterface } from "../resources/complianceDocument 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(); @@ -92,6 +93,7 @@ export class 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/utils.js b/lib/rest/utils.js index ae07f46..bf79ca9 100644 --- a/lib/rest/utils.js +++ b/lib/rest/utils.js @@ -81,6 +81,63 @@ 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; @@ -88,14 +145,15 @@ export function expectedValue(paramName, expectedValues, paramValue){ if(expectedValues.constructor === Array){ if(expectedValues.indexOf(paramValue) === -1){ - throw new InvalidRequestError(paramName + ': Expected one of ' + expectedValues + 'but received' + paramValue + 'instead'); + 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') + throw new InvalidRequestError(paramName + ': Expected ' + expectedValues + ' but received ' + paramValue + ' instead') } + return true; } } @@ -132,7 +190,7 @@ export function validUrl(paramName, paramValue, mandatory = false){ return true; } - let response = paramName.match(/(http(s)?:\/\/.)?(www\.)?[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)/g); + 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") } @@ -160,3 +218,66 @@ export function isOneAmongStringUrl(paramName, paramValue, mandatory = false, ex 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){ + 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") + } +} From 93c85714a9cda909909a73debd24fe3827f800f0 Mon Sep 17 00:00:00 2001 From: Koushik-Ayila Date: Wed, 26 Aug 2020 21:40:55 +0530 Subject: [PATCH 11/35] MPC API changes, TODO : Dev Testing --- lib/base.js | 46 +++++++++----- lib/resources/multiPartyCall.js | 105 ++++++++++++++++++++++++++------ 2 files changed, 117 insertions(+), 34 deletions(-) diff --git a/lib/base.js b/lib/base.js index e374e7c..29834c8 100644 --- a/lib/base.js +++ b/lib/base.js @@ -4,9 +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'); +let secondaryActionKey = Symbol('api action'); +let secondaryKlassKey = Symbol('constructor'); +let secondaryIdKey = Symbol('id filed'); export class PlivoGenericResponse { constructor(params, idString) { @@ -126,17 +126,35 @@ 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; -// } -// } +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) { diff --git a/lib/resources/multiPartyCall.js b/lib/resources/multiPartyCall.js index 6099bac..2eb71d8 100644 --- a/lib/resources/multiPartyCall.js +++ b/lib/resources/multiPartyCall.js @@ -1,5 +1,5 @@ import {extend, validate} from '../utils/common.js'; -import {PlivoResource, PlivoResourceInterface} from '../base'; +import {PlivoResource, PlivoResourceInterface, PlivoSecondaryResource} from '../base'; import { validSubAccount, validUrl, @@ -13,8 +13,8 @@ import { const clientKey = Symbol(); const action = 'MultiPartyCall/'; const idField = 'mpcUuid'; -// const secondaryAction = 'Participant/'; -// const secondaryIdField = 'participantUuid'; +const secondaryAction = 'Participant/'; +const secondaryIdField = 'participantUuid'; export class MPCError extends Error { } @@ -338,23 +338,47 @@ export class MultiPartyCall extends PlivoResource{ } } -// 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; -// } -// -// } +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], false) + } + + if(params.mute){ + validParam('mute', params.mute, [Boolean], false) + } + + if(params.hold){ + validParam('hold', params.hold, [Boolean], false) + } + + return super.executeAction(this.id, this.secondaryId, 'POST', params) + } + + kickParticipant(){ + return super.executeAction(this.id, this.secondaryId, 'DELETE') + } + + getParticipant(){ + return super.executeAction(this.id, this.secondaryId, 'GET') + } + +} export class MultiPartyCallInterface extends PlivoResourceInterface{ constructor(client, data = {}) { @@ -555,5 +579,46 @@ export class MultiPartyCallInterface extends PlivoResourceInterface{ return new MultiPartyCall(this[clientKey], {id: mpcId[0] + mpcId[1]}).listParticipants(params) } + updateParticipant(participantId, uuid= null, friendlyName = null, params){ + if(participantId){ + 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){ + if(participantId){ + 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){ + if(participantId){ + 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() + } } From b59e57cf9a8c7624905665a7481fff341324b25f Mon Sep 17 00:00:00 2001 From: Koushik-Ayila Date: Mon, 31 Aug 2020 16:01:14 +0530 Subject: [PATCH 12/35] Example Script --- example_script.js | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 example_script.js diff --git a/example_script.js b/example_script.js new file mode 100644 index 0000000..5c762a7 --- /dev/null +++ b/example_script.js @@ -0,0 +1,47 @@ +let plivo = require('./'); +var client = new plivo.Client('MAMDJMMTEZOWY0ZMQWM2', 'OTljNmVmOGVkNGZhNjJlOWIyMWM0ZDI0ZjQwZDdk'); + +// client.calls.create( "+919090909090", // from +// "sip:koushikqa119062465586783372208@phone-qa.voice.plivodev.com", // to +// "https://plivobin.non-prod.plivops.com/api/v1/Conference_test07.xml").then(function (response) { +// console.log(response); +// }, function (err) { +// console.error(err); +// }); + +// client.calls.transfer( +// "35283f77-a738-4d91-81dc-9f565e28d74c", {"legs": "aleg", "alegUrl": "https://www.google.com"}).then(function (response) { +// console.log(response); +// }, function (err) { +// console.error(err); +// }); + +// client.calls.sendDigits( +// "bfc3f1fd-d66b-42ab-88e4-9e82c8e2537f", // call uuid +// 123, // digits +// { +// 'leg': 'aleg' +// } +// ).then(function (response) { +// console.log(response); +// }, function (err) { +// console.error(err); +// }); + +// client.conferences.startRecording('FStestconference').then(function (response) { +// console.log(response); +// }, function (err) { +// console.error(err); +// }); + +client.multiPartyCalls.addParticipant({'friendlyName' : 'TestMPC', 'from' : '+919090909090', 'to': 'sip:koushikqa119062465586783372208@phone-qa.voice.plivodev.com'}).then(function (response) { + console.log(response); +}, function (err) { + console.error(err); +}); + +// client.multiPartyCalls.list().then(function (response) { +// console.log(response); +// }, function (err) { +// console.error(err); +// }); From f2f3ec5ba0f7b285219082685bae8d3de3ceb8c5 Mon Sep 17 00:00:00 2001 From: Koushik-Ayila Date: Tue, 1 Sep 2020 16:39:44 +0530 Subject: [PATCH 13/35] Reverted back to original --- example_script.js | 2 +- lib/resources/multiPartyCall.js | 29 ++++------------------------- 2 files changed, 5 insertions(+), 26 deletions(-) diff --git a/example_script.js b/example_script.js index 5c762a7..5b8483e 100644 --- a/example_script.js +++ b/example_script.js @@ -34,7 +34,7 @@ var client = new plivo.Client('MAMDJMMTEZOWY0ZMQWM2', 'OTljNmVmOGVkNGZhNjJlOWIyM // console.error(err); // }); -client.multiPartyCalls.addParticipant({'friendlyName' : 'TestMPC', 'from' : '+919090909090', 'to': 'sip:koushikqa119062465586783372208@phone-qa.voice.plivodev.com'}).then(function (response) { +client.multiPartyCalls.addParticipant('agent', {"friendlyName" : "TestMPC", 'from' : '+919090909090', 'to': 'sip:koushikqa119062465586783372208@phone-qa.voice.plivodev.com'}).then(function (response) { console.log(response); }, function (err) { console.error(err); diff --git a/lib/resources/multiPartyCall.js b/lib/resources/multiPartyCall.js index 2eb71d8..9a049ef 100644 --- a/lib/resources/multiPartyCall.js +++ b/lib/resources/multiPartyCall.js @@ -45,9 +45,7 @@ export class MultiPartyCall extends PlivoResource{ throw new MPCError('specify (from, to) when not adding an existing callUuid to multi party participant') } - if(params.role){ - validParam('role', params.role.toLowerCase(), [String], true, ['agent', 'supervisor', 'customer']) - } + validParam('role', params.role.toLowerCase(), [String], true, ['agent', 'supervisor', 'customer']) if(params.from){ validParam('from', params.from, [String], false) @@ -295,7 +293,7 @@ export class MultiPartyCall extends PlivoResource{ return super.delete() } - startRecording(params){ + startRecording(params){ if(params.fileFormat){ validParam('fileFormat', params.fileFormat, [String], false, ['mp3', 'wav']) } @@ -405,25 +403,6 @@ export class MultiPartyCallInterface extends PlivoResourceInterface{ return identifier; } - /** - * List MultiPartyCalls - * @method - * @param {object} params - * @param {string} [params.subAccount] - * @param {string} [params.friendlyName] - * @param {string} [params.status] - * @param {number} [params.terminationCauseCode] - * @param {Date} [params.end_time__gt] - * @param {Date} [params.end_time__gte] - * @param {Date} [params.end_time__lt] - * @param {Date} [params.end_time__lte] - * @param {Date} [params.creation_time__gt] - * @param {Date} [params.creation_time__gte] - * @param {Date} [params.creation_time__lt] - * @param {Date} [params.creation_time__lte] - * @param {number} [params.limit] - * @param {number} [params.offset] - */ list(params={}) { if(params.subAccount){ validSubAccount(params.subAccount); @@ -482,7 +461,7 @@ export class MultiPartyCallInterface extends PlivoResourceInterface{ return new MultiPartyCall(this[clientKey], {id: mpcId[0] + mpcId[1]}).get(); } - addParticipant(role, params = {}){ + addParticipant( role = 'agent', params = {}){ let errors = validate([ {field: 'friendly_name', value: params.friendlyName, validators: ['isString']} ]); @@ -495,10 +474,10 @@ export class MultiPartyCallInterface extends PlivoResourceInterface{ if(params.friendlyName){ validParam('friendlyName', params.friendlyName, [String], false) } + console.log(params.friendlyName); 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) } From 4db015960bba98949b75f2f96c396d3fcc92f6d1 Mon Sep 17 00:00:00 2001 From: Koushik-Ayila Date: Tue, 1 Sep 2020 16:50:11 +0530 Subject: [PATCH 14/35] Reverted back to original --- example_script.js | 2 +- lib/resources/multiPartyCall.js | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/example_script.js b/example_script.js index 5b8483e..4ec220a 100644 --- a/example_script.js +++ b/example_script.js @@ -34,7 +34,7 @@ var client = new plivo.Client('MAMDJMMTEZOWY0ZMQWM2', 'OTljNmVmOGVkNGZhNjJlOWIyM // console.error(err); // }); -client.multiPartyCalls.addParticipant('agent', {"friendlyName" : "TestMPC", 'from' : '+919090909090', 'to': 'sip:koushikqa119062465586783372208@phone-qa.voice.plivodev.com'}).then(function (response) { +client.multiPartyCalls.addParticipant('agent', {'friendlyName' : 'TestMPC', 'from' : '+919090909090', 'to': 'sip:koushikqa119062465586783372208@phone-qa.voice.plivodev.com'}).then(function (response) { console.log(response); }, function (err) { console.error(err); diff --git a/lib/resources/multiPartyCall.js b/lib/resources/multiPartyCall.js index 9a049ef..1911b04 100644 --- a/lib/resources/multiPartyCall.js +++ b/lib/resources/multiPartyCall.js @@ -478,6 +478,7 @@ export class MultiPartyCallInterface extends PlivoResourceInterface{ 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) } From 3e297f9ef3787b727cffaadd6fc34859d0e8b5d3 Mon Sep 17 00:00:00 2001 From: Koushik-Ayila Date: Tue, 8 Sep 2020 00:40:30 +0530 Subject: [PATCH 15/35] MPC API and XML changes - Dev completed --- example_script.js | 33 +++- lib/base.js | 2 +- lib/resources/multiPartyCall.js | 71 ++++---- lib/rest/client-test.js | 2 + lib/rest/request-test.js | 300 ++++++++++++++++++++++++++++++++ lib/rest/utils.js | 4 +- lib/utils/plivoxml.js | 58 +++--- test/multiPartyCalls.js | 95 ++++++++++ 8 files changed, 486 insertions(+), 79 deletions(-) create mode 100644 test/multiPartyCalls.js diff --git a/example_script.js b/example_script.js index 4ec220a..f71399d 100644 --- a/example_script.js +++ b/example_script.js @@ -2,12 +2,18 @@ let plivo = require('./'); var client = new plivo.Client('MAMDJMMTEZOWY0ZMQWM2', 'OTljNmVmOGVkNGZhNjJlOWIyMWM0ZDI0ZjQwZDdk'); // client.calls.create( "+919090909090", // from -// "sip:koushikqa119062465586783372208@phone-qa.voice.plivodev.com", // to +// "+918309866821", // to // "https://plivobin.non-prod.plivops.com/api/v1/Conference_test07.xml").then(function (response) { // console.log(response); // }, function (err) { // console.error(err); // }); +// +// client.conferences.get( "FStestconference").then(function (response) { +// console.log(response); +// }, function (err) { +// console.error(err); +// }); // client.calls.transfer( // "35283f77-a738-4d91-81dc-9f565e28d74c", {"legs": "aleg", "alegUrl": "https://www.google.com"}).then(function (response) { @@ -34,13 +40,24 @@ var client = new plivo.Client('MAMDJMMTEZOWY0ZMQWM2', 'OTljNmVmOGVkNGZhNjJlOWIyM // console.error(err); // }); -client.multiPartyCalls.addParticipant('agent', {'friendlyName' : 'TestMPC', 'from' : '+919090909090', 'to': 'sip:koushikqa119062465586783372208@phone-qa.voice.plivodev.com'}).then(function (response) { - console.log(response); -}, function (err) { - console.error(err); -}); - -// client.multiPartyCalls.list().then(function (response) { +// client.multiPartyCalls.stop('6172e321-284d-4159-8242-5f5e92933de5').then(function (response) { +// console.log(response); +// }, function (err) { +// console.error(err); +// }); + +// client.multiPartyCalls.kickParticipant(10, "6bed1e3a-e5da-4ffc-8ed5-84b0a3e0d75c", null).then(function (response) { +// console.log(response); +// }, function (err) { +// console.error(err); +// }); +// client.multiPartyCalls.get(null, 'TestMPC').then(function (response) { +// console.log(response); +// }, function (err) { +// console.error(err); +// }); + +// client.multiPartyCalls.get('6f84d47c-ee82-4172-a155-c6e22f87d874').then(function (response) { // console.log(response); // }, function (err) { // console.error(err); diff --git a/lib/base.js b/lib/base.js index 29834c8..d6ba0d7 100644 --- a/lib/base.js +++ b/lib/base.js @@ -145,7 +145,7 @@ export class PlivoSecondaryResource { let secondaryIdField = this[secondaryIdKey] return new Promise((resolve, reject) => { - client(method, action + task + '/' + secondaryAction + secondaryTask, params) + client(method, action + task + '/' + secondaryAction + secondaryTask + '/', params) .then(response => { resolve(new PlivoGenericResponse(response.body, secondaryIdField)); }) diff --git a/lib/resources/multiPartyCall.js b/lib/resources/multiPartyCall.js index 1911b04..bfe9816 100644 --- a/lib/resources/multiPartyCall.js +++ b/lib/resources/multiPartyCall.js @@ -185,10 +185,10 @@ export class MultiPartyCall extends PlivoResource{ } if(params.record){ - validParam('record', params.record, [Boolean], false) + validParam('record', params.record, [Boolean, String], false) } else { - params.record = false + params.record = 'false' } if(params.recordFileFormat){ @@ -206,52 +206,52 @@ export class MultiPartyCall extends PlivoResource{ } if(params.stayAlone){ - validParam('stayAlone', params.stayAlone, [Boolean], false) + validParam('stayAlone', params.stayAlone, [Boolean, String], false) } else { - params.stayAlone = false + params.stayAlone = 'false' } if(params.coachMode){ - validParam('coachMode', params.coachMode, [Boolean], false) + validParam('coachMode', params.coachMode, [Boolean, String], false) } else { - params.coachMode = true + params.coachMode = 'true' } if(params.mute){ - validParam('mute', params.mute, [Boolean], false) + validParam('mute', params.mute, [Boolean, String], false) } else { - params.mute = false + params.mute = 'false' } if(params.hold){ - validParam('hold', params.hold, [Boolean], false) + validParam('hold', params.hold, [Boolean, String], false) } else { - params.hold = false + params.hold = 'false' } if(params.startMpcOnEnter){ - validParam('startMpcOnEnter', params.startMpcOnEnter, [Boolean], false) + validParam('startMpcOnEnter', params.startMpcOnEnter, [Boolean, String], false) } else { - params.startMpcOnEnter = false + params.startMpcOnEnter = 'true' } if(params.endMpcOnExit){ - validParam('endMpcOnExit', params.endMpcOnExit, [Boolean], false) + validParam('endMpcOnExit', params.endMpcOnExit, [Boolean, String], false) } else { - params.endMpcOnExit = false + params.endMpcOnExit = 'false' } if(params.relayDTMFInputs){ - validParam('relayDTMFInputs', params.relayDTMFInputs, [Boolean], false) + validParam('relayDTMFInputs', params.relayDTMFInputs, [Boolean, String], false) } else { - params.relayDTMFInputs = false + params.relayDTMFInputs = 'false' } if(params.enterSound){ @@ -282,18 +282,18 @@ export class MultiPartyCall extends PlivoResource{ params.exitSoundMethod = 'GET' } - return super.executeAction(this.id + '/Participant', 'POST', params) + return super.executeAction(this.id + '/Participant/', 'POST', params) } start(){ - return super.executeAction(this.id, 'POST', {'status' : 'active'}) + return super.executeAction(this.id + '/', 'POST', {'status' : 'active'}) } stop(){ return super.delete() } - startRecording(params){ + startRecording(params = {}){ if(params.fileFormat){ validParam('fileFormat', params.fileFormat, [String], false, ['mp3', 'wav']) } @@ -312,19 +312,19 @@ export class MultiPartyCall extends PlivoResource{ params.statusCallbackMethod = 'POST' } - return super.executeAction(this.id + '/Record', 'POST', params) + return super.executeAction(this.id + '/Record/', 'POST', params) } stopRecording(){ - return super.executeAction(this.id + '/Record', 'DELETE') + return super.executeAction(this.id + '/Record/', 'DELETE') } pauseRecording(){ - return super.executeAction(this.id + '/Record/Pause', 'POST') + return super.executeAction(this.id + '/Record/Pause/', 'POST') } resumeRecording(){ - return super.executeAction(this.id + '/Record/Resume', 'POST') + return super.executeAction(this.id + '/Record/Resume/', 'POST') } listParticipants(params = {}){ @@ -332,7 +332,7 @@ export class MultiPartyCall extends PlivoResource{ validParam('callUuid', params.callUuid, [String], false) } - return super.executeAction(this.id + '/Participant', 'GET', params) + return super.executeAction(this.id + '/Participant/', 'GET', params) } } @@ -352,17 +352,17 @@ export class MultiPartyCallParticipant extends PlivoSecondaryResource{ this[clientKey] = client; } - updateParticipant(params){ + updateParticipant(params = {}){ if(params.coachMode){ - validParam('coachMode', params.coachMode, [Boolean], false) + validParam('coachMode', params.coachMode, [Boolean, String], false) } if(params.mute){ - validParam('mute', params.mute, [Boolean], false) + validParam('mute', params.mute, [Boolean, String], false) } if(params.hold){ - validParam('hold', params.hold, [Boolean], false) + validParam('hold', params.hold, [Boolean, String], false) } return super.executeAction(this.id, this.secondaryId, 'POST', params) @@ -414,7 +414,7 @@ export class MultiPartyCallInterface extends PlivoResourceInterface{ validParam('status', params.status.toLowerCase(), [String], false, ['initialized', 'active', 'ended']) } if(params.terminationCauseCode){ - validParam('terminationCauseCode', params.terminationCauseCode, [Number], false) + validParam('terminationCauseCode', params.terminationCauseCode, [Number, String], false) } if(params.end_time__gt){ validDateFormat('end_time__gt', params.end_time__gt, false) @@ -474,7 +474,6 @@ export class MultiPartyCallInterface extends PlivoResourceInterface{ if(params.friendlyName){ validParam('friendlyName', params.friendlyName, [String], false) } - console.log(params.friendlyName); let mpcId = this.makeMpcId(params.uuid, params.friendlyName) delete params.uuid delete params.friendlyName @@ -560,9 +559,7 @@ export class MultiPartyCallInterface extends PlivoResourceInterface{ } updateParticipant(participantId, uuid= null, friendlyName = null, params){ - if(participantId){ - validParam('participantId', participantId, [String, Number], true) - } + validParam('participantId', participantId, [String, Number], true) if(uuid){ validParam('uuid', uuid, [String], false) } @@ -574,9 +571,7 @@ export class MultiPartyCallInterface extends PlivoResourceInterface{ } kickParticipant(participantId, uuid = null, friendlyName = null){ - if(participantId){ - validParam('participantId', participantId, [String, Number], true) - } + validParam('participantId', participantId, [String, Number], true) if(uuid){ validParam('uuid', uuid, [String], false) } @@ -588,9 +583,7 @@ export class MultiPartyCallInterface extends PlivoResourceInterface{ } getParticipant(participantId, uuid = null, friendlyName = null){ - if(participantId){ - validParam('participantId', participantId, [String, Number], true) - } + validParam('participantId', participantId, [String, Number], true) if(uuid){ validParam('uuid', uuid, [String], false) } diff --git a/lib/rest/client-test.js b/lib/rest/client-test.js index bf709ed..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) { @@ -95,6 +96,7 @@ export class 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/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 bf79ca9..6add094 100644 --- a/lib/rest/utils.js +++ b/lib/rest/utils.js @@ -208,7 +208,7 @@ export function isOneAmongStringUrl(paramName, paramValue, mandatory = false, ex return true; } - if(!(expectedValues.indexOf(paramValue) === -1) || !(expectedValues.indexOf(paramValue) === -1)){ + if(!(expectedValues.indexOf(paramValue.toLowerCase()) === -1) || !(expectedValues.indexOf(paramValue.toUpperCase()) === -1)){ return true; } else if (validUrl(paramName, paramValue)){ @@ -228,7 +228,7 @@ export function validDateFormat(paramName, paramValue, mandatory = false){ return true; } - let response = paramValue.match(/^(\d{4})\-(\d{2})\-(\d{2}) (\d{2}):(\d{2}):(\d{2})\.(\d{1-6})$/); + 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") } diff --git a/lib/utils/plivoxml.js b/lib/utils/plivoxml.js index d28595b..f6a30b3 100644 --- a/lib/utils/plivoxml.js +++ b/lib/utils/plivoxml.js @@ -481,188 +481,188 @@ Response.prototype = { 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') + 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') + 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') + 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') + 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') + 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') + 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') + 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') + 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') + 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') + 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') + 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') + 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') + 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') + 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') + 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') + 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') + 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') + 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') + 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') + 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') + 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') + 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') + 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') + 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') + 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') + 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') + 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') + 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') + throw new PlivoXMLError('Invalid attribute value ' + attributes.customerHoldMusicUrl + ' for customerHoldMusicUrl') } return this.add(new MultiPartyCall(Response), body, attributes); }, 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/') + }) + }); +}) From 9b8d26db63c191435342ce5573ae01c03776499b Mon Sep 17 00:00:00 2001 From: Koushik-Ayila Date: Tue, 8 Sep 2020 00:50:36 +0530 Subject: [PATCH 16/35] Removed example test file and changed URL back to prod from QA url --- example_script.js | 64 ----------------------------------------------- 1 file changed, 64 deletions(-) delete mode 100644 example_script.js diff --git a/example_script.js b/example_script.js deleted file mode 100644 index f71399d..0000000 --- a/example_script.js +++ /dev/null @@ -1,64 +0,0 @@ -let plivo = require('./'); -var client = new plivo.Client('MAMDJMMTEZOWY0ZMQWM2', 'OTljNmVmOGVkNGZhNjJlOWIyMWM0ZDI0ZjQwZDdk'); - -// client.calls.create( "+919090909090", // from -// "+918309866821", // to -// "https://plivobin.non-prod.plivops.com/api/v1/Conference_test07.xml").then(function (response) { -// console.log(response); -// }, function (err) { -// console.error(err); -// }); -// -// client.conferences.get( "FStestconference").then(function (response) { -// console.log(response); -// }, function (err) { -// console.error(err); -// }); - -// client.calls.transfer( -// "35283f77-a738-4d91-81dc-9f565e28d74c", {"legs": "aleg", "alegUrl": "https://www.google.com"}).then(function (response) { -// console.log(response); -// }, function (err) { -// console.error(err); -// }); - -// client.calls.sendDigits( -// "bfc3f1fd-d66b-42ab-88e4-9e82c8e2537f", // call uuid -// 123, // digits -// { -// 'leg': 'aleg' -// } -// ).then(function (response) { -// console.log(response); -// }, function (err) { -// console.error(err); -// }); - -// client.conferences.startRecording('FStestconference').then(function (response) { -// console.log(response); -// }, function (err) { -// console.error(err); -// }); - -// client.multiPartyCalls.stop('6172e321-284d-4159-8242-5f5e92933de5').then(function (response) { -// console.log(response); -// }, function (err) { -// console.error(err); -// }); - -// client.multiPartyCalls.kickParticipant(10, "6bed1e3a-e5da-4ffc-8ed5-84b0a3e0d75c", null).then(function (response) { -// console.log(response); -// }, function (err) { -// console.error(err); -// }); -// client.multiPartyCalls.get(null, 'TestMPC').then(function (response) { -// console.log(response); -// }, function (err) { -// console.error(err); -// }); - -// client.multiPartyCalls.get('6f84d47c-ee82-4172-a155-c6e22f87d874').then(function (response) { -// console.log(response); -// }, function (err) { -// console.error(err); -// }); From 403c78168cdc92b8fec0cdf50903f7ff16aa899b Mon Sep 17 00:00:00 2001 From: Koushik-Ayila Date: Wed, 26 Aug 2020 11:31:13 +0530 Subject: [PATCH 17/35] MPC API - Under Development --- lib/rest/client.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/rest/client.js b/lib/rest/client.js index 492c32d..7e13eae 100644 --- a/lib/rest/client.js +++ b/lib/rest/client.js @@ -65,7 +65,7 @@ export class Client { authId: authId, authToken: authToken, version: "v1", - url: "https://api.plivo.com/v1/Account/" + authId, + url: "https://api-qa.voice.plivodev.com/v1/Account/" + authId, userAgent: `${"plivo-node"}/${version || "Unknown Version"} (Node: ${ process.version })` From 8bf07ad13c2985a9c0e8df7dbbc383c88e5bc726 Mon Sep 17 00:00:00 2001 From: Koushik-Ayila Date: Wed, 26 Aug 2020 21:40:55 +0530 Subject: [PATCH 18/35] MPC API changes, TODO : Dev Testing --- lib/resources/multiPartyCall.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/resources/multiPartyCall.js b/lib/resources/multiPartyCall.js index bfe9816..4a26f14 100644 --- a/lib/resources/multiPartyCall.js +++ b/lib/resources/multiPartyCall.js @@ -461,7 +461,7 @@ export class MultiPartyCallInterface extends PlivoResourceInterface{ return new MultiPartyCall(this[clientKey], {id: mpcId[0] + mpcId[1]}).get(); } - addParticipant( role = 'agent', params = {}){ + addParticipant(role, params = {}){ let errors = validate([ {field: 'friendly_name', value: params.friendlyName, validators: ['isString']} ]); From c4d27a67e699473584466ebf5abbe01e16147c1c Mon Sep 17 00:00:00 2001 From: Koushik-Ayila Date: Mon, 31 Aug 2020 16:01:14 +0530 Subject: [PATCH 19/35] Example Script --- example_script.js | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 example_script.js diff --git a/example_script.js b/example_script.js new file mode 100644 index 0000000..5c762a7 --- /dev/null +++ b/example_script.js @@ -0,0 +1,47 @@ +let plivo = require('./'); +var client = new plivo.Client('MAMDJMMTEZOWY0ZMQWM2', 'OTljNmVmOGVkNGZhNjJlOWIyMWM0ZDI0ZjQwZDdk'); + +// client.calls.create( "+919090909090", // from +// "sip:koushikqa119062465586783372208@phone-qa.voice.plivodev.com", // to +// "https://plivobin.non-prod.plivops.com/api/v1/Conference_test07.xml").then(function (response) { +// console.log(response); +// }, function (err) { +// console.error(err); +// }); + +// client.calls.transfer( +// "35283f77-a738-4d91-81dc-9f565e28d74c", {"legs": "aleg", "alegUrl": "https://www.google.com"}).then(function (response) { +// console.log(response); +// }, function (err) { +// console.error(err); +// }); + +// client.calls.sendDigits( +// "bfc3f1fd-d66b-42ab-88e4-9e82c8e2537f", // call uuid +// 123, // digits +// { +// 'leg': 'aleg' +// } +// ).then(function (response) { +// console.log(response); +// }, function (err) { +// console.error(err); +// }); + +// client.conferences.startRecording('FStestconference').then(function (response) { +// console.log(response); +// }, function (err) { +// console.error(err); +// }); + +client.multiPartyCalls.addParticipant({'friendlyName' : 'TestMPC', 'from' : '+919090909090', 'to': 'sip:koushikqa119062465586783372208@phone-qa.voice.plivodev.com'}).then(function (response) { + console.log(response); +}, function (err) { + console.error(err); +}); + +// client.multiPartyCalls.list().then(function (response) { +// console.log(response); +// }, function (err) { +// console.error(err); +// }); From a3b7ea4f301c3cf4ebf2be9285afa068873f8bec Mon Sep 17 00:00:00 2001 From: Koushik-Ayila Date: Tue, 1 Sep 2020 16:39:44 +0530 Subject: [PATCH 20/35] Reverted back to original --- example_script.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example_script.js b/example_script.js index 5c762a7..5b8483e 100644 --- a/example_script.js +++ b/example_script.js @@ -34,7 +34,7 @@ var client = new plivo.Client('MAMDJMMTEZOWY0ZMQWM2', 'OTljNmVmOGVkNGZhNjJlOWIyM // console.error(err); // }); -client.multiPartyCalls.addParticipant({'friendlyName' : 'TestMPC', 'from' : '+919090909090', 'to': 'sip:koushikqa119062465586783372208@phone-qa.voice.plivodev.com'}).then(function (response) { +client.multiPartyCalls.addParticipant('agent', {"friendlyName" : "TestMPC", 'from' : '+919090909090', 'to': 'sip:koushikqa119062465586783372208@phone-qa.voice.plivodev.com'}).then(function (response) { console.log(response); }, function (err) { console.error(err); From 29a4be9f3cb26db83fd56bbfdc63c25aa04d67ed Mon Sep 17 00:00:00 2001 From: Koushik-Ayila Date: Tue, 1 Sep 2020 16:50:11 +0530 Subject: [PATCH 21/35] Reverted back to original --- example_script.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example_script.js b/example_script.js index 5b8483e..4ec220a 100644 --- a/example_script.js +++ b/example_script.js @@ -34,7 +34,7 @@ var client = new plivo.Client('MAMDJMMTEZOWY0ZMQWM2', 'OTljNmVmOGVkNGZhNjJlOWIyM // console.error(err); // }); -client.multiPartyCalls.addParticipant('agent', {"friendlyName" : "TestMPC", 'from' : '+919090909090', 'to': 'sip:koushikqa119062465586783372208@phone-qa.voice.plivodev.com'}).then(function (response) { +client.multiPartyCalls.addParticipant('agent', {'friendlyName' : 'TestMPC', 'from' : '+919090909090', 'to': 'sip:koushikqa119062465586783372208@phone-qa.voice.plivodev.com'}).then(function (response) { console.log(response); }, function (err) { console.error(err); From ab352d5d0ea1abab0a53f6ee5c8e7e971abf4222 Mon Sep 17 00:00:00 2001 From: Koushik-Ayila Date: Tue, 8 Sep 2020 00:40:30 +0530 Subject: [PATCH 22/35] MPC API and XML changes - Dev completed --- example_script.js | 33 +++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/example_script.js b/example_script.js index 4ec220a..f71399d 100644 --- a/example_script.js +++ b/example_script.js @@ -2,12 +2,18 @@ let plivo = require('./'); var client = new plivo.Client('MAMDJMMTEZOWY0ZMQWM2', 'OTljNmVmOGVkNGZhNjJlOWIyMWM0ZDI0ZjQwZDdk'); // client.calls.create( "+919090909090", // from -// "sip:koushikqa119062465586783372208@phone-qa.voice.plivodev.com", // to +// "+918309866821", // to // "https://plivobin.non-prod.plivops.com/api/v1/Conference_test07.xml").then(function (response) { // console.log(response); // }, function (err) { // console.error(err); // }); +// +// client.conferences.get( "FStestconference").then(function (response) { +// console.log(response); +// }, function (err) { +// console.error(err); +// }); // client.calls.transfer( // "35283f77-a738-4d91-81dc-9f565e28d74c", {"legs": "aleg", "alegUrl": "https://www.google.com"}).then(function (response) { @@ -34,13 +40,24 @@ var client = new plivo.Client('MAMDJMMTEZOWY0ZMQWM2', 'OTljNmVmOGVkNGZhNjJlOWIyM // console.error(err); // }); -client.multiPartyCalls.addParticipant('agent', {'friendlyName' : 'TestMPC', 'from' : '+919090909090', 'to': 'sip:koushikqa119062465586783372208@phone-qa.voice.plivodev.com'}).then(function (response) { - console.log(response); -}, function (err) { - console.error(err); -}); - -// client.multiPartyCalls.list().then(function (response) { +// client.multiPartyCalls.stop('6172e321-284d-4159-8242-5f5e92933de5').then(function (response) { +// console.log(response); +// }, function (err) { +// console.error(err); +// }); + +// client.multiPartyCalls.kickParticipant(10, "6bed1e3a-e5da-4ffc-8ed5-84b0a3e0d75c", null).then(function (response) { +// console.log(response); +// }, function (err) { +// console.error(err); +// }); +// client.multiPartyCalls.get(null, 'TestMPC').then(function (response) { +// console.log(response); +// }, function (err) { +// console.error(err); +// }); + +// client.multiPartyCalls.get('6f84d47c-ee82-4172-a155-c6e22f87d874').then(function (response) { // console.log(response); // }, function (err) { // console.error(err); From 9b2831d6f59bfc0e0c9fcb17555aa9d76068194c Mon Sep 17 00:00:00 2001 From: Koushik-Ayila Date: Tue, 8 Sep 2020 00:50:36 +0530 Subject: [PATCH 23/35] Removed example test file and changed URL back to prod from QA url --- example_script.js | 64 ---------------------------------------------- lib/rest/client.js | 2 +- 2 files changed, 1 insertion(+), 65 deletions(-) delete mode 100644 example_script.js diff --git a/example_script.js b/example_script.js deleted file mode 100644 index f71399d..0000000 --- a/example_script.js +++ /dev/null @@ -1,64 +0,0 @@ -let plivo = require('./'); -var client = new plivo.Client('MAMDJMMTEZOWY0ZMQWM2', 'OTljNmVmOGVkNGZhNjJlOWIyMWM0ZDI0ZjQwZDdk'); - -// client.calls.create( "+919090909090", // from -// "+918309866821", // to -// "https://plivobin.non-prod.plivops.com/api/v1/Conference_test07.xml").then(function (response) { -// console.log(response); -// }, function (err) { -// console.error(err); -// }); -// -// client.conferences.get( "FStestconference").then(function (response) { -// console.log(response); -// }, function (err) { -// console.error(err); -// }); - -// client.calls.transfer( -// "35283f77-a738-4d91-81dc-9f565e28d74c", {"legs": "aleg", "alegUrl": "https://www.google.com"}).then(function (response) { -// console.log(response); -// }, function (err) { -// console.error(err); -// }); - -// client.calls.sendDigits( -// "bfc3f1fd-d66b-42ab-88e4-9e82c8e2537f", // call uuid -// 123, // digits -// { -// 'leg': 'aleg' -// } -// ).then(function (response) { -// console.log(response); -// }, function (err) { -// console.error(err); -// }); - -// client.conferences.startRecording('FStestconference').then(function (response) { -// console.log(response); -// }, function (err) { -// console.error(err); -// }); - -// client.multiPartyCalls.stop('6172e321-284d-4159-8242-5f5e92933de5').then(function (response) { -// console.log(response); -// }, function (err) { -// console.error(err); -// }); - -// client.multiPartyCalls.kickParticipant(10, "6bed1e3a-e5da-4ffc-8ed5-84b0a3e0d75c", null).then(function (response) { -// console.log(response); -// }, function (err) { -// console.error(err); -// }); -// client.multiPartyCalls.get(null, 'TestMPC').then(function (response) { -// console.log(response); -// }, function (err) { -// console.error(err); -// }); - -// client.multiPartyCalls.get('6f84d47c-ee82-4172-a155-c6e22f87d874').then(function (response) { -// console.log(response); -// }, function (err) { -// console.error(err); -// }); diff --git a/lib/rest/client.js b/lib/rest/client.js index 7e13eae..492c32d 100644 --- a/lib/rest/client.js +++ b/lib/rest/client.js @@ -65,7 +65,7 @@ export class Client { authId: authId, authToken: authToken, version: "v1", - url: "https://api-qa.voice.plivodev.com/v1/Account/" + authId, + url: "https://api.plivo.com/v1/Account/" + authId, userAgent: `${"plivo-node"}/${version || "Unknown Version"} (Node: ${ process.version })` From e57a6bec3b52f4632ca34daad3e957d845ec0b7c Mon Sep 17 00:00:00 2001 From: Koushik-Ayila Date: Wed, 7 Oct 2020 16:40:55 +0530 Subject: [PATCH 24/35] Incorporated retry logic for MPC APIs and validated voice UTs --- lib/resources/applications.js | 2 +- lib/resources/multiPartyCall.js | 29 +++++++++++++++-------------- lib/rest/utils.js | 2 +- test/calls.js | 1 + 4 files changed, 18 insertions(+), 16 deletions(-) diff --git a/lib/resources/applications.js b/lib/resources/applications.js index 7d653f5..8f01b3a 100644 --- a/lib/resources/applications.js +++ b/lib/resources/applications.js @@ -327,4 +327,4 @@ export class ApplicationInterface extends PlivoResourceInterface { id: id }).delete(params, id); } -} \ No newline at end of file +} diff --git a/lib/resources/multiPartyCall.js b/lib/resources/multiPartyCall.js index 4a26f14..e122f13 100644 --- a/lib/resources/multiPartyCall.js +++ b/lib/resources/multiPartyCall.js @@ -30,8 +30,9 @@ export class MultiPartyCall extends PlivoResource{ this[clientKey] = client; } - get(){ - return super.executeAction(this.id, 'GET'); + get(params = {}){ + params.isVoiceRequest = 'true'; + return super.executeAction(this.id, 'GET', params); } addParticipant(params){ @@ -281,16 +282,16 @@ export class MultiPartyCall extends PlivoResource{ else { params.exitSoundMethod = 'GET' } - + params.isVoiceRequest = 'true'; return super.executeAction(this.id + '/Participant/', 'POST', params) } start(){ - return super.executeAction(this.id + '/', 'POST', {'status' : 'active'}) + return super.executeAction(this.id + '/', 'POST', {'status' : 'active', 'isVoiceRequest' : 'true'}) } stop(){ - return super.delete() + return super.delete({'isVoiceRequest' : 'true'}) } startRecording(params = {}){ @@ -311,27 +312,27 @@ export class MultiPartyCall extends PlivoResource{ else { params.statusCallbackMethod = 'POST' } - + params.isVoiceRequest = 'true'; return super.executeAction(this.id + '/Record/', 'POST', params) } stopRecording(){ - return super.executeAction(this.id + '/Record/', 'DELETE') + return super.executeAction(this.id + '/Record/', 'DELETE',{'isVoiceRequest' : 'true'}) } pauseRecording(){ - return super.executeAction(this.id + '/Record/Pause/', 'POST') + return super.executeAction(this.id + '/Record/Pause/', 'POST',{'isVoiceRequest' : 'true'}) } resumeRecording(){ - return super.executeAction(this.id + '/Record/Resume/', 'POST') + 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) } } @@ -364,16 +365,16 @@ export class MultiPartyCallParticipant extends PlivoSecondaryResource{ 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') + return super.executeAction(this.id, this.secondaryId, 'DELETE',{'isVoiceRequest' : 'true'}) } getParticipant(){ - return super.executeAction(this.id, this.secondaryId, 'GET') + return super.executeAction(this.id, this.secondaryId, 'GET',{'isVoiceRequest' : 'true'}) } } @@ -446,7 +447,7 @@ export class MultiPartyCallInterface extends PlivoResourceInterface{ if(params.offset){ validRange('offset', params.offset, false, 0) } - + params.isVoiceRequest = 'true'; return super.list(params); } diff --git a/lib/rest/utils.js b/lib/rest/utils.js index 6add094..49996bb 100644 --- a/lib/rest/utils.js +++ b/lib/rest/utils.js @@ -228,7 +228,7 @@ export function validDateFormat(paramName, paramValue, mandatory = false){ return true; } - let response = paramValue.match(/^\d{4}\-\d{2}\-\d{2} \d{2}:\d{2}:\d{2}(\.\d{1,6})?$/); + 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") } 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) From 1cfd02434a52cc53d9c6e4bdbe5c0203c7d85174 Mon Sep 17 00:00:00 2001 From: Koushik-Ayila Date: Wed, 7 Oct 2020 16:42:14 +0530 Subject: [PATCH 25/35] Updated CHANGELOG.md version --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e9fa7fd..c20b7c8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ # Change Log +## [5.0.0](https://github.com/plivo/plivo-node/releases/tag/v4.9.0)(2020-10-07) +- Add 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. From 0cd20c12e24d05485c9252afba54257fe22c7ce3 Mon Sep 17 00:00:00 2001 From: Koushik-Ayila Date: Wed, 4 Nov 2020 00:25:40 +0530 Subject: [PATCH 26/35] Updated changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c20b7c8..f5a7d59 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Change Log -## [5.0.0](https://github.com/plivo/plivo-node/releases/tag/v4.9.0)(2020-10-07) +## [5.0.0](https://github.com/plivo/plivo-node/releases/tag/v5.0.0)(2020-11-03) - Add 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) From b6002f453845f435444e435cc49fe22704dafb61 Mon Sep 17 00:00:00 2001 From: Koushik-Ayila Date: Thu, 12 Nov 2020 18:38:57 +0530 Subject: [PATCH 27/35] Fixed ringTimeout not working bug --- lib/rest/utils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/rest/utils.js b/lib/rest/utils.js index 49996bb..f58c3da 100644 --- a/lib/rest/utils.js +++ b/lib/rest/utils.js @@ -246,7 +246,7 @@ export function validRange(paramName, paramValue, mandatory = false, lowerBound return true; } - if(!expectedType(paramName, Number, paramValue)){ + if(!expectedType(paramName, [Number], paramValue)){ throw new InvalidRequestError(paramName + ": Expected an Integer but received " + paramValue.constructor + " instead") } From 454789324c2670127bc2688ebf44347767fbf206 Mon Sep 17 00:00:00 2001 From: Koushik-Ayila Date: Tue, 17 Nov 2020 10:59:50 +0530 Subject: [PATCH 28/35] Fixed error message bug --- lib/resources/multiPartyCall.js | 6 ------ 1 file changed, 6 deletions(-) diff --git a/lib/resources/multiPartyCall.js b/lib/resources/multiPartyCall.js index e122f13..1b84d9f 100644 --- a/lib/resources/multiPartyCall.js +++ b/lib/resources/multiPartyCall.js @@ -463,12 +463,6 @@ export class MultiPartyCallInterface extends PlivoResourceInterface{ } addParticipant(role, params = {}){ - let errors = validate([ - {field: 'friendly_name', value: params.friendlyName, validators: ['isString']} - ]); - if (errors) { - return errors; - } if(params.uuid){ validParam('uuid', params.uuid, [String], false) } From a6a7953132cad779b434e300d318bf9c5890de07 Mon Sep 17 00:00:00 2001 From: Koushik-Ayila Date: Thu, 19 Nov 2020 15:26:19 +0530 Subject: [PATCH 29/35] Fixed ringTimeout 0 error handling bug --- lib/resources/multiPartyCall.js | 6 +++--- lib/rest/utils.js | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/resources/multiPartyCall.js b/lib/resources/multiPartyCall.js index 1b84d9f..0ffe665 100644 --- a/lib/resources/multiPartyCall.js +++ b/lib/resources/multiPartyCall.js @@ -98,21 +98,21 @@ export class MultiPartyCall extends PlivoResource{ params.dialMusic = 'Real' } - if(params.ringTimeout){ + if(params.ringTimeout || params.ringTimeout === 0){ validRange('ringTimeout', params.ringTimeout, false, 15, 120) } else { params.ringTimeout = 45 } - if(params.maxDuration){ + if(params.maxDuration || params.maxDuration === 0){ validRange('maxDuration', params.maxDuration, false, 300, 28800) } else { params.maxDuration = 14400 } - if(params.maxParticipants){ + if(params.maxParticipants || params.maxParticipants === 0){ validRange('maxParticipants', params.maxParticipants, false, 2, 10) } else { diff --git a/lib/rest/utils.js b/lib/rest/utils.js index f58c3da..300fe5b 100644 --- a/lib/rest/utils.js +++ b/lib/rest/utils.js @@ -242,7 +242,7 @@ export function validRange(paramName, paramValue, mandatory = false, lowerBound throw new InvalidRequestError(paramName + " is a required parameter") } - if(!paramValue){ + if(!paramValue && paramValue !== 0){ return true; } From a65a44d29b6ff9ee2dcec9856ea034180a23e41e Mon Sep 17 00:00:00 2001 From: Koushik-Ayila Date: Mon, 19 Apr 2021 18:59:00 +0530 Subject: [PATCH 30/35] Added version bump up --- CHANGELOG.md | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f5a7d59..5c82c33 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,7 @@ # Change Log -## [5.0.0](https://github.com/plivo/plivo-node/releases/tag/v5.0.0)(2020-11-03) -- Add SDK support for Voice MultiPartyCall APIs and XML +## [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. diff --git a/package.json b/package.json index ddd9b7b..7df55cd 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "plivo", - "version": "4.15.0", + "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": [ From f006b19c8545e4b3b829754c467746f959902132 Mon Sep 17 00:00:00 2001 From: huzaif Date: Mon, 3 May 2021 15:19:38 +0530 Subject: [PATCH 31/35] update readme --- README.md | 56 +++++++++++++++++++++++++------------------------------ 1 file changed, 25 insertions(+), 31 deletions(-) diff --git a/README.md b/README.md index 6e86df8..ca2c8a8 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,11 @@ -# 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) +[![Coverage Status](https://coveralls.io/repos/github/plivo/plivo-node/badge.svg)](https://coveralls.io/github/plivo/plivo-node) +[![Downloads](https://img.shields.io/npm/dm/plivo.svg)](https://www.npmjs.com/package/plivo) + +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 +21,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 +33,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 +58,12 @@ let plivo = require('plivo'); let client = new plivo.Client(); client.messages.create( - 'your_source_number', - 'your_destination_number', + '', + '', 'Hello, world!' -).then(function(message_created) { - console.log(message_created) +).then(function(response) { + console.log(response) }); - ``` ### Make a call @@ -68,27 +73,23 @@ let plivo = require('plivo'); let client = new plivo.Client(); client.calls.create( - 'your_source_number', - 'your_destination_number', + '', + '', '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 +115,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. +Refer to the [Plivo API Reference](https://www.plivo.com/docs/sms/api/overview/) for more examples. Also refer to the [guide to setting up dev environment](https://www.plivo.com/docs/sdk/server/node-sdk/) on [Plivo Developers Portal](https://www.plivo.com/docs/sms/quickstart/node-expressjs/) to setup an Express server & 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). From 2c7b47272b042be568937c4232320783f1c0fec7 Mon Sep 17 00:00:00 2001 From: huzaif Date: Mon, 3 May 2021 16:25:03 +0530 Subject: [PATCH 32/35] update readme --- README.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/README.md b/README.md index ca2c8a8..1628fbb 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,6 @@ [![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) -[![Coverage Status](https://coveralls.io/repos/github/plivo/plivo-node/badge.svg)](https://coveralls.io/github/plivo/plivo-node) -[![Downloads](https://img.shields.io/npm/dm/plivo.svg)](https://www.npmjs.com/package/plivo) 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. @@ -126,7 +124,7 @@ console.log('Phlo run result', result); ``` ### More examples -Refer to the [Plivo API Reference](https://www.plivo.com/docs/sms/api/overview/) for more examples. Also refer to the [guide to setting up dev environment](https://www.plivo.com/docs/sdk/server/node-sdk/) on [Plivo Developers Portal](https://www.plivo.com/docs/sms/quickstart/node-expressjs/) to setup an Express server & use it to test out your integration in under 5 minutes. +Refer to the [Plivo API Example](https://github.com/plivo/plivo-examples-node) for more examples. 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). From 4efdb1ea4b209d97bac8d117948c8a193460ad56 Mon Sep 17 00:00:00 2001 From: huzaif Date: Mon, 3 May 2021 16:28:30 +0530 Subject: [PATCH 33/35] update readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1628fbb..432d402 100644 --- a/README.md +++ b/README.md @@ -124,7 +124,7 @@ console.log('Phlo run result', result); ``` ### More examples -Refer to the [Plivo API Example](https://github.com/plivo/plivo-examples-node) for more examples. 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. +More examples can be found in the [Plivo API Example](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). From 61156ef340f78fa11e220cf7efab80d1a8d94f68 Mon Sep 17 00:00:00 2001 From: huzaif Date: Mon, 3 May 2021 16:30:51 +0530 Subject: [PATCH 34/35] update readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 432d402..75f1ccc 100644 --- a/README.md +++ b/README.md @@ -124,7 +124,7 @@ console.log('Phlo run result', result); ``` ### More examples -More examples can be found in the [Plivo API Example](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. +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). From 012895d445b7008745d9571a7bfb42975ec95537 Mon Sep 17 00:00:00 2001 From: huzaif Date: Mon, 3 May 2021 16:41:49 +0530 Subject: [PATCH 35/35] update src & dst placeholders --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 75f1ccc..9befb13 100644 --- a/README.md +++ b/README.md @@ -56,8 +56,8 @@ let plivo = require('plivo'); let client = new plivo.Client(); client.messages.create( - '', - '', + '+14156667778', + '+14156667777', 'Hello, world!' ).then(function(response) { console.log(response) @@ -71,8 +71,8 @@ let plivo = require('plivo'); let client = new plivo.Client(); client.calls.create( - '', - '', + '+14156667778', + '+14156667777', 'http://answer.url' ).then(function(response) { console.log(response)