@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 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.11",
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.94",
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
- //togli questo route da qui e mettilo in altra route
885
- // NEW - RETURN THE USER NAME AND THE USER ID OF THE AVAILABLE PROJECT-USER FOR THE PROJECT ID PASSED
886
- router.get('/:projectid/users/availables', function (req, res) {
887
- //winston.debug("PROJECT ROUTES FINDS AVAILABLES project_users: projectid", req.params.projectid);
888
-
889
- if (req.query.raw && (req.query.raw === true || req.query.raw === 'true')) {
890
- Project_user.find({ id_project: req.params.projectid, user_available: true, role: { $in : [RoleConstants.OWNER, RoleConstants.ADMIN, RoleConstants.SUPERVISOR, RoleConstants.AGENT]}}).
891
- populate('id_user').
892
- exec(function (err, project_users) {
893
- if (err) {
894
- winston.debug('PROJECT ROUTES - FINDS AVAILABLES project_users - ERROR: ', err);
895
- return res.status(500).send({ success: false, msg: 'Error getting object.' });
896
- }
897
- if (project_users) {
898
-
899
- user_available_array = [];
900
- project_users.forEach(project_user => {
901
- if (project_user.id_user) {
902
- // winston.debug('PROJECT ROUTES - AVAILABLES PROJECT-USER: ', project_user)
903
- user_available_array.push({ "id": project_user.id_user._id, "firstname": project_user.id_user.firstname });
904
- } else {
905
- // winston.debug('PROJECT ROUTES - AVAILABLES PROJECT-USER (else): ', project_user)
906
- }
907
- });
908
-
909
- //winston.debug('ARRAY OF THE AVAILABLE USER ', user_available_array);
910
- res.json(user_available_array);
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
- } else {
914
- operatingHoursService.projectIsOpenNow(req.params.projectid, function (isOpen, err) {
915
- //winston.debug('P ---> [ OHS ] -> [ PROJECT ROUTES ] -> IS OPEN THE PROJECT: ', isOpen);
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
- if (err) {
918
- winston.debug('P ---> [ OHS ] -> [ PROJECT ROUTES ] -> IS OPEN THE PROJECT - EROR: ', err)
919
- // sendError(err, res);
920
- return res.status(500).send({ success: false, msg: err });
921
- } else if (isOpen) {
922
-
923
- Project_user.find({ id_project: req.params.projectid, user_available: true, role: { $in : [RoleConstants.OWNER, RoleConstants.ADMIN, RoleConstants.SUPERVISOR, RoleConstants.AGENT]}}).
924
- populate('id_user').
925
- exec(function (err, project_users) {
926
- if (err) {
927
- winston.debug('PROJECT ROUTES - FINDS AVAILABLES project_users - ERROR: ', err);
928
- return res.status(500).send({ success: false, msg: 'Error getting object.' });
929
- }
930
- if (project_users) {
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
- user_available_array = [];
933
- project_users.forEach(project_user => {
934
- if (project_user.id_user) {
935
- // winston.debug('PROJECT ROUTES - AVAILABLES PROJECT-USER: ', project_user)
936
- user_available_array.push({ "id": project_user.id_user._id, "firstname": project_user.id_user.firstname });
937
- } else {
938
- // winston.debug('PROJECT ROUTES - AVAILABLES PROJECT-USER (else): ', project_user)
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
- //winston.debug('ARRAY OF THE AVAILABLE USER ', user_available_array);
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
- res.json(user_available_array);
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
- } else {
950
- // winston.debug('P ---> [ OHS ] -> [ PROJECT ROUTES ] -> IS OPEN THE PRJCT: ', isOpen, ' -> AVAILABLE EMPTY');
951
- // closed
952
- user_available_array = [];
953
- res.json(user_available_array);
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
 
@@ -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
- CUSTOM: { requests: 3000, messages: 0, tokens: 5000000, email: 200, chatbots: 20, namespace: 3, kbs: 1000 }
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();
@@ -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 = true;
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
  });