jxp 2.12.1 → 2.12.3

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/bin/setup.js CHANGED
@@ -70,7 +70,7 @@ async function main() {
70
70
  "start": "node bin/server.js"
71
71
  },
72
72
  "dependencies": {
73
- "jxp": "^2.0.1-4"
73
+ "jxp": "^2.12.3"
74
74
  },
75
75
  "author": app_author,
76
76
  "license": app_license
package/libs/docs.js CHANGED
@@ -33,7 +33,7 @@ class Docs {
33
33
  res.end();
34
34
  } catch(err) {
35
35
  console.error(err);
36
- return errors.InternalServerError({ message: err.toString() });
36
+ return new errors.InternalServerError(err.toString());
37
37
  }
38
38
  }
39
39
 
@@ -43,20 +43,20 @@ class Docs {
43
43
  res.send(models);
44
44
  } catch (err) {
45
45
  console.error(err);
46
- return errors.InternalServerError({ message: err.toString() });
46
+ return new errors.InternalServerError(err.toString());
47
47
  }
48
48
  }
49
49
 
50
50
  metaModel(req, res, next) {
51
51
  try {
52
52
  if (!req.Model) {
53
- return errors.NotFoundError({ status: "error", error: "Model not found" })
53
+ return new errors.NotFoundError("Model not found")
54
54
  }
55
55
  res.send(req.Model.schema.paths);
56
56
  next();
57
57
  } catch (err) {
58
58
  console.error(err);
59
- return errors.InternalServerError({ message: err.toString() });
59
+ return new errors.InternalServerError(err.toString());
60
60
  }
61
61
  }
62
62
 
@@ -65,7 +65,7 @@ class Docs {
65
65
  res.send(this.models);
66
66
  next();
67
67
  } catch(err) {
68
- errors.InternalServerError({ message: err.toString() });
68
+ return new errors.InternalServerError(err.toString());
69
69
  }
70
70
  }
71
71
 
@@ -74,7 +74,7 @@ class Docs {
74
74
  this.renderTemplate(res, "index", {});
75
75
  next();
76
76
  } catch(err) {
77
- errors.InternalServerError({ message: err.toString() });
77
+ return new errors.InternalServerError(err.toString());
78
78
  }
79
79
  }
80
80
 
@@ -84,7 +84,7 @@ class Docs {
84
84
  const md_contents = md.render(body.toString()).body;
85
85
  this.renderTemplate(res, "md", { md_contents });
86
86
  } catch(err) {
87
- errors.InternalServerError({ message: err.toString() });
87
+ return new errors.InternalServerError(err.toString());
88
88
  }
89
89
  }
90
90
 
@@ -98,7 +98,7 @@ class Docs {
98
98
  this.renderTemplate(res, "model", { model, fields, perms });
99
99
  next();
100
100
  } catch(err) {
101
- errors.InternalServerError({ message: err.toString() });
101
+ return new errors.InternalServerError(err.toString());
102
102
  }
103
103
  }
104
104
  }
package/libs/groups.js CHANGED
@@ -12,11 +12,11 @@ const actionPut = async (req, res) => {
12
12
  const group = req.body.group;
13
13
  if (!group) {
14
14
  console.error("Group required");
15
- return errors.BadRequestError("Group required");
15
+ return new errors.BadRequestError("Group required");
16
16
  }
17
17
  if (!user_id) {
18
18
  console.error("user_id required");
19
- return errors.BadRequestError("user_id required", { message: "user_id is required" });
19
+ return new errors.BadRequestError("user_id is required");
20
20
  }
21
21
  try {
22
22
  let userGroup = await Groups.findOne({ user_id: user_id });
@@ -39,7 +39,7 @@ const actionPut = async (req, res) => {
39
39
  res.send(await userGroup.save());
40
40
  } catch(err) {
41
41
  console.error(err);
42
- return errors.InternalServerError({ message: err.toString()});
42
+ return new errors.InternalServerError(err.toString());
43
43
  }
44
44
  };
45
45
 
@@ -48,11 +48,11 @@ const actionPost = async (req, res) => {
48
48
  const group = req.body.group;
49
49
  if (!group) {
50
50
  console.error("Group required");
51
- return errors.BadRequestError("Group required");
51
+ return new errors.BadRequestError("Group required");
52
52
  }
53
53
  if (!user_id) {
54
54
  console.error("user_id required");
55
- return errors.BadRequestError("user_id required", { message: "user_id is required" });
55
+ return new errors.BadRequestError("user_id required");
56
56
  }
57
57
  try {
58
58
  let userGroup = await Groups.findOne({ user_id: user_id });
@@ -75,7 +75,7 @@ const actionPost = async (req, res) => {
75
75
  res.send(await userGroup.save());
76
76
  } catch (err) {
77
77
  console.error(err);
78
- return errors.InternalServerError({ message: err.toString()});
78
+ return new errors.InternalServerError(err.toString());
79
79
  }
80
80
  };
81
81
 
@@ -83,7 +83,7 @@ const actionGet = async (req, res) => {
83
83
  var user_id = req.params.user_id;
84
84
  if (!user_id) {
85
85
  console.error("user_id required");
86
- return errors.BadRequestError("user_id required", { message: "user_id is required" });
86
+ return new errors.BadRequestError("user_id required");
87
87
  }
88
88
  try {
89
89
  let userGroup = await Groups.findOne({ user_id });
@@ -94,7 +94,7 @@ const actionGet = async (req, res) => {
94
94
  res.send(userGroup);
95
95
  } catch (err) {
96
96
  console.error(err);
97
- return errors.InternalServerError({ message: err.toString()});
97
+ return new errors.InternalServerError(err.toString());
98
98
  }
99
99
  };
100
100
 
@@ -102,16 +102,16 @@ const actionDelete = async (req, res) => {
102
102
  const user_id = req.params.user_id;
103
103
  const group = req.query.group;
104
104
  if (!group) {
105
- return errors.BadRequestError("Group required");
105
+ return new errors.BadRequestError("Group required");
106
106
  }
107
107
  if (!user_id) {
108
108
  console.error("user_id required");
109
- return errors.BadRequestError("user_id required", { message: "user_id is required" });
109
+ return new errors.BadRequestError("user_id required");
110
110
  }
111
111
  try {
112
112
  let userGroup = await Groups.findOne({ user_id });
113
113
  if (!userGroup) {
114
- return errors.BadRequestError("User not found");
114
+ return new errors.BadRequestError("User not found");
115
115
  }
116
116
  let i = userGroup.groups.indexOf(group);
117
117
  if (i > -1) {
@@ -120,7 +120,7 @@ const actionDelete = async (req, res) => {
120
120
  res.send(await userGroup.save());
121
121
  } catch (err) {
122
122
  console.error(err);
123
- return errors.InternalServerError({ message: err.toString() });
123
+ return new errors.InternalServerError(err.toString());
124
124
  }
125
125
  };
126
126
 
package/libs/jxp.js CHANGED
@@ -13,6 +13,9 @@ const morgan = require("morgan");
13
13
  const ws = require("./ws");
14
14
  const modeldir = require("./modeldir");
15
15
  const query_manipulation = require("./query_manipulation");
16
+ const corsMiddleware = require('restify-cors-middleware2');
17
+ const json2csv = require('json2csv').parse;
18
+ global.JXPSchema = require("./schema");
16
19
 
17
20
  var models = {};
18
21
 
@@ -30,7 +33,7 @@ const middlewareModel = (req, res, next) => {
30
33
  return next();
31
34
  } catch (err) {
32
35
  console.error(new Date, err);
33
- throw new errors.NotFoundError("Not Found", { message: `Model ${modelname} not found` });
36
+ throw new errors.NotFoundError(`Model ${modelname} not found`);
34
37
  }
35
38
  };
36
39
 
@@ -56,16 +59,15 @@ const outputJSON = (req, res, next) => {
56
59
  next();
57
60
  } catch (err) {
58
61
  console.error(new Date(), err);
59
- throw new errors.InternalServerError("Error generating output", { message: err.toString() });
62
+ throw new errors.InternalServerError(err.toString());
60
63
  }
61
64
  }
62
65
 
63
66
  // Outputs whatever is in res.result as CSV
64
67
  const outputCSV = (req, res, next) => {
65
- const json2csv = require('json2csv').parse;
66
68
  const opts = { "flatten": true };
67
69
  if (!res.result.data) {
68
- throw new errors.InternalServerError("Error generating output", { message: "Not CSVable data" });
70
+ throw new errors.InternalServerError("Error generating CSV");
69
71
  }
70
72
  try {
71
73
  const data = res.result.data.map(row => row._doc);
@@ -81,7 +83,7 @@ const outputCSV = (req, res, next) => {
81
83
  next();
82
84
  } catch (err) {
83
85
  console.error(err);
84
- throw new errors.InternalServerError("Internal Error", { message: err.toString() });
86
+ throw new errors.InternalServerError(err.toString());
85
87
  }
86
88
  }
87
89
 
@@ -101,7 +103,7 @@ const actionGet = async (req, res) => {
101
103
  filters = parseFilter(req.query.filter);
102
104
  } catch (err) {
103
105
  console.trace(new Date(), err);
104
- throw new errors.InternalServerError("Internal Error", { message: err.toString() });
106
+ throw new errors.InternalServerError(err.toString());
105
107
  }
106
108
  let search = parseSearch(req.query.search);
107
109
  for (let i in search) {
@@ -191,7 +193,7 @@ const actionGet = async (req, res) => {
191
193
  console.error(new Date(), err);
192
194
  if (debug) console.timeEnd(opname);
193
195
  if (err.code) throw err;
194
- throw new errors.InternalServerError("Internal Error", { message: err.toString() });
196
+ throw new errors.InternalServerError(err.toString());
195
197
  }
196
198
  };
197
199
 
@@ -206,7 +208,7 @@ const actionGetOne = async (req, res) => {
206
208
  console.error(new Date(), err);
207
209
  if (debug) console.timeEnd(opname);
208
210
  if (err.code) throw err;
209
- throw new errors.InternalServerError("Internal Error", { message: err.toString() });
211
+ throw new errors.InternalServerError(err.toString());
210
212
  }
211
213
  };
212
214
 
@@ -236,7 +238,8 @@ const actionPost = async (req, res) => {
236
238
  } catch (err) {
237
239
  console.error(new Date(), err);
238
240
  if (debug) console.timeEnd(opname);
239
- throw new errors.InternalServerError("Internal Error", { message: err.toString() });
241
+ if (err.code) throw err;
242
+ throw new errors.InternalServerError(err.toString());
240
243
  }
241
244
  };
242
245
 
@@ -247,7 +250,7 @@ const actionPut = async (req, res) => {
247
250
  let item = await req.Model.findById(req.params.item_id);
248
251
  if (!item) {
249
252
  console.error(new Date(), "Document not found");
250
- throw new errors.NotFoundError("Not Found", { message: "Document not found" });
253
+ throw new errors.NotFoundError(`Document ${req.params.item_id} not found on ${req.modelname}`);
251
254
  }
252
255
  _populateItem(item, datamunging.deserialize(req.body));
253
256
  _versionItem(item);
@@ -271,7 +274,8 @@ const actionPut = async (req, res) => {
271
274
  } catch (err) {
272
275
  console.error(new Date(), err);
273
276
  if (debug) console.timeEnd(opname);
274
- throw new errors.InternalServerError("Internal Error", { message: err.toString() });
277
+ if (err.code) throw err;
278
+ throw new errors.InternalServerError(err.toString());
275
279
  }
276
280
  };
277
281
 
@@ -289,14 +293,15 @@ const actionUpdate = async (req, res) => {
289
293
  }
290
294
  res.json({
291
295
  status: "ok",
292
- message: req.modelname + " updateed",
296
+ message: req.modelname + " updated",
293
297
  data
294
298
  });
295
299
  if (debug) console.timeEnd(opname);
296
300
  } catch (err) {
297
301
  console.error(new Date(), err);
298
302
  if (debug) console.timeEnd(opname);
299
- throw new errors.InternalServerError("Internal Error", { message: err.toString() });
303
+ if (err.code) throw err;
304
+ throw new errors.InternalServerError(err.toString());
300
305
  }
301
306
  };
302
307
 
@@ -309,8 +314,7 @@ const actionDelete = async (req, res) => {
309
314
  try {
310
315
  let item = await req.Model.findById(req.params.item_id);
311
316
  if (!item) {
312
- console.error(new Date(), "Couldn't find item for delete");
313
- throw new errors.NotFoundError("Not Found", { message: "Couldn't find item for delete" });
317
+ throw new errors.NotFoundError(`Couldn't find item ${req.params.item_id} for delete on ${req.modelname}`);
314
318
  }
315
319
  // Get linked models
316
320
  const linked_models = [];
@@ -339,7 +343,7 @@ const actionDelete = async (req, res) => {
339
343
  await models[linked_model.modelname].updateMany(q, { _deleted: true });
340
344
  }
341
345
  } else {
342
- throw new errors.ConflictError("Conflict Error", { message: `Parent link item exists in ${linked_model.modelname}/${linked_model.field}` });
346
+ throw new errors.ConflictError(`Parent link item exists in ${linked_model.modelname}/${linked_model.field}`);
343
347
  }
344
348
  }
345
349
  }
@@ -373,7 +377,7 @@ const actionDelete = async (req, res) => {
373
377
  console.error(new Date(), err);
374
378
  if (debug) console.timeEnd(opname);
375
379
  if (err.code) throw err;
376
- throw new errors.InternalServerError("Internal Error", { message: err.toString() });
380
+ throw new errors.InternalServerError(err.toString());
377
381
  }
378
382
  };
379
383
 
@@ -392,7 +396,7 @@ const actionCount = async (req, res) => {
392
396
  filters = parseFilter(req.query.filter);
393
397
  } catch (err) {
394
398
  console.trace(new Date(), err);
395
- throw new errors.InternalServerError("Internal Error", { message: err.toString() });
399
+ throw new errors.InternalServerError(err.toString());
396
400
  }
397
401
  let search = parseSearch(req.query.search);
398
402
  for (let i in search) {
@@ -409,7 +413,7 @@ const actionCount = async (req, res) => {
409
413
  console.error(new Date(), err);
410
414
  if (debug) console.timeEnd(opname);
411
415
  if (err.code) throw err;
412
- throw new errors.InternalServerError("Internal Error", { message: err.toString() });
416
+ throw new errors.InternalServerError(err.toString());
413
417
  }
414
418
  };
415
419
 
@@ -423,7 +427,7 @@ const actionCall = async (req, res) => {
423
427
  } catch(err) {
424
428
  console.error(new Date(), err);
425
429
  if (err.code) throw err;
426
- throw new errors.InternalServerError("Internal Error", { message: err.toString() });
430
+ throw new errors.InternalServerError(err.toString());
427
431
  }
428
432
  };
429
433
 
@@ -431,7 +435,7 @@ const actionCallItem = async (req, res) => {
431
435
  try {
432
436
  const item = req.Model.findById(req.params.item_id);
433
437
  if (!item) {
434
- throw new errors.NotFoundError("Not Found", { message: "Couldn't find item for call" });
438
+ throw new errors.NotFoundError(`Couldn't find item ${req.params.item_id} on ${req.modelname} for call`);
435
439
  }
436
440
  req.params.__user = res.user || null;
437
441
  const result = await req.Model[req.params.method_name](item);
@@ -439,15 +443,14 @@ const actionCallItem = async (req, res) => {
439
443
  } catch(err) {
440
444
  console.trace(err);
441
445
  if (err.code) throw err;
442
- throw new errors.InternalServerError("Internal Error", { message: err.toString() });
446
+ throw new errors.InternalServerError(err.toString());
443
447
  }
444
448
  };
445
449
 
446
450
  // Actions (verbs)
447
451
  const actionQuery = async (req, res) => {
448
452
  if (!req.body || !req.body.query || typeof req.body.query !== "object") {
449
- console.error("query missing or not of type object")
450
- throw new errors.InternalServerError("Query missing", { message: "query missing or not of type object" });
453
+ throw new errors.BadRequestError("Query missing or not of type object");
451
454
  }
452
455
  const opname = `query ${req.modelname} ${ops++}`;
453
456
  console.time(opname);
@@ -517,7 +520,7 @@ const actionQuery = async (req, res) => {
517
520
  console.error(new Date(), err);
518
521
  if (debug) console.timeEnd(opname);
519
522
  if (err.code) throw err;
520
- throw new errors.InternalServerError("Internal Error", { message: err.toString() });
523
+ throw new errors.InternalServerError(err.toString());
521
524
  }
522
525
  };
523
526
 
@@ -526,7 +529,7 @@ const actionAggregate = async (req, res) => {
526
529
  let query = (req.body.query) ? req.body.query : req.body; // Don't require to embed in query anymore
527
530
  if (!query || !Array.isArray(query)) {
528
531
  console.error("query missing or not of type array")
529
- throw new errors.InternalServerError("Query missing", { message: "query missing or not of type array" });
532
+ throw new errors.BadRequestError("Query missing or not of type array");
530
533
  }
531
534
  query = query_manipulation.fix_query(query);
532
535
  const opname = `aggregate ${req.modelname} ${ops++}`;
@@ -544,7 +547,7 @@ const actionAggregate = async (req, res) => {
544
547
  } catch (err) {
545
548
  console.error(new Date(), err);
546
549
  if (debug) console.timeEnd(opname);
547
- throw new errors.InternalServerError("Internal Error", { message: err.toString() });
550
+ throw new errors.InternalServerError(err.toString());
548
551
  }
549
552
  };
550
553
 
@@ -552,7 +555,7 @@ const actionAggregate = async (req, res) => {
552
555
  const actionBulkWrite = async (req, res) => {
553
556
  if (!req.body || !Array.isArray(req.body)) {
554
557
  console.error("query missing or not of type array")
555
- throw new errors.InternalServerError("Query Missing", { message: "query missing or not of type array" });
558
+ throw new errors.BadRequestError("Query missing or not of type array");
556
559
  }
557
560
  const opname = `bulkwrite ${req.modelname} ${ops++}`;
558
561
  console.time(opname);
@@ -567,7 +570,7 @@ const actionBulkWrite = async (req, res) => {
567
570
  } catch (err) {
568
571
  console.error(new Date(), err);
569
572
  if (debug) console.timeEnd(opname);
570
- throw new errors.InternalServerError("Internal Error", { message: err.toString() });
573
+ throw new errors.InternalServerError(err.toString());
571
574
  }
572
575
  };
573
576
 
@@ -628,11 +631,11 @@ const getOne = async (Model, item_id, params, options) => {
628
631
  var item = await query.exec();
629
632
  if (!item) {
630
633
  // console.error("Could not find document");
631
- throw new errors.NotFoundError("Could not find document", { message: "Could not find document" });
634
+ throw new errors.NotFoundError(`Could not find document ${item_id} on ${Model.modelName}`);
632
635
  }
633
636
  if (item._deleted && !params.showDeleted) {
634
637
  // console.error("Document is deleted");
635
- throw new errors.NotFoundError("Document is deleted", { message: "Document is deleted" });
638
+ throw new errors.NotFoundError(`Document ${item_id} is deleted on ${Model.modelName}`);
636
639
  }
637
640
  item = item.toObject();
638
641
  //Don't ever return passwords
@@ -641,7 +644,7 @@ const getOne = async (Model, item_id, params, options) => {
641
644
  } catch(err) {
642
645
  console.error(err);
643
646
  if (err.code) throw err;
644
- throw new errors.InternalServerError("Internal Error", { message: err.toString() });
647
+ throw new errors.InternalServerError(err.toString());
645
648
  }
646
649
  };
647
650
 
@@ -762,8 +765,6 @@ const changeUrlParams = (req, key, val) => {
762
765
  return req.config.url + req.path() + "?" + querystring.stringify(q);
763
766
  };
764
767
 
765
- global.JXPSchema = require("./schema");
766
-
767
768
  const JXP = function(options) {
768
769
  const server = restify.createServer();
769
770
  const model_dir = options.model_dir || modeldir.findModelDir(path.dirname(process.argv[1]));
@@ -872,8 +873,6 @@ const JXP = function(options) {
872
873
  server.use(morgan("combined", { stream: accessLogStream }));
873
874
 
874
875
  // CORS
875
- const corsMiddleware = require('restify-cors-middleware');
876
-
877
876
  const cors = corsMiddleware({
878
877
  preflightMaxAge: 5, //Optional
879
878
  origins: ['*'],
@@ -894,6 +893,12 @@ const JXP = function(options) {
894
893
  next();
895
894
  });
896
895
 
896
+ // Set req.username = "anonymous" if not logged in
897
+ server.use((req, res, next) => {
898
+ if (!req.username) req.username = "anonymous";
899
+ next();
900
+ });
901
+
897
902
  // Define our endpoints
898
903
 
899
904
  /* Our API endpoints */
package/libs/login.js CHANGED
@@ -29,11 +29,11 @@ const recover = async (req, res) => {
29
29
  const email = req.body.email;
30
30
  if (!email) {
31
31
  console.error("Missing email parameter");
32
- throw new errors.BadRequestError("Bad Request", { status: "fail", message: "Missing email parameter" });
32
+ throw new errors.BadRequestError("Missing email parameter");
33
33
  }
34
34
  const user = await User.findOne({ email });
35
35
  if (!user) {
36
- throw new errors.NotFoundError("User Not Found", { status: "fail", message: "User not found" });
36
+ throw new errors.NotFoundError(`User with email ${email} Not Found`);
37
37
  }
38
38
  const result = await security.generateApiKey(user._id);
39
39
  const token = jwt.sign({ apikey: result.apikey, email: user.email, id: user._id }, req.config.shared_secret, { expiresIn: "2d" });
@@ -56,26 +56,26 @@ const recover = async (req, res) => {
56
56
  res.send({ status: "ok", message: "Sent recovery email" });
57
57
  } catch (err) {
58
58
  if (err.code) throw err;
59
- throw new errors.UnauthorizedError("Unauthorized", { status: "fail", message: "Unauthorized", info: err });
59
+ throw new errors.UnauthorizedError(err.toString());
60
60
  }
61
61
  }
62
62
 
63
63
  const logout = async (req, res) => {
64
64
  try {
65
- if (!res.user) throw new errors.ForbiddenError("Forbidden", { message: "You don't seem to be logged in" });
65
+ if (!res.user) throw new errors.ForbiddenError("You don't seem to be logged in");
66
66
  await security.revokeToken(res.user._id);
67
67
  res.send({ status: "ok", message: "User logged out" });
68
68
  } catch(err) {
69
69
  console.error(err);
70
70
  if (err.code) throw err;
71
- throw new errors.InternalServerError("Server Error", { status: "error", message: err.toString() });
71
+ throw new errors.InternalServerError(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
- throw new errors.InternalServerError("Internal Server Error", { message: req.params.provider + " config not defined" });
78
+ throw new errors.InternalServerError(`oAuth ${req.params.provider} config not defined`);
79
79
  }
80
80
  const state = Math.random().toString(36).substring(7);
81
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`;
@@ -148,7 +148,7 @@ const login = async (req, res) => {
148
148
  }
149
149
  if ((!password) || (!email)) {
150
150
  console.error(new Date(), "Missing email or password parameters");
151
- return errors.ForbiddenError({ status: "fail", message: "Missing email or password parameters" });
151
+ return new errors.ForbiddenError("Missing email or password parameters");
152
152
  }
153
153
  try {
154
154
  const user = await User.findOne({ email });
@@ -171,23 +171,23 @@ const login = async (req, res) => {
171
171
  } catch (err) {
172
172
  console.error(new Date(), `Authentication failed`, ip, err);
173
173
  if (err.code) throw err;
174
- return errors.ForbiddenError({ status: "fail", message: "Authentication failed" });
174
+ return new errors.ForbiddenError(err.toString());
175
175
  }
176
176
  }
177
177
 
178
178
  const getJWT = async (req, res) => {
179
179
  var user = null;
180
180
  if (!res.user.admin) {
181
- throw new errors.UnauthorizedError("Unauthorized", { status: "fail", message: "Unauthorized" });
181
+ throw new errors.UnauthorizedError("Unauthorized");
182
182
  }
183
183
  var email = req.params.email || req.body.email;
184
184
  if (!email) {
185
- throw new errors.BadRequestError("Bad Request", { status: "fail", message: "Email required" });
185
+ throw new errors.BadRequestError("Email required");
186
186
  }
187
187
  try {
188
188
  const result = await User.findOne({ email: email });
189
189
  if (!result || !result._id) {
190
- throw new errors.NotFoundError("Not Found", { status: "fail", message: "User not found" });
190
+ throw new errors.NotFoundError("User not found");
191
191
  }
192
192
  user = result;
193
193
  try {
@@ -197,11 +197,11 @@ const getJWT = async (req, res) => {
197
197
  });
198
198
  res.send({ email: user.email, token: token });
199
199
  } catch (err) {
200
- throw new errors.UnauthorizedError("Unauthorized", { status: "fail", message: "Unauthorized" });
200
+ throw new errors.UnauthorizedError("Unauthorized");
201
201
  }
202
202
  } catch (err) {
203
203
  if (err.code) throw err;
204
- throw new errors.InternalServerError("Internal Server Error", { status: "error", message: err.toString() });
204
+ throw new errors.InternalServerError(err.toString());
205
205
  }
206
206
  }
207
207
 
package/libs/security.js CHANGED
@@ -229,7 +229,7 @@ const refresh = async (req, res) => {
229
229
  } catch (err) {
230
230
  console.error(err);
231
231
  if (err.code) throw err;
232
- throw new errors.ForbiddenError("Forbidden", { message: err.toString() });
232
+ throw new errors.ForbiddenError(err.toString());
233
233
  }
234
234
  }
235
235
 
@@ -245,7 +245,7 @@ const login = async (req, res) => {
245
245
  } catch(err) {
246
246
  console.error(err);
247
247
  if (err.code) throw err;
248
- throw new errors.ForbiddenError("Forbidden", { message: err.toString() });
248
+ throw new errors.ForbiddenError(err.toString());
249
249
  }
250
250
  };
251
251
 
@@ -275,6 +275,7 @@ const authenticate = async req => {
275
275
  token: await ensureToken(user._id),
276
276
  refresh_token: await ensureRefreshToken(user._id),
277
277
  groups: await getGroups(user._id),
278
+ username: user.email,
278
279
  user
279
280
  }
280
281
 
@@ -283,8 +284,8 @@ const authenticate = async req => {
283
284
  const auth = async (req, res) => {
284
285
  // Check against model as to whether we're allowed to edit this model
285
286
  if (!req.Model) {
286
- console.error("Model missing");
287
- throw new errors.InternalServerError("Model missing", { message: "Model missing" });
287
+ // console.error("Model missing");
288
+ throw new errors.BadRequestError("Model missing");
288
289
  }
289
290
  try {
290
291
  var method = null;
@@ -298,14 +299,14 @@ const auth = async (req, res) => {
298
299
  } else if (req.method == "DELETE") {
299
300
  method = "d";
300
301
  } else {
301
- console.error("Unsupported operation", req.method);
302
- throw new errors.InternalServerError("Unsupported operation", { message: "Unsupported operation: " + req.method});
302
+ // console.error("Unsupported operation", req.method);
303
+ throw new errors.InternalServerError(`Unsupported operation: ${req.method}`);
303
304
  }
304
305
  return await check_perms(res.user, res.groups, req.Model, method, req.params.item_id);
305
306
  } catch(err) {
306
307
  console.error(err);
307
308
  if (err.code) throw err;
308
- throw new errors.ForbiddenError("Forbidden", { message: err.toString() });
309
+ throw new errors.ForbiddenError(err.toString());
309
310
  }
310
311
  };
311
312
 
@@ -319,7 +320,7 @@ const bulkAuth = async (req, res,) => {
319
320
  } catch (err) {
320
321
  console.error(err);
321
322
  if (err.code) throw err;
322
- throw new errors.ForbiddenError("Forbidden", { message: err.toString() });
323
+ throw new errors.ForbiddenError(err.toString());
323
324
  }
324
325
  };
325
326
 
@@ -329,7 +330,7 @@ const check_perms = async (user, groups, model, method, item_id) => {
329
330
  //If no perms are set, then this isn't an available model
330
331
  if (!perms.admin) {
331
332
  console.error("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" });
333
+ throw new errors.InternalServerError("Model permissions not set correctly - add an admin section");
333
334
  }
334
335
  //First check if "all" is able to do this. If so, let's get on with it.
335
336
  if (perms.all && perms.all.length) {
@@ -339,7 +340,7 @@ const check_perms = async (user, groups, model, method, item_id) => {
339
340
  }
340
341
  //This isn't an 'all' situation, so let's bail if the user isn't logged in
341
342
  if (!user) {
342
- throw new errors.ForbiddenError("User not logged in", { message: "User not logged in" });
343
+ throw new errors.ForbiddenError("User not logged in");
343
344
  }
344
345
  //Let's check perms in this order - admin, user, group, owner
345
346
  //Admin check
@@ -366,16 +367,16 @@ const check_perms = async (user, groups, model, method, item_id) => {
366
367
  throw ("Authorization failed");
367
368
  } catch (err) {
368
369
  if (err.code) throw err;
369
- throw new errors.ForbiddenError("Forbidden", { message: err.toString() });
370
+ throw new errors.ForbiddenError(err.toString());
370
371
  }
371
372
  }
372
373
 
373
374
  const admin_only = (req, res, next) => { // Chain after login
374
375
  if (!res.user) {
375
- throw new errors.ForbiddenError("Unauthorized", { message: "Unauthorized" });
376
+ throw new errors.ForbiddenError("User not logged in");
376
377
  }
377
378
  if (!res.user.admin) {
378
- throw new errors.ForbiddenError("Unauthorized", { message: "Unauthorized" });
379
+ throw new errors.ForbiddenError("User not admin");
379
380
  }
380
381
  next();
381
382
  }
package/libs/setup.js CHANGED
@@ -14,11 +14,12 @@ const checkUserDoesNotExist = async () => {
14
14
  try {
15
15
  const count = await User.countDocuments();
16
16
  if (count) {
17
- throw new errors.ConflictError("Conflict Error", { status: "failed", error: "Cannot setup if user exists" });
17
+ throw new errors.ConflictError("Cannot setup if user exists");
18
18
  }
19
19
  } catch(err) {
20
20
  console.error(err);
21
- throw new errors.InternalServerError("Internal Server Error", { status: "error", error: err.message });
21
+ if (err.code) throw err;
22
+ throw new errors.InternalServerError(err.toString());
22
23
  }
23
24
  };
24
25
 
@@ -47,7 +48,7 @@ const setup = async (req, res) => {
47
48
  });
48
49
  } catch(err) {
49
50
  console.error(err);
50
- throw new errors.InternalServerError("Internal Server Error", { status: "error", error: err.message });
51
+ throw new errors.InternalServerError(err.toString());
51
52
  }
52
53
  };
53
54
 
@@ -77,7 +78,7 @@ const data_setup = async (req, res) => {
77
78
  res.send({ status: "success", results });
78
79
  } catch(err) {
79
80
  console.error(err);
80
- throw new errors.InternalServerError("Internal Server Error", { status: "error", error: err.message });
81
+ throw new errors.InternalServerError(err.toString());
81
82
  }
82
83
  }
83
84
 
@@ -1,4 +1,5 @@
1
1
  /* global JXPSchema ObjectId Mixed */
2
+ const errors = require("restify-errors");
2
3
 
3
4
  const TestSchema = new JXPSchema({
4
5
  foo: String, // A normal string
@@ -33,6 +34,14 @@ TestSchema.statics.test = function() {
33
34
  return "Testing OKAY!";
34
35
  };
35
36
 
37
+ TestSchema.pre("save", function(next) {
38
+ // If we have the setting "error" set to true, we will throw an error
39
+ if (this.bar == "Throw an error") {
40
+ throw new errors.ImATeapotError("I'm a teapot");
41
+ }
42
+ next();
43
+ });
44
+
36
45
  // Finally, we export our model. Make sure to change the name!
37
46
  const Test = JXPSchema.model('Test', TestSchema);
38
47
  module.exports = Test;
package/package.json CHANGED
@@ -1,15 +1,17 @@
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.12.1",
4
+ "version": "2.12.3",
5
5
  "private": false,
6
6
  "main": "libs/jxp.js",
7
7
  "scripts": {
8
8
  "start": "node bin/server.js",
9
- "test": "mocha --timeout 10000 -b --exit",
10
- "wstest": "mocha test/wstest"
9
+ "test": "mocha --timeout 1000 -b --exit",
10
+ "wstest": "mocha test/wstest",
11
+ "setup": "node bin/setup.js"
11
12
  },
12
13
  "bin": {
14
+ "jxp": "bin/setup.js",
13
15
  "jxp-setup": "bin/setup.js",
14
16
  "jxp-add-admin": "bin/init_db.js"
15
17
  },
@@ -27,40 +29,41 @@
27
29
  "url": "https://github.com/j-norwood-young/jexpress-2/issues"
28
30
  },
29
31
  "dependencies": {
30
- "axios": "^1.2.0",
32
+ "axios": "^1.2.3",
31
33
  "bcryptjs": "^2.4.3",
32
- "commander": "^9.4.1",
33
- "config": "^3.3.8",
34
+ "commander": "^10.0.0",
35
+ "config": "^3.3.9",
34
36
  "dotenv": "^16.0.3",
35
- "glob": "8.0.3",
37
+ "glob": "8.1.0",
36
38
  "js-yaml": "4.1.0",
37
39
  "json2csv": "^5.0.7",
38
- "jsonwebtoken": "^8.5.1",
40
+ "jsonwebtoken": "^9.0.0",
39
41
  "jstransformer-markdown-it": "^3.0.0",
40
42
  "jxp-helper": "^1.4.0",
41
- "mkdirp": "^1.0.4",
42
- "mongoose": "6.7.5",
43
+ "mkdirp": "^2.1.3",
44
+ "moment": "^2.29.4",
45
+ "mongoose": "6.8.4",
43
46
  "mongoose-friendly": "^0.1.4",
44
47
  "morgan": "^1.10.0",
45
- "nodemailer": "^6.8.0",
48
+ "nodemailer": "^6.9.0",
46
49
  "nodemailer-smtp-transport": "^2.7.4",
47
50
  "path": "^0.12.7",
48
51
  "pug": "^3.0.2",
49
52
  "querystring": "^0.2.1",
50
53
  "rand-token": "^1.0.1",
51
54
  "readline-sync": "^1.4.10",
52
- "restify": "^10.0.0",
53
- "restify-cors-middleware": "^1.1.1",
55
+ "restify": "^11.0.0",
56
+ "restify-cors-middleware2": "^2.2.0",
54
57
  "restify-errors": "^8.0.2",
55
58
  "traverse": "^0.6.7",
56
59
  "underscore": "^1.13.6",
57
- "ws": "^8.11.0"
60
+ "ws": "^8.12.0"
58
61
  },
59
62
  "devDependencies": {
60
63
  "chai": "^4.3.7",
61
64
  "chai-http": "^4.3.0",
62
- "mocha": "^10.1.0",
63
- "should": "^13.2.3",
64
- "moment": "^2.29.4"
65
+ "mocha": "^10.2.0",
66
+ "moment": "^2.29.4",
67
+ "should": "^13.2.3"
65
68
  }
66
69
  }
package/test/test.js CHANGED
@@ -15,11 +15,17 @@ var server = require("../bin/server");
15
15
 
16
16
  chai.use(chaiHttp);
17
17
 
18
+ const pause = ms => new Promise(res => setTimeout(res, ms));
19
+
18
20
  describe('Test', () => {
19
21
  before(async function() {
20
22
  await init.init();
21
23
  })
22
24
 
25
+ beforeEach(async function() {
26
+ await pause(0);
27
+ })
28
+
23
29
 
24
30
  var apikey = null;
25
31
  var token = null;
@@ -438,7 +444,7 @@ describe('Test', () => {
438
444
  .get(`/api/test/${post_id}?populate=link`)
439
445
  .auth(init.email, init.password)
440
446
  .end((err, res) => {
441
- // console.log(res.body);
447
+ console.log(res.body);
442
448
  res.should.have.status(200);
443
449
  res.body.should.have.property("data");
444
450
  res.body.data.should.have.property("link")
@@ -870,7 +876,7 @@ describe('Test', () => {
870
876
  .del(`/api/test/${post_id}`)
871
877
  .auth(init.email, init.password)
872
878
  .end((err, res) => {
873
- console.log(res.body);
879
+ // console.log(res.body);
874
880
  res.should.have.status(200);
875
881
  res.body.status.should.equal('ok');
876
882
  done();
@@ -881,9 +887,9 @@ describe('Test', () => {
881
887
  .get(`/api/test/${post_id}`)
882
888
  .auth(init.email, init.password)
883
889
  .end((err, res) => {
884
- console.log(res.body);
890
+ // console.log(res.body);
885
891
  res.should.have.status(404);
886
- res.body.message.should.equal('Document is deleted');
892
+ res.body.message.should.equal(`Document ${post_id} is deleted on Test`);
887
893
  res.body.code.should.equal('NotFound');
888
894
  done();
889
895
  });
@@ -986,7 +992,8 @@ describe('Test', () => {
986
992
  .auth(init.email, init.password)
987
993
  .end((err, res) => {
988
994
  res.should.have.status(409);
989
- res.body.message.should.equal(`Conflict Error`);
995
+ // console.log(res.body.message);
996
+ res.body.message.should.equal(`Parent link item exists in test/link_id`);
990
997
  done();
991
998
  });
992
999
  });
@@ -1007,7 +1014,7 @@ describe('Test', () => {
1007
1014
  .auth(init.email, init.password)
1008
1015
  .end((err, res) => {
1009
1016
  res.should.have.status(404);
1010
- res.body.message.should.equal('Document is deleted');
1017
+ res.body.message.should.equal(`Document ${test_with_links_id} is deleted on Test`);
1011
1018
  done();
1012
1019
  });
1013
1020
  });
@@ -1063,7 +1070,7 @@ describe('Test', () => {
1063
1070
  .auth(init.email, init.password)
1064
1071
  .end((err, res) => {
1065
1072
  res.should.have.status(409);
1066
- res.body.message.should.equal(`Conflict Error`);
1073
+ res.body.message.should.equal(`Parent link item exists in test/link_id`);
1067
1074
  done();
1068
1075
  });
1069
1076
  });
@@ -1115,4 +1122,23 @@ describe('Test', () => {
1115
1122
  });
1116
1123
  });
1117
1124
  });
1125
+
1126
+ describe("Error Handling", () => {
1127
+ it ("should get an error", (done) => {
1128
+ chai.request(server)
1129
+ .post("/api/test")
1130
+ .auth(init.email, init.password)
1131
+ .send({
1132
+ error: true,
1133
+ bar: "Throw an error"
1134
+ })
1135
+ .end((err, res) => {
1136
+ // console.log(res.body);
1137
+ console.log(res.headers);
1138
+ res.should.have.status(418);
1139
+ res.body.message.should.equal(`I'm a teapot`);
1140
+ done();
1141
+ });
1142
+ })
1143
+ });
1118
1144
  });