@tiledesk/tiledesk-server 2.4.46 → 2.4.48

Sign up to get free protection for your applications and to get access to all the features.
package/app.js CHANGED
@@ -112,6 +112,7 @@ var jwtroute = require('./routes/jwt');
112
112
  var key = require('./routes/key');
113
113
  var widgets = require('./routes/widget');
114
114
  var widgetsLoader = require('./routes/widgetLoader');
115
+ var openai_kbs = require('./routes/openai_kbs');
115
116
 
116
117
  // var admin = require('./routes/admin');
117
118
  var faqpub = require('./routes/faqpub');
@@ -549,6 +550,8 @@ app.use('/:projectid/emails',[passport.authenticate(['basic', 'jwt'], { session:
549
550
 
550
551
  app.use('/:projectid/properties',[passport.authenticate(['basic', 'jwt'], { session: false }), validtoken, roleChecker.hasRoleOrTypes('agent', ['bot','subscription'])], property);
551
552
 
553
+ app.use('/:projectid/openai_kbs', [passport.authenticate(['basic', 'jwt'], { session: false }), validtoken, roleChecker.hasRoleOrTypes('agent')], openai_kbs);
554
+
552
555
 
553
556
 
554
557
  if (pubModulesManager) {
package/jobs.js CHANGED
@@ -93,9 +93,9 @@ async function main()
93
93
  jobsManager.listenActivityArchiver(activityArchiver);
94
94
 
95
95
 
96
- // let routingQueue = require('./pubmodules/routing-queue').listener; //ci sono altri eventi che nn gestisco in queue request.participants.join etc
97
- // winston.info("routingQueue1");
98
- // jobsManager.listenRoutingQueue(routingQueue);
96
+ let routingQueueQueued = require('./pubmodules/routing-queue').listenerQueued;
97
+ winston.debug("routingQueueQueued");
98
+ jobsManager.listenRoutingQueue(routingQueueQueued);
99
99
 
100
100
 
101
101
 
package/jobsManager.js CHANGED
@@ -45,14 +45,14 @@ class JobsManager {
45
45
  this.emailNotification.requestNotification.listen();
46
46
  }
47
47
 
48
- // listenRoutingQueue(routingQueue) {
49
- // winston.info("JobsManager routingQueue started");
50
- // if ( this.jobWorkerEnabled == true) {
51
- // return winston.info("JobsManager jobWorkerEnabled is enabled. Skipping listener for routingQueue");
52
- // }
53
- // this.routingQueue = routingQueue;
54
- // this.routingQueue.listen();
55
- // }
48
+ listenRoutingQueue(routingQueue) {
49
+ winston.info("JobsManager routingQueue started");
50
+ if ( this.jobWorkerEnabled == true) {
51
+ return winston.info("JobsManager jobWorkerEnabled is enabled. Skipping listener for routingQueue");
52
+ }
53
+ this.routingQueue = routingQueue;
54
+ this.routingQueue.listen();
55
+ }
56
56
 
57
57
  listenScheduler(scheduler) {
58
58
  winston.info("JobsManager scheduler started");
@@ -0,0 +1,23 @@
1
+ var mongoose = require('mongoose');
2
+ var Schema = mongoose.Schema;
3
+ var winston = require('../config/winston');
4
+
5
+ var OpenaiKbsSchema = new Schema({
6
+ name: {
7
+ type: String,
8
+ required: true
9
+ },
10
+ url: {
11
+ type: String,
12
+ required: true
13
+ },
14
+ id_project: {
15
+ type: String,
16
+ required: true,
17
+ index: true
18
+ },
19
+
20
+ });
21
+
22
+
23
+ module.exports = mongoose.model('OpenaiKbs', OpenaiKbsSchema);
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.4.46",
4
+ "version": "2.4.48",
5
5
  "scripts": {
6
6
  "start": "node ./bin/www",
7
7
  "pretest": "mongodb-runner start",
@@ -51,6 +51,7 @@ class PubModulesManager {
51
51
  this.jobsManager = undefined;
52
52
 
53
53
  this.routingQueue = undefined;
54
+ this.routingQueueQueued = undefined;
54
55
 
55
56
  this.cache = undefined;
56
57
 
@@ -407,8 +408,11 @@ class PubModulesManager {
407
408
 
408
409
  try {
409
410
  this.routingQueue = require('./routing-queue').listener;
411
+ this.routingQueueQueued = require('./routing-queue').listenerQueued;
412
+
410
413
  // this.routingQueue.listen();
411
414
  winston.debug("this.routingQueue:"+ this.routingQueue);
415
+ winston.debug("this.routingQueueQueued:"+ this.routingQueueQueued);
412
416
 
413
417
  winston.info("PubModulesManager routing queue initialized");
414
418
  } catch(err) {
@@ -515,13 +519,21 @@ class PubModulesManager {
515
519
 
516
520
  if (this.routingQueue) {
517
521
  try {
518
- this.routingQueue.listen();
519
- // this.jobsManager.listenRoutingQueue(this.routingQueue);
522
+ this.routingQueue.listen();
520
523
  winston.info("PubModulesManager routingQueue started");
521
524
  } catch(err) {
522
525
  winston.info("PubModulesManager error starting routingQueue module", err);
523
526
  }
524
527
  }
528
+ if (this.routingQueueQueued) {
529
+ try {
530
+ // this.routingQueueQueued.listen();
531
+ this.jobsManager.listenRoutingQueue(this.routingQueueQueued);
532
+ winston.info("PubModulesManager routingQueue queued started");
533
+ } catch(err) {
534
+ winston.info("PubModulesManager error starting routingQueue queued module", err);
535
+ }
536
+ }
525
537
 
526
538
  // if (this.dialogFlow) {
527
539
  // try {
@@ -1,3 +1,5 @@
1
1
  const listener = require("./listener");
2
+ const listenerQueued = require("./listenerQueued");
2
3
 
3
- module.exports = {listener:listener };
4
+
5
+ module.exports = {listener:listener, listenerQueued: listenerQueued };
@@ -1,13 +1,7 @@
1
- const projectEvent = require('../../event/projectEvent');
2
1
  const departmentEvent = require('../../event/departmentEvent');
3
- const authEvent = require('../../event/authEvent');
4
- const requestEvent = require('../../event/requestEvent');
5
2
  var Request = require('../../models/request');
6
- var Project = require('../../models/project');
7
- var Project_user = require('../../models/project_user');
8
3
  var winston = require('../../config/winston');
9
4
 
10
- var ProjectUserUtil = require("../../utils/project_userUtil");
11
5
 
12
6
  // var request = require('retry-request', {
13
7
  // request: require('request')
@@ -55,42 +49,6 @@ class Listener {
55
49
  // };
56
50
  }
57
51
 
58
- // db.getCollection('project_users').find({"number_assigned_requests" : {"$lt":0}}).count()
59
-
60
-
61
- updateProjectUser(id_user, id_project, operation) {
62
- winston.debug("updateProjectUser start");
63
- return Project_user
64
- .findOneAndUpdate({id_user: id_user, id_project: id_project}, {$inc : {'number_assigned_requests' : operation}}, {new: true, upsert:false}, function(err, updatedPU) {
65
- if (err) {
66
- return winston.error(err);
67
- }
68
- winston.debug("number_assigned_requests +1 :" + updatedPU.id);
69
-
70
- updatedPU.populate({path:'id_user', select:{'firstname':1, 'lastname':1}},function (err, updatedProject_userPopulated){
71
-
72
- var pu = updatedProject_userPopulated.toJSON();
73
-
74
- return Project.findById(id_project).exec(function(err, project) {
75
- pu.isBusy = ProjectUserUtil.isBusy(updatedProject_userPopulated, project.settings && project.settings.max_agent_assigned_chat);
76
- winston.debug("pu.isBusy: "+ pu.isBusy);
77
- authEvent.emit('project_user.update', {updatedProject_userPopulated:pu, req: undefined, skipArchive: true});
78
- })
79
-
80
- });
81
-
82
- });
83
- }
84
-
85
- updateParticipatingProjectUsers(request, operation) {
86
- winston.debug("request.participatingAgents", request.participatingAgents);
87
- if (request.participatingAgents.length>0) {
88
- request.participatingAgents.forEach(user => {
89
- winston.debug("request.participatingAgents user",user); //it is a user and not a project_user
90
- this.updateProjectUser(user.id, request.id_project, operation);
91
- });
92
- }
93
- }
94
52
 
95
53
  listen() {
96
54
 
@@ -101,57 +59,6 @@ class Listener {
101
59
  }
102
60
 
103
61
  var that = this;
104
-
105
- // TODO fai versione che passa anche project
106
- requestEvent.on('request.create', async (request) => {
107
- setImmediate(() => {
108
- this.updateParticipatingProjectUsers(request, +1);
109
- });
110
- });
111
-
112
- // TODO usa versione complete con project per evitare query??
113
- requestEvent.on('request.close', async (request) => {
114
- setImmediate(() => {
115
- this.updateParticipatingProjectUsers(request, -1);
116
- });
117
- });
118
-
119
-
120
- requestEvent.on('request.participants.join', async (data) => {
121
- var request = data.request;
122
- var member = data.member;
123
- setImmediate(() => {
124
- this.updateProjectUser(member, request.id_project, 1);
125
- });
126
- });
127
-
128
- requestEvent.on('request.participants.leave', async (data) => {
129
- var request = data.request;
130
- var member = data.member;
131
- setImmediate(() => {
132
- this.updateProjectUser(member, request.id_project, -1);
133
- });
134
- });
135
-
136
- requestEvent.on('request.participants.update', async (data) => {
137
- var request = data.request;
138
- var removedParticipants = data.removedParticipants;
139
- var addedParticipants = data.addedParticipants;
140
-
141
- setImmediate(() => {
142
-
143
- addedParticipants.forEach(participant => {
144
- winston.debug('addedParticipants participant', participant);
145
- this.updateProjectUser(participant, request.id_project, 1);
146
- });
147
-
148
- removedParticipants.forEach(participant => {
149
- winston.debug('removedParticipants participant', participant);
150
- this.updateProjectUser(participant, request.id_project, -1);
151
- });
152
-
153
- });
154
- });
155
62
 
156
63
  departmentEvent.on('operator.select.base2', async (res) => {
157
64
  // departmentEvent.prependListener('operator.select', async (data) => {
@@ -170,9 +77,7 @@ class Listener {
170
77
 
171
78
  }
172
79
 
173
-
174
-
175
-
80
+
176
81
 
177
82
 
178
83
 
@@ -0,0 +1,194 @@
1
+ const authEvent = require('../../event/authEvent');
2
+ const requestEvent = require('../../event/requestEvent');
3
+ var Project = require('../../models/project');
4
+ var Project_user = require('../../models/project_user');
5
+ var winston = require('../../config/winston');
6
+
7
+ var ProjectUserUtil = require("../../utils/project_userUtil");
8
+
9
+ // var request = require('retry-request', {
10
+ // request: require('request')
11
+ // });
12
+
13
+ // TODO riabilitare questo
14
+
15
+ // const ROUTE_QUEUE_ENDPOINT = process.env.ROUTE_QUEUE_ENDPOINT;
16
+ // winston.debug("ROUTE_QUEUE_ENDPOINT: " + ROUTE_QUEUE_ENDPOINT);
17
+
18
+ // if (ROUTE_QUEUE_ENDPOINT) {
19
+ // winston.info("Route queue endpoint: " + ROUTE_QUEUE_ENDPOINT);
20
+ // } else {
21
+ // winston.info("Route queue endpoint not configured");
22
+ // }
23
+
24
+
25
+
26
+
27
+ // TODO web socket is not supported with queue
28
+ class Listener {
29
+
30
+
31
+ constructor() {
32
+ this.enabled = true;
33
+ if (process.env.ROUTE_QUEUE_ENABLED=="false" || process.env.ROUTE_QUEUE_ENABLED==false) {
34
+ this.enabled = false;
35
+ }
36
+ winston.debug("Listener this.enabled: "+ this.enabled);
37
+ }
38
+
39
+
40
+ // db.getCollection('project_users').find({"number_assigned_requests" : {"$lt":0}}).count()
41
+
42
+
43
+ updateProjectUser(id_user, id_project, operation) {
44
+ winston.debug("Route queue updateProjectUser start");
45
+ return Project_user
46
+ .findOneAndUpdate({id_user: id_user, id_project: id_project}, {$inc : {'number_assigned_requests' : operation}}, {new: true, upsert:false}, function(err, updatedPU) {
47
+ if (err) {
48
+ return winston.error(err);
49
+ }
50
+ winston.debug("Route queue number_assigned_requests +1 :" + updatedPU.id);
51
+
52
+ updatedPU.populate({path:'id_user', select:{'firstname':1, 'lastname':1}},function (err, updatedProject_userPopulated){
53
+
54
+ var pu = updatedProject_userPopulated.toJSON();
55
+
56
+ return Project.findById(id_project).exec(function(err, project) {
57
+ pu.isBusy = ProjectUserUtil.isBusy(updatedProject_userPopulated, project.settings && project.settings.max_agent_assigned_chat);
58
+ winston.debug("Route queue pu.isBusy: "+ pu.isBusy);
59
+
60
+ authEvent.emit('project_user.update', {updatedProject_userPopulated:pu, req: undefined, skipArchive: true}); //if queued with jobs -> websocket notification on project_user.update doesn't work??? forse si in quanto viene convertito in .pub.queue e poi rifunziiona
61
+
62
+
63
+ // project_user.update triggers activityArchiver(tested), cache invalidation(tested), subscriptionNotifierQueued and websocket(tested works from queue i trigger ws)
64
+ if (requestEvent.queueEnabled) { //force to .queue to be catched into the queue (activity archiver, subscriptionNotifierQueued )
65
+ authEvent.emit('project_user.update.queue', {updatedProject_userPopulated:pu, req: undefined, skipArchive: true});
66
+ }
67
+
68
+ })
69
+
70
+ });
71
+
72
+ });
73
+ }
74
+
75
+ updateParticipatingProjectUsers(request, operation) {
76
+ winston.debug("Route queue request.participatingAgents", request.participatingAgents);
77
+ if (request.participatingAgents.length>0) {
78
+ request.participatingAgents.forEach(user => {
79
+ winston.debug("request.participatingAgents user",user); //it is a user and not a project_user
80
+ this.updateProjectUser(user.id, request.id_project, operation);
81
+ });
82
+ }
83
+ }
84
+
85
+ listen() {
86
+
87
+ if (this.enabled==true) {
88
+ winston.info("Route queue with queue Listener listen");
89
+ } else {
90
+ return winston.info("Route queue with queue Listener disabled");
91
+ }
92
+
93
+ var that = this;
94
+
95
+ // TODO fai versione che passa anche project
96
+ var requestCreateKey = 'request.create';
97
+ if (requestEvent.queueEnabled) {
98
+ requestCreateKey = 'request.create.queue';
99
+ }
100
+ winston.debug('Route queue requestCreateKey: ' + requestCreateKey);
101
+
102
+ requestEvent.on(requestCreateKey, async (request) => {
103
+ setImmediate(() => {
104
+ winston.debug('Route queue requestCreate');
105
+ this.updateParticipatingProjectUsers(request, +1);
106
+ });
107
+ });
108
+
109
+ // TODO usa versione complete con project per evitare query??
110
+ var requestCloseKey = 'request.close'; //request.close event here queued under job
111
+ if (requestEvent.queueEnabled) {
112
+ requestCloseKey = 'request.close.queue';
113
+ }
114
+ winston.debug('Route queue requestCloseKey: ' + requestCloseKey);
115
+
116
+ requestEvent.on(requestCloseKey, async (request) => { //request.close event here noqueued
117
+ winston.debug("request.close event here 4")
118
+ setImmediate(() => {
119
+ winston.debug('Route queue requestClose');
120
+ this.updateParticipatingProjectUsers(request, -1);
121
+ });
122
+ });
123
+
124
+
125
+ var requestParticipantsJoinKey = 'request.participants.join';
126
+ if (requestEvent.queueEnabled) {
127
+ requestParticipantsJoinKey = 'request.participants.join.queue';
128
+ }
129
+ winston.debug('Route queue requestParticipantsJoinKey: ' + requestParticipantsJoinKey);
130
+
131
+ requestEvent.on(requestParticipantsJoinKey, async (data) => {
132
+ winston.debug('Route queue ParticipantsJoin');
133
+
134
+ var request = data.request;
135
+ var member = data.member;
136
+ setImmediate(() => {
137
+ this.updateProjectUser(member, request.id_project, 1);
138
+ });
139
+ });
140
+
141
+ var requestParticipantsLeaveKey = 'request.participants.leave';
142
+ if (requestEvent.queueEnabled) {
143
+ requestParticipantsLeaveKey = 'request.participants.leave.queue';
144
+ }
145
+ winston.debug('Route queue requestParticipantsLeaveKey: ' + requestParticipantsLeaveKey);
146
+
147
+ requestEvent.on(requestParticipantsLeaveKey, async (data) => {
148
+ winston.debug('Route queue ParticipantsLeave');
149
+
150
+ var request = data.request;
151
+ var member = data.member;
152
+ setImmediate(() => {
153
+ this.updateProjectUser(member, request.id_project, -1);
154
+ });
155
+ });
156
+
157
+ var requestParticipantsUpdateKey = 'request.participants.update';
158
+ if (requestEvent.queueEnabled) {
159
+ requestParticipantsUpdateKey = 'request.participants.update.queue';
160
+ }
161
+ winston.debug('Route queue requestParticipantsUpdateKey: ' + requestParticipantsUpdateKey);
162
+
163
+ requestEvent.on(requestParticipantsUpdateKey, async (data) => {
164
+ winston.debug('Route queue Participants Update');
165
+
166
+ var request = data.request;
167
+ var removedParticipants = data.removedParticipants;
168
+ var addedParticipants = data.addedParticipants;
169
+
170
+ setImmediate(() => {
171
+
172
+ addedParticipants.forEach(participant => {
173
+ winston.debug('addedParticipants participant', participant);
174
+ this.updateProjectUser(participant, request.id_project, 1);
175
+ });
176
+
177
+ removedParticipants.forEach(participant => {
178
+ winston.debug('removedParticipants participant', participant);
179
+ this.updateProjectUser(participant, request.id_project, -1);
180
+ });
181
+
182
+ });
183
+ });
184
+
185
+
186
+
187
+ }
188
+
189
+ }
190
+
191
+ var listener = new Listener();
192
+
193
+
194
+ module.exports = listener;
package/routes/email.js CHANGED
@@ -303,33 +303,35 @@ if (process.env.ENABLE_TEST_EMAIL_ENDPOINT==true || process.env.ENABLE_TEST_EMAI
303
303
 
304
304
 
305
305
  //TODO add cc
306
- router.post('/send',
307
- async (req, res) => {
308
- let to = req.body.to;
309
- winston.debug("to: " + to);
306
+ // router.post('/send',
307
+ // async (req, res) => {
308
+ // let to = req.body.to;
309
+ // winston.debug("to: " + to);
310
310
 
311
- let text = req.body.text;
312
- winston.debug("text: " + text);
311
+ // let text = req.body.text;
312
+ // winston.debug("text: " + text);
313
313
 
314
- let request_id = req.body.request_id;
315
- winston.debug("request_id: " + request_id);
314
+ // let request_id = req.body.request_id;
315
+ // winston.debug("request_id: " + request_id);
316
316
 
317
- let subject = req.body.subject;
318
- winston.debug("subject: " + subject);
317
+ // let subject = req.body.subject;
318
+ // winston.debug("subject: " + subject);
319
319
 
320
- winston.debug("req.project", req.project);
320
+ // winston.debug("req.project", req.project);
321
321
 
322
- let newto = await recipientEmailUtil.process(to, req.projectid);
323
- winston.debug("newto: " + newto);
322
+ // let newto = await recipientEmailUtil.process(to, req.projectid);
323
+ // winston.debug("newto: " + newto);
324
324
 
325
- let replyto = req.body.replyto;
326
- winston.debug("replyto: " + replyto);
325
+ // let replyto = req.body.replyto;
326
+ // winston.debug("replyto: " + replyto);
327
327
 
328
- //sendEmailDirect(to, text, project, request_id, subject, tokenQueryString, sourcePage, payload)
329
- emailService.sendEmailDirect(newto, text, req.project, request_id, subject, undefined, undefined, undefined, replyto);
328
+ // winston.info("Sending an email with text : " + text + " to " + to);
329
+
330
+ // //sendEmailDirect(to, text, project, request_id, subject, tokenQueryString, sourcePage, payload)
331
+ // emailService.sendEmailDirect(newto, text, req.project, request_id, subject, undefined, undefined, undefined, replyto);
330
332
 
331
- res.json({"queued": true});
333
+ // res.json({"queued": true});
332
334
 
333
- });
335
+ // });
334
336
 
335
337
  module.exports = router;
package/routes/faq.js CHANGED
@@ -168,10 +168,12 @@ router.post('/', function (req, res) {
168
168
  if (req.body.actions) {
169
169
  newFaq.actions = req.body.actions
170
170
  }
171
-
172
171
  if (req.body.attributes) {
173
172
  newFaq.attributes = req.body.attributes
174
173
  }
174
+ if (req.body.intent_id) {
175
+ newFaq.intent_id = req.body.intent_id;
176
+ }
175
177
 
176
178
  newFaq.save(function (err, savedFaq) {
177
179
  if (err) {
@@ -0,0 +1,57 @@
1
+ var express = require('express');
2
+ var OpenaiKbs = require('../models/openai_kbs');
3
+ var router = express.Router();
4
+
5
+
6
+ router.get('/', async (req, res) => {
7
+
8
+ let project_id = req.projectid;
9
+
10
+ OpenaiKbs.find({ id_project: project_id }, (err, kbs) => {
11
+ if (err) {
12
+ console.error("find all kbs error: ", err);
13
+ return res.status(500).send({ success: false, error: err });
14
+ } else {
15
+ return res.status(200).send(kbs);
16
+ }
17
+ })
18
+ })
19
+
20
+ router.post('/', async (req, res) => {
21
+
22
+ let body = req.body;
23
+
24
+ let new_kbs = new OpenaiKbs({
25
+ name: body.name,
26
+ url: body.url,
27
+ id_project: req.projectid
28
+ })
29
+
30
+ new_kbs.save(function (err, savedKbs) {
31
+ if (err) {
32
+ console.error("save new kbs error: ", err);
33
+ return res.status(500).send({ success: false, error: err});
34
+ } else {
35
+ return res.status(200).send(savedKbs);
36
+ }
37
+ })
38
+ })
39
+
40
+ router.put('/', async (req, res) => {
41
+
42
+ })
43
+
44
+ router.delete('/:kbs_id', async (req, res) => {
45
+ let kbs_id = req.params.kbs_id;
46
+
47
+ OpenaiKbs.findOneAndDelete( { _id: kbs_id }, (err, kbDeleted) => {
48
+ if (err) {
49
+ console.error("find one and delete kbs error: ", err);
50
+ return res.status(500).send({ success: false, error: err});
51
+ } else {
52
+ return res.status(200).send({ success: true, message: 'Knowledge Base deleted successfully', openai_kb: kbDeleted });
53
+ }
54
+ })
55
+ })
56
+
57
+ module.exports = router;
@@ -12,53 +12,53 @@ class FaqService {
12
12
  var that = this;
13
13
  return new Promise(function (resolve, reject) {
14
14
 
15
- //winston.debug('FAQ-KB POST REQUEST BODY ', req.body);
16
- var newFaq_kb = new Faq_kb({
17
- name: name,
18
- description: description,
19
- url: url,
20
- id_project: projectid,
21
- webhook_url: webhook_url,
22
- webhook_enabled: webhook_enabled,
23
- type: type,
24
- language: language,
25
- public: false,
26
- certified: false,
27
- mainCategory: mainCategory,
28
- intentsEngine: intentsEngine,
29
- trashed: false,
30
- createdBy: user_id,
31
- updatedBy: user_id,
32
- attributes: attributes
33
- });
34
-
15
+ //winston.debug('FAQ-KB POST REQUEST BODY ', req.body);
16
+ var newFaq_kb = new Faq_kb({
17
+ name: name,
18
+ description: description,
19
+ url: url,
20
+ id_project: projectid,
21
+ webhook_url: webhook_url,
22
+ webhook_enabled: webhook_enabled,
23
+ type: type,
24
+ language: language,
25
+ public: false,
26
+ certified: false,
27
+ mainCategory: mainCategory,
28
+ intentsEngine: intentsEngine,
29
+ trashed: false,
30
+ createdBy: user_id,
31
+ updatedBy: user_id,
32
+ attributes: attributes
33
+ });
35
34
 
36
- newFaq_kb.save(function (err, savedFaq_kb) {
37
- if (err) {
38
- winston.error('--- > ERROR ', err)
39
- return reject('Error saving object.' );
35
+
36
+ newFaq_kb.save(function (err, savedFaq_kb) {
37
+ if (err) {
38
+ winston.error('--- > ERROR ', err)
39
+ return reject('Error saving object.');
40
+ }
41
+ winston.debug('-> -> SAVED FAQFAQ KB ', savedFaq_kb.toObject())
42
+
43
+ botEvent.emit('faqbot.create', savedFaq_kb);
44
+
45
+ winston.debug('type ' + type)
46
+
47
+ if (type === "internal" || type === "tilebot") {
48
+
49
+ if (!template) {
50
+ template = "empty";
40
51
  }
41
- winston.debug('-> -> SAVED FAQFAQ KB ', savedFaq_kb.toObject())
42
-
43
- botEvent.emit('faqbot.create', savedFaq_kb);
44
-
45
- winston.debug('type '+ type)
46
-
47
- if (type==="internal" || type==="tilebot") {
48
-
49
- if (!template) {
50
- template = "empty";
51
- }
52
- winston.debug('template '+ template);
53
- that.createGreetingsAndOperationalsFaqs(savedFaq_kb._id, savedFaq_kb.createdBy, savedFaq_kb.id_project, template);
54
- } else {
55
- winston.debug('external bot: ', savedFaq_kb);
56
- }
52
+ winston.debug('template ' + template);
53
+ that.createGreetingsAndOperationalsFaqs(savedFaq_kb._id, savedFaq_kb.createdBy, savedFaq_kb.id_project, template);
54
+ } else {
55
+ winston.debug('external bot: ', savedFaq_kb);
56
+ }
57
57
 
58
-
59
58
 
60
- return resolve(savedFaq_kb);
61
- });
59
+
60
+ return resolve(savedFaq_kb);
61
+ });
62
62
  });
63
63
  }
64
64
 
@@ -69,98 +69,119 @@ class FaqService {
69
69
  // aggiungi esempio tdAction con intent_id
70
70
 
71
71
  // TODO non scatta i trigger sui rest hook. fare?
72
- winston.debug('template: '+ template);
72
+ winston.debug('template: ' + template);
73
73
 
74
74
  var faqsArray;
75
75
 
76
- if (template==="example") {
76
+ if (template === "example") {
77
77
 
78
78
  faqsArray = [
79
79
  { 'question': 'Hi', 'answer': 'Hi', 'topic': 'greetings' },
80
80
  { 'question': 'Hello', 'answer': 'Hello', 'topic': 'greetings' },
81
- { 'question': 'Who are you?', 'answer': 'Hi, I\'m a bot 🤖. You can find more about me [here](https://tiledesk.com/chatbot-for-customer-service).\ntdImage:https://console.tiledesk.com/assets/images/tily-welcomebot.gif\n* See the website https://tiledesk.com/\n* Back to start tdAction:start', 'topic': 'greetings' },
82
- { 'question': '👨🏻‍🦰 I want an agent', 'answer': 'We are looking for an operator.. '+ActionsConstants.CHAT_ACTION_MESSAGE.AGENT, 'intent_display_name': 'agent_handoff', 'topic': 'internal' },
83
- { 'question': 'Close\nResolved', 'answer': ActionsConstants.CHAT_ACTION_MESSAGE.CLOSE, 'topic': 'internal' },
84
- { 'question': '\\start', 'answer': 'Hello 👋. I\'m a bot 🤖.\n\nChoose one of the options below or write a message to reach our staff.\n* Who are you?\n* Where are you?\n* What can you do?\n* 👨🏻‍🦰 I want an agent', 'intent_display_name': 'start', 'topic': 'internal' },
81
+ { 'question': 'Who are you?', 'answer': 'Hi, I\'m a bot 🤖. You can find more about me [here](https://tiledesk.com/chatbot-for-customer-service).\ntdImage:https://console.tiledesk.com/assets/images/tily-welcomebot.gif\n* See the website https://tiledesk.com/\n* Back to start tdAction:start', 'topic': 'greetings' },
82
+ { 'question': '👨🏻‍🦰 I want an agent', 'answer': 'We are looking for an operator.. ' + ActionsConstants.CHAT_ACTION_MESSAGE.AGENT, 'intent_display_name': 'agent_handoff', 'topic': 'internal' },
83
+ { 'question': 'Close\nResolved', 'answer': ActionsConstants.CHAT_ACTION_MESSAGE.CLOSE, 'topic': 'internal' },
84
+ { 'question': '\\start', 'answer': 'Hello 👋. I\'m a bot 🤖.\n\nChoose one of the options below or write a message to reach our staff.\n* Who are you?\n* Where are you?\n* What can you do?\n* 👨🏻‍🦰 I want an agent', 'intent_display_name': 'start', 'topic': 'internal' },
85
85
  { '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', 'topic': 'internal' }, //TODO se metto spazio n * nn va
86
- { 'question': 'What can you do?', 'answer': 'Using natural language processing, I\'m able to find the best answer for your users. I also support images, videos etc.. Let\'s try:\n* Sample Image\n* Sample Video\n* Sample Action tdAction:action1\n* Sample Frame\n* Back to start tdAction:start', 'topic': 'sample' },
87
- { 'question': 'Sample Image', 'answer': 'tdImage:https://tiledesk.com/wp-content/uploads/2022/07/tiledesk_v2.png\n* What can you do?\n* Back to start tdAction:start', 'topic': 'sample' },
88
- { 'question': 'Sample Frame', 'answer': 'tdFrame:https://www.emanueleferonato.com/wp-content/uploads/2019/02/runner/\n* What can you do?\n* Back to start tdAction:start', 'topic': 'sample' },
89
- { 'question': 'Sample Video', 'answer': 'tdVideo:https://www.youtube.com/embed/EngW7tLk6R8\n* What can you do?\n* Back to start tdAction:start', 'topic': 'sample' },
90
- { 'question': 'Where are you?', 'answer': 'We are here ❤️\ntdFrame:https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d6087916.923447935!2d8.234804542117423!3d41.836572992140624!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x12d4fe82448dd203%3A0xe22cf55c24635e6f!2sItaly!5e0!3m2!1sen!2sit!4v1613657475377!5m2!1sen!2sit\n* Back to start tdAction:start', 'topic': 'sample' },
91
-
86
+ { 'question': 'What can you do?', 'answer': 'Using natural language processing, I\'m able to find the best answer for your users. I also support images, videos etc.. Let\'s try:\n* Sample Image\n* Sample Video\n* Sample Action tdAction:action1\n* Sample Frame\n* Back to start tdAction:start', 'topic': 'sample' },
87
+ { 'question': 'Sample Image', 'answer': 'tdImage:https://tiledesk.com/wp-content/uploads/2022/07/tiledesk_v2.png\n* What can you do?\n* Back to start tdAction:start', 'topic': 'sample' },
88
+ { 'question': 'Sample Frame', 'answer': 'tdFrame:https://www.emanueleferonato.com/wp-content/uploads/2019/02/runner/\n* What can you do?\n* Back to start tdAction:start', 'topic': 'sample' },
89
+ { 'question': 'Sample Video', 'answer': 'tdVideo:https://www.youtube.com/embed/EngW7tLk6R8\n* What can you do?\n* Back to start tdAction:start', 'topic': 'sample' },
90
+ { 'question': 'Where are you?', 'answer': 'We are here ❤️\ntdFrame:https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d6087916.923447935!2d8.234804542117423!3d41.836572992140624!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x12d4fe82448dd203%3A0xe22cf55c24635e6f!2sItaly!5e0!3m2!1sen!2sit!4v1613657475377!5m2!1sen!2sit\n* Back to start tdAction:start', 'topic': 'sample' },
91
+
92
92
  // { 'question': 'Sample Webhook', 'answer': 'tdWebhook:https://tiledesk-bot-webhook.tiledesk.repl.co', 'topic': 'sample' },
93
- { 'question': 'Sample Action', 'answer': 'Hello 👋 Would you like to take a closer look at our offer?\n* Yes, please tdAction:yes_action\n* No tdAction:no_action','intent_display_name': 'action1', 'topic': 'sample' },
94
- { 'question': 'Yes Action', 'answer': 'Great! Take a look here:\n* Tiledesk Pricing https://tiledesk.com/pricing-cloud/', 'intent_display_name': 'yes_action','topic': 'sample' },
95
- { 'question': 'No Action', 'answer': 'All right! If you need anything, let us know.', 'intent_display_name': 'no_action','topic': 'sample' },
96
-
97
-
93
+ { 'question': 'Sample Action', 'answer': 'Hello 👋 Would you like to take a closer look at our offer?\n* Yes, please tdAction:yes_action\n* No tdAction:no_action', 'intent_display_name': 'action1', 'topic': 'sample' },
94
+ { 'question': 'Yes Action', 'answer': 'Great! Take a look here:\n* Tiledesk Pricing https://tiledesk.com/pricing-cloud/', 'intent_display_name': 'yes_action', 'topic': 'sample' },
95
+ { 'question': 'No Action', 'answer': 'All right! If you need anything, let us know.', 'intent_display_name': 'no_action', 'topic': 'sample' },
96
+
97
+
98
98
  // action button nn si può fare perche gli id cambiano
99
99
  ]
100
100
 
101
101
  }
102
102
 
103
- if (template==="blank") {
103
+ if (template === "blank") {
104
104
 
105
105
  // faqsArray = [
106
106
  // { 'question': '\\start', 'answer': 'Hello', 'intent_display_name': 'start', 'topic': 'internal' },
107
107
  // { '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', 'topic': 'internal' }, //TODO se metto spazio n * nn va
108
108
  // ]
109
- faqsArray = [
110
- {
111
- 'question': '\\start',
112
- "actions" : [
113
- {
114
- "_tdActionType" : "reply",
115
- "text" : "Hi, how can I help you?",
116
- "attributes" : {
117
- "commands" : [
118
- {
119
- "type" : "message",
120
- "message" : {
121
- "type" : "text",
122
- "text" : "Hi, how can I help you?"
123
- }
124
- }
125
- ]
126
- }
127
- }
128
- ],
129
- 'intent_display_name': 'start',
130
- 'topic': 'internal'
131
- },
132
- {
133
- 'question': 'defaultFallback',
134
- "actions" : [
135
- {
136
- "_tdActionType" : "reply",
137
- "text" : "I didn't understand. Can you rephrase your question?",
138
- "attributes" : {
139
- "commands" : [
140
- {
141
- "type" : "message",
142
- "message" : {
143
- "type" : "text",
144
- "text" : "I didn't understand. Can you rephrase your question?"
145
- }
146
- }
147
- ]
148
- }
149
- }
150
- ],
151
- 'intent_display_name': 'defaultFallback',
152
- 'topic': 'internal'
153
- }, //TODO se metto spazio n * nn va
154
- ]
109
+ faqsArray = [{
110
+ "webhook_enabled": false,
111
+ "enabled": true,
112
+ "actions": [{
113
+ "_tdActionType": "reply",
114
+ "text": "I didn't understand. Can you rephrase your question?",
115
+ "attributes": {
116
+ "commands": [{
117
+ "type": "message",
118
+ "message": {
119
+ "type": "text",
120
+ "text": "I didn't understand. Can you rephrase your question?"
121
+ }
122
+ }]
123
+ }
124
+ }],
125
+ "intent_display_name": "defaultFallback",
126
+ "attributes": {
127
+ "position": {
128
+ "x": 714,
129
+ "y": 528
130
+ }
131
+ }
132
+ }, {
133
+ "webhook_enabled": false,
134
+ "enabled": true,
135
+ "actions": [{
136
+ "_tdActionType": "intent",
137
+ "intentName": "#9d0b96b9-e036-4c2d-8504-1181b5c4be75"
138
+ }],
139
+ "question": "\\start",
140
+ "intent_display_name": "start",
141
+ "attributes": {
142
+ "position": {
143
+ "x": 172,
144
+ "y": 384
145
+ }
146
+ }
147
+ }, {
148
+ "webhook_enabled": false,
149
+ "enabled": true,
150
+ "actions": [{
151
+ "_tdActionType": "reply",
152
+ "attributes": {
153
+ "disableInputMessage": false,
154
+ "commands": [{
155
+ "type": "wait",
156
+ "time": 500
157
+ }, {
158
+ "type": "message",
159
+ "message": {
160
+ "type": "text",
161
+ "text": "Hi, how can I help you?"
162
+ }
163
+ }]
164
+ },
165
+ "text": "Hi, how can I help you?\r\n"
166
+ }],
167
+ "intent_display_name": "welcome",
168
+ "intent_id": "9d0b96b9-e036-4c2d-8504-1181b5c4be75",
169
+ "attributes": {
170
+ "position": {
171
+ "x": 714,
172
+ "y": 113
173
+ }
174
+ }
175
+ }]
155
176
 
156
177
  }
157
178
 
158
179
 
159
- if (template==="handoff") {
180
+ if (template === "handoff") {
160
181
 
161
- faqsArray = [
162
- { 'question': '\\start', 'answer': 'Hello', 'intent_display_name': 'start', 'topic': 'internal' },
163
- { 'question': '👨🏻‍🦰 I want an agent', 'answer': 'We are looking for an operator.. '+ActionsConstants.CHAT_ACTION_MESSAGE.AGENT, 'intent_display_name': 'agent_handoff', 'topic': 'internal' },
182
+ faqsArray = [
183
+ { 'question': '\\start', 'answer': 'Hello', 'intent_display_name': 'start', 'topic': 'internal' },
184
+ { 'question': '👨🏻‍🦰 I want an agent', 'answer': 'We are looking for an operator.. ' + ActionsConstants.CHAT_ACTION_MESSAGE.AGENT, 'intent_display_name': 'agent_handoff', 'topic': 'internal' },
164
185
  { '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', 'topic': 'internal' }, //TODO se metto spazio n * nn va
165
186
  ]
166
187
 
@@ -169,18 +190,20 @@ class FaqService {
169
190
  if (template === "empty") {
170
191
  faqsArray = [];
171
192
  }
172
-
173
-
193
+
194
+
174
195
  faqsArray.forEach(faq => {
175
196
 
176
197
  var newFaq = new Faq({
177
198
  id_faq_kb: faq_kb_id,
199
+ intent_id: faq.intent_id,
178
200
  question: faq.question,
179
201
  answer: faq.answer,
180
202
  actions: faq.actions,
181
203
  reply: faq.reply,
182
204
  intent_display_name: faq.intent_display_name,
183
205
  language: "en",
206
+ attributes: faq.attributes,
184
207
  id_project: projectid,
185
208
  topic: faq.topic,
186
209
  createdBy: created_by,
@@ -207,8 +230,8 @@ class FaqService {
207
230
  winston.debug("(Service) GET ALL FAQ OF THE BOT ID (req.query): ", faq_kb_id);
208
231
 
209
232
  return new Promise((resolve, reject) => {
210
-
211
- Faq.find({ id_faq_kb: faq_kb_id}, (err, faqs) => {
233
+
234
+ Faq.find({ id_faq_kb: faq_kb_id }, (err, faqs) => {
212
235
  if (err) {
213
236
  reject(err);
214
237
  }
package/test/faqRoute.js CHANGED
@@ -53,7 +53,7 @@ describe('FaqKBRoute', () => {
53
53
  chai.request(server)
54
54
  .post('/' + savedProject._id + '/faq')
55
55
  .auth(email, pwd)
56
- .send({ id_faq_kb: id_faq_kb, question: "question1", answer: "answer1", attributes: { attr1: { one: "one", two: "two"}, attr2: {three: "three"}} })
56
+ .send({ id_faq_kb: id_faq_kb, question: "question1", answer: "answer1", attributes: { attr1: { one: "one", two: "two"}, attr2: {three: "three"}}, intent_id: 'custom-intent-id' }) // if intent_id is null the value will be the default one
57
57
  .end((err, res) => {
58
58
  //console.log("res", res);
59
59
  console.log("res.body", res.body);
@@ -111,6 +111,48 @@ describe('FaqKBRoute', () => {
111
111
 
112
112
 
113
113
 
114
+ });
115
+ })
116
+ })
117
+ })
118
+
119
+ it('create with template blank', (done) => {
120
+
121
+ var email = "test-signup-" + Date.now() + "@email.com";
122
+ var pwd = "pwd";
123
+
124
+ userService.signup(email, pwd, "Test Firstname", "Test Lastname").then((savedUser) => {
125
+ projectService.create("test-faqkb-create", savedUser._id).then((savedProject) => {
126
+
127
+ chai.request(server)
128
+ .post('/' + savedProject._id + '/faq_kb')
129
+ .auth(email, pwd)
130
+ .send({ "name": "testbot", type: "internal", template: "blank" })
131
+ .end((err, res) => {
132
+ if (log) {
133
+ }
134
+ console.log("res.body", res.body);
135
+ res.should.have.status(200);
136
+ res.body.should.be.a('object');
137
+ expect(res.body.name).to.equal("testbot");
138
+ var id_faq_kb = res.body._id;
139
+
140
+ chai.request(server)
141
+ .get('/' + savedProject._id + '/faq?id_faq_kb=' + id_faq_kb)
142
+ .auth(email, pwd)
143
+ .end((err, res) => {
144
+ if (log) {
145
+ }
146
+ console.log("faq_list: ", JSON.stringify(res.body, null, 2));
147
+ res.should.have.status(200);
148
+ res.body.should.be.an('array').that.is.not.empty;
149
+
150
+ done();
151
+
152
+ })
153
+
154
+
155
+
114
156
  });
115
157
  })
116
158
  })
@@ -0,0 +1,75 @@
1
+ //During the test the env variable is set to test
2
+ process.env.NODE_ENV = 'test';
3
+
4
+ let log = false;
5
+
6
+ //Require the dev-dependencies
7
+ let chai = require('chai');
8
+ let chaiHttp = require('chai-http');
9
+ let server = require('../app');
10
+ let should = chai.should();
11
+ var fs = require('fs');
12
+ const path = require('path');
13
+
14
+ // chai.config.includeStack = true;
15
+
16
+ var expect = chai.expect;
17
+ var assert = chai.assert;
18
+
19
+ chai.use(chaiHttp);
20
+
21
+ describe('FaqKBRoute', () => {
22
+
23
+ describe('/create', () => {
24
+
25
+ it('home', (done) => {
26
+
27
+ })
28
+
29
+ it('create', (done) => {
30
+
31
+ var email = "test-signup-" + Date.now() + "@email.com";
32
+ var pwd = "pwd";
33
+
34
+ userService.signup(email, pwd, "Test Firstname", "Test lastname").then(function (savedUser) {
35
+ projectService.create("test-faqkb-create", savedUser._id).then(function (savedProject) {
36
+ chai.request(server)
37
+ .post('/' + savedProject._id + '/faq_kb')
38
+ .auth(email, pwd)
39
+ .send({ "name": "testbot", type: "external", language: 'fr' })
40
+ .end((err, res) => {
41
+ if (log) {
42
+ console.log("res.body", res.body);
43
+ }
44
+ res.should.have.status(200);
45
+ res.body.should.be.a('object');
46
+ expect(res.body.name).to.equal("testbot");
47
+ expect(res.body.language).to.equal("fr");
48
+
49
+ chai.request(server)
50
+ .get('/' + savedProject._id + '/faq_kb/' + res.body._id)
51
+ .auth(email, pwd)
52
+ .end((err, res) => {
53
+ if (log) {
54
+ console.log("res.body", res.body);
55
+ }
56
+ res.should.have.status(200);
57
+
58
+ done();
59
+ });
60
+ });
61
+
62
+
63
+ });
64
+ });
65
+
66
+ }).timeout(20000);
67
+
68
+
69
+
70
+
71
+ });
72
+
73
+ });
74
+
75
+