@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.
- package/.circleci/config.yml +54 -0
- package/.env.sample +1 -1
- package/.github/workflows/docker-community-push-latest.yml +22 -0
- package/.github/workflows/{docker-image-push.yml → docker-image-en-tag-push.yml} +1 -1
- package/.github/workflows/docker-image-tag-community-tag-push.yml +21 -0
- package/.github/workflows/{docker-push-latest.yml → docker-push-en-push-latest.yml} +1 -1
- package/CHANGELOG.md +198 -1
- package/Dockerfile +1 -1
- package/Dockerfile-en +1 -1
- package/README.md +5 -7
- package/app.js +12 -1
- package/channels/chat21/chat21Contact.js +34 -8
- package/channels/chat21/chat21Handler.js +48 -5
- package/channels/chat21/chat21WebHook.js +34 -5
- package/channels/chat21/nativeauth.js +2 -2
- package/config/email.js +2 -1
- package/config/global.js +3 -0
- package/config/labels/widget.json +170 -16
- package/event/messageEvent.js +18 -1
- package/middleware/passport.js +10 -4
- package/models/actionsConstants.js +7 -0
- package/models/department.js +3 -0
- package/models/faq.js +8 -2
- package/models/faq_kb.js +6 -0
- package/models/message.js +10 -4
- package/models/messageConstants.js +3 -3
- package/models/request.js +33 -3
- package/package.json +31 -28
- package/pubmodules/emailNotification/requestNotification.js +380 -62
- package/pubmodules/messageActions/messageActionsInterceptor.js +20 -7
- package/pubmodules/messageTransformer/index.js +1 -1
- package/pubmodules/messageTransformer/microLanguageAttributesTransformerInterceptor.js +67 -0
- package/pubmodules/pubModulesManager.js +66 -14
- package/pubmodules/rules/conciergeBot.js +81 -49
- package/routes/auth.js +34 -10
- package/routes/campaigns.js +117 -25
- package/routes/faq.js +19 -0
- package/routes/faq_kb.js +13 -4
- package/routes/faqpub.js +1 -1
- package/routes/images.js +1 -1
- package/routes/jwt.js +0 -1
- package/routes/logs.js +26 -0
- package/routes/message.js +7 -2
- package/routes/messagesRoot.js +73 -16
- package/routes/project_user.js +36 -1
- package/routes/request.js +88 -12
- package/routes/requestUtilRoot.js +30 -0
- package/routes/urls.js +12 -0
- package/routes/users.js +5 -1
- package/services/BotSubscriptionNotifier.js +1 -0
- package/services/departmentService.js +29 -5
- package/services/emailService.js +1103 -298
- package/services/faqBotHandler.js +176 -61
- package/services/faqBotSupport.js +181 -117
- package/services/faqService.js +17 -14
- package/services/messageService.js +57 -9
- package/services/modulesManager.js +86 -23
- package/services/requestService.js +58 -17
- package/template/email/assignedEmailMessage.html +205 -0
- package/template/email/assignedRequest.html +44 -14
- package/template/email/beenInvitedExistingUser.html +2 -2
- package/template/email/beenInvitedNewUser.html +1 -1
- package/template/email/newMessage.html +31 -12
- package/template/email/passwordChanged.html +2 -3
- package/template/email/pooledEmailMessage.html +208 -0
- package/template/email/pooledRequest.html +41 -14
- package/template/email/resetPassword.html +2 -3
- package/template/email/sendTranscript.html +1 -1
- package/template/email/test.html +1 -1
- package/template/email/ticket.html +78 -52
- package/template/email/ticket.txt +5 -1
- package/template/email/verify.html +1 -1
- package/test/authentication.js +76 -4
- package/test/authenticationJwt.js +76 -2
- package/test/campaignsRoute.js +226 -0
- package/test/faqService.js +3 -3
- package/test/faqkbRoute.js +3 -2
- package/test/messageRootRoute.js +193 -0
- package/test/messageRoute.js +75 -0
- package/test/messageService.js +5 -5
- package/test/requestRoute.js +27 -9
- package/test/requestService.js +472 -11
- package/test-int/bot.js +673 -8
- package/websocket/webSocketServer.js +7 -4
- 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.
|
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
|
-
|
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
|
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
|
-
|
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,
|
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 =>
|
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)
|