@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.
- 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 +195 -1
- package/Dockerfile +1 -1
- package/Dockerfile-en +1 -1
- package/README.md +5 -7
- package/app.js +12 -1
- package/channels/channelManager.js +1 -1
- package/channels/chat21/chat21Contact.js +34 -8
- package/channels/chat21/chat21Handler.js +48 -5
- package/channels/chat21/chat21WebHook.js +34 -9
- package/channels/chat21/nativeauth.js +2 -2
- package/channels/chat21/package-lock.json +3013 -0
- package/config/email.js +2 -0
- 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/migrations/1619185894304-request-remove-duplicated-request-by-request_id--autosync.js +67 -0
- 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 +9 -3
- package/models/request.js +33 -3
- package/package.json +31 -28
- package/pubmodules/emailNotification/requestNotification.js +483 -56
- package/pubmodules/messageActions/messageActionsInterceptor.js +20 -7
- package/pubmodules/messageTransformer/index.js +5 -1
- package/pubmodules/messageTransformer/messageTransformerInterceptor.js +4 -2
- package/pubmodules/messageTransformer/microLanguageAttributesTransformerInterceptor.js +67 -0
- package/pubmodules/messageTransformer/microLanguageTransformerInterceptor.js +67 -0
- package/pubmodules/pubModulesManager.js +66 -13
- package/pubmodules/rules/conciergeBot.js +81 -49
- package/routes/auth.js +46 -11
- package/routes/campaigns.js +117 -25
- package/routes/department.js +2 -2
- package/routes/faq.js +19 -0
- package/routes/faq_kb.js +13 -4
- package/routes/faqpub.js +1 -1
- package/routes/files.js +17 -2
- 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 +1170 -239
- package/services/faqBotHandler.js +176 -61
- package/services/faqBotSupport.js +182 -117
- package/services/faqService.js +18 -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 +191 -0
- package/template/email/ticket.txt +11 -0
- 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 +39 -2
- 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/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)
|