@tiledesk/tiledesk-server 2.9.26 → 2.9.28

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.
@@ -17,8 +17,10 @@ var UIDGenerator = require("../utils/UIDGenerator");
17
17
  const { TdCache } = require('../utils/TdCache');
18
18
  const { QuoteManager } = require('./QuoteManager');
19
19
  var configGlobal = require('../config/global');
20
+ const projectService = require('./projectService');
20
21
  const axios = require("axios").default;
21
22
 
23
+
22
24
  const apiUrl = process.env.API_URL || configGlobal.apiUrl;
23
25
 
24
26
  let tdCache = new TdCache({
@@ -272,7 +274,7 @@ class RequestService {
272
274
  var beforeParticipants = requestBeforeRoute.participants;
273
275
  winston.debug("beforeParticipants: ", beforeParticipants);
274
276
 
275
- return that.routeInternal(request, departmentid, id_project, nobot).then(function (routedRequest) {
277
+ return that.routeInternal(request, departmentid, id_project, nobot).then( async function (routedRequest) {
276
278
 
277
279
  winston.debug("after routeInternal", routedRequest);
278
280
  // winston.info("requestBeforeRoute.participants " +requestBeforeRoute.request_id , requestBeforeRoute.participants);
@@ -286,13 +288,22 @@ class RequestService {
286
288
  winston.debug("beforeDepartmentId:" + beforeDepartmentId);
287
289
  }
288
290
 
291
+
289
292
  let afterDepartmentId;
290
293
  if (routedRequest.department) {
291
294
  afterDepartmentId = routedRequest.department.toString();
292
295
  winston.debug("afterDepartmentId:" + afterDepartmentId);
293
296
  }
294
297
 
295
-
298
+ winston.debug("requestBefore status: ", requestBeforeRoute.status)
299
+ winston.debug("routedRequest status: ", routedRequest.status)
300
+ /**
301
+ * Case 1
302
+ * After internal routing:
303
+ * - same STATUS
304
+ * - same DEPARTMENT
305
+ * - same PARTICIPANTS
306
+ */
296
307
  if (requestBeforeRoute.status === routedRequest.status &&
297
308
  beforeDepartmentId === afterDepartmentId &&
298
309
  requestUtil.arraysEqual(beforeParticipants, routedRequest.participants)) {
@@ -317,6 +328,62 @@ class RequestService {
317
328
  });
318
329
  }
319
330
 
331
+ let project = await projectService.getCachedProject(id_project).catch((err) => {
332
+ winston.warn("Error getting cached project. Skip conversation quota check.")
333
+ winston.warn("Getting cached project error: ", err)
334
+ })
335
+
336
+
337
+ let isTestConversation = false;
338
+ let isVoiceConversation = false;
339
+ let isStandardConversation = false;
340
+
341
+ let payload = {
342
+ project: project,
343
+ request: request
344
+ }
345
+
346
+ if (request.attributes && request.attributes.sourcePage && (request.attributes.sourcePage.indexOf("td_draft=true") > -1)) {
347
+ winston.verbose("is a test conversation --> skip quote availability check")
348
+ isTestConversation = true;
349
+ }
350
+ else if (request.channel && (request.channel.name === 'voice-vxml')) {
351
+ winston.verbose("is a voice conversation --> skip quote availability check")
352
+ isVoiceConversation = true;
353
+ }
354
+ else {
355
+ isStandardConversation = true;
356
+ let available = await qm.checkQuote(project, request, 'requests');
357
+ if (available === false) {
358
+ winston.info("Requests limits reached for project " + project._id)
359
+ return reject("Requests limits reached for project " + project._id);
360
+ }
361
+ }
362
+
363
+ /**
364
+ * Case 2 - Leaving TEMP status
365
+ * After internal routing:
366
+ * - STATUS changed from 50 to 100 or 200
367
+ */
368
+ if (requestBeforeRoute.status === RequestConstants.TEMP && (routedRequest.status === RequestConstants.ASSIGNED || routedRequest.status === RequestConstants.UNASSIGNED)) {
369
+ // console.log("Case 2 - Leaving TEMP status")
370
+ if (isStandardConversation) {
371
+ requestEvent.emit('request.create.quote', payload);
372
+ }
373
+ }
374
+
375
+ /**
376
+ * Case 3 - Conversation opened through proactive message
377
+ * After internal routing:
378
+ * - STATUS changed from undefined to 100
379
+ */
380
+ if ((!requestBeforeRoute.status || requestBeforeRoute.status === undefined) && routedRequest.status === RequestConstants.ASSIGNED) {
381
+ // console.log("Case 3 - 'Proactive' request")
382
+ if (isStandardConversation) {
383
+ requestEvent.emit('request.create.quote', payload);
384
+ }
385
+ }
386
+
320
387
  //cacheinvalidation
321
388
  return routedRequest.save(function (err, savedRequest) {
322
389
  // https://stackoverflow.com/questions/54792749/mongoose-versionerror-no-matching-document-found-for-id-when-document-is-being
@@ -469,6 +536,232 @@ class RequestService {
469
536
 
470
537
  async create(request) {
471
538
 
539
+ if (!request.createdAt) {
540
+ request.createdAt = new Date();
541
+ }
542
+
543
+ var request_id = request.request_id;
544
+ var project_user_id = request.project_user_id;
545
+ var lead_id = request.lead_id;
546
+ var id_project = request.id_project;
547
+ var first_text = request.first_text;
548
+ var departmentid = request.departmentid;
549
+ var sourcePage = request.sourcePage;
550
+ var language = request.language;
551
+ var userAgent = request.userAgent;
552
+ var status = request.status;
553
+ var createdBy = request.createdBy;
554
+ var attributes = request.attributes;
555
+ var subject = request.subject;
556
+ var preflight = request.preflight;
557
+ var channel = request.channel;
558
+ var location = request.location;
559
+ var participants = request.participants || [];
560
+ var tags = request.tags;
561
+ var notes = request.notes;
562
+ var priority = request.priority;
563
+ var auto_close = request.auto_close;
564
+ var followers = request.followers;
565
+ let createdAt = request.createdAt;
566
+
567
+ if (!departmentid) {
568
+ departmentid = 'default';
569
+ }
570
+
571
+ if (!createdBy) {
572
+ if (project_user_id) {
573
+ createdBy = project_user_id;
574
+ } else {
575
+ createdBy = "system";
576
+ }
577
+ }
578
+
579
+ // Utils
580
+ let payload;
581
+ let isTestConversation = false;
582
+ let isVoiceConversation = false;
583
+ let isStandardConversation = false;
584
+ var that = this;
585
+
586
+ return new Promise( async (resolve, reject) => {
587
+ var context = {
588
+ request: {
589
+ request_id: request_id, project_user_id: project_user_id, lead_id: lead_id, id_project: id_project,
590
+ first_text: first_text, departmentid: departmentid, sourcePage: sourcePage, language: language, userAgent: userAgent, status: status,
591
+ createdBy: createdBy, attributes: attributes, subject: subject, preflight: preflight, channel: channel, location: location,
592
+ participants: participants, tags: tags, notes: notes,
593
+ priority: priority, auto_close: auto_close, followers: followers
594
+ }
595
+ };
596
+ winston.debug("context", context);
597
+
598
+ var participantsAgents = [];
599
+ var participantsBots = [];
600
+ var hasBot = false;
601
+ var dep_id = undefined;
602
+ var assigned_at = undefined;
603
+ var agents = [];
604
+ var snapshot = {};
605
+
606
+ try {
607
+ // (method) DepartmentService.getOperators(departmentid: any, projectid: any, nobot: any, disableWebHookCall: any, context: any): Promise<any>
608
+ var result = await departmentService.getOperators(departmentid, id_project, false, undefined, context);
609
+ winston.debug("getOperators", result);
610
+
611
+ } catch (err) {
612
+ return reject(err);
613
+ }
614
+
615
+ agents = result.agents;
616
+
617
+ if (status == 50) {
618
+ // skip assignment
619
+ if (participants.length == 0) {
620
+ dep_id = result.department._id;
621
+ }
622
+ } else {
623
+
624
+ let project = await projectService.getCachedProject(id_project).catch((err) => {
625
+ winston.warn("Error getting cached project. Skip conversation quota check.")
626
+ winston.warn("Getting cached project error: ", err)
627
+ })
628
+
629
+ payload = {
630
+ project: project,
631
+ request: request
632
+ }
633
+
634
+ if (attributes && attributes.sourcePage && (attributes.sourcePage.indexOf("td_draft=true") > -1)) {
635
+ winston.verbose("is a test conversation --> skip quote availability check")
636
+ isTestConversation = true;
637
+ }
638
+ else if (channel && (channel.name === 'voice-vxml')) {
639
+ winston.verbose("is a voice conversation --> skip quote availability check")
640
+ isVoiceConversation = true;
641
+ }
642
+ else {
643
+ isStandardConversation = true;
644
+ let available = await qm.checkQuote(project, request, 'requests');
645
+ if (available === false) {
646
+ winston.info("Requests limits reached for project " + project._id)
647
+ return reject("Requests limits reached for project " + project._id);
648
+ }
649
+ }
650
+
651
+
652
+ if (participants.length == 0) {
653
+ if (result.operators && result.operators.length > 0) {
654
+ participants.push(result.operators[0].id_user.toString());
655
+ }
656
+ // for preflight it is important to save agents in req for trigger. try to optimize it
657
+ dep_id = result.department._id;
658
+ }
659
+
660
+ if (participants.length > 0) {
661
+ status = RequestConstants.ASSIGNED;
662
+ // botprefix
663
+ if (participants[0].startsWith("bot_")) {
664
+
665
+ hasBot = true;
666
+ winston.debug("hasBot:" + hasBot);
667
+
668
+ // botprefix
669
+ var assigned_operator_idStringBot = participants[0].replace("bot_", "");
670
+ winston.debug("assigned_operator_idStringBot:" + assigned_operator_idStringBot);
671
+
672
+ participantsBots.push(assigned_operator_idStringBot);
673
+
674
+ } else {
675
+
676
+ participantsAgents.push(participants[0]);
677
+
678
+ }
679
+
680
+ assigned_at = Date.now();
681
+
682
+ } else {
683
+ status = RequestConstants.UNASSIGNED;
684
+ }
685
+ }
686
+
687
+ if (dep_id) {
688
+ snapshot.department = result.department;
689
+ }
690
+
691
+ snapshot.agents = agents;
692
+ snapshot.availableAgentsCount = that.getAvailableAgentsCount(agents);
693
+
694
+ if (request.requester) {
695
+ snapshot.requester = request.requester;
696
+ }
697
+ if (request.lead) {
698
+ snapshot.lead = request.lead;
699
+ }
700
+
701
+ var newRequest = new Request({
702
+ request_id: request_id,
703
+ requester: project_user_id,
704
+ lead: lead_id,
705
+ first_text: first_text,
706
+ subject: subject,
707
+ status: status,
708
+ participants: participants,
709
+ participantsAgents: participantsAgents,
710
+ participantsBots: participantsBots,
711
+ hasBot: hasBot,
712
+ department: dep_id,
713
+ // agents: agents,
714
+ //others
715
+ sourcePage: sourcePage,
716
+ language: language,
717
+ userAgent: userAgent,
718
+ assigned_at: assigned_at,
719
+ attributes: attributes,
720
+ //standard
721
+ id_project: id_project,
722
+ createdBy: createdBy,
723
+ updatedBy: createdBy,
724
+ preflight: preflight,
725
+ channel: channel,
726
+ location: location,
727
+ snapshot: snapshot,
728
+ tags: tags,
729
+ notes: notes,
730
+ priority: priority,
731
+ auto_close: auto_close,
732
+ followers: followers,
733
+ createdAt: createdAt
734
+ });
735
+
736
+ if (isTestConversation) {
737
+ newRequest.draft = true;
738
+ }
739
+
740
+ winston.debug('newRequest.', newRequest);
741
+
742
+ //cacheinvalidation
743
+ return newRequest.save( async function (err, savedRequest) {
744
+
745
+ if (err) {
746
+ winston.error('RequestService error for method createWithIdAndRequester for newRequest' + JSON.stringify(newRequest), err);
747
+ return reject(err);
748
+ }
749
+ winston.debug("Request created", savedRequest.toObject());
750
+
751
+ requestEvent.emit('request.create.simple', savedRequest);
752
+
753
+ if (isStandardConversation) {
754
+ requestEvent.emit('request.create.quote', payload);;
755
+ }
756
+
757
+ return resolve(savedRequest);
758
+
759
+ });
760
+ })
761
+ }
762
+
763
+ async _create(request) {
764
+
472
765
  var startDate = new Date();
473
766
 
474
767
  if (!request.createdAt) {
@@ -512,6 +805,7 @@ class RequestService {
512
805
  var followers = request.followers;
513
806
  let createdAt = request.createdAt;
514
807
 
808
+
515
809
  if (!departmentid) {
516
810
  departmentid = 'default';
517
811
  }
@@ -560,11 +854,12 @@ class RequestService {
560
854
  isVoiceConversation = true;
561
855
  }
562
856
  else {
563
- let available = await qm.checkQuote(p, request, 'requests');
564
- if (available === false) {
565
- winston.info("Requests limits reached for project " + p._id)
566
- return false;
567
- }
857
+ // console.log("! check quota moved")
858
+ // let available = await qm.checkQuote(p, request, 'requests');
859
+ // if (available === false) {
860
+ // winston.info("Requests limits reached for project " + p._id)
861
+ // return false;
862
+ // }
568
863
  }
569
864
 
570
865
 
@@ -626,6 +921,18 @@ class RequestService {
626
921
 
627
922
  status = RequestConstants.ASSIGNED;
628
923
 
924
+ /**
925
+ * QUOTAS - START!!!
926
+ */
927
+ if (!isTestConversation && !isVoiceConversation) {
928
+ requestEvent.emit('request.create.quote', payload);
929
+ }
930
+ /**
931
+ * QUOTAS - END!!!
932
+ */
933
+
934
+
935
+
629
936
  // botprefix
630
937
  if (participants[0].startsWith("bot_")) {
631
938
 
@@ -736,7 +1043,7 @@ class RequestService {
736
1043
  requestEvent.emit('request.create.simple', savedRequest);
737
1044
 
738
1045
  if (!isTestConversation && !isVoiceConversation) {
739
- requestEvent.emit('request.create.quote', payload);;
1046
+ // requestEvent.emit('request.create.quote', payload);;
740
1047
  }
741
1048
 
742
1049
  return resolve(savedRequest);
@@ -752,7 +1059,7 @@ class RequestService {
752
1059
  }
753
1060
 
754
1061
 
755
- async _create(request) {
1062
+ async __create(request) {
756
1063
 
757
1064
  var startDate = new Date();
758
1065
 
@@ -2505,6 +2812,34 @@ class RequestService {
2505
2812
 
2506
2813
  }
2507
2814
 
2815
+ async getConversationsCount(id_project, status, preflight, hasBot, startDate, endDate) {
2816
+ return new Promise( async (resolve, reject) => {
2817
+ let query = { id_project: id_project, status: status, preflight: preflight};
2818
+ if (hasBot != null) {
2819
+ query.hasBot = hasBot;
2820
+ }
2821
+ if (status === 201) {
2822
+ query.status = {
2823
+ $in: [100,200]
2824
+ }
2825
+ }
2826
+ if (preflight === null) {
2827
+ delete query.preflight;
2828
+ }
2829
+ if (startDate && endDate) {
2830
+ query.createdAt = { $gte: startDate.toDate(), $lte: endDate.toDate() }
2831
+ }
2832
+ winston.debug("getConversationsCount query: ", query)
2833
+ let count = await Request.countDocuments(query).catch((err) => {
2834
+ winston.error("Error getting requests count: ", err);
2835
+ reject(err);
2836
+ })
2837
+ winston.verbose("Requests found for query " + JSON.stringify(query) + ": " + count);
2838
+ resolve(count)
2839
+ })
2840
+ }
2841
+
2842
+
2508
2843
  }
2509
2844
 
2510
2845
 
@@ -167,7 +167,7 @@
167
167
  style=" background-color: #ff8574 !important; border: none; color: white; padding: 6px 18px; text-align: center; text-decoration: none; display: inline-block; font-size: 14px; font-weight: 600; letter-spacing: 1px; margin: 4px 2px; cursor: pointer; border-radius: 8px;">
168
168
  Enjoy Tiledesk
169
169
  </a> -->
170
- <a href="https://panel.tiledesk.com/v3/cds/#/project/{{project_id}}/chatbot/{{chatbot_id}}/intent/0?jwt={{token}}"
170
+ <a href="{{redirect_url}}"
171
171
  style=" background-color: #ff8574 !important; border: none; color: white; padding: 6px 18px; text-align: center; text-decoration: none; display: inline-block; font-size: 14px; font-weight: 600; letter-spacing: 1px; margin: 4px 2px; cursor: pointer; border-radius: 8px;">
172
172
  Enjoy Tiledesk
173
173
  </a>
@@ -184,7 +184,7 @@
184
184
  {{baseScope.baseUrl}}/#/project/{{project_id}}/home
185
185
  </a> -->
186
186
  <a
187
- href="https://panel.tiledesk.com/v3/cds/#/project/{{project_id}}/chatbot/{{chatbot_id}}/intent/0?jwt={{token}}">
187
+ href="{{redirect_url}}">
188
188
  {{baseScope.baseUrl}}/#/project/{{project_id}}/home
189
189
  </a>
190
190
  </div>
@@ -68,6 +68,7 @@ const mockProjectBasicPlan = {
68
68
  "name": "mock-project",
69
69
  "activeOperatingHours": false,
70
70
  "createdBy": "64e36f5cbf72263f7c05ba36",
71
+ "isActiveSubscription": true,
71
72
  "profile": {
72
73
  "name": "Basic",
73
74
  "trialDays": 14,
@@ -110,6 +111,33 @@ const mockProjectPremiumPlan = {
110
111
  "createdAt": new Date('2023-10-16T08:45:54.058Z')
111
112
  }
112
113
 
114
+ const mockProjectPremiumPlan2 = {
115
+ "_id": "64e36f5dbf72263f7c059999",
116
+ "status": 100,
117
+ "ipFilterEnabled": false,
118
+ "ipFilter": [],
119
+ "ipFilterDenyEnabled": false,
120
+ "ipFilterDeny": [],
121
+ "name": "mock-project",
122
+ "activeOperatingHours": false,
123
+ "createdBy": "64e36f5cbf72263f7c05ba36",
124
+ "isActiveSubscription": true,
125
+ "profile": {
126
+ "name": "Premium",
127
+ "trialDays": 14,
128
+ "agents": 0,
129
+ "type": "payment",
130
+ "subStart": new Date('2024-01-31T10:00:00.058Z')
131
+ },
132
+ "versions": 20115,
133
+ "channels": [
134
+ {
135
+ "name": "chat21"
136
+ }
137
+ ],
138
+ "createdAt": new Date('2024-01-20T10:00:00.058Z')
139
+ }
140
+
113
141
  const mockProjectCustomPlan = {
114
142
  "_id": "64e36f5dbf72263f7c059999",
115
143
  "status": 100,
@@ -167,4 +195,4 @@ const mockOldProjecPlusPlan = {
167
195
  "ipFilterDenyEnabled": false
168
196
  }
169
197
 
170
- module.exports = { mockProjectUser, mockProjectFreeTrialPlan, mockProjectSandboxPlan, mockProjectBasicPlan, mockProjectPremiumPlan, mockProjectCustomPlan, mockOldProjecPlusPlan };
198
+ module.exports = { mockProjectUser, mockProjectFreeTrialPlan, mockProjectSandboxPlan, mockProjectBasicPlan, mockProjectPremiumPlan, mockProjectPremiumPlan2, mockProjectCustomPlan, mockOldProjecPlusPlan };
@@ -22,12 +22,13 @@ var Group = require('../models/group');
22
22
  var expect = chai.expect;
23
23
  var assert = chai.assert;
24
24
 
25
-
25
+ let operatingHours = '{"1":[{"start":"09:00","end":"13:00"},{"start":"14:00","end":"18:00"}],"2":[{"start":"09:00","end":"13:00"},{"start":"14:00","end":"18:00"}],"3":[{"start":"09:00","end":"11:00"},{"start":"14:00","end":"18:00"}],"4":[{"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"}';
26
26
  let timeSlotsSample = {
27
27
  "819559cc": {
28
28
  name: "Slot1",
29
29
  active: true,
30
- 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\"}"
30
+ //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\":\"America/Los_Angeles\"}"
31
+ hours: "{\"1\":[{\"start\":\"09:00\",\"end\":\"13:00\"},{\"start\":\"14:00\",\"end\":\"18:00\"}],\"3\":[{\"start\":\"09:00\",\"end\":\"15:00\"},{\"start\":\"17:00\",\"end\":\"18:00\"}],\"5\":[{\"start\":\"09:00\",\"end\":\"13:00\"},{\"start\":\"14:00\",\"end\":\"18:00\"}],\"tzname\":\"Europe/Rome\"}"
31
32
  },
32
33
  "5d4368de": {
33
34
  name: "Slot2",
@@ -115,6 +116,9 @@ describe('ProjectRoute', () => {
115
116
  })
116
117
  }).timeout(10000)
117
118
 
119
+
120
+
121
+
118
122
  it('updateProjectTimeSlots', (done) => {
119
123
 
120
124
  var email = "test-signup-" + Date.now() + "@email.com";
@@ -180,8 +184,47 @@ describe('ProjectRoute', () => {
180
184
  })
181
185
  }).timeout(10000)
182
186
 
183
- it('availableUsers', (done) => {
187
+ it('isOpenOperatingHours', (done) => {
188
+
189
+ var email = "test-signup-" + Date.now() + "@email.com";
190
+ var pwd = "pwd";
191
+
192
+ userService.signup(email, pwd, "Test Firstname", "Test Lastname").then((savedUser) => {
193
+ projectService.create("test-project-create", savedUser._id).then((savedProject) => {
194
+
195
+ chai.request(server)
196
+ // .put('/projects/' + savedProject._id + "/update")
197
+ .put('/projects/' + savedProject._id)
198
+ .auth(email, pwd)
199
+ .send({ activeOperatingHours: true, operatingHours: operatingHours })
200
+ .end((err, res) => {
201
+
202
+ if (log) { console.log("update project time slots res.body: ", res.body) };
203
+ res.should.have.status(200);
204
+ res.body.should.be.a('object');
205
+
206
+ chai.request(server)
207
+ .get('/projects/' + savedProject._id + '/isopen')
208
+ .auth(email, pwd)
209
+ .end((err, res) => {
210
+
211
+ if (err) { console.error("err: ", err) };
212
+ if (log) { console.log("res.body isopen: ", res.body) };
213
+
214
+ // Unable to do other checks due to currentTime change.
215
+ res.should.have.status(200);
216
+
217
+ done();
218
+
219
+ })
220
+ })
221
+
222
+
223
+ })
224
+ })
225
+ }).timeout(10000)
184
226
 
227
+ it('availableUsers', (done) => {
185
228
  var email = "test-signup-" + Date.now() + "@email.com";
186
229
  var pwd = "pwd";
187
230
 
@@ -198,6 +241,46 @@ describe('ProjectRoute', () => {
198
241
 
199
242
  done();
200
243
  })
244
+ })
245
+ })
246
+ })
247
+
248
+ it('utcChecker', (done) => {
249
+
250
+ var email = "test-signup-" + Date.now() + "@email.com";
251
+ var pwd = "pwd";
252
+
253
+ userService.signup(email, pwd, "Test Firstname", "Test Lastname").then((savedUser) => {
254
+ projectService.create("test-project-create", savedUser._id).then((savedProject) => {
255
+
256
+ chai.request(server)
257
+ // .put('/projects/' + savedProject._id + "/update")
258
+ .put('/projects/' + savedProject._id)
259
+ .auth(email, pwd)
260
+ .send({ timeSlots: timeSlotsSample })
261
+ .end((err, res) => {
262
+
263
+ if (log) { console.log("update project time slots res.body: ", res.body) };
264
+ res.should.have.status(200);
265
+ res.body.should.be.a('object');
266
+
267
+ chai.request(server)
268
+ .get('/projects/' + savedProject._id + '/isopen?timeSlot=819559cc')
269
+ .auth(email, pwd)
270
+ .end((err, res) => {
271
+
272
+ if (err) { console.error("err: ", err) };
273
+ if (log) { console.log("res.body isopen: ", res.body) };
274
+
275
+ // Unable to do other checks due to currentTime change.
276
+ res.should.have.status(200);
277
+
278
+ done();
279
+
280
+ })
281
+ })
282
+
283
+
201
284
  })
202
285
  })
203
286
  }).timeout(10000)