@tiledesk/tiledesk-voice-twilio-connector 0.1.9 → 0.1.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.js +5 -38
- package/package.json +1 -1
- package/tiledesk/TiledeskTwilioTranslator.js +28 -10
- package/tiledesk/constants.js +12 -1
- package/tiledesk/utils-message.js +36 -1
package/index.js
CHANGED
|
@@ -274,44 +274,11 @@ router.post('/nextblock/:callSid/', async(req, res) => {
|
|
|
274
274
|
//update delayIndex for wait command message time
|
|
275
275
|
await voiceChannel.saveDelayIndexForCallId(callSid)
|
|
276
276
|
}
|
|
277
|
-
|
|
278
|
-
/*
|
|
279
|
-
if(usertext === '' || !usertext){
|
|
280
|
-
//get message from queue
|
|
281
|
-
queue = await tdChannel.getMessagesFromQueue(conversation_id)
|
|
282
|
-
winston.debug('QUEUE --> ',queue.length)
|
|
283
|
-
if(queue.length === 0){
|
|
284
|
-
//CASE: queue is empty --> generate Tiledesk wait message
|
|
285
|
-
message = await tdChannel.generateWaitTdMessage(ani, callId)
|
|
286
|
-
winston.debug('QUEUE is empty--> ',queue)
|
|
287
|
-
}else{
|
|
288
|
-
//CASE: queue has at least one message to reproduce --> get message from tiledesk queue
|
|
289
|
-
message = queue[0]
|
|
290
|
-
winston.debug('QUEUE --> ',queue[0])
|
|
291
|
-
//remove message from queue
|
|
292
|
-
await tdChannel.removeMessageFromQueue(conversation_id, message._id)
|
|
293
|
-
|
|
294
|
-
queue = await tdChannel.getMessagesFromQueue(conversation_id)
|
|
295
|
-
winston.debug('QUEUE after remove --> ',queue.length)
|
|
296
|
-
}
|
|
297
|
-
}else{
|
|
298
|
-
//send message to tiledesk
|
|
299
|
-
let tiledeskMessage= {
|
|
300
|
-
text:usertext,
|
|
301
|
-
senderFullname: ani,
|
|
302
|
-
type: 'text',
|
|
303
|
-
channel: { name: CHANNEL_NAME }
|
|
304
|
-
};
|
|
305
|
-
let tdMessage = await tdChannel.send(tiledeskMessage, user.token, conversation_id);
|
|
306
|
-
winston.debug("message sent : ", tdMessage);
|
|
307
|
-
//generate Tiledesk wait message
|
|
308
|
-
message = await tdChannel.generateWaitTdMessage(ani, callId)
|
|
309
|
-
}
|
|
310
|
-
*/
|
|
277
|
+
|
|
311
278
|
|
|
312
279
|
// convert response to vxml
|
|
313
280
|
let messageToVXML = await tdTranslator.toVXML(message, callSid, vxmlAttributes)
|
|
314
|
-
winston.debug("(
|
|
281
|
+
winston.debug("(voice) VXML to SEND: "+ messageToVXML);
|
|
315
282
|
|
|
316
283
|
// Render the response as XML in reply to the webhook request
|
|
317
284
|
res.set('Content-Type', 'text/xml');
|
|
@@ -962,12 +929,12 @@ async function startApp(settings, callback) {
|
|
|
962
929
|
}
|
|
963
930
|
|
|
964
931
|
if (!settings.API_URL) {
|
|
965
|
-
|
|
966
|
-
|
|
932
|
+
let port = process.env.PORT || 3000;
|
|
933
|
+
API_URL = 'http://localhost:' + port;
|
|
967
934
|
} else {
|
|
968
935
|
API_URL = settings.API_URL;
|
|
969
|
-
winston.info("(voice) API_URL: " + API_URL);
|
|
970
936
|
}
|
|
937
|
+
winston.info("(voice) API_URL: " + API_URL)
|
|
971
938
|
|
|
972
939
|
if (!settings.BASE_URL) {
|
|
973
940
|
winston.error("(voice) BASE_URL is mandatory. Exit...");
|
package/package.json
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
const { v4: uuidv4 } = require("uuid");
|
|
2
2
|
const winston = require("../winston");
|
|
3
3
|
const xmlbuilder = require("xmlbuilder");
|
|
4
|
+
const querystring = require("querystring");
|
|
5
|
+
|
|
4
6
|
const utils = require("./utils-message.js");
|
|
5
7
|
const MENU_CHOICE = require("./constants.js").MENU_CHOICE;
|
|
6
8
|
const WAIT_MESSAGE = require("./constants.js").WAIT_MESSAGE;
|
|
@@ -9,6 +11,8 @@ const SETTING_MESSAGE = require('./constants').SETTING_MESSAGE
|
|
|
9
11
|
const CHANNEL_NAME = require('./constants').CHANNEL_NAME
|
|
10
12
|
|
|
11
13
|
const TYPE_ACTION_VXML = require('./constants').TYPE_ACTION_VXML
|
|
14
|
+
const TYPE_MESSAGE = require('./constants').TYPE_MESSAGE
|
|
15
|
+
const INFO_MESSAGE_TYPE = require('./constants').INFO_MESSAGE_TYPE
|
|
12
16
|
|
|
13
17
|
class TiledeskTwilioTranslator {
|
|
14
18
|
/**
|
|
@@ -63,6 +67,14 @@ class TiledeskTwilioTranslator {
|
|
|
63
67
|
vxmlAttributes = this.manageVoiceAttributes(msg, vxmlAttributes)
|
|
64
68
|
//const header = this.headerVXML(xml, vxmlAttributes);
|
|
65
69
|
|
|
70
|
+
//MANAGE CLOSE info message
|
|
71
|
+
const isInfoSupport = utils.messageType(TYPE_MESSAGE.INFO_SUPPORT, msg)
|
|
72
|
+
winston.verbose("[TiledeskVXMLTranslator] isInfoSupport::"+ isInfoSupport);
|
|
73
|
+
if(isInfoSupport && utils.infoMessageType(msg) === INFO_MESSAGE_TYPE.CHAT_CLOSED){
|
|
74
|
+
const hangUp = this.hangupCall(xml)
|
|
75
|
+
return hangUp;
|
|
76
|
+
}
|
|
77
|
+
|
|
66
78
|
|
|
67
79
|
if (msg.attributes && msg.attributes.commands && msg.attributes.commands.length > 0 ) {
|
|
68
80
|
const commands = msg.attributes.commands;
|
|
@@ -218,10 +230,16 @@ class TiledeskTwilioTranslator {
|
|
|
218
230
|
return buttons;
|
|
219
231
|
}
|
|
220
232
|
|
|
233
|
+
async hangupCall(rootEle){
|
|
234
|
+
rootEle.ele("Hangup").up()
|
|
235
|
+
|
|
236
|
+
return rootEle.end({ pretty: true });
|
|
237
|
+
}
|
|
238
|
+
|
|
221
239
|
|
|
222
240
|
async delayVXMLConverter(rootEle, message, xmlAttributes){
|
|
223
241
|
const command = message.attributes.commands[0]
|
|
224
|
-
rootEle.ele("Redirect", {
|
|
242
|
+
rootEle.ele("Redirect", {method: "POST"}, this.BASE_URL + '/nextblock/' + xmlAttributes.callSid).up()
|
|
225
243
|
|
|
226
244
|
return rootEle.end({ pretty: true });
|
|
227
245
|
}
|
|
@@ -231,8 +249,8 @@ class TiledeskTwilioTranslator {
|
|
|
231
249
|
|
|
232
250
|
const prompt = this.promptVXML(rootEle, message, xmlAttributes);
|
|
233
251
|
|
|
234
|
-
const queryUrl = '?intentName='+ xmlAttributes.intentName + '&previousIntentTimestamp='+Date.now();
|
|
235
|
-
rootEle.ele("Redirect", {
|
|
252
|
+
const queryUrl = '?intentName='+ querystring.encode(xmlAttributes.intentName) + '&previousIntentTimestamp='+Date.now();
|
|
253
|
+
rootEle.ele("Redirect", {method: "POST"}, this.BASE_URL + '/nextblock/' + xmlAttributes.callSid + queryUrl).up()
|
|
236
254
|
//prompt.ele("submit", { fetchhint: "safe", expr: "proxyBaseUrl +'/nextblock/' + session.connection.calltoken", method: "post", namelist: "usertext session intentName previousIntentTimestamp" });
|
|
237
255
|
|
|
238
256
|
return rootEle.end({ pretty: true });
|
|
@@ -249,7 +267,7 @@ class TiledeskTwilioTranslator {
|
|
|
249
267
|
gather.att("timeout", xmlAttributes.noInputTimeout/1000 ).up();
|
|
250
268
|
}
|
|
251
269
|
|
|
252
|
-
const queryUrl = '?intentName='+ xmlAttributes.intentName + "&previousIntentTimestamp="+Date.now();
|
|
270
|
+
const queryUrl = '?intentName='+ querystring.encode(xmlAttributes.intentName) + "&previousIntentTimestamp="+Date.now();
|
|
253
271
|
gather.att("action", this.BASE_URL + '/nextblock/' + xmlAttributes.callSid + queryUrl)
|
|
254
272
|
.att("method", "POST")
|
|
255
273
|
.att("language", xmlAttributes.voiceLanguage)
|
|
@@ -296,7 +314,7 @@ class TiledeskTwilioTranslator {
|
|
|
296
314
|
options.forEach((option) => menu_options += option.value + ':' + option.action.substring(1) + ';')
|
|
297
315
|
|
|
298
316
|
|
|
299
|
-
let queryUrl = '?intentName='+ xmlAttributes.intentName + '&previousIntentTimestamp='+Date.now() + '&menu_options=' + menu_options;
|
|
317
|
+
let queryUrl = '?intentName='+ querystring.encode(xmlAttributes.intentName) + '&previousIntentTimestamp='+Date.now() + '&menu_options=' + menu_options;
|
|
300
318
|
const handleNoInputNoMatchQuery = await this.handleNoInputNoMatch(rootEle, message, xmlAttributes);
|
|
301
319
|
if(handleNoInputNoMatchQuery && handleNoInputNoMatchQuery.queryNoMatch){
|
|
302
320
|
queryUrl += '&button_action='+ handleNoInputNoMatchQuery.queryNoMatch.split('button_action=')[1]
|
|
@@ -326,7 +344,7 @@ class TiledeskTwilioTranslator {
|
|
|
326
344
|
|
|
327
345
|
const gather = rootEle.ele("Gather", { input: "dtmf"})
|
|
328
346
|
|
|
329
|
-
const queryUrl = '?intentName='+ xmlAttributes.intentName + "&previousIntentTimestamp="+Date.now();
|
|
347
|
+
const queryUrl = '?intentName='+ querystring.encode(xmlAttributes.intentName) + "&previousIntentTimestamp="+Date.now();
|
|
330
348
|
gather.att("timeout", xmlAttributes.noInputTimeout/1000 )
|
|
331
349
|
.att("action", this.BASE_URL + '/menublock/' + xmlAttributes.callSid + queryUrl)
|
|
332
350
|
.att("method", "POST")
|
|
@@ -402,8 +420,8 @@ class TiledeskTwilioTranslator {
|
|
|
402
420
|
value: 'no_input'
|
|
403
421
|
}
|
|
404
422
|
|
|
405
|
-
|
|
406
|
-
queryNoInput = 'intentName='+ attributes.intentName + '&previousIntentTimestamp='+Date.now() + '&button_action='+button_noIput.action.substring(1);
|
|
423
|
+
|
|
424
|
+
queryNoInput = 'intentName='+ querystring.encode(attributes.intentName) + '&previousIntentTimestamp='+Date.now() + '&button_action='+button_noIput.action.substring(1);
|
|
407
425
|
//rootEle.ele("Redirect", {}, this.BASE_URL + '/handle/' + attributes.callSid + '/no_input'+ queryNoInput)
|
|
408
426
|
|
|
409
427
|
|
|
@@ -430,7 +448,7 @@ class TiledeskTwilioTranslator {
|
|
|
430
448
|
value: 'no_match'
|
|
431
449
|
}
|
|
432
450
|
|
|
433
|
-
queryNoMatch = 'intentName='+ attributes.intentName + '&previousIntentTimestamp='+Date.now() + '&button_action='+button_noMatch.action.substring(1); //remove '#' from intentId because is not a valid char for XML lang
|
|
451
|
+
queryNoMatch = 'intentName='+ querystring.encode(attributes.intentName) + '&previousIntentTimestamp='+Date.now() + '&button_action='+button_noMatch.action.substring(1); //remove '#' from intentId because is not a valid char for XML lang
|
|
434
452
|
//rootEle.ele("Redirect", {}, this.BASE_URL + '/handle/' + attributes.callSid + '/no_match'+ queryNoMatch)
|
|
435
453
|
|
|
436
454
|
/*element.ele("nomatch")
|
|
@@ -518,7 +536,7 @@ class TiledeskTwilioTranslator {
|
|
|
518
536
|
|
|
519
537
|
const transfer = rootEle.ele("Dial");
|
|
520
538
|
|
|
521
|
-
let queryUrl = '?intentName='+ attributes.intentName + '&previousIntentTimestamp='+Date.now()
|
|
539
|
+
let queryUrl = '?intentName='+ querystring.encode(attributes.intentName) + '&previousIntentTimestamp='+Date.now()
|
|
522
540
|
/* <-- transfer error --> */
|
|
523
541
|
if(lastCommand.settings && lastCommand.settings.falseIntent){
|
|
524
542
|
queryUrl += '&' + 'button_success=' + attributes.trueIntent.substring(1)
|
package/tiledesk/constants.js
CHANGED
|
@@ -7,7 +7,18 @@ module.exports = {
|
|
|
7
7
|
FRAME: 'frame',
|
|
8
8
|
GALLERY: 'gallery',
|
|
9
9
|
INFO: 'info',
|
|
10
|
-
SUPPORT_INFO: 'support/info'
|
|
10
|
+
SUPPORT_INFO: 'support/info',
|
|
11
|
+
INFO_SUPPORT: 'info/support'
|
|
12
|
+
},
|
|
13
|
+
INFO_MESSAGE_TYPE: {
|
|
14
|
+
CHAT_REOPENED : 'CHAT_REOPENED',
|
|
15
|
+
CHAT_CLOSED : 'CHAT_CLOSED',
|
|
16
|
+
MEMBER_JOINED_GROUP : 'MEMBER_JOINED_GROUP',
|
|
17
|
+
MEMBER_LEFT_GROUP : "MEMBER_LEFT_GROUP",
|
|
18
|
+
LEAD_UPDATED : "LEAD_UPDATED",
|
|
19
|
+
TOUCHING_OPERATOR : "TOUCHING_OPERATOR",
|
|
20
|
+
LIVE_PAGE : "LIVE_PAGE",
|
|
21
|
+
PLAN_EXPIRED : "PLAN_EXPIRED"
|
|
11
22
|
},
|
|
12
23
|
MESSAGE_TYPE_MINE: 'MINE',
|
|
13
24
|
MESSAGE_TYPE_OTHERS: 'OTHERS',
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
|
|
2
2
|
const TYPE_MESSAGE = require('./constants').TYPE_MESSAGE
|
|
3
|
+
const INFO_MESSAGE_TYPE = require('./constants').INFO_MESSAGE_TYPE
|
|
3
4
|
const MESSAGE_TYPE_MINE = require('./constants').MESSAGE_TYPE_MINE
|
|
4
5
|
const MESSAGE_TYPE_OTHERS = require('./constants').MESSAGE_TYPE_OTHERS
|
|
5
6
|
|
|
@@ -38,6 +39,13 @@ function isInfo(message) {
|
|
|
38
39
|
return false;
|
|
39
40
|
}
|
|
40
41
|
|
|
42
|
+
function isInfoSupport(message) {
|
|
43
|
+
if (message && message.attributes && message.attributes.subtype === TYPE_MESSAGE.INFO_SUPPORT) {
|
|
44
|
+
return true;
|
|
45
|
+
}
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
|
|
41
49
|
function isMine(message, user) {
|
|
42
50
|
if (message && message.sender && message.sender === user.userid) {
|
|
43
51
|
return true;
|
|
@@ -50,6 +58,9 @@ function messageType(msgType, message, user) {
|
|
|
50
58
|
if (msgType === TYPE_MESSAGE.INFO) {
|
|
51
59
|
return this.isInfo(message);
|
|
52
60
|
}
|
|
61
|
+
if (msgType === TYPE_MESSAGE.INFO_SUPPORT) {
|
|
62
|
+
return this.isInfoSupport(message);
|
|
63
|
+
}
|
|
53
64
|
if (msgType === MESSAGE_TYPE_MINE) {
|
|
54
65
|
return isMine(message, user);
|
|
55
66
|
}
|
|
@@ -61,4 +72,28 @@ function messageType(msgType, message, user) {
|
|
|
61
72
|
}
|
|
62
73
|
}
|
|
63
74
|
|
|
64
|
-
|
|
75
|
+
function infoMessageType(msg){
|
|
76
|
+
if(msg && msg.attributes.messagelabel && msg.attributes.messagelabel.key === INFO_MESSAGE_TYPE.MEMBER_JOINED_GROUP){
|
|
77
|
+
return INFO_MESSAGE_TYPE.MEMBER_JOINED_GROUP
|
|
78
|
+
}
|
|
79
|
+
if(msg && msg.attributes.messagelabel && msg.attributes.messagelabel.key === INFO_MESSAGE_TYPE.CHAT_CLOSED){
|
|
80
|
+
return INFO_MESSAGE_TYPE.CHAT_CLOSED
|
|
81
|
+
}
|
|
82
|
+
if(msg && msg.attributes.messagelabel && msg.attributes.messagelabel.key === INFO_MESSAGE_TYPE.CHAT_REOPENED){
|
|
83
|
+
return INFO_MESSAGE_TYPE.CHAT_REOPENED
|
|
84
|
+
}
|
|
85
|
+
if(msg && msg.attributes.messagelabel && msg.attributes.messagelabel.key === INFO_MESSAGE_TYPE.TOUCHING_OPERATOR){
|
|
86
|
+
return INFO_MESSAGE_TYPE.TOUCHING_OPERATOR
|
|
87
|
+
}
|
|
88
|
+
if(msg && msg.attributes.messagelabel && msg.attributes.messagelabel.key === INFO_MESSAGE_TYPE.LEAD_UPDATED){
|
|
89
|
+
return INFO_MESSAGE_TYPE.LEAD_UPDATED
|
|
90
|
+
}
|
|
91
|
+
if(msg && msg.attributes.messagelabel && msg.attributes.messagelabel.key === INFO_MESSAGE_TYPE.MEMBER_LEFT_GROUP){
|
|
92
|
+
return INFO_MESSAGE_TYPE.MEMBER_LEFT_GROUP
|
|
93
|
+
}
|
|
94
|
+
if(msg && msg.attributes.messagelabel && msg.attributes.messagelabel.key === INFO_MESSAGE_TYPE.LIVE_PAGE){
|
|
95
|
+
return INFO_MESSAGE_TYPE.LIVE_PAGE
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
module.exports = {isCarousel, isImage, isFile, isAudio, isInfo, isInfoSupport, messageType, infoMessageType}
|