@tiledesk/tiledesk-server 2.19.13 → 2.19.14

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/routes/kb.js CHANGED
@@ -894,7 +894,13 @@ router.delete('/deleteall', async (req, res) => {
894
894
 
895
895
  aiService.deleteNamespace(data).then((resp) => {
896
896
  winston.debug("delete namespace resp: ", resp.data);
897
- kbEvent.emit('kb.contents.delete', { req, namespace_id, project_id });
897
+ kbEvent.emit('kb.contents.delete', {
898
+ req,
899
+ namespace_id,
900
+ project_id,
901
+ namespace_name: namespace.name,
902
+ deleteMode: 'contents_only'
903
+ });
898
904
  res.status(200).send(resp.data);
899
905
  }).catch((err) => {
900
906
  winston.error("delete namespace err: ", err);
@@ -1443,7 +1449,14 @@ router.delete('/namespace/:id', async (req, res) => {
1443
1449
  })
1444
1450
  winston.debug("delete all contents response: ", deleteResponse);
1445
1451
 
1446
- kbEvent.emit('kb.contents.delete', { req, namespace_id, project_id, deletedCount: deleteResponse?.deletedCount });
1452
+ kbEvent.emit('kb.contents.delete', {
1453
+ req,
1454
+ namespace_id,
1455
+ project_id,
1456
+ namespace_name: namespace.name,
1457
+ deletedCount: deleteResponse?.deletedCount,
1458
+ deleteMode: 'contents_only'
1459
+ });
1447
1460
 
1448
1461
  return res.status(200).send({ success: true, message: "All contents deleted successfully" })
1449
1462
 
@@ -1485,6 +1498,14 @@ router.delete('/namespace/:id', async (req, res) => {
1485
1498
  })
1486
1499
  winston.debug("delete namespace response: ", deleteNamespaceResponse);
1487
1500
 
1501
+ kbEvent.emit('kb.namespace.delete', {
1502
+ req,
1503
+ namespace_id,
1504
+ project_id,
1505
+ namespace_name: namespace.name,
1506
+ deletedCount: deleteResponse?.deletedCount
1507
+ });
1508
+
1488
1509
  return res.status(200).send({ success: true, message: "Namespace deleted succesfully" })
1489
1510
 
1490
1511
  }).catch((err) => {
@@ -1757,6 +1778,18 @@ router.post('/', async (req, res) => {
1757
1778
  }
1758
1779
 
1759
1780
  aiManager.scheduleScrape([json], namespace.hybrid);
1781
+
1782
+ kbEvent.emit('kb.contents.add', {
1783
+ req,
1784
+ project_id: id_project,
1785
+ namespace_id: namespace_id,
1786
+ namespace_name: namespace.name,
1787
+ contentAddType: 'content',
1788
+ count: 1,
1789
+ type: saved_kb.type,
1790
+ source: saved_kb.source || saved_kb.name
1791
+ });
1792
+
1760
1793
  return res.status(200).send(raw_content);
1761
1794
 
1762
1795
  }
@@ -1825,6 +1858,14 @@ router.post('/multi', upload.single('uploadFile'), async (req, res) => {
1825
1858
 
1826
1859
  try {
1827
1860
  const result = await aiManager.addMultipleUrls(namespace, list, options);
1861
+ kbEvent.emit('kb.contents.add', {
1862
+ req,
1863
+ project_id: id_project,
1864
+ namespace_id: namespace_id,
1865
+ namespace_name: namespace.name,
1866
+ contentAddType: 'url_list',
1867
+ count: list.length
1868
+ });
1828
1869
  return res.status(200).send(result);
1829
1870
  } catch (err) {
1830
1871
  winston.error("addMultipleUrls error: ", err)
@@ -1931,6 +1972,16 @@ router.post('/csv', upload.single('uploadFile'), async (req, res) => {
1931
1972
  }
1932
1973
 
1933
1974
  aiManager.scheduleScrape(resources, hybrid);
1975
+
1976
+ kbEvent.emit('kb.contents.add', {
1977
+ req,
1978
+ project_id: project_id,
1979
+ namespace_id: namespace_id,
1980
+ namespace_name: namespace.name,
1981
+ contentAddType: 'csv',
1982
+ count: kbs.length
1983
+ });
1984
+
1934
1985
  return res.status(200).send(result);
1935
1986
 
1936
1987
  }).catch((err) => {
@@ -2068,6 +2119,18 @@ router.post('/sitemap/import', async (req, res) => {
2068
2119
  return res.status(200).send(result);
2069
2120
  }
2070
2121
  result.push(saved_content);
2122
+
2123
+ kbEvent.emit('kb.contents.add', {
2124
+ req,
2125
+ project_id: id_project,
2126
+ namespace_id: namespace_id,
2127
+ namespace_name: namespace.name,
2128
+ contentAddType: 'sitemap',
2129
+ count: urls.length,
2130
+ type: 'sitemap',
2131
+ source: source
2132
+ });
2133
+
2071
2134
  return res.status(200).send(result);
2072
2135
  } catch (err) {
2073
2136
  return res.status(500).send({ success: false, error: "Unable to add multiple urls from sitemap due to an error." });
@@ -2279,6 +2342,29 @@ router.delete('/:kb_id', async (req, res) => {
2279
2342
  data.engine = namespace.engine || default_engine;
2280
2343
  winston.verbose("/:delete_id data: ", data);
2281
2344
 
2345
+ const emitKbContentDelete = (deletedKb) => {
2346
+ const content = deletedKb || kb;
2347
+ const contentSnapshot = content.toObject ? content.toObject() : content;
2348
+ kbEvent.emit('kb.content.delete', {
2349
+ req,
2350
+ kb_id,
2351
+ project_id,
2352
+ namespace_id,
2353
+ namespace_name: namespace.name,
2354
+ kb: {
2355
+ _id: contentSnapshot._id,
2356
+ name: contentSnapshot.name,
2357
+ source: contentSnapshot.source,
2358
+ type: contentSnapshot.type
2359
+ }
2360
+ });
2361
+ };
2362
+
2363
+ if (process.env.NODE_ENV === 'test') {
2364
+ emitKbContentDelete(kb);
2365
+ return res.status(200).send({ success: true, message: "Content deleted successfully" });
2366
+ }
2367
+
2282
2368
  aiService.deleteIndex(data).then((resp) => {
2283
2369
  winston.debug("delete resp: ", resp.data);
2284
2370
  if (resp.data.success === true) {
@@ -2288,6 +2374,7 @@ router.delete('/:kb_id', async (req, res) => {
2288
2374
  winston.error("Delete kb error: ", err);
2289
2375
  return res.status(500).send({ success: false, error: err });
2290
2376
  }
2377
+ emitKbContentDelete(deletedKb);
2291
2378
  res.status(200).send(deletedKb);
2292
2379
  })
2293
2380
 
@@ -2303,6 +2390,7 @@ router.delete('/:kb_id', async (req, res) => {
2303
2390
  winston.verbose("Unable to delete the content in indexing status")
2304
2391
  return res.status(500).send({ success: false, error: "Unable to delete the content in indexing status" })
2305
2392
  } else {
2393
+ emitKbContentDelete(deletedKb);
2306
2394
  res.status(200).send(deletedKb);
2307
2395
  }
2308
2396
  })
@@ -18,6 +18,25 @@ var validtoken = require('../middleware/valid-token')
18
18
  var roleChecker = require('../middleware/has-role');
19
19
  const puEvent = require('../event/projectUserEvent');
20
20
  const { track } = require('../lib/analyticsClient');
21
+ const projectUserUpdateContextUtil = require('../utils/projectUserUpdateContextUtil');
22
+
23
+ function emitProjectUserDeleteActivity(req, project_user, deleteType) {
24
+ if (!project_user) {
25
+ return;
26
+ }
27
+ project_user.populate({ path: 'id_user', select: { firstname: 1, lastname: 1, email: 1 } }, function (populateErr, project_userPopulated) {
28
+ if (populateErr) {
29
+ winston.error('Error populating project_user for delete activity', populateErr);
30
+ }
31
+ const pu = project_userPopulated || project_user;
32
+ const payload = pu.toJSON ? pu.toJSON() : pu;
33
+ authEvent.emit('project_user.delete', {
34
+ req: req,
35
+ project_userPopulated: payload,
36
+ deleteType: deleteType
37
+ });
38
+ });
39
+ }
21
40
 
22
41
 
23
42
  router.post('/invite', [passport.authenticate(['basic', 'jwt'], { session: false }), validtoken, roleChecker.hasRole('admin')], function (req, res) {
@@ -111,15 +130,19 @@ router.post('/invite', [passport.authenticate(['basic', 'jwt'], { session: false
111
130
 
112
131
  emailService.sendYouHaveBeenInvited(email, req.user.firstname, req.user.lastname, req.project.name, id_project, user.firstname, user.lastname, req.body.role)
113
132
 
114
- updatedPuser.populate({path:'id_user', select:{'firstname':1, 'lastname':1, 'email': 1}},function (err, updatedPuserPopulated){
115
- var pu = updatedPuserPopulated.toJSON();
133
+ savedProject_user.populate({path:'id_user', select:{'firstname':1, 'lastname':1, 'email': 1}},function (err, savedProject_userPopulated){
134
+ if (err) {
135
+ winston.error("Error populating project user after re-invite", err);
136
+ return;
137
+ }
138
+ var pu = savedProject_userPopulated.toJSON();
116
139
  pu.isBusy = ProjectUserUtil.isBusy(savedProject_userPopulated, req.project.settings && req.project.settings.max_agent_assigned_chat);
117
- var eventData = {req:req, updatedPuserPopulated: pu};
140
+ var eventData = {req:req, savedProject_userPopulated: pu};
118
141
  winston.debug("eventData",eventData);
119
142
  authEvent.emit('project_user.invite', eventData);
120
143
  });
121
144
 
122
- return res.status(200).send(updatedPuser);
145
+ return res.status(200).send(savedProject_user);
123
146
  })
124
147
 
125
148
  } else {
@@ -220,6 +243,13 @@ router.put('/', [passport.authenticate(['basic', 'jwt'], { session: false }), va
220
243
  }
221
244
 
222
245
  const previousUserAvailable = req.projectuser.user_available;
246
+ const previousProfileStatus = req.projectuser.profileStatus;
247
+ const updateContext = projectUserUpdateContextUtil.buildProjectUserUpdateContext(
248
+ req,
249
+ previousUserAvailable,
250
+ previousProfileStatus,
251
+ projectUserUpdateContextUtil.resolveUserId(req.projectuser.id_user)
252
+ );
223
253
 
224
254
  Project_user.findByIdAndUpdate(req.projectuser.id, update, { new: true, upsert: true }, function (err, updatedProject_user) {
225
255
  if (err) {
@@ -230,7 +260,13 @@ router.put('/', [passport.authenticate(['basic', 'jwt'], { session: false }), va
230
260
  updatedProject_user.populate({ path:'id_user', select: { 'firstname': 1, 'lastname': 1 }}, function (err, updatedProject_userPopulated) {
231
261
  var pu = updatedProject_userPopulated.toJSON();
232
262
  pu.isBusy = ProjectUserUtil.isBusy(updatedProject_userPopulated, req.project.settings && req.project.settings.max_agent_assigned_chat);
233
- authEvent.emit('project_user.update', {updatedProject_userPopulated:pu, req: req, previousUserAvailable: previousUserAvailable});
263
+ authEvent.emit('project_user.update', {
264
+ updatedProject_userPopulated: pu,
265
+ req: req,
266
+ previousUserAvailable: previousUserAvailable,
267
+ previousProfileStatus: previousProfileStatus,
268
+ updateContext: updateContext
269
+ });
234
270
  });
235
271
 
236
272
  res.json(updatedProject_user);
@@ -286,7 +322,14 @@ router.put('/:project_userid', [passport.authenticate(['basic', 'jwt'], { sessio
286
322
 
287
323
  winston.debug("project_userid update", update);
288
324
 
289
- function _doUpdateProjectUser(previousUserAvailable) {
325
+ function _doUpdateProjectUser(previousUserAvailable, previousProfileStatus, targetUserId) {
326
+ const updateContext = projectUserUpdateContextUtil.buildProjectUserUpdateContext(
327
+ req,
328
+ previousUserAvailable,
329
+ previousProfileStatus,
330
+ targetUserId
331
+ );
332
+
290
333
  Project_user.findByIdAndUpdate(req.params.project_userid, update, { new: true, upsert: true }, function (err, updatedProject_user) {
291
334
  if (err) {
292
335
  winston.error("Error gettting project_user for update", err);
@@ -299,7 +342,13 @@ router.put('/:project_userid', [passport.authenticate(['basic', 'jwt'], { sessio
299
342
  var pu = updatedProject_userPopulated.toJSON();
300
343
  pu.isBusy = ProjectUserUtil.isBusy(updatedProject_user, req.project.settings && req.project.settings.max_agent_assigned_chat);
301
344
 
302
- authEvent.emit('project_user.update', {updatedProject_userPopulated:pu, req: req, previousUserAvailable: previousUserAvailable});
345
+ authEvent.emit('project_user.update', {
346
+ updatedProject_userPopulated: pu,
347
+ req: req,
348
+ previousUserAvailable: previousUserAvailable,
349
+ previousProfileStatus: previousProfileStatus,
350
+ updateContext: updateContext
351
+ });
303
352
  });
304
353
 
305
354
 
@@ -307,12 +356,16 @@ router.put('/:project_userid', [passport.authenticate(['basic', 'jwt'], { sessio
307
356
  });
308
357
  }
309
358
 
310
- if (update.user_available !== undefined && process.env.ANALYTICS_INGEST_URL) {
311
- Project_user.findById(req.params.project_userid, 'user_available').lean().exec(function(err, currentPu) {
312
- _doUpdateProjectUser(currentPu ? currentPu.user_available : null);
359
+ if (update.user_available !== undefined || update.profileStatus !== undefined) {
360
+ Project_user.findById(req.params.project_userid, 'user_available profileStatus id_user').lean().exec(function(err, currentPu) {
361
+ _doUpdateProjectUser(
362
+ currentPu ? currentPu.user_available : null,
363
+ currentPu ? currentPu.profileStatus : null,
364
+ currentPu ? currentPu.id_user : null
365
+ );
313
366
  });
314
367
  } else {
315
- _doUpdateProjectUser(null);
368
+ _doUpdateProjectUser(null, null, null);
316
369
  }
317
370
  });
318
371
 
@@ -340,7 +393,7 @@ router.delete('/:project_userid', [passport.authenticate(['basic', 'jwt'], { ses
340
393
  }
341
394
 
342
395
  puEvent.emit('project_user.deleted', project_user);
343
- // Event 'project_user.delete' not working - Check it and improve it to manage soft/hard delete
396
+ emitProjectUserDeleteActivity(req, project_user, 'soft');
344
397
  return res.status(200).send(project_user);
345
398
 
346
399
  })
@@ -360,11 +413,7 @@ router.delete('/:project_userid', [passport.authenticate(['basic', 'jwt'], { ses
360
413
 
361
414
  winston.debug("Hard deleted project_user", project_user);
362
415
 
363
- if (project_user) {
364
- project_user.populate({ path: 'id_user', select: { 'firstname': 1, 'lastname': 1 } }, function (err, project_userPopulated) {
365
- authEvent.emit('project_user.delete', { req: req, project_userPopulated: project_userPopulated });
366
- });
367
- }
416
+ emitProjectUserDeleteActivity(req, project_user, 'hard');
368
417
 
369
418
  puEvent.emit('project_user.deleted', project_user);
370
419
  return res.status(200).send(project_user);
package/routes/request.js CHANGED
@@ -20,6 +20,7 @@ var Message = require("../models/message");
20
20
  var cacheUtil = require('../utils/cacheUtil');
21
21
  var RequestConstants = require("../models/requestConstants");
22
22
  var cacheEnabler = require("../services/cacheEnabler");
23
+ var assignmentContextUtil = require('../utils/assignmentContextUtil');
23
24
  var Project_user = require("../models/project_user");
24
25
  var Lead = require("../models/lead");
25
26
  var UIDGenerator = require("../utils/UIDGenerator");
@@ -408,7 +409,8 @@ router.post('/:requestid/participants',
408
409
  }
409
410
 
410
411
  //addParticipantByRequestId(request_id, id_project, member)
411
- return requestService.addParticipantByRequestId(req.params.requestid, req.projectid, req.body.member).then(function (updatedRequest) {
412
+ const assignmentOptions = assignmentContextUtil.buildAddParticipantOptions(req, req.body.member);
413
+ return requestService.addParticipantByRequestId(req.params.requestid, req.projectid, req.body.member, assignmentOptions).then(function (updatedRequest) {
412
414
 
413
415
  winston.verbose("participant added", updatedRequest);
414
416
 
@@ -439,7 +441,8 @@ router.put('/:requestid/participants', async (req, res) => {
439
441
  winston.debug("var participants", participants);
440
442
 
441
443
  //setParticipantsByRequestId(request_id, id_project, participants)
442
- return requestService.setParticipantsByRequestId(req.params.requestid, req.projectid, participants).then(function (updatedRequest) {
444
+ const assignmentOptions = assignmentContextUtil.buildSetParticipantsOptions(req, participants);
445
+ return requestService.setParticipantsByRequestId(req.params.requestid, req.projectid, participants, assignmentOptions).then(function (updatedRequest) {
443
446
 
444
447
  winston.debug("participant set", updatedRequest);
445
448
 
@@ -516,7 +519,8 @@ router.put('/:requestid/replace', async (req, res) => {
516
519
  participants.push(id);
517
520
  winston.verbose("participants to be set: ", participants);
518
521
 
519
- requestService.setParticipantsByRequestId(req.params.requestid, req.projectid, participants).then((updatedRequest) => {
522
+ const assignmentOptions = assignmentContextUtil.buildSetParticipantsOptions(req, participants);
523
+ requestService.setParticipantsByRequestId(req.params.requestid, req.projectid, participants, assignmentOptions).then((updatedRequest) => {
520
524
  winston.debug("SetParticipant response: ", updatedRequest);
521
525
  // Additive: include the resolved canonical (root) bot id for analytics
522
526
  // attribution. Existing consumers ignore the extra field.
@@ -531,8 +535,13 @@ router.put('/:requestid/replace', async (req, res) => {
531
535
  // TODO make a synchronous chat21 version (with query parameter?) with request.support_group.created
532
536
  router.delete('/:requestid/participants/:participantid', async (req, res) => {
533
537
  winston.debug(req.body);
534
- //removeParticipantByRequestId(request_id, id_project, member)
535
- return requestService.removeParticipantByRequestId(req.params.requestid, req.projectid, req.params.participantid).then(function (updatedRequest) {
538
+ const leaveOptions = assignmentContextUtil.buildRemoveParticipantOptions(req, req.params.participantid);
539
+ return requestService.removeParticipantByRequestId(
540
+ req.params.requestid,
541
+ req.projectid,
542
+ req.params.participantid,
543
+ leaveOptions
544
+ ).then(function (updatedRequest) {
536
545
 
537
546
  winston.verbose("participant removed", updatedRequest);
538
547
 
@@ -593,7 +602,8 @@ router.put('/:requestid/assign', function (req, res) {
593
602
  return res.json(request);
594
603
  }
595
604
  //route(request_id, departmentid, id_project) {
596
- requestService.route(req.params.requestid, req.body.departmentid, req.projectid, req.body.nobot, req.body.no_populate).then(function (updatedRequest) {
605
+ const assignmentOptions = assignmentContextUtil.buildAutoRouteOptions(req, 'api');
606
+ requestService.route(req.params.requestid, req.body.departmentid, req.projectid, req.body.nobot, req.body.no_populate, assignmentOptions).then(function (updatedRequest) {
597
607
 
598
608
  winston.debug("department changed", updatedRequest);
599
609
 
@@ -615,7 +625,8 @@ router.put('/:requestid/assign', function (req, res) {
615
625
  router.put('/:requestid/departments', function (req, res) {
616
626
  winston.debug(req.body);
617
627
  //route(request_id, departmentid, id_project) {
618
- requestService.route(req.params.requestid, req.body.departmentid, req.projectid, req.body.nobot, req.body.no_populate).then(function (updatedRequest) {
628
+ const assignmentOptions = assignmentContextUtil.buildDepartmentRouteOptions(req, 'api');
629
+ requestService.route(req.params.requestid, req.body.departmentid, req.projectid, req.body.nobot, req.body.no_populate, assignmentOptions).then(function (updatedRequest) {
619
630
 
620
631
  winston.debug("department changed", updatedRequest);
621
632
 
@@ -651,7 +662,8 @@ router.put('/:requestid/agent', async (req, res) => {
651
662
  }
652
663
  winston.debug("departmentid after: " + departmentid);
653
664
 
654
- requestService.route(req.params.requestid, departmentid, req.projectid, true, undefined).then(function (updatedRequest) {
665
+ const assignmentOptions = assignmentContextUtil.buildAutoRouteOptions(req, 'chatbot');
666
+ requestService.route(req.params.requestid, departmentid, req.projectid, true, undefined, assignmentOptions).then(function (updatedRequest) {
655
667
 
656
668
  winston.debug("department changed", updatedRequest);
657
669
 
@@ -6,11 +6,14 @@ class ChatbotService {
6
6
 
7
7
  constructor() {}
8
8
 
9
- async fork(id_faq_kb, api_url, token, project_id) {
9
+ async fork(id_faq_kb, api_url, token, project_id, options) {
10
10
  winston.debug("(ChatbotService) fork");
11
11
 
12
+ const forPublish = options && options.forPublish === true;
13
+ const forPublishQuery = forPublish ? '&for_publish=true' : '';
14
+
12
15
  return await axios({
13
- url: api_url + '/' + project_id + '/faq_kb/fork/'+id_faq_kb+"?projectid="+project_id+"&public=false&globals=true",
16
+ url: api_url + '/' + project_id + '/faq_kb/fork/' + id_faq_kb + '?projectid=' + project_id + '&public=false&globals=true' + forPublishQuery,
14
17
  headers: {
15
18
  'Content-Type': 'application/json',
16
19
  'Authorization': token
@@ -76,7 +79,7 @@ class ChatbotService {
76
79
  winston.debug("(ChatbotService) createBot");
77
80
 
78
81
  return await axios({
79
- url: api_url + '/' + project_id + '/faq_kb/',
82
+ url: api_url + '/' + project_id + '/faq_kb/?skip_activity=true',
80
83
  headers: {
81
84
  'Content-Type': 'application/json',
82
85
  'Authorization': token