@tiledesk/tiledesk-server 2.9.25 → 2.9.27
Sign up to get free protection for your applications and to get access to all the features.
- package/CHANGELOG.md +10 -0
- package/package.json +2 -2
- package/pubmodules/pubModulesManager.js +41 -41
- package/routes/faq_kb.js +1 -1
- package/routes/kb.js +114 -1
- package/routes/message.js +55 -50
- package/routes/request.js +581 -47
- package/routes/users.js +4 -7
- package/services/QuoteManager.js +104 -16
- package/services/emailService.js +11 -2
- package/services/operatingHoursService.js +1 -0
- package/services/projectService.js +21 -0
- package/services/requestService.js +344 -9
- package/template/email/redirectToDesktopEmail.html +2 -2
- package/test/example-kb-faqs.csv +2 -0
- package/test/kbRoute.js +45 -0
- package/test/mock/projectMock.js +29 -1
- package/test/projectRoute.js +86 -3
- package/test/quoteManager.js +77 -5
- package/test/requestRoute.js +42 -0
- package/websocket/webSocketServer.js +21 -0
package/CHANGELOG.md
CHANGED
@@ -5,6 +5,16 @@
|
|
5
5
|
🚀 IN PRODUCTION 🚀
|
6
6
|
(https://www.npmjs.com/package/@tiledesk/tiledesk-server/v/2.3.77)
|
7
7
|
|
8
|
+
# 2.9.27
|
9
|
+
- Updated tybot-connector to 0.2.107
|
10
|
+
- Improved quotas slots
|
11
|
+
- Improved requests quota count (temporary conversation will no longer counted)
|
12
|
+
- Fixed bug: savedFaq is not defined in /importjson
|
13
|
+
|
14
|
+
# 2.9.26
|
15
|
+
- Updated tybot-connector to 0.2.105
|
16
|
+
- Added route for faqs csv file uploading on /kb
|
17
|
+
|
8
18
|
# 2.9.25
|
9
19
|
- Updated vxml-connector to 0.1.44
|
10
20
|
|
package/package.json
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
{
|
2
2
|
"name": "@tiledesk/tiledesk-server",
|
3
3
|
"description": "The Tiledesk server module",
|
4
|
-
"version": "2.9.
|
4
|
+
"version": "2.9.27",
|
5
5
|
"scripts": {
|
6
6
|
"start": "node ./bin/www",
|
7
7
|
"pretest": "mongodb-runner start",
|
@@ -48,7 +48,7 @@
|
|
48
48
|
"@tiledesk/tiledesk-rasa-connector": "^1.0.10",
|
49
49
|
"@tiledesk/tiledesk-telegram-connector": "^0.1.14",
|
50
50
|
"@tiledesk/tiledesk-train-jobworker": "^0.0.11",
|
51
|
-
"@tiledesk/tiledesk-tybot-connector": "^0.2.
|
51
|
+
"@tiledesk/tiledesk-tybot-connector": "^0.2.107",
|
52
52
|
"@tiledesk/tiledesk-whatsapp-connector": "^0.1.73",
|
53
53
|
"@tiledesk/tiledesk-whatsapp-jobworker": "^0.0.8",
|
54
54
|
"@tiledesk/tiledesk-sms-connector": "^0.1.10",
|
@@ -33,11 +33,11 @@ class PubModulesManager {
|
|
33
33
|
this.telegram = undefined;
|
34
34
|
this.telegramRoute = undefined;
|
35
35
|
|
36
|
-
this.sms = undefined;
|
37
|
-
this.smsRoute = undefined;
|
36
|
+
// this.sms = undefined;
|
37
|
+
// this.smsRoute = undefined;
|
38
38
|
|
39
|
-
this.voice = undefined;
|
40
|
-
this.voiceRoute = undefined;
|
39
|
+
// this.voice = undefined;
|
40
|
+
// this.voiceRoute = undefined;
|
41
41
|
|
42
42
|
this.mqttTest = undefined;
|
43
43
|
this.mqttTestRoute = undefined;
|
@@ -97,14 +97,14 @@ class PubModulesManager {
|
|
97
97
|
app.use('/modules/telegram', this.telegramRoute);
|
98
98
|
winston.info("PubModulesManager telegramRoute controller loaded");
|
99
99
|
}
|
100
|
-
if (this.smsRoute) {
|
101
|
-
|
102
|
-
|
103
|
-
}
|
104
|
-
if (this.voiceRoute) {
|
105
|
-
|
106
|
-
|
107
|
-
}
|
100
|
+
// if (this.smsRoute) {
|
101
|
+
// app.use('/modules/sms', this.smsRoute);
|
102
|
+
// winston.info("PubModulesManager smsRoute controller loaded");
|
103
|
+
// }
|
104
|
+
// if (this.voiceRoute) {
|
105
|
+
// app.use('/modules/voice', this.voiceRoute);
|
106
|
+
// winston.info("PubModulesManager voiceRoute controller loaded");
|
107
|
+
// }
|
108
108
|
if (this.mqttTestRoute) {
|
109
109
|
app.use('/modules/mqttTest', this.mqttTestRoute);
|
110
110
|
winston.info("PubModulesManager mqttTestRoute controller loaded");
|
@@ -345,40 +345,40 @@ class PubModulesManager {
|
|
345
345
|
}
|
346
346
|
}
|
347
347
|
|
348
|
-
if (process.env.VOICE_TOKEN === process.env.VOICE_SECRET) {
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
348
|
+
// if (process.env.VOICE_TOKEN === process.env.VOICE_SECRET) {
|
349
|
+
// try {
|
350
|
+
// this.voice = require('./voice');
|
351
|
+
// winston.info("this.voice: " + this.voice);
|
352
|
+
// this.voice.listener.listen(config);
|
353
353
|
|
354
|
-
|
354
|
+
// this.voiceRoute = this.voice.voiceRoute;
|
355
355
|
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
}
|
356
|
+
// winston.info("PubModulesManager initialized apps (voice).")
|
357
|
+
// } catch(err) {
|
358
|
+
// console.log("\n Unable to start voice connector: ", err);
|
359
|
+
// if (err.code == 'MODULE_NOT_FOUND') {
|
360
|
+
// winston.info("PubModulesManager init apps module not found ");
|
361
|
+
// } else {
|
362
|
+
// winston.info("PubModulesManager error initializing init apps module", err);
|
363
|
+
// }
|
364
|
+
// }
|
365
|
+
// }
|
366
366
|
|
367
|
-
try {
|
368
|
-
|
369
|
-
|
370
|
-
|
367
|
+
// try {
|
368
|
+
// this.sms = require('./sms');
|
369
|
+
// winston.info("this.sms: " + this.sms);
|
370
|
+
// this.sms.listener.listen(config);
|
371
371
|
|
372
|
-
|
372
|
+
// this.smsRoute = this.sms.smsRoute;
|
373
373
|
|
374
|
-
|
375
|
-
} catch(err) {
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
}
|
374
|
+
// winston.info("PubModulesManager initialized apps (sms).")
|
375
|
+
// } catch(err) {
|
376
|
+
// if (err.code == 'MODULE_NOT_FOUND') {
|
377
|
+
// winston.info("PubModulesManager init apps module not found ");
|
378
|
+
// } else {
|
379
|
+
// winston.info("PubModulesManager error initializing init apps module", err);
|
380
|
+
// }
|
381
|
+
// }
|
382
382
|
|
383
383
|
try {
|
384
384
|
this.mqttTest = require('./mqttTest');
|
package/routes/faq_kb.js
CHANGED
package/routes/kb.js
CHANGED
@@ -14,6 +14,7 @@ var mongoose = require('mongoose');
|
|
14
14
|
const faq = require('../models/faq');
|
15
15
|
const faq_kb = require('../models/faq_kb');
|
16
16
|
let Integration = require('../models/integrations');
|
17
|
+
var parsecsv = require("fast-csv");
|
17
18
|
|
18
19
|
const { MODELS_MULTIPLIER } = require('../utils/aiUtils');
|
19
20
|
|
@@ -465,7 +466,7 @@ router.get('/namespace/:id/chatbots', async (req, res) => {
|
|
465
466
|
|
466
467
|
let project_id = req.projectid;
|
467
468
|
let namespace_id = req.params.id;
|
468
|
-
|
469
|
+
|
469
470
|
let chatbotsArray = [];
|
470
471
|
|
471
472
|
let namespaces = await Namespace.find({ id_project: project_id }).catch((err) => {
|
@@ -491,6 +492,7 @@ router.get('/namespace/:id/chatbots', async (req, res) => {
|
|
491
492
|
let chatbots = intents.map(i => i.id_faq_kb);
|
492
493
|
let uniqueChatbots = [...new Set(chatbots)];
|
493
494
|
|
495
|
+
|
494
496
|
let chatbotPromises = uniqueChatbots.map(async (c_id) => {
|
495
497
|
try {
|
496
498
|
let chatbot = await faq_kb.findOne({ _id: c_id, trashed: false });
|
@@ -994,6 +996,117 @@ router.post('/multi', upload.single('uploadFile'), async (req, res) => {
|
|
994
996
|
|
995
997
|
})
|
996
998
|
|
999
|
+
router.post('/csv', upload.single('uploadFile'), async (req, res) => {
|
1000
|
+
|
1001
|
+
let project_id = req.projectid;
|
1002
|
+
|
1003
|
+
let csv = req.file.buffer.toString('utf8');
|
1004
|
+
winston.debug("csv: ", csv);
|
1005
|
+
|
1006
|
+
let delimiter = req.body.delimiter || ";";
|
1007
|
+
winston.debug("delimiter: ", delimiter);
|
1008
|
+
|
1009
|
+
let namespace_id = req.query.namespace;
|
1010
|
+
if (!namespace_id) {
|
1011
|
+
return res.status(400).send({ success: false, error: "queryParam 'namespace' is not defined" })
|
1012
|
+
}
|
1013
|
+
|
1014
|
+
let namespaces = await Namespace.find({ id_project: project_id }).catch((err) => {
|
1015
|
+
winston.error("find namespaces error: ", err)
|
1016
|
+
res.status(500).send({ success: false, error: err })
|
1017
|
+
})
|
1018
|
+
|
1019
|
+
if (!namespaces || namespaces.length == 0) {
|
1020
|
+
let alert = "No namespace found for the selected project " + project_id + ". Cannot add content to a non-existent namespace."
|
1021
|
+
winston.warn(alert);
|
1022
|
+
res.status(403).send({ success: false, error: alert });
|
1023
|
+
}
|
1024
|
+
|
1025
|
+
let namespaceIds = namespaces.map(namespace => namespace.id);
|
1026
|
+
|
1027
|
+
if (!namespaceIds.includes(namespace_id)) {
|
1028
|
+
return res.status(403).send({ success: false, error: "Not allowed. The namespace does not belong to the current project." })
|
1029
|
+
}
|
1030
|
+
|
1031
|
+
let quoteManager = req.app.get('quote_manager');
|
1032
|
+
let limits = await quoteManager.getPlanLimits(req.project);
|
1033
|
+
let kbs_limit = limits.kbs;
|
1034
|
+
winston.verbose("Limit of kbs for current plan: " + kbs_limit);
|
1035
|
+
|
1036
|
+
let kbs_count = await KB.countDocuments({ id_project: project_id }).exec();
|
1037
|
+
winston.verbose("Kbs count: " + kbs_count);
|
1038
|
+
|
1039
|
+
if (kbs_count >= kbs_limit) {
|
1040
|
+
return res.status(403).send({ success: false, error: "Maximum number of resources reached for the current plan", plan_limit: kbs_limit })
|
1041
|
+
}
|
1042
|
+
|
1043
|
+
let webhook = apiUrl + '/webhook/kb/status?token=' + KB_WEBHOOK_TOKEN;
|
1044
|
+
|
1045
|
+
let kbs = [];
|
1046
|
+
|
1047
|
+
parsecsv.parseString(csv, { headers: false, delimiter: delimiter })
|
1048
|
+
.on("data", (data) => {
|
1049
|
+
|
1050
|
+
let question = data[0];
|
1051
|
+
let answer = data[1];
|
1052
|
+
|
1053
|
+
console.log("data. ", data)
|
1054
|
+
kbs.push({
|
1055
|
+
id_project: project_id,
|
1056
|
+
name: question,
|
1057
|
+
source: question,
|
1058
|
+
type: 'faq',
|
1059
|
+
content: question + "\n" + answer,
|
1060
|
+
namespace: namespace_id,
|
1061
|
+
status: -1
|
1062
|
+
})
|
1063
|
+
})
|
1064
|
+
.on("end", () => {
|
1065
|
+
winston.debug("kbs after CSV parsing: ", kbs);
|
1066
|
+
|
1067
|
+
let total_count = kbs_count + kbs.length;
|
1068
|
+
if (total_count >= kbs_limit) {
|
1069
|
+
return res.status(403).send({ success: false, error: "Cannot exceed the number of resources in the current plan", plan_limit: kbs_limit })
|
1070
|
+
}
|
1071
|
+
|
1072
|
+
if (kbs.length > 300) {
|
1073
|
+
return res.status(403).send({ success: false, error: "Too many faqs. Can't index more than 300 urls at a time." })
|
1074
|
+
}
|
1075
|
+
|
1076
|
+
let operations = kbs.map(doc => {
|
1077
|
+
return {
|
1078
|
+
updateOne: {
|
1079
|
+
filter: { id_project: doc.id_project, type: 'faq', source: doc.source },
|
1080
|
+
update: doc,
|
1081
|
+
upsert: true,
|
1082
|
+
returnOriginal: false
|
1083
|
+
}
|
1084
|
+
}
|
1085
|
+
})
|
1086
|
+
|
1087
|
+
saveBulk(operations, kbs, project_id).then((result) => {
|
1088
|
+
let resources = result.map(({ name, status, __v, createdAt, updatedAt, id_project, ...keepAttrs }) => keepAttrs)
|
1089
|
+
resources = resources.map(({ _id, ...rest}) => {
|
1090
|
+
return { id: _id, webhooh: webhook, ...rest };
|
1091
|
+
})
|
1092
|
+
winston.verbose("resources to be sent to worker: ", resources);
|
1093
|
+
if (!process.env.NODE_ENV) {
|
1094
|
+
scheduleScrape(resources);
|
1095
|
+
}
|
1096
|
+
res.status(200).send(result);
|
1097
|
+
}).catch((err) => {
|
1098
|
+
winston.error("Unabled to saved kbs in bulk " + err);
|
1099
|
+
res.status(500).send(err);
|
1100
|
+
})
|
1101
|
+
|
1102
|
+
})
|
1103
|
+
.on("error", (err) => {
|
1104
|
+
winston.error("CSV parsing error: ", err);
|
1105
|
+
res.status(400).send({ success: false, error: err });
|
1106
|
+
})
|
1107
|
+
|
1108
|
+
})
|
1109
|
+
|
997
1110
|
router.post('/sitemap', async (req, res) => {
|
998
1111
|
|
999
1112
|
let sitemap_url = req.body.sitemap;
|
package/routes/message.js
CHANGED
@@ -181,77 +181,82 @@ async (req, res) => {
|
|
181
181
|
requester: project_user,
|
182
182
|
priority: req.body.priority,
|
183
183
|
followers: req.body.followers,
|
184
|
+
proactive: true
|
184
185
|
};
|
185
186
|
|
186
187
|
return requestService.create(new_request).then(function (savedRequest) {
|
187
188
|
|
189
|
+
|
190
|
+
if (!savedRequest) {
|
191
|
+
return res.status(403).send({ success: false, message: "Requests quota exceeded"})
|
192
|
+
}
|
188
193
|
winston.debug("returning savedRequest to", savedRequest.toJSON());
|
189
194
|
|
190
195
|
// createWithIdAndRequester(request_id, project_user_id, lead_id, id_project, first_text, departmentid, sourcePage, language, userAgent, status,
|
191
196
|
// createdBy, attributes, subject, preflight, channel, location) {
|
192
|
-
|
193
|
-
// return requestService.createWithIdAndRequester(req.params.request_id, req.projectuser._id, createdLead._id, req.projectid,
|
194
|
-
// req.body.text, req.body.departmentid, req.body.sourcePage,
|
195
|
-
// req.body.language, req.body.userAgent, null, req.user._id, req.body.attributes, req.body.subject, undefined, req.body.channel, req.body.location ).then(function (savedRequest) {
|
196
197
|
|
198
|
+
// return requestService.createWithIdAndRequester(req.params.request_id, req.projectuser._id, createdLead._id, req.projectid,
|
199
|
+
// req.body.text, req.body.departmentid, req.body.sourcePage,
|
200
|
+
// req.body.language, req.body.userAgent, null, req.user._id, req.body.attributes, req.body.subject, undefined, req.body.channel, req.body.location ).then(function (savedRequest) {
|
197
201
|
|
198
|
-
|
199
|
-
|
200
|
-
// create(sender, senderFullname, recipient, text, id_project, createdBy, status, attributes, type, metadata, language, channel_type, channel) {
|
201
|
-
return messageService.create(sender || req.user._id, fullname, req.params.request_id, req.body.text,
|
202
|
-
req.projectid, req.user._id, messageStatus, req.body.attributes, req.body.type, req.body.metadata, req.body.language, undefined, req.body.channel).then(function(savedMessage){
|
203
|
-
|
204
|
-
// return requestService.incrementMessagesCountByRequestId(savedRequest.request_id, savedRequest.id_project).then(function(savedRequestWithIncrement) {
|
205
202
|
|
206
|
-
let message = savedMessage.toJSON();
|
207
203
|
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
.populate({path:'requester',populate:{path:'id_user'}})
|
221
|
-
// .exec(function (err, savedRequestPopulated){
|
222
|
-
.execPopulate(function (err, savedRequestPopulated){ //bug with execPopulate request.attributes are invalid (NOT real data). but this bug is related to chat21 listener changes by reference. i think populate suffer from this problem bacause it it the same obect passed by reference
|
223
|
-
|
224
|
-
if (err) {
|
225
|
-
return winston.error("Error gettting savedRequestPopulated for send Message", err);
|
226
|
-
}
|
227
|
-
|
228
|
-
winston.debug("returning savedRequest221 to", savedRequest.toJSON());
|
204
|
+
|
205
|
+
// create(sender, senderFullname, recipient, text, id_project, createdBy, status, attributes, type, metadata, language, channel_type, channel) {
|
206
|
+
return messageService.create(sender || req.user._id, fullname, req.params.request_id, req.body.text,
|
207
|
+
req.projectid, req.user._id, messageStatus, req.body.attributes, req.body.type, req.body.metadata, req.body.language, undefined, req.body.channel).then(function (savedMessage) {
|
208
|
+
|
209
|
+
// return requestService.incrementMessagesCountByRequestId(savedRequest.request_id, savedRequest.id_project).then(function(savedRequestWithIncrement) {
|
210
|
+
|
211
|
+
let message = savedMessage.toJSON();
|
212
|
+
|
213
|
+
winston.debug("returning message to", message);
|
214
|
+
|
215
|
+
winston.debug("returning savedRequest2210 to", savedRequest.toJSON());
|
229
216
|
|
230
217
|
|
231
|
-
|
218
|
+
savedRequest //bug
|
219
|
+
// Request.findById(savedRequest.id)
|
220
|
+
.populate('lead')
|
221
|
+
.populate('department')
|
222
|
+
.populate('participatingBots')
|
223
|
+
.populate('participatingAgents')
|
224
|
+
// .populate('followers')
|
225
|
+
.populate({ path: 'requester', populate: { path: 'id_user' } })
|
226
|
+
// .exec(function (err, savedRequestPopulated){
|
227
|
+
.execPopulate(function (err, savedRequestPopulated) { //bug with execPopulate request.attributes are invalid (NOT real data). but this bug is related to chat21 listener changes by reference. i think populate suffer from this problem bacause it it the same obect passed by reference
|
232
228
|
|
233
|
-
|
229
|
+
if (err) {
|
230
|
+
return winston.error("Error gettting savedRequestPopulated for send Message", err);
|
231
|
+
}
|
234
232
|
|
233
|
+
winston.debug("returning savedRequest221 to", savedRequest.toJSON());
|
235
234
|
|
236
|
-
message.request = savedRequestPopulated;
|
237
|
-
winston.debug("returning2 message to", message);
|
238
235
|
|
236
|
+
winston.debug("savedRequestPopulated", savedRequestPopulated.toJSON());
|
239
237
|
|
240
|
-
|
241
|
-
|
238
|
+
winston.debug("returning savedRequest22 to", savedRequest.toJSON());
|
239
|
+
|
240
|
+
|
241
|
+
message.request = savedRequestPopulated;
|
242
|
+
winston.debug("returning2 message to", message);
|
243
|
+
|
244
|
+
|
245
|
+
return res.json(message);
|
242
246
|
});
|
243
|
-
})
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
// winston.error("Error creating message", err);
|
251
|
-
return res.status(500).send({success: false, msg: 'Error creating request', err:err });
|
252
|
-
});
|
253
|
-
|
247
|
+
});
|
248
|
+
}).catch(function (err) { //pubblica questo
|
249
|
+
winston.error('Error creating request: ' + JSON.stringify(err));
|
250
|
+
winston.log({
|
251
|
+
level: 'error',
|
252
|
+
message: 'Error creating request: ' + JSON.stringify(err) + " " + JSON.stringify(req.body),
|
253
|
+
label: req.projectid
|
254
254
|
});
|
255
|
+
// winston.error("Error creating message", err);
|
256
|
+
return res.status(500).send({ success: false, msg: 'Error creating request', err: err });
|
257
|
+
});
|
258
|
+
|
259
|
+
});
|
255
260
|
|
256
261
|
|
257
262
|
|