@tiledesk/tiledesk-server 2.1.41 → 2.2.4

Sign up to get free protection for your applications and to get access to all the features.
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