@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.
@@ -10,6 +10,7 @@ const leadEvent = require('../event/leadEvent');
10
10
  var winston = require('../config/winston');
11
11
  var RequestConstants = require("../models/requestConstants");
12
12
  var requestUtil = require("../utils/requestUtil");
13
+ var assignmentContextUtil = require("../utils/assignmentContextUtil");
13
14
  var cacheUtil = require("../utils/cacheUtil");
14
15
  var arrayUtil = require("../utils/arrayUtil");
15
16
  var cacheEnabler = require("../services/cacheEnabler");
@@ -245,7 +246,7 @@ class RequestService {
245
246
 
246
247
  // TODO changePreflightByRequestId se un agente entra in request freflight true disabilitare add agente e reassing ma mettere un bottone removePreflight???
247
248
  // usalo no_populate
248
- async route(request_id, departmentid, id_project, nobot, no_populate) {
249
+ async route(request_id, departmentid, id_project, nobot, no_populate, options) {
249
250
 
250
251
  try {
251
252
  winston.debug("request_id:" + request_id);
@@ -324,7 +325,13 @@ class RequestService {
324
325
  this.emitParticipantsEvents(
325
326
  request,
326
327
  requestComplete,
327
- beforeParticipants
328
+ beforeParticipants,
329
+ options,
330
+ beforeDepartmentId !== afterDepartmentId ? {
331
+ previousDepartmentId: beforeDepartmentId,
332
+ departmentId: afterDepartmentId,
333
+ departmentName: requestComplete.department && requestComplete.department.name
334
+ } : undefined
328
335
  );
329
336
 
330
337
  return requestComplete;
@@ -379,10 +386,18 @@ class RequestService {
379
386
  .execPopulate();
380
387
 
381
388
 
389
+ const departmentChange = beforeDepartmentId !== afterDepartmentId ? {
390
+ previousDepartmentId: beforeDepartmentId,
391
+ departmentId: afterDepartmentId,
392
+ departmentName: requestComplete.department && requestComplete.department.name
393
+ } : undefined;
394
+
382
395
  this.emitParticipantsEvents(
383
396
  request,
384
397
  requestComplete,
385
- beforeParticipants
398
+ beforeParticipants,
399
+ options,
400
+ departmentChange
386
401
  );
387
402
 
388
403
  requestEvent.emit("request.department.update", requestComplete);
@@ -396,9 +411,14 @@ class RequestService {
396
411
  }
397
412
 
398
413
 
399
- reroute(request_id, id_project, nobot) {
414
+ reroute(request_id, id_project, nobot, options) {
400
415
  var that = this;
401
416
  var startDate = new Date();
417
+ const assignmentOptions = options || {
418
+ actor: assignmentContextUtil.systemActor(),
419
+ source: 'queue',
420
+ assignmentType: 'auto'
421
+ };
402
422
  return new Promise(function (resolve, reject) {
403
423
  // winston.debug("request_id", request_id);
404
424
  // winston.debug("newstatus", newstatus);
@@ -432,7 +452,7 @@ class RequestService {
432
452
  }
433
453
 
434
454
 
435
- return that.route(request_id, request.department.toString(), id_project, nobot).then(function (routedRequest) {
455
+ return that.route(request_id, request.department.toString(), id_project, nobot, undefined, assignmentOptions).then(function (routedRequest) {
436
456
 
437
457
  var endDate = new Date();
438
458
  winston.verbose("Performance Request reroute in millis: " + endDate - startDate);
@@ -1528,10 +1548,11 @@ class RequestService {
1528
1548
 
1529
1549
 
1530
1550
 
1531
- setParticipantsByRequestId(request_id, id_project, newparticipants) {
1551
+ setParticipantsByRequestId(request_id, id_project, newparticipants, options) {
1532
1552
 
1533
1553
  //TODO validate participants
1534
1554
  // validate if array of string newparticipants
1555
+ var that = this;
1535
1556
  return new Promise(function (resolve, reject) {
1536
1557
 
1537
1558
  var isArray = Array.isArray(newparticipants);
@@ -1677,6 +1698,14 @@ class RequestService {
1677
1698
  request: requestComplete
1678
1699
  });
1679
1700
 
1701
+ that.emitAssignedEvent(requestComplete, {
1702
+ assignmentType: options && options.assignmentType,
1703
+ actor: options && options.actor,
1704
+ source: options && options.source,
1705
+ addedParticipants: addedParticipants,
1706
+ removedParticipants: removedParticipants
1707
+ });
1708
+
1680
1709
  // TODO allora neanche qui participatingAgent è ok?
1681
1710
  return resolve(requestComplete);
1682
1711
  });
@@ -1688,12 +1717,12 @@ class RequestService {
1688
1717
  });
1689
1718
  }
1690
1719
 
1691
- addParticipantByRequestId(request_id, id_project, member) {
1720
+ addParticipantByRequestId(request_id, id_project, member, options) {
1692
1721
  winston.debug("request_id: " + request_id);
1693
1722
  winston.debug("id_project: " + id_project);
1694
1723
  winston.debug("addParticipantByRequestId member: " + member);
1695
1724
 
1696
-
1725
+ var that = this;
1697
1726
 
1698
1727
  //TODO control if member is a valid project_user of the project
1699
1728
  // validate member is string
@@ -1776,6 +1805,14 @@ class RequestService {
1776
1805
  requestEvent.emit("request.updated", { comment: "PARTICIPANT_ADD", request: requestComplete, patch: { member: member } });
1777
1806
  requestEvent.emit('request.participants.join', { member: member, request: requestComplete });
1778
1807
 
1808
+ that.emitAssignedEvent(requestComplete, {
1809
+ assignmentType: options && options.assignmentType,
1810
+ actor: options && options.actor,
1811
+ source: options && options.source,
1812
+ addedParticipants: [member],
1813
+ removedParticipants: []
1814
+ });
1815
+
1779
1816
  return resolve(requestComplete);
1780
1817
  });
1781
1818
  });
@@ -1797,7 +1834,7 @@ class RequestService {
1797
1834
  });
1798
1835
  }
1799
1836
 
1800
- removeParticipantByRequestId(request_id, id_project, member) {
1837
+ removeParticipantByRequestId(request_id, id_project, member, options) {
1801
1838
  winston.debug("request_id", request_id);
1802
1839
  winston.debug("id_project", id_project);
1803
1840
  winston.debug("member", member);
@@ -1923,7 +1960,13 @@ class RequestService {
1923
1960
  requestEvent.emit('request.update', requestComplete);
1924
1961
  requestEvent.emit("request.update.comment", { comment: "PARTICIPANT_REMOVE", request: requestComplete });//Deprecated
1925
1962
  requestEvent.emit("request.updated", { comment: "PARTICIPANT_REMOVE", request: requestComplete, patch: { member: member } });
1926
- requestEvent.emit('request.participants.leave', { member: member, request: requestComplete });
1963
+ requestEvent.emit('request.participants.leave', {
1964
+ member: member,
1965
+ request: requestComplete,
1966
+ actor: options && options.actor,
1967
+ source: options && options.source,
1968
+ trackLeave: options && options.trackLeave
1969
+ });
1927
1970
 
1928
1971
 
1929
1972
  return resolve(requestComplete);
@@ -2487,7 +2530,8 @@ class RequestService {
2487
2530
  })
2488
2531
  }
2489
2532
 
2490
- emitParticipantsEvents(beforeRequest, requestComplete, oldParticipants) {
2533
+ emitParticipantsEvents(beforeRequest, requestComplete, oldParticipants, options, departmentChange) {
2534
+ const that = this;
2491
2535
  const newParticipants = requestComplete.participants;
2492
2536
 
2493
2537
  const removedParticipants = oldParticipants.filter(
@@ -2510,6 +2554,110 @@ class RequestService {
2510
2554
  addedParticipants,
2511
2555
  request: requestComplete
2512
2556
  });
2557
+
2558
+ that.emitAssignedEvent(requestComplete, {
2559
+ assignmentType: options && options.assignmentType,
2560
+ actor: options && options.actor,
2561
+ source: options && options.source,
2562
+ addedParticipants,
2563
+ removedParticipants,
2564
+ departmentChange
2565
+ });
2566
+ }
2567
+
2568
+ emitAssignedEvent(requestComplete, context) {
2569
+ const {
2570
+ assignmentType,
2571
+ actor,
2572
+ source,
2573
+ addedParticipants = [],
2574
+ removedParticipants = [],
2575
+ departmentChange
2576
+ } = context || {};
2577
+
2578
+ const humanAdded = assignmentContextUtil.filterHumanParticipants(addedParticipants);
2579
+ const humanRemoved = assignmentContextUtil.filterHumanParticipants(removedParticipants);
2580
+ const botAdded = assignmentContextUtil.filterBotParticipants(addedParticipants);
2581
+ const resolvedActor = actor || assignmentContextUtil.systemActor();
2582
+ const resolvedSource = source || 'system';
2583
+
2584
+ if (
2585
+ assignmentType === 'manual_reassign_department' &&
2586
+ departmentChange &&
2587
+ departmentChange.departmentId &&
2588
+ String(departmentChange.departmentId) !== String(departmentChange.previousDepartmentId || '')
2589
+ ) {
2590
+ requestEvent.emit('request.assigned', {
2591
+ request: requestComplete,
2592
+ assigneeId: String(departmentChange.departmentId),
2593
+ assigneeName: departmentChange.departmentName || assignmentContextUtil.resolveDepartmentName(requestComplete),
2594
+ assigneeType: 'department',
2595
+ assignmentType: 'manual_reassign_department',
2596
+ actor: resolvedActor,
2597
+ source: resolvedSource,
2598
+ previousAssigneeId: humanRemoved.length > 0 ? String(humanRemoved[0]) : null,
2599
+ removedParticipants: humanRemoved
2600
+ });
2601
+ return;
2602
+ }
2603
+
2604
+ if (assignmentType === 'manual_reassign_bot' && botAdded.length > 0) {
2605
+ const botId = assignmentContextUtil.botIdFromParticipant(botAdded[0]);
2606
+ requestEvent.emit('request.assigned', {
2607
+ request: requestComplete,
2608
+ assigneeId: botId,
2609
+ assigneeName: assignmentContextUtil.resolveBotName(requestComplete, botId),
2610
+ assigneeType: 'bot',
2611
+ assignmentType: 'manual_reassign_bot',
2612
+ actor: resolvedActor,
2613
+ source: resolvedSource,
2614
+ previousAssigneeId: humanRemoved.length > 0 ? String(humanRemoved[0]) : null,
2615
+ removedParticipants: humanRemoved
2616
+ });
2617
+ return;
2618
+ }
2619
+
2620
+ if (assignmentType === 'unassign' || (humanAdded.length === 0 && humanRemoved.length > 0)) {
2621
+ humanRemoved.forEach((assigneeId) => {
2622
+ requestEvent.emit('request.assigned', {
2623
+ request: requestComplete,
2624
+ assigneeId: String(assigneeId),
2625
+ assignmentType: 'unassign',
2626
+ actor: resolvedActor,
2627
+ source: resolvedSource,
2628
+ removedParticipants: humanRemoved,
2629
+ previousAssigneeId: String(assigneeId)
2630
+ });
2631
+ });
2632
+ return;
2633
+ }
2634
+
2635
+ if (humanAdded.length === 0) {
2636
+ return;
2637
+ }
2638
+
2639
+ const resolvedType = assignmentType || assignmentContextUtil.deriveAssignmentType({
2640
+ actor: resolvedActor,
2641
+ assigneeIds: humanAdded,
2642
+ isUnassign: false
2643
+ });
2644
+
2645
+ if (!resolvedType) {
2646
+ return;
2647
+ }
2648
+
2649
+ humanAdded.forEach((assigneeId) => {
2650
+ requestEvent.emit('request.assigned', {
2651
+ request: requestComplete,
2652
+ assigneeId: String(assigneeId),
2653
+ assigneeType: 'user',
2654
+ assignmentType: resolvedType,
2655
+ actor: resolvedActor,
2656
+ source: resolvedSource,
2657
+ removedParticipants: humanRemoved,
2658
+ previousAssigneeId: humanRemoved.length > 0 ? String(humanRemoved[0]) : null
2659
+ });
2660
+ });
2513
2661
  }
2514
2662
 
2515
2663
 
@@ -1217,6 +1217,7 @@ describe('FaqKBRoute', () => {
1217
1217
  if (err) { console.error("err: ", err); }
1218
1218
  if (log) { console.log("res.body", res.body); }
1219
1219
 
1220
+ console.log("chatbot trashed: ", res.body);
1220
1221
  res.should.have.status(200);
1221
1222
  res.body.should.be.a('object');
1222
1223
  expect(res.body.trashed).to.equal(true);
package/test/kbRoute.js CHANGED
@@ -9,6 +9,7 @@ process.env.PINECONE_INDEX_HYBRID = "test-index-hybrid";
9
9
  process.env.PINECONE_TYPE_HYBRID = "serverless";
10
10
  process.env.ADMIN_EMAIL = "admin@tiledesk.com";
11
11
  process.env.KB_ENDPOINT_TRAIN = "http://kb-train.test";
12
+ process.env.ACTIVITY_HISTORY_ENABLED = true;
12
13
 
13
14
  var userService = require('../services/userService');
14
15
  var projectService = require('../services/projectService');
@@ -792,6 +793,64 @@ describe('KbRoute', () => {
792
793
  });
793
794
  }).timeout(10000)
794
795
 
796
+ it('delete-content', (done) => {
797
+
798
+ var email = "test-signup-" + Date.now() + "@email.com";
799
+ var pwd = "pwd";
800
+
801
+ userService.signup(email, pwd, "Test Firstname", "Test lastname").then(function (savedUser) {
802
+ projectService.create("test-faqkb-create", savedUser._id).then(function (savedProject) {
803
+
804
+ chai.request(server)
805
+ .get('/' + savedProject._id + '/kb/namespace/all')
806
+ .auth(email, pwd)
807
+ .end((err, res) => {
808
+ if (err) { console.error("err: ", err); }
809
+ if (log) { console.log("get namespaces res.body: ", res.body); }
810
+
811
+ res.should.have.status(200);
812
+
813
+ let namespace_id = res.body[0].id;
814
+
815
+ let kb = {
816
+ name: "example_text_delete",
817
+ type: "text",
818
+ source: "example_text_delete",
819
+ content: "Example text",
820
+ namespace: namespace_id
821
+ }
822
+
823
+ chai.request(server)
824
+ .post('/' + savedProject._id + '/kb')
825
+ .auth(email, pwd)
826
+ .send(kb)
827
+ .end((err, res) => {
828
+ if (err) { console.error("err: ", err); }
829
+ if (log) { console.log("create kb res.body: ", res.body); }
830
+
831
+ res.should.have.status(200);
832
+
833
+ let kb_id = res.body.data.value._id;
834
+
835
+ chai.request(server)
836
+ .delete('/' + savedProject._id + '/kb/' + kb_id)
837
+ .auth(email, pwd)
838
+ .end((err, res) => {
839
+ if (err) { console.error("err: ", err); }
840
+ if (log) { console.log("delete kb res.body: ", res.body); }
841
+
842
+ res.should.have.status(200);
843
+ expect(res.body.success).to.equal(true);
844
+ expect(res.body.message).to.equal("Content deleted successfully");
845
+
846
+ done();
847
+ })
848
+ })
849
+ })
850
+ })
851
+ })
852
+ })
853
+
795
854
  it('get-content-chunks', (done) => {
796
855
 
797
856
  var email = "test-signup-" + Date.now() + "@email.com";
@@ -0,0 +1,167 @@
1
+ 'use strict';
2
+
3
+ const User = require('../models/user');
4
+ const winston = require('../config/winston');
5
+ const projectUserUpdateContextUtil = require('./projectUserUpdateContextUtil');
6
+
7
+ function actorFromReq(req) {
8
+ if (!req || !req.user) {
9
+ return { type: 'system', id: 'system', name: 'System' };
10
+ }
11
+ return projectUserUpdateContextUtil.actorFromPrincipal(req.user);
12
+ }
13
+
14
+ function actorFromUserId(userId) {
15
+ if (!userId) {
16
+ return { type: 'system', id: 'system', name: 'System' };
17
+ }
18
+ const id = String(userId);
19
+ return { type: 'user', id: id, name: id };
20
+ }
21
+
22
+ function resolveId(value) {
23
+ if (!value) {
24
+ return null;
25
+ }
26
+ if (value._id) {
27
+ return String(value._id);
28
+ }
29
+ return String(value);
30
+ }
31
+
32
+ function resolveUserFromParticipatingAgents(agents, userId) {
33
+ if (!Array.isArray(agents) || !userId) {
34
+ return null;
35
+ }
36
+
37
+ for (const agent of agents) {
38
+ const id = agent._id || agent.id;
39
+ if (id && String(id) === String(userId)) {
40
+ return agent;
41
+ }
42
+ }
43
+
44
+ return null;
45
+ }
46
+
47
+ function resolveUserFromSnapshotAgents(agents, userId) {
48
+ if (!Array.isArray(agents) || !userId) {
49
+ return null;
50
+ }
51
+
52
+ for (const projectUser of agents) {
53
+ const user = projectUser.id_user || projectUser;
54
+ const id = (user && (user._id || user.id)) || projectUser._id;
55
+ if (id && String(id) === String(userId)) {
56
+ return user;
57
+ }
58
+ }
59
+
60
+ return null;
61
+ }
62
+
63
+ function isSystemClosedBy(closedBy) {
64
+ if (!closedBy) {
65
+ return true;
66
+ }
67
+ const value = String(closedBy).toLowerCase();
68
+ return value === 'system' || value === '_trigger';
69
+ }
70
+
71
+ function actorFromClosedBy(request) {
72
+ if (!request) {
73
+ return { type: 'system', id: 'system', name: 'System' };
74
+ }
75
+
76
+ const closedBy = request.closed_by;
77
+ if (isSystemClosedBy(closedBy)) {
78
+ return { type: 'system', id: 'system', name: 'System' };
79
+ }
80
+
81
+ const userId = String(closedBy);
82
+ let user = resolveUserFromParticipatingAgents(request.participatingAgents, userId);
83
+ if (!user && request.snapshot) {
84
+ user = resolveUserFromSnapshotAgents(request.snapshot.agents, userId);
85
+ }
86
+
87
+ const name = (user && projectUserUpdateContextUtil.userDisplayName(user)) ||
88
+ request.closed_by_name ||
89
+ userId;
90
+
91
+ return {
92
+ type: 'user',
93
+ id: userId,
94
+ name: name
95
+ };
96
+ }
97
+
98
+ function actorFromRequestCreate(request) {
99
+ const requesterId = request && request.requester_id;
100
+ const lead = request && request.lead;
101
+ const leadId = lead && (lead._id || lead.id);
102
+ const leadFullname = lead && (lead.fullname || lead.fullName);
103
+ const participantsBots = (request && request.participantsBots) || [];
104
+ const participatingBotIds = (request && request.participatingBots || []).map(function (bot) {
105
+ return String((bot && (bot._id || bot.id)) || bot);
106
+ });
107
+
108
+ winston.info('ActivityArchiver REQUEST_CREATE actor resolution', {
109
+ request_id: request && request.request_id,
110
+ request_mongo_id: request && request._id && String(request._id),
111
+ requester_id: requesterId != null ? String(requesterId) : null,
112
+ requester_name: request && request.requester_name,
113
+ createdBy: request && request.createdBy,
114
+ lead_id: leadId != null ? String(leadId) : null,
115
+ lead_fullname: leadFullname,
116
+ participantsBots: participantsBots,
117
+ participatingBotIds: participatingBotIds,
118
+ hasBot: request && request.hasBot,
119
+ note: 'REQUEST_CREATE actor is always type=user with id=requester_id (lead virtual). JWT/token is not used here.'
120
+ });
121
+
122
+ const actor = {
123
+ type: 'user',
124
+ id: requesterId != null ? String(requesterId) : undefined,
125
+ name: (request && request.requester_name) || leadFullname || undefined
126
+ };
127
+
128
+ if (participantsBots.length > 0 || participatingBotIds.length > 0) {
129
+ winston.info('ActivityArchiver REQUEST_CREATE bot participants present (not used as actor)', {
130
+ request_id: request && request.request_id,
131
+ actor: actor,
132
+ participantsBots: participantsBots,
133
+ participatingBotIds: participatingBotIds
134
+ });
135
+ }
136
+
137
+ return actor;
138
+ }
139
+
140
+ async function resolveActorFromClosedBy(request) {
141
+ const actor = actorFromClosedBy(request);
142
+
143
+ if (actor.type !== 'user' || actor.name !== actor.id) {
144
+ return actor;
145
+ }
146
+
147
+ try {
148
+ const user = await User.findById(actor.id).select('firstname lastname email').lean().exec();
149
+ const displayName = user && projectUserUpdateContextUtil.userDisplayName(user);
150
+ if (displayName) {
151
+ return Object.assign({}, actor, { name: displayName });
152
+ }
153
+ } catch (err) {
154
+ // keep id fallback
155
+ }
156
+
157
+ return actor;
158
+ }
159
+
160
+ module.exports = {
161
+ actorFromReq,
162
+ actorFromUserId,
163
+ actorFromRequestCreate,
164
+ actorFromClosedBy,
165
+ resolveActorFromClosedBy,
166
+ resolveId
167
+ };