@tiledesk/tiledesk-server 2.1.40 → 2.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.circleci/config.yml +54 -0
- package/.env.sample +1 -1
- package/.github/workflows/docker-community-push-latest.yml +22 -0
- package/.github/workflows/{docker-image-push.yml → docker-image-en-tag-push.yml} +1 -1
- package/.github/workflows/docker-image-tag-community-tag-push.yml +21 -0
- package/.github/workflows/{docker-push-latest.yml → docker-push-en-push-latest.yml} +1 -1
- package/CHANGELOG.md +195 -1
- package/Dockerfile +1 -1
- package/Dockerfile-en +1 -1
- package/README.md +5 -7
- package/app.js +12 -1
- package/channels/channelManager.js +1 -1
- package/channels/chat21/chat21Contact.js +34 -8
- package/channels/chat21/chat21Handler.js +48 -5
- package/channels/chat21/chat21WebHook.js +34 -9
- package/channels/chat21/nativeauth.js +2 -2
- package/channels/chat21/package-lock.json +3013 -0
- package/config/email.js +2 -0
- package/config/global.js +3 -0
- package/config/labels/widget.json +170 -16
- package/event/messageEvent.js +18 -1
- package/middleware/passport.js +10 -4
- package/migrations/1619185894304-request-remove-duplicated-request-by-request_id--autosync.js +67 -0
- package/models/actionsConstants.js +7 -0
- package/models/department.js +3 -0
- package/models/faq.js +8 -2
- package/models/faq_kb.js +6 -0
- package/models/message.js +10 -4
- package/models/messageConstants.js +9 -3
- package/models/request.js +33 -3
- package/package.json +31 -28
- package/pubmodules/emailNotification/requestNotification.js +483 -56
- package/pubmodules/messageActions/messageActionsInterceptor.js +20 -7
- package/pubmodules/messageTransformer/index.js +5 -1
- package/pubmodules/messageTransformer/messageTransformerInterceptor.js +4 -2
- package/pubmodules/messageTransformer/microLanguageAttributesTransformerInterceptor.js +67 -0
- package/pubmodules/messageTransformer/microLanguageTransformerInterceptor.js +67 -0
- package/pubmodules/pubModulesManager.js +66 -13
- package/pubmodules/rules/conciergeBot.js +81 -49
- package/routes/auth.js +46 -11
- package/routes/campaigns.js +117 -25
- package/routes/department.js +2 -2
- package/routes/faq.js +19 -0
- package/routes/faq_kb.js +13 -4
- package/routes/faqpub.js +1 -1
- package/routes/files.js +17 -2
- package/routes/images.js +1 -1
- package/routes/jwt.js +0 -1
- package/routes/logs.js +26 -0
- package/routes/message.js +7 -2
- package/routes/messagesRoot.js +73 -16
- package/routes/project_user.js +36 -1
- package/routes/request.js +88 -12
- package/routes/requestUtilRoot.js +30 -0
- package/routes/urls.js +12 -0
- package/routes/users.js +5 -1
- package/services/BotSubscriptionNotifier.js +1 -0
- package/services/departmentService.js +29 -5
- package/services/emailService.js +1170 -239
- package/services/faqBotHandler.js +176 -61
- package/services/faqBotSupport.js +182 -117
- package/services/faqService.js +18 -14
- package/services/messageService.js +57 -9
- package/services/modulesManager.js +86 -23
- package/services/requestService.js +58 -17
- package/template/email/assignedEmailMessage.html +205 -0
- package/template/email/assignedRequest.html +44 -14
- package/template/email/beenInvitedExistingUser.html +2 -2
- package/template/email/beenInvitedNewUser.html +1 -1
- package/template/email/newMessage.html +31 -12
- package/template/email/passwordChanged.html +2 -3
- package/template/email/pooledEmailMessage.html +208 -0
- package/template/email/pooledRequest.html +41 -14
- package/template/email/resetPassword.html +2 -3
- package/template/email/sendTranscript.html +1 -1
- package/template/email/test.html +1 -1
- package/template/email/ticket.html +191 -0
- package/template/email/ticket.txt +11 -0
- package/template/email/verify.html +1 -1
- package/test/authentication.js +76 -4
- package/test/authenticationJwt.js +76 -2
- package/test/campaignsRoute.js +226 -0
- package/test/faqService.js +3 -3
- package/test/faqkbRoute.js +3 -2
- package/test/messageRootRoute.js +193 -0
- package/test/messageRoute.js +75 -0
- package/test/messageService.js +39 -2
- package/test/requestRoute.js +27 -9
- package/test/requestService.js +472 -11
- package/test-int/bot.js +673 -8
- package/websocket/webSocketServer.js +7 -4
package/routes/campaigns.js
CHANGED
@@ -1,9 +1,8 @@
|
|
1
1
|
var express = require('express');
|
2
2
|
var router = express.Router();
|
3
|
-
var
|
4
|
-
var
|
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
|
-
|
34
|
-
|
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,
|
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
|
-
|
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
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
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/department.js
CHANGED
@@ -230,14 +230,14 @@ router.get('/', function (req, res) {
|
|
230
230
|
|
231
231
|
var query = { "id_project": req.projectid, "status": 1 };
|
232
232
|
winston.debug('GET DEPTS FILTERED FOR STATUS === 1 req.projectid ', req.projectid);
|
233
|
-
if (req.project.profile) {
|
233
|
+
if (req.project && req.project.profile) {
|
234
234
|
winston.debug('GET DEPTS FILTERED FOR STATUS === 1 req.project.profile.type ', req.project.profile.type);
|
235
235
|
}
|
236
236
|
winston.debug('GET DEPTS FILTERED FOR STATUS === 1 req.project.profile.type ', req.project.trialExpired);
|
237
237
|
winston.debug('GET DEPTS FILTERED FOR STATUS === 1 req.project.isActiveSubscription ', req.project.isActiveSubscription);
|
238
238
|
|
239
239
|
|
240
|
-
if (req.project.profile && (req.project.profile.type === 'free' && req.project.trialExpired === true) || (req.project.profile.type === 'payment' && req.project.isActiveSubscription === false)) {
|
240
|
+
if (req.project && req.project.profile && (req.project.profile.type === 'free' && req.project.trialExpired === true) || (req.project.profile.type === 'payment' && req.project.isActiveSubscription === false)) {
|
241
241
|
|
242
242
|
query.default = true;
|
243
243
|
}
|
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
|
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
|
-
|
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
|
-
|
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
package/routes/files.js
CHANGED
@@ -4,6 +4,7 @@ var passport = require('passport');
|
|
4
4
|
require('../middleware/passport')(passport);
|
5
5
|
var validtoken = require('../middleware/valid-token')
|
6
6
|
var winston = require('../config/winston');
|
7
|
+
var pathlib = require('path');
|
7
8
|
|
8
9
|
|
9
10
|
var router = express.Router();
|
@@ -29,7 +30,7 @@ curl -u andrea.leo@f21.it:123456 \
|
|
29
30
|
*/
|
30
31
|
|
31
32
|
router.post('/users', [passport.authenticate(['basic', 'jwt'], { session: false }), validtoken], upload.single('file'), (req, res, next) => {
|
32
|
-
|
33
|
+
winston.info("files/users")
|
33
34
|
return res.status(201).json({
|
34
35
|
message: 'File uploded successfully',
|
35
36
|
filename: req.file.filename
|
@@ -42,10 +43,12 @@ curl \
|
|
42
43
|
-F "file=@/Users/andrealeo/dev/chat21/tiledesk-server-dev-org/README.md" \
|
43
44
|
http://localhost:3000/files/public/
|
44
45
|
|
46
|
+
|
47
|
+
|
45
48
|
*/
|
46
49
|
|
47
50
|
router.post('/public', upload.single('file'), (req, res, next) => {
|
48
|
-
|
51
|
+
winston.debug("files/public")
|
49
52
|
return res.status(201).json({
|
50
53
|
message: 'File uploded successfully',
|
51
54
|
filename: req.file.filename
|
@@ -74,4 +77,16 @@ router.get("/", (req, res) => {
|
|
74
77
|
});
|
75
78
|
|
76
79
|
|
80
|
+
router.get("/download", (req, res) => {
|
81
|
+
winston.debug('path', req.query.path);
|
82
|
+
// if (path.indexOf("/users/"))
|
83
|
+
let filename = pathlib.basename(req.query.path);
|
84
|
+
winston.info("filename:"+filename);
|
85
|
+
|
86
|
+
res.attachment(filename);
|
87
|
+
fileService.getFileDataAsStream(req.query.path).pipe(res);
|
88
|
+
});
|
89
|
+
|
90
|
+
|
91
|
+
|
77
92
|
module.exports = router;
|
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);
|
package/routes/messagesRoot.js
CHANGED
@@ -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
|
-
|
23
|
-
|
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
|
-
|
35
|
-
|
36
|
-
|
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
|
-
|
97
|
+
|
98
|
+
module.exports = router;
|
package/routes/project_user.js
CHANGED
@@ -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.
|
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
|
|