@tiledesk/tiledesk-server 2.3.6 → 2.3.7-1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (126) hide show
  1. package/.github/workflows/docker-community-worker-push-latest.yml +23 -0
  2. package/.github/workflows/docker-image-tag-worker-community-tag-push.yml +22 -0
  3. package/CHANGELOG.md +361 -3
  4. package/Dockerfile-jobs +31 -0
  5. package/app.js +62 -69
  6. package/channels/chat21/chat21Handler.js +37 -6
  7. package/channels/chat21/chat21WebHook.js +62 -34
  8. package/channels/chat21/package-lock.json +663 -706
  9. package/channels/chat21/package.json +2 -2
  10. package/config/labels/widget.json +337 -136
  11. package/deploy.sh +2 -0
  12. package/event/messageEvent.js +110 -9
  13. package/jobs.js +80 -0
  14. package/jobsManager.js +47 -0
  15. package/middleware/has-role.js +10 -3
  16. package/middleware/ipFilter.js +220 -0
  17. package/middleware/passport.js +8 -2
  18. package/models/department.js +1 -1
  19. package/models/faq.js +77 -25
  20. package/models/faq_kb.js +19 -0
  21. package/models/message.js +10 -8
  22. package/models/project.js +10 -0
  23. package/models/project_user.js +10 -0
  24. package/models/request.js +12 -1
  25. package/package.json +12 -11
  26. package/pubmodules/activities/activityArchiver.js +216 -90
  27. package/pubmodules/activities/routes/activity.js +1 -1
  28. package/pubmodules/apps/index.js +8 -0
  29. package/pubmodules/apps/listener.js +27 -0
  30. package/pubmodules/cache/index.js +2 -0
  31. package/pubmodules/cache/mongoose-cachegoose-fn.js +630 -0
  32. package/pubmodules/canned/cannedResponse.js +4 -0
  33. package/pubmodules/canned/cannedResponseRoute.js +10 -5
  34. package/pubmodules/dialogflow/index.js +10 -0
  35. package/pubmodules/dialogflow/listener.js +66 -0
  36. package/pubmodules/emailNotification/requestNotification.js +58 -28
  37. package/pubmodules/events/eventRoute.js +49 -24
  38. package/pubmodules/messageTransformer/messageHandlebarsTransformerInterceptor.js +6 -1
  39. package/pubmodules/messageTransformer/messageTransformerInterceptor.js +10 -4
  40. package/pubmodules/pubModulesManager.js +173 -7
  41. package/pubmodules/queue/index.js +4 -0
  42. package/pubmodules/queue/reconnect.js +331 -0
  43. package/pubmodules/queue/reconnectFanout.js +256 -0
  44. package/pubmodules/rasa/listener.js +5 -5
  45. package/pubmodules/routing-queue/index.js +3 -0
  46. package/pubmodules/routing-queue/listener.js +328 -0
  47. package/pubmodules/rules/conciergeBot.js +2 -2
  48. package/pubmodules/scheduler/tasks/closeAgentUnresponsiveRequestTask.js +6 -1
  49. package/pubmodules/scheduler/tasks/closeBotUnresponsiveRequestTask.js +7 -1
  50. package/pubmodules/tilebot/index.js +11 -0
  51. package/pubmodules/tilebot/listener.js +85 -0
  52. package/pubmodules/trigger/rulesTrigger.js +137 -14
  53. package/pubmodules/trigger/start.js +5 -1
  54. package/pubmodules/whatsapp/index.js +7 -0
  55. package/pubmodules/whatsapp/listener.js +32 -0
  56. package/routes/auth.js +7 -2
  57. package/routes/campaigns.js +3 -3
  58. package/routes/department.js +3 -2
  59. package/routes/email.js +32 -2
  60. package/routes/faq.js +37 -2
  61. package/routes/faq_kb.js +496 -133
  62. package/routes/faqpub.js +5 -0
  63. package/routes/lead.js +56 -0
  64. package/routes/message.js +196 -14
  65. package/routes/messagesRoot.js +39 -0
  66. package/routes/project.js +76 -4
  67. package/routes/project_user.js +11 -1
  68. package/routes/project_user_test.js +19 -0
  69. package/routes/request.js +134 -30
  70. package/routes/troubleshooting.js +12 -0
  71. package/routes/users-util.js +39 -0
  72. package/routes/users.js +1 -1
  73. package/routes/widget.js +64 -2
  74. package/services/BotSubscriptionNotifier.js +5 -0
  75. package/services/banUserNotifier.js +86 -0
  76. package/services/cacheEnabler.js +56 -0
  77. package/services/chatbotService.js +101 -0
  78. package/services/departmentService.js +25 -3
  79. package/services/emailService.js +170 -28
  80. package/services/faqBotHandler.js +2 -3
  81. package/services/faqService.js +28 -3
  82. package/services/geoService.js +36 -6
  83. package/services/labelService.js +1 -1
  84. package/services/leadService.js +3 -2
  85. package/services/messageService.js +4 -2
  86. package/services/modulesManager.js +23 -76
  87. package/services/operatingHoursService.js +9 -4
  88. package/services/requestService.js +75 -39
  89. package/services/subscriptionNotifier.js +9 -4
  90. package/services/trainingService.js +106 -0
  91. package/template/email/assignedEmailMessage.html +21 -11
  92. package/template/email/assignedRequest.html +21 -11
  93. package/template/email/beenInvitedExistingUser.html +16 -6
  94. package/template/email/beenInvitedNewUser.html +16 -6
  95. package/template/email/emailDirect.html +130 -0
  96. package/template/email/newMessage.html +18 -8
  97. package/template/email/newMessageFollower.html +22 -12
  98. package/template/email/passwordChanged.html +15 -5
  99. package/template/email/pooledEmailMessage.html +21 -11
  100. package/template/email/pooledRequest.html +20 -10
  101. package/template/email/resetPassword.html +15 -5
  102. package/template/email/sendTranscript.html +7 -4
  103. package/template/email/ticket.html +17 -7
  104. package/template/email/verify.html +15 -5
  105. package/test/cannedRoute.js +157 -0
  106. package/test/chatbot-mock.js +127 -0
  107. package/test/example-json-intents.txt +1 -0
  108. package/test/example-json.txt +1 -0
  109. package/test/example.json +1 -0
  110. package/test/faqRoute.js +353 -208
  111. package/test/faqkbRoute.js +669 -64
  112. package/test/imageRoute.js +1 -1
  113. package/test/messageRoute.js +387 -5
  114. package/test/requestRoute.js +6 -6
  115. package/test/requestService.js +55 -4
  116. package/test-int/cache-project.js +90 -0
  117. package/test-int/cache-project_user.js +88 -0
  118. package/utils/UIDGenerator.js +20 -0
  119. package/utils/cacheUtil.js +2 -2
  120. package/utils/orgUtil.js +3 -3
  121. package/utils/promiseUtil.js +31 -0
  122. package/utils/recipientEmailUtil.js +66 -0
  123. package/utils/sendEmailUtil.js +34 -0
  124. package/utils/sendMessageUtil.js +1 -1
  125. package/utils/stringUtil.js +12 -0
  126. package/websocket/webSocketServer.js +33 -10
@@ -0,0 +1,256 @@
1
+ var amqp = require('amqplib/callback_api');
2
+ var winston = require('../../config/winston');
3
+ const requestEvent = require('../../event/requestEvent');
4
+ const messageEvent = require('../../event/messageEvent');
5
+ const authEvent = require('../../event/authEvent');
6
+ // https://elements.heroku.com/addons/cloudamqp
7
+ // https://gist.github.com/carlhoerberg/006b01ac17a0a94859ba#file-reconnect-js
8
+ // http://www.rabbitmq.com/tutorials/tutorial-one-javascript.html
9
+
10
+ // if the connection is closed or fails to be established at all, we will reconnect
11
+ var amqpConn = null;
12
+ var url = process.env.CLOUDAMQP_URL + "?heartbeat=60" || "amqp://localhost";
13
+ // attento devi aggiornare configMap di PRE E PROD
14
+ // var url = process.env.AMQP_URL + "?heartbeat=60" || "amqp://localhost";
15
+
16
+ // MOD0
17
+ var exchange = 'ws';
18
+
19
+ function start() {
20
+ amqp.connect(url, function(err, conn) {
21
+ if (err) {
22
+ winston.error("[AMQP Fanout]", err);
23
+ return setTimeout(start, 1000);
24
+ }
25
+ conn.on("error", function(err) {
26
+ if (err.message !== "Connection closing") {
27
+ winston.error("[AMQP Fanout] conn error", err);
28
+ }
29
+ });
30
+ conn.on("close", function() {
31
+ winston.error("[AMQP Fanout] reconnecting");
32
+ return setTimeout(start, 1000);
33
+ });
34
+
35
+ winston.info("[AMQP Fanout] connected");
36
+ amqpConn = conn;
37
+
38
+ whenConnected();
39
+ });
40
+ }
41
+
42
+ function whenConnected() {
43
+ startPublisher();
44
+ startWorker();
45
+ }
46
+
47
+ var pubChannel = null;
48
+ var offlinePubQueue = [];
49
+ function startPublisher() {
50
+ amqpConn.createConfirmChannel(function(err, ch) {
51
+ if (closeOnErr(err)) return;
52
+ ch.on("error", function(err) {
53
+ winston.error("[AMQP Fanout] channel error", err);
54
+ });
55
+ ch.on("close", function() {
56
+ winston.info("[AMQP Fanout] channel closed");
57
+ });
58
+
59
+ pubChannel = ch;
60
+ while (true) {
61
+ var m = offlinePubQueue.shift();
62
+ if (!m) break;
63
+ publish(m[0], m[1], m[2]);
64
+ }
65
+ });
66
+ }
67
+
68
+ // method to publish a message, will queue messages internally if the connection is down and resend later
69
+ function publish(exchange, routingKey, content) {
70
+ try {
71
+
72
+ // MOD2
73
+ // pubChannel.publish('logs', '', Buffer.from('Hello World!'));
74
+ pubChannel.publish(exchange, routingKey, content, { },
75
+ // pubChannel.publish(exchange, routingKey, content, { persistent: true },
76
+ function(err, ok) {
77
+ if (err) {
78
+ winston.error("[AMQP Fanout] publish", err);
79
+ offlinePubQueue.push([exchange, routingKey, content]);
80
+ pubChannel.connection.close();
81
+ }
82
+ });
83
+ } catch (e) {
84
+ winston.error("[AMQP Fanout] publish", e);
85
+ offlinePubQueue.push([exchange, routingKey, content]);
86
+ }
87
+ }
88
+
89
+ // A worker that acks messages only if processed succesfully
90
+ // var channel;
91
+ function startWorker() {
92
+ amqpConn.createChannel(function(err, ch) {
93
+ if (closeOnErr(err)) return;
94
+ ch.on("error", function(err) {
95
+ winston.error("[AMQP Fanout] channel error", err);
96
+ });
97
+ ch.on("close", function() {
98
+ winston.info("[AMQP Fanout] channel closed");
99
+ });
100
+ ch.prefetch(10);//leggila da env
101
+
102
+ // ch.assertExchange(exchange, 'topic', {
103
+ // durable: true
104
+ // });
105
+
106
+ // MOD1
107
+ ch.assertExchange(exchange, 'fanout', {durable: false});
108
+
109
+ //MOD3
110
+ ch.assertQueue('', {exclusive: true}, function(err, _ok) {
111
+ // ch.assertQueue("jobs", { durable: true }, function(err, _ok) {
112
+
113
+ if (closeOnErr(err)) return;
114
+
115
+ //MOD4
116
+ ch.bindQueue(_ok.queue, exchange, '', {}, function(err3, oka) {
117
+ winston.info("Queue Fanout bind: "+_ok.queue+ " err: "+err3);
118
+ winston.info("Data Queue Fanout", oka)
119
+ });
120
+
121
+ // ch.bindQueue(_ok.queue, exchange, "request_create", {}, function(err3, oka) {
122
+ // console.log("queue bind: "+_ok.queue+ " err: "+err3+ " key: request_create");
123
+ // console.log("data queue", oka)
124
+ // });
125
+ // ch.bindQueue(_ok.queue, exchange, "request_update", {}, function(err3, oka) {
126
+ // console.log("queue bind: "+_ok.queue+ " err: "+err3+ " key: request_update");
127
+ // console.log("data queue", oka)
128
+ // });
129
+ // ch.bindQueue(_ok.queue, exchange, "message_create", {}, function(err3, oka) {
130
+ // console.log("queue bind: "+_ok.queue+ " err: "+err3+ " key: message_create");
131
+ // console.log("data queue", oka)
132
+ // });
133
+ // ch.bindQueue(_ok.queue, exchange, "project_user_update", {}, function(err3, oka) {
134
+ // console.log("queue bind: "+_ok.queue+ " err: "+err3+ " key: project_user_update");
135
+ // console.log("data queue", oka)
136
+ // });
137
+ ch.consume(_ok.queue, processMsg, { noAck: false });
138
+ winston.info("Worker Fanout is started");
139
+ });
140
+
141
+
142
+ function processMsg(msg) {
143
+ work(msg, function(ok) {
144
+ try {
145
+ if (ok)
146
+ ch.ack(msg);
147
+ else
148
+ ch.reject(msg, true);
149
+ } catch (e) {
150
+ closeOnErr(e);
151
+ }
152
+ });
153
+ }
154
+ });
155
+ }
156
+
157
+ function work(msg, cb) {
158
+ const message_string = msg.content.toString();
159
+ const topic = msg.fields.routingKey //.replace(/[.]/g, '/');
160
+
161
+ winston.debug("Got Fanout msg topic:" + topic);
162
+
163
+ winston.debug("Got Fanout msg:"+ message_string + " topic:" + topic);
164
+
165
+ if (topic === 'request_create') {
166
+ winston.debug("reconnectfanout here topic:" + topic);
167
+ winston.debug("reconnect request.update")
168
+ requestEvent.emit('request.create.queue.pubsub', JSON.parse(message_string));
169
+ }
170
+ if (topic === 'request_update') {
171
+ winston.debug("reconnectfanout here topic:" + topic);
172
+ requestEvent.emit('request.update.queue.pubsub', JSON.parse(message_string));
173
+ }
174
+ if (topic === 'message_create') {
175
+ winston.debug("reconnectfanout here topic:" + topic);
176
+ messageEvent.emit('message.create.queue.pubsub', JSON.parse(message_string));
177
+ }
178
+ if (topic === 'project_user_update') {
179
+ winston.debug("reconnectfanout here topic:" + topic);
180
+ authEvent.emit('project_user.update.queue.pubsub', JSON.parse(message_string));
181
+ }
182
+ cb(true);
183
+ // WebSocket.cb(true);
184
+ // requestEvent.on(msg.KEYYYYYYY+'.ws', msg.content);
185
+ }
186
+
187
+
188
+ function closeOnErr(err) {
189
+ if (!err) return false;
190
+ winston.error("[AMQP Fanout] error", err);
191
+ amqpConn.close();
192
+ return true;
193
+ }
194
+
195
+ // setInterval(function() {
196
+ // var d = new Date();
197
+ // publish(exchange, "request_create", Buffer.from("work work work: "+d));
198
+ // }, 10000);
199
+
200
+
201
+
202
+ // http://www.squaremobius.net/amqp.node/channel_api.html
203
+ // https://docs.parseplatform.org/parse-server/guide/#scalability
204
+
205
+
206
+
207
+ function listen() {
208
+
209
+ requestEvent.on('request.create', function(request) {
210
+ setImmediate(() => {
211
+ publish(exchange, "request_create", Buffer.from(JSON.stringify(request)));
212
+ });
213
+ });
214
+
215
+ requestEvent.on('request.update', function(request) {
216
+ setImmediate(() => {
217
+ publish(exchange, "request_update", Buffer.from(JSON.stringify(request)));
218
+ });
219
+ });
220
+
221
+
222
+ messageEvent.on('message.create', function(message) {
223
+ setImmediate(() => {
224
+ publish(exchange, "message_create", Buffer.from(JSON.stringify(message)));
225
+ });
226
+ });
227
+
228
+ authEvent.on('project_user.update',function(data) {
229
+ setImmediate(() => {
230
+ let user = undefined;
231
+ let body = undefined;
232
+ if (data.req ) {
233
+ if (data.req.user) { //i think is null from chat21webhook
234
+ user = data.req.user;
235
+ }
236
+ if (data.req.body) {
237
+ body = data.req.body;
238
+ }
239
+ }
240
+ var dat = {updatedProject_userPopulated: data.updatedProject_userPopulated, req: {user: user, body: body}}; //remove request
241
+ winston.debug("dat",dat);
242
+
243
+ publish(exchange, "project_user_update", Buffer.from(JSON.stringify(dat)));
244
+ });
245
+ });
246
+ }
247
+
248
+ if (process.env.QUEUE_ENABLED === "true") {
249
+ requestEvent.queueEnabled = true;
250
+ messageEvent.queueEnabled = true;
251
+ authEvent.queueEnabled = true;
252
+ listen();
253
+ start();
254
+ winston.info("Queue Fanout enabled. endpint: " + url );
255
+ }
256
+
@@ -6,7 +6,7 @@ var configGlobal = require('../../config/global');
6
6
 
7
7
  var port = process.env.PORT || '3000';
8
8
 
9
- const BOT_RASA_ENDPOINT = "http://localhost:" + port+ "/modules/rasa/rasabot" || process.env.BOT_RASA_ENDPOINT;
9
+ const BOT_RASA_ENDPOINT = process.env.BOT_RASA_ENDPOINT || "http://localhost:" + port+ "/modules/rasa/rasabot";
10
10
  winston.debug("BOT_RASA_ENDPOINT: " + BOT_RASA_ENDPOINT);
11
11
 
12
12
  // if (BOT_RASA_ENDPOINT) {
@@ -23,7 +23,7 @@ class Listener {
23
23
  listen(config) {
24
24
 
25
25
  winston.info('Rasa Listener listen');
26
- winston.debug("config databaseUri: " + config.databaseUri);
26
+ winston.debug("rasa config databaseUri: " + config.databaseUri);
27
27
 
28
28
 
29
29
  var that = this;
@@ -34,7 +34,7 @@ class Listener {
34
34
  KVBASE_COLLECTION : process.env.KVBASE_COLLECTION,
35
35
  MONGODB_URI: config.databaseUri,
36
36
  API_ENDPOINT: apiUrl,
37
- log: true
37
+ log: process.env.RASABOT_LOG
38
38
  }, () => {
39
39
  winston.info("RASA proxy server successfully started.");
40
40
  });
@@ -44,10 +44,10 @@ class Listener {
44
44
  botEvent.on('faqbot.create', function(bot) {
45
45
  if (BOT_RASA_ENDPOINT) {
46
46
 
47
- winston.info('bot.type:'+bot.type);
47
+ winston.debug('bot.type:'+bot.type);
48
48
  if (bot.type==="rasa") {
49
49
 
50
- winston.info('qui.type:'+bot.type);
50
+ winston.debug('qui.type:'+bot.type);
51
51
 
52
52
 
53
53
  Faq_kb.findByIdAndUpdate(bot.id, {"url":BOT_RASA_ENDPOINT}, { new: true, upsert: true }, function (err, savedFaq_kb) {
@@ -0,0 +1,3 @@
1
+ const listener = require("./listener");
2
+
3
+ module.exports = {listener:listener };
@@ -0,0 +1,328 @@
1
+ const projectEvent = require('../../event/projectEvent');
2
+ const departmentEvent = require('../../event/departmentEvent');
3
+ const authEvent = require('../../event/authEvent');
4
+ const requestEvent = require('../../event/requestEvent');
5
+ var Request = require('../../models/request');
6
+ var Project = require('../../models/project');
7
+ var Project_user = require('../../models/project_user');
8
+ var winston = require('../../config/winston');
9
+
10
+ var ProjectUserUtil = require("../../utils/project_userUtil");
11
+
12
+ // var request = require('retry-request', {
13
+ // request: require('request')
14
+ // });
15
+
16
+ // TODO riabilitare questo
17
+
18
+ // const ROUTE_QUEUE_ENDPOINT = process.env.ROUTE_QUEUE_ENDPOINT;
19
+ // winston.debug("ROUTE_QUEUE_ENDPOINT: " + ROUTE_QUEUE_ENDPOINT);
20
+
21
+ // if (ROUTE_QUEUE_ENDPOINT) {
22
+ // winston.info("Route queue endpoint: " + ROUTE_QUEUE_ENDPOINT);
23
+ // } else {
24
+ // winston.info("Route queue endpoint not configured");
25
+ // }
26
+
27
+
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
+ nextOperator(array, index) {
40
+ // console.log('array: ', array);
41
+ // console.log('index: ' + index);
42
+
43
+ index = index || 0;
44
+
45
+ if (array === undefined || array === null)
46
+ array = [];
47
+ else if (!Array.isArray(array))
48
+ throw new Error('Expecting argument to RoundRound to be an Array');
49
+
50
+ // return function () {
51
+ index++;
52
+ if (index >= array.length) index = 0;
53
+ // console.log('index: ' + index);
54
+ return array[index];
55
+ // };
56
+ }
57
+
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
+
95
+ listen() {
96
+
97
+ if (this.enabled==true) {
98
+ winston.info("Route queue Listener listen");
99
+ } else {
100
+ return winston.info("Route queue Listener disabled");
101
+ }
102
+
103
+ 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
+
156
+ departmentEvent.on('operator.select.base2', async (res) => {
157
+ // departmentEvent.prependListener('operator.select', async (data) => {
158
+
159
+ var operatorsResult = res.result;
160
+ winston.debug('operator.select.base2 res', res);
161
+
162
+
163
+ var disableWebHookCall = res.disableWebHookCall;
164
+ winston.debug("operator.select.base2 disableWebHookCall: "+ disableWebHookCall);
165
+
166
+ if (disableWebHookCall===true) {
167
+ winston.debug("operator.select.base2 disableWebHookCall enabled: "+ disableWebHookCall);
168
+ // return callNextEvent('operator.select', res);
169
+ return res.resolve(operatorsResult);
170
+
171
+ }
172
+
173
+
174
+
175
+
176
+
177
+
178
+
179
+
180
+ var project = operatorsResult.project;
181
+ var max_agent_assigned_chat = undefined;
182
+
183
+
184
+ // console.log("project: ", project);
185
+
186
+ if (project && project.settings && project.settings.chat_limit_on && project.settings.max_agent_assigned_chat) {
187
+ max_agent_assigned_chat = project.settings.max_agent_assigned_chat;
188
+ winston.debug('operator.select max_agent_assigned_chat: '+max_agent_assigned_chat);
189
+
190
+ } else {
191
+ winston.debug("chat_limit_on not defined calling next ");
192
+ return departmentEvent.callNextEvent('operator.select', res);
193
+ }
194
+
195
+
196
+
197
+
198
+ // winston.info('qui', operatorsResult.available_agents.length);
199
+ operatorsResult.available_agents_request = [];
200
+
201
+ if (operatorsResult && operatorsResult.available_agents && operatorsResult.available_agents.length > 0) {
202
+
203
+ // winston.info('qui1');
204
+ // qui1000
205
+ var query = {id_project: operatorsResult.id_project, status: {$lt:1000}};
206
+ // asyncForEach(operatorsResult.available_agents, async (aa) => {
207
+ for (const aa of operatorsResult.available_agents) {
208
+ query.participants = aa.id_user._id.toString();// attento qui
209
+ winston.debug("department operators query:" , query);
210
+
211
+
212
+ // questa cosa nn va bene. nn puoi usare ? number_assigned_requests??
213
+ var count = await Request.countDocuments(query);
214
+ winston.debug("department operators count: "+ count);
215
+ operatorsResult.available_agents_request.push({project_user: aa, openRequetsCount : count});
216
+
217
+ }
218
+
219
+ }
220
+
221
+
222
+
223
+
224
+
225
+
226
+ var available_agents_request = operatorsResult.available_agents_request;
227
+ var available_agents_not_busy = [];
228
+ if (available_agents_request && available_agents_request.length>0) {
229
+ for (const aa of available_agents_request) {
230
+ // console.log("aa.openRequetsCount ", aa.openRequetsCount, " for:", aa.project_user.id_user);
231
+
232
+ var maxAssignedchatForUser = max_agent_assigned_chat;
233
+
234
+ var max_agent_assigned_chat_specific_user = aa.project_user.max_assigned_chat;
235
+ // console.log("max_agent_assigned_chat_specific_user: ", max_agent_assigned_chat_specific_user);
236
+
237
+ if (max_agent_assigned_chat_specific_user && max_agent_assigned_chat_specific_user!=-1 ) {
238
+ maxAssignedchatForUser = max_agent_assigned_chat_specific_user;
239
+ }
240
+
241
+ winston.debug("maxAssignedchatForUser: "+ maxAssignedchatForUser);
242
+
243
+ if (aa.openRequetsCount < maxAssignedchatForUser) {
244
+ winston.debug("adding "+ aa.project_user.id_user+ " with openRequetsCount: "+ aa.openRequetsCount +" and with maxAssignedchatForUser " + maxAssignedchatForUser +" to available_agents_not_busy" );
245
+ available_agents_not_busy.push(aa.project_user);
246
+ }
247
+ }
248
+ } else {
249
+ winston.debug("available_agents_request not defined");
250
+ }
251
+
252
+ winston.debug("available_agents_not_busy", available_agents_not_busy);
253
+
254
+
255
+
256
+ // TODO non riassegnare allo stesso utente usa history oppure lastabandonedby in attributes
257
+ // in project_user sengni il numero di abandoni se uguale a psettng lo metto offline
258
+ winston.debug("res.context",res.context);
259
+
260
+ winston.debug("res.context.request.attributes",res.context.request.attributes);
261
+
262
+ if (res.context && res.context.request && res.context.request &&
263
+ res.context.request.attributes && res.context.request.attributes.abandoned_by_project_users ) { //&& res.context.request.attributes.queue_important==false (vip sla continuo reassign)
264
+
265
+ // var abandoned_by_project_users= {"5ecd44cfa3f5670034109b44":true,"5ecd56a10e7d2d00343203cc":true}
266
+
267
+ winston.debug("res.context.request.attributes.abandoned_by_project_users: ", res.context.request.attributes.abandoned_by_project_users );
268
+
269
+ var abandoned_by_project_usersAsArray = Object.keys(res.context.request.attributes.abandoned_by_project_users);
270
+
271
+ if (abandoned_by_project_usersAsArray.length>0 ) {
272
+ winston.debug("abandoned_by_project_usersAsArray", abandoned_by_project_usersAsArray);
273
+
274
+ var available_agents_not_busy = available_agents_not_busy.filter(projectUser=> !abandoned_by_project_usersAsArray.includes(projectUser._id.toString()))
275
+
276
+ winston.debug("available_agents_not_busy after: ", available_agents_not_busy );
277
+ }
278
+ }
279
+
280
+ // if (res.context && res.context.request && res.context.request &&
281
+ // res.context.request.attributes && res.context.request.attributes.last_abandoned_by ) {
282
+ // winston.debug("res.context.request.attributes.last_abandoned_by: "+res.context.request.attributes.last_abandoned_by );
283
+ // let last_abandoned_by_index = available_agents_not_busy.findIndex(projectUser => projectUser._id.toString() === res.context.request.attributes.last_abandoned_by);
284
+ // winston.debug("last_abandoned_by_index: "+last_abandoned_by_index );
285
+ // if (last_abandoned_by_index>-1) {
286
+ // available_agents_not_busy.splice(last_abandoned_by_index, 1);
287
+ // winston.debug("available_agents_not_busy after", available_agents_not_busy );
288
+ // }
289
+
290
+ // }
291
+
292
+
293
+ var lastOperatorId = operatorsResult.lastOperatorId;
294
+
295
+ let lastOperatorIndex = available_agents_not_busy.findIndex(projectUser => projectUser.id_user.toString() === lastOperatorId);
296
+ winston.debug("lastOperatorIndex: "+ lastOperatorIndex);
297
+ var nextOper = that.nextOperator(available_agents_not_busy, lastOperatorIndex);
298
+ // console.log("nextOper: ", nextOper);
299
+ var nextOperatorId = undefined;
300
+ if (nextOper && nextOper.id_user) {
301
+ nextOperatorId = nextOper.id_user;
302
+ winston.verbose("nextOperatorId: "+ nextOperatorId);
303
+
304
+ operatorsResult.operators = [{id_user: nextOperatorId}];
305
+
306
+ // return resolve(result);
307
+ } else {
308
+ winston.debug("nextOper is not defined");
309
+ operatorsResult.operators = [];
310
+ // return resolve(result);
311
+ }
312
+
313
+
314
+ return departmentEvent.callNextEvent('operator.select', res);
315
+
316
+
317
+
318
+ });
319
+
320
+
321
+ }
322
+
323
+ }
324
+
325
+ var listener = new Listener();
326
+
327
+
328
+ module.exports = listener;
@@ -198,7 +198,7 @@ devi mandare un messaggio welcome tu altrimenti il bot inserito successivamente
198
198
  "Chat closed",
199
199
  request.id_project,
200
200
  'system',
201
- {subtype:"info/support", "updateconversation" : false, messagelabel: {key: "CHAT_CLOSED"}},
201
+ {subtype:"info/support", "updateconversation" : false, messagelabel: {key: "CHAT_CLOSED"}}, // TODO send request.closed_by <- c'è il campo l'ho verificato
202
202
  undefined,
203
203
  request.language
204
204
  );
@@ -228,7 +228,7 @@ devi mandare un messaggio welcome tu altrimenti il bot inserito successivamente
228
228
  request.request_id,
229
229
  "Chat reopened",
230
230
  request.id_project,
231
- 'system',
231
+ 'system', //changed from false to true 6Aug22 because reopen from dashboard history doesn't update convs in ionic
232
232
  {subtype:"info/support", "updateconversation" : true, messagelabel: {key: "CHAT_REOPENED"}},
233
233
  undefined,
234
234
  request.language
@@ -90,7 +90,12 @@ findUnresponsiveRequests() {
90
90
  winston.verbose("CloseAgentUnresponsiveRequestTask: Request closed with request_id: " + request.request_id);
91
91
  // winston.info("Request closed",updatedStatusRequest);
92
92
  }).catch(function(err) {
93
- winston.error("CloseAgentUnresponsiveRequestTask: Error closing the request with request_id: " + request.request_id, err);
93
+ if (process.env.HIDE_CLOSE_REQUEST_ERRORS == true || process.env.HIDE_CLOSE_REQUEST_ERRORS == "true" ) {
94
+
95
+ } else {
96
+ winston.error("CloseAgentUnresponsiveRequestTask: Error closing the request with request_id: " + request.request_id, err);
97
+ }
98
+
94
99
  })
95
100
 
96
101
  });
@@ -65,6 +65,7 @@ findUnresponsiveRequests() {
65
65
 
66
66
  // db.getCollection('requests').find({"hasBot":true, "status": { "$lt": 1000 }, "createdAt": { "$lte" :new ISODate("2020-11-28T20:15:31Z")} }).count()
67
67
 
68
+
68
69
  var query = {hasBot:true, status: { $lt: 1000 }, createdAt: { $lte :new Date(Date.now() - this.queryAfterTimeout ).toISOString()} };
69
70
 
70
71
  if (this.queryProject) {
@@ -101,7 +102,12 @@ findUnresponsiveRequests() {
101
102
  winston.info("CloseBotUnresponsiveRequestTask: Request closed with request_id: " + request.request_id);
102
103
  // winston.info("Request closed",updatedStatusRequest);
103
104
  }).catch(function(err) {
104
- winston.error("CloseBotUnresponsiveRequestTask: Error closing the request with request_id: " + request.request_id, err);
105
+ if (process.env.HIDE_CLOSE_REQUEST_ERRORS == true || process.env.HIDE_CLOSE_REQUEST_ERRORS == "true" ) {
106
+
107
+ } else {
108
+ winston.error("CloseBotUnresponsiveRequestTask: Error closing the request with request_id: " + request.request_id, err);
109
+ }
110
+
105
111
  })
106
112
 
107
113
  });