@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
package/routes/request.js CHANGED
@@ -27,9 +27,9 @@ const { check, validationResult } = require('express-validator');
27
27
 
28
28
 
29
29
 
30
- // undocumented
30
+ // undocumented, used by test
31
31
 
32
- // TODO make a synchronous chat21 version (with query parameter?) with request.support_group.created
32
+ // TODO make a synchronous chat21 version (with query parameter?) with request.support_group.create
33
33
  router.post('/',
34
34
  [
35
35
  check('text').notEmpty(),
@@ -58,7 +58,7 @@ function (req, res) {
58
58
  let messageStatus = req.body.status || MessageConstants.CHAT_MESSAGE_STATUS.SENDING;
59
59
  winston.debug('messageStatus: ' + messageStatus);
60
60
 
61
- var request_id = req.params.request_id || 'support-group-'+uuidv4();
61
+ var request_id = req.params.request_id || 'support-group-' + req.projectid + "-" + uuidv4();
62
62
 
63
63
  // createIfNotExistsWithLeadId(lead_id, fullname, email, id_project, createdBy, attributes) {
64
64
  return leadService.createIfNotExistsWithLeadId(req.body.sender || req.user._id, req.body.senderFullname || req.user.fullName , req.body.email || req.user.email, req.projectid, null, req.body.attributes || req.user.attributes)
@@ -107,7 +107,6 @@ function (req, res) {
107
107
 
108
108
 
109
109
 
110
-
111
110
  // TODO make a synchronous chat21 version (with query parameter?) with request.support_group.created
112
111
  router.patch('/:requestid', function (req, res) {
113
112
  winston.debug(req.body);
@@ -159,7 +158,9 @@ router.patch('/:requestid', function (req, res) {
159
158
  if (req.body.location) {
160
159
  update.location = req.body.location;
161
160
  }
162
-
161
+ if (req.body.priority) {
162
+ update.priority = req.body.priority;
163
+ }
163
164
 
164
165
 
165
166
  winston.verbose("Request patch update",update);
@@ -189,6 +190,7 @@ router.patch('/:requestid', function (req, res) {
189
190
 
190
191
  });
191
192
 
193
+
192
194
  // TODO make a synchronous chat21 version (with query parameter?) with request.support_group.created
193
195
  router.put('/:requestid/close', function (req, res) {
194
196
  winston.debug(req.body);
@@ -198,7 +200,8 @@ router.put('/:requestid/close', function (req, res) {
198
200
 
199
201
  winston.verbose("request closed", closedRequest);
200
202
 
201
- return res.json(closedRequest);
203
+ return res.json(closedRequest);
204
+
202
205
  });
203
206
 
204
207
 
@@ -336,7 +339,10 @@ router.put('/:requestid/assign', function (req, res) {
336
339
  winston.debug("department changed", updatedRequest);
337
340
 
338
341
  return res.json(updatedRequest);
339
- });
342
+ }).catch(function(error) {
343
+ winston.error('Error changing the department.', error)
344
+ return res.status(500).send({ success: false, msg: 'Error changing the department.' });
345
+ })
340
346
  });
341
347
  });
342
348
 
@@ -349,7 +355,10 @@ router.put('/:requestid/departments', function (req, res) {
349
355
  winston.debug("department changed", updatedRequest);
350
356
 
351
357
  return res.json(updatedRequest);
352
- });
358
+ }).catch(function(error) {
359
+ winston.error('Error changing the department.', error)
360
+ return res.status(500).send({ success: false, msg: 'Error changing the department.' });
361
+ })
353
362
  });
354
363
 
355
364
 
@@ -541,6 +550,37 @@ router.delete('/:requestid', function (req, res) {
541
550
 
542
551
 
543
552
 
553
+ router.delete('/id/:id', function (req, res) {
554
+
555
+ var projectuser = req.projectuser;
556
+
557
+
558
+ if (projectuser.role != "owner" ) {
559
+ return res.status(403).send({ success: false, msg: 'Unauthorized.' });
560
+ }
561
+
562
+ Request.remove({ _id: req.params.id }, function (err, request) {
563
+ if (err) {
564
+ winston.error('--- > ERROR ', err);
565
+ return res.status(500).send({ success: false, msg: 'Error deleting object.' });
566
+ }
567
+
568
+ if (!request) {
569
+ return res.status(404).send({ success: false, msg: 'Object not found.' });
570
+ }
571
+
572
+ winston.verbose('Request deleted with id: '+ req.params.id );
573
+
574
+ requestEvent.emit('request.delete', request);
575
+
576
+ res.json(request);
577
+
578
+ });
579
+ });
580
+
581
+
582
+
583
+
544
584
  router.get('/', function (req, res, next) {
545
585
 
546
586
  winston.debug("req projectid", req.projectid);
@@ -632,6 +672,11 @@ router.get('/', function (req, res, next) {
632
672
  query.hasBot = req.query.hasbot;
633
673
  }
634
674
 
675
+ // if (req.query.waiting_time_exists) { //non basta aggiungi anche che nn è null
676
+ // query.waiting_time = {"$exists": req.query.waiting_time_exists} //{$ne:null}
677
+ // winston.debug('REQUEST ROUTE - QUERY waiting_time_exists', query.waiting_time_exists);
678
+ // }
679
+
635
680
 
636
681
  if (req.query.tags) {
637
682
  winston.debug('req.query.tags', req.query.tags);
@@ -826,7 +871,7 @@ router.get('/', function (req, res, next) {
826
871
  });
827
872
 
828
873
 
829
-
874
+ // TODO converti con fast-csv e stream
830
875
  // DOWNLOAD HISTORY REQUESTS AS CSV
831
876
  router.get('/csv', function (req, res, next) {
832
877
 
@@ -918,7 +963,7 @@ router.get('/csv', function (req, res, next) {
918
963
  query.createdAt = { $gte: new Date(Date.parse(startDate)).toISOString() };
919
964
  winston.debug('REQUEST ROUTE - QUERY CREATED AT (only for start date)', query.createdAt);
920
965
  }
921
-
966
+ winston.debug("csv query", query);
922
967
 
923
968
  var direction = 1; //-1 descending , 1 ascending
924
969
  if (req.query.direction) {
@@ -938,11 +983,13 @@ router.get('/csv', function (req, res, next) {
938
983
  winston.debug("sort query", sortQuery);
939
984
 
940
985
  winston.debug('REQUEST ROUTE - REQUEST FIND ', query)
941
- return Request.find(query, '-transcript -agents -status -__v').
986
+ return Request.find(query, '-transcript -status -__v').
942
987
  skip(skip).limit(limit).
943
988
  //populate('department', {'_id':-1, 'name':1}).
944
989
  populate('department').
945
990
  populate('lead').
991
+ // populate('participatingBots').
992
+ // populate('participatingAgents').
946
993
  lean().
947
994
  // populate({
948
995
  // path: 'department',
@@ -987,17 +1034,46 @@ router.get('/csv', function (req, res, next) {
987
1034
 
988
1035
  element.lead_email = lead_email;
989
1036
 
1037
+ var tags = [];
1038
+ var tagsString = "";
1039
+ if (element.tags && element.tags.length>0) {
1040
+
1041
+ element.tags.forEach(function(tag) {
1042
+ // tags = tags + tag.tag + ", ";
1043
+ tags.push(tag.tag);
1044
+ });
1045
+ }
1046
+ tagsString = tags.join(", ")
1047
+
1048
+ winston.debug('tagsString ' +tagsString)
1049
+
1050
+ element.tags = tagsString;
1051
+
1052
+
1053
+ // var participatingAgents = "";
1054
+ // if (element.participatingAgents && element.participatingAgents.length>0) {
1055
+ // element.participatingAgents.forEach(function(agent) {
1056
+ // participatingAgents = participatingAgents + ", " + agent;
1057
+ // });
1058
+ // }
1059
+ // // da terminare e testare. potrebbe essere troppo lenta la query per tanti record
1060
+ // element.participatingAgents = participatingAgents;
1061
+
1062
+
1063
+
990
1064
  delete element.lead;
991
1065
 
992
1066
  delete element.attributes;
993
1067
 
994
1068
  delete element.notes;
995
1069
 
996
- delete element.tags;
1070
+ // delete element.tags;
997
1071
 
998
1072
  delete element.channelOutbound;
999
1073
 
1000
1074
  delete element.location;
1075
+
1076
+ delete element.snapshot;
1001
1077
 
1002
1078
 
1003
1079
  // TODO print also lead. use a library to flattize
@@ -0,0 +1,30 @@
1
+ var express = require('express');
2
+
3
+ var router = express.Router();
4
+
5
+ var Request = require("../models/request");
6
+ var winston = require('../config/winston');
7
+
8
+ // https://tiledesk-server-pre.herokuapp.com/requests_util/lookup/id_project/support-group-60ffe291f725db00347661ef-b4cb6875785c4a23b27244fe498eecf4
9
+ router.get('/lookup/id_project/:request_id', function(req, res) {
10
+ winston.debug("lookup: "+req.params.request_id);
11
+
12
+ return Request.findOne({request_id: req.params.request_id}).select("id_project").exec(function(err, request) {
13
+ if (err) {
14
+ return res.status(500).send({success: false, msg: 'Error creating message', err:err });
15
+ }
16
+ if (!request) {
17
+ return res.status(404).send({success: false, msg: "Request with " + req.params.request_id + " not found" });
18
+ }
19
+ winston.debug("request",request);
20
+ res.json({id_project: request.id_project});
21
+ });
22
+
23
+ });
24
+
25
+
26
+ module.exports = router;
27
+
28
+
29
+
30
+
package/routes/urls.js ADDED
@@ -0,0 +1,12 @@
1
+ var express = require('express');
2
+ var router = express.Router();
3
+ var winston = require('../config/winston');
4
+
5
+
6
+ router.get('/redirect', function (req, res) {
7
+ winston.debug("redirect: "+ req.query.path);
8
+ res.redirect(req.query.path);
9
+ });
10
+
11
+
12
+ module.exports = router;
package/routes/users.js CHANGED
@@ -154,11 +154,15 @@ router.get('/resendverifyemail', function (req, res) {
154
154
 
155
155
  router.get('/', function (req, res) {
156
156
  winston.debug("users");
157
- User.findById(req.user.id, 'firstname lastname _id', function (err, user) {
157
+ var userid = req.user.id;
158
+
159
+ User.findById(userid, 'email firstname lastname _id emailverified', function (err, user) {
158
160
  if (err) {
161
+ winston.error('Error getting object.',err);
159
162
  return res.status(500).send({ success: false, msg: 'Error getting object.' });
160
163
  }
161
164
  if (!user) {
165
+ winston.warn("Object not found with id " +req.user.id);
162
166
  return res.status(404).send({ success: false, msg: 'Object not found.' });
163
167
  }
164
168
  winston.debug("GET USER BY ID RES JSON", user);
@@ -55,6 +55,7 @@ class BotSubscriptionNotifier {
55
55
  winston.verbose("SENT notify for bot with url " + url + " with err " + err);
56
56
  if (err) {
57
57
  winston.error("Error sending notify for bot with url " + url + " with err " + err);
58
+ //TODO Reply with error
58
59
  // next(err, json);
59
60
  }
60
61
  });
@@ -78,7 +78,9 @@ roundRobin(operatorSelectedEvent) {
78
78
  // db.getCollection('requests').find({id_project: "5c12662488379d0015753c49", participants: { $exists: true, $ne: [] }}).sort({_id:-1}).limit(1)
79
79
 
80
80
  // https://stackoverflow.com/questions/14789684/find-mongodb-records-where-array-field-is-not-empty
81
- let query = {id_project: operatorSelectedEvent.id_project, participants: { $exists: true, $ne: [] }};
81
+ let query = {id_project: operatorSelectedEvent.id_project,
82
+ hasBot:false, preflight:false, status: { $gt: 100 },
83
+ participants: { $exists: true, $ne: [] }};
82
84
 
83
85
  winston.debug('query', query);
84
86
 
@@ -94,6 +96,7 @@ roundRobin(operatorSelectedEvent) {
94
96
  winston.debug('lastRequests',lastRequests);
95
97
 
96
98
  if (lastRequests.length==0) {
99
+ winston.debug('roundRobin lastRequest not found. fall back to random info',operatorSelectedEvent);
97
100
  winston.verbose('roundRobin lastRequest not found. fall back to random');
98
101
  //first request use default random algoritm
99
102
  // return 0;
@@ -121,11 +124,29 @@ roundRobin(operatorSelectedEvent) {
121
124
  if (operatorSelectedEvent.available_agents && operatorSelectedEvent.available_agents.length==0) {
122
125
  winston.debug('operatorSelectedEvent.available_agents empty ', operatorSelectedEvent.available_agents);
123
126
  return resolve(operatorSelectedEvent);
124
- }
127
+ }
128
+
129
+
130
+ //when the agent has a custom auth jwt. so he has uuid_user and not id_user
131
+ // error: uncaughtException: Cannot read property 'toString' of undefined
132
+ // 2021-10-14T08:54:00.099370+00:00 app[web.1]: TypeError: Cannot read property 'toString' of undefined
133
+ // 2021-10-14T08:54:00.099371+00:00 app[web.1]: at /app/services/departmentService.js:130:119
134
+ // 2021-10-14T08:54:00.099372+00:00 app[web.1]: at Array.findIndex (<anonymous>)
135
+ // 2021-10-14T08:54:00.099372+00:00 app[web.1]: at /app/services/departmentService.js:130:74
136
+ // 2021-10-14T08:54:00.099372+00:00 app[web.1]: at /app/node_modules/mongoose/lib/model.js:5074:18
137
+ // 2021-10-14T08:54:00.099381+00:00 app[web.1]: at processTicksAndRejections (internal/process/task_q
125
138
 
126
139
  // https://stackoverflow.com/questions/15997879/get-the-index-of-the-object-inside-an-array-matching-a-condition
127
- let lastOperatorIndex = operatorSelectedEvent.available_agents.findIndex(projectUser => projectUser.id_user.toString() === lastOperatorId);
140
+ let lastOperatorIndex = operatorSelectedEvent.available_agents.findIndex(projectUser => {
141
+ if (projectUser.id_user) {
142
+ return projectUser.id_user.toString() === lastOperatorId;
143
+ } else { //when the agent has a custom auth jwt. so he has uuid_user and not id_user
144
+ return projectUser.uuid_user === lastOperatorId;
145
+ }
146
+ }
147
+ );
128
148
 
149
+
129
150
  // if lastOperatorIndex is -1(last operator is not available)-> that.nextOperator increment index +1 so it's work
130
151
 
131
152
 
@@ -133,6 +154,9 @@ roundRobin(operatorSelectedEvent) {
133
154
 
134
155
  winston.debug('lastOperatorIndex: ' + lastOperatorIndex);
135
156
 
157
+ winston.debug('operatorSelectedEvent.available_agents: ', operatorSelectedEvent.available_agents);
158
+
159
+
136
160
  let nextOperator = that.nextOperator(operatorSelectedEvent.available_agents, lastOperatorIndex);
137
161
 
138
162
 
@@ -208,8 +232,8 @@ getOperators(departmentid, projectid, nobot, disableWebHookCall, context) {
208
232
  }
209
233
  // console.log("department", department);
210
234
  if (!department) {
211
- winston.error("Department not found for query ", query);
212
- return reject({ success: false, msg: 'Department not found.' });
235
+ winston.error("Department not found for projectid: "+ projectid +" for query: ", query, context);
236
+ return reject({ success: false, msg: 'Department not found for projectid: '+ projectid +' for query: ' + JSON.stringify(query) });
213
237
  }
214
238
  // console.log('OPERATORS - »»» DETECTED ROUTING ', department.routing)
215
239
  // console.log('OPERATORS - »»» DEPARTMENT - ID BOT ', department.id_bot)