@tiledesk/tiledesk-server 2.9.11 → 2.9.13
Sign up to get free protection for your applications and to get access to all the features.
- package/CHANGELOG.md +7 -0
- package/package.json +2 -2
- package/routes/project.js +168 -67
- package/services/QuoteManager.js +6 -1
- package/services/projectUserService.js +32 -0
- package/test/projectRoute.js +76 -1
package/CHANGELOG.md
CHANGED
@@ -5,6 +5,13 @@
|
|
5
5
|
🚀 IN PRODUCTION 🚀
|
6
6
|
(https://www.npmjs.com/package/@tiledesk/tiledesk-server/v/2.3.77)
|
7
7
|
|
8
|
+
# 2.9.13
|
9
|
+
- Updated tybot-connector to 0.2.95
|
10
|
+
- Improved /users/availables endpoint with department and smart assignment check
|
11
|
+
|
12
|
+
# 2.9.12
|
13
|
+
- Added support for Team plan
|
14
|
+
|
8
15
|
# 2.9.11
|
9
16
|
- Bug fix quotas reset after stripe subscription update
|
10
17
|
|
package/package.json
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
{
|
2
2
|
"name": "@tiledesk/tiledesk-server",
|
3
3
|
"description": "The Tiledesk server module",
|
4
|
-
"version": "2.9.
|
4
|
+
"version": "2.9.13",
|
5
5
|
"scripts": {
|
6
6
|
"start": "node ./bin/www",
|
7
7
|
"pretest": "mongodb-runner start",
|
@@ -48,7 +48,7 @@
|
|
48
48
|
"@tiledesk/tiledesk-rasa-connector": "^1.0.10",
|
49
49
|
"@tiledesk/tiledesk-telegram-connector": "^0.1.14",
|
50
50
|
"@tiledesk/tiledesk-train-jobworker": "^0.0.11",
|
51
|
-
"@tiledesk/tiledesk-tybot-connector": "^0.2.
|
51
|
+
"@tiledesk/tiledesk-tybot-connector": "^0.2.95",
|
52
52
|
"@tiledesk/tiledesk-whatsapp-connector": "^0.1.72",
|
53
53
|
"@tiledesk/tiledesk-whatsapp-jobworker": "^0.0.8",
|
54
54
|
"@tiledesk/tiledesk-sms-connector": "^0.1.7",
|
package/routes/project.js
CHANGED
@@ -3,10 +3,13 @@ var router = express.Router();
|
|
3
3
|
var Project = require("../models/project");
|
4
4
|
var projectEvent = require("../event/projectEvent");
|
5
5
|
var projectService = require("../services/projectService");
|
6
|
+
var projectUserService = require("../services/projectUserService");
|
6
7
|
|
7
8
|
var Project_user = require("../models/project_user");
|
8
9
|
|
9
10
|
var operatingHoursService = require("../services/operatingHoursService");
|
11
|
+
var Department = require('../models/department');
|
12
|
+
var Group = require('../models/group');
|
10
13
|
|
11
14
|
var winston = require('../config/winston');
|
12
15
|
var roleChecker = require('../middleware/has-role');
|
@@ -20,7 +23,7 @@ var RoleConstants = require("../models/roleConstants");
|
|
20
23
|
var cacheUtil = require('../utils/cacheUtil');
|
21
24
|
var orgUtil = require("../utils/orgUtil");
|
22
25
|
var cacheEnabler = require("../services/cacheEnabler");
|
23
|
-
|
26
|
+
var mongoose = require('mongoose');
|
24
27
|
|
25
28
|
router.post('/', [passport.authenticate(['basic', 'jwt'], { session: false }), validtoken], async (req, res) => {
|
26
29
|
|
@@ -881,83 +884,181 @@ router.get('/:projectid/isopen', function (req, res) {
|
|
881
884
|
}
|
882
885
|
});
|
883
886
|
|
884
|
-
|
885
|
-
|
886
|
-
|
887
|
-
|
888
|
-
|
889
|
-
|
890
|
-
|
891
|
-
|
892
|
-
|
893
|
-
|
894
|
-
|
895
|
-
|
896
|
-
|
897
|
-
|
898
|
-
|
899
|
-
|
900
|
-
|
901
|
-
|
902
|
-
|
903
|
-
|
904
|
-
|
905
|
-
|
906
|
-
|
907
|
-
|
908
|
-
|
909
|
-
|
910
|
-
|
887
|
+
|
888
|
+
router.get('/:projectid/users/availables', async (req, res) => {
|
889
|
+
|
890
|
+
let projectid = req.params.projectid;
|
891
|
+
let raw_option = req.query.raw;
|
892
|
+
let dep_id = req.query.department;
|
893
|
+
let isOpen = true;
|
894
|
+
|
895
|
+
winston.debug("(Users Availables) raw_option: " + raw_option);
|
896
|
+
winston.debug("(Users Availables) dep_id: " + dep_id);
|
897
|
+
|
898
|
+
let available_agents_array = [];
|
899
|
+
|
900
|
+
if (!raw_option || raw_option === false) {
|
901
|
+
try {
|
902
|
+
isOpen = await new Promise((resolve, reject) => {
|
903
|
+
operatingHoursService.projectIsOpenNow(projectid, (isOpen, err) => {
|
904
|
+
if (err) reject(err);
|
905
|
+
else resolve(isOpen);
|
906
|
+
});
|
907
|
+
});
|
908
|
+
} catch (err) {
|
909
|
+
wisnton.error("(Users Availables) check operating hours error: ", err);
|
910
|
+
return res.status(500).send({ success: false, msg: err });
|
911
|
+
}
|
912
|
+
}
|
913
|
+
|
914
|
+
if (isOpen === false) {
|
915
|
+
return res.json(available_agents_array);
|
916
|
+
}
|
917
|
+
|
918
|
+
let query = { id_project: projectid, user_available: true, role: { $in : [RoleConstants.OWNER, RoleConstants.ADMIN, RoleConstants.SUPERVISOR, RoleConstants.AGENT]} };
|
919
|
+
|
920
|
+
if (dep_id) {
|
921
|
+
let department = await Department.findById(dep_id).catch((err) => {
|
922
|
+
winston.error("(Users Availables) find department error: ", err)
|
923
|
+
return res.status(500).send({ success: false, error: err })
|
924
|
+
})
|
925
|
+
|
926
|
+
if (!department) {
|
927
|
+
winston.error("(Users Availables) department not found")
|
928
|
+
return res.status(404).send({ success: false, error: "Department " + dep_id + " not found" })
|
929
|
+
}
|
930
|
+
|
931
|
+
let group_id = department.id_group;
|
932
|
+
if (group_id) {
|
933
|
+
let group = await Group.findById(group_id).catch((err) => {
|
934
|
+
winston.error("(Users Availables) find group error: ", err)
|
935
|
+
return res.status(500).send({ success: false, error: err })
|
936
|
+
})
|
937
|
+
|
938
|
+
if (!group) {
|
939
|
+
winston.error("(Users Availables) group not found")
|
940
|
+
return res.status(404).send({ success: false, error: "Group " + group_id + " not found" })
|
941
|
+
}
|
942
|
+
|
943
|
+
query.id_user = { $in: group.members.map(id => mongoose.Types.ObjectId(id) )}
|
944
|
+
|
945
|
+
}
|
946
|
+
}
|
947
|
+
|
948
|
+
winston.debug("(Users Availables) project_users query ", query)
|
949
|
+
Project_user.find(query)
|
950
|
+
.populate('id_user')
|
951
|
+
.exec( async (err, project_users) => {
|
952
|
+
if (err) {
|
953
|
+
winston.debug('PROJECT ROUTES - FINDS AVAILABLES project_users - ERROR: ', err);
|
954
|
+
return res.status(500).send({ success: false, msg: 'Error getting object.' + err});
|
955
|
+
}
|
956
|
+
|
957
|
+
let project = await Project.findById(projectid).catch((err) => {
|
958
|
+
winston.error("find project error: ", err)
|
959
|
+
res.status(500).send({ success: false, error: err })
|
960
|
+
})
|
961
|
+
|
962
|
+
// check on SMART ASSIGNMENT
|
963
|
+
let available_agents = projectUserService.checkAgentsAvailablesWithSmartAssignment(project, project_users);
|
964
|
+
winston.verbose("(Users Availables) available agents after smart assignment check", available_agents);
|
965
|
+
|
966
|
+
if (available_agents) {
|
967
|
+
|
968
|
+
available_agents_array = [];
|
969
|
+
available_agents.forEach(agent => {
|
970
|
+
if (agent.id_user) {
|
971
|
+
available_agents_array.push({ "id": agent.id_user._id, "firstname": agent.id_user.firstname });
|
972
|
+
} else {
|
973
|
+
winston.warn("(Users Availables) agent.id_user is undefined");
|
911
974
|
}
|
912
975
|
});
|
913
|
-
|
914
|
-
|
915
|
-
|
976
|
+
|
977
|
+
winston.debug("(Users Availables) return following available_agents_array", available_agents_array);
|
978
|
+
res.json(available_agents_array);
|
979
|
+
}
|
980
|
+
})
|
916
981
|
|
917
|
-
|
918
|
-
|
919
|
-
|
920
|
-
|
921
|
-
|
922
|
-
|
923
|
-
|
924
|
-
|
925
|
-
|
926
|
-
|
927
|
-
|
928
|
-
|
929
|
-
|
930
|
-
|
982
|
+
})
|
983
|
+
|
984
|
+
// OLD ENDPOINT for /users/availables
|
985
|
+
//togli questo route da qui e mettilo in altra route
|
986
|
+
// NEW - RETURN THE USER NAME AND THE USER ID OF THE AVAILABLE PROJECT-USER FOR THE PROJECT ID PASSED
|
987
|
+
// router.get('/:projectid/users/availables', function (req, res) {
|
988
|
+
// //winston.debug("PROJECT ROUTES FINDS AVAILABLES project_users: projectid", req.params.projectid);
|
989
|
+
|
990
|
+
// if (req.query.raw && (req.query.raw === true || req.query.raw === 'true')) {
|
991
|
+
// Project_user.find({ id_project: req.params.projectid, user_available: true, role: { $in : [RoleConstants.OWNER, RoleConstants.ADMIN, RoleConstants.SUPERVISOR, RoleConstants.AGENT]}}).
|
992
|
+
// populate('id_user').
|
993
|
+
// exec(function (err, project_users) {
|
994
|
+
// if (err) {
|
995
|
+
// winston.debug('PROJECT ROUTES - FINDS AVAILABLES project_users - ERROR: ', err);
|
996
|
+
// return res.status(500).send({ success: false, msg: 'Error getting object.' });
|
997
|
+
// }
|
998
|
+
// if (project_users) {
|
931
999
|
|
932
|
-
|
933
|
-
|
934
|
-
|
935
|
-
|
936
|
-
|
937
|
-
|
938
|
-
|
939
|
-
|
940
|
-
|
1000
|
+
// user_available_array = [];
|
1001
|
+
// project_users.forEach(project_user => {
|
1002
|
+
// if (project_user.id_user) {
|
1003
|
+
// // winston.debug('PROJECT ROUTES - AVAILABLES PROJECT-USER: ', project_user)
|
1004
|
+
// user_available_array.push({ "id": project_user.id_user._id, "firstname": project_user.id_user.firstname });
|
1005
|
+
// } else {
|
1006
|
+
// // winston.debug('PROJECT ROUTES - AVAILABLES PROJECT-USER (else): ', project_user)
|
1007
|
+
// }
|
1008
|
+
// });
|
941
1009
|
|
942
|
-
|
1010
|
+
// //winston.debug('ARRAY OF THE AVAILABLE USER ', user_available_array);
|
1011
|
+
// res.json(user_available_array);
|
1012
|
+
// }
|
1013
|
+
// });
|
1014
|
+
// } else {
|
1015
|
+
// operatingHoursService.projectIsOpenNow(req.params.projectid, function (isOpen, err) {
|
1016
|
+
// //winston.debug('P ---> [ OHS ] -> [ PROJECT ROUTES ] -> IS OPEN THE PROJECT: ', isOpen);
|
943
1017
|
|
944
|
-
|
945
|
-
|
946
|
-
|
1018
|
+
// if (err) {
|
1019
|
+
// winston.debug('P ---> [ OHS ] -> [ PROJECT ROUTES ] -> IS OPEN THE PROJECT - EROR: ', err)
|
1020
|
+
// // sendError(err, res);
|
1021
|
+
// return res.status(500).send({ success: false, msg: err });
|
1022
|
+
// } else if (isOpen) {
|
947
1023
|
|
1024
|
+
// Project_user.find({ id_project: req.params.projectid, user_available: true, role: { $in : [RoleConstants.OWNER, RoleConstants.ADMIN, RoleConstants.SUPERVISOR, RoleConstants.AGENT]}}).
|
1025
|
+
// populate('id_user').
|
1026
|
+
// exec(function (err, project_users) {
|
1027
|
+
// if (err) {
|
1028
|
+
// winston.debug('PROJECT ROUTES - FINDS AVAILABLES project_users - ERROR: ', err);
|
1029
|
+
// return res.status(500).send({ success: false, msg: 'Error getting object.' });
|
1030
|
+
// }
|
1031
|
+
// if (project_users) {
|
948
1032
|
|
949
|
-
|
950
|
-
|
951
|
-
|
952
|
-
|
953
|
-
|
954
|
-
|
955
|
-
|
956
|
-
|
1033
|
+
// user_available_array = [];
|
1034
|
+
// project_users.forEach(project_user => {
|
1035
|
+
// if (project_user.id_user) {
|
1036
|
+
// // winston.debug('PROJECT ROUTES - AVAILABLES PROJECT-USER: ', project_user)
|
1037
|
+
// user_available_array.push({ "id": project_user.id_user._id, "firstname": project_user.id_user.firstname });
|
1038
|
+
// } else {
|
1039
|
+
// // winston.debug('PROJECT ROUTES - AVAILABLES PROJECT-USER (else): ', project_user)
|
1040
|
+
// }
|
1041
|
+
// });
|
1042
|
+
|
1043
|
+
// //winston.debug('ARRAY OF THE AVAILABLE USER ', user_available_array);
|
1044
|
+
|
1045
|
+
// res.json(user_available_array);
|
1046
|
+
// }
|
1047
|
+
// });
|
1048
|
+
|
1049
|
+
|
1050
|
+
// } else {
|
1051
|
+
// // winston.debug('P ---> [ OHS ] -> [ PROJECT ROUTES ] -> IS OPEN THE PRJCT: ', isOpen, ' -> AVAILABLE EMPTY');
|
1052
|
+
// // closed
|
1053
|
+
// user_available_array = [];
|
1054
|
+
// res.json(user_available_array);
|
1055
|
+
// }
|
1056
|
+
// });
|
1057
|
+
// }
|
957
1058
|
|
958
1059
|
|
959
1060
|
|
960
|
-
});
|
1061
|
+
// });
|
961
1062
|
|
962
1063
|
|
963
1064
|
|
package/services/QuoteManager.js
CHANGED
@@ -13,12 +13,14 @@ const emailEvent = require('../event/emailEvent');
|
|
13
13
|
// CUSTOM: { requests: 3000, messages: 0, tokens: 5000000, email: 200, chatbots: 20, kbs: 500}
|
14
14
|
// }
|
15
15
|
|
16
|
+
|
16
17
|
const PLANS_LIST = {
|
17
18
|
FREE_TRIAL: { requests: 200, messages: 0, tokens: 100000, email: 200, chatbots: 20, namespace: 3, kbs: 50 }, // same as PREMIUM
|
18
19
|
SANDBOX: { requests: 200, messages: 0, tokens: 100000, email: 200, chatbots: 2, namespace: 1, kbs: 50 },
|
19
20
|
BASIC: { requests: 800, messages: 0, tokens: 2000000, email: 200, chatbots: 5, namespace: 1, kbs: 150 },
|
20
21
|
PREMIUM: { requests: 3000, messages: 0, tokens: 5000000, email: 200, chatbots: 20, namespace: 3, kbs: 300 },
|
21
|
-
|
22
|
+
TEAM: { requests: 5000, messages: 0, tokens: 10000000, email: 200, chatbots: 50, namespace: 10, kbs: 1000 },
|
23
|
+
CUSTOM: { requests: 5000, messages: 0, tokens: 10000000, email: 200, chatbots: 50, namespace: 10, kbs: 1000 },
|
22
24
|
}
|
23
25
|
|
24
26
|
const typesList = ['requests', 'messages', 'email', 'tokens', 'chatbots', 'kbs']
|
@@ -333,6 +335,9 @@ class QuoteManager {
|
|
333
335
|
case 'Premium':
|
334
336
|
limits = PLANS_LIST.PREMIUM;
|
335
337
|
break;
|
338
|
+
case 'Team':
|
339
|
+
limits = PLANS_LIST.TEAM;
|
340
|
+
break;
|
336
341
|
case 'Custom':
|
337
342
|
limits = PLANS_LIST.CUSTOM;
|
338
343
|
break;
|
@@ -9,6 +9,38 @@ var pendinginvitation = require("../services/pendingInvitationService");
|
|
9
9
|
|
10
10
|
class ProjectUserService {
|
11
11
|
|
12
|
+
checkAgentsAvailablesWithSmartAssignment(project, available_agents) {
|
13
|
+
|
14
|
+
let max_assigned_chat;
|
15
|
+
let available_agents_request = [];
|
16
|
+
|
17
|
+
if (project && project.settings && project.settings.chat_limit_on && project.settings.max_agent_assigned_chat) {
|
18
|
+
max_assigned_chat = project.settings.max_agent_assigned_chat;
|
19
|
+
winston.verbose('[ProjectUserService] max_agent_assigned_chat: ' + max_assigned_chat);
|
20
|
+
} else {
|
21
|
+
winston.verbose('[ProjectUserService] chat_limit_on or max_agent_assigned_chat is undefined');
|
22
|
+
return available_agents
|
23
|
+
}
|
24
|
+
|
25
|
+
if (available_agents.length == 0) {
|
26
|
+
return available_agents_request;
|
27
|
+
}
|
28
|
+
|
29
|
+
for (const aa of available_agents) {
|
30
|
+
let max_assigned_chat_specific_user = max_assigned_chat;
|
31
|
+
if (aa.max_assigned_chat && aa.max_assigned_chat != -1) {
|
32
|
+
max_assigned_chat_specific_user = aa.max_assigned_chat;
|
33
|
+
}
|
34
|
+
winston.verbose("[ProjectUserService] max_assigned_chat_specific_user " + max_assigned_chat_specific_user);
|
35
|
+
|
36
|
+
if (aa.number_assigned_requests < max_assigned_chat_specific_user) {
|
37
|
+
available_agents_request.push(aa);
|
38
|
+
}
|
39
|
+
}
|
40
|
+
|
41
|
+
return available_agents_request;
|
42
|
+
|
43
|
+
}
|
12
44
|
|
13
45
|
}
|
14
46
|
var projectUserService = new ProjectUserService();
|
package/test/projectRoute.js
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
process.env.NODE_ENV = 'test';
|
3
3
|
process.env.ADMIN_EMAIL = "admin@tiledesk.com";
|
4
4
|
|
5
|
-
let log =
|
5
|
+
let log = false;
|
6
6
|
var projectService = require('../services/projectService');
|
7
7
|
var userService = require('../services/userService');
|
8
8
|
|
@@ -13,12 +13,16 @@ let server = require('../app');
|
|
13
13
|
let should = chai.should();
|
14
14
|
var fs = require('fs');
|
15
15
|
const path = require('path');
|
16
|
+
const departmentService = require('../services/departmentService');
|
17
|
+
const routingConstants = require('../models/routingConstants');
|
18
|
+
var Group = require('../models/group');
|
16
19
|
|
17
20
|
// chai.config.includeStack = true;
|
18
21
|
|
19
22
|
var expect = chai.expect;
|
20
23
|
var assert = chai.assert;
|
21
24
|
|
25
|
+
|
22
26
|
let timeSlotsSample = {
|
23
27
|
"819559cc": {
|
24
28
|
name: "Slot1",
|
@@ -176,6 +180,77 @@ describe('ProjectRoute', () => {
|
|
176
180
|
})
|
177
181
|
}).timeout(10000)
|
178
182
|
|
183
|
+
it('availableUsers', (done) => {
|
184
|
+
|
185
|
+
var email = "test-signup-" + Date.now() + "@email.com";
|
186
|
+
var pwd = "pwd";
|
187
|
+
|
188
|
+
userService.signup(email, pwd, "Test Firstname", "Test Lastname").then((savedUser) => {
|
189
|
+
projectService.create("test-project-create", savedUser._id).then((savedProject) => {
|
190
|
+
|
191
|
+
chai.request(server)
|
192
|
+
.get('/projects/' + savedProject._id + '/users/availables')
|
193
|
+
.auth(email, pwd)
|
194
|
+
.end((err, res) => {
|
195
|
+
|
196
|
+
console.error("err: ", err);
|
197
|
+
console.log("res.body: ", res.body);
|
198
|
+
|
199
|
+
done();
|
200
|
+
})
|
201
|
+
})
|
202
|
+
})
|
203
|
+
}).timeout(10000)
|
204
|
+
|
205
|
+
it('departmentGroupAvailableUsers', (done) => {
|
206
|
+
|
207
|
+
var email = "test-signup-" + Date.now() + "@email.com";
|
208
|
+
var email2 = "test-signup2-" + Date.now() + "@email.com";
|
209
|
+
var pwd = "pwd";
|
210
|
+
|
211
|
+
userService.signup(email, pwd, "Test Firstname", "Test Lastname").then((savedUser) => {
|
212
|
+
// ignore second user (need to be added to the same project)
|
213
|
+
userService.signup(email2, pwd, "Test Firstname 2", "Test Lastname 2").then((savedUser2) => {
|
214
|
+
projectService.create("test-project-create", savedUser._id).then((savedProject) => {
|
215
|
+
|
216
|
+
chai.request(server)
|
217
|
+
.post('/' + savedProject._id + '/groups')
|
218
|
+
.auth(email, pwd)
|
219
|
+
.send({ name: "test-department-group", members: [savedUser._id] })
|
220
|
+
.end((err, res) => {
|
221
|
+
|
222
|
+
if (err) { console.error("err: ", err) };
|
223
|
+
if (log) { console.log("create group res.body: ", res.body); }
|
224
|
+
let savedGroup = res.body;
|
225
|
+
|
226
|
+
chai.request(server)
|
227
|
+
.post('/' + savedProject._id + '/departments/')
|
228
|
+
.auth(email, pwd)
|
229
|
+
.send({ id_project: "66977908249376002d57a434", name: "test-department", routing: "assigned", id_group: savedGroup._id })
|
230
|
+
.end((err, res) => {
|
231
|
+
|
232
|
+
if (err) { console.error("err: ", err) };
|
233
|
+
if (log) { console.log("savedDepartment: ", res.body); }
|
234
|
+
let savedDepartment = res.body;
|
235
|
+
|
236
|
+
chai.request(server)
|
237
|
+
.get('/projects/' + savedProject._id + '/users/availables/?department=' + savedDepartment._id)
|
238
|
+
.auth(email, pwd)
|
239
|
+
.end((err, res) => {
|
240
|
+
|
241
|
+
if (err) { console.error("err: ", err); }
|
242
|
+
if (log) { console.log("res.body: ", res.body); }
|
243
|
+
|
244
|
+
done();
|
245
|
+
})
|
246
|
+
|
247
|
+
})
|
248
|
+
})
|
249
|
+
})
|
250
|
+
})
|
251
|
+
})
|
252
|
+
}).timeout(10000)
|
253
|
+
|
179
254
|
});
|
180
255
|
|
181
256
|
});
|