@tiledesk/tiledesk-server 2.2.39 → 2.3.1-8.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (93) hide show
  1. package/CHANGELOG.md +121 -0
  2. package/LICENSE +14 -657
  3. package/README.md +17 -3
  4. package/app.js +21 -60
  5. package/channels/chat21/chat21Handler.js +18 -3
  6. package/channels/chat21/chat21WebHook.js +31 -15
  7. package/channels/chat21/package-lock.json +663 -706
  8. package/channels/chat21/package.json +2 -2
  9. package/deploy.sh +2 -0
  10. package/event/botEvent.js +1 -1
  11. package/event/subscriptionEvent.js +11 -0
  12. package/fonts/Roboto-Italic.ttf +0 -0
  13. package/fonts/Roboto-Medium.ttf +0 -0
  14. package/fonts/Roboto-MediumItalic.ttf +0 -0
  15. package/fonts/Roboto-Regular.ttf +0 -0
  16. package/middleware/ipFilter.js +220 -0
  17. package/middleware/passport.js +11 -2
  18. package/models/lead.js +2 -0
  19. package/models/project.js +10 -0
  20. package/models/project_user.js +4 -0
  21. package/models/request.js +50 -12
  22. package/models/subscriptionLog.js +34 -0
  23. package/models/tagLibrary.js +42 -0
  24. package/package.json +6 -12
  25. package/pubmodules/activities/activityArchiver.js +314 -0
  26. package/pubmodules/activities/index.js +3 -0
  27. package/pubmodules/activities/models/activity.js +88 -0
  28. package/pubmodules/activities/routes/activity.js +710 -0
  29. package/pubmodules/activities/test/activityRoute.js +85 -0
  30. package/pubmodules/analytics/analytics.js +1719 -0
  31. package/pubmodules/analytics/index.js +3 -0
  32. package/pubmodules/canned/cannedResponse.js +55 -0
  33. package/pubmodules/canned/cannedResponseRoute.js +163 -0
  34. package/pubmodules/canned/index.js +3 -0
  35. package/pubmodules/emailNotification/requestNotification.js +215 -28
  36. package/pubmodules/events/eventRoute.js +37 -7
  37. package/pubmodules/messageActions/messageActionsInterceptor.js +4 -2
  38. package/pubmodules/pubModulesManager.js +129 -5
  39. package/pubmodules/rasa/listener.js +5 -5
  40. package/pubmodules/rules/conciergeBot.js +4 -4
  41. package/pubmodules/scheduler/tasks/closeAgentUnresponsiveRequestTask.js +3 -1
  42. package/pubmodules/scheduler/tasks/closeBotUnresponsiveRequestTask.js +3 -1
  43. package/pubmodules/tilebot/index.js +11 -0
  44. package/pubmodules/tilebot/listener.js +69 -0
  45. package/pubmodules/trigger/default.js +271 -0
  46. package/pubmodules/trigger/event/actionEventEmitter.js +10 -0
  47. package/pubmodules/trigger/event/flowEventEmitter.js +10 -0
  48. package/pubmodules/trigger/event/triggerEventEmitter.js +10 -0
  49. package/pubmodules/trigger/index.js +3 -0
  50. package/pubmodules/trigger/models/trigger.js +149 -0
  51. package/pubmodules/trigger/rulesTrigger.js +1181 -0
  52. package/pubmodules/trigger/start.js +118 -0
  53. package/pubmodules/trigger/triggerRoute.js +150 -0
  54. package/routes/auth.js +7 -2
  55. package/routes/department.js +51 -0
  56. package/routes/faq.js +7 -0
  57. package/routes/faq_kb.js +1 -1
  58. package/routes/group.js +140 -0
  59. package/routes/lead.js +24 -1
  60. package/routes/message.js +6 -3
  61. package/routes/project.js +118 -0
  62. package/routes/project_user.js +9 -0
  63. package/routes/public-request.js +280 -2
  64. package/routes/request.js +122 -16
  65. package/routes/subscription.js +140 -0
  66. package/routes/tag.js +138 -0
  67. package/routes/user-request.js +3 -2
  68. package/routes/users.js +1 -1
  69. package/routes/widget.js +80 -3
  70. package/routes/widgetLoader.js +31 -0
  71. package/services/banUserNotifier.js +86 -0
  72. package/services/emailService.js +189 -11
  73. package/services/faqService.js +2 -2
  74. package/services/geoService.js +30 -4
  75. package/services/leadService.js +2 -0
  76. package/services/modulesManager.js +7 -188
  77. package/services/requestService.js +364 -6
  78. package/services/subscriptionNotifier.js +485 -0
  79. package/template/email/assignedEmailMessage.html +1 -1
  80. package/template/email/assignedRequest.html +1 -1
  81. package/template/email/newMessage.html +1 -1
  82. package/template/email/newMessageFollower.html +236 -0
  83. package/template/email/passwordChanged.html +1 -1
  84. package/template/email/pooledEmailMessage.html +1 -1
  85. package/template/email/pooledRequest.html +1 -1
  86. package/template/email/resetPassword.html +2 -2
  87. package/template/email/ticket.html +1 -1
  88. package/test/cannedRoute.js +166 -0
  89. package/test/messageRoute.js +69 -0
  90. package/test/requestService.js +3 -1
  91. package/utils/orgUtil.js +3 -3
  92. package/views/messages.jade +2 -2
  93. package/websocket/webSocketServer.js +23 -5
package/README.md CHANGED
@@ -9,11 +9,23 @@
9
9
 
10
10
  # Introduction
11
11
 
12
- Tiledesk-server is the server engine of Tiledesk. Tiledesk is an Open Source Live Chat platform with integrated ChatBot written in NodeJs and Express. Build your own customer support with a multi-channel platform for Web, Android and iOS. More info here https://www.tiledesk.com.
12
+ Tiledesk-server is the server engine of Tiledesk. Tiledesk is an Open Source Live Chat platform with integrated Chatbots written in NodeJs and Express. Build your own customer support with a multi-channel platform for Web, Android and iOS.
13
13
 
14
- You can find more info here: https://developer.tiledesk.com
14
+ Designed to be open source since the beginning, we actively worked on it to create a totally new, first class customer service platform based on instant messaging.
15
15
 
16
- # Prerequisites
16
+ What is Tiledesk today? It became the open source “conversational app development” platform that everyone needs 😌
17
+
18
+ You can use Tiledesk to increase sales for your website or for post-sales customer service. Every conversation can be automated using our first class native chatbot technology.
19
+ You can also connect your own applications using our APIs or Webhooks.
20
+ Moreover you can deploy entire visual applications inside a conversation. And your applications can converse with your chatbots or your end-users! We know this is cool 😎
21
+
22
+ Tiledesk is multichannel in a totally new way. You can write your chatbot scripts with images, buttons and other cool elements that your channels support. But you will configureyour chatbot replies only once. They will run on every channel, auto-adapting the responses to the target channel whatever it is, Whatsapp, Facebook Messenger, Telegram etc.
23
+
24
+ More info on Tiledesk website: https://www.tiledesk.com.
25
+
26
+ You can find technical documentation here: https://developer.tiledesk.com
27
+
28
+ # Prerequisites for Installation
17
29
 
18
30
  * [Nodejs](https://www.npmjs.com/) and npm installed. Suggested versions are NodeJS 12.20.2 and NPM 6.14.11
19
31
  * [MongoDb](https://www.mongodb.com) installed
@@ -80,6 +92,8 @@ Deploy with button:
80
92
 
81
93
  [![Deploy](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy?template=https://github.com/Tiledesk/tiledesk-server)
82
94
 
95
+ # Community? Questions? Support ?
96
+ If you need help or just want to hang out, come, say hi on our [<img width="15" alt="Tiledesk discord" src="https://seeklogo.com/images/D/discord-color-logo-E5E6DFEF80-seeklogo.com.png"> Discord](https://discord.gg/nERZEZ7SmG) server.
83
97
 
84
98
  # REST API
85
99
 
package/app.js CHANGED
@@ -87,6 +87,9 @@ var lead = require('./routes/lead');
87
87
  var message = require('./routes/message');
88
88
  var messagesRootRoute = require('./routes/messagesRoot');
89
89
  var department = require('./routes/department');
90
+ var group = require('./routes/group');
91
+ var resthook = require('./routes/subscription');
92
+ var tag = require('./routes/tag');
90
93
  var faq = require('./routes/faq');
91
94
  var faq_kb = require('./routes/faq_kb');
92
95
  var project = require('./routes/project');
@@ -124,6 +127,9 @@ var RouterLogger = require('./models/routerLogger');
124
127
 
125
128
  require('./services/mongoose-cache-fn')(mongoose);
126
129
 
130
+ var subscriptionNotifier = require('./services/subscriptionNotifier');
131
+ subscriptionNotifier.start();
132
+
127
133
  var botSubscriptionNotifier = require('./services/BotSubscriptionNotifier');
128
134
  botSubscriptionNotifier.start();
129
135
 
@@ -140,10 +146,10 @@ pubModulesManager.init({express:express, mongoose:mongoose, passport:passport, d
140
146
  var channelManager = require('./channels/channelManager');
141
147
  channelManager.listen();
142
148
 
143
- const ipfilter = require('express-ipfilter').IpFilter
144
- // const IpDeniedError = require('express-ipfilter').IpDeniedError;
145
-
149
+ var IPFilter = require('./middleware/ipFilter');
146
150
 
151
+ var BanUserNotifier = require('./services/banUserNotifier');
152
+ BanUserNotifier.listen();
147
153
 
148
154
  var modulesManager = undefined;
149
155
  try {
@@ -170,7 +176,6 @@ if (process.env.CREATE_INITIAL_DATA !== "false") {
170
176
 
171
177
 
172
178
 
173
-
174
179
  var app = express();
175
180
 
176
181
 
@@ -331,57 +336,6 @@ var projectSetter = function (req, res, next) {
331
336
  }
332
337
 
333
338
 
334
- function customDetection (req) {
335
- // const ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress;
336
- const ip = (req.headers['x-forwarded-for'] || '').split(',').pop().trim() || //https://stackoverflow.com/questions/8107856/how-to-determine-a-users-ip-address-in-node
337
- req.socket.remoteAddress
338
-
339
- winston.info("standard ip: "+ip); // ip address of the user
340
- return ip;
341
- }
342
-
343
-
344
- var projectIpFilter = function (req, res, next) {
345
- // var projectIpFilter = function (err, req, res, next) {
346
-
347
- // var ip = require('ip');
348
- // winston.info("projectIpFilter ip2: " + ip.address() );
349
-
350
-
351
- const nextIp = function(err) {
352
- winston.info("projectIpFilter next",err);
353
-
354
- if (err && err.name === "IpDeniedError") {
355
- winston.info("IpDeniedError");
356
- return res.status(401).json({ err: "error project ip filter" });
357
- // next(err)
358
- }
359
-
360
- next();
361
-
362
- }
363
-
364
-
365
- if (!req.project) {
366
- return next();
367
- }
368
-
369
- var projectIpFilterEnabled = req.project.ipFilterEnabled;
370
- winston.debug("project projectIpFilterEnabled: " +projectIpFilterEnabled)
371
-
372
- var projectIpFilter = req.project.ipFilter
373
- winston.debug("project ipFilter: " + projectIpFilter)
374
-
375
- if (projectIpFilterEnabled === true && projectIpFilter && projectIpFilter.length > 0) {
376
- var ip = ipfilter(projectIpFilter, { detectIp: customDetection, mode: 'allow' })
377
- // var ip = ipfilter(projectIpFilter, { mode: 'allow' })
378
- ip(req, res, nextIp);
379
- } else {
380
- next();
381
- }
382
-
383
- }
384
-
385
339
 
386
340
 
387
341
  // app.use('/admin', admin);
@@ -398,6 +352,8 @@ app.use('/auth', auth);
398
352
  app.use('/testauth', [passport.authenticate(['basic', 'jwt'], { session: false }), validtoken], authtest);
399
353
 
400
354
  app.use('/widgets', widgetsLoader);
355
+ app.use('/w', widgetsLoader);
356
+
401
357
  app.use('/images', images);
402
358
  app.use('/files', files);
403
359
  app.use('/urls', urls);
@@ -425,8 +381,7 @@ if (modulesManager) {
425
381
  modulesManager.use(app);
426
382
  }
427
383
 
428
-
429
- app.use('/:projectid/', [projectIdSetter, projectSetter, projectIpFilter]);
384
+ app.use('/:projectid/', [projectIdSetter, projectSetter, IPFilter.projectIpFilter, IPFilter.projectIpFilterDeny, IPFilter.decodeJwt, IPFilter.projectBanUserFilter]);
430
385
 
431
386
 
432
387
  app.use('/:projectid/authtestWithRoleCheck', [passport.authenticate(['basic', 'jwt'], { session: false }), validtoken], authtestWithRoleCheck);
@@ -441,11 +396,17 @@ app.use('/:projectid/departments', department);
441
396
 
442
397
 
443
398
 
399
+
400
+
444
401
  channelManager.useUnderProjects(app);
445
402
 
403
+ app.use('/:projectid/groups', [passport.authenticate(['basic', 'jwt'], { session: false }), validtoken, roleChecker.hasRole('agent')], group);
404
+ app.use('/:projectid/tags', [passport.authenticate(['basic', 'jwt'], { session: false }), validtoken, roleChecker.hasRole('agent')], tag);
405
+ app.use('/:projectid/subscriptions', [passport.authenticate(['basic', 'jwt'], { session: false }), validtoken, roleChecker.hasRole('admin')], resthook);
406
+
446
407
  //deprecated
447
- app.use('/:projectid/faq', [passport.authenticate(['basic', 'jwt'], { session: false }), validtoken, roleChecker.hasRole('agent')], faq);
448
- app.use('/:projectid/intents', [passport.authenticate(['basic', 'jwt'], { session: false }), validtoken, roleChecker.hasRole('agent')], faq);
408
+ app.use('/:projectid/faq', [passport.authenticate(['basic', 'jwt'], { session: false }), validtoken, roleChecker.hasRoleOrTypes('agent', ['bot','subscription'])], faq);
409
+ app.use('/:projectid/intents', [passport.authenticate(['basic', 'jwt'], { session: false }), validtoken, roleChecker.hasRoleOrTypes('agent', ['bot','subscription'])], faq);
449
410
 
450
411
  //Deprecated??
451
412
  app.use('/:projectid/faqpub', faqpub);
@@ -528,7 +489,7 @@ app.use(function (err, req, res, next) {
528
489
  // error handler
529
490
  app.use((err, req, res, next) => {
530
491
 
531
- winston.info("err.name", err.name)
492
+ winston.debug("err.name", err.name)
532
493
  if (err.name === "IpDeniedError") {
533
494
  winston.info("IpDeniedError");
534
495
  return res.status(401).json({ err: "error ip filter" });
@@ -246,7 +246,18 @@ class Chat21Handler {
246
246
  });
247
247
 
248
248
 
249
+ messageEvent.on('message.test', function(message) {
250
+
251
+ winston.info("Chat21Sender message.test");
252
+
253
+ chat21.auth.setAdminToken(adminToken);
249
254
 
255
+ return chat21.messages.sendToGroup(message.senderFullname, message.recipient,
256
+ message.recipient_fullname, message.text, message.sender, message.attributes, message.type, message.metadata, message.timestamp, message.group)
257
+ .then(function(data){
258
+ winston.info("Chat21Sender sendToGroup test: "+ JSON.stringify(data));
259
+ });
260
+ });
250
261
 
251
262
 
252
263
  messageEvent.on('message.sending', function(message) {
@@ -299,7 +310,8 @@ class Chat21Handler {
299
310
  }
300
311
 
301
312
  var recipient_fullname = "Guest";
302
- // TODO qui va message.recipient_fullname ma nn c'è
313
+ // guest_here
314
+
303
315
  if (message.request && message.request.lead && message.request.lead.fullname) {
304
316
  recipient_fullname = message.request.lead.fullname;
305
317
  }
@@ -332,6 +344,7 @@ class Chat21Handler {
332
344
  }
333
345
  */
334
346
 
347
+
335
348
  return chat21.messages.sendToGroup(message.senderFullname, message.recipient,
336
349
  recipient_fullname, message.text, message.sender, attributes, message.type, message.metadata, timestamp)
337
350
  .then(function(data){
@@ -339,7 +352,7 @@ class Chat21Handler {
339
352
 
340
353
 
341
354
  // chat21.conversations.stopTyping(message.recipient,message.sender);
342
-
355
+
343
356
  chat21Event.emit('message.sent', data);
344
357
 
345
358
  messageService.changeStatus(message._id, MessageConstants.CHAT_MESSAGE_STATUS.DELIVERED) .then(function(upMessage){
@@ -563,13 +576,15 @@ class Chat21Handler {
563
576
  var groupId = request.request_id;
564
577
 
565
578
  var group_name = "Guest";
566
-
579
+ // guest_here
580
+
567
581
  if (request.lead && request.lead.fullname) {
568
582
  group_name = request.lead.fullname;
569
583
  }
570
584
  if (request.subject) {
571
585
  group_name = request.subject;
572
586
  }
587
+
573
588
  //TODO racecondition?
574
589
  return chat21.groups.create(group_name, members, gAttributes, groupId).then(function(data) {
575
590
  winston.verbose("Chat21 group created: " + JSON.stringify(data));
@@ -201,12 +201,16 @@ router.post('/', function (req, res) {
201
201
  return winston.error("project_user not found with query: ", queryProjectUser);
202
202
  }
203
203
 
204
+
205
+
206
+
204
207
 
205
208
  var new_request = {
206
209
  request_id: message.recipient, project_user_id:project_user_id, lead_id:createdLead._id, id_project:projectid, first_text:message.text,
207
210
  departmentid:departmentid, sourcePage:sourcePage, language:language, userAgent:client, status:requestStatus, createdBy: undefined,
208
211
  attributes:rAttributes, subject:undefined, preflight:false, channel:undefined, location:undefined,
209
212
  lead:createdLead, requester:project_user
213
+
210
214
  };
211
215
 
212
216
  winston.debug("new_request", new_request);
@@ -226,10 +230,10 @@ router.post('/', function (req, res) {
226
230
  // upsert(id, sender, senderFullname, recipient, text, id_project, createdBy, status, attributes, type, metadata, language)
227
231
  return messageService.upsert(messageId, message.sender, message.sender_fullname, message.recipient, message.text,
228
232
  projectid, null, MessageConstants.CHAT_MESSAGE_STATUS.RECEIVED, message.attributes, message.type, message.metadata, language).then(function(savedMessage){
229
-
230
- return requestService.incrementMessagesCountByRequestId(savedRequest.request_id, savedRequest.id_project).then(function(savedRequestWithIncrement) {
231
- return res.json(savedRequestWithIncrement);
232
- });
233
+ return res.json(savedRequest);
234
+ // return requestService.incrementMessagesCountByRequestId(savedRequest.request_id, savedRequest.id_project).then(function(savedRequestWithIncrement) {
235
+ // return res.json(savedRequestWithIncrement);
236
+ // });
233
237
 
234
238
 
235
239
  }).catch(function (err) {
@@ -286,23 +290,25 @@ router.post('/', function (req, res) {
286
290
 
287
291
  // TOOD update also request attributes and sourcePage
288
292
 
289
- return requestService.incrementMessagesCountByRequestId(request.request_id, request.id_project).then(function(savedRequest) {
293
+ // return requestService.incrementMessagesCountByRequestId(request.request_id, request.id_project).then(function(savedRequest) {
290
294
  // winston.debug("savedRequest.participants.indexOf(message.sender)", savedRequest.participants.indexOf(message.sender));
291
295
 
292
296
  // TODO it doesn't work for internal requests bacause participanets == message.sender⁄
293
- if (savedRequest.participants && savedRequest.participants.indexOf(message.sender) > -1) { //update waiitng time if write an agent (member of participants)
297
+ if (request.participants && request.participants.indexOf(message.sender) > -1) { //update waiitng time if write an agent (member of participants)
294
298
  winston.debug("updateWaitingTimeByRequestId");
299
+
295
300
  return requestService.updateWaitingTimeByRequestId(request.request_id, request.id_project).then(function(upRequest) {
296
301
  return res.json(upRequest);
297
302
  });
298
303
  }else {
299
- return res.json(savedRequest);
304
+
305
+ return res.json(savedMessage);
300
306
  }
301
- });
302
- }).catch(function(err){
303
- winston.error("Error creating message", {err: err, message: message});
304
- return res.status(500).send({success: false, msg: 'Error creating message', err:err });
305
- });
307
+ // });
308
+ }).catch(function(err){
309
+ winston.error("Error creating chat21 webhook message: "+ JSON.stringify({err: err, message: message}));
310
+ return res.status(500).send({success: false, msg: 'Error creating message', err:err });
311
+ });
306
312
 
307
313
 
308
314
 
@@ -398,7 +404,9 @@ router.post('/', function (req, res) {
398
404
  // winston.debug('updatedParticipantsRequest', updatedParticipantsRequest);
399
405
  // manca id
400
406
 
401
- return requestService.closeRequestByRequestId(recipient_id, projectId).then(function(updatedStatusRequest) {
407
+ // closeRequestByRequestId(request_id, id_project, skipStatsUpdate, notify, closed_by)
408
+ const closed_by = user_id;
409
+ return requestService.closeRequestByRequestId(recipient_id, projectId, false, true,closed_by ).then(function(updatedStatusRequest) {
402
410
 
403
411
  winston.debug('updatedStatusRequest', updatedStatusRequest.toObject());
404
412
  return res.json(updatedStatusRequest);
@@ -532,7 +540,7 @@ router.post('/', function (req, res) {
532
540
  });
533
541
  }
534
542
 
535
- else if (req.body.event_type == "deleted-archivedconversation") {
543
+ else if (req.body.event_type == "deleted-archivedconversation" || req.body.event_type == "conversation-unarchived") {
536
544
 
537
545
  winston.debug("event_type","deleted-archivedconversation");
538
546
 
@@ -544,7 +552,7 @@ router.post('/', function (req, res) {
544
552
  }
545
553
 
546
554
 
547
- var conversation = req.body.data;
555
+ var conversation = req.body.data;
548
556
  // winston.debug("conversation",conversation);
549
557
 
550
558
  var user_id = req.body.user_id;
@@ -561,16 +569,24 @@ router.post('/', function (req, res) {
561
569
  return res.status(400).send({success: false, msg: "not a support conversation" });
562
570
  }
563
571
 
572
+
573
+
564
574
  if (user_id!="system"){
565
575
  winston.debug("not a system conversation");
566
576
  return res.status(400).send({success: false, msg: "not a system conversation" });
567
577
  }
568
578
 
569
579
 
580
+
581
+ // scrivo... nuova viene popolato projectid in attributes poi chiudo ed in archived c'è projectid
582
+ // quando scrivo viene cancellato archived e nuovo messaggio crea conv ma senza project id... lineare che è cosi
583
+ // si verifica solo se admin (da ionic ) archivia di nuovo senza che widget abbia scritto nulla (widget risetta projectid in properties)
584
+
570
585
  var id_project;
571
586
  if (conversation && conversation.attributes) {
572
587
  id_project = conversation.attributes.projectId;
573
588
  }else {
589
+ winston.debug( "not a support deleting archived conversation" );
574
590
  return res.status(400).send({success: false, msg: "not a support deleting archived conversation" });
575
591
  }
576
592
  winston.debug("id_project", id_project);