@tiledesk/tiledesk-server 2.9.11 → 2.9.13
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/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
|
});
|