@tiledesk/tiledesk-server 2.1.40 → 2.2.3

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.
Files changed (91) hide show
  1. package/.circleci/config.yml +54 -0
  2. package/.env.sample +1 -1
  3. package/.github/workflows/docker-community-push-latest.yml +22 -0
  4. package/.github/workflows/{docker-image-push.yml → docker-image-en-tag-push.yml} +1 -1
  5. package/.github/workflows/docker-image-tag-community-tag-push.yml +21 -0
  6. package/.github/workflows/{docker-push-latest.yml → docker-push-en-push-latest.yml} +1 -1
  7. package/CHANGELOG.md +195 -1
  8. package/Dockerfile +1 -1
  9. package/Dockerfile-en +1 -1
  10. package/README.md +5 -7
  11. package/app.js +12 -1
  12. package/channels/channelManager.js +1 -1
  13. package/channels/chat21/chat21Contact.js +34 -8
  14. package/channels/chat21/chat21Handler.js +48 -5
  15. package/channels/chat21/chat21WebHook.js +34 -9
  16. package/channels/chat21/nativeauth.js +2 -2
  17. package/channels/chat21/package-lock.json +3013 -0
  18. package/config/email.js +2 -0
  19. package/config/global.js +3 -0
  20. package/config/labels/widget.json +170 -16
  21. package/event/messageEvent.js +18 -1
  22. package/middleware/passport.js +10 -4
  23. package/migrations/1619185894304-request-remove-duplicated-request-by-request_id--autosync.js +67 -0
  24. package/models/actionsConstants.js +7 -0
  25. package/models/department.js +3 -0
  26. package/models/faq.js +8 -2
  27. package/models/faq_kb.js +6 -0
  28. package/models/message.js +10 -4
  29. package/models/messageConstants.js +9 -3
  30. package/models/request.js +33 -3
  31. package/package.json +31 -28
  32. package/pubmodules/emailNotification/requestNotification.js +483 -56
  33. package/pubmodules/messageActions/messageActionsInterceptor.js +20 -7
  34. package/pubmodules/messageTransformer/index.js +5 -1
  35. package/pubmodules/messageTransformer/messageTransformerInterceptor.js +4 -2
  36. package/pubmodules/messageTransformer/microLanguageAttributesTransformerInterceptor.js +67 -0
  37. package/pubmodules/messageTransformer/microLanguageTransformerInterceptor.js +67 -0
  38. package/pubmodules/pubModulesManager.js +66 -13
  39. package/pubmodules/rules/conciergeBot.js +81 -49
  40. package/routes/auth.js +46 -11
  41. package/routes/campaigns.js +117 -25
  42. package/routes/department.js +2 -2
  43. package/routes/faq.js +19 -0
  44. package/routes/faq_kb.js +13 -4
  45. package/routes/faqpub.js +1 -1
  46. package/routes/files.js +17 -2
  47. package/routes/images.js +1 -1
  48. package/routes/jwt.js +0 -1
  49. package/routes/logs.js +26 -0
  50. package/routes/message.js +7 -2
  51. package/routes/messagesRoot.js +73 -16
  52. package/routes/project_user.js +36 -1
  53. package/routes/request.js +88 -12
  54. package/routes/requestUtilRoot.js +30 -0
  55. package/routes/urls.js +12 -0
  56. package/routes/users.js +5 -1
  57. package/services/BotSubscriptionNotifier.js +1 -0
  58. package/services/departmentService.js +29 -5
  59. package/services/emailService.js +1170 -239
  60. package/services/faqBotHandler.js +176 -61
  61. package/services/faqBotSupport.js +182 -117
  62. package/services/faqService.js +18 -14
  63. package/services/messageService.js +57 -9
  64. package/services/modulesManager.js +86 -23
  65. package/services/requestService.js +58 -17
  66. package/template/email/assignedEmailMessage.html +205 -0
  67. package/template/email/assignedRequest.html +44 -14
  68. package/template/email/beenInvitedExistingUser.html +2 -2
  69. package/template/email/beenInvitedNewUser.html +1 -1
  70. package/template/email/newMessage.html +31 -12
  71. package/template/email/passwordChanged.html +2 -3
  72. package/template/email/pooledEmailMessage.html +208 -0
  73. package/template/email/pooledRequest.html +41 -14
  74. package/template/email/resetPassword.html +2 -3
  75. package/template/email/sendTranscript.html +1 -1
  76. package/template/email/test.html +1 -1
  77. package/template/email/ticket.html +191 -0
  78. package/template/email/ticket.txt +11 -0
  79. package/template/email/verify.html +1 -1
  80. package/test/authentication.js +76 -4
  81. package/test/authenticationJwt.js +76 -2
  82. package/test/campaignsRoute.js +226 -0
  83. package/test/faqService.js +3 -3
  84. package/test/faqkbRoute.js +3 -2
  85. package/test/messageRootRoute.js +193 -0
  86. package/test/messageRoute.js +75 -0
  87. package/test/messageService.js +39 -2
  88. package/test/requestRoute.js +27 -9
  89. package/test/requestService.js +472 -11
  90. package/test-int/bot.js +673 -8
  91. package/websocket/webSocketServer.js +7 -4
@@ -10,9 +10,60 @@ var BotFromParticipant = require("../utils/botFromParticipant");
10
10
  var cacheUtil = require('../utils/cacheUtil');
11
11
  var eventService = require('../pubmodules/events/eventService');
12
12
  var mongoose = require('mongoose');
13
+ const { TiledeskChatbotUtil } = require('@tiledesk/tiledesk-chatbot-util');
14
+ const ActionsConstants = require('../models/actionsConstants');
13
15
 
14
16
  class FaqBotHandler {
15
17
 
18
+ static is_command(text) {
19
+ // console.log("msg:", msg);
20
+ if (!text) {
21
+ return {
22
+ 'command': null,
23
+ 'text': null
24
+ }
25
+ }
26
+ // const text = msg.text;
27
+ // console.log("msg.text:", msg.text);
28
+ // console.log("TiledeskChatbotUtil.AGENT_COMMAND:", TiledeskChatbotUtil.AGENT_COMMAND.replace(/\\\\/g, '\\'));
29
+ //const agent_pattern = new RegExp('^(' + TiledeskChatbotUtil.AGENT_COMMAND.replace(/\\/g, '\\\\') + ')$', 'm');
30
+ // console.log("agent_pattern:", agent_pattern);
31
+ //const match_agent = text.match(agent_pattern);
32
+ //console.log("match_agent: ", match_agent);
33
+ const match_agent = text.indexOf(ActionsConstants.CHAT_ACTION_MESSAGE.AGENT);
34
+ const match_close = text.indexOf(ActionsConstants.CHAT_ACTION_MESSAGE.CLOSE);
35
+ //console.log("match_agent: ", match_agent);
36
+ // const agent_handoff = null;
37
+ //if (match_agent && match_agent.length >=2) {
38
+ if (match_close >-1) {
39
+ // console.log("match!");
40
+ // let parts = text.split('\\agent');
41
+ // console.log(parts)
42
+ const new_msg_text = text.replace(ActionsConstants.CHAT_ACTION_MESSAGE.CLOSE,"");
43
+ // const new_msg_text = parts[0].trim()
44
+ // console.log(new_msg_text)
45
+ return {
46
+ 'command': ActionsConstants.CHAT_ACTION_MESSAGE.CLOSE,
47
+ 'text': new_msg_text
48
+ }
49
+ }
50
+ if (match_agent >-1) {
51
+ // console.log("match!");
52
+ // let parts = text.split('\\agent');
53
+ // console.log(parts)
54
+ const new_msg_text = text.replace(ActionsConstants.CHAT_ACTION_MESSAGE.AGENT,"");
55
+ // const new_msg_text = parts[0].trim()
56
+ // console.log(new_msg_text)
57
+ return {
58
+ 'command': ActionsConstants.CHAT_ACTION_MESSAGE.AGENT,
59
+ 'text': new_msg_text
60
+ }
61
+ }
62
+ return {
63
+ 'command': null,
64
+ 'text': text
65
+ }
66
+ }
16
67
 
17
68
 
18
69
  listen() {
@@ -51,8 +102,14 @@ class FaqBotHandler {
51
102
  var query = { "id_project": message.id_project, "id_faq_kb": faq_kb._id, "question": message.text};
52
103
 
53
104
  if (message.attributes && message.attributes.action) {
105
+
54
106
  var action = message.attributes.action;
55
-
107
+ var action_parameters_index = action.indexOf("?");
108
+ if (action_parameters_index > -1) {
109
+ action = action.substring(0,action_parameters_index);
110
+ }
111
+ winston.debug("action: " + action);
112
+
56
113
  var isObjectId = mongoose.Types.ObjectId.isValid(action);
57
114
  winston.debug("isObjectId:"+ isObjectId);
58
115
 
@@ -66,7 +123,18 @@ class FaqBotHandler {
66
123
  winston.debug("query message.attributes.action ", query);
67
124
  }
68
125
 
69
-
126
+
127
+ if (message.request && message.request.attributes && message.request.attributes.blocked_intent) {
128
+ query = { "id_project": message.id_project, "id_faq_kb": faq_kb._id, $or:[{"intent_id": message.request.attributes.blocked_intent}, {"intent_display_name": message.request.attributes.blocked_intent}]};
129
+ // TODO skip if type reset (better create a resetIntent action /reset reset the attributes) -> TODO DELETE message.request.attributes.blocked_intent for next call
130
+ winston.debug("query message.attributes.blocked_intent ", query);
131
+ // res.send({text:"ripeti la mail", action: id_intent}); fai un test che forse già funziona
132
+ }
133
+
134
+
135
+
136
+
137
+
70
138
  Faq.find(query)
71
139
  .lean().
72
140
  exec(function (err, faqs) {
@@ -91,31 +159,6 @@ class FaqBotHandler {
91
159
  answerObj.score = 100; //exact search not set score
92
160
  winston.debug("answerObj.score", answerObj.score);
93
161
 
94
-
95
-
96
- // === TEMPORARY: search for handoff to agent command (\agent)
97
- /*
98
- const handoff_parsed = TiledeskChatbotUtil.is_agent_handoff_command(message);
99
- winston.debug('handoff_parsed?', handoff_parsed);
100
-
101
- if (handoff_parsed.agent_handoff) {
102
- console.log("agent_handoff command found");
103
-
104
- messageService.send(sender, botName, message.recipient, handoff_parsed.agent_handoff,
105
- message.id_project, sender, {subtype: "info"}, 'text', undefined).then(function(savedMessage){
106
- winston.info("faqbot agent sent ", savedMessage.toObject());
107
- });
108
-
109
- // PATCH: Chat clients (i.e. web widget) remove messages with text = null
110
- // handoff_parsed.text contains the eventual text before the \agent command
111
- // or 'all the message text' if \agent was not found
112
- message.text = handoff_parsed.text? handoff_parsed.text : '';
113
- }
114
- */
115
- // === TEMPORARY: search for handoff to agent command (\agent)
116
-
117
-
118
-
119
162
  // qui
120
163
  faqBotSupport.getParsedMessage(answerObj.answer, message, faq_kb, answerObj).then(function(bot_answer) {
121
164
  // send(sender, senderFullname, recipient, text, id_project, createdBy, attributes, type) {
@@ -128,66 +171,90 @@ class FaqBotHandler {
128
171
  // attr._answer = that.getCircularReplacer(answerObj);
129
172
  if (answerObj && answerObj._id) {
130
173
  attr._answerid = answerObj._id.toString();
131
- }
132
-
174
+ }
133
175
 
134
176
  let question_payload = Object.assign({}, message);
135
177
  delete question_payload.request;
136
178
 
137
179
  winston.debug("question_payload", question_payload);
138
180
 
181
+ let clonedfaqs = faqs.slice();
182
+ if (clonedfaqs && clonedfaqs.length>0) {
183
+ clonedfaqs = clonedfaqs.shift()
184
+ }
185
+ winston.verbose("clonedfaqs", clonedfaqs);
186
+
139
187
  const intent_info = {
140
188
  intent_name: answerObj.intent_display_name,
141
189
  is_fallback: false,
142
190
  confidence: answerObj.score,
143
- question_payload: question_payload
191
+ question_payload: question_payload,
192
+ others: clonedfaqs
144
193
  }
145
194
  winston.debug("intent_info", intent_info);
146
195
  attr.intent_info = intent_info;
147
196
 
148
197
  winston.debug("answerObj", answerObj);
149
198
  // winston.info("that.getCircularReplacer(answerObj)", that.getCircularReplacer(answerObj));
150
- winston.debug("attr", attr);
199
+ winston.debug("attr", attr);
151
200
 
152
- messageService.send(sender, botName, message.recipient, bot_answer.text,
153
- message.id_project, sender, attr, bot_answer.type, bot_answer.metadata).then(function(savedMessage){
154
- winston.debug("faqbot message botAns ", savedMessage.toObject());
155
- });
156
-
157
- /* messageService.send(sender, botName, message.recipient, answerObj.answer,
158
- message.id_project, sender).then(function(savedMessage){
159
- winston.info("faqbot message sending ", savedMessage.toObject());
160
- });*/
201
+
202
+
203
+ const command_parsed = FaqBotHandler.is_command(bot_answer.text);
204
+ winston.debug('command_parsed?', command_parsed);
205
+
206
+ if (command_parsed.command) {
207
+ winston.debug("agent_handoff faqs command found");
208
+
209
+ messageService.send(sender, botName, message.recipient, command_parsed.command,
210
+ message.id_project, sender, {subtype: "info"}, 'text', undefined).then(function(savedMessage){
211
+ winston.debug("agent_handoff faqs agent sent ", savedMessage.toObject());
212
+ });
213
+ // PATCH: Chat clients (i.e. web widget) remove messages with text = null
214
+ // command_parsed.text contains the eventual text before the \agent command
215
+ // or 'all the message text' if \agent was not found
216
+ bot_answer.text = command_parsed.text? command_parsed.text : undefined;
217
+ winston.debug("bot_answer.text1 "+ bot_answer.text );
218
+ }
219
+
220
+
221
+
222
+ winston.debug("bot_answer.text2 "+ bot_answer.text );
223
+ // if (bot_answer.text) { //can be undefined id /agent only
224
+ messageService.send(sender, botName, message.recipient, bot_answer.text,
225
+ message.id_project, sender, attr, bot_answer.type, bot_answer.metadata, bot_answer.language).then(function(savedMessage){
226
+ winston.debug("faqbot message botAns ", savedMessage.toObject());
227
+ });
228
+ // }
229
+
230
+
231
+
161
232
  });
162
233
 
163
234
 
164
235
  }
165
236
 
166
-
167
- // getBotMessageNew(botAnswer, projectid, bot, language, threshold)
168
- // faqBotSupport.getBotMessageNew(answerObj, message.id_project, faq_kb, message, 1.2).then(function(botAns){
169
- // // faqBotSupport.getBotMessage(answerObj, message.id_project, message.request.department._id, message.language, 1.2).then(function(botAns){
170
- // winston.debug("faqbot message botAns ", botAns);
171
-
172
- // if (botAns) {
173
- // // let attributes = {bot_reponse_template: botAns.template};
174
- // messageService.send(sender, botName, message.recipient, botAns.text,
175
- // message.id_project, sender, botAns.attributes, botAns.type, botAns.metadata).then(function(savedMessage){
176
- // winston.info("faqbot message bot answer " ,savedMessage.toObject());
177
- // });
178
- // }
179
- // });
180
-
237
+
181
238
 
182
239
  } else {
183
240
 
184
241
  query = { "id_project": message.id_project, "id_faq_kb": faq_kb._id};
185
- query.$text = {"$search": message.text};
186
-
242
+
243
+ var search_obj = {"$search": message.text};
244
+
245
+ if (faq_kb.language) {
246
+ search_obj["$language"] = faq_kb.language;
247
+ }
248
+ query.$text = search_obj;
249
+ winston.debug("fulltext search query", query);
250
+
187
251
  Faq.find(query, {score: { $meta: "textScore" } })
188
252
  .sort( { score: { $meta: "textScore" } } ) //https://docs.mongodb.com/manual/reference/operator/query/text/#sort-by-text-search-score
189
253
  .lean().
190
254
  exec(function (err, faqs) {
255
+ if (err) {
256
+ return winston.error('Error getting fulltext objects.', err);
257
+ }
191
258
  winston.debug("faqs", faqs);
192
259
 
193
260
  // botprefix
@@ -218,11 +285,18 @@ class FaqBotHandler {
218
285
 
219
286
  winston.debug("question_payload", question_payload);
220
287
 
288
+ let clonedfaqs = faqs.slice();
289
+ if (clonedfaqs && clonedfaqs.length>0) {
290
+ clonedfaqs = clonedfaqs.shift()
291
+ }
292
+ winston.verbose("clonedfaqs", clonedfaqs);
293
+
221
294
  const intent_info = {
222
295
  intent_name: answerObj.intent_display_name,
223
296
  is_fallback: false,
224
297
  confidence: answerObj.score,
225
- question_payload: question_payload
298
+ question_payload: question_payload,
299
+ others: clonedfaqs
226
300
  }
227
301
  winston.debug("intent_info", intent_info);
228
302
  attr.intent_info = intent_info;
@@ -230,9 +304,30 @@ class FaqBotHandler {
230
304
 
231
305
 
232
306
  winston.debug("attr", attr);
307
+
308
+
309
+ const command_parsed = FaqBotHandler.is_command(bot_answer.text);
310
+ winston.debug('command_parsed?', command_parsed);
311
+
312
+ if (command_parsed.command) {
313
+ winston.debug("agent_handoff faqs command found");
314
+
315
+ messageService.send(sender, botName, message.recipient, command_parsed.command,
316
+ message.id_project, sender, {subtype: "info"}, 'text', undefined).then(function(savedMessage){
317
+ winston.debug("agent_handoff faqs agent sent ", savedMessage.toObject());
318
+ });
319
+ // PATCH: Chat clients (i.e. web widget) remove messages with text = null
320
+ // command_parsed.text contains the eventual text before the \agent command
321
+ // or 'all the message text' if \agent was not found
322
+ bot_answer.text = command_parsed.text? command_parsed.text : undefined;
323
+ winston.debug("bot_answer.text1 "+ bot_answer.text );
324
+ }
325
+
326
+
327
+
233
328
  // send(sender, senderFullname, recipient, text, id_project, createdBy, attributes) {
234
329
  messageService.send(sender, botName, message.recipient, bot_answer.text,
235
- message.id_project, sender, attr, bot_answer.type, bot_answer.metadata).then(function(savedMessage){
330
+ message.id_project, sender, attr, bot_answer.type, bot_answer.metadata, bot_answer.language).then(function(savedMessage){
236
331
 
237
332
  winston.debug("faqbot message sending ", savedMessage.toObject());
238
333
  });
@@ -244,7 +339,6 @@ class FaqBotHandler {
244
339
  var threshold = 1.2;
245
340
 
246
341
  faqBotSupport.getBotMessage(answerObj, message.id_project, faq_kb, message, threshold).then(function(botAns){
247
- // faqBotSupport.getBotMessage(answerObj, message.id_project, message.request.department._id, message.language, 1.2).then(function(botAns){
248
342
  winston.debug("faqbot message botAns ", botAns);
249
343
 
250
344
  if (botAns) {
@@ -304,9 +398,30 @@ class FaqBotHandler {
304
398
  winston.debug("attr", attr);
305
399
 
306
400
 
401
+
402
+ const command_parsed = FaqBotHandler.is_command(botAns.text);
403
+ winston.debug('command_parsed?', command_parsed);
404
+
405
+ if (command_parsed.command) {
406
+ winston.debug("agent_handoff faqs command found");
407
+
408
+ messageService.send(sender, botName, message.recipient, command_parsed.command,
409
+ message.id_project, sender, {subtype: "info"}, 'text', undefined).then(function(savedMessage){
410
+ winston.debug("agent_handoff faqs agent sent ", savedMessage.toObject());
411
+ });
412
+ // PATCH: Chat clients (i.e. web widget) remove messages with text = null
413
+ // command_parsed.text contains the eventual text before the \agent command
414
+ // or 'all the message text' if \agent was not found
415
+ botAns.text = command_parsed.text? command_parsed.text : undefined;
416
+ winston.debug("bot_answer.text1 "+ botAns.text );
417
+ }
418
+
419
+
420
+
421
+
307
422
  // send(sender, senderFullname, recipient, text, id_project, createdBy, attributes, type, metadata)
308
423
  messageService.send(sender, botName, message.recipient, botAns.text,
309
- message.id_project, sender, attr, botAns.type, botAns.metadata).then(function(savedMessage){
424
+ message.id_project, sender, attr, botAns.type, botAns.metadata, botAns.language).then(function(savedMessage){
310
425
  winston.debug("faqbot message botAns " ,savedMessage.toObject());
311
426
  });
312
427
  }