@tiledesk/tiledesk-server 2.1.41 → 2.2.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (85) 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 +198 -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/chat21/chat21Contact.js +34 -8
  13. package/channels/chat21/chat21Handler.js +48 -5
  14. package/channels/chat21/chat21WebHook.js +34 -5
  15. package/channels/chat21/nativeauth.js +2 -2
  16. package/config/email.js +2 -1
  17. package/config/global.js +3 -0
  18. package/config/labels/widget.json +170 -16
  19. package/event/messageEvent.js +18 -1
  20. package/middleware/passport.js +10 -4
  21. package/models/actionsConstants.js +7 -0
  22. package/models/department.js +3 -0
  23. package/models/faq.js +8 -2
  24. package/models/faq_kb.js +6 -0
  25. package/models/message.js +10 -4
  26. package/models/messageConstants.js +3 -3
  27. package/models/request.js +33 -3
  28. package/package.json +31 -28
  29. package/pubmodules/emailNotification/requestNotification.js +380 -62
  30. package/pubmodules/messageActions/messageActionsInterceptor.js +20 -7
  31. package/pubmodules/messageTransformer/index.js +1 -1
  32. package/pubmodules/messageTransformer/microLanguageAttributesTransformerInterceptor.js +67 -0
  33. package/pubmodules/pubModulesManager.js +66 -14
  34. package/pubmodules/rules/conciergeBot.js +81 -49
  35. package/routes/auth.js +34 -10
  36. package/routes/campaigns.js +117 -25
  37. package/routes/faq.js +19 -0
  38. package/routes/faq_kb.js +13 -4
  39. package/routes/faqpub.js +1 -1
  40. package/routes/images.js +1 -1
  41. package/routes/jwt.js +0 -1
  42. package/routes/logs.js +26 -0
  43. package/routes/message.js +7 -2
  44. package/routes/messagesRoot.js +73 -16
  45. package/routes/project_user.js +36 -1
  46. package/routes/request.js +88 -12
  47. package/routes/requestUtilRoot.js +30 -0
  48. package/routes/urls.js +12 -0
  49. package/routes/users.js +5 -1
  50. package/services/BotSubscriptionNotifier.js +1 -0
  51. package/services/departmentService.js +29 -5
  52. package/services/emailService.js +1103 -298
  53. package/services/faqBotHandler.js +176 -61
  54. package/services/faqBotSupport.js +181 -117
  55. package/services/faqService.js +17 -14
  56. package/services/messageService.js +57 -9
  57. package/services/modulesManager.js +86 -23
  58. package/services/requestService.js +58 -17
  59. package/template/email/assignedEmailMessage.html +205 -0
  60. package/template/email/assignedRequest.html +44 -14
  61. package/template/email/beenInvitedExistingUser.html +2 -2
  62. package/template/email/beenInvitedNewUser.html +1 -1
  63. package/template/email/newMessage.html +31 -12
  64. package/template/email/passwordChanged.html +2 -3
  65. package/template/email/pooledEmailMessage.html +208 -0
  66. package/template/email/pooledRequest.html +41 -14
  67. package/template/email/resetPassword.html +2 -3
  68. package/template/email/sendTranscript.html +1 -1
  69. package/template/email/test.html +1 -1
  70. package/template/email/ticket.html +78 -52
  71. package/template/email/ticket.txt +5 -1
  72. package/template/email/verify.html +1 -1
  73. package/test/authentication.js +76 -4
  74. package/test/authenticationJwt.js +76 -2
  75. package/test/campaignsRoute.js +226 -0
  76. package/test/faqService.js +3 -3
  77. package/test/faqkbRoute.js +3 -2
  78. package/test/messageRootRoute.js +193 -0
  79. package/test/messageRoute.js +75 -0
  80. package/test/messageService.js +5 -5
  81. package/test/requestRoute.js +27 -9
  82. package/test/requestService.js +472 -11
  83. package/test-int/bot.js +673 -8
  84. package/websocket/webSocketServer.js +7 -4
  85. package/template/email/ticket-taking.txt +0 -7
@@ -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
  }