@tiledesk/tiledesk-server 2.15.8 → 2.16.0
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/CHANGELOG.md +5 -0
- package/event/messageEvent.js +24 -0
- package/models/request.js +1 -0
- package/package.json +1 -1
- package/pubmodules/queue/reconnect.js +16 -0
- package/pubmodules/routing-queue/listenerQueued.js +22 -3
- package/pubmodules/scheduler/tasks/closeAgentUnresponsiveRequestTask.js +2 -1
- package/pubmodules/scheduler/tasks/closeBotUnresponsiveRequestTask.js +2 -1
- package/routes/kb.js +160 -17
- package/routes/request.js +174 -92
- package/services/aiManager.js +68 -0
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,11 @@
|
|
|
5
5
|
🚀 IN PRODUCTION 🚀
|
|
6
6
|
(https://www.npmjs.com/package/@tiledesk/tiledesk-server/v/2.3.77)
|
|
7
7
|
|
|
8
|
+
# 2.16.0
|
|
9
|
+
- Added possibility to update Knowledge Base content
|
|
10
|
+
- Added rated only filter in Conversations History
|
|
11
|
+
- Improved pending requests management
|
|
12
|
+
|
|
8
13
|
# 2.15.8
|
|
9
14
|
- Updated tybot-connector to 2.0.45
|
|
10
15
|
- Added support for tags management in knowledge base routes
|
package/event/messageEvent.js
CHANGED
|
@@ -5,6 +5,7 @@ var Message = require("../models/message");
|
|
|
5
5
|
var Faq_kb = require("../models/faq_kb");
|
|
6
6
|
var MessageConstants = require("../models/messageConstants");
|
|
7
7
|
var message2Event = require("../event/message2Event");
|
|
8
|
+
var requestEvent = require("../event/requestEvent");
|
|
8
9
|
|
|
9
10
|
var cacheUtil = require('../utils/cacheUtil');
|
|
10
11
|
var cacheEnabler = require("../services/cacheEnabler");
|
|
@@ -178,6 +179,29 @@ function populateMessageWithRequest(message, eventPrefix) {
|
|
|
178
179
|
messageEvent.on('message.create.simple', populateMessageCreate);
|
|
179
180
|
messageEvent.on('message.update.simple', populateMessageUpdate);
|
|
180
181
|
|
|
182
|
+
// When the user (lead/requester) sends a message, reopen the conversation if it was pending
|
|
183
|
+
messageEvent.on('message.create.from.requester', function (messageJson) {
|
|
184
|
+
if (!messageJson.request || messageJson.request.workingStatus !== 'pending') return;
|
|
185
|
+
var request_id = messageJson.request.request_id;
|
|
186
|
+
var id_project = messageJson.request.id_project;
|
|
187
|
+
Request.findOneAndUpdate(
|
|
188
|
+
{ request_id: request_id, id_project: id_project },
|
|
189
|
+
{ $set: { workingStatus: 'open' } },
|
|
190
|
+
{ new: true },
|
|
191
|
+
function (err, updatedRequest) {
|
|
192
|
+
if (err) {
|
|
193
|
+
winston.error("Error updating request workingStatus from pending to open", err);
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
if (updatedRequest) {
|
|
197
|
+
winston.debug("Request workingStatus set to open (was pending)", { request_id, id_project });
|
|
198
|
+
requestEvent.emit('request.workingStatus.update', { request: updatedRequest });
|
|
199
|
+
requestEvent.emit('request.update', updatedRequest);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
);
|
|
203
|
+
});
|
|
204
|
+
|
|
181
205
|
|
|
182
206
|
|
|
183
207
|
// // riattiva commentato per performance
|
package/models/request.js
CHANGED
|
@@ -507,6 +507,7 @@ RequestSchema.index({ id_project: 1, createdAt: -1, status: 1 })
|
|
|
507
507
|
RequestSchema.index({ id_project: 1, preflight: 1, smartAssignment: 1, "snapshot.department.routing": 1, createdAt: 1, status: 1 })
|
|
508
508
|
|
|
509
509
|
RequestSchema.index({ status: 1, hasBot: 1, updatedAt: 1 }) // For closing unresponsive requests
|
|
510
|
+
RequestSchema.index({ status: 1, hasBot: 1, workingStatus: 1, updatedAt: 1 }) // For closing unresponsive requests
|
|
510
511
|
|
|
511
512
|
// Contact search by phone / email
|
|
512
513
|
RequestSchema.index({ id_project: 1, 'contact.phone': 1 });
|
package/package.json
CHANGED
|
@@ -175,6 +175,11 @@ function startWorker() {
|
|
|
175
175
|
winston.info("Data queue", oka)
|
|
176
176
|
});
|
|
177
177
|
|
|
178
|
+
ch.bindQueue(_ok.queue, exchange, "request_workingStatus_update", {}, function(err3, oka) {
|
|
179
|
+
winston.info("Queue bind: "+_ok.queue+ " err: "+err3+ " key: request_workingStatus_update");
|
|
180
|
+
winston.info("Data queue", oka)
|
|
181
|
+
});
|
|
182
|
+
|
|
178
183
|
ch.bindQueue(_ok.queue, exchange, "message_create", {}, function(err3, oka) {
|
|
179
184
|
winston.info("Queue bind: "+_ok.queue+ " err: "+err3+ " key: message_create");
|
|
180
185
|
winston.info("Data queue", oka)
|
|
@@ -286,6 +291,11 @@ function work(msg, cb) {
|
|
|
286
291
|
requestEvent.emit('request.close.extended.queue', JSON.parse(message_string));
|
|
287
292
|
}
|
|
288
293
|
|
|
294
|
+
if (topic === 'request_workingStatus_update') {
|
|
295
|
+
winston.debug("reconnect here topic:" + topic);
|
|
296
|
+
requestEvent.emit('request.workingStatus.update.queue', JSON.parse(message_string));
|
|
297
|
+
}
|
|
298
|
+
|
|
289
299
|
if (topic === 'message_create') {
|
|
290
300
|
winston.debug("reconnect here topic:" + topic);
|
|
291
301
|
// requestEvent.emit('request.create.queue', msg.content);
|
|
@@ -410,6 +420,12 @@ function listen() {
|
|
|
410
420
|
});
|
|
411
421
|
});
|
|
412
422
|
|
|
423
|
+
requestEvent.on('request.workingStatus.update', function(request) {
|
|
424
|
+
setImmediate(() => {
|
|
425
|
+
publish(exchange, "request_workingStatus_update", Buffer.from(JSON.stringify(request)));
|
|
426
|
+
});
|
|
427
|
+
});
|
|
428
|
+
|
|
413
429
|
requestEvent.on('request.snapshot.update', function(data) {
|
|
414
430
|
setImmediate(() => {
|
|
415
431
|
winston.debug("reconnect request.snapshot.update")
|
|
@@ -50,7 +50,7 @@ class Listener {
|
|
|
50
50
|
return winston.warn("Chatbot is not a project_user. Skip update.")
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
return Request.countDocuments({ id_project: id_project, participantsAgents: id_user, status: { $lt: 1000 }, draft: { $in: [null, false] } }, (err, requestsCount) => {
|
|
53
|
+
return Request.countDocuments({ id_project: id_project, participantsAgents: id_user, status: { $lt: 1000 }, draft: { $in: [null, false] }, workingStatus: { $ne: 'pending' } }, (err, requestsCount) => {
|
|
54
54
|
winston.verbose("requestsCount for id_user: ", id_user, "and project: ", id_project, "-->", requestsCount);
|
|
55
55
|
if (err) {
|
|
56
56
|
return winston.error(err);
|
|
@@ -236,8 +236,27 @@ class Listener {
|
|
|
236
236
|
});
|
|
237
237
|
});
|
|
238
238
|
|
|
239
|
-
|
|
240
|
-
|
|
239
|
+
var requestWorkingStatusUpdateKey = 'request.workingStatus.update';
|
|
240
|
+
if (requestEvent.queueEnabled) {
|
|
241
|
+
requestWorkingStatusUpdateKey = 'request.workingStatus.update.queue';
|
|
242
|
+
}
|
|
243
|
+
winston.debug('Route queue requestWorkingStatusUpdateKey: ' + requestWorkingStatusUpdateKey);
|
|
244
|
+
|
|
245
|
+
requestEvent.on(requestWorkingStatusUpdateKey, async (data) => {
|
|
246
|
+
winston.debug('Route queue WorkingStatus Update');
|
|
247
|
+
|
|
248
|
+
var request = data.request;
|
|
249
|
+
var participantIds = (request.participantsAgents && request.participantsAgents.length)
|
|
250
|
+
? request.participantsAgents
|
|
251
|
+
: (request.participatingAgents || []).map(u => u._id || u.id);
|
|
252
|
+
setImmediate(() => {
|
|
253
|
+
participantIds.forEach(id_user => {
|
|
254
|
+
if (id_user && !String(id_user).startsWith('bot_')) {
|
|
255
|
+
this.updateProjectUser(id_user, request.id_project, 0);
|
|
256
|
+
}
|
|
257
|
+
});
|
|
258
|
+
});
|
|
259
|
+
});
|
|
241
260
|
}
|
|
242
261
|
|
|
243
262
|
}
|
package/routes/kb.js
CHANGED
|
@@ -1773,38 +1773,181 @@ router.post('/sitemap/import', async (req, res) => {
|
|
|
1773
1773
|
|
|
1774
1774
|
router.put('/:kb_id', async (req, res) => {
|
|
1775
1775
|
|
|
1776
|
-
|
|
1777
|
-
|
|
1776
|
+
const id_project = req.projectid;
|
|
1777
|
+
const project = req.project;
|
|
1778
|
+
const kb_id = req.params.kb_id;
|
|
1779
|
+
|
|
1780
|
+
const { name, type, source, content, refresh_rate, scrape_type, scrape_options, tags } = req.body;
|
|
1781
|
+
const namespace_id = req.body.namespace;
|
|
1778
1782
|
|
|
1779
|
-
|
|
1783
|
+
if (!namespace_id) {
|
|
1784
|
+
return res.status(400).send({ success: false, error: "Missing 'namespace' body parameter" })
|
|
1785
|
+
}
|
|
1780
1786
|
|
|
1781
|
-
|
|
1782
|
-
|
|
1787
|
+
let namespace;
|
|
1788
|
+
try {
|
|
1789
|
+
namespace = await aiManager.checkNamespace(id_project, namespace_id);
|
|
1790
|
+
} catch (err) {
|
|
1791
|
+
let errorCode = err?.errorCode ?? 500;
|
|
1792
|
+
return res.status(errorCode).send({ success: false, error: err.error });
|
|
1783
1793
|
}
|
|
1784
1794
|
|
|
1785
|
-
|
|
1786
|
-
|
|
1795
|
+
let kb = await KB.findOne({ id_project, namespace: namespace_id, _id: kb_id }).lean().exec();
|
|
1796
|
+
|
|
1797
|
+
if (!kb) {
|
|
1798
|
+
return res.status(404).send({ success: false, error: "Content not found. Unable to update a non-existing content" })
|
|
1787
1799
|
}
|
|
1788
1800
|
|
|
1789
|
-
|
|
1801
|
+
let data = {
|
|
1802
|
+
id: kb._id,
|
|
1803
|
+
namespace: namespace_id,
|
|
1804
|
+
engine: namespace.engine || default_engine
|
|
1805
|
+
}
|
|
1790
1806
|
|
|
1791
|
-
|
|
1807
|
+
// if (kb.type === 'sitemap') {
|
|
1808
|
+
// let new_sitemap = {
|
|
1809
|
+
// id_project,
|
|
1810
|
+
// name,
|
|
1811
|
+
// source,
|
|
1812
|
+
// type: 'sitemap',
|
|
1813
|
+
// content: "",
|
|
1814
|
+
// namespace: namespace_id,
|
|
1815
|
+
// status: -1,
|
|
1816
|
+
// scrape_type,
|
|
1817
|
+
// scrape_options,
|
|
1818
|
+
// refresh_rate,
|
|
1819
|
+
// ...(Array.isArray(tags) && tags.length > 0 ? { tags } : {})
|
|
1820
|
+
// }
|
|
1792
1821
|
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1822
|
+
// try {
|
|
1823
|
+
// let result = await aiManager.updateSitemap(id_project, namespace, kb, new_sitemap);
|
|
1824
|
+
// return res.status(200).send(result);
|
|
1825
|
+
// } catch (err) {
|
|
1826
|
+
// winston.error("Error updating sitemap: ", err);
|
|
1827
|
+
// return res.status(500).send({ success: false, error: err });
|
|
1828
|
+
// }
|
|
1829
|
+
// }
|
|
1830
|
+
|
|
1831
|
+
try {
|
|
1832
|
+
let delete_response = await aiService.deleteIndex(data);
|
|
1833
|
+
|
|
1834
|
+
if (delete_response.data.success === true) {
|
|
1835
|
+
await KB.findOneAndDelete({ id_project, namespace: namespace_id, source }).lean().exec();
|
|
1836
|
+
// continue the flow
|
|
1837
|
+
} else {
|
|
1838
|
+
winston.error("Unable to update content due to an error: ", delete_response.data.error);
|
|
1839
|
+
return res.status(500).send({ success: false, error: delete_response.data.error });
|
|
1796
1840
|
}
|
|
1797
1841
|
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1842
|
+
} catch (err) {
|
|
1843
|
+
winston.error("Error updating content: ", err);
|
|
1844
|
+
return res.status(500).send({ success: false, error: err });
|
|
1845
|
+
}
|
|
1846
|
+
|
|
1847
|
+
let new_content = {
|
|
1848
|
+
id_project,
|
|
1849
|
+
name,
|
|
1850
|
+
type,
|
|
1851
|
+
source,
|
|
1852
|
+
content,
|
|
1853
|
+
namespace: namespace_id,
|
|
1854
|
+
status: -1,
|
|
1855
|
+
}
|
|
1856
|
+
|
|
1857
|
+
if (new_content.type === 'url') {
|
|
1858
|
+
new_content.refresh_rate = refresh_rate || 'never';
|
|
1859
|
+
if (!scrape_type || scrape_type === 2) {
|
|
1860
|
+
new_content.scrape_type = 2;
|
|
1861
|
+
new_content.scrape_options = aiManager.setDefaultScrapeOptions();
|
|
1862
|
+
} else {
|
|
1863
|
+
new_content.scrape_type = scrape_type;
|
|
1864
|
+
new_content.scrape_options = scrape_options;
|
|
1801
1865
|
}
|
|
1866
|
+
}
|
|
1802
1867
|
|
|
1803
|
-
|
|
1804
|
-
|
|
1868
|
+
if (kb.sitemap_origin_id) {
|
|
1869
|
+
new_content.sitemap_origin_id = kb.sitemap_origin_id;
|
|
1870
|
+
new_content.sitemap_origin = kb.sitemap_origin;
|
|
1871
|
+
}
|
|
1872
|
+
|
|
1873
|
+
if (tags && Array.isArray(tags) && tags.every(tag => typeof tag === "string")) {
|
|
1874
|
+
new_content.tags = tags;
|
|
1875
|
+
}
|
|
1876
|
+
|
|
1877
|
+
winston.debug("Update content. New content: ", new_content);
|
|
1878
|
+
|
|
1879
|
+
let updated_content;
|
|
1880
|
+
try {
|
|
1881
|
+
updated_content = await KB.findOneAndUpdate({ id_project, namespace: namespace_id, source }, new_content, { upsert: true, new: true }).lean().exec();
|
|
1882
|
+
} catch (err) {
|
|
1883
|
+
winston.error("Error updating content: ", err);
|
|
1884
|
+
return res.status(500).send({ success: false, error: err });
|
|
1885
|
+
}
|
|
1886
|
+
|
|
1887
|
+
const embedding = normalizeEmbedding(namespace.embedding);
|
|
1888
|
+
embedding.api_key = process.env.EMBEDDING_API_KEY || process.env.GPTKEY;
|
|
1889
|
+
let webhook = apiUrl + '/webhook/kb/status?token=' + KB_WEBHOOK_TOKEN;
|
|
1890
|
+
|
|
1891
|
+
const json = {
|
|
1892
|
+
id: updated_content._id,
|
|
1893
|
+
type: updated_content.type,
|
|
1894
|
+
source: updated_content.source,
|
|
1895
|
+
content: updated_content.content || "",
|
|
1896
|
+
namespace: updated_content.namespace,
|
|
1897
|
+
webhook: webhook,
|
|
1898
|
+
hybrid: namespace.hybrid,
|
|
1899
|
+
engine: namespace.engine || default_engine,
|
|
1900
|
+
embedding: embedding,
|
|
1901
|
+
...(updated_content.scrape_type && { scrape_type: updated_content.scrape_type }),
|
|
1902
|
+
...(updated_content.scrape_options && { parameters_scrape_type_4: updated_content.scrape_options }),
|
|
1903
|
+
...(updated_content.tags && { tags: updated_content.tags }),
|
|
1904
|
+
}
|
|
1905
|
+
|
|
1906
|
+
winston.debug("json: ", json);
|
|
1907
|
+
|
|
1908
|
+
if (process.env.NODE_ENV === 'test') {
|
|
1909
|
+
return res.status(200).send({ success: true, message: "Schedule scrape skipped in test environment", data: updated_content, schedule_json: json });
|
|
1910
|
+
}
|
|
1911
|
+
|
|
1912
|
+
aiManager.scheduleScrape([json], namespace.hybrid);
|
|
1913
|
+
return res.status(200).send(updated_content);
|
|
1805
1914
|
|
|
1806
1915
|
})
|
|
1807
1916
|
|
|
1917
|
+
// router.put('/:kb_id', async (req, res) => {
|
|
1918
|
+
|
|
1919
|
+
// let kb_id = req.params.kb_id;
|
|
1920
|
+
// winston.verbose("update kb_id " + kb_id);
|
|
1921
|
+
|
|
1922
|
+
// let update = {};
|
|
1923
|
+
|
|
1924
|
+
// if (req.body.name != undefined) {
|
|
1925
|
+
// update.name = req.body.name;
|
|
1926
|
+
// }
|
|
1927
|
+
|
|
1928
|
+
// if (req.body.status != undefined) {
|
|
1929
|
+
// update.status = req.body.status;
|
|
1930
|
+
// }
|
|
1931
|
+
|
|
1932
|
+
// winston.debug("kb update: ", update);
|
|
1933
|
+
|
|
1934
|
+
// KB.findByIdAndUpdate(kb_id, update, { new: true }, (err, savedKb) => {
|
|
1935
|
+
|
|
1936
|
+
// if (err) {
|
|
1937
|
+
// winston.error("KB findByIdAndUpdate error: ", err);
|
|
1938
|
+
// return res.status(500).send({ success: false, error: err });
|
|
1939
|
+
// }
|
|
1940
|
+
|
|
1941
|
+
// if (!savedKb) {
|
|
1942
|
+
// winston.debug("Try to updating a non-existing kb");
|
|
1943
|
+
// return res.status(400).send({ success: false, message: "Content not found" })
|
|
1944
|
+
// }
|
|
1945
|
+
|
|
1946
|
+
// res.status(200).send(savedKb)
|
|
1947
|
+
// })
|
|
1948
|
+
|
|
1949
|
+
// })
|
|
1950
|
+
|
|
1808
1951
|
router.delete('/:kb_id', async (req, res) => {
|
|
1809
1952
|
|
|
1810
1953
|
let project_id = req.projectid;
|
package/routes/request.js
CHANGED
|
@@ -318,6 +318,10 @@ router.patch('/:requestid', function (req, res) {
|
|
|
318
318
|
return res.status(404).send({ success: false, msg: 'Request not found' });
|
|
319
319
|
}
|
|
320
320
|
|
|
321
|
+
if (update.workingStatus !== undefined) {
|
|
322
|
+
requestEvent.emit('request.workingStatus.update', { request });
|
|
323
|
+
}
|
|
324
|
+
|
|
321
325
|
requestEvent.emit("request.update", request);
|
|
322
326
|
requestEvent.emit("request.update.comment", { comment: "PATCH", request: request }); //Deprecated
|
|
323
327
|
requestEvent.emit("request.updated", { comment: "PATCH", request: request, patch: update });
|
|
@@ -1376,6 +1380,10 @@ router.get('/', function (req, res, next) {
|
|
|
1376
1380
|
}
|
|
1377
1381
|
}
|
|
1378
1382
|
|
|
1383
|
+
if (req.query.workingStatus?.ne) {
|
|
1384
|
+
query.workingStatus = { $ne: req.query.workingStatus.ne };
|
|
1385
|
+
}
|
|
1386
|
+
|
|
1379
1387
|
if (req.query.priority) {
|
|
1380
1388
|
query.priority = req.query.priority;
|
|
1381
1389
|
}
|
|
@@ -1421,10 +1429,31 @@ router.get('/', function (req, res, next) {
|
|
|
1421
1429
|
query["attributes.fully_abandoned"] = true
|
|
1422
1430
|
}
|
|
1423
1431
|
|
|
1432
|
+
if (req.query.rated && (req.query.rated === true || req.query.rated === 'true')) {
|
|
1433
|
+
query.rating = { $exists: true }
|
|
1434
|
+
}
|
|
1435
|
+
|
|
1424
1436
|
if (req.query.draft && (req.query.draft === 'false' || req.query.draft === false)) {
|
|
1425
1437
|
query.draft = { $in: [false, null] }
|
|
1426
1438
|
}
|
|
1427
1439
|
|
|
1440
|
+
let inWStatus = req.query.workingStatus?.in?.split(',').map(s => s.trim()).filter(Boolean);
|
|
1441
|
+
let ninWStatus = req.query.workingStatus?.nin?.split(',').map(s => s.trim()).filter(Boolean);
|
|
1442
|
+
|
|
1443
|
+
if (ninWStatus && ninWStatus.length > 0) {
|
|
1444
|
+
if (ninWStatus.length === 1) {
|
|
1445
|
+
query.workingStatus = { $ne: ninWStatus[0] };
|
|
1446
|
+
} else {
|
|
1447
|
+
query.workingStatus = { $nin: ninWStatus };
|
|
1448
|
+
}
|
|
1449
|
+
} else if (inWStatus && inWStatus.length > 0) {
|
|
1450
|
+
if (inWStatus.length === 1) {
|
|
1451
|
+
query.workingStatus = inWStatus[0];
|
|
1452
|
+
} else {
|
|
1453
|
+
query.workingStatus = { $in: inWStatus };
|
|
1454
|
+
}
|
|
1455
|
+
}
|
|
1456
|
+
|
|
1428
1457
|
var projection = undefined;
|
|
1429
1458
|
|
|
1430
1459
|
if (req.query.full_text) {
|
|
@@ -1872,57 +1901,67 @@ router.get('/csv', function (req, res, next) {
|
|
|
1872
1901
|
|
|
1873
1902
|
var limit = 100000; // Number of request per page
|
|
1874
1903
|
var page = 0;
|
|
1904
|
+
var skip = 0;
|
|
1905
|
+
let statusArray = [];
|
|
1906
|
+
var projectuser = req.projectuser;
|
|
1907
|
+
let filterRangeField = req.query.filterRangeField || 'createdAt';
|
|
1875
1908
|
|
|
1876
1909
|
if (req.query.page) {
|
|
1877
1910
|
page = req.query.page;
|
|
1878
1911
|
}
|
|
1879
1912
|
|
|
1880
|
-
|
|
1913
|
+
skip = page * limit;
|
|
1881
1914
|
winston.debug('REQUEST ROUTE - SKIP PAGE ', skip);
|
|
1882
1915
|
|
|
1883
|
-
|
|
1916
|
+
// Default query (same as GET /)
|
|
1917
|
+
var query = { "id_project": req.projectid, "status": { $lt: 1000, $nin: [50, 150] }, preflight: false };
|
|
1884
1918
|
|
|
1885
|
-
|
|
1919
|
+
if (req.user instanceof Subscription) {
|
|
1920
|
+
// All request
|
|
1921
|
+
} else if (projectuser && (projectuser.role == "owner" || projectuser.role == "admin")) {
|
|
1922
|
+
if (req.query.mine) {
|
|
1923
|
+
query["$or"] = [{ "snapshot.agents.id_user": req.user.id }, { "participants": req.user.id }];
|
|
1924
|
+
}
|
|
1925
|
+
} else {
|
|
1926
|
+
query["$or"] = [{ "snapshot.agents.id_user": req.user.id }, { "participants": req.user.id }];
|
|
1927
|
+
}
|
|
1886
1928
|
|
|
1887
1929
|
if (req.query.dept_id) {
|
|
1888
1930
|
query.department = req.query.dept_id;
|
|
1889
1931
|
winston.debug('REQUEST ROUTE - QUERY DEPT ID', query.department);
|
|
1890
1932
|
}
|
|
1891
1933
|
|
|
1934
|
+
if (req.query.requester_email) {
|
|
1935
|
+
query["snapshot.lead.email"] = req.query.requester_email;
|
|
1936
|
+
}
|
|
1937
|
+
|
|
1892
1938
|
if (req.query.full_text) {
|
|
1893
1939
|
winston.debug('req.query.fulltext', req.query.full_text);
|
|
1894
1940
|
query.$text = { "$search": req.query.full_text };
|
|
1895
1941
|
}
|
|
1896
1942
|
|
|
1897
|
-
if (req.query.
|
|
1943
|
+
if (req.query.phone) {
|
|
1944
|
+
var phoneDigits = req.query.phone.replace(/\D/g, '');
|
|
1945
|
+
if (phoneDigits.length > 0) {
|
|
1946
|
+
query["contact.phone"] = new RegExp(phoneDigits);
|
|
1947
|
+
}
|
|
1948
|
+
}
|
|
1949
|
+
|
|
1950
|
+
var history_search = false;
|
|
1898
1951
|
|
|
1952
|
+
// Multiple status management (same as GET /)
|
|
1953
|
+
if (req.query.status) {
|
|
1899
1954
|
if (req.query.status === 'all') {
|
|
1900
1955
|
delete query.status;
|
|
1901
1956
|
} else {
|
|
1902
|
-
|
|
1903
|
-
statusArray = statusArray.map(status => { return isNaN(status) ? null : status }).filter(status => status !== null)
|
|
1957
|
+
statusArray = req.query.status.split(',').map(Number);
|
|
1958
|
+
statusArray = statusArray.map(status => { return isNaN(status) ? null : status }).filter(status => status !== null);
|
|
1904
1959
|
if (statusArray.length > 0) {
|
|
1905
|
-
query.status = {
|
|
1906
|
-
$in: statusArray
|
|
1907
|
-
}
|
|
1960
|
+
query.status = { $in: statusArray };
|
|
1908
1961
|
} else {
|
|
1909
1962
|
delete query.status;
|
|
1910
1963
|
}
|
|
1911
1964
|
}
|
|
1912
|
-
|
|
1913
|
-
if (statusArray.length > 0) {
|
|
1914
|
-
query.status = {
|
|
1915
|
-
$in: statusArray
|
|
1916
|
-
}
|
|
1917
|
-
}
|
|
1918
|
-
|
|
1919
|
-
}
|
|
1920
|
-
|
|
1921
|
-
if (req.query.preflight) {
|
|
1922
|
-
let preflight = (req.query.preflight === 'false');
|
|
1923
|
-
if (preflight) {
|
|
1924
|
-
query.preflight = false;
|
|
1925
|
-
}
|
|
1926
1965
|
}
|
|
1927
1966
|
|
|
1928
1967
|
if (req.query.lead) {
|
|
@@ -1942,49 +1981,96 @@ router.get('/csv', function (req, res, next) {
|
|
|
1942
1981
|
query.hasBot = req.query.hasbot;
|
|
1943
1982
|
}
|
|
1944
1983
|
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1984
|
+
if (req.query.tags) {
|
|
1985
|
+
query["tags.tag"] = req.query.tags;
|
|
1986
|
+
}
|
|
1987
|
+
|
|
1988
|
+
if (req.query.location) {
|
|
1989
|
+
query.location = req.query.location;
|
|
1990
|
+
}
|
|
1991
|
+
|
|
1992
|
+
if (req.query.ticket_id) {
|
|
1993
|
+
query.ticket_id = req.query.ticket_id;
|
|
1994
|
+
}
|
|
1995
|
+
|
|
1996
|
+
if (req.query.preflight && (req.query.preflight === 'true' || req.query.preflight === true)) {
|
|
1997
|
+
delete query.preflight;
|
|
1998
|
+
}
|
|
1999
|
+
|
|
2000
|
+
let timezone = req.query.timezone || 'Europe/Rome';
|
|
2001
|
+
let queryDateRange = false;
|
|
2002
|
+
let queryStartDate;
|
|
2003
|
+
let queryEndDate;
|
|
2004
|
+
|
|
2005
|
+
if (history_search === true && req.project && req.project.profile && ((req.project.profile.type === 'free' && req.project.trialExpired === true) || (req.project.profile.type === 'payment' && req.project.isActiveSubscription === false))) {
|
|
2006
|
+
queryDateRange = true;
|
|
2007
|
+
queryStartDate = moment().subtract(14, "days").format("YYYY/MM/DD");
|
|
2008
|
+
queryEndDate = null;
|
|
2009
|
+
}
|
|
1950
2010
|
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
2011
|
+
if (req.query.start_date || req.query.end_date) {
|
|
2012
|
+
queryDateRange = true;
|
|
2013
|
+
queryStartDate = req.query.start_date;
|
|
2014
|
+
queryEndDate = req.query.end_date;
|
|
2015
|
+
} else if (req.query.start_date_time || req.query.end_date_time) {
|
|
2016
|
+
queryDateRange = true;
|
|
2017
|
+
queryStartDate = req.query.start_date_time;
|
|
2018
|
+
queryEndDate = req.query.end_date_time;
|
|
2019
|
+
}
|
|
1956
2020
|
|
|
2021
|
+
if (queryDateRange) {
|
|
2022
|
+
try {
|
|
2023
|
+
let rangeQuery = datesUtil.createDateRangeQuery(queryStartDate, queryEndDate, timezone, filterRangeField);
|
|
2024
|
+
Object.assign(query, rangeQuery);
|
|
2025
|
+
} catch (error) {
|
|
2026
|
+
winston.error('Error creating date range query: ', error);
|
|
2027
|
+
return res.status(500).send({ success: false, error: error?.message });
|
|
2028
|
+
}
|
|
2029
|
+
}
|
|
1957
2030
|
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
var endDate = moment(req.query.end_date, 'DD/MM/YYYY').format('YYYY-MM-DD');
|
|
2031
|
+
if (req.query.snap_department_routing) {
|
|
2032
|
+
query["snapshot.department.routing"] = req.query.snap_department_routing;
|
|
2033
|
+
}
|
|
1962
2034
|
|
|
1963
|
-
|
|
1964
|
-
|
|
2035
|
+
if (req.query.snap_department_default) {
|
|
2036
|
+
query["snapshot.department.default"] = req.query.snap_department_default;
|
|
2037
|
+
}
|
|
2038
|
+
|
|
2039
|
+
if (req.query.snap_department_id_bot) {
|
|
2040
|
+
query["snapshot.department.id_bot"] = req.query.snap_department_id_bot;
|
|
2041
|
+
}
|
|
1965
2042
|
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
var endDate_plusOneDay = newdate.setDate(newdate.getDate() + 1);
|
|
1970
|
-
winston.debug('REQUEST ROUTE - REQ QUERY FORMATTED END DATE + 1 DAY ', endDate_plusOneDay);
|
|
1971
|
-
// var endDate_plusOneDay = moment('2018-09-03').add(1, 'd')
|
|
1972
|
-
// var endDate_plusOneDay = endDate.add(1).day();
|
|
1973
|
-
// var toDate = new Date(Date.parse(endDate_plusOneDay)).toISOString()
|
|
2043
|
+
if (req.query.snap_department_id_bot_exists) {
|
|
2044
|
+
query["snapshot.department.id_bot"] = { "$exists": req.query.snap_department_id_bot_exists };
|
|
2045
|
+
}
|
|
1974
2046
|
|
|
1975
|
-
|
|
1976
|
-
|
|
2047
|
+
if (req.query.snap_lead_lead_id) {
|
|
2048
|
+
query["snapshot.lead.lead_id"] = req.query.snap_lead_lead_id;
|
|
2049
|
+
}
|
|
1977
2050
|
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
2051
|
+
if (req.query.snap_lead_email) {
|
|
2052
|
+
query["snapshot.lead.email"] = req.query.snap_lead_email;
|
|
2053
|
+
}
|
|
1981
2054
|
|
|
1982
|
-
|
|
1983
|
-
|
|
2055
|
+
if (req.query.smartAssignment) {
|
|
2056
|
+
query.smartAssignment = req.query.smartAssignment;
|
|
1984
2057
|
}
|
|
1985
|
-
winston.debug("csv query", query);
|
|
1986
2058
|
|
|
1987
|
-
|
|
2059
|
+
if (req.query.channel) {
|
|
2060
|
+
if (req.query.channel === "offline") {
|
|
2061
|
+
query["channel.name"] = { "$in": ["email", "form"] };
|
|
2062
|
+
} else if (req.query.channel === "online") {
|
|
2063
|
+
query["channel.name"] = { "$nin": ["email", "form"] };
|
|
2064
|
+
} else {
|
|
2065
|
+
query["channel.name"] = req.query.channel;
|
|
2066
|
+
}
|
|
2067
|
+
}
|
|
2068
|
+
|
|
2069
|
+
if (req.query.priority) {
|
|
2070
|
+
query.priority = req.query.priority;
|
|
2071
|
+
}
|
|
2072
|
+
|
|
2073
|
+
var direction = -1; // same default as GET /
|
|
1988
2074
|
if (req.query.direction) {
|
|
1989
2075
|
direction = req.query.direction;
|
|
1990
2076
|
}
|
|
@@ -1998,20 +2084,9 @@ router.get('/csv', function (req, res, next) {
|
|
|
1998
2084
|
|
|
1999
2085
|
var sortQuery = {};
|
|
2000
2086
|
sortQuery[sortField] = direction;
|
|
2001
|
-
|
|
2002
2087
|
winston.debug("sort query", sortQuery);
|
|
2003
2088
|
|
|
2004
|
-
|
|
2005
|
-
if (req.query.channel === "offline") {
|
|
2006
|
-
query["channel.name"] = { "$in": ["email", "form"] }
|
|
2007
|
-
} else if (req.query.channel === "online") {
|
|
2008
|
-
query["channel.name"] = { "$nin": ["email", "form"] }
|
|
2009
|
-
} else {
|
|
2010
|
-
query["channel.name"] = req.query.channel
|
|
2011
|
-
}
|
|
2012
|
-
}
|
|
2013
|
-
|
|
2014
|
-
// VOICE FILTERS - Start
|
|
2089
|
+
// VOICE FILTERS
|
|
2015
2090
|
if (req.query.caller) {
|
|
2016
2091
|
query["attributes.caller_phone"] = req.query.caller;
|
|
2017
2092
|
}
|
|
@@ -2021,45 +2096,52 @@ router.get('/csv', function (req, res, next) {
|
|
|
2021
2096
|
if (req.query.call_id) {
|
|
2022
2097
|
query["attributes.call_id"] = req.query.call_id;
|
|
2023
2098
|
}
|
|
2024
|
-
// VOICE FILTERS - End
|
|
2025
|
-
|
|
2026
|
-
// TODO ORDER BY SCORE
|
|
2027
|
-
// return Faq.find(query, {score: { $meta: "textScore" } })
|
|
2028
|
-
// .sort( { score: { $meta: "textScore" } } ) //https://docs.mongodb.com/manual/reference/operator/query/text/#sort-by-text-search-score
|
|
2029
|
-
|
|
2030
|
-
// aggiungi filtro per data marco
|
|
2031
2099
|
|
|
2032
2100
|
if (req.query.duration && req.query.duration_op) {
|
|
2033
2101
|
let duration = Number(req.query.duration) * 60 * 1000;
|
|
2034
2102
|
if (req.query.duration_op === 'gt') {
|
|
2035
|
-
query.duration = { $gte: duration }
|
|
2103
|
+
query.duration = { $gte: duration };
|
|
2036
2104
|
} else if (req.query.duration_op === 'lt') {
|
|
2037
|
-
query.duration = { $lte: duration }
|
|
2105
|
+
query.duration = { $lte: duration };
|
|
2038
2106
|
} else {
|
|
2039
|
-
winston.verbose("Duration operator can be 'gt' or 'lt'. Skip duration_op " + req.query.duration_op)
|
|
2107
|
+
winston.verbose("Duration operator can be 'gt' or 'lt'. Skip duration_op " + req.query.duration_op);
|
|
2040
2108
|
}
|
|
2041
2109
|
}
|
|
2042
2110
|
|
|
2111
|
+
if (req.query.abandonded && (req.query.abandoned === true || req.query.abandoned === 'true')) {
|
|
2112
|
+
query["attributes.fully_abandoned"] = true;
|
|
2113
|
+
}
|
|
2114
|
+
|
|
2115
|
+
if (req.query.rated && (req.query.rated === true || req.query.rated === 'true')) {
|
|
2116
|
+
query.rating = { $exists: true };
|
|
2117
|
+
}
|
|
2118
|
+
|
|
2043
2119
|
if (req.query.draft && (req.query.draft === 'false' || req.query.draft === false)) {
|
|
2044
|
-
query.draft = { $in: [false, null] }
|
|
2120
|
+
query.draft = { $in: [false, null] };
|
|
2045
2121
|
}
|
|
2046
2122
|
|
|
2047
|
-
|
|
2048
|
-
|
|
2123
|
+
var csvProjection = '-transcript -status -__v';
|
|
2124
|
+
if (req.query.full_text && req.query.no_textscore != "true" && req.query.no_textscore != true) {
|
|
2125
|
+
winston.verbose('fulltext projection on');
|
|
2126
|
+
csvProjection = { transcript: 0, status: 0, __v: 0, score: { $meta: "textScore" } };
|
|
2127
|
+
}
|
|
2128
|
+
|
|
2129
|
+
winston.debug("csv query", query);
|
|
2130
|
+
winston.debug('REQUEST ROUTE - REQUEST FIND ', query);
|
|
2131
|
+
|
|
2132
|
+
var q = Request.find(query, csvProjection).
|
|
2049
2133
|
skip(skip).limit(limit).
|
|
2050
|
-
//populate('department', {'_id':-1, 'name':1}).
|
|
2051
2134
|
populate('department').
|
|
2052
2135
|
populate('lead').
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
exec(function (err, requests) {
|
|
2136
|
+
lean();
|
|
2137
|
+
|
|
2138
|
+
if (req.query.full_text && req.query.no_textscore != "true" && req.query.no_textscore != true) {
|
|
2139
|
+
q.sort({ score: { $meta: "textScore" } });
|
|
2140
|
+
} else {
|
|
2141
|
+
q.sort(sortQuery);
|
|
2142
|
+
}
|
|
2143
|
+
|
|
2144
|
+
return q.exec(function (err, requests) {
|
|
2063
2145
|
if (err) {
|
|
2064
2146
|
winston.error('REQUEST ROUTE - REQUEST FIND ERR ', err)
|
|
2065
2147
|
return res.status(500).send({ success: false, msg: 'Error getting csv requests.', err: err });
|
package/services/aiManager.js
CHANGED
|
@@ -5,6 +5,7 @@ const { Scheduler } = require("./Scheduler");
|
|
|
5
5
|
const { default: Sitemapper } = require('sitemapper');
|
|
6
6
|
const winston = require('../config/winston');
|
|
7
7
|
const configGlobal = require('../config/global');
|
|
8
|
+
const _ = require('lodash');
|
|
8
9
|
const JobManager = require('../utils/jobs-worker-queue-manager/JobManagerV2');
|
|
9
10
|
|
|
10
11
|
// Constants
|
|
@@ -142,6 +143,73 @@ class AiManager {
|
|
|
142
143
|
})
|
|
143
144
|
}
|
|
144
145
|
|
|
146
|
+
async updateSitemap(id_project, namespace, old_sitemap, new_sitemap) {
|
|
147
|
+
|
|
148
|
+
let fieldsToCheck = ['scrape_type', 'scrape_options', 'refresh_rate', 'tags'];
|
|
149
|
+
let { stop } = this.shouldStop(old_sitemap, new_sitemap, fieldsToCheck);
|
|
150
|
+
|
|
151
|
+
let updated_sitemap;
|
|
152
|
+
try {
|
|
153
|
+
updated_sitemap = await KB.findOneAndUpdate({ id_project, namespace: namespace.id, _id: old_sitemap._id }, new_sitemap, { new: true });
|
|
154
|
+
} catch (err) {
|
|
155
|
+
winston.error("Error updating sitemap: ", err);
|
|
156
|
+
throw err;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
if (stop) {
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// Find all url contents with sitemap_origin_id
|
|
164
|
+
let urlContents = await KB.find({ id_project, namespace: namespace.id, sitemap_origin_id: old_sitemap._id }).lean().exec();
|
|
165
|
+
if (urlContents.length === 0) {
|
|
166
|
+
winston.error("No url contents found with sitemap_origin_id: ", old_sitemap._id);
|
|
167
|
+
throw new Error("No url contents found with sitemap_origin_id: " + old_sitemap._id);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Remove all url contents found with sitemap_origin_id
|
|
171
|
+
try {
|
|
172
|
+
await this.removeMultipleContents(namespace, urlContents);
|
|
173
|
+
} catch (err) {
|
|
174
|
+
winston.error("Error removing multiple contents: ", err);
|
|
175
|
+
throw err;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// Recreate all url contents with sitemap_origin_id
|
|
179
|
+
let result;
|
|
180
|
+
try {
|
|
181
|
+
result = await this.addMultipleUrls(namespace, urlContents.map(urlContent => urlContent.source), {
|
|
182
|
+
sitemap_origin_id: updated_sitemap._id,
|
|
183
|
+
sitemap_origin: updated_sitemap.source,
|
|
184
|
+
scrape_type: updated_sitemap.scrape_type,
|
|
185
|
+
scrape_options: updated_sitemap.scrape_options,
|
|
186
|
+
refresh_rate: updated_sitemap.refresh_rate,
|
|
187
|
+
tags: updated_sitemap.tags,
|
|
188
|
+
});
|
|
189
|
+
} catch (err) {
|
|
190
|
+
winston.error("Error recreating multiple contents: ", err);
|
|
191
|
+
throw err;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
return result;
|
|
195
|
+
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
shouldStop(oldObj, newObj, fieldsToCheck) {
|
|
201
|
+
for (const field of fieldsToCheck) {
|
|
202
|
+
const oldValue = _.get(oldObj, field);
|
|
203
|
+
const newValue = _.get(newObj, field);
|
|
204
|
+
|
|
205
|
+
if (!_.isEqual(oldValue, newValue)) {
|
|
206
|
+
return { stop: false };
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
return { stop: true };
|
|
211
|
+
}
|
|
212
|
+
|
|
145
213
|
async checkNamespace(id_project, namespace_id) {
|
|
146
214
|
return new Promise( async (resolve, reject) => {
|
|
147
215
|
|