@tiledesk/tiledesk-server 2.9.3 → 2.9.5

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.5
9
+ - Added raw option in /users/availables
10
+
11
+ # 2.9.4
12
+ - Update tybot-connector to 0.2.86
13
+ - Added time-slots management
14
+
8
15
  # 2.9.3
9
16
  - Added log for AMQP error in closeOnErr
10
17
 
package/models/project.js CHANGED
@@ -34,6 +34,9 @@ var ProjectSchema = new Schema({
34
34
  operatingHours: {
35
35
  type: Object,
36
36
  },
37
+ timeSlots: {
38
+ type: Object,
39
+ },
37
40
  settings: {
38
41
  type: Object,
39
42
  default: function () {
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.3",
4
+ "version": "2.9.5",
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.84",
51
+ "@tiledesk/tiledesk-tybot-connector": "^0.2.86",
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
@@ -307,6 +307,10 @@ router.put('/:projectid', [passport.authenticate(['basic', 'jwt'], { session: fa
307
307
  if (req.body.operatingHours!=undefined) {
308
308
  update.operatingHours = req.body.operatingHours;
309
309
  }
310
+
311
+ if (req.body.timeSlots!=undefined) {
312
+ update.timeSlots = req.body.timeSlots;
313
+ }
310
314
 
311
315
  if (req.body.settings!=undefined) {
312
316
  update.settings = req.body.settings;
@@ -849,16 +853,32 @@ router.get('/', [passport.authenticate(['basic', 'jwt'], { session: false }), va
849
853
 
850
854
  // GET ALL PROJECTS BY CURRENT USER ID. usaed by unisalento to know if a project is open
851
855
  router.get('/:projectid/isopen', function (req, res) {
852
- operatingHoursService.projectIsOpenNow(req.params.projectid, function (isOpen, err) {
853
- winston.debug('project', req.params.projectid, 'isopen: ', isOpen);
854
856
 
855
- if (err) {
856
- winston.error('Error getting projectIsOpenNow', err);
857
- return res.status(500).send({ success: false, msg: err });
858
- }
859
- res.json({"isopen":isOpen});
860
- });
857
+ let project_id = req.params.projectid;
858
+ // Check if a timeSlot is passed
859
+ if (req.query.timeSlot) {
860
+ let slot_id = req.query.timeSlot;
861
+ operatingHoursService.slotIsOpenNow(project_id, slot_id, (isOpen, err) => {
862
+
863
+ if (err) {
864
+ winston.error("Error getting slotIsOpenNow ", err);
865
+ return res.status(500).send({ success: false, error: err });
866
+ }
867
+ return res.status(200).send({ isopen: isOpen})
868
+ })
869
+
870
+ } else {
861
871
 
872
+ operatingHoursService.projectIsOpenNow(project_id, function (isOpen, err) {
873
+ winston.debug('project', project_id, 'isopen: ', isOpen);
874
+
875
+ if (err) {
876
+ winston.error('Error getting projectIsOpenNow', err);
877
+ return res.status(500).send({ success: false, msg: err });
878
+ }
879
+ return res.status(200).send({ isopen: isOpen})
880
+ });
881
+ }
862
882
  });
863
883
 
864
884
  //togli questo route da qui e mettilo in altra route
@@ -866,52 +886,81 @@ router.get('/:projectid/isopen', function (req, res) {
866
886
  router.get('/:projectid/users/availables', function (req, res) {
867
887
  //winston.debug("PROJECT ROUTES FINDS AVAILABLES project_users: projectid", req.params.projectid);
868
888
 
869
- operatingHoursService.projectIsOpenNow(req.params.projectid, function (isOpen, err) {
870
- //winston.debug('P ---> [ OHS ] -> [ PROJECT ROUTES ] -> IS OPEN THE PROJECT: ', isOpen);
871
-
872
- if (err) {
873
- winston.debug('P ---> [ OHS ] -> [ PROJECT ROUTES ] -> IS OPEN THE PROJECT - EROR: ', err)
874
- // sendError(err, res);
875
- return res.status(500).send({ success: false, msg: err });
876
- } else if (isOpen) {
877
-
878
- Project_user.find({ id_project: req.params.projectid, user_available: true, role: { $in : [RoleConstants.OWNER, RoleConstants.ADMIN, RoleConstants.SUPERVISOR, RoleConstants.AGENT]}}).
879
- populate('id_user').
880
- exec(function (err, project_users) {
881
- if (err) {
882
- winston.debug('PROJECT ROUTES - FINDS AVAILABLES project_users - ERROR: ', err);
883
- return res.status(500).send({ success: false, msg: 'Error getting object.' });
884
- }
885
- if (project_users) {
886
-
887
- user_available_array = [];
888
- project_users.forEach(project_user => {
889
- if (project_user.id_user) {
890
- // winston.debug('PROJECT ROUTES - AVAILABLES PROJECT-USER: ', project_user)
891
- user_available_array.push({ "id": project_user.id_user._id, "firstname": project_user.id_user.firstname });
892
- } else {
893
- // winston.debug('PROJECT ROUTES - AVAILABLES PROJECT-USER (else): ', project_user)
894
- }
895
- });
896
-
897
- //winston.debug('ARRAY OF THE AVAILABLE USER ', user_available_array);
898
-
899
- res.json(user_available_array);
900
- }
901
- });
902
-
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);
911
+ }
912
+ });
913
+ } else {
914
+ operatingHoursService.projectIsOpenNow(req.params.projectid, function (isOpen, err) {
915
+ //winston.debug('P ---> [ OHS ] -> [ PROJECT ROUTES ] -> IS OPEN THE PROJECT: ', isOpen);
916
+
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) {
931
+
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
+ });
941
+
942
+ //winston.debug('ARRAY OF THE AVAILABLE USER ', user_available_array);
943
+
944
+ res.json(user_available_array);
945
+ }
946
+ });
947
+
948
+
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
+ }
903
957
 
904
- } else {
905
- // winston.debug('P ---> [ OHS ] -> [ PROJECT ROUTES ] -> IS OPEN THE PRJCT: ', isOpen, ' -> AVAILABLE EMPTY');
906
- // closed
907
- user_available_array = [];
908
- res.json(user_available_array);
909
- }
910
- });
958
+
911
959
 
912
960
  });
913
961
 
914
962
 
915
963
 
916
964
 
965
+
917
966
  module.exports = router;
@@ -175,7 +175,101 @@ class OperatingHoursService {
175
175
 
176
176
  } // ./end projectIsOpenNow
177
177
 
178
+ slotIsOpenNow(projectId, slot_id, callback) {
178
179
 
180
+ let q = Project.findOne({ _id: projectId, status: 100});
181
+ if (cacheEnabler.project) {
182
+ q.cache(cacheUtil.longTTL, "projects:id:"+projectId) //project_cache
183
+ winston.debug('project cache enabled for slotIsOpenNow');
184
+ }
185
+ q.exec( async (err, project) => {
186
+
187
+ if (err) {
188
+ winston.error("(slotIsOpenNow) Error getting project: ", err);
189
+ callback(null, { errorCode: 1000, msg: "Error getting project." })
190
+ return;
191
+ }
192
+ if (!project) {
193
+ winston.warn("(slotIsOpenNow) Project not found with id: " + projectId);
194
+ callback(null, { errorCode: 1010, msg: 'Project not found for id' + projectId });
195
+ return;
196
+ }
197
+
198
+ // Return ALWAYS true if the plan is free, trial is expired or the subscription is not active
199
+ if (project.profile && (project.profile.type === 'free' && project.trialExpired === true) || (project.profile.type === 'payment' && project.isActiveSubscription === false)) {
200
+ winston.debug('(slotIsOpenNow) Trial Expired or Subscription NOT Active')
201
+ callback(true, null) ;
202
+ return;
203
+ }
204
+
205
+ if (!project.timeSlots) {
206
+ winston.warn("(slotIsOpenNow) No time slots specified for the project " + projectId);
207
+ callback(true, null)
208
+ return
209
+ }
210
+
211
+ let timeSlot = project.timeSlots[slot_id];
212
+ console.log("timeSlot: ", timeSlot);
213
+
214
+ if (!timeSlot) {
215
+ callback(null, { errorCode: 1030, msg: 'Slot not found with id ' + slot_id })
216
+ return;
217
+ }
218
+
219
+ if (timeSlot.active == false) {
220
+ winston.verbose("(slotIsOpenNow) selected slot is not active")
221
+ callback(true, null);
222
+ return;
223
+ }
224
+
225
+ if (!timeSlot.hours) {
226
+ callback(null, { errorCode: 1020, msg: 'Operating hours is empty' });
227
+ return;
228
+ }
229
+
230
+ const hours = JSON.parse(timeSlot.hours);
231
+ const tzname = hours.tzname;
232
+ delete hours.tzname;
233
+
234
+ // Get the current time in the specified timezone
235
+ const currentTime = moment_tz.tz(tzname);
236
+ const currentWeekday = currentTime.isoWeekday();
237
+
238
+ const daySlots = hours[currentWeekday];
239
+ if (!daySlots) {
240
+ callback(false, null)
241
+ }
242
+
243
+ let promises = [];
244
+
245
+ daySlots.forEach((slot) => {
246
+ promises.push(slotCheck(currentTime, slot))
247
+ })
248
+
249
+ await Promise.all(promises).then((resp) => {
250
+ if (resp.indexOf(true) != -1) {
251
+ callback(true, null);
252
+ return;
253
+ }
254
+ callback(false, null);
255
+ return;
256
+ })
257
+ })
258
+ }
259
+ }
260
+
261
+ function slotCheck(currentTime, slot) {
262
+ return new Promise((resolve) => {
263
+
264
+ const startTime = moment_tz(slot.start, 'HH:mm');
265
+ const endTime = moment_tz(slot.end, 'HH:mm');
266
+
267
+ if (currentTime.isBetween(startTime, endTime, null, '[)')) {
268
+ resolve(true)
269
+ } else {
270
+ resolve(false);
271
+ }
272
+ })
179
273
  }
180
274
 
181
275
  function addOrSubstractProjcTzOffsetFromDateNow(prjcTimezoneName) {
@@ -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 = false;
5
+ let log = true;
6
6
  var projectService = require('../services/projectService');
7
7
  var userService = require('../services/userService');
8
8
 
@@ -19,6 +19,26 @@ const path = require('path');
19
19
  var expect = chai.expect;
20
20
  var assert = chai.assert;
21
21
 
22
+ let timeSlotsSample = {
23
+ "819559cc": {
24
+ name: "Slot1",
25
+ active: true,
26
+ hours: "{\"1\":[{\"start\":\"09:00\",\"end\":\"13:00\"},{\"start\":\"14:00\",\"end\":\"18:00\"}],\"3\":[{\"start\":\"09:00\",\"end\":\"13:00\"},{\"start\":\"14:00\",\"end\":\"18:00\"}],\"5\":[{\"start\":\"09:00\",\"end\":\"13:00\"},{\"start\":\"14:00\",\"end\":\"18:00\"}],\"tzname\":\"Europe/Rome\"}"
27
+ },
28
+ "5d4368de": {
29
+ name: "Slot2",
30
+ active: true,
31
+ hours: "{\"0\":[{\"start\":\"09:00\",\"end\":\"13:00\"},{\"start\":\"14:00\",\"end\":\"18:00\"}],\"6\":[{\"start\":\"09:00\",\"end\":\"13:00\"},{\"start\":\"14:00\",\"end\":\"18:00\"}],\"tzname\":\"Europe/Rome\"}"
32
+ },
33
+ "2975ec45": {
34
+ name: "Slot3",
35
+ active: false,
36
+ hours: "{\"0\":[{\"start\":\"09:00\",\"end\":\"13:00\"},{\"start\":\"14:00\",\"end\":\"18:00\"}],\"6\":[{\"start\":\"09:00\",\"end\":\"13:00\"},{\"start\":\"14:00\",\"end\":\"18:00\"}],\"tzname\":\"Europe/Rome\"}"
37
+ }
38
+ }
39
+
40
+
41
+
22
42
  chai.use(chaiHttp);
23
43
 
24
44
  describe('ProjectRoute', () => {
@@ -50,7 +70,7 @@ describe('ProjectRoute', () => {
50
70
  // .put('/projects/' + savedProject._id + "/update")
51
71
  .put('/projects/' + savedProject._id)
52
72
  .set('Authorization', superadmin_token)
53
- .send({ profile: { name: "Custom", quotes: { kbs: 1000} } })
73
+ .send({ profile: { name: "Custom", quotes: { kbs: 1000 } } })
54
74
  .end((err, res) => {
55
75
 
56
76
  if (log) { console.log("update project profile res.body: ", res.body) };
@@ -78,7 +98,7 @@ describe('ProjectRoute', () => {
78
98
  .put('/projects/' + savedProject._id)
79
99
  // .put('/projects/' + savedProject._id + "/update")
80
100
  .auth(email, pwd)
81
- .send({ profile: { name: "Custom", quotes: { kbs: 1000} } })
101
+ .send({ profile: { name: "Custom", quotes: { kbs: 1000 } } })
82
102
  .end((err, res) => {
83
103
 
84
104
  if (log) { console.log("update project profile res.body: ", res.body) };
@@ -90,6 +110,72 @@ describe('ProjectRoute', () => {
90
110
  })
91
111
  })
92
112
  }).timeout(10000)
113
+
114
+ it('updateProjectTimeSlots', (done) => {
115
+
116
+ var email = "test-signup-" + Date.now() + "@email.com";
117
+ var pwd = "pwd";
118
+
119
+ userService.signup(email, pwd, "Test Firstname", "Test Lastname").then((savedUser) => {
120
+ projectService.create("test-project-create", savedUser._id).then((savedProject) => {
121
+
122
+ chai.request(server)
123
+ // .put('/projects/' + savedProject._id + "/update")
124
+ .put('/projects/' + savedProject._id)
125
+ .auth(email, pwd)
126
+ .send({ timeSlots: timeSlotsSample })
127
+ .end((err, res) => {
128
+
129
+ if (log) { console.log("update project time slots res.body: ", res.body) };
130
+ res.should.have.status(200);
131
+ res.body.should.be.a('object');
132
+
133
+ done();
134
+ })
135
+ })
136
+ })
137
+ }).timeout(10000)
138
+
139
+ it('isOpenTimeSlot', (done) => {
140
+
141
+ var email = "test-signup-" + Date.now() + "@email.com";
142
+ var pwd = "pwd";
143
+
144
+ userService.signup(email, pwd, "Test Firstname", "Test Lastname").then((savedUser) => {
145
+ projectService.create("test-project-create", savedUser._id).then((savedProject) => {
146
+
147
+ chai.request(server)
148
+ // .put('/projects/' + savedProject._id + "/update")
149
+ .put('/projects/' + savedProject._id)
150
+ .auth(email, pwd)
151
+ .send({ timeSlots: timeSlotsSample })
152
+ .end((err, res) => {
153
+
154
+ if (log) { console.log("update project time slots res.body: ", res.body) };
155
+ res.should.have.status(200);
156
+ res.body.should.be.a('object');
157
+
158
+ chai.request(server)
159
+ .get('/projects/' + savedProject._id + '/isopen?timeSlot=819559cc')
160
+ .auth(email, pwd)
161
+ .end((err, res) => {
162
+
163
+ if (err) { console.error("err: ", err) };
164
+ if (log) { console.log("res.body isopen: ", res.body) };
165
+
166
+ // Unable to do other checks due to currentTime change.
167
+ res.should.have.status(200);
168
+
169
+ done();
170
+
171
+ })
172
+ })
173
+
174
+
175
+ })
176
+ })
177
+ }).timeout(10000)
178
+
93
179
  });
94
180
 
95
181
  });