@tiledesk/tiledesk-server 2.3.17 → 2.3.18

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@tiledesk/tiledesk-chat21-app",
3
3
  "description": "The Tiledesk Chat21 module",
4
- "version": "1.1.4",
4
+ "version": "1.1.7",
5
5
  "private": false,
6
6
  "author": "Andrea Leo - Frontiere21 SRL",
7
7
  "license": "AGPL-3.0",
@@ -11,7 +11,7 @@
11
11
  "url": "https://github.com/Tiledesk/tiledesk-server"
12
12
  },
13
13
  "dependencies": {
14
- "@chat21/chat21-node-sdk": "^1.1.4",
14
+ "@chat21/chat21-node-sdk": "^1.1.7",
15
15
  "winston": "^3.3.3",
16
16
  "firebase-admin": "^9.5.0"
17
17
  },
@@ -37,6 +37,9 @@ var TagSchema = require("../models/tag");
37
37
  index: true
38
38
  // required: true
39
39
  },
40
+ profileStatus: {
41
+ type: String,
42
+ },
40
43
  presence: PresenceSchema,
41
44
  attributes: {
42
45
  type: Object,
@@ -108,5 +111,6 @@ Project_userSchema.virtual('isAuthenticated').get(function () {
108
111
  // Project_user.find({ id_project: projectid, id_user: { $in : group[0].members}, role: { $in : [RoleConstants.OWNER, RoleConstants.ADMIN, RoleConstants.AGENT]} })
109
112
  Project_userSchema.index({ id_project: 1, id_user:1, role: 1 });
110
113
 
114
+
111
115
  module.exports = mongoose.model('project_user', Project_userSchema);;
112
116
 
package/models/request.js CHANGED
@@ -273,7 +273,16 @@ var RequestSchema = new Schema({
273
273
  required: true,
274
274
  index: true
275
275
  },
276
-
276
+ smartAssignment: {
277
+ type: Boolean,
278
+ default: true,
279
+ index: true
280
+ },
281
+ workingStatus: { //new, pending
282
+ type: String,
283
+ required: false,
284
+ index: true
285
+ },
277
286
  createdBy: {
278
287
  type: String,
279
288
  required: true
@@ -465,6 +474,8 @@ RequestSchema.index({ id_project: 1, createdAt: 1, preflight: 1});
465
474
  RequestSchema.index({ hasBot: 1, status: 1, createdAt: 1});
466
475
 
467
476
 
477
+
478
+
468
479
  // cannot index parallel arrays [agents] [participants] {"driv
469
480
  // RequestSchema.index({ id_project: 1, status: 1, preflight:1, participants:1, "agents.id_user":1, updatedAt: -1 }); //NN LO APPLICA
470
481
 
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.3.17",
4
+ "version": "2.3.18",
5
5
  "scripts": {
6
6
  "start": "node ./bin/www",
7
7
  "pretest": "mongodb-runner start",
@@ -40,11 +40,11 @@
40
40
  "@tiledesk-ent/tiledesk-server-enterprise": "^1.0.0"
41
41
  },
42
42
  "dependencies": {
43
- "@tiledesk/tiledesk-chat21-app": "^1.1.4",
43
+ "@tiledesk/tiledesk-chat21-app": "^1.1.7",
44
44
  "@tiledesk/tiledesk-chatbot-util": "^0.8.33",
45
45
  "@tiledesk/tiledesk-json-rules-engine": "^4.0.3",
46
46
  "@tiledesk/tiledesk-rasa-connector": "^1.0.10",
47
- "@tiledesk/tiledesk-tybot-connector": "^0.1.4",
47
+ "@tiledesk/tiledesk-tybot-connector": "^0.1.5",
48
48
  "app-root-path": "^3.0.0",
49
49
  "bcrypt-nodejs": "0.0.3",
50
50
  "body-parser": "^1.20.0",
@@ -275,7 +275,7 @@ class ActivityArchiver {
275
275
  setImmediate(() => {
276
276
 
277
277
  try {
278
- winston.error('ActivityArchiver close');
278
+ winston.debug('ActivityArchiver close');
279
279
 
280
280
  var activity = new Activity({actor: {type:"user", id: request.closed_by},
281
281
  verb: "REQUEST_CLOSE", actionObj: request,
@@ -154,7 +154,7 @@ router.get('/', function (req, res) {
154
154
  return (err);
155
155
  }
156
156
 
157
- return Activity.count(query, function (err, totalRowCount) {
157
+ return Activity.countDocuments(query, function (err, totalRowCount) {
158
158
  if (err) {
159
159
  winston.error('Activity ROUTE - REQUEST FIND ERR ', err)
160
160
  return (err);
@@ -14,6 +14,10 @@ var CannedResponseSchema = new Schema({
14
14
  type: String,
15
15
  required: true,
16
16
  },
17
+ shared: {
18
+ type: Boolean,
19
+ required: true
20
+ },
17
21
  attributes: {
18
22
  type: Object,
19
23
  },
@@ -12,12 +12,18 @@ router.post('/', function (req, res) {
12
12
 
13
13
  var newCannedResponse = new CannedResponse({
14
14
  title: req.body.title,
15
- text: req.body.text,
15
+ text: req.body.text,
16
16
  id_project: req.projectid,
17
17
  createdBy: req.user.id,
18
18
  updatedBy: req.user.id
19
19
  });
20
20
 
21
+ if (req.projectuser.role == 'owner' || req.projectuser.role == 'admin') {
22
+ newCannedResponse.shared = true;
23
+ } else {
24
+ newCannedResponse.shared = false;
25
+ }
26
+
21
27
  newCannedResponse.save(function (err, savedCannedResponse) {
22
28
  if (err) {
23
29
  winston.error('--- > ERROR ', err)
@@ -104,7 +110,7 @@ router.get('/:cannedResponseid', function (req, res) {
104
110
  });
105
111
 
106
112
  router.get('/', function (req, res) {
107
- var limit = 40; // Number of CannedResponses per page
113
+ var limit = 1000; // Number of CannedResponses per page
108
114
  var page = 0;
109
115
 
110
116
  if (req.query.page) {
@@ -114,15 +120,15 @@ router.get('/', function (req, res) {
114
120
  var skip = page * limit;
115
121
  winston.debug('CannedResponse ROUTE - SKIP PAGE ', skip);
116
122
 
117
-
118
- var query = { "id_project": req.projectid, "status": {$lt:1000}};
123
+ // var query = { "id_project": req.projectid, "status": {$lt:1000}};
124
+ console.log("canned_req.user: ", req.user);
125
+ var query = {"id_project": req.projectid, "status": { $lt:1000 }, $or:[ { shared: true }, { createdBy: req.user._id } ] }
119
126
 
120
127
  if (req.query.full_text) {
121
128
  winston.debug('CannedResponse ROUTE req.query.fulltext', req.query.full_text);
122
129
  query.$text = { "$search": req.query.full_text };
123
130
  }
124
131
 
125
-
126
132
  var direction = -1; //-1 descending , 1 ascending
127
133
  if (req.query.direction) {
128
134
  direction = req.query.direction;
@@ -31,11 +31,25 @@ winston.debug('********* RequestNotification apiUrl: ' + apiUrl);
31
31
 
32
32
  class RequestNotification {
33
33
 
34
+ constructor() {
35
+ this.enabled = true;
36
+ if (process.env.EMAIL_NOTIFICATION_ENABLED=="false" || process.env.EMAIL_NOTIFICATION_ENABLED==false) {
37
+ this.enabled = false;
38
+ }
39
+ winston.debug("RequestNotification this.enabled: "+ this.enabled);
40
+ }
34
41
 
35
42
  listen() {
36
- var that = this;
43
+ var that = this;
37
44
 
38
45
 
46
+
47
+ if (this.enabled==true) {
48
+ winston.info("RequestNotification listener started");
49
+ } else {
50
+ return winston.info("RequestNotification listener disabled");
51
+ }
52
+
39
53
 
40
54
  var messageCreateKey = 'message.create';
41
55
  if (messageEvent.queueEnabled) {
@@ -813,7 +827,12 @@ sendAgentEmail(projectid, savedRequest) {
813
827
  // send email
814
828
  try {
815
829
 
816
-
830
+ // console.log("sendAgentEmail")
831
+ if (savedRequest.preflight === true) { //only for channel email and form preflight is false otherwise request.participants.update is used i think?
832
+ winston.debug("preflight request sendAgentEmail disabled")
833
+ return 0;
834
+ }
835
+
817
836
  Project.findOne({_id: projectid, status: 100}).select("+settings").exec( async function(err, project){
818
837
  if (err) {
819
838
  return winston.error(err);
@@ -834,6 +853,8 @@ sendAgentEmail(projectid, savedRequest) {
834
853
  // TODO fare il controllo anche sul dipartimento con modalità assigned o pooled
835
854
  if (savedRequest.status==RequestConstants.UNASSIGNED) { //POOLED
836
855
 
856
+ winston.debug("savedRequest.status==RequestConstants.UNASSIGNED");
857
+
837
858
  if (project.settings && project.settings.email && project.settings.email.notification && project.settings.email.notification.conversation && project.settings.email.notification.conversation.pooled == false ) {
838
859
  return winston.info("RequestNotification email notification for the project with id : " + projectid + " for the pooled conversation is disabled");
839
860
  }
@@ -906,6 +927,8 @@ sendAgentEmail(projectid, savedRequest) {
906
927
  // TODO fare il controllo anche sul dipartimento con modalità assigned o pooled
907
928
  else if (savedRequest.status==RequestConstants.ASSIGNED) { //ASSIGNED
908
929
 
930
+ winston.debug("savedRequest.status==RequestConstants.ASSIGNED");
931
+
909
932
  if (project.settings && project.settings.email && project.settings.email.notification && project.settings.email.notification.conversation && project.settings.email.notification.conversation.assigned == false ) {
910
933
  return winston.verbose("RequestNotification email notification for the project with id : " + projectid + " for the assigned conversation is disabled");
911
934
  }
@@ -2,7 +2,6 @@ var express = require('express');
2
2
  var router = express.Router({mergeParams: true});
3
3
  var Event = require("./event");
4
4
  var winston = require('../../config/winston');
5
- const eventEvent = require('./eventEvent');
6
5
  var validtoken = require('../../middleware/valid-token');
7
6
  const eventService = require('./eventService');
8
7
  const { check, validationResult } = require('express-validator');
@@ -10,6 +9,9 @@ var passport = require('passport');
10
9
  require('../../middleware/passport')(passport);
11
10
  var roleChecker = require('../../middleware/has-role');
12
11
 
12
+ const messageEvent = require('../../event/messageEvent');
13
+
14
+
13
15
  router.post('/', [
14
16
  passport.authenticate(['basic', 'jwt'],
15
17
  { session: false }),
@@ -37,13 +39,41 @@ router.post('/', [
37
39
  pu = req.projectuser.id
38
40
  }
39
41
 
42
+ console.log("************* emit event"+new Date().toISOString());
43
+
44
+ // // message.senderFullname, message.recipient,
45
+ // // message.recipient_fullname, message.text, message.sender, attributes, message.type, message.metadata, timestamp, message.group
46
+ // var recipient = req.body.attributes.request_id;
47
+ // console.log("recipient",recipient);
48
+ // var sender = req.user.id;
49
+ // console.log("sender",sender);
50
+
51
+ // messageEvent.emit("message.test",
52
+ // {
53
+ // recipient: recipient,
54
+ // recipient_fullname: "pluto",
55
+ // // sender:"bb0d809b-b093-419b-8b48-11a192cc3619",
56
+ // sender: sender,
57
+ // senderFullname: "Tiledesk",
58
+ // text:"welcome",
59
+ // group: {
60
+ // members: {
61
+ // // "bb0d809b-b093-419b-8b48-11a192cc3619": 1,
62
+ // sender: 1
63
+
64
+ // }
65
+ // }
66
+ // }
67
+ // );
68
+
40
69
  // emit(name, attributes, id_project, project_user, createdBy, status, user) {
41
70
  eventService.emit(req.body.name, req.body.attributes, req.projectid, pu, req.user.id, undefined, req.user).then(function(event) {
42
- res.json(event);
43
- }).catch(function(err) {
44
- winston.error('Error saving the event '+ JSON.stringify(event), err)
45
- return res.status(500).send({success: false, msg: 'Error saving the event '+ JSON.stringify(event)});
46
- });
71
+
72
+ res.json(event);
73
+ }).catch(function(err) {
74
+ winston.error('Error saving the event '+ JSON.stringify(event), err)
75
+ return res.status(500).send({success: false, msg: 'Error saving the event '+ JSON.stringify(event)});
76
+ });
47
77
 
48
78
  // var newEvent = new Event({
49
79
  // name: req.body.name,
@@ -137,7 +167,7 @@ router.get('/', [passport.authenticate(['basic', 'jwt'],
137
167
  }
138
168
 
139
169
  // collection.count is deprecated, and will be removed in a future version. Use Collection.countDocuments or Collection.estimatedDocumentCount instead
140
- return Event.count(query, function (err, totalRowCount) {
170
+ return Event.countDocuments(query, function (err, totalRowCount) {
141
171
 
142
172
  var objectToReturn = {
143
173
  perPage: limit,
@@ -102,9 +102,13 @@ projectEvent.on('project.create', async (project) => {
102
102
  */
103
103
 
104
104
 
105
- winston.info("triggers created for new project");
105
+ winston.debug("triggers created for new project");
106
106
 
107
107
 
108
+
109
+
110
+ // cc
111
+
108
112
  });
109
113
  });
110
114
 
package/routes/auth.js CHANGED
@@ -112,13 +112,18 @@ function (req, res) {
112
112
  winston.error("SigninAnonymously validation error", {errors: errors, reqBody: req.body, reqUrl: req.url });
113
113
  return res.status(422).json({ errors: errors.array() });
114
114
  }
115
- var firstname = req.body.firstname || "Guest";
115
+
116
+ let uid = uuidv4();
117
+ let shortuid = uid.substring(0,4);
118
+ var firstname = req.body.firstname || "guest#"+shortuid; // guest_here
119
+ // var firstname = req.body.firstname || "Guest"; // guest_here
120
+
116
121
 
117
122
 
118
123
  //TODO togli trattini da uuidv4()
119
124
 
120
125
  // TODO remove email.sec?
121
- let userAnonym = {_id: uuidv4(), firstname:firstname, lastname: req.body.lastname, email: req.body.email, attributes: req.body.attributes};
126
+ let userAnonym = {_id: uid, firstname:firstname, lastname: req.body.lastname, email: req.body.email, attributes: req.body.attributes};
122
127
 
123
128
  req.user = UserUtil.decorateUser(userAnonym);
124
129
 
@@ -220,6 +220,10 @@ router.put('/', [passport.authenticate(['basic', 'jwt'], { session: false }), va
220
220
  if (req.body.user_available!=undefined) {
221
221
  update.user_available = req.body.user_available;
222
222
  }
223
+
224
+ if (req.body.profileStatus!=undefined) {
225
+ update.profileStatus = req.body.profileStatus;
226
+ }
223
227
 
224
228
  if (req.body.max_assigned_chat!=undefined) {
225
229
  update.max_assigned_chat = req.body.max_assigned_chat;
@@ -241,6 +245,7 @@ router.put('/', [passport.authenticate(['basic', 'jwt'], { session: false }), va
241
245
 
242
246
 
243
247
 
248
+
244
249
  Project_user.findByIdAndUpdate(req.projectuser.id, update, { new: true, upsert: true }, function (err, updatedProject_user) {
245
250
  if (err) {
246
251
  winston.error("Error gettting project_user for update", err);
@@ -274,6 +279,10 @@ router.put('/:project_userid', [passport.authenticate(['basic', 'jwt'], { sessio
274
279
  update.user_available = req.body.user_available;
275
280
  }
276
281
 
282
+ if (req.body.profileStatus!=undefined) {
283
+ update.profileStatus = req.body.profileStatus;
284
+ }
285
+
277
286
  if (req.body.max_assigned_chat!=undefined) {
278
287
  update.max_assigned_chat = req.body.max_assigned_chat;
279
288
  }
package/routes/request.js CHANGED
@@ -162,6 +162,20 @@ router.patch('/:requestid', function (req, res) {
162
162
  update.priority = req.body.priority;
163
163
  }
164
164
 
165
+ if (req.body.smartAssignment!=undefined) {
166
+ update.smartAssignment = req.body.smartAssignment;
167
+ }
168
+
169
+ if (req.body.workingStatus!=undefined) {
170
+ update.workingStatus = req.body.workingStatus;
171
+ }
172
+
173
+
174
+ if (req.body.channelName) {
175
+ update["channel.name"] = req.body.channelName;
176
+ }
177
+
178
+
165
179
 
166
180
  winston.verbose("Request patch update",update);
167
181
 
@@ -710,6 +724,10 @@ router.get('/', function (req, res, next) {
710
724
  winston.debug('REQUEST ROUTE - QUERY DEPT ID', query.department);
711
725
  }
712
726
 
727
+ if (req.query.requester_email) {
728
+ query["snapshot.lead.email"] = req.query.requester_email;
729
+ }
730
+
713
731
  if (req.query.full_text) {
714
732
  winston.debug('req.query.fulltext', req.query.full_text);
715
733
  query.$text = { "$search": req.query.full_text };
@@ -8,6 +8,13 @@ var geoip = require('geoip-lite');
8
8
 
9
9
  class GeoService {
10
10
 
11
+ constructor() {
12
+ this.enabled = true;
13
+ if (process.env.GEO_SERVICE_ENABLED=="false" || process.env.GEO_SERVICE_ENABLED==false) {
14
+ this.enabled = false;
15
+ }
16
+ winston.debug("GeoService this.enabled: "+ this.enabled);
17
+ }
11
18
 
12
19
 
13
20
  // https://medium.com/@rossbulat/node-js-client-ip-location-with-geoip-lite-fallback-c25833c94a76
@@ -16,7 +23,12 @@ class GeoService {
16
23
 
17
24
  listen() {
18
25
 
19
- winston.info("GeoService listener started");
26
+ if (this.enabled==true) {
27
+ winston.info("GeoService listener started");
28
+ } else {
29
+ return winston.info("GeoService listener disabled");
30
+ }
31
+
20
32
 
21
33
 
22
34
 
@@ -36,9 +48,19 @@ class GeoService {
36
48
  // area: 200 }
37
49
 
38
50
 
39
- requestEvent.on('request.create', function(request) {
40
51
 
41
- winston.debug("request", request.toObject());
52
+ var requestCreateKey = 'request.create';
53
+ // if (requestEvent.queueEnabled) {
54
+ // requestCreateKey = 'request.create.queue';
55
+ // }
56
+ // winston.debug('GeoService requestCreateKey: ' + requestCreateKey);
57
+
58
+
59
+ requestEvent.on(requestCreateKey, function(request) {
60
+
61
+ setImmediate(() => {
62
+
63
+ winston.debug("request", request);
42
64
 
43
65
  var ip = (request.location && request.location.ipAddress) || (request.attributes && request.attributes.ipAddress);
44
66
  winston.debug("ip" + ip);
@@ -114,11 +136,15 @@ class GeoService {
114
136
  }
115
137
  return winston.verbose("Saved location metadata for request with id " + request._id);
116
138
  });
139
+
140
+ //TODO AGGIORNA ANCHE LEAD e req.snapshot.lead?
141
+ // leggi ip da request e nn da attributes
117
142
 
118
143
  }
119
144
  }
120
145
  });
121
- }
146
+ });
147
+ }
122
148
 
123
149
 
124
150
  }
@@ -82,7 +82,7 @@
82
82
 
83
83
  <div style="text-align:center">
84
84
  <a href="http://www.tiledesk.com" style="color:#2daae1;font-weight:bold;text-decoration:none;word-break:break-word" target="_blank">
85
- <img src="https://tiledesk.com/wp-content/uploads/2022/07/tiledesk_v2.png" style="width:10%;outline:none;text-decoration:none;border:none;min-height:36px" class="CToWUd">
85
+ <img src="https://tiledesk.com/wp-content/uploads/2022/07/tiledesk_v2.png" style="max-width:200px;outline:none;text-decoration:none;border:none;height:auto;margin-left:0px;" class="CToWUd">
86
86
  </a>
87
87
  </div>
88
88
  </tr>
@@ -0,0 +1,166 @@
1
+ //During the test the env variable is set to test
2
+ process.env.NODE_ENV = 'test';
3
+
4
+ //Require the dev-dependencies
5
+ let chai = require('chai');
6
+ let expect = require('chai').expect;
7
+
8
+ let chaiHttp = require('chai-http');
9
+ let server = require('../app');
10
+ const projectService = require('../services/projectService');
11
+ const userService = require('../services/userService');
12
+ var RoleConstants = require("../models/roleConstants");
13
+ const Project_user = require('../models/project_user');
14
+ let should = chai.should();
15
+
16
+
17
+
18
+ chai.use(chaiHttp);
19
+
20
+ describe('CannedRoute', () => {
21
+
22
+ it('new canned by owner/admin', (done) => {
23
+ var email = "test-signup-" + Date.now() + "@email.com";
24
+ var pwd = "pwd";
25
+
26
+ userService.signup(email, pwd, "Test Firstname", "Test Lastname").then(savedUser => {
27
+ projectService.create("test1", savedUser._id).then(savedProject => {
28
+
29
+ chai.request(server)
30
+ .post('/' + savedProject._id + '/canned/')
31
+ .auth(email, pwd)
32
+ .set('content-type', 'application/json')
33
+ .send({ "title": "Test Title", "text": "Test Text" })
34
+ .end((err, res) => {
35
+ console.log("res.body", res.body);
36
+ res.should.have.status(200);
37
+ res.body.should.be.a('object');
38
+ res.body.should.have.property('title').eql("Test Title");
39
+ res.body.should.have.property('text').eql("Test Text");
40
+ res.body.should.have.property('createdBy').eql(savedUser._id.toString());
41
+ res.body.should.have.property('shared').eql(true);
42
+
43
+ done();
44
+ })
45
+ })
46
+ })
47
+ })
48
+
49
+ it('new canned by agent', (done) => {
50
+ var email = "test-signup-" + Date.now() + "@email.com";
51
+ var pwd = "pwd";
52
+
53
+ userService.signup(email, pwd, "Test Firstname", "Test Lastname").then(savedUser => {
54
+ projectService.create("test1", savedUser._id).then(savedProject => {
55
+
56
+ console.log("RoleConstants.AGENT: ", RoleConstants.AGENT);
57
+ Project_user.findOneAndUpdate({id_project: savedProject._id, id_user: savedUser._id }, { role: RoleConstants.AGENT }, function(err, savedProject_user){
58
+ chai.request(server)
59
+ .post('/' + savedProject._id + '/canned/')
60
+ .auth(email, pwd)
61
+ .set('content-type', 'application/json')
62
+ .send({ title: "Test Title", text: "Test Text" })
63
+ .end((err, res) => {
64
+ console.log("res.body", res.body);
65
+ res.body.should.be.a('object');
66
+ res.body.should.have.property('title').eql("Test Title");
67
+ res.body.should.have.property('text').eql("Test Text");
68
+ res.body.should.have.property('createdBy').eql(savedUser._id.toString());
69
+ res.body.should.have.property('shared').eql(false);
70
+
71
+ done();
72
+ })
73
+ })
74
+ })
75
+ })
76
+ })
77
+
78
+ it('get canned', (done) => {
79
+
80
+ var email_owner = "owner-signup-" + Date.now() + "@email.com";
81
+ var email_agent = "agent-signup-" + Date.now() + "@email.com";
82
+ var pwd = "pwd";
83
+
84
+ userService.signup(email_owner, pwd, "Owner Firstname", "Owner Lastname").then(savedOwner => {
85
+ userService.signup(email_agent, pwd, "Agent Firstname", "Agent Lastname").then(savedAgent => {
86
+ projectService.create("test1", savedOwner._id).then(savedProject => {
87
+
88
+ // invite Agent on savedProject (?)
89
+ chai.request(server)
90
+ .post('/' + savedProject._id + "/project_users/invite")
91
+ .auth(email_owner, pwd)
92
+ .set('content-type', 'application/json')
93
+ .send({ email: email_agent, role: "agent", userAvailable: false })
94
+ .end((err, res) => {
95
+ console.log("res.boy", res.body)
96
+ res.should.have.status(200);
97
+
98
+
99
+ chai.request(server)
100
+ .post('/' + savedProject._id + "/canned/")
101
+ .auth(email_owner, pwd)
102
+ .set('content-type', 'application/json')
103
+ .send({ title: "Test1 Title", text: "Test1 Text" })
104
+ .end((err, res) => {
105
+
106
+ console.log("res.body", res.body);
107
+ res.should.have.status(200);
108
+ res.body.should.be.a('object');
109
+
110
+ chai.request(server)
111
+ .post('/' + savedProject._id + "/canned/")
112
+ .auth(email_agent, pwd)
113
+ .set('content-type', 'application/json')
114
+ .send({ title: "Test2 Title", text: "Test2 Text" })
115
+ .end((err, res) => {
116
+
117
+ console.log("res.body", res.body);
118
+ res.should.have.status(200);
119
+ res.body.should.be.a('object');
120
+
121
+ chai.request(server)
122
+ .get('/' + savedProject._id + "/canned/")
123
+ .auth(email_owner, pwd)
124
+ .set('content-type', 'application-json')
125
+ .send()
126
+ .end((err, res) => {
127
+
128
+ console.log("res.body", res.body);
129
+ res.should.have.status(200);
130
+ //res.body.should.be.a('array');
131
+
132
+ expect(res.body).to.be.an('array')
133
+ expect(res.body.length).to.equal(1);
134
+
135
+ chai.request(server)
136
+ .get('/' + savedProject._id + "/canned/")
137
+ .auth(email_agent, pwd)
138
+ .set('content-type', 'application-json')
139
+ .send()
140
+ .end((err, res) => {
141
+
142
+ console.log("res.body", res.body);
143
+ console.log("\n --> body.length", res.body.length);
144
+ res.should.have.status(200);
145
+ //res.body.should.be.a('array');
146
+
147
+ expect(res.body).to.be.an('array')
148
+ expect(res.body.length).to.equal(2);
149
+
150
+ done();
151
+
152
+ })
153
+
154
+
155
+ })
156
+
157
+
158
+ })
159
+
160
+ })
161
+ })
162
+ })
163
+ })
164
+ })
165
+ }).timeout(5000);
166
+ })