diff --git a/CHANGELOG.md b/CHANGELOG.md
index 7573d86..2ea73de 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,14 @@
# Change Log
+## [4.1.6](https://github.com/plivo/plivo-node/releases/tag/v4.1.6)(2019-11-14)
+- Fix list APIs to return meta in response.
+
+## [4.1.5](https://github.com/plivo/plivo-node/releases/tag/v4.1.5)(2019-11-13)
+- Add GetInput XML support
+
+## [4.1.4](https://github.com/plivo/plivo-node/releases/tag/v4.1.4)(2019-11-06)
+- Add SSML support
+
## [4.1.3](https://github.com/plivo/plivo-node/releases/tag/v4.1.3)(2019-07-30)
- Add proxy-support for Signature Validation
- Add HTTP status codes in responses
diff --git a/Jenkinsfile b/Jenkinsfile
new file mode 100644
index 0000000..b2874e8
--- /dev/null
+++ b/Jenkinsfile
@@ -0,0 +1,7 @@
+#!groovy
+
+@Library('plivo_standard_libs@sdks') _
+
+sdksPipeline ([
+ buildContainer: 'plivo/jenkins-ci/node-sdk:latest'
+])
diff --git a/ci/config.yml b/ci/config.yml
new file mode 100644
index 0000000..71c3e3a
--- /dev/null
+++ b/ci/config.yml
@@ -0,0 +1,7 @@
+---
+parent: central
+serviceName: plivo-node
+language: node-sdk
+build:
+ command: |
+ npm install
diff --git a/examples/speak.js b/examples/speak.js
new file mode 100644
index 0000000..62f6526
--- /dev/null
+++ b/examples/speak.js
@@ -0,0 +1,59 @@
+var Plivo = require('../dist/rest/client.js');
+var response = new Plivo.Response();
+
+const speak = response.addSpeak('hello', {
+ voice: "Polly.Aditi",
+ language: 'en-IN',
+});
+
+speak.addLang('आप लोग कैसे हो', {
+ 'xml:lang': 'hi-IN',
+});
+
+const emphasis = speak.addEmphasis('emphasis', {
+ 'level': 'x-strong',
+})
+emphasis.addBreak();
+emphasis.addLang('language!!!');
+
+// Mixed-content without tag
+speak.addText('extra text');
+
+speak.addLang('how are you people?', {
+ 'xml:lang': 'en-IN',
+});
+
+speak.addSayAs('30101996', {
+ 'interpret-as': 'date',
+ 'format': 'dmy'
+});
+
+speak.addLang('well well well').addBreak();
+
+speak.addLang('no no no');
+
+speak.addProsody('कैसे हो');
+
+speak.addSayAs('S A Y A S', {
+ 'interpret-as': 'characters',
+});
+
+speak.addP('this is p tag');
+
+speak.addPhoneme('this is Phoneme', {
+ 'alphabet': 'ipa',
+});
+
+speak.addS('this is s tag');
+
+speak.addSub('Hg', {
+ alias: 'Mercury',
+});
+
+speak.addText('Past of read is')
+
+speak.addW('read', {
+ 'role': 'amazon:VBD',
+});
+
+console.log(response.toXML());
\ No newline at end of file
diff --git a/lib/base.js b/lib/base.js
index aa7701b..4597b8e 100644
--- a/lib/base.js
+++ b/lib/base.js
@@ -113,7 +113,7 @@ export class PlivoResourceInterface {
client('GET', action, params)
.then(response => {
let objects = [];
- Object.defineProperty(objects, 'meta', { value: response.body.meta });
+ Object.defineProperty(objects, 'meta', { value: response.body.meta, enumerable: true });
response.body.objects.forEach(item => {
objects.push(new Klass(client, item));
});
diff --git a/lib/rest/utils.js b/lib/rest/utils.js
index 27a9bf7..cf3793b 100644
--- a/lib/rest/utils.js
+++ b/lib/rest/utils.js
@@ -3,6 +3,7 @@ import _snakeCase from 'lodash/snakeCase';
import _mapKeys from 'lodash/mapKeys';
import _mapValues from 'lodash/mapValues';
import _map from 'lodash/map';
+import { parseString } from 'xml2js';
function recursivelyRenameObject(object, renameFunc) {
if (!(object instanceof Object)) {
@@ -54,3 +55,20 @@ export function camelCaseRequestWrapper(requestFunc) {
}
}
+export function validateSpeakAttributes(content, voice) {
+
+ if (!voice || ['MAN', 'WOMAN'].indexOf(voice) != -1) {
+ return { success: true };
+ }
+
+ var voiceParts = voice.split('.');
+ if (voiceParts.length != 2 || voiceParts[0] != 'Polly') {
+ return {
+ success: false, msg: "Invalid voice " + voice + '.'
+ };
+ };
+ return {
+ success: true,
+ }
+}
+
diff --git a/lib/utils/exceptions.js b/lib/utils/exceptions.js
index 0900363..04805f2 100644
--- a/lib/utils/exceptions.js
+++ b/lib/utils/exceptions.js
@@ -1,6 +1,7 @@
-export class PlivoRestError extends Error {}
-export class ResourceNotFoundError extends PlivoRestError {}
-export class ServerError extends PlivoRestError {}
-export class InvalidRequestError extends PlivoRestError {}
-export class PlivoXMLError extends PlivoRestError {}
-export class AuthenticationError extends PlivoRestError {}
+export class PlivoRestError extends Error { }
+export class ResourceNotFoundError extends PlivoRestError { }
+export class ServerError extends PlivoRestError { }
+export class InvalidRequestError extends PlivoRestError { }
+export class PlivoXMLError extends PlivoRestError { }
+export class PlivoXMLValidationError extends PlivoRestError { }
+export class AuthenticationError extends PlivoRestError { }
diff --git a/lib/utils/plivoxml.js b/lib/utils/plivoxml.js
index 94f5266..79ec786 100644
--- a/lib/utils/plivoxml.js
+++ b/lib/utils/plivoxml.js
@@ -1,6 +1,8 @@
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');
export class PlivoXMLError extends Error { }
@@ -11,7 +13,7 @@ export class PlivoXMLError extends Error { }
*/
export function Response() {
this.element = 'Response';
- this.nestables = ['Speak', 'Play', 'GetDigits', 'Record', 'Dial', 'Message',
+ this.nestables = ['Speak', 'Play', 'GetDigits', 'GetInput', 'Record', 'Dial', 'Message',
'Redirect', 'Wait', 'Hangup', 'PreAnswer', 'Conference', 'DTMF'];
this.valid_attributes = [];
this.elem = xmlBuilder.begin().ele(this.element);
@@ -162,6 +164,31 @@ Response.prototype = {
return this.add(new GetDigits(Response), '', attributes);
},
+ /**
+ * Add a GetInput element
+ * @method
+ * @param {object} attributes
+ * @param {string} [attributes.action]
+ * @param {string} [attributes.method]
+ * @param {string} [attributes.inputType]
+ * @param {number} [attributes.executionTimeout]
+ * @param {number} [attributes.digitEndTimeout]
+ * @param {number} [attributes.speechEndTimeout]
+ * @param {string} [attributes.finishOnKey]
+ * @param {number} [attributes.numDigits]
+ * @param {string} [attributes.speechModel]
+ * @param {string} [attributes.hints]
+ * @param {string} [attributes.language]
+ * @param {string} [attributes.interimSpeechResultsCallback]
+ * @param {string} [attributes.interimSpeechResultsCallbackMethod]
+ * @param {boolean} [attributes.log]
+ * @param {boolean} [attributes.redirect]
+ * @param {string} [attributes.profanityFilter]
+ */
+ addGetInput: function (attributes) {
+ return this.add(new GetInput(Response), '', attributes);
+ },
+
/**
* Add a Hangup element
* @method
@@ -252,22 +279,141 @@ Response.prototype = {
* @param {number} [attributes.loop]
*/
addSpeak: function (body, attributes) {
- //Convert accented characters to numerical references first
- let accentedCharsList = {
- "Á": "A", "Ă": "A", "Ắ": "A", "Ặ": "A", "Ằ": "A", "Ẳ": "A", "Ẵ": "A", "Ǎ": "A", "Â": "A", "Ấ": "A", "Ậ": "A", "Ầ": "A", "Ẩ": "A", "Ẫ": "A", "Ä": "A", "Ǟ": "A", "Ȧ": "A", "Ǡ": "A", "Ạ": "A", "Ȁ": "A", "À": "A", "Ả": "A", "Ȃ": "A", "Ā": "A", "Ą": "A", "Å": "A", "Ǻ": "A", "Ḁ": "A", "Ⱥ": "A", "Ã": "A", "Ꜳ": "AA", "Æ": "AE", "Ǽ": "AE", "Ǣ": "AE", "Ꜵ": "AO", "Ꜷ": "AU", "Ꜹ": "AV", "Ꜻ": "AV", "Ꜽ": "AY", "Ḃ": "B", "Ḅ": "B", "Ɓ": "B", "Ḇ": "B", "Ƀ": "B", "Ƃ": "B", "Ć": "C", "Č": "C", "Ç": "C", "Ḉ": "C", "Ĉ": "C", "Ċ": "C", "Ƈ": "C", "Ȼ": "C", "Ď": "D", "Ḑ": "D", "Ḓ": "D", "Ḋ": "D", "Ḍ": "D", "Ɗ": "D", "Ḏ": "D", "Dz": "D", "Dž": "D", "Đ": "D", "Ƌ": "D", "DZ": "DZ", "DŽ": "DZ", "É": "E", "Ĕ": "E", "Ě": "E", "Ȩ": "E", "Ḝ": "E", "Ê": "E", "Ế": "E", "Ệ": "E", "Ề": "E", "Ể": "E", "Ễ": "E", "Ḙ": "E", "Ë": "E", "Ė": "E", "Ẹ": "E", "Ȅ": "E", "È": "E", "Ẻ": "E", "Ȇ": "E", "Ē": "E", "Ḗ": "E", "Ḕ": "E", "Ę": "E", "Ɇ": "E", "Ẽ": "E", "Ḛ": "E", "Ꝫ": "ET", "Ḟ": "F", "Ƒ": "F", "Ǵ": "G", "Ğ": "G", "Ǧ": "G", "Ģ": "G", "Ĝ": "G", "Ġ": "G", "Ɠ": "G", "Ḡ": "G", "Ǥ": "G", "Ḫ": "H", "Ȟ": "H", "Ḩ": "H", "Ĥ": "H", "Ⱨ": "H", "Ḧ": "H", "Ḣ": "H", "Ḥ": "H", "Ħ": "H", "Í": "I", "Ĭ": "I", "Ǐ": "I", "Î": "I", "Ï": "I", "Ḯ": "I", "İ": "I", "Ị": "I", "Ȉ": "I", "Ì": "I", "Ỉ": "I", "Ȋ": "I", "Ī": "I", "Į": "I", "Ɨ": "I", "Ĩ": "I", "Ḭ": "I", "Ꝺ": "D", "Ꝼ": "F", "Ᵹ": "G", "Ꞃ": "R", "Ꞅ": "S", "Ꞇ": "T", "Ꝭ": "IS", "Ĵ": "J", "Ɉ": "J", "Ḱ": "K", "Ǩ": "K", "Ķ": "K", "Ⱪ": "K", "Ꝃ": "K", "Ḳ": "K", "Ƙ": "K", "Ḵ": "K", "Ꝁ": "K", "Ꝅ": "K", "Ĺ": "L", "Ƚ": "L", "Ľ": "L", "Ļ": "L", "Ḽ": "L", "Ḷ": "L", "Ḹ": "L", "Ⱡ": "L", "Ꝉ": "L", "Ḻ": "L", "Ŀ": "L", "Ɫ": "L", "Lj": "L", "Ł": "L", "LJ": "LJ", "Ḿ": "M", "Ṁ": "M", "Ṃ": "M", "Ɱ": "M", "Ń": "N", "Ň": "N", "Ņ": "N", "Ṋ": "N", "Ṅ": "N", "Ṇ": "N", "Ǹ": "N", "Ɲ": "N", "Ṉ": "N", "Ƞ": "N", "Nj": "N", "Ñ": "N", "NJ": "NJ", "Ó": "O", "Ŏ": "O", "Ǒ": "O", "Ô": "O", "Ố": "O", "Ộ": "O", "Ồ": "O", "Ổ": "O", "Ỗ": "O", "Ö": "O", "Ȫ": "O", "Ȯ": "O", "Ȱ": "O", "Ọ": "O", "Ő": "O", "Ȍ": "O", "Ò": "O", "Ỏ": "O", "Ơ": "O", "Ớ": "O", "Ợ": "O", "Ờ": "O", "Ở": "O", "Ỡ": "O", "Ȏ": "O", "Ꝋ": "O", "Ꝍ": "O", "Ō": "O", "Ṓ": "O", "Ṑ": "O", "Ɵ": "O", "Ǫ": "O", "Ǭ": "O", "Ø": "O", "Ǿ": "O", "Õ": "O", "Ṍ": "O", "Ṏ": "O", "Ȭ": "O", "Ƣ": "OI", "Ꝏ": "OO", "Ɛ": "E", "Ɔ": "O", "Ȣ": "OU", "Ṕ": "P", "Ṗ": "P", "Ꝓ": "P", "Ƥ": "P", "Ꝕ": "P", "Ᵽ": "P", "Ꝑ": "P", "Ꝙ": "Q", "Ꝗ": "Q", "Ŕ": "R", "Ř": "R", "Ŗ": "R", "Ṙ": "R", "Ṛ": "R", "Ṝ": "R", "Ȑ": "R", "Ȓ": "R", "Ṟ": "R", "Ɍ": "R", "Ɽ": "R", "Ꜿ": "C", "Ǝ": "E", "Ś": "S", "Ṥ": "S", "Š": "S", "Ṧ": "S", "Ş": "S", "Ŝ": "S", "Ș": "S", "Ṡ": "S", "Ṣ": "S", "Ṩ": "S", "Ť": "T", "Ţ": "T", "Ṱ": "T", "Ț": "T", "Ⱦ": "T", "Ṫ": "T", "Ṭ": "T", "Ƭ": "T", "Ṯ": "T", "Ʈ": "T", "Ŧ": "T", "Ɐ": "A", "Ꞁ": "L", "Ɯ": "M", "Ʌ": "V", "Ꜩ": "TZ", "Ú": "U", "Ŭ": "U", "Ǔ": "U", "Û": "U", "Ṷ": "U", "Ü": "U", "Ǘ": "U", "Ǚ": "U", "Ǜ": "U", "Ǖ": "U", "Ṳ": "U", "Ụ": "U", "Ű": "U", "Ȕ": "U", "Ù": "U", "Ủ": "U", "Ư": "U", "Ứ": "U", "Ự": "U", "Ừ": "U", "Ử": "U", "Ữ": "U", "Ȗ": "U", "Ū": "U", "Ṻ": "U", "Ų": "U", "Ů": "U", "Ũ": "U", "Ṹ": "U", "Ṵ": "U", "Ꝟ": "V", "Ṿ": "V", "Ʋ": "V", "Ṽ": "V", "Ꝡ": "VY", "Ẃ": "W", "Ŵ": "W", "Ẅ": "W", "Ẇ": "W", "Ẉ": "W", "Ẁ": "W", "Ⱳ": "W", "Ẍ": "X", "Ẋ": "X", "Ý": "Y", "Ŷ": "Y", "Ÿ": "Y", "Ẏ": "Y", "Ỵ": "Y", "Ỳ": "Y", "Ƴ": "Y", "Ỷ": "Y", "Ỿ": "Y", "Ȳ": "Y", "Ɏ": "Y", "Ỹ": "Y", "Ź": "Z", "Ž": "Z", "Ẑ": "Z", "Ⱬ": "Z", "Ż": "Z", "Ẓ": "Z", "Ȥ": "Z", "Ẕ": "Z", "Ƶ": "Z", "IJ": "IJ", "Œ": "OE", "ᴀ": "A", "ᴁ": "AE", "ʙ": "B", "ᴃ": "B", "ᴄ": "C", "ᴅ": "D", "ᴇ": "E", "ꜰ": "F", "ɢ": "G", "ʛ": "G", "ʜ": "H", "ɪ": "I", "ʁ": "R", "ᴊ": "J", "ᴋ": "K", "ʟ": "L", "ᴌ": "L", "ᴍ": "M", "ɴ": "N", "ᴏ": "O", "ɶ": "OE", "ᴐ": "O", "ᴕ": "OU", "ᴘ": "P", "ʀ": "R", "ᴎ": "N", "ᴙ": "R", "ꜱ": "S", "ᴛ": "T", "ⱻ": "E", "ᴚ": "R", "ᴜ": "U", "ᴠ": "V", "ᴡ": "W", "ʏ": "Y", "ᴢ": "Z", "á": "a", "ă": "a", "ắ": "a", "ặ": "a", "ằ": "a", "ẳ": "a", "ẵ": "a", "ǎ": "a", "â": "a", "ấ": "a", "ậ": "a", "ầ": "a", "ẩ": "a", "ẫ": "a", "ä": "a", "ǟ": "a", "ȧ": "a", "ǡ": "a", "ạ": "a", "ȁ": "a", "à": "a", "ả": "a", "ȃ": "a", "ā": "a", "ą": "a", "ᶏ": "a", "ẚ": "a", "å": "a", "ǻ": "a", "ḁ": "a", "ⱥ": "a", "ã": "a", "ꜳ": "aa", "æ": "ae", "ǽ": "ae", "ǣ": "ae", "ꜵ": "ao", "ꜷ": "au", "ꜹ": "av", "ꜻ": "av", "ꜽ": "ay", "ḃ": "b", "ḅ": "b", "ɓ": "b", "ḇ": "b", "ᵬ": "b", "ᶀ": "b", "ƀ": "b", "ƃ": "b", "ɵ": "o", "ć": "c", "č": "c", "ç": "c", "ḉ": "c", "ĉ": "c", "ɕ": "c", "ċ": "c", "ƈ": "c", "ȼ": "c", "ď": "d", "ḑ": "d", "ḓ": "d", "ȡ": "d", "ḋ": "d", "ḍ": "d", "ɗ": "d", "ᶑ": "d", "ḏ": "d", "ᵭ": "d", "ᶁ": "d", "đ": "d", "ɖ": "d", "ƌ": "d", "ı": "i", "ȷ": "j", "ɟ": "j", "ʄ": "j", "dz": "dz", "dž": "dz", "é": "e", "ĕ": "e", "ě": "e", "ȩ": "e", "ḝ": "e", "ê": "e", "ế": "e", "ệ": "e", "ề": "e", "ể": "e", "ễ": "e", "ḙ": "e", "ë": "e", "ė": "e", "ẹ": "e", "ȅ": "e", "è": "e", "ẻ": "e", "ȇ": "e", "ē": "e", "ḗ": "e", "ḕ": "e", "ⱸ": "e", "ę": "e", "ᶒ": "e", "ɇ": "e", "ẽ": "e", "ḛ": "e", "ꝫ": "et", "ḟ": "f", "ƒ": "f", "ᵮ": "f", "ᶂ": "f", "ǵ": "g", "ğ": "g", "ǧ": "g", "ģ": "g", "ĝ": "g", "ġ": "g", "ɠ": "g", "ḡ": "g", "ᶃ": "g", "ǥ": "g", "ḫ": "h", "ȟ": "h", "ḩ": "h", "ĥ": "h", "ⱨ": "h", "ḧ": "h", "ḣ": "h", "ḥ": "h", "ɦ": "h", "ẖ": "h", "ħ": "h", "ƕ": "hv", "í": "i", "ĭ": "i", "ǐ": "i", "î": "i", "ï": "i", "ḯ": "i", "ị": "i", "ȉ": "i", "ì": "i", "ỉ": "i", "ȋ": "i", "ī": "i", "į": "i", "ᶖ": "i", "ɨ": "i", "ĩ": "i", "ḭ": "i", "ꝺ": "d", "ꝼ": "f", "ᵹ": "g", "ꞃ": "r", "ꞅ": "s", "ꞇ": "t", "ꝭ": "is", "ǰ": "j", "ĵ": "j", "ʝ": "j", "ɉ": "j", "ḱ": "k", "ǩ": "k", "ķ": "k", "ⱪ": "k", "ꝃ": "k", "ḳ": "k", "ƙ": "k", "ḵ": "k", "ᶄ": "k", "ꝁ": "k", "ꝅ": "k", "ĺ": "l", "ƚ": "l", "ɬ": "l", "ľ": "l", "ļ": "l", "ḽ": "l", "ȴ": "l", "ḷ": "l", "ḹ": "l", "ⱡ": "l", "ꝉ": "l", "ḻ": "l", "ŀ": "l", "ɫ": "l", "ᶅ": "l", "ɭ": "l", "ł": "l", "lj": "lj", "ſ": "s", "ẜ": "s", "ẛ": "s", "ẝ": "s", "ḿ": "m", "ṁ": "m", "ṃ": "m", "ɱ": "m", "ᵯ": "m", "ᶆ": "m", "ń": "n", "ň": "n", "ņ": "n", "ṋ": "n", "ȵ": "n", "ṅ": "n", "ṇ": "n", "ǹ": "n", "ɲ": "n", "ṉ": "n", "ƞ": "n", "ᵰ": "n", "ᶇ": "n", "ɳ": "n", "ñ": "n", "nj": "nj", "ó": "o", "ŏ": "o", "ǒ": "o", "ô": "o", "ố": "o", "ộ": "o", "ồ": "o", "ổ": "o", "ỗ": "o", "ö": "o", "ȫ": "o", "ȯ": "o", "ȱ": "o", "ọ": "o", "ő": "o", "ȍ": "o", "ò": "o", "ỏ": "o", "ơ": "o", "ớ": "o", "ợ": "o", "ờ": "o", "ở": "o", "ỡ": "o", "ȏ": "o", "ꝋ": "o", "ꝍ": "o", "ⱺ": "o", "ō": "o", "ṓ": "o", "ṑ": "o", "ǫ": "o", "ǭ": "o", "ø": "o", "ǿ": "o", "õ": "o", "ṍ": "o", "ṏ": "o", "ȭ": "o", "ƣ": "oi", "ꝏ": "oo", "ɛ": "e", "ᶓ": "e", "ɔ": "o", "ᶗ": "o", "ȣ": "ou", "ṕ": "p", "ṗ": "p", "ꝓ": "p", "ƥ": "p", "ᵱ": "p", "ᶈ": "p", "ꝕ": "p", "ᵽ": "p", "ꝑ": "p", "ꝙ": "q", "ʠ": "q", "ɋ": "q", "ꝗ": "q", "ŕ": "r", "ř": "r", "ŗ": "r", "ṙ": "r", "ṛ": "r", "ṝ": "r", "ȑ": "r", "ɾ": "r", "ᵳ": "r", "ȓ": "r", "ṟ": "r", "ɼ": "r", "ᵲ": "r", "ᶉ": "r", "ɍ": "r", "ɽ": "r", "ↄ": "c", "ꜿ": "c", "ɘ": "e", "ɿ": "r", "ś": "s", "ṥ": "s", "š": "s", "ṧ": "s", "ş": "s", "ŝ": "s", "ș": "s", "ṡ": "s", "ṣ": "s", "ṩ": "s", "ʂ": "s", "ᵴ": "s", "ᶊ": "s", "ȿ": "s", "ɡ": "g", "ᴑ": "o", "ᴓ": "o", "ᴝ": "u", "ť": "t", "ţ": "t", "ṱ": "t", "ț": "t", "ȶ": "t", "ẗ": "t", "ⱦ": "t", "ṫ": "t", "ṭ": "t", "ƭ": "t", "ṯ": "t", "ᵵ": "t", "ƫ": "t", "ʈ": "t", "ŧ": "t", "ᵺ": "th", "ɐ": "a", "ᴂ": "ae", "ǝ": "e", "ᵷ": "g", "ɥ": "h", "ʮ": "h", "ʯ": "h", "ᴉ": "i", "ʞ": "k", "ꞁ": "l", "ɯ": "m", "ɰ": "m", "ᴔ": "oe", "ɹ": "r", "ɻ": "r", "ɺ": "r", "ⱹ": "r", "ʇ": "t", "ʌ": "v", "ʍ": "w", "ʎ": "y", "ꜩ": "tz", "ú": "u", "ŭ": "u", "ǔ": "u", "û": "u", "ṷ": "u", "ü": "u", "ǘ": "u", "ǚ": "u", "ǜ": "u", "ǖ": "u", "ṳ": "u", "ụ": "u", "ű": "u", "ȕ": "u", "ù": "u", "ủ": "u", "ư": "u", "ứ": "u", "ự": "u", "ừ": "u", "ử": "u", "ữ": "u", "ȗ": "u", "ū": "u", "ṻ": "u", "ų": "u", "ᶙ": "u", "ů": "u", "ũ": "u", "ṹ": "u", "ṵ": "u", "ᵫ": "ue", "ꝸ": "um", "ⱴ": "v", "ꝟ": "v", "ṿ": "v", "ʋ": "v", "ᶌ": "v", "ⱱ": "v", "ṽ": "v", "ꝡ": "vy", "ẃ": "w", "ŵ": "w", "ẅ": "w", "ẇ": "w", "ẉ": "w", "ẁ": "w", "ⱳ": "w", "ẘ": "w", "ẍ": "x", "ẋ": "x", "ᶍ": "x", "ý": "y", "ŷ": "y", "ÿ": "y", "ẏ": "y", "ỵ": "y", "ỳ": "y", "ƴ": "y", "ỷ": "y", "ỿ": "y", "ȳ": "y", "ẙ": "y", "ɏ": "y", "ỹ": "y", "ź": "z", "ž": "z", "ẑ": "z", "ʑ": "z", "ⱬ": "z", "ż": "z", "ẓ": "z", "ȥ": "z", "ẕ": "z", "ᵶ": "z", "ᶎ": "z", "ʐ": "z", "ƶ": "z", "ɀ": "z", "ff": "ff", "ffi": "ffi", "ffl": "ffl", "fi": "fi", "fl": "fl", "ij": "ij", "œ": "oe", "st": "st", "ₐ": "a", "ₑ": "e", "ᵢ": "i", "ⱼ": "j", "ₒ": "o", "ᵣ": "r", "ᵤ": "u", "ᵥ": "v", "ₓ": "x"
- };
- let newBody = '';
- for (var i = 0; i < body.length; i++) {
- if (accentedCharsList[body[i]]) {
- newBody += '' + body.charCodeAt(i) + ';';
- } else {
- newBody += body[i];
- }
+ let validation;
+ if (attributes && attributes.voice) {
+ validation = plivoUtils.validateSpeakAttributes(body, attributes.voice);
+ } else {
+ validation = plivoUtils.validateSpeakAttributes(body);
+ }
+ var item = this;
+ if (validation.success == true) {
+ var result = item.add(new Speak(Response), body, attributes);
+ return result;
+ } else {
+ throw new Exceptions.PlivoXMLValidationError(validation.msg);
}
- return this.add(new Speak(Response), newBody, attributes);
},
+ /**
+ * Add a Break element
+ * @method
+ * @param {object} attributes
+ * @param {string} [attributes.strength]
+ * @param {string} [attributes.time]
+ */
+ addBreak: function (attributes) {
+ return this.add(new Break(Response), '', attributes);
+ },
+
+
+ /**
+ * Add a Emphasis element
+ * @method
+ * @param {string} body
+ * @param {object} attributes
+ * @param {string} [attributes.level]
+ */
+ addEmphasis: function (body, attributes) {
+ return this.add(new Emphasis(Response), body, attributes);
+ },
+
+ /**
+ * Add a Lang element
+ * @method
+ * @param {string} body
+ * @param {object} attributes
+ * @param {string} [attributes.xml:lang]
+ */
+ addLang: function (body, attributes) {
+ return this.add(new Lang(Response), body, attributes);
+ },
+
+ /**
+ * Add a P element
+ * @method
+ * @param {string} body
+ */
+ addP: function (body) {
+ return this.add(new P(Response), body, {});
+ },
+
+ /**
+ * Add a Phoneme element
+ * @method
+ * @param {string} body
+ * @param {object} attributes
+ * @param {string} [attributes.alphabet]
+ * @param {string} [attributes.ph]
+ */
+ addPhoneme: function (body, attributes) {
+ return this.add(new Phoneme(Response), body, attributes);
+ },
+
+ /**
+ * Add a Prosody element
+ * @method
+ * @param {string} body
+ * @param {object} attributes
+ * @param {string} [attributes.pitch]
+ * @param {string} [attributes.rate]
+ * @param {string} [attributes.volume]
+ */
+ addProsody: function (body, attributes) {
+ return this.add(new Prosody(Response), body, attributes);
+ },
+
+ /**
+ * Add a S element
+ * @method
+ * @param {string} body
+ */
+ addS: function (body) {
+ return this.add(new S(Response), body, {});
+ },
+
+ /**
+ * Add a SayAs element
+ * @method
+ * @param {string} body
+ * @param {object} attributes
+ * @param {string} [attributes.interpret-as]
+ * @param {string} [attributes.format]
+ */
+ addSayAs: function (body, attributes) {
+ return this.add(new SayAs(Response), body, attributes);
+ },
+
+ /**
+ * Add a Sub element
+ * @method
+ * @param {string} body
+ * @param {object} attributes
+ * @param {string} [attributes.alias]
+ */
+ addSub: function (body, attributes) {
+ return this.add(new Sub(Response), body, attributes);
+ },
+
+ /**
+ * Add a W element
+ * @method
+ * @param {string} body
+ * @param {object} attributes
+ * @param {string} [attributes.role]
+ */
+ addW: function (body, attributes) {
+ return this.add(new W(Response), body, attributes);
+ },
+
+ /**
+ * Add a body to the element
+ * @method
+ * @param {string} body
+ */
+ addText: function (body) {
+ return this.elem.txt(body);
+ },
/**
* Add a Wait element
@@ -366,6 +512,20 @@ function GetDigits(Response) {
}
util.inherits(GetDigits, Response);
+/**
+ * GetInput element
+ * @constructor
+ */
+function GetInput(Response) {
+ this.element = 'GetInput';
+ this.valid_attributes = ['action', 'method', 'inputType', 'executionTimeout',
+ 'digitEndTimeout', 'speechEndTimeout', 'finishOnKey', 'numDigits',
+ 'speechModel', 'hints','language', 'interimSpeechResultsCallback',
+ 'interimSpeechResultsCallbackMethod', 'log', 'redirect', 'profanityFilter'];
+ this.nestables = ['Speak', 'Play', 'Wait'];
+}
+util.inherits(GetInput, Response);
+
/**
* Hangup element
* @constructor
@@ -445,10 +605,120 @@ util.inherits(Redirect, Response);
function Speak(Response) {
this.element = 'Speak';
this.valid_attributes = ['voice', 'language', 'loop'];
- this.nestables = [];
+ this.nestables = ['break', 'emphasis', 'lang', 'p', 'phoneme', 'prosody', 's', 'say-as', 'sub', 'w'];
}
util.inherits(Speak, Response);
+/**
+ * Break element
+ * @constructor
+ */
+function Break(Response) {
+ this.element = 'break';
+ this.valid_attributes = ['strength', 'time'];
+ this.nestables = [];
+}
+util.inherits(Break, Response);
+
+/**
+ * Emphasis element
+ * @constructor
+ */
+function Emphasis(Response) {
+ this.element = 'emphasis';
+ this.valid_attributes = ['level'];
+ this.nestables = ['break', 'emphasis', 'lang', 'phoneme', 'prosody', 'say-as', 'sub', 'w'];
+}
+util.inherits(Emphasis, Response);
+
+/**
+ * Lang element
+ * @constructor
+ */
+function Lang(Response) {
+ this.element = 'lang';
+ this.valid_attributes = ['xml:lang'];
+ this.nestables = ['break', 'emphasis', 'lang', 'p', 'phoneme', 'prosody', 's', 'say-as', 'sub', 'w'];
+}
+util.inherits(Lang, Response);
+
+/**
+ * P element
+ * @constructor
+ */
+function P(Response) {
+ this.element = 'p';
+ this.valid_attributes = [];
+ this.nestables = ['break', 'emphasis', 'lang', 'prosody', 's', 'say-as', 'sub', 'w'];
+}
+util.inherits(P, Response);
+
+/**
+ * SayAs element
+ * @constructor
+ */
+function Phoneme(Response) {
+ this.element = 'phoneme';
+ this.valid_attributes = ['alphabet', 'ph'];
+ this.nestables = [];
+}
+util.inherits(Phoneme, Response);
+
+/**
+ * Prosody element
+ * @constructor
+ */
+function Prosody(Response) {
+ this.element = 'prosody';
+ this.valid_attributes = ['pitch', 'rate', 'volume'];
+ this.nestables = ['break', 'emphasis', 'lang', 'p', 'phoneme', 'prosody', 's', 'say-as', 'sub', 'w'];
+}
+util.inherits(Prosody, Response);
+
+/**
+ * S element
+ * @constructor
+ */
+function S(Response) {
+ this.element = 's';
+ this.valid_attributes = [];
+ this.nestables = ['break', 'emphasis', 'lang', 'phoneme', 'prosody', 'say-as', 'sub', 'w'];
+}
+util.inherits(S, Response);
+
+/**
+ * SayAs element
+ * @constructor
+ */
+function SayAs(Response) {
+ this.element = 'say-as';
+ this.valid_attributes = ['interpret-as', 'format'];
+ this.nestables = [];
+}
+util.inherits(SayAs, Response);
+
+/**
+ * Sub element
+ * @constructor
+ */
+function Sub(Response) {
+ this.element = 'sub';
+ this.valid_attributes = ['alias'];
+ this.nestables = [];
+}
+util.inherits(Sub, Response);
+
+/**
+ * W element
+ * @constructor
+ */
+function W(Response) {
+ this.element = 'w';
+ this.valid_attributes = ['role'];
+ this.nestables = ['break', 'emphasis', 'phoneme', 'prosody', 'say-as', 'sub'];
+}
+util.inherits(W, Response);
+
/**
* Wait element
* @constructor
@@ -471,4 +741,3 @@ function DTMF(Response) {
}
util.inherits(DTMF, Response);
-
diff --git a/package-lock.json b/package-lock.json
index bfdb65a..347cb92 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "plivo",
- "version": "4.0.5",
+ "version": "4.1.2",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@@ -4669,6 +4669,11 @@
"integrity": "sha512-1HwIYD/8UlOtFS3QO3w7ey+SdSDFE4HRNLZoZRYVQefrOY3l17epswImeB1ijgJFQJodIaHcwkp3r/myBjFVbg==",
"dev": true
},
+ "sax": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
+ "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw=="
+ },
"semver": {
"version": "4.3.6",
"resolved": "https://registry.npmjs.org/semver/-/semver-4.3.6.tgz",
@@ -5565,6 +5570,15 @@
"mkdirp": "^0.5.1"
}
},
+ "xml2js": {
+ "version": "0.4.19",
+ "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz",
+ "integrity": "sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q==",
+ "requires": {
+ "sax": ">=0.6.0",
+ "xmlbuilder": "~9.0.1"
+ }
+ },
"xmlbuilder": {
"version": "9.0.7",
"resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz",
diff --git a/package.json b/package.json
index 5d5c8c5..93ffbdf 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "plivo",
- "version": "4.1.3",
+ "version": "4.1.6",
"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": [
@@ -64,6 +64,7 @@
"request": "^2.81.0",
"uri-parser": "^1.0.0",
"utf8": "^2.1.2",
+ "xml2js": "^0.4.19",
"xmlbuilder": "^9.0.1"
}
-}
\ No newline at end of file
+}
diff --git a/test/ssml.js b/test/ssml.js
new file mode 100644
index 0000000..ee68a06
--- /dev/null
+++ b/test/ssml.js
@@ -0,0 +1,97 @@
+import assert from 'assert';
+import { Response, Client } from '../lib/rest/client';
+import { PlivoGenericResponse } from '../lib/base.js';
+let client = new Client('sampleid', 'sammpletoken', 'sampleproxy');
+
+describe('SsmlInterface', function () {
+
+ it('Ssml - Invalid SSML XML Structure', function (done) {
+
+ let response = new Response();
+
+ // Invalid speak body
+ let speak_body = ' Here is a number read \
+ as a cardinal number: \
+ read. \
+ Here is a word spelled out: \
+ hello.';
+
+ // response.addSpeak(speak_body, { language: 'Spanish-Castilian', voice: 'Polly.*' });
+ response.addSpeak(speak_body, { language: 'Spanish-Castilian', voice: 'Polly.Conchita' }).then((result) => {
+ done(new Error("Invalid xml should be rejected and should throw error."));
+ }).catch((err) => {
+ assert.equal('Invalid SSML xml structure. Content must be a valid xml.', err.message);
+ done();
+ });
+
+ });
+
+ it('Ssml - Invalid SSML Tags', function (done) {
+
+ let response = new Response();
+
+ // Invalid speak body
+ let speak_body = ' Here is a number read \
+ as a cardinal number: \
+ read. \
+ Here is a word spelled out: \
+ hello.';
+
+ // response.addSpeak(speak_body, { language: 'Spanish-Castilian', voice: 'Polly.*' });
+ response.addSpeak(speak_body, { language: 'Spanish-Castilian', voice: 'Polly.Conchita' }).then((result) => {
+ done(new Error("Invalid xml tags should be rejected and should throw error."));
+ }).catch((err) => {
+ assert.equal('Ssml tag is not supported.', err.message);
+ done();
+ });
+
+ });
+
+ it('Ssml - Invalid Language Validation', function (done) {
+
+ let response = new Response();
+
+ // Invalid speak body
+ let speak_body = ' Here is a number';
+
+ response.addSpeak(speak_body, { language: 'Spanish-Castilian1', voice: 'Polly.Conchita' }).then((result) => {
+ done(new Error("Unsupported language `Spanish-Castilian1` should be rejected and should throw error."));
+ }).catch((err) => {
+ assert.equal('Invalid language. Language `Spanish-Castilian1` is not supported.', err.message);
+ done();
+ });
+
+ });
+
+ it('Ssml - Invalid Language-Voice Combination', function (done) {
+
+ let response = new Response();
+
+ // Invalid speak body
+ let speak_body = 'Here is a number';
+
+ response.addSpeak(speak_body, { language: 'Spanish-Castilian', voice: 'Polly.Maxim' }).then((result) => {
+ done(new Error("Invalid language voice combination should be rejected"));
+ }).catch((err) => {
+ assert.equal(' voice ‘Polly.Maxim’ is not valid. Refer for list of supported voices.', err.message);
+ done();
+ });
+
+ });
+
+ it('Ssml - Valid Language-Voice Combination', function (done) {
+
+ let response = new Response();
+
+ // Invalid speak body
+ let speak_body = 'Here is a number';
+
+ response.addSpeak(speak_body, { language: 'Spanish-Castilian', voice: 'Polly.Conchita' }).then((result) => {
+ done();
+ }).catch((err) => {
+ done('Validate Language Voice combination should be accepted.');
+ });
+
+
+ });
+});
diff --git a/test/xml.js b/test/xml.js
index 9b935fd..efb2b60 100644
--- a/test/xml.js
+++ b/test/xml.js
@@ -1,27 +1,32 @@
import assert from 'assert';
import sinon from 'sinon';
-import {Response} from '../lib/utils/plivoxml';
+import { Response } from '../lib/utils/plivoxml';
describe('PlivoXML', function () {
- it('should work', function () {
+ it('should work', function (done) {
const response = new Response();
response.addPreAnswer();
response.addRecord();
response.addHangup();
- response.addSpeak('text');
- response.addWait();
- response.addDTMF('123');
- response.addConference('test');
- response.addRedirect('url');
- response.addGetDigits();
- response.addPlay('url');
- const dial = response.addDial();
- dial.addNumber('123');
- dial.addUser('sip:test@sip.plivo.com');
- response.addMessage('∫test', {
- src: '123',
- dst: '456',
+ response.addSpeak('text').then(function (result) {
+ response.addWait();
+ response.addDTMF('123');
+ response.addConference('test');
+ response.addRedirect('url');
+ response.addGetDigits();
+ response.addPlay('url');
+ const dial = response.addDial();
+ dial.addNumber('123');
+
+ dial.addUser('sip:test@sip.plivo.com');
+ response.addMessage('∫test', {
+ src: '123',
+ dst: '456',
+ });
+ assert.equal('text123testurlurl123sip:test@sip.plivo.com∫test', response.toXML());
+ done();
+ }).catch(function (err) {
+ done("Failed to test Plivo Xml due to unknown error");
});
- assert.equal('text123testurlurl123sip:test@sip.plivo.com∫test', response.toXML());
});
});