@tiledesk/tiledesk-voice-twilio-connector 0.1.9 → 0.1.10

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 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("(vxml) VXML to SEND: "+ messageToVXML);
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
- winston.error("(voice) API_URL is mandatory. Exit...");
966
- return callback('Missing parameter: API_URL');
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,6 @@
1
1
  {
2
2
  "name": "@tiledesk/tiledesk-voice-twilio-connector",
3
- "version": "0.1.9",
3
+ "version": "0.1.10",
4
4
  "description": "Tiledesk VOICE Twilio connector",
5
5
  "license": "MIT",
6
6
  "author": "Gabriele Panico",
@@ -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,6 +230,12 @@ 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]
@@ -231,7 +249,7 @@ class TiledeskTwilioTranslator {
231
249
 
232
250
  const prompt = this.promptVXML(rootEle, message, xmlAttributes);
233
251
 
234
- const queryUrl = '?intentName='+ xmlAttributes.intentName + '&previousIntentTimestamp='+Date.now();
252
+ const queryUrl = '?intentName='+ querystring.encode(xmlAttributes.intentName) + '&previousIntentTimestamp='+Date.now();
235
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
 
@@ -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)
@@ -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
- module.exports = {isCarousel, isImage, isFile, isAudio, isInfo, messageType}
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}