@tiledesk/tiledesk-server 2.19.12 → 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.
@@ -0,0 +1,280 @@
1
+ const express = require('express');
2
+ const router = express.Router();
3
+ const winston = require('../config/winston');
4
+ const dataTableService = require('../services/dataTableService');
5
+
6
+ function getRowPayload(body) {
7
+ if (body && body.data && typeof body.data === 'object' && !Array.isArray(body.data)) {
8
+ return body.data;
9
+ }
10
+ return body;
11
+ }
12
+
13
+ function isValidationError(err) {
14
+ if (!err || !err.message) return false;
15
+ const msg = err.message;
16
+ return msg.indexOf('does not exist') !== -1 ||
17
+ msg.indexOf('required') !== -1 ||
18
+ msg.indexOf('Invalid') !== -1 ||
19
+ msg.indexOf('must be') !== -1 ||
20
+ msg.indexOf('already exists') !== -1 ||
21
+ msg.indexOf('Column id') !== -1 ||
22
+ msg.indexOf('not provided') !== -1 ||
23
+ msg.indexOf('Operator') !== -1 ||
24
+ msg.indexOf('id_row or conditions') !== -1 ||
25
+ msg.indexOf('data is required') !== -1 ||
26
+ msg.indexOf('valid JSON') !== -1;
27
+ }
28
+
29
+ function handleError(res, err, action) {
30
+ if (err && err.message === 'TABLE_SIZE_LIMIT_EXCEEDED') {
31
+ return res.status(413).send({ success: false, message: 'TABLE_SIZE_LIMIT_EXCEEDED' });
32
+ }
33
+ if (isValidationError(err)) {
34
+ const status = err.message.indexOf('already exists') !== -1 ? 409 : 400;
35
+ return res.status(status).send({ success: false, message: err.message });
36
+ }
37
+ if (err.message === 'Column not found' || err.message.indexOf('Column not found:') === 0) {
38
+ return res.status(404).send({ success: false, message: err.message });
39
+ }
40
+ winston.error('DataTable ' + action + ': ', err);
41
+ return res.status(500).send({ success: false, error: 'Error ' + action });
42
+ }
43
+
44
+ // --- Tables ---
45
+
46
+ router.get('/', async function (req, res) {
47
+ try {
48
+ res.status(200).send(await dataTableService.listTables(req.projectid));
49
+ } catch (err) {
50
+ handleError(res, err, 'finding tables');
51
+ }
52
+ });
53
+
54
+ router.get('/:id', async function (req, res) {
55
+ try {
56
+ const table = await dataTableService.getTable(req.projectid, req.params.id);
57
+ if (!table) return res.status(404).send({ success: false, error: 'Table not found' });
58
+ res.status(200).send(table);
59
+ } catch (err) {
60
+ handleError(res, err, 'finding table');
61
+ }
62
+ });
63
+
64
+ router.post('/', async function (req, res) {
65
+ try {
66
+ const table = await dataTableService.createTable(
67
+ req.projectid,
68
+ req.body,
69
+ req.user.id || req.user._id
70
+ );
71
+ res.status(200).send(table);
72
+ } catch (err) {
73
+ handleError(res, err, 'creating table');
74
+ }
75
+ });
76
+
77
+ router.put('/:id', async function (req, res) {
78
+ try {
79
+ const table = await dataTableService.updateTable(req.projectid, req.params.id, req.body);
80
+ if (!table) return res.status(404).send({ success: false, error: 'Table not found' });
81
+ res.status(200).send(table);
82
+ } catch (err) {
83
+ handleError(res, err, 'updating table');
84
+ }
85
+ });
86
+
87
+ router.delete('/:id', async function (req, res) {
88
+ try {
89
+ const deleted = await dataTableService.deleteTable(req.projectid, req.params.id);
90
+ if (!deleted) return res.status(404).send({ success: false, error: 'Table not found' });
91
+ res.status(200).send({ success: true, message: 'Table deleted successfully' });
92
+ } catch (err) {
93
+ handleError(res, err, 'deleting table');
94
+ }
95
+ });
96
+
97
+ // --- Columns ---
98
+
99
+ router.post('/:id/columns', async function (req, res) {
100
+ try {
101
+ const table = await dataTableService.addColumn(req.projectid, req.params.id, req.body);
102
+ if (!table) return res.status(404).send({ success: false, error: 'Table not found' });
103
+ res.status(200).send(table);
104
+ } catch (err) {
105
+ handleError(res, err, 'adding column');
106
+ }
107
+ });
108
+
109
+ router.patch('/:id/columns/:columnId', async function (req, res) {
110
+ try {
111
+ const table = await dataTableService.renameColumn(
112
+ req.projectid,
113
+ req.params.id,
114
+ req.params.columnId,
115
+ req.body.name
116
+ );
117
+ if (!table) return res.status(404).send({ success: false, error: 'Table not found' });
118
+ res.status(200).send(table);
119
+ } catch (err) {
120
+ handleError(res, err, 'renaming column');
121
+ }
122
+ });
123
+
124
+ router.delete('/:id/columns/:columnId', async function (req, res) {
125
+ try {
126
+ const table = await dataTableService.deleteColumn(
127
+ req.projectid,
128
+ req.params.id,
129
+ req.params.columnId
130
+ );
131
+ if (!table) return res.status(404).send({ success: false, error: 'Table not found' });
132
+ res.status(200).send(table);
133
+ } catch (err) {
134
+ handleError(res, err, 'deleting column');
135
+ }
136
+ });
137
+
138
+ // --- Rows (insert / update / upsert / delete by id_row or conditions) ---
139
+
140
+ function getRowsListParams(req) {
141
+ var params = Object.assign({}, req.query);
142
+ if (req.body && typeof req.body === 'object' && !Array.isArray(req.body)) {
143
+ if (req.body.must_match !== undefined) params.must_match = req.body.must_match;
144
+ if (req.body.match !== undefined) params.match = req.body.match;
145
+ if (req.body.conditions !== undefined) params.conditions = req.body.conditions;
146
+ }
147
+ return params;
148
+ }
149
+
150
+ router.get('/:id/rows/list', async function (req, res) {
151
+
152
+ console.log("List rows")
153
+ try {
154
+ const rows = await dataTableService.listRowsWithFilter(
155
+ req.projectid,
156
+ req.params.id,
157
+ Object.assign({}, getRowsListParams(req), { sort: -1, limit: 200 })
158
+ );
159
+ if (rows === null) return res.status(404).send({ success: false, error: 'Table not found' });
160
+ res.status(200).send(rows);
161
+ } catch (err) {
162
+ handleError(res, err, 'listing rows');
163
+ }
164
+ });
165
+
166
+ router.post('/:id/row/insert', async function (req, res) {
167
+ console.log("Insert row")
168
+ try {
169
+ const row = await dataTableService.insertRowByBody(req.projectid, req.params.id, req.body);
170
+ if (!row) return res.status(404).send({ success: false, error: 'Table not found' });
171
+ res.status(200).send(row);
172
+ } catch (err) {
173
+ handleError(res, err, 'inserting row');
174
+ }
175
+ });
176
+
177
+ router.put('/:id/row/update', async function (req, res) {
178
+ try {
179
+ const row = await dataTableService.updateRowByBody(req.projectid, req.params.id, req.body);
180
+ if (row === null) return res.status(404).send({ success: false, error: 'Table not found' });
181
+ if (row === undefined) return res.status(404).send({ success: false, error: 'Row not found' });
182
+ res.status(200).send(row);
183
+ } catch (err) {
184
+ handleError(res, err, 'updating row');
185
+ }
186
+ });
187
+
188
+ router.put('/:id/row/upsert', async function (req, res) {
189
+ try {
190
+ const result = await dataTableService.upsertRowByBody(req.projectid, req.params.id, req.body);
191
+ if (result === null) return res.status(404).send({ success: false, error: 'Table not found' });
192
+ res.status(200).send(result);
193
+ } catch (err) {
194
+ if (err.message === 'Multiple rows match the conditions') {
195
+ return res.status(409).send({ success: false, message: err.message });
196
+ }
197
+ handleError(res, err, 'upserting row');
198
+ }
199
+ });
200
+
201
+ router.put('/:id/row/delete', async function (req, res) {
202
+ try {
203
+ const row = await dataTableService.deleteRowByBody(req.projectid, req.params.id, req.body);
204
+ if (row === null) return res.status(404).send({ success: false, error: 'Table not found' });
205
+ if (row === undefined) return res.status(404).send({ success: false, error: 'Row not found' });
206
+ res.status(200).send(row);
207
+ } catch (err) {
208
+ handleError(res, err, 'deleting row');
209
+ }
210
+ });
211
+
212
+ // --- Rows (REST) ---
213
+
214
+ // router.get('/:id/rows', async function (req, res) {
215
+ // try {
216
+ // const rows = await dataTableService.listRows(req.projectid, req.params.id);
217
+ // if (rows === null) return res.status(404).send({ success: false, error: 'Table not found' });
218
+ // res.status(200).send(rows);
219
+ // } catch (err) {
220
+ // handleError(res, err, 'finding rows');
221
+ // }
222
+ // });
223
+
224
+ // router.get('/:id/rows/:rowId', async function (req, res) {
225
+ // try {
226
+ // const row = await dataTableService.getRow(req.projectid, req.params.id, req.params.rowId);
227
+ // if (!row) return res.status(404).send({ success: false, error: 'Row not found' });
228
+ // res.status(200).send(row);
229
+ // } catch (err) {
230
+ // handleError(res, err, 'finding row');
231
+ // }
232
+ // });
233
+
234
+ // router.post('/:id/rows', async function (req, res) {
235
+ // try {
236
+ // const row = await dataTableService.insertRow(req.projectid, req.params.id, getRowPayload(req.body));
237
+ // if (!row) return res.status(404).send({ success: false, error: 'Table not found' });
238
+ // res.status(200).send(row);
239
+ // } catch (err) {
240
+ // handleError(res, err, 'inserting row');
241
+ // }
242
+ // });
243
+
244
+ // router.put('/:id/rows/:rowId', async function (req, res) {
245
+ // try {
246
+ // const row = await dataTableService.updateRow(
247
+ // req.projectid,
248
+ // req.params.id,
249
+ // req.params.rowId,
250
+ // getRowPayload(req.body)
251
+ // );
252
+ // if (row === null) return res.status(404).send({ success: false, error: 'Table not found' });
253
+ // if (row === undefined) return res.status(404).send({ success: false, error: 'Row not found' });
254
+ // res.status(200).send(row);
255
+ // } catch (err) {
256
+ // handleError(res, err, 'updating row');
257
+ // }
258
+ // });
259
+
260
+ // router.delete('/:id/rows/:rowId', async function (req, res) {
261
+ // try {
262
+ // const row = await dataTableService.deleteRow(req.projectid, req.params.id, req.params.rowId);
263
+ // if (!row) return res.status(404).send({ success: false, error: 'Row not found' });
264
+ // res.status(200).send(row);
265
+ // } catch (err) {
266
+ // handleError(res, err, 'deleting row');
267
+ // }
268
+ // });
269
+
270
+ // router.post('/:id/rows/search', async function (req, res) {
271
+ // try {
272
+ // const rows = await dataTableService.searchRows(req.projectid, req.params.id, req.body);
273
+ // if (rows === null) return res.status(404).send({ success: false, error: 'Table not found' });
274
+ // res.status(200).send(rows);
275
+ // } catch (err) {
276
+ // handleError(res, err, 'searching rows');
277
+ // }
278
+ // });
279
+
280
+ module.exports = router;
package/routes/faq_kb.js CHANGED
@@ -52,6 +52,9 @@ router.post('/', roleChecker.hasRole('admin'), async function (req, res) {
52
52
  }
53
53
 
54
54
  faqService.create(req.projectid, req.user.id, req.body).then((savedFaq_kb) => {
55
+ if (req.query.skip_activity !== 'true') {
56
+ botEvent.emit('faqbot.created', { req, chatbot: savedFaq_kb });
57
+ }
55
58
  res.status(200).send(savedFaq_kb);
56
59
  }).catch((err) => {
57
60
  res.status(500).send({ succes: false, error: err })
@@ -269,7 +272,7 @@ router.put('/:faq_kbid/publish', roleChecker.hasRole('admin'), async (req, res)
269
272
 
270
273
  try {
271
274
  // fork(id_faq_kb, api_url, token, project_id)
272
- let forked = await cs.fork(chatbot_id, api_url, token, current_project_id);
275
+ let forked = await cs.fork(chatbot_id, api_url, token, current_project_id, { forPublish: true });
273
276
  // winston.debug("forked: ", forked)
274
277
 
275
278
  let forkedChatBotId = forked.bot_id;
@@ -294,6 +297,13 @@ router.put('/:faq_kbid/publish', roleChecker.hasRole('admin'), async (req, res)
294
297
 
295
298
  botEvent.emit('faqbot.update', updatedOriginalChabot);
296
299
 
300
+ botEvent.emit('faqbot.publish', {
301
+ req: req,
302
+ chatbot: updatedOriginalChabot,
303
+ publishedBotId: forkedChatBotId,
304
+ release_note: release_note
305
+ });
306
+
297
307
  return res.status(200).send({ message: "Chatbot published successfully", bot_id: forkedChatBotId });
298
308
 
299
309
  } catch (e) {
@@ -355,6 +365,13 @@ router.put('/:faq_kbid', roleChecker.hasRoleOrTypes('admin', ['bot', 'subscripti
355
365
  }
356
366
 
357
367
  botEvent.emit('faqbot.update', updatedFaq_kb);
368
+
369
+ // A soft-delete is performed via PUT by setting trashed: true (the schema applies a TTL).
370
+ // Emit faqbot.deleted so the deletion is tracked just like the hard-delete endpoint.
371
+ if (req.body.trashed === true || req.body.trashed === 'true') {
372
+ botEvent.emit('faqbot.deleted', { req, chatbot: updatedFaq_kb });
373
+ }
374
+
358
375
  res.json(updatedFaq_kb);
359
376
  });
360
377
  });
@@ -460,6 +477,7 @@ router.delete('/:faq_kbid', roleChecker.hasRole('admin'), function (req, res) {
460
477
  * WARNING: faq_kb is the operation result, not the faq_kb object. The event subscriber will not receive the object as expected.
461
478
  */
462
479
  botEvent.emit('faqbot.delete', faq_kb);
480
+ botEvent.emit('faqbot.deleted', { req, chatbot: faq_kb });
463
481
  res.status(200).send({ success: true, message: "Chatbot with id " + req.params.faq_kbid + " deleted successfully" })
464
482
  });
465
483
  });
@@ -707,6 +725,10 @@ router.post('/fork/:id_faq_kb', roleChecker.hasRole('admin'), async (req, res) =
707
725
  return res.status(500).send({ success: false, message: "Unable to import intents in the new chatbot" });
708
726
  }
709
727
 
728
+ if (req.query.for_publish !== 'true') {
729
+ botEvent.emit('faqbot.created', { req, chatbot: savedChatbot, id_project: landing_project_id });
730
+ }
731
+
710
732
  return res.status(200).send({ message: "Chatbot forked successfully", bot_id: savedChatbot._id });
711
733
 
712
734
  })
@@ -774,6 +796,7 @@ router.post('/importjson/:id_faq_kb', roleChecker.hasRole('admin'), upload.singl
774
796
  })
775
797
 
776
798
  botEvent.emit('faqbot.create', savedChatbot);
799
+ botEvent.emit('faqbot.created', { req, chatbot: savedChatbot });
777
800
 
778
801
  if (json.intents) {
779
802
 
package/routes/kb.js CHANGED
@@ -894,7 +894,13 @@ router.delete('/deleteall', async (req, res) => {
894
894
 
895
895
  aiService.deleteNamespace(data).then((resp) => {
896
896
  winston.debug("delete namespace resp: ", resp.data);
897
- kbEvent.emit('kb.contents.delete', { req, namespace_id, project_id });
897
+ kbEvent.emit('kb.contents.delete', {
898
+ req,
899
+ namespace_id,
900
+ project_id,
901
+ namespace_name: namespace.name,
902
+ deleteMode: 'contents_only'
903
+ });
898
904
  res.status(200).send(resp.data);
899
905
  }).catch((err) => {
900
906
  winston.error("delete namespace err: ", err);
@@ -1443,7 +1449,14 @@ router.delete('/namespace/:id', async (req, res) => {
1443
1449
  })
1444
1450
  winston.debug("delete all contents response: ", deleteResponse);
1445
1451
 
1446
- kbEvent.emit('kb.contents.delete', { req, namespace_id, project_id, deletedCount: deleteResponse?.deletedCount });
1452
+ kbEvent.emit('kb.contents.delete', {
1453
+ req,
1454
+ namespace_id,
1455
+ project_id,
1456
+ namespace_name: namespace.name,
1457
+ deletedCount: deleteResponse?.deletedCount,
1458
+ deleteMode: 'contents_only'
1459
+ });
1447
1460
 
1448
1461
  return res.status(200).send({ success: true, message: "All contents deleted successfully" })
1449
1462
 
@@ -1485,6 +1498,14 @@ router.delete('/namespace/:id', async (req, res) => {
1485
1498
  })
1486
1499
  winston.debug("delete namespace response: ", deleteNamespaceResponse);
1487
1500
 
1501
+ kbEvent.emit('kb.namespace.delete', {
1502
+ req,
1503
+ namespace_id,
1504
+ project_id,
1505
+ namespace_name: namespace.name,
1506
+ deletedCount: deleteResponse?.deletedCount
1507
+ });
1508
+
1488
1509
  return res.status(200).send({ success: true, message: "Namespace deleted succesfully" })
1489
1510
 
1490
1511
  }).catch((err) => {
@@ -1757,6 +1778,18 @@ router.post('/', async (req, res) => {
1757
1778
  }
1758
1779
 
1759
1780
  aiManager.scheduleScrape([json], namespace.hybrid);
1781
+
1782
+ kbEvent.emit('kb.contents.add', {
1783
+ req,
1784
+ project_id: id_project,
1785
+ namespace_id: namespace_id,
1786
+ namespace_name: namespace.name,
1787
+ contentAddType: 'content',
1788
+ count: 1,
1789
+ type: saved_kb.type,
1790
+ source: saved_kb.source || saved_kb.name
1791
+ });
1792
+
1760
1793
  return res.status(200).send(raw_content);
1761
1794
 
1762
1795
  }
@@ -1825,6 +1858,14 @@ router.post('/multi', upload.single('uploadFile'), async (req, res) => {
1825
1858
 
1826
1859
  try {
1827
1860
  const result = await aiManager.addMultipleUrls(namespace, list, options);
1861
+ kbEvent.emit('kb.contents.add', {
1862
+ req,
1863
+ project_id: id_project,
1864
+ namespace_id: namespace_id,
1865
+ namespace_name: namespace.name,
1866
+ contentAddType: 'url_list',
1867
+ count: list.length
1868
+ });
1828
1869
  return res.status(200).send(result);
1829
1870
  } catch (err) {
1830
1871
  winston.error("addMultipleUrls error: ", err)
@@ -1931,6 +1972,16 @@ router.post('/csv', upload.single('uploadFile'), async (req, res) => {
1931
1972
  }
1932
1973
 
1933
1974
  aiManager.scheduleScrape(resources, hybrid);
1975
+
1976
+ kbEvent.emit('kb.contents.add', {
1977
+ req,
1978
+ project_id: project_id,
1979
+ namespace_id: namespace_id,
1980
+ namespace_name: namespace.name,
1981
+ contentAddType: 'csv',
1982
+ count: kbs.length
1983
+ });
1984
+
1934
1985
  return res.status(200).send(result);
1935
1986
 
1936
1987
  }).catch((err) => {
@@ -2068,6 +2119,18 @@ router.post('/sitemap/import', async (req, res) => {
2068
2119
  return res.status(200).send(result);
2069
2120
  }
2070
2121
  result.push(saved_content);
2122
+
2123
+ kbEvent.emit('kb.contents.add', {
2124
+ req,
2125
+ project_id: id_project,
2126
+ namespace_id: namespace_id,
2127
+ namespace_name: namespace.name,
2128
+ contentAddType: 'sitemap',
2129
+ count: urls.length,
2130
+ type: 'sitemap',
2131
+ source: source
2132
+ });
2133
+
2071
2134
  return res.status(200).send(result);
2072
2135
  } catch (err) {
2073
2136
  return res.status(500).send({ success: false, error: "Unable to add multiple urls from sitemap due to an error." });
@@ -2279,6 +2342,29 @@ router.delete('/:kb_id', async (req, res) => {
2279
2342
  data.engine = namespace.engine || default_engine;
2280
2343
  winston.verbose("/:delete_id data: ", data);
2281
2344
 
2345
+ const emitKbContentDelete = (deletedKb) => {
2346
+ const content = deletedKb || kb;
2347
+ const contentSnapshot = content.toObject ? content.toObject() : content;
2348
+ kbEvent.emit('kb.content.delete', {
2349
+ req,
2350
+ kb_id,
2351
+ project_id,
2352
+ namespace_id,
2353
+ namespace_name: namespace.name,
2354
+ kb: {
2355
+ _id: contentSnapshot._id,
2356
+ name: contentSnapshot.name,
2357
+ source: contentSnapshot.source,
2358
+ type: contentSnapshot.type
2359
+ }
2360
+ });
2361
+ };
2362
+
2363
+ if (process.env.NODE_ENV === 'test') {
2364
+ emitKbContentDelete(kb);
2365
+ return res.status(200).send({ success: true, message: "Content deleted successfully" });
2366
+ }
2367
+
2282
2368
  aiService.deleteIndex(data).then((resp) => {
2283
2369
  winston.debug("delete resp: ", resp.data);
2284
2370
  if (resp.data.success === true) {
@@ -2288,6 +2374,7 @@ router.delete('/:kb_id', async (req, res) => {
2288
2374
  winston.error("Delete kb error: ", err);
2289
2375
  return res.status(500).send({ success: false, error: err });
2290
2376
  }
2377
+ emitKbContentDelete(deletedKb);
2291
2378
  res.status(200).send(deletedKb);
2292
2379
  })
2293
2380
 
@@ -2303,6 +2390,7 @@ router.delete('/:kb_id', async (req, res) => {
2303
2390
  winston.verbose("Unable to delete the content in indexing status")
2304
2391
  return res.status(500).send({ success: false, error: "Unable to delete the content in indexing status" })
2305
2392
  } else {
2393
+ emitKbContentDelete(deletedKb);
2306
2394
  res.status(200).send(deletedKb);
2307
2395
  }
2308
2396
  })
@@ -18,6 +18,25 @@ var validtoken = require('../middleware/valid-token')
18
18
  var roleChecker = require('../middleware/has-role');
19
19
  const puEvent = require('../event/projectUserEvent');
20
20
  const { track } = require('../lib/analyticsClient');
21
+ const projectUserUpdateContextUtil = require('../utils/projectUserUpdateContextUtil');
22
+
23
+ function emitProjectUserDeleteActivity(req, project_user, deleteType) {
24
+ if (!project_user) {
25
+ return;
26
+ }
27
+ project_user.populate({ path: 'id_user', select: { firstname: 1, lastname: 1, email: 1 } }, function (populateErr, project_userPopulated) {
28
+ if (populateErr) {
29
+ winston.error('Error populating project_user for delete activity', populateErr);
30
+ }
31
+ const pu = project_userPopulated || project_user;
32
+ const payload = pu.toJSON ? pu.toJSON() : pu;
33
+ authEvent.emit('project_user.delete', {
34
+ req: req,
35
+ project_userPopulated: payload,
36
+ deleteType: deleteType
37
+ });
38
+ });
39
+ }
21
40
 
22
41
 
23
42
  router.post('/invite', [passport.authenticate(['basic', 'jwt'], { session: false }), validtoken, roleChecker.hasRole('admin')], function (req, res) {
@@ -111,15 +130,19 @@ router.post('/invite', [passport.authenticate(['basic', 'jwt'], { session: false
111
130
 
112
131
  emailService.sendYouHaveBeenInvited(email, req.user.firstname, req.user.lastname, req.project.name, id_project, user.firstname, user.lastname, req.body.role)
113
132
 
114
- updatedPuser.populate({path:'id_user', select:{'firstname':1, 'lastname':1, 'email': 1}},function (err, updatedPuserPopulated){
115
- var pu = updatedPuserPopulated.toJSON();
133
+ savedProject_user.populate({path:'id_user', select:{'firstname':1, 'lastname':1, 'email': 1}},function (err, savedProject_userPopulated){
134
+ if (err) {
135
+ winston.error("Error populating project user after re-invite", err);
136
+ return;
137
+ }
138
+ var pu = savedProject_userPopulated.toJSON();
116
139
  pu.isBusy = ProjectUserUtil.isBusy(savedProject_userPopulated, req.project.settings && req.project.settings.max_agent_assigned_chat);
117
- var eventData = {req:req, updatedPuserPopulated: pu};
140
+ var eventData = {req:req, savedProject_userPopulated: pu};
118
141
  winston.debug("eventData",eventData);
119
142
  authEvent.emit('project_user.invite', eventData);
120
143
  });
121
144
 
122
- return res.status(200).send(updatedPuser);
145
+ return res.status(200).send(savedProject_user);
123
146
  })
124
147
 
125
148
  } else {
@@ -220,6 +243,13 @@ router.put('/', [passport.authenticate(['basic', 'jwt'], { session: false }), va
220
243
  }
221
244
 
222
245
  const previousUserAvailable = req.projectuser.user_available;
246
+ const previousProfileStatus = req.projectuser.profileStatus;
247
+ const updateContext = projectUserUpdateContextUtil.buildProjectUserUpdateContext(
248
+ req,
249
+ previousUserAvailable,
250
+ previousProfileStatus,
251
+ projectUserUpdateContextUtil.resolveUserId(req.projectuser.id_user)
252
+ );
223
253
 
224
254
  Project_user.findByIdAndUpdate(req.projectuser.id, update, { new: true, upsert: true }, function (err, updatedProject_user) {
225
255
  if (err) {
@@ -230,7 +260,13 @@ router.put('/', [passport.authenticate(['basic', 'jwt'], { session: false }), va
230
260
  updatedProject_user.populate({ path:'id_user', select: { 'firstname': 1, 'lastname': 1 }}, function (err, updatedProject_userPopulated) {
231
261
  var pu = updatedProject_userPopulated.toJSON();
232
262
  pu.isBusy = ProjectUserUtil.isBusy(updatedProject_userPopulated, req.project.settings && req.project.settings.max_agent_assigned_chat);
233
- authEvent.emit('project_user.update', {updatedProject_userPopulated:pu, req: req, previousUserAvailable: previousUserAvailable});
263
+ authEvent.emit('project_user.update', {
264
+ updatedProject_userPopulated: pu,
265
+ req: req,
266
+ previousUserAvailable: previousUserAvailable,
267
+ previousProfileStatus: previousProfileStatus,
268
+ updateContext: updateContext
269
+ });
234
270
  });
235
271
 
236
272
  res.json(updatedProject_user);
@@ -286,7 +322,14 @@ router.put('/:project_userid', [passport.authenticate(['basic', 'jwt'], { sessio
286
322
 
287
323
  winston.debug("project_userid update", update);
288
324
 
289
- function _doUpdateProjectUser(previousUserAvailable) {
325
+ function _doUpdateProjectUser(previousUserAvailable, previousProfileStatus, targetUserId) {
326
+ const updateContext = projectUserUpdateContextUtil.buildProjectUserUpdateContext(
327
+ req,
328
+ previousUserAvailable,
329
+ previousProfileStatus,
330
+ targetUserId
331
+ );
332
+
290
333
  Project_user.findByIdAndUpdate(req.params.project_userid, update, { new: true, upsert: true }, function (err, updatedProject_user) {
291
334
  if (err) {
292
335
  winston.error("Error gettting project_user for update", err);
@@ -299,7 +342,13 @@ router.put('/:project_userid', [passport.authenticate(['basic', 'jwt'], { sessio
299
342
  var pu = updatedProject_userPopulated.toJSON();
300
343
  pu.isBusy = ProjectUserUtil.isBusy(updatedProject_user, req.project.settings && req.project.settings.max_agent_assigned_chat);
301
344
 
302
- authEvent.emit('project_user.update', {updatedProject_userPopulated:pu, req: req, previousUserAvailable: previousUserAvailable});
345
+ authEvent.emit('project_user.update', {
346
+ updatedProject_userPopulated: pu,
347
+ req: req,
348
+ previousUserAvailable: previousUserAvailable,
349
+ previousProfileStatus: previousProfileStatus,
350
+ updateContext: updateContext
351
+ });
303
352
  });
304
353
 
305
354
 
@@ -307,12 +356,16 @@ router.put('/:project_userid', [passport.authenticate(['basic', 'jwt'], { sessio
307
356
  });
308
357
  }
309
358
 
310
- if (update.user_available !== undefined && process.env.ANALYTICS_INGEST_URL) {
311
- Project_user.findById(req.params.project_userid, 'user_available').lean().exec(function(err, currentPu) {
312
- _doUpdateProjectUser(currentPu ? currentPu.user_available : null);
359
+ if (update.user_available !== undefined || update.profileStatus !== undefined) {
360
+ Project_user.findById(req.params.project_userid, 'user_available profileStatus id_user').lean().exec(function(err, currentPu) {
361
+ _doUpdateProjectUser(
362
+ currentPu ? currentPu.user_available : null,
363
+ currentPu ? currentPu.profileStatus : null,
364
+ currentPu ? currentPu.id_user : null
365
+ );
313
366
  });
314
367
  } else {
315
- _doUpdateProjectUser(null);
368
+ _doUpdateProjectUser(null, null, null);
316
369
  }
317
370
  });
318
371
 
@@ -340,7 +393,7 @@ router.delete('/:project_userid', [passport.authenticate(['basic', 'jwt'], { ses
340
393
  }
341
394
 
342
395
  puEvent.emit('project_user.deleted', project_user);
343
- // Event 'project_user.delete' not working - Check it and improve it to manage soft/hard delete
396
+ emitProjectUserDeleteActivity(req, project_user, 'soft');
344
397
  return res.status(200).send(project_user);
345
398
 
346
399
  })
@@ -360,11 +413,7 @@ router.delete('/:project_userid', [passport.authenticate(['basic', 'jwt'], { ses
360
413
 
361
414
  winston.debug("Hard deleted project_user", project_user);
362
415
 
363
- if (project_user) {
364
- project_user.populate({ path: 'id_user', select: { 'firstname': 1, 'lastname': 1 } }, function (err, project_userPopulated) {
365
- authEvent.emit('project_user.delete', { req: req, project_userPopulated: project_userPopulated });
366
- });
367
- }
416
+ emitProjectUserDeleteActivity(req, project_user, 'hard');
368
417
 
369
418
  puEvent.emit('project_user.deleted', project_user);
370
419
  return res.status(200).send(project_user);