@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
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)