@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 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
  });