jxp 2.11.1 → 2.12.0

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/README.md CHANGED
@@ -35,4 +35,8 @@ JXP is an opinionated RESTful API framework that lets you make an API just by de
35
35
  * [Roles and Permissions](https://jxp.readthedocs.io/en/v2.0.0/permissions)
36
36
  * [Hooks](https://jxp.readthedocs.io/en/v2.0.0/hooks)
37
37
  * [Special Features](https://jxp.readthedocs.io/en/v2.0.0/special)
38
- * [Changelog](https://jxp.readthedocs.io/en/v2.0.0/changelog)
38
+ * [Changelog](https://jxp.readthedocs.io/en/v2.0.0/changelog)
39
+
40
+ ## Installing from source
41
+
42
+ `npm i --legacy-peer-deps`
package/bin/server.js CHANGED
@@ -196,17 +196,23 @@ const mongoose = require("mongoose");
196
196
  const JXP = require("../libs/jxp");
197
197
  const config = require("config");
198
198
  require("dotenv").config();
199
+ const pkg = require("../package.json");
199
200
 
200
201
  config.callbacks = {
201
- post: function(modelname, item, user) {
202
- // console.log("Post callback");
203
- },
204
- put: function(modelname, item, user) {
205
- // console.log("Put callback");
206
- },
207
- delete: function(modelname, item, user, opts) {
208
- // console.log("Delete callback");
209
- }
202
+ // Examples:
203
+ // post: function(modelname, item, user) {
204
+ // console.log("Post callback");
205
+ // },
206
+ // put: function(modelname, item, user) {
207
+ // console.log("Put callback");
208
+ // },
209
+ // delete: function(modelname, item, user, opts) {
210
+ // console.log("Delete callback");
211
+ // }
212
+
213
+ post: function() {},
214
+ put: function() {},
215
+ delete: function() {}
210
216
  };
211
217
 
212
218
  config.pre_hooks = {
@@ -259,7 +265,7 @@ var server = new JXP(config);
259
265
  let port = process.env.NODE_DOCKER_PORT || process.env.PORT || config.port || 4001;
260
266
  if (process.env.NODE_ENV === "test") port = 4005;
261
267
  server.listen(port, function() {
262
- console.log('%s listening at %s', server.name, server.url);
268
+ console.log('%s listening at %s', `${pkg.name} v${pkg.version}`, server.url);
263
269
  });
264
270
 
265
271
  module.exports = server; // For testing
package/libs/docs.js CHANGED
@@ -6,6 +6,7 @@ const md = require('jstransformer')(require('jstransformer-markdown-it'));
6
6
  const util = require('util');
7
7
  const readFile = util.promisify(fs.readFile);
8
8
  const schema_description = require("./schema_description");
9
+ const errors = require("restify-errors");
9
10
 
10
11
  class Docs {
11
12
  constructor(opts) {
@@ -32,7 +33,7 @@ class Docs {
32
33
  res.end();
33
34
  } catch(err) {
34
35
  console.error(err);
35
- return res.send(500, { status: "error", error: err, message: err.toString() });
36
+ return errors.InternalServerError({ message: err.toString() });
36
37
  }
37
38
  }
38
39
 
@@ -42,20 +43,20 @@ class Docs {
42
43
  res.send(models);
43
44
  } catch (err) {
44
45
  console.error(err);
45
- return res.send(500, { status: "error", error: err, message: err.toString() });
46
+ return errors.InternalServerError({ message: err.toString() });
46
47
  }
47
48
  }
48
49
 
49
50
  metaModel(req, res, next) {
50
51
  try {
51
52
  if (!req.Model) {
52
- return res.send(404, { status: "error", error: "Model not found" })
53
+ return errors.NotFoundError({ status: "error", error: "Model not found" })
53
54
  }
54
55
  res.send(req.Model.schema.paths);
55
56
  next();
56
57
  } catch (err) {
57
58
  console.error(err);
58
- return res.send(500, { status: "error", error: err, message: err.toString() });
59
+ return errors.InternalServerError({ message: err.toString() });
59
60
  }
60
61
  }
61
62
 
@@ -64,7 +65,7 @@ class Docs {
64
65
  res.send(this.models);
65
66
  next();
66
67
  } catch(err) {
67
- res.send(500, { status: "error", error: err, message: err.toString() });
68
+ errors.InternalServerError({ message: err.toString() });
68
69
  }
69
70
  }
70
71
 
@@ -73,7 +74,7 @@ class Docs {
73
74
  this.renderTemplate(res, "index", {});
74
75
  next();
75
76
  } catch(err) {
76
- res.send(500, { status: "error", error: err, message: err.toString() });
77
+ errors.InternalServerError({ message: err.toString() });
77
78
  }
78
79
  }
79
80
 
@@ -83,7 +84,7 @@ class Docs {
83
84
  const md_contents = md.render(body.toString()).body;
84
85
  this.renderTemplate(res, "md", { md_contents });
85
86
  } catch(err) {
86
- res.send(500, { status: "error", error: err, message: err.toString() });
87
+ errors.InternalServerError({ message: err.toString() });
87
88
  }
88
89
  }
89
90
 
@@ -97,7 +98,7 @@ class Docs {
97
98
  this.renderTemplate(res, "model", { model, fields, perms });
98
99
  next();
99
100
  } catch(err) {
100
- res.send(500, { status: "error", error: err, message: err.toString() });
101
+ errors.InternalServerError({ message: err.toString() });
101
102
  }
102
103
  }
103
104
  }
package/libs/groups.js CHANGED
@@ -1,4 +1,6 @@
1
- var Groups = null;
1
+ const errors = require("restify-errors");
2
+
3
+ let Groups = null;
2
4
 
3
5
  const init = config => {
4
6
  const path = require("path");
@@ -10,13 +12,11 @@ const actionPut = async (req, res) => {
10
12
  const group = req.body.group;
11
13
  if (!group) {
12
14
  console.error("Group required");
13
- res.send(400, "Group required");
14
- return;
15
+ return errors.BadRequestError("Group required");
15
16
  }
16
17
  if (!user_id) {
17
18
  console.error("user_id required");
18
- res.send(400, "user_id required");
19
- return;
19
+ return errors.BadRequestError("user_id required", { message: "user_id is required" });
20
20
  }
21
21
  try {
22
22
  let userGroup = await Groups.findOne({ user_id: user_id });
@@ -39,8 +39,7 @@ const actionPut = async (req, res) => {
39
39
  res.send(await userGroup.save());
40
40
  } catch(err) {
41
41
  console.error(err);
42
- res.send(500, err);
43
- return;
42
+ return errors.InternalServerError({ message: err.toString()});
44
43
  }
45
44
  };
46
45
 
@@ -49,13 +48,11 @@ const actionPost = async (req, res) => {
49
48
  const group = req.body.group;
50
49
  if (!group) {
51
50
  console.error("Group required");
52
- res.send(400, "Group required");
53
- return;
51
+ return errors.BadRequestError("Group required");
54
52
  }
55
53
  if (!user_id) {
56
54
  console.error("user_id required");
57
- res.send(400, "user_id required");
58
- return;
55
+ return errors.BadRequestError("user_id required", { message: "user_id is required" });
59
56
  }
60
57
  try {
61
58
  let userGroup = await Groups.findOne({ user_id: user_id });
@@ -78,8 +75,7 @@ const actionPost = async (req, res) => {
78
75
  res.send(await userGroup.save());
79
76
  } catch (err) {
80
77
  console.error(err);
81
- res.send(500, err);
82
- return;
78
+ return errors.InternalServerError({ message: err.toString()});
83
79
  }
84
80
  };
85
81
 
@@ -87,8 +83,7 @@ const actionGet = async (req, res) => {
87
83
  var user_id = req.params.user_id;
88
84
  if (!user_id) {
89
85
  console.error("user_id required");
90
- res.send(400, "user_id required");
91
- return;
86
+ return errors.BadRequestError("user_id required", { message: "user_id is required" });
92
87
  }
93
88
  try {
94
89
  let userGroup = await Groups.findOne({ user_id });
@@ -99,8 +94,7 @@ const actionGet = async (req, res) => {
99
94
  res.send(userGroup);
100
95
  } catch (err) {
101
96
  console.error(err);
102
- res.send(500, err);
103
- return;
97
+ return errors.InternalServerError({ message: err.toString()});
104
98
  }
105
99
  };
106
100
 
@@ -108,19 +102,16 @@ const actionDelete = async (req, res) => {
108
102
  const user_id = req.params.user_id;
109
103
  const group = req.query.group;
110
104
  if (!group) {
111
- res.send(400, "Group required");
112
- return;
105
+ return errors.BadRequestError("Group required");
113
106
  }
114
107
  if (!user_id) {
115
108
  console.error("user_id required");
116
- res.send(400, "user_id required");
117
- return;
109
+ return errors.BadRequestError("user_id required", { message: "user_id is required" });
118
110
  }
119
111
  try {
120
112
  let userGroup = await Groups.findOne({ user_id });
121
113
  if (!userGroup) {
122
- res.send(400, "User not found");
123
- return;
114
+ return errors.BadRequestError("User not found");
124
115
  }
125
116
  let i = userGroup.groups.indexOf(group);
126
117
  if (i > -1) {
@@ -129,8 +120,7 @@ const actionDelete = async (req, res) => {
129
120
  res.send(await userGroup.save());
130
121
  } catch (err) {
131
122
  console.error(err);
132
- res.send(500, err);
133
- return;
123
+ return errors.InternalServerError({ message: err.toString() });
134
124
  }
135
125
  };
136
126
 
package/libs/jxp.js CHANGED
@@ -1,3 +1,4 @@
1
+ const errors = require("restify-errors");
1
2
  const restify = require("restify");
2
3
  const path = require("path");
3
4
  const security = require("./security");
@@ -29,7 +30,7 @@ const middlewareModel = (req, res, next) => {
29
30
  return next();
30
31
  } catch (err) {
31
32
  console.error(new Date, err);
32
- return res.send(404, { status: "error", error: err, message: `Model ${modelname} not found` });
33
+ throw new errors.NotFoundError("Not Found", { message: `Model ${modelname} not found` });
33
34
  }
34
35
  };
35
36
 
@@ -50,8 +51,13 @@ const middlewareCheckAdmin = (req, res, next) => {
50
51
 
51
52
  // Outputs whatever is in res.result as JSON
52
53
  const outputJSON = (req, res, next) => {
53
- res.send(res.result);
54
- next();
54
+ try {
55
+ res.send(res.result);
56
+ next();
57
+ } catch (err) {
58
+ console.error(new Date(), err);
59
+ throw new errors.InternalServerError("Error generating output", { message: err.toString() });
60
+ }
55
61
  }
56
62
 
57
63
  // Outputs whatever is in res.result as CSV
@@ -59,7 +65,7 @@ const outputCSV = (req, res, next) => {
59
65
  const json2csv = require('json2csv').parse;
60
66
  const opts = { "flatten": true };
61
67
  if (!res.result.data) {
62
- return res.send(500, "Not CSVable data");
68
+ throw new errors.InternalServerError("Error generating output", { message: "Not CSVable data" });
63
69
  }
64
70
  try {
65
71
  const data = res.result.data.map(row => row._doc);
@@ -75,7 +81,7 @@ const outputCSV = (req, res, next) => {
75
81
  next();
76
82
  } catch (err) {
77
83
  console.error(err);
78
- res.send(500, { status: "error", error: err, message: err.toString() });
84
+ throw new errors.InternalServerError("Internal Error", { message: err.toString() });
79
85
  }
80
86
  }
81
87
 
@@ -83,13 +89,6 @@ const outputCSV = (req, res, next) => {
83
89
  const actionGet = async (req, res) => {
84
90
  const opname = `get ${req.modelname} ${ops++}`;
85
91
  console.time(opname);
86
- try {
87
- if (res.user) {
88
- req.Model.__user = res.user;
89
- }
90
- } catch(err) {
91
- console.error(err);
92
- }
93
92
  const parseSearch = function(search) {
94
93
  let result = {};
95
94
  for (let i in search) {
@@ -102,8 +101,7 @@ const actionGet = async (req, res) => {
102
101
  filters = parseFilter(req.query.filter);
103
102
  } catch (err) {
104
103
  console.trace(new Date(), err);
105
- res.send(500, { status: "error", error: err, message: err.toString() });
106
- return;
104
+ throw new errors.InternalServerError("Internal Error", { message: err.toString() });
107
105
  }
108
106
  let search = parseSearch(req.query.search);
109
107
  for (let i in search) {
@@ -124,6 +122,9 @@ const actionGet = async (req, res) => {
124
122
  countquery = Object.assign({ $text: { $search: req.query.search }}, countquery);
125
123
  qcount = req.Model.find({ $text: { $search: req.query.search }});
126
124
  }
125
+ if (res.user) {
126
+ q.options = ({ user: res.user });
127
+ }
127
128
  try {
128
129
  let count = await req.Model.estimatedDocumentCount();
129
130
  if (count < 100000 && Object.keys(countquery).length !== 0) {
@@ -189,7 +190,8 @@ const actionGet = async (req, res) => {
189
190
  } catch(err) {
190
191
  console.error(new Date(), err);
191
192
  if (debug) console.timeEnd(opname);
192
- res.send(500, { status: "error", message: err.toString() });
193
+ if (err.code) throw err;
194
+ throw new errors.InternalServerError("Internal Error", { message: err.toString() });
193
195
  }
194
196
  };
195
197
 
@@ -197,20 +199,14 @@ const actionGetOne = async (req, res) => {
197
199
  const opname = `getOne ${req.modelname}/${req.params.item_id} ${ops++}`;
198
200
  console.time(opname);
199
201
  try {
200
- if (res.user) {
201
- req.Model.__user = res.user;
202
- }
203
- const data = await getOne(req.Model, req.params.item_id, req.query);
202
+ const data = await getOne(req.Model, req.params.item_id, req.query, { user: res.user });
204
203
  res.send({ data });
205
204
  if (debug) console.timeEnd(opname);
206
205
  } catch(err) {
207
206
  console.error(new Date(), err);
208
207
  if (debug) console.timeEnd(opname);
209
- if (err.msg) {
210
- res.send(err.code || 500, { status: "error", message: err.msg });
211
- } else {
212
- res.send(err.code || 500, { status: "error", message: err.toString() });
213
- }
208
+ if (err.code) throw err;
209
+ throw new errors.InternalServerError("Internal Error", { message: err.toString() });
214
210
  }
215
211
  };
216
212
 
@@ -240,7 +236,7 @@ const actionPost = async (req, res) => {
240
236
  } catch (err) {
241
237
  console.error(new Date(), err);
242
238
  if (debug) console.timeEnd(opname);
243
- res.send(500, { status: "error", message: err.toString() });
239
+ throw new errors.InternalServerError("Internal Error", { message: err.toString() });
244
240
  }
245
241
  };
246
242
 
@@ -251,8 +247,7 @@ const actionPut = async (req, res) => {
251
247
  let item = await req.Model.findById(req.params.item_id);
252
248
  if (!item) {
253
249
  console.error(new Date(), "Document not found");
254
- res.send(404, { status: "error", message: "Document not found" });
255
- return;
250
+ throw new errors.NotFoundError("Not Found", { message: "Document not found" });
256
251
  }
257
252
  _populateItem(item, datamunging.deserialize(req.body));
258
253
  _versionItem(item);
@@ -276,8 +271,7 @@ const actionPut = async (req, res) => {
276
271
  } catch (err) {
277
272
  console.error(new Date(), err);
278
273
  if (debug) console.timeEnd(opname);
279
- res.send(500, { status: "error", message: err.toString() });
280
- return;
274
+ throw new errors.InternalServerError("Internal Error", { message: err.toString() });
281
275
  }
282
276
  };
283
277
 
@@ -302,8 +296,7 @@ const actionUpdate = async (req, res) => {
302
296
  } catch (err) {
303
297
  console.error(new Date(), err);
304
298
  if (debug) console.timeEnd(opname);
305
- res.send(500, { status: "error", message: err.toString() });
306
- return;
299
+ throw new errors.InternalServerError("Internal Error", { message: err.toString() });
307
300
  }
308
301
  };
309
302
 
@@ -317,8 +310,7 @@ const actionDelete = async (req, res) => {
317
310
  let item = await req.Model.findById(req.params.item_id);
318
311
  if (!item) {
319
312
  console.error(new Date(), "Couldn't find item for delete");
320
- res.send(404, "Could not find document");
321
- return;
313
+ throw new errors.NotFoundError("Not Found", { message: "Couldn't find item for delete" });
322
314
  }
323
315
  // Get linked models
324
316
  const linked_models = [];
@@ -347,8 +339,7 @@ const actionDelete = async (req, res) => {
347
339
  await models[linked_model.modelname].updateMany(q, { _deleted: true });
348
340
  }
349
341
  } else {
350
- res.send(409, { status: "error", message: `Parent link item exists in ${linked_model.modelname}/${linked_model.field}` });
351
- return;
342
+ throw new errors.ConflictError("Conflict Error", { message: `Parent link item exists in ${linked_model.modelname}/${linked_model.field}` });
352
343
  }
353
344
  }
354
345
  }
@@ -381,8 +372,8 @@ const actionDelete = async (req, res) => {
381
372
  } catch(err) {
382
373
  console.error(new Date(), err);
383
374
  if (debug) console.timeEnd(opname);
384
- res.send(500, { status: "error", message: err.toString() });
385
- return;
375
+ if (err.code) throw err;
376
+ throw new errors.InternalServerError("Internal Error", { message: err.toString() });
386
377
  }
387
378
  };
388
379
 
@@ -401,8 +392,7 @@ const actionCount = async (req, res) => {
401
392
  filters = parseFilter(req.query.filter);
402
393
  } catch (err) {
403
394
  console.trace(new Date(), err);
404
- res.send(500, { status: "error", error: err, message: err.toString() });
405
- return;
395
+ throw new errors.InternalServerError("Internal Error", { message: err.toString() });
406
396
  }
407
397
  let search = parseSearch(req.query.search);
408
398
  for (let i in search) {
@@ -418,7 +408,8 @@ const actionCount = async (req, res) => {
418
408
  } catch(err) {
419
409
  console.error(new Date(), err);
420
410
  if (debug) console.timeEnd(opname);
421
- res.send(500, { status: "error", message: err.toString() });
411
+ if (err.code) throw err;
412
+ throw new errors.InternalServerError("Internal Error", { message: err.toString() });
422
413
  }
423
414
  };
424
415
 
@@ -431,7 +422,8 @@ const actionCall = async (req, res) => {
431
422
  res.json(result);
432
423
  } catch(err) {
433
424
  console.error(new Date(), err);
434
- res.send(500, { status: "error", message: err.toString() });
425
+ if (err.code) throw err;
426
+ throw new errors.InternalServerError("Internal Error", { message: err.toString() });
435
427
  }
436
428
  };
437
429
 
@@ -439,16 +431,15 @@ const actionCallItem = async (req, res) => {
439
431
  try {
440
432
  const item = req.Model.findById(req.params.item_id);
441
433
  if (!item) {
442
- res.send(404, "Document not found for " + req.params.method_name);
443
- return;
434
+ throw new errors.NotFoundError("Not Found", { message: "Couldn't find item for call" });
444
435
  }
445
436
  req.params.__user = res.user || null;
446
437
  const result = await req.Model[req.params.method_name](item);
447
438
  res.json(result);
448
-
449
439
  } catch(err) {
450
440
  console.trace(err);
451
- res.send(500, { status: "error", message: err.toString() });
441
+ if (err.code) throw err;
442
+ throw new errors.InternalServerError("Internal Error", { message: err.toString() });
452
443
  }
453
444
  };
454
445
 
@@ -456,7 +447,7 @@ const actionCallItem = async (req, res) => {
456
447
  const actionQuery = async (req, res) => {
457
448
  if (!req.body || !req.body.query || typeof req.body.query !== "object") {
458
449
  console.error("query missing or not of type object")
459
- return res.send(500, { status: "error", message: "query missing or not of type object" });
450
+ throw new errors.InternalServerError("Query missing", { message: "query missing or not of type object" });
460
451
  }
461
452
  const opname = `query ${req.modelname} ${ops++}`;
462
453
  console.time(opname);
@@ -525,7 +516,8 @@ const actionQuery = async (req, res) => {
525
516
  } catch(err) {
526
517
  console.error(new Date(), err);
527
518
  if (debug) console.timeEnd(opname);
528
- res.send(500, { status: "error", message: err.toString() });
519
+ if (err.code) throw err;
520
+ throw new errors.InternalServerError("Internal Error", { message: err.toString() });
529
521
  }
530
522
  };
531
523
 
@@ -534,7 +526,7 @@ const actionAggregate = async (req, res) => {
534
526
  let query = (req.body.query) ? req.body.query : req.body; // Don't require to embed in query anymore
535
527
  if (!query || !Array.isArray(query)) {
536
528
  console.error("query missing or not of type array")
537
- return res.send(500, { status: "error", message: "query missing or not of type array" });
529
+ throw new errors.InternalServerError("Query missing", { message: "query missing or not of type array" });
538
530
  }
539
531
  query = query_manipulation.fix_query(query);
540
532
  const opname = `aggregate ${req.modelname} ${ops++}`;
@@ -552,7 +544,7 @@ const actionAggregate = async (req, res) => {
552
544
  } catch (err) {
553
545
  console.error(new Date(), err);
554
546
  if (debug) console.timeEnd(opname);
555
- res.send(500, { status: "error", message: err.toString() });
547
+ throw new errors.InternalServerError("Internal Error", { message: err.toString() });
556
548
  }
557
549
  };
558
550
 
@@ -560,7 +552,7 @@ const actionAggregate = async (req, res) => {
560
552
  const actionBulkWrite = async (req, res) => {
561
553
  if (!req.body || !Array.isArray(req.body)) {
562
554
  console.error("query missing or not of type array")
563
- return res.send(500, { status: "error", message: "query missing or not of type array" });
555
+ throw new errors.InternalServerError("Query Missing", { message: "query missing or not of type array" });
564
556
  }
565
557
  const opname = `bulkwrite ${req.modelname} ${ops++}`;
566
558
  console.time(opname);
@@ -575,7 +567,7 @@ const actionBulkWrite = async (req, res) => {
575
567
  } catch (err) {
576
568
  console.error(new Date(), err);
577
569
  if (debug) console.timeEnd(opname);
578
- res.send(500, { status: "error", message: err.toString() });
570
+ throw new errors.InternalServerError("Internal Error", { message: err.toString() });
579
571
  }
580
572
  };
581
573
 
@@ -613,8 +605,8 @@ const actionBulkWrite = async (req, res) => {
613
605
 
614
606
  // Utitlities
615
607
 
616
- const getOne = async (Model, item_id, params) => {
617
- const query = Model.findById(item_id);
608
+ const getOne = async (Model, item_id, params, options) => {
609
+ const query = Model.findById(item_id, {}, options);
618
610
  if (params.populate) {
619
611
  if ((typeof params.populate === "object") && !Array.isArray(params.populate)) {
620
612
  for (let i in params.populate) {
@@ -636,11 +628,11 @@ const getOne = async (Model, item_id, params) => {
636
628
  var item = await query.exec();
637
629
  if (!item) {
638
630
  // console.error("Could not find document");
639
- return Promise.reject({ code: 404, msg: "Could not find document" });
631
+ throw new errors.NotFoundError("Could not find document", { message: "Could not find document" });
640
632
  }
641
633
  if (item._deleted && !params.showDeleted) {
642
634
  // console.error("Document is deleted");
643
- return Promise.reject({ code: 404, msg: "Document is deleted" });
635
+ throw new errors.NotFoundError("Document is deleted", { message: "Document is deleted" });
644
636
  }
645
637
  item = item.toObject();
646
638
  //Don't ever return passwords
@@ -648,7 +640,8 @@ const getOne = async (Model, item_id, params) => {
648
640
  return item;
649
641
  } catch(err) {
650
642
  console.error(err);
651
- return Promise.reject({ code: 500, msg: err });
643
+ if (err.code) throw err;
644
+ throw new errors.InternalServerError("Internal Error", { message: err.toString() });
652
645
  }
653
646
  };
654
647
 
package/libs/login.js CHANGED
@@ -3,13 +3,12 @@ const jwt = require("jsonwebtoken");
3
3
  const bcrypt = require('bcryptjs');
4
4
  const security = require("../libs/security");
5
5
  const nodemailer = require('nodemailer');
6
+ const errors = require("restify-errors");
6
7
  const smtpTransport = require('nodemailer-smtp-transport');
7
- var User = null;
8
- var APIKey = null;
8
+ const path = require("path");
9
+ let User = null;
9
10
 
10
11
  var init = function (config) {
11
- var path = require("path");
12
- APIKey = require(path.join(config.model_dir, 'apikey_model'));
13
12
  User = require(path.join(config.model_dir, 'user_model'));
14
13
  security.init(config);
15
14
  };
@@ -30,12 +29,11 @@ const recover = async (req, res) => {
30
29
  const email = req.body.email;
31
30
  if (!email) {
32
31
  console.error("Missing email parameter");
33
- res.send(400, { status: "fail", message: "Missing email parameter" });
34
- return;
32
+ throw new errors.BadRequestError("Bad Request", { status: "fail", message: "Missing email parameter" });
35
33
  }
36
34
  const user = await User.findOne({ email });
37
35
  if (!user) {
38
- throw ("Could not find email");
36
+ throw new errors.NotFoundError("User Not Found", { status: "fail", message: "User not found" });
39
37
  }
40
38
  const result = await security.generateApiKey(user._id);
41
39
  const token = jwt.sign({ apikey: result.apikey, email: user.email, id: user._id }, req.config.shared_secret, { expiresIn: "2d" });
@@ -57,26 +55,27 @@ const recover = async (req, res) => {
57
55
  });
58
56
  res.send({ status: "ok", message: "Sent recovery email" });
59
57
  } catch (err) {
60
- res.send(403, { status: "fail", message: "Unauthorized", err });
58
+ if (err.code) throw err;
59
+ throw new errors.UnauthorizedError("Unauthorized", { status: "fail", message: "Unauthorized", info: err });
61
60
  }
62
61
  }
63
62
 
64
63
  const logout = async (req, res) => {
65
64
  try {
66
- if (!res.user) throw("You don't seem to be logged in");
65
+ if (!res.user) throw new errors.ForbiddenError("Forbidden", { message: "You don't seem to be logged in" });
67
66
  await security.revokeToken(res.user._id);
68
67
  res.send({ status: "ok", message: "User logged out" });
69
68
  } catch(err) {
70
69
  console.error(err);
71
- res.send(500, { status: "error", error: err });
70
+ if (err.code) throw err;
71
+ throw new errors.InternalServerError("Server Error", { status: "error", message: err.toString() });
72
72
  }
73
73
  }
74
74
 
75
75
  const oauth = (req, res, next) => { // Log in through an OAuth2 provider, defined in config.js
76
76
  const provider_config = req.config.oauth[req.params.provider];
77
77
  if (!provider_config) {
78
- res.send(500, req.params.provider + " config not defined");
79
- return;
78
+ throw new errors.InternalServerError("Internal Server Error", { message: req.params.provider + " config not defined" });
80
79
  }
81
80
  const state = Math.random().toString(36).substring(7);
82
81
  const uri = `${provider_config.auth_uri}?client_id=${provider_config.app_id}&redirect_uri=${req.config.url}/login/oauth/callback/${req.params.provider}&scope=${provider_config.scope}&state=${state}&response_type=code`;
@@ -149,8 +148,7 @@ const login = async (req, res) => {
149
148
  }
150
149
  if ((!password) || (!email)) {
151
150
  console.error(new Date(), "Missing email or password parameters");
152
- res.send(404, { status: "fail", message: "Missing email or password parameters" });
153
- return;
151
+ return errors.ForbiddenError({ status: "fail", message: "Missing email or password parameters" });
154
152
  }
155
153
  try {
156
154
  const user = await User.findOne({ email });
@@ -171,28 +169,25 @@ const login = async (req, res) => {
171
169
  provider: token.provider,
172
170
  });
173
171
  } catch (err) {
174
- res.send(401, { status: "fail", message: "Authentication failed", err });
175
172
  console.error(new Date(), `Authentication failed`, ip, err);
176
- return;
173
+ if (err.code) throw err;
174
+ return errors.ForbiddenError({ status: "fail", message: "Authentication failed" });
177
175
  }
178
176
  }
179
177
 
180
178
  const getJWT = async (req, res) => {
181
179
  var user = null;
182
180
  if (!res.user.admin) {
183
- res.send(403, { status: "fail", message: "Unauthorized" });
184
- return;
181
+ throw new errors.UnauthorizedError("Unauthorized", { status: "fail", message: "Unauthorized" });
185
182
  }
186
183
  var email = req.params.email || req.body.email;
187
184
  if (!email) {
188
- res.send(400, { status: "fail", message: "Email required" });
189
- return;
185
+ throw new errors.BadRequestError("Bad Request", { status: "fail", message: "Email required" });
190
186
  }
191
187
  try {
192
188
  const result = await User.findOne({ email: email });
193
189
  if (!result || !result._id) {
194
- res.send(404, { status: "fail", message: "User not found" });
195
- return;
190
+ throw new errors.NotFoundError("Not Found", { status: "fail", message: "User not found" });
196
191
  }
197
192
  user = result;
198
193
  try {
@@ -202,11 +197,11 @@ const getJWT = async (req, res) => {
202
197
  });
203
198
  res.send({ email: user.email, token: token });
204
199
  } catch (err) {
205
- res.send(403, { status: "fail", message: "Unauthorized" });
206
- return;
200
+ throw new errors.UnauthorizedError("Unauthorized", { status: "fail", message: "Unauthorized" });
207
201
  }
208
202
  } catch (err) {
209
- res.send(500, { status: "error", error: err });
203
+ if (err.code) throw err;
204
+ throw new errors.InternalServerError("Internal Server Error", { status: "error", message: err.toString() });
210
205
  }
211
206
  }
212
207
 
@@ -9,7 +9,7 @@ const getModelFileContents = (model_dir) => {
9
9
  return reject(err);
10
10
  }
11
11
  let models = [];
12
- for (file of files) {
12
+ for (const file of files) {
13
13
  const modelname = path.basename(file, ".js").replace("_model", "");
14
14
  try {
15
15
  const modelobj = require(path.join(model_dir, file));
package/libs/security.js CHANGED
@@ -1,6 +1,7 @@
1
1
  const bcrypt = require("bcryptjs");
2
2
  const randToken = require("rand-token");
3
3
  const path = require("path");
4
+ const errors = require("restify-errors");
4
5
  var APIKey = null;
5
6
  var Token = null;
6
7
  var Groups = null;
@@ -17,10 +18,6 @@ const init = function(config) {
17
18
  if (config.url) provider = config.url;
18
19
  };
19
20
 
20
- const fail = function (res, code, message) {
21
- res.send(code, { status: "error", message });
22
- };
23
-
24
21
  const basicAuthData = function(req) {
25
22
  if (!req.headers.authorization) {
26
23
  return false;
@@ -51,7 +48,7 @@ const basicAuth = async ba => {
51
48
  return user;
52
49
  } catch(err) {
53
50
  console.error(new Date(), err);
54
- return Promise.reject(err);
51
+ throw err;
55
52
  }
56
53
  };
57
54
 
@@ -84,7 +81,7 @@ const bearerAuth = async t => {
84
81
  return user;
85
82
  } catch (err) {
86
83
  console.error(err);
87
- return Promise.reject(err);
84
+ throw err;
88
85
  }
89
86
  }
90
87
 
@@ -98,7 +95,7 @@ const apiKeyAuth = async apikey => {
98
95
  return user;
99
96
  } catch(err) {
100
97
  console.error(new Date(), err);
101
- return Promise.reject(err);
98
+ throw err;
102
99
  }
103
100
  };
104
101
 
@@ -109,7 +106,7 @@ const getGroups = async user_id => {
109
106
  return groups;
110
107
  } catch(err) {
111
108
  console.error(new Date(), err);
112
- return Promise.reject(err);
109
+ throw err;
113
110
  }
114
111
  };
115
112
 
@@ -131,7 +128,7 @@ const generateApiKey = async user_id => {
131
128
  return apikey;
132
129
  } catch(err) {
133
130
  console.error(new Date(), err);
134
- return Promise.reject(err);
131
+ throw err;
135
132
  }
136
133
  };
137
134
 
@@ -156,16 +153,21 @@ const generateToken = async user_id => {
156
153
  return token;
157
154
  } catch (err) {
158
155
  console.error(new Date(), err);
159
- return Promise.reject(err);
156
+ throw err;
160
157
  }
161
158
  };
162
159
 
163
160
  const ensureToken = async user_id => {
164
- const token = await Token.findOne({ user_id, provider }).sort({ createdAt: -1 }).exec();
165
- if (tokenIsValid(token)) {
166
- return token;
161
+ try {
162
+ const token = await Token.findOne({ user_id, provider }).sort({ createdAt: -1 }).exec();
163
+ if (tokenIsValid(token)) {
164
+ return token;
165
+ }
166
+ return await generateToken(user_id);
167
+ } catch (err) {
168
+ console.error(new Date(), err);
169
+ throw err;
167
170
  }
168
- return await generateToken(user_id);
169
171
  }
170
172
 
171
173
  const refreshToken = async user_id => {
@@ -187,7 +189,7 @@ const generateRefreshToken = async user_id => {
187
189
  return refreshtoken;
188
190
  } catch (err) {
189
191
  console.error(new Date(), err);
190
- return Promise.reject(err);
192
+ throw err;
191
193
  }
192
194
  };
193
195
 
@@ -226,7 +228,8 @@ const refresh = async (req, res) => {
226
228
  }
227
229
  } catch (err) {
228
230
  console.error(err);
229
- return fail(res, 403, err);
231
+ if (err.code) throw err;
232
+ throw new errors.ForbiddenError("Forbidden", { message: err.toString() });
230
233
  }
231
234
  }
232
235
 
@@ -241,7 +244,8 @@ const login = async (req, res) => {
241
244
  res = Object.assign(res, authenticate_result);
242
245
  } catch(err) {
243
246
  console.error(err);
244
- return fail(res, 403, err);
247
+ if (err.code) throw err;
248
+ throw new errors.ForbiddenError("Forbidden", { message: err.toString() });
245
249
  }
246
250
  };
247
251
 
@@ -250,40 +254,37 @@ const authenticate = async req => {
250
254
  if (!req.query.apikey && !req.headers.authorization && !(req.headers["X-API-Key"] || req.headers["x-api-key"])) {
251
255
  return false;
252
256
  }
253
- try {
254
- if (req.headers.authorization && req.headers.authorization.trim().toLowerCase().indexOf("basic") === 0) {
255
- // Basic Auth
256
- user = await basicAuth(basicAuthData(req));
257
- } else if (req.headers.authorization && req.headers.authorization.trim().toLowerCase().indexOf("bearer") === 0) {
258
- // Token Auth
259
- user = await bearerAuth(bearerAuthData(req));
260
- } else if (req.query.apikey) {
261
- user = await apiKeyAuth(req.query.apikey);
262
- } else if (req.headers["X-API-Key"] || req.headers["x-api-key"]) {
263
- // API Key
264
- user = await apiKeyAuth(req.query.apikey || req.headers["X-API-Key"] || req.headers["x-api-key"])
265
- } else {
266
- throw ("Could not find any way to authenticate");
267
- }
268
- if (!user) {
269
- throw ("Could not find user");
270
- }
271
- return {
272
- token: await ensureToken(user._id),
273
- refresh_token: await ensureRefreshToken(user._id),
274
- groups: await getGroups(user._id),
275
- user
276
- }
277
- } catch (err) {
278
- return Promise.reject(err);
257
+ if (req.headers.authorization && req.headers.authorization.trim().toLowerCase().indexOf("basic") === 0) {
258
+ // Basic Auth
259
+ user = await basicAuth(basicAuthData(req));
260
+ } else if (req.headers.authorization && req.headers.authorization.trim().toLowerCase().indexOf("bearer") === 0) {
261
+ // Token Auth
262
+ user = await bearerAuth(bearerAuthData(req));
263
+ } else if (req.query.apikey) {
264
+ user = await apiKeyAuth(req.query.apikey);
265
+ } else if (req.headers["X-API-Key"] || req.headers["x-api-key"]) {
266
+ // API Key
267
+ user = await apiKeyAuth(req.query.apikey || req.headers["X-API-Key"] || req.headers["x-api-key"])
268
+ } else {
269
+ throw ("Could not find any way to authenticate");
270
+ }
271
+ if (!user) {
272
+ throw ("Could not find user");
273
+ }
274
+ return {
275
+ token: await ensureToken(user._id),
276
+ refresh_token: await ensureRefreshToken(user._id),
277
+ groups: await getGroups(user._id),
278
+ user
279
279
  }
280
+
280
281
  }
281
282
 
282
283
  const auth = async (req, res) => {
283
284
  // Check against model as to whether we're allowed to edit this model
284
285
  if (!req.Model) {
285
286
  console.error("Model missing");
286
- return fail(res, 500, "Model missing");
287
+ throw new errors.InternalServerError("Model missing", { message: "Model missing" });
287
288
  }
288
289
  try {
289
290
  var method = null;
@@ -298,12 +299,13 @@ const auth = async (req, res) => {
298
299
  method = "d";
299
300
  } else {
300
301
  console.error("Unsupported operation", req.method);
301
- return fail(res, 500, "Unsupported operation: " + req.method);
302
+ throw new errors.InternalServerError("Unsupported operation", { message: "Unsupported operation: " + req.method});
302
303
  }
303
- await check_perms(res.user, res.groups, req.Model, method, req.params.item_id);
304
+ return await check_perms(res.user, res.groups, req.Model, method, req.params.item_id);
304
305
  } catch(err) {
305
306
  console.error(err);
306
- return fail(res, 403, { status: "Unauthorized", error: err });
307
+ if (err.code) throw err;
308
+ throw new errors.ForbiddenError("Forbidden", { message: err.toString() });
307
309
  }
308
310
  };
309
311
 
@@ -316,7 +318,8 @@ const bulkAuth = async (req, res,) => {
316
318
  await check_perms(res.user, res.groups, req.Model, "d");
317
319
  } catch (err) {
318
320
  console.error(err);
319
- return fail(res, 403, { status: "Unauthorized", error: err });
321
+ if (err.code) throw err;
322
+ throw new errors.ForbiddenError("Forbidden", { message: err.toString() });
320
323
  }
321
324
  };
322
325
 
@@ -326,17 +329,17 @@ const check_perms = async (user, groups, model, method, item_id) => {
326
329
  //If no perms are set, then this isn't an available model
327
330
  if (!perms.admin) {
328
331
  console.error("Model permissions not set correctly - add an admin section");
329
- throw("Model permissions not set correctly - add an admin section");
332
+ throw new errors.InternalServerError("Model permissions not set correctly - add an admin section", { message: "Model permissions not set correctly - add an admin section" });
330
333
  }
331
334
  //First check if "all" is able to do this. If so, let's get on with it.
332
- if (perms.all) {
335
+ if (perms.all && perms.all.length) {
333
336
  if (perms.all.indexOf(method) !== -1) {
334
337
  return true;
335
338
  }
336
339
  }
337
340
  //This isn't an 'all' situation, so let's bail if the user isn't logged in
338
341
  if (!user) {
339
- throw("Unauthorized");
342
+ throw new errors.ForbiddenError("User not logged in", { message: "User not logged in" });
340
343
  }
341
344
  //Let's check perms in this order - admin, user, group, owner
342
345
  //Admin check
@@ -362,16 +365,17 @@ const check_perms = async (user, groups, model, method, item_id) => {
362
365
  if (item && item._owner_id && item._owner_id.toString() == user._id.toString() && (perms.owner && perms.owner.includes(method))) return true;
363
366
  throw ("Authorization failed");
364
367
  } catch (err) {
365
- return Promise.reject(err);
368
+ if (err.code) throw err;
369
+ throw new errors.ForbiddenError("Forbidden", { message: err.toString() });
366
370
  }
367
371
  }
368
372
 
369
373
  const admin_only = (req, res, next) => { // Chain after login
370
374
  if (!res.user) {
371
- return fail(res, 403, "Unauthorized");
375
+ throw new errors.ForbiddenError("Unauthorized", { message: "Unauthorized" });
372
376
  }
373
377
  if (!res.user.admin) {
374
- return fail(res, 403, "Unauthorized");
378
+ throw new errors.ForbiddenError("Unauthorized", { message: "Unauthorized" });
375
379
  }
376
380
  next();
377
381
  }
package/libs/setup.js CHANGED
@@ -1,5 +1,6 @@
1
1
  const rand_token = require("rand-token");
2
2
  const path = require("path");
3
+ const errors = require("restify-errors");
3
4
  const security = require("./security");
4
5
  const ObjectID = require('mongodb').ObjectID;
5
6
  var User = null;
@@ -9,15 +10,15 @@ const init = config => {
9
10
  User = require(path.join(config.model_dir, "user_model"));
10
11
  }
11
12
 
12
- const checkUserDoesNotExist = async (req, res) => {
13
+ const checkUserDoesNotExist = async () => {
13
14
  try {
14
15
  const count = await User.countDocuments();
15
16
  if (count) {
16
- return res.send(403, { status: "failed", error: "Cannot setup if user exists" });
17
+ throw new errors.ConflictError("Conflict Error", { status: "failed", error: "Cannot setup if user exists" });
17
18
  }
18
19
  } catch(err) {
19
20
  console.error(err);
20
- res.send(500, { status: "error", error: err.message });
21
+ throw new errors.InternalServerError("Internal Server Error", { status: "error", error: err.message });
21
22
  }
22
23
  };
23
24
 
@@ -46,7 +47,7 @@ const setup = async (req, res) => {
46
47
  });
47
48
  } catch(err) {
48
49
  console.error(err);
49
- res.send(500, { status: "error", error: err.message });
50
+ throw new errors.InternalServerError("Internal Server Error", { status: "error", error: err.message });
50
51
  }
51
52
  };
52
53
 
@@ -76,7 +77,7 @@ const data_setup = async (req, res) => {
76
77
  res.send({ status: "success", results });
77
78
  } catch(err) {
78
79
  console.error(err);
79
- res.send(500, { status: "error", error: err.message });
80
+ throw new errors.InternalServerError("Internal Server Error", { status: "error", error: err.message });
80
81
  }
81
82
  }
82
83
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "jxp",
3
3
  "description:": "An opinionated RESTful API library based on Mongoose and Restify. Make an API by just writing Mongoose models.",
4
- "version": "2.11.1",
4
+ "version": "2.12.0",
5
5
  "private": false,
6
6
  "main": "libs/jxp.js",
7
7
  "scripts": {
@@ -39,7 +39,7 @@
39
39
  "jstransformer-markdown-it": "^3.0.0",
40
40
  "jxp-helper": "^1.4.0",
41
41
  "mkdirp": "^1.0.4",
42
- "mongoose": "6.7.3",
42
+ "mongoose": "6.7.5",
43
43
  "mongoose-friendly": "^0.1.4",
44
44
  "morgan": "^1.10.0",
45
45
  "nodemailer": "^6.8.0",
@@ -49,8 +49,9 @@
49
49
  "querystring": "^0.2.1",
50
50
  "rand-token": "^1.0.1",
51
51
  "readline-sync": "^1.4.10",
52
- "restify": "^9.0.0",
52
+ "restify": "^10.0.0",
53
53
  "restify-cors-middleware": "^1.1.1",
54
+ "restify-errors": "^8.0.2",
54
55
  "traverse": "^0.6.7",
55
56
  "underscore": "^1.13.6",
56
57
  "ws": "^8.11.0"
package/test/init.js CHANGED
@@ -13,7 +13,7 @@ const security = require("../libs/security");
13
13
 
14
14
  const empty = async model => {
15
15
  try {
16
- const result = await model.deleteMany({});
16
+ await model.deleteMany({});
17
17
  } catch(err) {
18
18
  console.error(err);
19
19
  throw(err);
@@ -3,14 +3,13 @@ const config = require("config");
3
3
  const path = require("path");
4
4
 
5
5
  var model_dir = config.model_dir || path.join(process.cwd(), "./models");
6
- const Test = require(path.join(model_dir, "test_model"));
6
+ require(path.join(model_dir, "test_model"));
7
7
 
8
8
  var chai = require('chai');
9
9
  var chaiHttp = require('chai-http');
10
10
  var should = chai.should();
11
11
 
12
12
  var init = require("./init");
13
-
14
13
  var server = require("../bin/server");
15
14
 
16
15
  chai.use(chaiHttp);
@@ -27,6 +26,7 @@ const mock_data = {
27
26
  describe('Setup', () => {
28
27
  beforeEach(async function() {
29
28
  await init.empty_user_collections();
29
+ console.log("Emptied collections");
30
30
  })
31
31
 
32
32
  describe("setup", () => {
@@ -35,6 +35,7 @@ describe('Setup', () => {
35
35
  .post("/setup")
36
36
  .send({ email: init.email, password: init.password })
37
37
  .end((err, res) => {
38
+ // console.log(res);
38
39
  res.should.have.status(200);
39
40
  res.body.status.should.equal('success');
40
41
  res.body.name.should.equal('admin');
package/test/test.js CHANGED
@@ -121,6 +121,7 @@ describe('Test', () => {
121
121
  .get("/api/user")
122
122
  .auth(init.email, init.password)
123
123
  .end((err, res) => {
124
+ // console.log(res.body);
124
125
  res.should.have.status(200);
125
126
  res.body.data.should.be.an('array');
126
127
  done();
@@ -159,6 +160,7 @@ describe('Test', () => {
159
160
  chai.request(server)
160
161
  .get(`/api/user`)
161
162
  .end((err, res) => {
163
+ // console.log(res.body);
162
164
  res.should.have.status(403);
163
165
  done();
164
166
  });
@@ -565,7 +567,7 @@ describe('Test', () => {
565
567
  .get(`/api/test?populate=array_link`)
566
568
  .auth(init.email, init.password)
567
569
  .end((err, res) => {
568
- // console.log(res.body.data);
570
+ // console.log(res.body);
569
571
  res.should.have.status(200);
570
572
  res.body.data[0].should.have.property("array_link");
571
573
  res.body.data[0].array_link.should.be.an("array");
@@ -708,7 +710,7 @@ describe('Test', () => {
708
710
  var query = [
709
711
  {
710
712
  $match: {
711
- "_id": `ObjectId(\"${objectid}\")`
713
+ "_id": `ObjectId("${objectid}")`
712
714
  }
713
715
  },
714
716
  { $group: { _id: null, count: { $sum: 1 } } }
@@ -719,7 +721,7 @@ describe('Test', () => {
719
721
  .send({ query })
720
722
  .end((err, res) => {
721
723
  res.should.have.status(200);
722
- console.log(res.body);
724
+ // console.log(res.body);
723
725
  res.body.data.should.be.an('array');
724
726
  res.body.data[0].should.have.property("_id");
725
727
  res.body.data[0].should.have.property("count");
@@ -832,21 +834,21 @@ describe('Test', () => {
832
834
  });
833
835
  });
834
836
  });
835
- it("should $push to an array", done => {
836
- chai.request(server)
837
- .patch("/api/test/" + post_id)
838
- .auth(init.email, init.password)
839
- .send({ $push: { shmack: "fah" } })
840
- .end((err, res) => {
841
- console.log(res.body.data);
842
- res.should.have.status(200);
843
- res.body.data.should.be.an('object');
844
- res.body.data.should.have.property("shmack")
845
- res.body.data.shmack.should.be.an("array");
846
- res.body.data.shmack.should.have.length(4);
847
- done();
848
- });
849
- });
837
+ // it("should $push to an array", done => {
838
+ // chai.request(server)
839
+ // .patch("/api/test/" + post_id)
840
+ // .auth(init.email, init.password)
841
+ // .send({ $push: { shmack: "fah" } })
842
+ // .end((err, res) => {
843
+ // // console.log(res.body.data);
844
+ // res.should.have.status(200);
845
+ // res.body.data.should.be.an('object');
846
+ // res.body.data.should.have.property("shmack")
847
+ // res.body.data.shmack.should.be.an("array");
848
+ // res.body.data.shmack.should.have.length(4);
849
+ // done();
850
+ // });
851
+ // });
850
852
  });
851
853
 
852
854
  describe("Models", () => {
@@ -868,6 +870,7 @@ describe('Test', () => {
868
870
  .del(`/api/test/${post_id}`)
869
871
  .auth(init.email, init.password)
870
872
  .end((err, res) => {
873
+ console.log(res.body);
871
874
  res.should.have.status(200);
872
875
  res.body.status.should.equal('ok');
873
876
  done();
@@ -878,9 +881,10 @@ describe('Test', () => {
878
881
  .get(`/api/test/${post_id}`)
879
882
  .auth(init.email, init.password)
880
883
  .end((err, res) => {
884
+ console.log(res.body);
881
885
  res.should.have.status(404);
882
886
  res.body.message.should.equal('Document is deleted');
883
- res.body.status.should.equal('error');
887
+ res.body.code.should.equal('NotFound');
884
888
  done();
885
889
  });
886
890
  });
@@ -982,8 +986,7 @@ describe('Test', () => {
982
986
  .auth(init.email, init.password)
983
987
  .end((err, res) => {
984
988
  res.should.have.status(409);
985
- res.body.message.should.equal(`Parent link item exists in test/link_id`);
986
- res.body.status.should.equal('error');
989
+ res.body.message.should.equal(`Conflict Error`);
987
990
  done();
988
991
  });
989
992
  });
@@ -992,7 +995,7 @@ describe('Test', () => {
992
995
  .del(`/api/link/${link_id}?_cascade=1`)
993
996
  .auth(init.email, init.password)
994
997
  .end((err, res) => {
995
- console.log(res.body, res.status);
998
+ // console.log(res.body, res.status);
996
999
  res.should.have.status(200);
997
1000
  res.body.status.should.equal('ok');
998
1001
  done();
@@ -1004,7 +1007,7 @@ describe('Test', () => {
1004
1007
  .auth(init.email, init.password)
1005
1008
  .end((err, res) => {
1006
1009
  res.should.have.status(404);
1007
- res.body.status.should.equal('error');
1010
+ res.body.message.should.equal('Document is deleted');
1008
1011
  done();
1009
1012
  });
1010
1013
  });
@@ -1060,8 +1063,7 @@ describe('Test', () => {
1060
1063
  .auth(init.email, init.password)
1061
1064
  .end((err, res) => {
1062
1065
  res.should.have.status(409);
1063
- res.body.message.should.equal(`Parent link item exists in test/link_id`);
1064
- res.body.status.should.equal('error');
1066
+ res.body.message.should.equal(`Conflict Error`);
1065
1067
  done();
1066
1068
  });
1067
1069
  });
@@ -1087,7 +1089,6 @@ describe('Test', () => {
1087
1089
  });
1088
1090
 
1089
1091
  describe("/Filter with +", () => {
1090
- let plus_user_id = null;
1091
1092
  it("it should POST a user with a + in email", (done) => {
1092
1093
  var user = {
1093
1094
  name: "Plus User",
@@ -1100,7 +1101,6 @@ describe('Test', () => {
1100
1101
  .end((err, res) => {
1101
1102
  res.should.have.status(200);
1102
1103
  res.body.data.should.have.property("_id");
1103
- plus_user_id = res.body.data._id;
1104
1104
  done();
1105
1105
  });
1106
1106
  });