@tiledesk/tiledesk-server 2.1.41 → 2.2.4

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.
Files changed (85) hide show
  1. package/.circleci/config.yml +54 -0
  2. package/.env.sample +1 -1
  3. package/.github/workflows/docker-community-push-latest.yml +22 -0
  4. package/.github/workflows/{docker-image-push.yml → docker-image-en-tag-push.yml} +1 -1
  5. package/.github/workflows/docker-image-tag-community-tag-push.yml +21 -0
  6. package/.github/workflows/{docker-push-latest.yml → docker-push-en-push-latest.yml} +1 -1
  7. package/CHANGELOG.md +198 -1
  8. package/Dockerfile +1 -1
  9. package/Dockerfile-en +1 -1
  10. package/README.md +5 -7
  11. package/app.js +12 -1
  12. package/channels/chat21/chat21Contact.js +34 -8
  13. package/channels/chat21/chat21Handler.js +48 -5
  14. package/channels/chat21/chat21WebHook.js +34 -5
  15. package/channels/chat21/nativeauth.js +2 -2
  16. package/config/email.js +2 -1
  17. package/config/global.js +3 -0
  18. package/config/labels/widget.json +170 -16
  19. package/event/messageEvent.js +18 -1
  20. package/middleware/passport.js +10 -4
  21. package/models/actionsConstants.js +7 -0
  22. package/models/department.js +3 -0
  23. package/models/faq.js +8 -2
  24. package/models/faq_kb.js +6 -0
  25. package/models/message.js +10 -4
  26. package/models/messageConstants.js +3 -3
  27. package/models/request.js +33 -3
  28. package/package.json +31 -28
  29. package/pubmodules/emailNotification/requestNotification.js +380 -62
  30. package/pubmodules/messageActions/messageActionsInterceptor.js +20 -7
  31. package/pubmodules/messageTransformer/index.js +1 -1
  32. package/pubmodules/messageTransformer/microLanguageAttributesTransformerInterceptor.js +67 -0
  33. package/pubmodules/pubModulesManager.js +66 -14
  34. package/pubmodules/rules/conciergeBot.js +81 -49
  35. package/routes/auth.js +34 -10
  36. package/routes/campaigns.js +117 -25
  37. package/routes/faq.js +19 -0
  38. package/routes/faq_kb.js +13 -4
  39. package/routes/faqpub.js +1 -1
  40. package/routes/images.js +1 -1
  41. package/routes/jwt.js +0 -1
  42. package/routes/logs.js +26 -0
  43. package/routes/message.js +7 -2
  44. package/routes/messagesRoot.js +73 -16
  45. package/routes/project_user.js +36 -1
  46. package/routes/request.js +88 -12
  47. package/routes/requestUtilRoot.js +30 -0
  48. package/routes/urls.js +12 -0
  49. package/routes/users.js +5 -1
  50. package/services/BotSubscriptionNotifier.js +1 -0
  51. package/services/departmentService.js +29 -5
  52. package/services/emailService.js +1103 -298
  53. package/services/faqBotHandler.js +176 -61
  54. package/services/faqBotSupport.js +181 -117
  55. package/services/faqService.js +17 -14
  56. package/services/messageService.js +57 -9
  57. package/services/modulesManager.js +86 -23
  58. package/services/requestService.js +58 -17
  59. package/template/email/assignedEmailMessage.html +205 -0
  60. package/template/email/assignedRequest.html +44 -14
  61. package/template/email/beenInvitedExistingUser.html +2 -2
  62. package/template/email/beenInvitedNewUser.html +1 -1
  63. package/template/email/newMessage.html +31 -12
  64. package/template/email/passwordChanged.html +2 -3
  65. package/template/email/pooledEmailMessage.html +208 -0
  66. package/template/email/pooledRequest.html +41 -14
  67. package/template/email/resetPassword.html +2 -3
  68. package/template/email/sendTranscript.html +1 -1
  69. package/template/email/test.html +1 -1
  70. package/template/email/ticket.html +78 -52
  71. package/template/email/ticket.txt +5 -1
  72. package/template/email/verify.html +1 -1
  73. package/test/authentication.js +76 -4
  74. package/test/authenticationJwt.js +76 -2
  75. package/test/campaignsRoute.js +226 -0
  76. package/test/faqService.js +3 -3
  77. package/test/faqkbRoute.js +3 -2
  78. package/test/messageRootRoute.js +193 -0
  79. package/test/messageRoute.js +75 -0
  80. package/test/messageService.js +5 -5
  81. package/test/requestRoute.js +27 -9
  82. package/test/requestService.js +472 -11
  83. package/test-int/bot.js +673 -8
  84. package/websocket/webSocketServer.js +7 -4
  85. package/template/email/ticket-taking.txt +0 -7
@@ -1,9 +1,8 @@
1
1
  var express = require('express');
2
2
  var router = express.Router();
3
- var Lead = require("../models/lead");
4
- var LeadConstants = require("../models/leadConstants");
3
+ var Group = require("../models/group");
4
+ var User = require("../models/user");
5
5
  var winston = require('../config/winston');
6
- var leadService = require("../services/leadService");
7
6
  var requestService = require("../services/requestService");
8
7
  var messageService = require("../services/messageService");
9
8
  var MessageConstants = require("../models/messageConstants");
@@ -12,13 +11,6 @@ const uuidv4 = require('uuid/v4');
12
11
 
13
12
 
14
13
 
15
- // curl -v -X POST -H 'Content-Type:application/json' -u andrea.leo@f21.it:123456 -d '{"text":"ciao"}' http://localhost:3000/5f897142c9e7ad9602a744c9/campaigns/
16
- // curl -v -X POST -H 'Content-Type:application/json' -u andrea.leo@f21.it:123456 -d '{"text":"ciao", "leadid":"213213221"}' http://localhost:3000/5f897142c9e7ad9602a744c9/campaigns/
17
-
18
-
19
- // curl -v -X POST -H 'Content-Type:application/json' -u andrea.leo@frontiere21.it:258456 -d '{"text":"ciao", "leadid":"5f8972c82db41c003473cb03"}' https://tiledesk-server-pre.herokuapp.com/5f86c201189063003453a045/campaigns/
20
- // curl -v -X POST -H 'Content-Type:application/json' -u andrea.leo@frontiere21.it:258456 -d '{"text":"ciao", "leadid":"5f8972c82db41c003473cb03", "request_id":"group-123456789112233"}' https://tiledesk-server-pre.herokuapp.com/5f86c201189063003453a045/campaigns/
21
-
22
14
 
23
15
  // this endpoint supports support-group- or groups. this create a conversation for the sender (agent console)
24
16
  router.post('/', function (req, res) {
@@ -27,43 +19,143 @@ router.post('/', function (req, res) {
27
19
 
28
20
  winston.debug(req.body);
29
21
  winston.debug("req.user", req.user);
30
- var request_id = req.body.request_id || 'support-group-'+uuidv4();
31
-
22
+ var request_id = req.body.request_id || 'support-group-' + req.projectid + "-" + uuidv4();
23
+
24
+ // TODO cicla su segment
25
+
26
+
32
27
  // createWithIdAndRequester(request_id, project_user_id, lead_id, id_project, first_text, departmentid, sourcePage, language, userAgent, status, createdBy, attributes, subject, preflight, channel) {
33
- return requestService.createWithIdAndRequester(request_id, req.projectuser._id, req.body.leadid, req.projectid,
34
- req.body.text, req.body.departmentid, req.body.sourcePage,
28
+
29
+ //TODO USE NEW requestService.create()
30
+ return requestService.createWithIdAndRequester(request_id, req.projectuser._id, req.body.leadid, req.projectid,
31
+ req.body.text, req.body.departmentid, req.body.sourcePage,
35
32
  req.body.language, req.body.userAgent, null, req.user._id, req.body.attributes, req.body.subject, true, req.body.channel).then(function (savedRequest) {
36
33
 
37
34
  winston.info("savedRequest", savedRequest);
38
35
 
39
36
  // create(sender, senderFullname, recipient, text, id_project, createdBy, status, attributes, type, metadata, language, channel_type) {
40
37
  return messageService.create(req.body.sender || req.user._id, req.body.senderFullname || req.user.fullName, savedRequest.request_id, req.body.text,
41
- req.projectid, req.user._id, messageStatus, req.body.attributes, req.body.type, req.body.metadata, req.body.language, MessageConstants.CHANNEL_TYPE.DIRECT, req.body.channel).then(function(savedMessage){
38
+ req.projectid, req.user._id, messageStatus, req.body.attributes, req.body.type, req.body.metadata, req.body.language, MessageConstants.CHANNEL_TYPE.DIRECT, req.body.channel).then(function (savedMessage) {
42
39
  res.json(savedMessage);
43
- });
40
+ });
44
41
 
45
- });
42
+ });
46
43
  });
47
44
 
48
- // curl -v -X POST -H 'Content-Type:application/json' -u andrea.leo@frontiere21.it:258456 -d '{"text":"ciao", "recipient":"5f8972c82db41c003473cb03"}' https://tiledesk-server-pre.herokuapp.com/5f86c201189063003453a045/campaigns/direct
49
- router.post('/direct', function (req, res) {
45
+ router.post('/direct', async function (req, res) {
50
46
 
51
47
  let messageStatus = req.body.status || MessageConstants.CHAT_MESSAGE_STATUS.SENDING;
52
48
 
53
49
  winston.debug(req.body);
54
50
  winston.debug("req.user", req.user);
51
+
52
+ var recipients = [];
53
+
54
+ var recipient = req.body.recipient;
55
+ if (recipient) {
56
+ recipients.push(recipient);
57
+ }
58
+
59
+ // TODO cicla su segment
60
+ var segment_id = req.body.segment_id;
61
+ if (segment_id) {
62
+
63
+ }
64
+
65
+ var group_id = req.body.group_id;
66
+ if (group_id) {
67
+ var group = await Group.findOne({ _id: group_id, id_project: req.projectid }).exec();
68
+ winston.info("group", group);
69
+
70
+ var recipients = group.members;
71
+ // winston.info("members", members);
72
+
73
+
74
+ }
75
+
76
+ winston.info("recipients", recipients);
77
+ winston.info("recipients.length: " + recipients.length);
78
+
79
+ let message = {
80
+ sender: req.body.sender || req.user._id,
81
+ senderFullname: req.body.senderFullname || req.user.fullName,
82
+ recipient: req.body.recipient,
83
+ recipientFullname: req.body.recipientFullname,
84
+ text: req.body.text,
85
+ id_project: req.projectid, // rendilo opzionale?
86
+ createdBy: req.user._id,
87
+ status: messageStatus,
88
+ attributes: req.body.attributes,
89
+ type: req.body.type,
90
+ metadata: req.body.metadata,
91
+ language: req.body.language,
92
+ channel_type: MessageConstants.CHANNEL_TYPE.DIRECT,
93
+ channel: req.body.channel
94
+ };
55
95
 
56
96
 
57
- // create(sender, senderFullname, recipient, text, id_project, createdBy, status, attributes, type, metadata, language, channel_type) {
58
- return messageService.create(req.body.sender || req.user._id, req.body.senderFullname || req.user.fullName, req.body.recipient, req.body.text,
59
- req.projectid, req.user._id, messageStatus, req.body.attributes, req.body.type, req.body.metadata, req.body.language, MessageConstants.CHANNEL_TYPE.DIRECT, req.body.channel).then(function(savedMessage){
60
- res.json(savedMessage);
61
- });
97
+ if (recipients.length == 0) {
98
+ // return res XXX
99
+ }
100
+
101
+ if (recipients.length == 1) {
102
+ return messageService.save(message).then(function(savedMessage){
103
+ if (req.body.returnobject) {
104
+ return res.json(savedMessage);
105
+ } else {
106
+ return res.json({ success: true });
107
+ }
108
+
109
+ });
110
+ }
111
+
112
+
113
+ var promises = [];
114
+ for (const recipient of recipients) {
115
+ // recipients.forEach( async (recipient) => {
116
+
117
+ // create(sender, senderFullname, recipient, text, id_project, createdBy, status, attributes, type, metadata, language, channel_type) {
118
+ // var promise = messageService.create(req.body.sender || req.user._id, req.body.senderFullname || req.user.fullName, recipient, req.body.text,
119
+ // req.projectid, req.user._id, messageStatus, req.body.attributes, req.body.type, req.body.metadata, req.body.language, MessageConstants.CHANNEL_TYPE.DIRECT, req.body.channel);
120
+
121
+ winston.info("recipient: " + recipient);
122
+
123
+ message.recipient = recipient;
124
+
125
+ var user = await User.findOne({_id:recipient}).exec();
126
+ winston.info("user", user);
127
+
128
+ message.recipientFullname = user.fullName;
129
+
130
+ var promise = messageService.save(message);
131
+ promises.push(promise);
132
+ // .then(function(savedMessage){
133
+ // result.push(savedMessage);
134
+ // res.json(savedMessage);
135
+ }
136
+ //);
137
+
138
+ Promise.all(promises).then(function (data) {
139
+ if (req.body.returnobject) {
140
+ return res.json(data);
141
+ }
142
+ });
143
+
144
+ if (!req.body.returnobject) {
145
+ return res.json({ success: true });
146
+ }
147
+
148
+
149
+
62
150
 
63
-
64
151
  });
65
152
 
66
153
 
67
154
 
68
155
 
156
+
157
+
158
+
159
+
160
+
69
161
  module.exports = router;
package/routes/faq.js CHANGED
@@ -250,6 +250,24 @@ router.get('/', function (req, res, next) {
250
250
  query.id_faq_kb = req.query.id_faq_kb;
251
251
  }
252
252
 
253
+ var limit = 100; // Number of request per page
254
+
255
+ if (req.query.limit) {
256
+ limit = parseInt(req.query.limit);
257
+ winston.debug('faq ROUTE - limit: '+limit);
258
+ }
259
+
260
+ var page = 0;
261
+
262
+ if (req.query.page) {
263
+ page = req.query.page;
264
+ }
265
+
266
+ var skip = page * limit;
267
+ winston.debug('faq ROUTE - SKIP PAGE ', skip);
268
+
269
+
270
+
253
271
  if (req.query.text) {
254
272
  winston.debug("GET FAQ req.projectid", req.projectid);
255
273
 
@@ -263,6 +281,7 @@ router.get('/', function (req, res, next) {
263
281
  // query.$text = {"$search": "question"};
264
282
 
265
283
  return Faq.find(query).
284
+ skip(skip).limit(limit).
266
285
  populate({path:'faq_kb'})//, match: { trashed: { $in: [null, false] } }}).
267
286
  .exec(function (err, faq) {
268
287
  winston.debug("GET FAQ ", faq);
package/routes/faq_kb.js CHANGED
@@ -9,7 +9,8 @@ var winston = require('../config/winston');
9
9
 
10
10
  router.post('/', function (req, res) {
11
11
  // create(name, url, projectid, user_id, type, description) {
12
- faqService.create(req.body.name, req.body.url, req.projectid, req.user.id, req.body.type, req.body.description).then(function(savedFaq_kb) {
12
+ faqService.create(req.body.name, req.body.url, req.projectid, req.user.id, req.body.type, req.body.description, undefined, undefined,
13
+ req.body.language).then(function(savedFaq_kb) {
13
14
  res.json(savedFaq_kb);
14
15
  });
15
16
 
@@ -58,8 +59,15 @@ router.post('/askbot', function (req, res) {
58
59
  }else {
59
60
  query = { "id_project": req.projectid, "id_faq_kb": req.body.id_faq_kb};
60
61
 
61
- query.$text = {"$search": req.body.question};
62
-
62
+ var search_obj = {"$search": req.body.question};
63
+
64
+ if (faq_kb.language) {
65
+ search_obj["$language"] = faq_kb.language;
66
+ }
67
+ query.$text = search_obj;
68
+ winston.debug("fulltext search query", query);
69
+
70
+
63
71
  winston.debug('internal ft query: '+ query);
64
72
 
65
73
  Faq.find(query, {score: { $meta: "textScore" } })
@@ -67,7 +75,8 @@ router.post('/askbot', function (req, res) {
67
75
  .lean().
68
76
  exec(function (err, faqs) {
69
77
  if (err) {
70
- return res.status(500).send({ success: false, msg: 'Error getting object.' });
78
+ winston.error('Error getting object.', err);
79
+ return res.status(500).send({ success: false, msg: 'Error getting fulltext object.' });
71
80
  }
72
81
 
73
82
  winston.debug("faqs", faqs);
package/routes/faqpub.js CHANGED
@@ -33,7 +33,7 @@ router.get('/', function (req, res, next) {
33
33
  winston.debug("GET FAQ ", faq);
34
34
 
35
35
  if (err) {
36
- winston.debug('GET FAQ err ', err)
36
+ winston.error('GET FAQ err ', err)
37
37
  return next(err)
38
38
  };
39
39
  winston.debug('GET FAQ ', faq)
package/routes/images.js CHANGED
@@ -23,7 +23,7 @@ const fileService = new FileGridFsService("images");
23
23
 
24
24
 
25
25
  const fileFilter = (req, file, cb) => {
26
- if (file.mimetype == 'image/jpeg' || file.mimetype == 'image/png') {
26
+ if (file.mimetype == 'image/jpeg' || file.mimetype == 'image/png' || file.mimetype == 'image/vnd.microsoft.icon') {
27
27
  cb(null, true);
28
28
  } else {
29
29
  cb(null, false);
package/routes/jwt.js CHANGED
@@ -7,7 +7,6 @@ var router = express.Router();
7
7
  var config = require('../config/database');
8
8
  var jwt = require('jsonwebtoken');
9
9
  var validtoken = require('../middleware/valid-token');
10
- // var secret = process.env.SECRET || config.secret;
11
10
  var requestUtil = require('../utils/requestUtil');
12
11
  var Project = require('../models/project');
13
12
  var winston = require('../config/winston');
package/routes/logs.js ADDED
@@ -0,0 +1,26 @@
1
+ var express = require('express');
2
+ var router = express.Router();
3
+ var winston = require('../config/winston');
4
+
5
+
6
+
7
+ router.get('/', function(req, res, next) {
8
+ winston.info("logs", req.body);
9
+ return res.status(200).send({ success: true});
10
+ });
11
+
12
+
13
+ router.post('/', function(req, res, next) {
14
+ winston.info("logs", req.body);
15
+ return res.status(200).send({ success: true});
16
+ });
17
+
18
+
19
+
20
+
21
+
22
+
23
+
24
+
25
+
26
+ module.exports = router;
package/routes/message.js CHANGED
@@ -130,6 +130,8 @@ async (req, res) => {
130
130
  return leadService.createIfNotExistsWithLeadId(sender || req.user._id, fullname, email, req.projectid, null, req.body.attributes || req.user.attributes)
131
131
  .then(function(createdLead) {
132
132
 
133
+
134
+
133
135
 
134
136
  var new_request = { // problema
135
137
  request_id: req.params.request_id, project_user_id: project_user._id, lead_id: createdLead._id, id_project:req.projectid,
@@ -137,7 +139,8 @@ async (req, res) => {
137
139
  language: req.body.language, userAgent:req.body.userAgent, status:null, createdBy: req.user._id,
138
140
  attributes: req.body.attributes, subject: req.body.subject, preflight:undefined, channel: req.body.channel, location: req.body.location,
139
141
  participants: req.body.participants,
140
- lead: createdLead, requester: project_user
142
+ lead: createdLead, requester: project_user,
143
+ priority: req.body.priority
141
144
  };
142
145
 
143
146
  return requestService.create(new_request).then(function (savedRequest) {
@@ -176,6 +179,7 @@ async (req, res) => {
176
179
 
177
180
  message.request = savedRequestPopulated;
178
181
 
182
+
179
183
  return res.json(message);
180
184
  });
181
185
  });
@@ -205,6 +209,8 @@ async (req, res) => {
205
209
  return requestService.updateWaitingTimeByRequestId(request.request_id, request.id_project).then(function(upRequest) {
206
210
  let message = savedMessage.toJSON();
207
211
  message.request = upRequest;
212
+
213
+
208
214
  return res.json(message);
209
215
  });
210
216
  }else {
@@ -279,7 +285,6 @@ async (req, res) => {
279
285
  // });
280
286
  // });
281
287
 
282
-
283
288
  router.get('/:messageid', function(req, res) {
284
289
 
285
290
  console.log(req.body);
@@ -1,41 +1,98 @@
1
1
  var express = require('express');
2
2
 
3
3
  // https://stackoverflow.com/questions/28977253/express-router-undefined-params-with-router-use-when-split-across-files
4
- var router = express.Router();
4
+ var router = express.Router({mergeParams: true});
5
5
 
6
6
  var MessageConstants = require("../models/messageConstants");
7
+ var Message = require("../models/message");
7
8
  var messageService = require("../services/messageService");
8
9
  var winston = require('../config/winston');
10
+ var fastCsv = require("fast-csv");
11
+ var roleChecker = require('../middleware/has-role');
12
+ const { check, validationResult } = require('express-validator');
9
13
 
10
- // curl -v -X POST -H 'Content-Type:application/json' -u andrea.leo@frontiere21.it:258456td -d '{"senderFullname":"Bot","recipient":"USERID", "text":"ciao"}' https://tiledesk-server-pre.herokuapp.com/5f86c201189063003453a045/messages/
11
- // curl -v -X POST -H 'Content-Type:application/json' -u andrea.leo@f21.it:123456 -d '{"senderFullname":"Bot","recipient":"USERID", "text":"ciao"}' http://localhost:3000/609e3fd8e049553972114b88/messages/
12
14
 
13
15
  router.post('/',
16
+ [
17
+ check('recipient').notEmpty(),
18
+ check('recipientFullname').notEmpty(),
19
+ check('text').custom((value, { req }) => {
20
+ winston.debug('validation: '+ value + ' req.body.type ' + req.body.type);
21
+ if (!value && (!req.body.type || req.body.type === "text") ) {
22
+ winston.debug('validation1 ');
23
+ return Promise.reject('Text field is required for messages with type "text"');
24
+ }
25
+ winston.debug('validation2 ');
26
+ return Promise.resolve('validation ok');
27
+ })
28
+ ],
14
29
  async (req, res) => {
15
30
 
16
31
  winston.debug('req.body post message', req.body);
17
32
  winston.debug('req.params: ', req.params);
18
33
  winston.debug('req.params.request_id: ' + req.params.request_id);
19
34
 
20
- let messageStatus = req.body.status || MessageConstants.CHAT_MESSAGE_STATUS.SENDING;
21
35
 
22
- return messageService.create(req.body.sender || req.user._id, req.body.senderFullname || req.user.fullName, req.body.recipient, req.body.text,
23
- req.projectid, req.user._id, messageStatus, req.body.attributes, req.body.type, req.body.metadata, req.body.language, MessageConstants.CHANNEL_TYPE.DIRECT, req.body.channel).then(function(savedMessage){
36
+ const errors = validationResult(req);
37
+ if (!errors.isEmpty()) {
38
+ winston.error("Signup validation error", errors);
39
+ return res.status(422).json({ errors: errors.array() });
40
+ }
41
+ let message = {
42
+ sender: req.body.sender || req.user._id,
43
+ senderFullname: req.body.senderFullname || req.user.fullName,
44
+ recipient: req.body.recipient,
45
+ recipientFullname: req.body.recipientFullname,
46
+ text: req.body.text,
47
+ id_project: req.projectid, // rendilo opzionale?
48
+ createdBy: req.user._id,
49
+ status: MessageConstants.CHAT_MESSAGE_STATUS.SENDING,
50
+ attributes: req.body.attributes,
51
+ type: req.body.type,
52
+ metadata: req.body.metadata,
53
+ language: req.body.language,
54
+ channel_type: req.body.channel_type || MessageConstants.CHANNEL_TYPE.DIRECT,
55
+ channel: req.body.channel
56
+ };
57
+ return messageService.save(message).then(function(savedMessage){
24
58
  res.json(savedMessage);
25
- });
59
+ }).catch(function(err){
60
+ winston.error('Error saving message.', err);
61
+ return res.status(500).send({ success: false, msg: 'Error saving message.', err: err });
62
+ })
26
63
 
27
64
  });
28
65
 
29
66
 
30
- //TODO reenable it with role owner
31
- /*
32
- router.get('/csv', function(req, res) {
33
67
 
34
- return Message.find({id_project: req.projectid}).sort({createdAt: 'asc'}).exec(function(err, messages) {
35
- if (err) return next(err);
36
- res.csv(messages, true);
37
- });
68
+ router.get('/csv', roleChecker.hasRoleOrTypes('owner'), function(req, res) {
69
+
70
+
71
+ const cursor = Message.find({id_project: req.projectid}).select("-channel -attributes -metadata");
72
+
73
+ const transformer = (doc)=> {
74
+ return {
75
+ Id: doc._id,
76
+ Name: doc.fullname,
77
+ Email: doc.email,
78
+ Type: doc.registration_type,
79
+ RegisterOn: doc.registered_on
80
+ };
81
+ }
82
+
83
+ const filename = 'export.csv';
84
+
85
+ res.setHeader('Content-disposition', `attachment; filename=${filename}`);
86
+ res.writeHead(200, { 'Content-Type': 'text/csv' });
87
+
88
+ res.flushHeaders();
89
+
90
+ console.log("fastCsv",fastCsv)
91
+ var csvStream = fastCsv.format({headers: true})//.transform(transformer)
92
+ // var csvStream = fastCsv.createWriteStream({headers: true}).transform(transformer)
93
+ cursor.stream().pipe(csvStream).pipe(res);
94
+
38
95
  });
39
- */
40
96
 
41
- module.exports = router;
97
+
98
+ module.exports = router;
@@ -112,7 +112,7 @@ router.post('/invite', [passport.authenticate(['basic', 'jwt'], { session: false
112
112
  // if ('5ae6c62c61c7d54bf119ac73' == '5ae6c62c61c7d54bf119ac73') {
113
113
 
114
114
  winston.debug('»»»» THE PRJCT-USER ID ', p_user.id_user, ' MATCHES THE FOUND USER-ID', user._id)
115
- winston.debug('»»»» USER IS ALREADY A MEMBER OF THE PROJECT ')
115
+ winston.warn("User " + projectUserId+ " is already a member of the project: " + req.projectid)
116
116
 
117
117
  // cannot use continue or break inside a JavaScript Array.prototype.forEach loop. However, there are other options:
118
118
  throw new Error('User is already a member'); // break
@@ -359,6 +359,37 @@ router.get('/:project_userid', [passport.authenticate(['basic', 'jwt'], { sessio
359
359
  });
360
360
 
361
361
 
362
+ router.get('/users/search', [passport.authenticate(['basic', 'jwt'], { session: false }), validtoken, roleChecker.hasRoleOrTypes('agent', ['subscription'])], async (req, res, next) => {
363
+ winston.info("--> users search ");
364
+
365
+ if (!req.project) {
366
+ return res.status(404).send({ success: false, msg: 'Project not found.' });
367
+ }
368
+
369
+
370
+ let query = {email: req.query.email};
371
+
372
+ winston.info('query: ', query);
373
+
374
+ let user = await User.findOne(query).exec();
375
+ winston.info('user: ', user);
376
+
377
+ if (!user) {
378
+ return res.status(404).send({ success: false, msg: 'Object not found.' });
379
+ }
380
+
381
+
382
+ let project_user = await Project_user.findOne({id_user: user._id, id_project: req.projectid}).exec();
383
+ winston.info('project_user: ', project_user);
384
+
385
+ if (!project_user) {
386
+ return res.status(403).json({msg: "Unauthorized. This is not a your teammate." });
387
+ }
388
+
389
+
390
+ return res.json({_id: user._id});
391
+
392
+ });
362
393
 
363
394
  /**
364
395
  * GET PROJECT-USER BY PROJECT ID AND CURRENT USER ID
@@ -368,6 +399,10 @@ router.get('/:project_userid', [passport.authenticate(['basic', 'jwt'], { sessio
368
399
  router.get('/users/:user_id', [passport.authenticate(['basic', 'jwt'], { session: false }), validtoken, roleChecker.hasRoleOrTypes('agent', ['subscription'])], function (req, res, next) {
369
400
  winston.debug("--> users USER ID ", req.params.user_id);
370
401
 
402
+ if (!req.project) {
403
+ return res.status(404).send({ success: false, msg: 'Project not found.' });
404
+ }
405
+
371
406
  var isObjectId = mongoose.Types.ObjectId.isValid(req.params.user_id);
372
407
  winston.debug("isObjectId:"+ isObjectId);
373
408