@tiledesk/tiledesk-server 2.15.7 → 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/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
- var skip = page * limit;
1913
+ skip = page * limit;
1881
1914
  winston.debug('REQUEST ROUTE - SKIP PAGE ', skip);
1882
1915
 
1883
- let statusArray = [];
1916
+ // Default query (same as GET /)
1917
+ var query = { "id_project": req.projectid, "status": { $lt: 1000, $nin: [50, 150] }, preflight: false };
1884
1918
 
1885
- var query = { "id_project": req.projectid };
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.status) {
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
- let statusArray = req.query.status.split(',').map(Number);
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
- * DATE RANGE */
1947
- if (req.query.start_date && req.query.end_date) {
1948
- winston.debug('REQUEST ROUTE - REQ QUERY start_date ', req.query.start_date);
1949
- winston.debug('REQUEST ROUTE - REQ QUERY end_date ', req.query.end_date);
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
- * USING TIMESTAMP in MS */
1953
- // var formattedStartDate = new Date(+req.query.start_date);
1954
- // var formattedEndDate = new Date(+req.query.end_date);
1955
- // query.createdAt = { $gte: formattedStartDate, $lte: formattedEndDate }
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
- * USING MOMENT */
1960
- var startDate = moment(req.query.start_date, 'DD/MM/YYYY').format('YYYY-MM-DD');
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
- winston.debug('REQUEST ROUTE - REQ QUERY FORMATTED START DATE ', startDate);
1964
- winston.debug('REQUEST ROUTE - REQ QUERY FORMATTED END DATE ', endDate);
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
- // ADD ONE DAY TO THE END DAY
1967
- var date = new Date(endDate);
1968
- var newdate = new Date(date);
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
- query.createdAt = { $gte: new Date(Date.parse(startDate)).toISOString(), $lte: new Date(endDate_plusOneDay).toISOString() }
1976
- winston.debug('REQUEST ROUTE - QUERY CREATED AT ', query.createdAt);
2047
+ if (req.query.snap_lead_lead_id) {
2048
+ query["snapshot.lead.lead_id"] = req.query.snap_lead_lead_id;
2049
+ }
1977
2050
 
1978
- } else if (req.query.start_date && !req.query.end_date) {
1979
- winston.debug('REQUEST ROUTE - REQ QUERY END DATE IS EMPTY (so search only for start date)');
1980
- var startDate = moment(req.query.start_date, 'DD/MM/YYYY').format('YYYY-MM-DD');
2051
+ if (req.query.snap_lead_email) {
2052
+ query["snapshot.lead.email"] = req.query.snap_lead_email;
2053
+ }
1981
2054
 
1982
- query.createdAt = { $gte: new Date(Date.parse(startDate)).toISOString() };
1983
- winston.debug('REQUEST ROUTE - QUERY CREATED AT (only for start date)', query.createdAt);
2055
+ if (req.query.smartAssignment) {
2056
+ query.smartAssignment = req.query.smartAssignment;
1984
2057
  }
1985
- winston.debug("csv query", query);
1986
2058
 
1987
- var direction = 1; //-1 descending , 1 ascending
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
- if (req.query.channel) {
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
- winston.debug('REQUEST ROUTE - REQUEST FIND ', query)
2048
- return Request.find(query, '-transcript -status -__v').
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
- // populate('participatingBots').
2054
- // populate('participatingAgents').
2055
- lean().
2056
- // populate({
2057
- // path: 'department',
2058
- // //select: { '_id': -1,'name':1}
2059
- // select: {'name':1}
2060
- // }).
2061
- sort(sortQuery).
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 });
@@ -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
@@ -66,11 +67,12 @@ class AiManager {
66
67
  content: "",
67
68
  namespace: namespace.id,
68
69
  status: -1,
69
- sitemap_origin_id: options.sitemap_origin_id,
70
- sitemap_origin: options.sitemap_origin,
71
70
  scrape_type: options.scrape_type,
72
71
  scrape_options: options.scrape_options,
73
- refresh_rate: options.refresh_rate
72
+ refresh_rate: options.refresh_rate,
73
+ ...(options.sitemap_origin_id && { sitemap_origin_id: options.sitemap_origin_id }),
74
+ ...(options.sitemap_origin && { sitemap_origin: options.sitemap_origin }),
75
+ ...(options.tags && { tags: options.tags }),
74
76
  }
75
77
  return kb;
76
78
  })
@@ -141,6 +143,73 @@ class AiManager {
141
143
  })
142
144
  }
143
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
+
144
213
  async checkNamespace(id_project, namespace_id) {
145
214
  return new Promise( async (resolve, reject) => {
146
215
 
@@ -1,2 +1,2 @@
1
- Question 1;Question 1 Answer 1
2
- Question 2;Question 2 Answer 2
1
+ Question 1;Answer 1
2
+ Question 2;Answer 2
@@ -19,7 +19,8 @@
19
19
  "name": "Example content",
20
20
  "namespace": "6835be87d0a352002d806f73",
21
21
  "status": -1,
22
- "updatedAt": "2025-05-27T13:32:18.078Z"
22
+ "updatedAt": "2025-05-27T13:32:18.078Z",
23
+ "tags": ["tag1", "tag2"]
23
24
  },
24
25
  {
25
26
  "_id": "6835bed02c061f7021f46e99",