@tiledesk/tiledesk-server 2.3.49 → 2.3.51
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/CHANGELOG.md +4 -0
- package/app.js +2 -1
- package/package.json +4 -2
- package/pubmodules/apps/index.js +8 -0
- package/pubmodules/apps/listener.js +27 -0
- package/pubmodules/pubModulesManager.js +45 -0
- package/pubmodules/rules/conciergeBot.js +2 -2
- package/pubmodules/trigger/rulesTrigger.js +7 -4
- package/pubmodules/whatsapp/index.js +7 -0
- package/pubmodules/whatsapp/listener.js +32 -0
- package/routes/email.js +26 -2
- package/routes/faq_kb.js +264 -206
- package/routes/lead.js +4 -0
- package/services/emailService.js +97 -6
- package/services/leadService.js +1 -0
- package/services/requestService.js +2 -1
- package/template/email/beenInvitedExistingUser.html +1 -1
- package/template/email/beenInvitedNewUser.html +1 -1
- package/template/email/emailDirect.html +121 -0
- package/test/example-json-intents.txt +1 -0
- package/test/faqkbRoute.js +98 -0
package/CHANGELOG.md
CHANGED
@@ -5,6 +5,10 @@
|
|
5
5
|
🚀 IN PRODUCTION 🚀
|
6
6
|
(https://www.npmjs.com/package/@tiledesk/tiledesk-server/v/2.3.48)
|
7
7
|
|
8
|
+
# Untagged
|
9
|
+
- Added new email sending endpoint
|
10
|
+
- Emails endpoint is now usable by agents
|
11
|
+
|
8
12
|
# 2.3.49 -> PROD
|
9
13
|
- @tiledesk/tiledesk-tybot-connector": "^0.1.22
|
10
14
|
|
package/app.js
CHANGED
@@ -481,7 +481,8 @@ app.use('/:projectid/labels', [fetchLabels],labels);
|
|
481
481
|
|
482
482
|
app.use('/:projectid/campaigns',[passport.authenticate(['basic', 'jwt'], { session: false }), validtoken, roleChecker.hasRole('agent')], campaigns);
|
483
483
|
|
484
|
-
app.use('/:projectid/emails',[passport.authenticate(['basic', 'jwt'], { session: false }), validtoken, roleChecker.hasRole('
|
484
|
+
app.use('/:projectid/emails',[passport.authenticate(['basic', 'jwt'], { session: false }), validtoken, roleChecker.hasRole('agent')], email);
|
485
|
+
|
485
486
|
|
486
487
|
|
487
488
|
|
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.3.
|
4
|
+
"version": "2.3.51",
|
5
5
|
"scripts": {
|
6
6
|
"start": "node ./bin/www",
|
7
7
|
"pretest": "mongodb-runner start",
|
@@ -14,7 +14,7 @@
|
|
14
14
|
"enable-ent": "echo //registry.npmjs.org/:_authToken=${NPM_TOKEN} > .npmrc"
|
15
15
|
},
|
16
16
|
"private": false,
|
17
|
-
"author": "Andrea Leo -
|
17
|
+
"author": "Andrea Leo - Tiledesk SRL",
|
18
18
|
"license": "AGPL-3.0",
|
19
19
|
"homepage": "https://www.tiledesk.com",
|
20
20
|
"repository": {
|
@@ -36,6 +36,8 @@
|
|
36
36
|
"@tiledesk-ent/tiledesk-server-enterprise": "^1.0.0"
|
37
37
|
},
|
38
38
|
"dependencies": {
|
39
|
+
"@tiledesk/tiledesk-apps": "^1.0.6",
|
40
|
+
"@tiledesk/tiledesk-whatsapp-connector": "^0.1.19",
|
39
41
|
"@tiledesk/tiledesk-chat21-app": "^1.1.7",
|
40
42
|
"@tiledesk/tiledesk-chatbot-util": "^0.8.33",
|
41
43
|
"@tiledesk/tiledesk-json-rules-engine": "^4.0.3",
|
@@ -0,0 +1,27 @@
|
|
1
|
+
const apps = require("@tiledesk/tiledesk-apps");
|
2
|
+
var winston = require('../../config/winston');
|
3
|
+
|
4
|
+
class Listener {
|
5
|
+
|
6
|
+
listen(config) {
|
7
|
+
|
8
|
+
winston.info("Apps Listener listen");
|
9
|
+
|
10
|
+
if (config.databaseUri) {
|
11
|
+
winston.debug("apps config databaseUri: " + config.databaseUri);
|
12
|
+
}
|
13
|
+
|
14
|
+
apps.startApp({
|
15
|
+
ACCESS_TOKEN_SECRET: process.env.APPS_ACCESS_TOKEN_SECRET || 'nodeauthsecret',
|
16
|
+
MONGODB_URI: process.env.APPS_MONGODB_URI || config.databaseUri,
|
17
|
+
}, () => {
|
18
|
+
winston.info("Tiledesk Apps proxy server succesfully started.")
|
19
|
+
})
|
20
|
+
|
21
|
+
}
|
22
|
+
|
23
|
+
}
|
24
|
+
|
25
|
+
var listener = new Listener();
|
26
|
+
|
27
|
+
module.exports = listener;
|
@@ -21,6 +21,12 @@ class PubModulesManager {
|
|
21
21
|
this.rasa = undefined;
|
22
22
|
this.rasaRoute = undefined;
|
23
23
|
|
24
|
+
this.apps = undefined;
|
25
|
+
this.appsRoute = undefined;
|
26
|
+
|
27
|
+
this.whatsapp = undefined;
|
28
|
+
this.whatsappRoute = undefined;
|
29
|
+
|
24
30
|
this.activityArchiver = undefined;
|
25
31
|
this.activityRoute = undefined;
|
26
32
|
|
@@ -53,6 +59,14 @@ class PubModulesManager {
|
|
53
59
|
app.use('/modules/rasa', this.rasaRoute);
|
54
60
|
winston.info("ModulesManager rasaRoute controller loaded");
|
55
61
|
}
|
62
|
+
if (this.appsRoute) {
|
63
|
+
app.use('/modules/apps', this.appsRoute);
|
64
|
+
winston.info("ModulesManager appsRoute controller loaded");
|
65
|
+
}
|
66
|
+
if (this.whatsappRoute) {
|
67
|
+
app.use('/modules/whatsapp', this.whatsappRoute);
|
68
|
+
winston.info("ModulesManager whatsappRoute controller loaded");
|
69
|
+
}
|
56
70
|
if (this.tilebotRoute) {
|
57
71
|
app.use('/modules/tilebot', this.tilebotRoute);
|
58
72
|
winston.info("ModulesManager tilebot controller loaded");
|
@@ -217,7 +231,38 @@ class PubModulesManager {
|
|
217
231
|
}
|
218
232
|
}
|
219
233
|
|
234
|
+
try {
|
235
|
+
this.apps = require('./apps');
|
236
|
+
winston.debug("this.apps: " + this.apps);
|
237
|
+
this.apps.listener.listen(config);
|
238
|
+
|
239
|
+
this.appsRoute = this.apps.appsRoute;
|
220
240
|
|
241
|
+
winston.info("PubModulesManager initialized apps.");
|
242
|
+
} catch(err) {
|
243
|
+
if (err.code == 'MODULE_NOT_FOUND') {
|
244
|
+
winston.info("PubModulesManager init apps module not found");
|
245
|
+
}else {
|
246
|
+
winston.info("PubModulesManager error initializing init apps module", err);
|
247
|
+
}
|
248
|
+
}
|
249
|
+
|
250
|
+
try {
|
251
|
+
this.whatsapp = require('./whatsapp');
|
252
|
+
winston.debug("this.whatsapp: " + this.whatsapp);
|
253
|
+
this.whatsapp.listener.listen(config);
|
254
|
+
|
255
|
+
this.whatsappRoute = this.whatsapp.whatsappRoute;
|
256
|
+
|
257
|
+
winston.info("PubModulesManager initialized apps.");
|
258
|
+
} catch(err) {
|
259
|
+
if (err.code == 'MODULE_NOT_FOUND') {
|
260
|
+
winston.info("PubModulesManager init apps module not found");
|
261
|
+
}else {
|
262
|
+
winston.info("PubModulesManager error initializing init apps module", err);
|
263
|
+
}
|
264
|
+
}
|
265
|
+
|
221
266
|
|
222
267
|
try {
|
223
268
|
this.activityArchiver = require('./activities').activityArchiver;
|
@@ -198,7 +198,7 @@ devi mandare un messaggio welcome tu altrimenti il bot inserito successivamente
|
|
198
198
|
"Chat closed",
|
199
199
|
request.id_project,
|
200
200
|
'system',
|
201
|
-
{subtype:"info/support", "updateconversation" : false, messagelabel: {key: "CHAT_CLOSED"}},
|
201
|
+
{subtype:"info/support", "updateconversation" : false, messagelabel: {key: "CHAT_CLOSED"}}, // TODO send request.closed_by <- c'è il campo l'ho verificato
|
202
202
|
undefined,
|
203
203
|
request.language
|
204
204
|
);
|
@@ -228,7 +228,7 @@ devi mandare un messaggio welcome tu altrimenti il bot inserito successivamente
|
|
228
228
|
request.request_id,
|
229
229
|
"Chat reopened",
|
230
230
|
request.id_project,
|
231
|
-
'system',
|
231
|
+
'system', //changed from false to true 6Aug22 because reopen from dashboard history doesn't update convs in ionic
|
232
232
|
{subtype:"info/support", "updateconversation" : true, messagelabel: {key: "CHAT_REOPENED"}},
|
233
233
|
undefined,
|
234
234
|
request.language
|
@@ -65,6 +65,9 @@ class RulesTrigger {
|
|
65
65
|
});
|
66
66
|
});
|
67
67
|
|
68
|
+
|
69
|
+
|
70
|
+
// da aggiungere in dashboard
|
68
71
|
requestEvent.on('request.participants.join', function(data) {
|
69
72
|
let request = data.request;
|
70
73
|
let member = data.member;
|
@@ -82,10 +85,10 @@ class RulesTrigger {
|
|
82
85
|
// operatingHoursService.projectIsOpenNow(request.id_project, function (isOpen, err) {
|
83
86
|
that.exec(message, 'message.create.from.requester', success, error);
|
84
87
|
});
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
88
|
+
|
89
|
+
messageEvent.on('message.received', function(message) {
|
90
|
+
that.exec(message, 'message.received', success, error);
|
91
|
+
});
|
89
92
|
|
90
93
|
// event2Event.on('*', function(event){
|
91
94
|
// winston.verbose('event2Event this.event: ' + this.event);
|
@@ -0,0 +1,32 @@
|
|
1
|
+
const whatsapp = require("@tiledesk/tiledesk-whatsapp-connector");
|
2
|
+
var winston = require('../../config/winston');
|
3
|
+
var configGlobal = require('../../config/global');
|
4
|
+
|
5
|
+
const apiUrl = process.env.API_URL || configGlobal.apiUrl;
|
6
|
+
winston.info('Whatsapp apiUrl: ' + apiUrl);
|
7
|
+
|
8
|
+
class Listener {
|
9
|
+
|
10
|
+
listen(config) {
|
11
|
+
winston.info("WhatsApp Listener listen");
|
12
|
+
if (config.databaseUri) {
|
13
|
+
winston.debug("whatsapp config databaseUri: " + config.databaseUri);
|
14
|
+
}
|
15
|
+
|
16
|
+
whatsapp.startApp({
|
17
|
+
MONGODB_URL: config.databaseUri,
|
18
|
+
API_URL: apiUrl,
|
19
|
+
GRAPH_URL: process.env.META_GRAPH_URL || config.graphUrl,
|
20
|
+
BASE_URL: apiUrl + "/modules/whatsapp",
|
21
|
+
APPS_API_URL: apiUrl + "/modules/apps",
|
22
|
+
log: process.env.WHATSAPP_LOG
|
23
|
+
}, () => {
|
24
|
+
winston.info("Tiledesk WhatsApp Connector proxy server succesfully started.");
|
25
|
+
})
|
26
|
+
|
27
|
+
}
|
28
|
+
}
|
29
|
+
|
30
|
+
var listener = new Listener();
|
31
|
+
|
32
|
+
module.exports = listener;
|
package/routes/email.js
CHANGED
@@ -17,10 +17,10 @@ router.get('/templates/:templateid',
|
|
17
17
|
router.post('/test/send',
|
18
18
|
async (req, res) => {
|
19
19
|
let to = req.body.to;
|
20
|
-
winston.
|
20
|
+
winston.debug("to",to);
|
21
21
|
|
22
22
|
let configEmail = req.body.config;
|
23
|
-
winston.
|
23
|
+
winston.debug("configEmail", configEmail);
|
24
24
|
|
25
25
|
emailService.sendTest(to, configEmail, function(err,obj) {
|
26
26
|
// winston.info("sendTest rest", err, obj);
|
@@ -29,4 +29,28 @@ router.post('/test/send',
|
|
29
29
|
|
30
30
|
});
|
31
31
|
|
32
|
+
|
33
|
+
router.post('/send',
|
34
|
+
async (req, res) => {
|
35
|
+
let to = req.body.to;
|
36
|
+
winston.info("to: " + to);
|
37
|
+
|
38
|
+
let text = req.body.text;
|
39
|
+
winston.info("text: " + text);
|
40
|
+
|
41
|
+
let request_id = req.body.request_id;
|
42
|
+
winston.info("request_id: " + request_id);
|
43
|
+
|
44
|
+
let subject = req.body.subject;
|
45
|
+
winston.info("subject: " + subject);
|
46
|
+
|
47
|
+
winston.info("req.project", req.project);
|
48
|
+
|
49
|
+
//sendEmailDirect(to, text, project, request_id, subject, tokenQueryString, sourcePage)
|
50
|
+
emailService.sendEmailDirect(to, text, req.project, request_id, subject, undefined, undefined);
|
51
|
+
|
52
|
+
res.json({"queued": true});
|
53
|
+
|
54
|
+
});
|
55
|
+
|
32
56
|
module.exports = router;
|
package/routes/faq_kb.js
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
var express = require('express');
|
2
2
|
var router = express.Router();
|
3
3
|
var Faq_kb = require("../models/faq_kb");
|
4
|
-
var Faq= require("../models/faq");
|
4
|
+
var Faq = require("../models/faq");
|
5
5
|
var Department = require("../models/department");
|
6
6
|
var faqService = require("../services/faqService");
|
7
7
|
const botEvent = require('../event/botEvent');
|
@@ -14,11 +14,11 @@ var upload = multer()
|
|
14
14
|
|
15
15
|
|
16
16
|
router.post('/', function (req, res) {
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
17
|
+
winston.info('create BOT ', req.body);
|
18
|
+
//create(name, url, projectid, user_id, type, description, webhook_url, webhook_enabled, language, template)
|
19
|
+
faqService.create(req.body.name, req.body.url, req.projectid, req.user.id, req.body.type, req.body.description, undefined, undefined, req.body.language, req.body.template).then(function (savedFaq_kb) {
|
20
|
+
res.json(savedFaq_kb);
|
21
|
+
});
|
22
22
|
|
23
23
|
});
|
24
24
|
|
@@ -27,7 +27,7 @@ router.post('/train', function (req, res) {
|
|
27
27
|
|
28
28
|
winston.info('train BOT ', req.body);
|
29
29
|
|
30
|
-
Faq_kb.findById(req.body.id_faq_kb).exec(function(err, faq_kb) {
|
30
|
+
Faq_kb.findById(req.body.id_faq_kb).exec(function (err, faq_kb) {
|
31
31
|
if (err) {
|
32
32
|
return res.status(500).send({ success: false, msg: 'Error getting object.' });
|
33
33
|
}
|
@@ -36,59 +36,59 @@ router.post('/train', function (req, res) {
|
|
36
36
|
}
|
37
37
|
winston.debug('faq_kb ', faq_kb.toJSON());
|
38
38
|
|
39
|
-
winston.debug('faq_kb.type :'+ faq_kb.type);
|
40
|
-
if (faq_kb.type =="internal" && faq_kb.url) {
|
39
|
+
winston.debug('faq_kb.type :' + faq_kb.type);
|
40
|
+
if (faq_kb.type == "internal" && faq_kb.url) {
|
41
41
|
|
42
42
|
|
43
43
|
|
44
|
-
var train =
|
45
|
-
language:faq_kb.language,
|
46
|
-
nlu:[]
|
44
|
+
var train = {
|
45
|
+
language: faq_kb.language,
|
46
|
+
nlu: []
|
47
47
|
};
|
48
|
-
winston.info("train", train);
|
49
|
-
|
50
|
-
|
51
|
-
var query = { "id_project": req.projectid, "id_faq_kb": req.body.id_faq_kb};
|
52
|
-
|
53
|
-
Faq.find(query)
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
}
|
60
|
-
if (faqs && faqs.length>0) {
|
61
|
-
winston.info("faqs exact", faqs);
|
62
|
-
|
63
|
-
faqs.forEach(function(f) {
|
64
|
-
var intent = {
|
65
|
-
intent:f.intent_display_name,
|
66
|
-
examples:[]
|
67
|
-
}
|
68
|
-
var questions = f.question.split("\n");
|
69
|
-
winston.info("questions", questions);
|
70
|
-
|
71
|
-
questions.forEach(function(q) {
|
72
|
-
winston.info("q", q);
|
73
|
-
intent.examples.push(q);
|
74
|
-
});
|
75
|
-
winston.info("intent", intent);
|
76
|
-
train.nlu.push(intent);
|
77
|
-
});
|
78
|
-
winston.info("train", train);
|
79
|
-
|
80
|
-
try {
|
81
|
-
var trainHttp = await httpUtil.call(faq_kb.url+"/trainandload", undefined, train, "POST");
|
82
|
-
}catch(e) {
|
83
|
-
winston.error("error training", e);
|
48
|
+
winston.info("train", train);
|
49
|
+
|
50
|
+
|
51
|
+
var query = { "id_project": req.projectid, "id_faq_kb": req.body.id_faq_kb };
|
52
|
+
|
53
|
+
Faq.find(query)
|
54
|
+
.limit(10000)
|
55
|
+
.lean().
|
56
|
+
exec(async (err, faqs) => {
|
57
|
+
if (err) {
|
58
|
+
return res.status(500).send({ success: false, msg: 'Error getting object.' });
|
84
59
|
}
|
85
|
-
|
60
|
+
if (faqs && faqs.length > 0) {
|
61
|
+
winston.info("faqs exact", faqs);
|
62
|
+
|
63
|
+
faqs.forEach(function (f) {
|
64
|
+
var intent = {
|
65
|
+
intent: f.intent_display_name,
|
66
|
+
examples: []
|
67
|
+
}
|
68
|
+
var questions = f.question.split("\n");
|
69
|
+
winston.info("questions", questions);
|
70
|
+
|
71
|
+
questions.forEach(function (q) {
|
72
|
+
winston.info("q", q);
|
73
|
+
intent.examples.push(q);
|
74
|
+
});
|
75
|
+
winston.info("intent", intent);
|
76
|
+
train.nlu.push(intent);
|
77
|
+
});
|
78
|
+
winston.info("train", train);
|
79
|
+
|
80
|
+
try {
|
81
|
+
var trainHttp = await httpUtil.call(faq_kb.url + "/trainandload", undefined, train, "POST");
|
82
|
+
} catch (e) {
|
83
|
+
winston.error("error training", e);
|
84
|
+
}
|
85
|
+
|
86
86
|
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
87
|
+
return res.json({ train: train, httpResponse: trainHttp });
|
88
|
+
// return res.json(trainHttp);
|
89
|
+
} else {
|
90
|
+
return res.status(400).send({ success: false, msg: 'no faq to train on external bot.' });
|
91
|
+
}
|
92
92
|
});
|
93
93
|
} else {
|
94
94
|
winston.debug('external query: ');
|
@@ -97,28 +97,28 @@ router.post('/train', function (req, res) {
|
|
97
97
|
|
98
98
|
});
|
99
99
|
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
100
|
+
/*
|
101
|
+
{
|
102
|
+
"language":"it",
|
103
|
+
"nlu":[
|
104
|
+
{
|
105
|
+
"intent":"eta",
|
106
|
+
"examples":[
|
107
|
+
"quanti anni hai",
|
108
|
+
"dimmi la tua età",
|
109
|
+
"quanto sei grande",
|
110
|
+
"parlami della tua età"
|
111
|
+
]
|
112
|
+
},
|
113
|
+
{
|
114
|
+
"intent":"brutteparole",
|
115
|
+
"examples":[
|
116
|
+
"non dire parolacce",
|
117
|
+
"le brutte parole non dovrebbero dirsi"
|
118
|
+
]
|
119
|
+
}
|
120
|
+
]
|
121
|
+
}
|
122
122
|
*/
|
123
123
|
|
124
124
|
});
|
@@ -128,7 +128,7 @@ router.post('/askbot', function (req, res) {
|
|
128
128
|
|
129
129
|
winston.debug('ASK BOT ', req.body);
|
130
130
|
|
131
|
-
Faq_kb.findById(req.body.id_faq_kb).exec(function(err, faq_kb) {
|
131
|
+
Faq_kb.findById(req.body.id_faq_kb).exec(function (err, faq_kb) {
|
132
132
|
if (err) {
|
133
133
|
return res.status(500).send({ success: false, msg: 'Error getting object.' });
|
134
134
|
}
|
@@ -136,73 +136,73 @@ router.post('/askbot', function (req, res) {
|
|
136
136
|
return res.status(404).send({ success: false, msg: 'Object not found.' });
|
137
137
|
}
|
138
138
|
winston.debug('faq_kb ', faq_kb.toJSON());
|
139
|
-
winston.debug('faq_kb.type :'+ faq_kb.type);
|
140
|
-
if (faq_kb.type =="internal" || faq_kb.type =="tilebot") {
|
139
|
+
winston.debug('faq_kb.type :' + faq_kb.type);
|
140
|
+
if (faq_kb.type == "internal" || faq_kb.type == "tilebot") {
|
141
|
+
|
141
142
|
|
142
143
|
|
143
144
|
|
144
|
-
|
145
145
|
|
146
|
-
var query = { "id_project": req.projectid, "id_faq_kb": req.body.id_faq_kb, "question": req.body.question};
|
146
|
+
var query = { "id_project": req.projectid, "id_faq_kb": req.body.id_faq_kb, "question": req.body.question };
|
147
147
|
|
148
|
-
Faq.find(query)
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
148
|
+
Faq.find(query)
|
149
|
+
.lean().
|
150
|
+
exec(function (err, faqs) {
|
151
|
+
if (err) {
|
152
|
+
return res.status(500).send({ success: false, msg: 'Error getting object.' });
|
153
|
+
}
|
154
|
+
if (faqs && faqs.length > 0) {
|
155
|
+
winston.debug("faqs exact", faqs);
|
156
156
|
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
157
|
+
faqs.forEach(f => {
|
158
|
+
f.score = 100;
|
159
|
+
});
|
160
|
+
var result = { hits: faqs };
|
161
161
|
|
162
162
|
|
163
|
-
|
164
|
-
|
165
|
-
|
163
|
+
res.json(result);
|
164
|
+
} else {
|
165
|
+
query = { "id_project": req.projectid, "id_faq_kb": req.body.id_faq_kb };
|
166
166
|
|
167
|
-
|
167
|
+
var search_obj = { "$search": req.body.question };
|
168
168
|
|
169
|
-
|
169
|
+
if (faq_kb.language) {
|
170
170
|
search_obj["$language"] = faq_kb.language;
|
171
|
+
}
|
172
|
+
query.$text = search_obj;
|
173
|
+
winston.debug("fulltext search query", query);
|
174
|
+
|
175
|
+
|
176
|
+
winston.debug('internal ft query: ' + query);
|
177
|
+
|
178
|
+
Faq.find(query, { score: { $meta: "textScore" } })
|
179
|
+
.sort({ score: { $meta: "textScore" } }) //https://docs.mongodb.com/manual/reference/operator/query/text/#sort-by-text-search-score
|
180
|
+
.lean().
|
181
|
+
exec(function (err, faqs) {
|
182
|
+
if (err) {
|
183
|
+
winston.error('Error getting object.', err);
|
184
|
+
return res.status(500).send({ success: false, msg: 'Error getting fulltext object.' });
|
185
|
+
}
|
186
|
+
|
187
|
+
winston.debug("faqs", faqs);
|
188
|
+
|
189
|
+
var result = { hits: faqs };
|
190
|
+
res.json(result);
|
191
|
+
});
|
192
|
+
|
193
|
+
|
171
194
|
}
|
172
|
-
query.$text = search_obj;
|
173
|
-
winston.debug("fulltext search query", query);
|
174
|
-
|
175
|
-
|
176
|
-
winston.debug('internal ft query: '+ query);
|
177
|
-
|
178
|
-
Faq.find(query, {score: { $meta: "textScore" } })
|
179
|
-
.sort( { score: { $meta: "textScore" } } ) //https://docs.mongodb.com/manual/reference/operator/query/text/#sort-by-text-search-score
|
180
|
-
.lean().
|
181
|
-
exec(function (err, faqs) {
|
182
|
-
if (err) {
|
183
|
-
winston.error('Error getting object.', err);
|
184
|
-
return res.status(500).send({ success: false, msg: 'Error getting fulltext object.' });
|
185
|
-
}
|
186
|
-
|
187
|
-
winston.debug("faqs", faqs);
|
188
|
-
|
189
|
-
var result = {hits:faqs};
|
190
|
-
res.json(result);
|
191
|
-
});
|
192
195
|
|
193
|
-
|
194
|
-
}
|
195
196
|
|
196
|
-
|
197
|
-
|
197
|
+
});
|
198
|
+
|
198
199
|
|
199
|
-
|
200
|
-
}else {
|
200
|
+
} else {
|
201
201
|
winston.debug('external query: ');
|
202
202
|
return res.status(400).send({ success: false, msg: 'askbot on external bot.' });
|
203
203
|
}
|
204
|
-
|
205
|
-
|
204
|
+
|
205
|
+
|
206
206
|
});
|
207
207
|
|
208
208
|
});
|
@@ -214,26 +214,26 @@ router.put('/:faq_kbid', function (req, res) {
|
|
214
214
|
winston.debug(req.body);
|
215
215
|
|
216
216
|
var update = {};
|
217
|
-
if (req.body.name!=undefined) {
|
217
|
+
if (req.body.name != undefined) {
|
218
218
|
update.name = req.body.name;
|
219
219
|
}
|
220
|
-
if (req.body.description!=undefined) {
|
220
|
+
if (req.body.description != undefined) {
|
221
221
|
update.description = req.body.description;
|
222
222
|
}
|
223
|
-
if (req.body.url!=undefined) {
|
223
|
+
if (req.body.url != undefined) {
|
224
224
|
update.url = req.body.url;
|
225
225
|
}
|
226
|
-
if (req.body.webhook_url!=undefined) {
|
226
|
+
if (req.body.webhook_url != undefined) {
|
227
227
|
update.webhook_url = req.body.webhook_url;
|
228
228
|
}
|
229
|
-
if (req.body.webhook_enabled!=undefined) {
|
229
|
+
if (req.body.webhook_enabled != undefined) {
|
230
230
|
update.webhook_enabled = req.body.webhook_enabled;
|
231
231
|
}
|
232
|
-
|
233
|
-
if (req.body.type!=undefined) {
|
232
|
+
|
233
|
+
if (req.body.type != undefined) {
|
234
234
|
update.type = req.body.type;
|
235
235
|
}
|
236
|
-
if (req.body.trashed!=undefined) {
|
236
|
+
if (req.body.trashed != undefined) {
|
237
237
|
update.trashed = req.body.trashed;
|
238
238
|
}
|
239
239
|
|
@@ -321,10 +321,10 @@ router.get('/', function (req, res) {
|
|
321
321
|
*/
|
322
322
|
var query = { "id_project": req.projectid, "trashed": { $in: [null, false] } };
|
323
323
|
|
324
|
-
if (req.query.all!="true") {
|
324
|
+
if (req.query.all != "true") {
|
325
325
|
query.type = { $ne: "identity" }
|
326
326
|
}
|
327
|
-
|
327
|
+
|
328
328
|
winston.debug("query", query);
|
329
329
|
|
330
330
|
Faq_kb.find(query, function (err, faq_kb) {
|
@@ -347,86 +347,134 @@ router.post('/importjson/:id_faq_kb', upload.single('uploadFile'), (req, res) =>
|
|
347
347
|
let json_string = req.file.buffer.toString('utf-8');
|
348
348
|
winston.debug("json_string: ", json_string);
|
349
349
|
|
350
|
-
|
351
|
-
if (err) {
|
352
|
-
winston.error("GET FAQ-KB ERROR", err);
|
353
|
-
return res.status(500).send({ success: false, msg: "Error getting bot." });
|
354
|
-
}
|
355
|
-
if (!faq_kb) {
|
356
|
-
return res.status(404).send({ success: false, msg: 'Bot not found.'});
|
357
|
-
}
|
350
|
+
if (req.query.intentsOnly == "true") {
|
358
351
|
|
359
|
-
|
352
|
+
winston.info("intents only")
|
360
353
|
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
}
|
367
|
-
if (json.language) {
|
368
|
-
faq_kb.language = json.language;
|
369
|
-
}
|
370
|
-
if (json.name) {
|
371
|
-
faq_kb.name = json.name;
|
372
|
-
}
|
373
|
-
if (json.description) {
|
374
|
-
faq_kb.description = json.description;
|
375
|
-
}
|
354
|
+
const json = JSON.parse(json_string)
|
355
|
+
console.log("\n intents --> \n")
|
356
|
+
console.log(json)
|
357
|
+
|
358
|
+
json.intents.forEach((intent) => {
|
376
359
|
|
377
|
-
|
360
|
+
var new_faq = new Faq({
|
361
|
+
id_faq_kb: id_faq_kb,
|
362
|
+
id_project: req.projectid,
|
363
|
+
createdBy: req.user.id,
|
364
|
+
question: intent.question,
|
365
|
+
answer: intent.answer,
|
366
|
+
reply: intent.reply,
|
367
|
+
form: intent.form,
|
368
|
+
enabled: intent.enabled,
|
369
|
+
webhook_enabled: intent.webhook_enabled,
|
370
|
+
language: intent.language,
|
371
|
+
|
372
|
+
})
|
373
|
+
|
374
|
+
new_faq.save((err, savedFaq) => {
|
375
|
+
if (err) {
|
376
|
+
winston.error("GET FAQ-KB ERROR", err);
|
377
|
+
if (err.code == 11000) {
|
378
|
+
return res.status(409).send({ success: false, msg: 'Duplicate intent_display_name.' });
|
379
|
+
} else {
|
380
|
+
winston.debug('--- > ERROR ', err)
|
381
|
+
return res.status(500).send({ success: false, msg: 'Error saving intent.' });
|
382
|
+
}
|
383
|
+
}
|
384
|
+
winston.debug("NEW FAQ CREATED WITH ID: ", savedFaq._id);
|
385
|
+
faqBotEvent.emit('faq.create', savedFaq);
|
386
|
+
})
|
387
|
+
|
388
|
+
})
|
389
|
+
|
390
|
+
return res.status(200).send({ success: true, msg: "Intents imported successfully"})
|
391
|
+
|
392
|
+
} else {
|
393
|
+
|
394
|
+
Faq_kb.findById(id_faq_kb, (err, faq_kb) => {
|
378
395
|
if (err) {
|
379
|
-
|
396
|
+
winston.error("GET FAQ-KB ERROR", err);
|
397
|
+
return res.status(500).send({ success: false, msg: "Error getting bot." });
|
380
398
|
}
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
399
|
+
if (!faq_kb) {
|
400
|
+
return res.status(404).send({ success: false, msg: 'Bot not found.' });
|
401
|
+
}
|
402
|
+
|
403
|
+
const json = JSON.parse(json_string);
|
404
|
+
|
405
|
+
if (json.webhook_enabled) {
|
406
|
+
faq_kb.webhook_enabled = json.webhook_enabled;
|
407
|
+
}
|
408
|
+
if (json.webhook_url) {
|
409
|
+
faq_kb.webhook_url = json.webhook_url;
|
410
|
+
}
|
411
|
+
if (json.language) {
|
412
|
+
faq_kb.language = json.language;
|
413
|
+
}
|
414
|
+
if (json.name) {
|
415
|
+
faq_kb.name = json.name;
|
416
|
+
}
|
417
|
+
if (json.description) {
|
418
|
+
faq_kb.description = json.description;
|
419
|
+
}
|
420
|
+
|
421
|
+
Faq_kb.findByIdAndUpdate(id_faq_kb, faq_kb, { new: true }, (err, updatedFaq_kb) => {
|
422
|
+
if (err) {
|
423
|
+
return res.status(500).send({ success: false, msg: "Error updating bot." });
|
424
|
+
}
|
425
|
+
|
426
|
+
botEvent.emit('faqbot.update', updatedFaq_kb);
|
427
|
+
|
428
|
+
json.intents.forEach((intent) => {
|
429
|
+
|
430
|
+
var new_faq = new Faq({
|
431
|
+
id_faq_kb: updatedFaq_kb._id,
|
432
|
+
id_project: req.projectid,
|
433
|
+
createdBy: req.user.id,
|
434
|
+
question: intent.question,
|
435
|
+
answer: intent.answer,
|
436
|
+
reply: intent.reply,
|
437
|
+
form: intent.form,
|
438
|
+
enabled: intent.enabled,
|
439
|
+
webhook_enabled: intent.webhook_enabled,
|
440
|
+
language: intent.language,
|
441
|
+
|
442
|
+
})
|
443
|
+
|
444
|
+
new_faq.save((err, savedFaq) => {
|
445
|
+
if (err) {
|
446
|
+
winston.error("GET FAQ-KB ERROR", err);
|
447
|
+
if (err.code == 11000) {
|
448
|
+
return res.status(409).send({ success: false, msg: 'Duplicate intent_display_name.' });
|
449
|
+
} else {
|
450
|
+
winston.debug('--- > ERROR ', err)
|
451
|
+
return res.status(500).send({ success: false, msg: 'Error saving intent.' });
|
452
|
+
}
|
453
|
+
}
|
454
|
+
winston.debug("NEW FAQ CREATED WITH ID: ", savedFaq._id);
|
455
|
+
faqBotEvent.emit('faq.create', savedFaq);
|
456
|
+
})
|
457
|
+
|
412
458
|
})
|
413
|
-
|
414
|
-
})
|
415
459
|
|
416
|
-
|
460
|
+
return res.send(updatedFaq_kb);
|
461
|
+
|
462
|
+
})
|
417
463
|
|
418
464
|
})
|
419
|
-
|
420
|
-
})
|
465
|
+
}
|
421
466
|
|
422
467
|
})
|
423
468
|
|
424
469
|
router.get('/exportjson/:id_faq_kb', (req, res) => {
|
425
470
|
|
471
|
+
winston.info("exporting bot...")
|
472
|
+
|
473
|
+
|
426
474
|
let id_faq_kb = req.params.id_faq_kb;
|
427
475
|
|
428
476
|
Faq_kb.findById(id_faq_kb, (err, faq_kb) => {
|
429
|
-
if (err){
|
477
|
+
if (err) {
|
430
478
|
winston.error('GET FAQ-KB ERROR ', err)
|
431
479
|
return res.status(500).send({ success: false, msg: 'Error getting bot.' });
|
432
480
|
} else {
|
@@ -434,9 +482,9 @@ router.get('/exportjson/:id_faq_kb', (req, res) => {
|
|
434
482
|
|
435
483
|
|
436
484
|
faqService.getAll(id_faq_kb).then((faqs) => {
|
437
|
-
|
438
|
-
const intents = faqs.map(({_id, id_project, topic, status, id_faq_kb, createdBy, intent_id, createdAt, updatedAt, __v, ...keepAttrs}) => keepAttrs)
|
439
|
-
|
485
|
+
|
486
|
+
const intents = faqs.map(({ _id, id_project, topic, status, id_faq_kb, createdBy, intent_id, createdAt, updatedAt, __v, ...keepAttrs }) => keepAttrs)
|
487
|
+
|
440
488
|
let json = {
|
441
489
|
webhook_enabled: faq_kb.webhook_enabled,
|
442
490
|
webhook_url: faq_kb.webhook_url,
|
@@ -446,10 +494,20 @@ router.get('/exportjson/:id_faq_kb', (req, res) => {
|
|
446
494
|
intents: intents
|
447
495
|
}
|
448
496
|
|
449
|
-
|
497
|
+
if (req.query.intentsOnly == 'true') {
|
498
|
+
let intents_obj = {
|
499
|
+
intents: intents
|
500
|
+
}
|
501
|
+
let intents_string = JSON.stringify(intents_obj);
|
502
|
+
res.set({ "Content-Disposition": "attachment; filename=\"intents.txt\"" });
|
503
|
+
return res.send(intents_string);
|
504
|
+
|
505
|
+
} else {
|
506
|
+
let json_string = JSON.stringify(json);
|
507
|
+
res.set({ "Content-Disposition": "attachment; filename=\"bot.txt\"" });
|
508
|
+
return res.send(json_string);
|
509
|
+
}
|
450
510
|
|
451
|
-
res.set({"Content-Disposition":"attachment; filename=\"bot.txt\""});
|
452
|
-
return res.send(json_string);
|
453
511
|
|
454
512
|
}).catch((err) => {
|
455
513
|
winston.error('GET FAQ ERROR: ', err)
|
@@ -457,7 +515,7 @@ router.get('/exportjson/:id_faq_kb', (req, res) => {
|
|
457
515
|
})
|
458
516
|
}
|
459
517
|
})
|
460
|
-
|
518
|
+
|
461
519
|
})
|
462
520
|
|
463
521
|
|
package/routes/lead.js
CHANGED
@@ -88,6 +88,10 @@ router.put('/:leadid', function (req, res) {
|
|
88
88
|
if (req.body.email!=undefined) {
|
89
89
|
leadEvent.emit('lead.email.update', updatedLead);
|
90
90
|
}
|
91
|
+
|
92
|
+
if (req.body.email!=undefined || req.body.fullname!=undefined) {
|
93
|
+
leadEvent.emit('lead.fullname.email.update', updatedLead);
|
94
|
+
}
|
91
95
|
|
92
96
|
res.json(updatedLead);
|
93
97
|
});
|
package/services/emailService.js
CHANGED
@@ -1030,7 +1030,7 @@ class EmailService {
|
|
1030
1030
|
|
1031
1031
|
}
|
1032
1032
|
|
1033
|
-
|
1033
|
+
|
1034
1034
|
|
1035
1035
|
async sendEmailChannelNotification(to, message, project, tokenQueryString, sourcePage) {
|
1036
1036
|
|
@@ -1360,10 +1360,6 @@ class EmailService {
|
|
1360
1360
|
}
|
1361
1361
|
|
1362
1362
|
|
1363
|
-
|
1364
|
-
|
1365
|
-
|
1366
|
-
|
1367
1363
|
/*
|
1368
1364
|
sendEmailChannelTakingNotification(to, request, project, tokenQueryString) {
|
1369
1365
|
|
@@ -1411,6 +1407,102 @@ class EmailService {
|
|
1411
1407
|
}
|
1412
1408
|
*/
|
1413
1409
|
|
1410
|
+
|
1411
|
+
|
1412
|
+
|
1413
|
+
|
1414
|
+
|
1415
|
+
|
1416
|
+
async sendEmailDirect(to, text, project, request_id, subject, tokenQueryString, sourcePage) {
|
1417
|
+
|
1418
|
+
var that = this;
|
1419
|
+
|
1420
|
+
|
1421
|
+
if (project.toJSON) {
|
1422
|
+
project = project.toJSON();
|
1423
|
+
}
|
1424
|
+
|
1425
|
+
var html = await this.readTemplate('emailDirect.html', project.settings);
|
1426
|
+
|
1427
|
+
var envTemplate = process.env.EMAIL_DIRECT_HTML_TEMPLATE;
|
1428
|
+
winston.debug("envTemplate: " + envTemplate);
|
1429
|
+
|
1430
|
+
if (envTemplate) {
|
1431
|
+
html = envTemplate;
|
1432
|
+
}
|
1433
|
+
|
1434
|
+
winston.debug("html: " + html);
|
1435
|
+
|
1436
|
+
var template = handlebars.compile(html);
|
1437
|
+
|
1438
|
+
var baseScope = JSON.parse(JSON.stringify(that));
|
1439
|
+
delete baseScope.pass;
|
1440
|
+
|
1441
|
+
|
1442
|
+
let msgText = text;
|
1443
|
+
msgText = encode(msgText);
|
1444
|
+
if (this.markdown) {
|
1445
|
+
msgText = marked(msgText);
|
1446
|
+
}
|
1447
|
+
|
1448
|
+
winston.debug("msgText: " + msgText);
|
1449
|
+
winston.debug("baseScope: " + JSON.stringify(baseScope));
|
1450
|
+
|
1451
|
+
|
1452
|
+
var replacements = {
|
1453
|
+
project: project,
|
1454
|
+
seamlessPage: sourcePage,
|
1455
|
+
msgText: msgText,
|
1456
|
+
tokenQueryString: tokenQueryString,
|
1457
|
+
baseScope: baseScope
|
1458
|
+
};
|
1459
|
+
|
1460
|
+
var html = template(replacements);
|
1461
|
+
winston.debug("html: " + html);
|
1462
|
+
|
1463
|
+
|
1464
|
+
let replyTo;
|
1465
|
+
if (this.replyEnabled) {
|
1466
|
+
replyTo = request_id + this.inboundDomainDomainWithAt;
|
1467
|
+
}
|
1468
|
+
|
1469
|
+
let from;
|
1470
|
+
let configEmail;
|
1471
|
+
if (project && project.settings && project.settings.email) {
|
1472
|
+
if (project.settings.email.config) {
|
1473
|
+
configEmail = project.settings.email.config;
|
1474
|
+
winston.verbose("custom email configEmail setting found: ", configEmail);
|
1475
|
+
}
|
1476
|
+
if (project.settings.email.from) {
|
1477
|
+
from = project.settings.email.from;
|
1478
|
+
winston.verbose("custom from email setting found: "+ from);
|
1479
|
+
}
|
1480
|
+
}
|
1481
|
+
|
1482
|
+
|
1483
|
+
// if (message.request && message.request.lead && message.request.lead.email) {
|
1484
|
+
// winston.info("message.request.lead.email: " + message.request.lead.email);
|
1485
|
+
// replyTo = replyTo + ", "+ message.request.lead.email;
|
1486
|
+
// }
|
1487
|
+
|
1488
|
+
// if (!subject) {
|
1489
|
+
// subject = "Tiledesk"
|
1490
|
+
// }
|
1491
|
+
|
1492
|
+
that.send({
|
1493
|
+
from:from,
|
1494
|
+
to:to,
|
1495
|
+
replyTo: replyTo,
|
1496
|
+
subject:subject,
|
1497
|
+
text:html,
|
1498
|
+
html:html,
|
1499
|
+
config:configEmail,
|
1500
|
+
});
|
1501
|
+
|
1502
|
+
}
|
1503
|
+
|
1504
|
+
|
1505
|
+
|
1414
1506
|
// ok
|
1415
1507
|
async sendPasswordResetRequestEmail(to, resetPswRequestId, userFirstname, userLastname) {
|
1416
1508
|
|
@@ -1693,6 +1785,5 @@ async sendRequestTranscript(to, messages, request, project) {
|
|
1693
1785
|
|
1694
1786
|
var emailService = new EmailService();
|
1695
1787
|
|
1696
|
-
// emailService.sendTest("abc@abc.it");
|
1697
1788
|
|
1698
1789
|
module.exports = emailService;
|
package/services/leadService.js
CHANGED
@@ -130,6 +130,7 @@ class LeadService {
|
|
130
130
|
leadEvent.emit('lead.update', updatedLead);
|
131
131
|
leadEvent.emit('lead.email.update', updatedLead);
|
132
132
|
leadEvent.emit('lead.fullname.update', updatedLead);
|
133
|
+
leadEvent.emit('lead.fullname.email.update', updatedLead);
|
133
134
|
return resolve(updatedLead);
|
134
135
|
});
|
135
136
|
});
|
@@ -63,7 +63,8 @@ class RequestService {
|
|
63
63
|
|
64
64
|
|
65
65
|
sendMessageUpdateLead() {
|
66
|
-
leadEvent.on('lead.fullname.update', function(lead) {
|
66
|
+
leadEvent.on('lead.fullname.email.update', function(lead) {
|
67
|
+
winston.debug("lead.fullname.email.update ");
|
67
68
|
// leadEvent.on('lead.update', function(lead) {
|
68
69
|
|
69
70
|
setImmediate(() => {
|
@@ -94,7 +94,7 @@
|
|
94
94
|
{{currentUserFirstname}} {{currentUserLastname}} has invited you to the TileDesk project <strong> {{projectName}}</strong>
|
95
95
|
</h2>
|
96
96
|
|
97
|
-
<br> <br
|
97
|
+
<br> <br><strong style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;">Hi {{invitedUserFirstname}} {{invitedUserLastname}},</strong>
|
98
98
|
|
99
99
|
<br> <br>
|
100
100
|
I invited you to take on the role of {{invitedUserRole}} of the TileDesk <strong> {{projectName}}</strong> project
|
@@ -95,7 +95,7 @@
|
|
95
95
|
{{currentUserFirstname}} {{currentUserLastname}} has invited you to the Tiledesk project <strong> {{projectName}}</strong>
|
96
96
|
</h2>
|
97
97
|
|
98
|
-
<br> <br
|
98
|
+
<br> <br><strong style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;">{{to}},</strong>
|
99
99
|
|
100
100
|
<br> <br>
|
101
101
|
I invited you to take on the role of {{invitedUserRole}} of the Tiledesk <strong> {{projectName}}</strong> project
|
@@ -0,0 +1,121 @@
|
|
1
|
+
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
2
|
+
<html lang="en" xmlns="http://www.w3.org/1999/xhtml" style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;">
|
3
|
+
|
4
|
+
<head>
|
5
|
+
<meta name="viewport" content="width=device-width" />
|
6
|
+
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
7
|
+
<title>New Ticket from TileDesk</title>
|
8
|
+
|
9
|
+
<style type="text/css">
|
10
|
+
img {
|
11
|
+
max-width: 100%;
|
12
|
+
margin-left:16px;
|
13
|
+
margin-bottom:16px;
|
14
|
+
text-align:center !important;
|
15
|
+
}
|
16
|
+
body {
|
17
|
+
-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; width: 100% !important; height: 100%; line-height: 1.6em;
|
18
|
+
}
|
19
|
+
body {
|
20
|
+
background-color: #f6f6f6;
|
21
|
+
}
|
22
|
+
|
23
|
+
@media only screen and (max-width: 640px) {
|
24
|
+
body {
|
25
|
+
padding: 0 !important;
|
26
|
+
}
|
27
|
+
h1 {
|
28
|
+
font-weight: 800 !important; margin: 20px 0 5px !important;
|
29
|
+
text-align:center !important;
|
30
|
+
}
|
31
|
+
h2 {
|
32
|
+
font-weight: 800 !important; margin: 20px 0 5px !important;
|
33
|
+
}
|
34
|
+
h3 {
|
35
|
+
font-weight: 800 !important; margin: 20px 0 5px !important;
|
36
|
+
}
|
37
|
+
h4 {
|
38
|
+
font-weight: 800 !important; margin: 20px 0 5px !important;
|
39
|
+
}
|
40
|
+
h1 {
|
41
|
+
font-size: 22px !important;
|
42
|
+
}
|
43
|
+
h2 {
|
44
|
+
font-size: 18px !important;
|
45
|
+
}
|
46
|
+
h3 {
|
47
|
+
font-size: 16px !important;
|
48
|
+
}
|
49
|
+
.container {
|
50
|
+
padding: 0 !important; width: 100% !important;
|
51
|
+
}
|
52
|
+
.content {
|
53
|
+
padding: 0 !important;
|
54
|
+
}
|
55
|
+
.content-wrap {
|
56
|
+
padding: 10px !important;
|
57
|
+
}
|
58
|
+
.invoice {
|
59
|
+
width: 100% !important;
|
60
|
+
}
|
61
|
+
}
|
62
|
+
</style>
|
63
|
+
</head>
|
64
|
+
|
65
|
+
<body itemscope itemtype="http://schema.org/EmailMessage" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; width: 100% !important; height: 100%; line-height: 1.6em; background-color: #f6f6f6; margin: 0;" bgcolor="#f6f6f6">
|
66
|
+
|
67
|
+
{{#if baseScope.replyEnabled}}
|
68
|
+
<div>\# Please type your reply above this line \#</div>
|
69
|
+
{{/if}}
|
70
|
+
|
71
|
+
<table class="main" width="100%" cellpadding="0" cellspacing="0" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; border-radius: 3px; background-color: #fff; margin: 0; border: 1px solid #e9e9e9;" bgcolor="#fff">
|
72
|
+
|
73
|
+
<tr style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;">
|
74
|
+
<td class="alert alert-warning" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 16px; vertical-align: top; font-weight: 500; text-align: center; border-radius: 3px 3px 0 0; margin: 0;" align="center" valign="top">
|
75
|
+
|
76
|
+
<div style="text-align:center">
|
77
|
+
<a href="http://www.tiledesk.com" style="color:#2daae1;font-weight:bold;text-decoration:none;word-break:break-word" target="_blank">
|
78
|
+
<!-- <img src="https://tiledesk.com/wp-content/uploads/2022/07/tiledesk_v2.png" style="width:20%;outline:none;text-decoration:none;border:none;min-height:36px" class="CToWUd"> -->
|
79
|
+
<img src="https://tiledesk.com/wp-content/uploads/2022/09/tiledeesk_log_email.png" style="max-width:200px;outline:none;text-decoration:none;border:none;height:auto;margin-left:0px;" class="CToWUd">
|
80
|
+
</a>
|
81
|
+
</div>
|
82
|
+
</td>
|
83
|
+
</tr>
|
84
|
+
|
85
|
+
|
86
|
+
<tr style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;">
|
87
|
+
<td class="content-wrap" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; vertical-align: top; margin: 0; padding: 20px;" valign="top">
|
88
|
+
<table width="100%" cellpadding="0" cellspacing="0" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;">
|
89
|
+
|
90
|
+
|
91
|
+
|
92
|
+
|
93
|
+
<tr style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;">
|
94
|
+
<td class="content-block" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; vertical-align: top; margin: 0; padding: 0 0 20px;" valign="top">
|
95
|
+
<div style="white-space: pre-wrap;">{{{msgText}}}</div>
|
96
|
+
</td>
|
97
|
+
</tr>
|
98
|
+
|
99
|
+
|
100
|
+
|
101
|
+
|
102
|
+
<tr style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;">
|
103
|
+
<td class="content-block" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; vertical-align: top; margin: 0; padding: 0 0 20px;" valign="top">
|
104
|
+
</td>
|
105
|
+
</tr>
|
106
|
+
</table>
|
107
|
+
</td>
|
108
|
+
</tr>
|
109
|
+
</table>
|
110
|
+
<div class="footer" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; width: 100%; clear: both; color: #999; margin: 0; padding: 20px;">
|
111
|
+
<table width="100%" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;">
|
112
|
+
<tr style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;">
|
113
|
+
<td class="aligncenter content-block" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 12px; vertical-align: top; color: #999; text-align: center; margin: 0; padding: 0 0 20px;" align="center" valign="top">
|
114
|
+
<span><a href="http://www.tiledesk.com" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 12px; color: #999; text-decoration: underline; margin: 0;" > Tiledesk.com </a></span>
|
115
|
+
<!-- <br><span><a href="%unsubscribe_url%" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 12px; color: #999; text-decoration: underline; margin: 0;">Unsubscribe</a></span> -->
|
116
|
+
</td>
|
117
|
+
</tr>
|
118
|
+
</table>
|
119
|
+
|
120
|
+
</body>
|
121
|
+
</html>
|
@@ -0,0 +1 @@
|
|
1
|
+
{"intents":[{"webhook_enabled":false,"enabled":true,"question":"\\start","answer":"Hello","intent_display_name":"start","language":"en"},{"webhook_enabled":false,"enabled":true,"question":"defaultFallback","answer":"I can not provide an adequate answer. Write a new question or talk to a human agent.\n* Back to start tdAction:start\n* See the docs https://docs.tiledesk.com/\n* 👨🏻🦰 I want an agent","intent_display_name":"defaultFallback","language":"en"}]}
|
package/test/faqkbRoute.js
CHANGED
@@ -148,6 +148,54 @@ describe('FaqKBRoute', () => {
|
|
148
148
|
})
|
149
149
|
})
|
150
150
|
|
151
|
+
it('import json (intents only)', (done) => {
|
152
|
+
|
153
|
+
var email = "test-signup-" + Date.now() + "@email.com";
|
154
|
+
var pwd = "pwd";
|
155
|
+
|
156
|
+
userService.signup(email, pwd, "Test Firstname", "Test lastname").then(function (savedUser) {
|
157
|
+
projectService.create("test-faqkb-create", savedUser._id).then(function (savedProject) {
|
158
|
+
|
159
|
+
chai.request(server)
|
160
|
+
.post('/' + savedProject._id + '/faq_kb')
|
161
|
+
.auth(email, pwd)
|
162
|
+
.send({ "name": "testbot", type: "internal", language: 'fr' })
|
163
|
+
.end((err, res) => {
|
164
|
+
console.log("res.body: ", res.body);
|
165
|
+
res.should.have.status(200);
|
166
|
+
res.body.should.be.a('object');
|
167
|
+
expect(res.body.name).to.equal("testbot");
|
168
|
+
expect(res.body.language).to.equal("fr");
|
169
|
+
let id_faq_kb = res.body._id;
|
170
|
+
|
171
|
+
chai.request(server)
|
172
|
+
.post('/' + savedProject._id + '/faq_kb/importjson/' + id_faq_kb + '?intentsOnly=true')
|
173
|
+
.auth(email, pwd)
|
174
|
+
.set('Content-Type', 'text/plain')
|
175
|
+
.attach('uploadFile', fs.readFileSync(path.resolve(__dirname, './example-json-intents.txt')), 'example-json-intents.txt')
|
176
|
+
.end((err, res) => {
|
177
|
+
console.log("import (intents only) json res: ", res.body);
|
178
|
+
res.should.have.status(200);
|
179
|
+
//res.should.be.a('object');
|
180
|
+
//expect(res.body.success).to.equal(true);
|
181
|
+
|
182
|
+
chai.request(server)
|
183
|
+
.get('/' + savedProject._id + '/faq?id_faq_kb=' + id_faq_kb)
|
184
|
+
.auth(email, pwd)
|
185
|
+
.end((err, res) => {
|
186
|
+
console.log("faq_list: ", res.body);
|
187
|
+
res.should.have.status(200);
|
188
|
+
res.body.should.be.an('array').that.is.not.empty;
|
189
|
+
|
190
|
+
done();
|
191
|
+
|
192
|
+
})
|
193
|
+
})
|
194
|
+
})
|
195
|
+
})
|
196
|
+
})
|
197
|
+
})
|
198
|
+
|
151
199
|
|
152
200
|
it('export json', (done) => {
|
153
201
|
|
@@ -199,6 +247,56 @@ describe('FaqKBRoute', () => {
|
|
199
247
|
|
200
248
|
}).timeout(20000);
|
201
249
|
|
250
|
+
it('export json (intents only)', (done) => {
|
251
|
+
|
252
|
+
|
253
|
+
// this.timeout();
|
254
|
+
|
255
|
+
var email = "test-signup-" + Date.now() + "@email.com";
|
256
|
+
var pwd = "pwd";
|
257
|
+
|
258
|
+
userService.signup(email, pwd, "Test Firstname", "Test lastname").then(function (savedUser) {
|
259
|
+
projectService.create("test-faqkb-create", savedUser._id).then(function (savedProject) {
|
260
|
+
|
261
|
+
chai.request(server)
|
262
|
+
.post('/' + savedProject._id + '/faq_kb')
|
263
|
+
.auth(email, pwd)
|
264
|
+
.send({ "name": "testbot", type: "internal", template: "example", language: 'fr' })
|
265
|
+
.end((err, res) => {
|
266
|
+
//console.log("res", res);
|
267
|
+
console.log("res.body", res.body);
|
268
|
+
res.should.have.status(200);
|
269
|
+
res.body.should.be.a('object');
|
270
|
+
expect(res.body.name).to.equal("testbot");
|
271
|
+
expect(res.body.language).to.equal("fr");
|
272
|
+
let id_faq_kb = res.body._id;
|
273
|
+
console.log("res.body._id: ", res.body._id)
|
274
|
+
|
275
|
+
chai.request(server)
|
276
|
+
.get('/' + savedProject._id + '/faq?id_faq_kb=' + id_faq_kb)
|
277
|
+
.auth(email, pwd)
|
278
|
+
.end((err, res) => {
|
279
|
+
console.log("faq_list: ", res.body);
|
280
|
+
res.should.have.status(200);
|
281
|
+
res.body.should.be.an('array').that.is.not.empty;
|
282
|
+
|
283
|
+
chai.request(server)
|
284
|
+
.get('/' + savedProject._id + '/faq_kb/exportjson/' + id_faq_kb + "?intentsOnly=true")
|
285
|
+
.auth(email, pwd)
|
286
|
+
.end((err, res) => {
|
287
|
+
console.log("export json res: ", res.body);
|
288
|
+
res.should.have.status(200);
|
289
|
+
//res.body.should.be.a('string');
|
290
|
+
|
291
|
+
done();
|
292
|
+
})
|
293
|
+
})
|
294
|
+
});
|
295
|
+
});
|
296
|
+
});
|
297
|
+
|
298
|
+
}).timeout(20000);
|
299
|
+
|
202
300
|
|
203
301
|
// mocha test/faqkbRoute.js --grep 'train'
|
204
302
|
it('train', (done) => {
|