@tiledesk/tiledesk-server 2.4.46 → 2.4.48

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/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
+