@tiledesk/tiledesk-server 2.3.16 → 2.3.18

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.
@@ -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.16",
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
+ })