From 957817f3057f608c22a26826ff46c70ad5a5673b Mon Sep 17 00:00:00 2001 From: Koushik-Ayila Date: Fri, 14 Aug 2020 16:54:31 +0530 Subject: [PATCH 01/22] 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 02/22] 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 03/22] 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 04/22] 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 05/22] 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 06/22] 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 07/22] 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 08/22] 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 09/22] 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 10/22] 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 11/22] 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 12/22] 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 13/22] 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 14/22] 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 15/22] 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 16/22] 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 17/22] 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 18/22] 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 19/22] 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 20/22] 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 21/22] 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 22/22] 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": [