Skip to content

Commit acec9dc

Browse files
committed
Merge branch 'master' of github.com:strongloop/loopback into feature/globalize-error-messages
* 'master' of github.com:strongloop/loopback: (25 commits) Update strong-remoting dep Allow accessType per remote method v2.9.0 Update juggler dep v2.8.8 Fix context middleware to preserve domains Fix Geo test cases Allow User.hashPassword/validatePassword to be overridden Additional password reset unit tests for API and REST - strongloop#944 Small formatting update to have consistency with identical logic in other areas. - strongloop#944 Simplify the API test for invalidCredentials (removed create), move above REST calls for better grouping of tests - strongloop#944 Force request to send body as string, this ensures headers aren't automatically set to application/json - strongloop#944 Ensure error checking logic is in place for all REST calls, expand formatting for consistency with existing instances. - strongloop#944 Correct invalidCredentials so that it differs from validCredentialsEmailVerified, unit test now passes as desired. - strongloop#944 Update to demonstrate unit test is actually failing due to incorrect values of invalidCredentials - strongloop#944 v2.8.7 API and REST tests added to ensure complete and valid credentials are supplied for verified error message to be returned - tests added as suggested and fail under previous version of User model - strongloop#931 Require valid login credentials before verified email check. - strongloop#931. Change urlNotFound.js to url-not-found.js Add lib/server-app.js ... Conflicts: common/models/user.js
2 parents 79d6a5f + 497678e commit acec9dc

13 files changed

+460
-74
lines changed

CHANGES.md

Lines changed: 70 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,53 @@
1+
2015-01-07, Version 2.9.0
2+
=========================
3+
4+
* Update juggler dep (Raymond Feng)
5+
6+
* Fix Geo test cases (Raymond Feng)
7+
8+
* Allow User.hashPassword/validatePassword to be overridden (Raymond Feng)
9+
10+
11+
2015-01-07, Version 2.8.8
12+
=========================
13+
14+
* Fix context middleware to preserve domains (Pham Anh Tuan)
15+
16+
* Additional password reset unit tests for API and REST - strongloop/loopback#944 (Ron Edgecomb)
17+
18+
* Small formatting update to have consistency with identical logic in other areas. - strongloop/loopback#944 (Ron Edgecomb)
19+
20+
* Simplify the API test for invalidCredentials (removed create), move above REST calls for better grouping of tests - strongloop/loopback#944 (Ron Edgecomb)
21+
22+
* Force request to send body as string, this ensures headers aren't automatically set to application/json - strongloop/loopback#944 (Ron Edgecomb)
23+
24+
* Ensure error checking logic is in place for all REST calls, expand formatting for consistency with existing instances. - strongloop/loopback#944 (Ron Edgecomb)
25+
26+
* Correct invalidCredentials so that it differs from validCredentialsEmailVerified, unit test now passes as desired. - strongloop/loopback#944 (Ron Edgecomb)
27+
28+
* Update to demonstrate unit test is actually failing due to incorrect values of invalidCredentials - strongloop/loopback#944 (Ron Edgecomb)
29+
30+
* fix jscs warning (Clark Wang)
31+
32+
* fix nestRemoting is nesting hooks from other relations (Clark Wang)
33+
34+
35+
2015-01-06, Version 2.8.7
36+
=========================
37+
38+
* Change urlNotFound.js to url-not-found.js (Rand McKinney)
39+
40+
* Add lib/server-app.js (Rand McKinney)
41+
42+
* package: add versioned sl-blip dependency (Ryan Graham)
43+
44+
* fix User.settings.ttl can't be overridden in sub model (Clark Wang)
45+
46+
* Fix Change.getCheckpointModel() giving new models each call (Farid Neshat)
47+
48+
* Update README.md (Rand McKinney)
49+
50+
151
2014-12-15, Version 2.8.6
252
=========================
353

@@ -17,19 +67,16 @@
1767

1868
* Fix bcrypt issues for browserify (Raymond Feng)
1969

20-
* Allow native bcrypt for performance (Raymond Feng)
21-
2270

23-
2014-12-08, Version 2.8.3
71+
2014-12-08, Version 2.8.4
2472
=========================
2573

74+
* Allow native bcrypt for performance (Raymond Feng)
2675

2776

28-
2014-12-08, Version 2.8.4
77+
2014-12-08, Version 2.8.3
2978
=========================
3079

31-
* Allow native bcrypt for performance (Raymond Feng)
32-
3380
* Remove unused underscore dependency (Ryan Graham)
3481

3582

@@ -1251,6 +1298,14 @@
12511298

12521299
* 2.0.0-beta1 (Ritchie Martori)
12531300

1301+
* Bump version (Raymond Feng)
1302+
1303+
* Add postgresql to the keywords (Raymond Feng)
1304+
1305+
* updated package.json with SOAP and framework keywords (altsang)
1306+
1307+
* updated package.json with keywords and updated description (Raymond Feng)
1308+
12541309
* Make app.datasources unique per app instance (Miroslav Bajtoš)
12551310

12561311
* Add RC version (Ritchie Martori)
@@ -1316,6 +1371,11 @@
13161371
* Add Change model (Ritchie Martori)
13171372

13181373

1374+
2014-05-27, Version 1.8.4
1375+
=========================
1376+
1377+
1378+
13191379
2014-05-27, Version 1.8.5
13201380
=========================
13211381

@@ -1327,14 +1387,8 @@
13271387

13281388
* updated package.json with keywords and updated description (Raymond Feng)
13291389

1330-
1331-
2014-05-27, Version 1.8.4
1332-
=========================
1333-
13341390
* Add more keywords (Raymond Feng)
13351391

1336-
* Bump version (Raymond Feng)
1337-
13381392
* app: flatten model config (Miroslav Bajtoš)
13391393

13401394
* Fix the test for mocha 1.19.0 (Raymond Feng)
@@ -1655,15 +1709,6 @@
16551709

16561710
* Improve jsdox documentation of app object (Miroslav Bajtoš)
16571711

1658-
* Make sure methods are called in the context of the calling class (Raymond Feng)
1659-
1660-
* Start to move md to jsdoc (Ritchie Martori)
1661-
1662-
1663-
2014-01-14, Version 1.5.0
1664-
=========================
1665-
1666-
16671712

16681713
2014-01-14, Version 1.5.1
16691714
=========================
@@ -1674,6 +1719,10 @@
16741719

16751720
* Start to move md to jsdoc (Ritchie Martori)
16761721

1722+
1723+
2014-01-14, Version 1.5.0
1724+
=========================
1725+
16771726
* Replace `on` with `once` in middleware examples (Miroslav Bajtoš)
16781727

16791728
* Fix incorrect transports (Ritchie Martori)

common/models/change.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -419,7 +419,7 @@ module.exports = function(Change) {
419419
Change.getCheckpointModel = function() {
420420
var checkpointModel = this.Checkpoint;
421421
if (checkpointModel) return checkpointModel;
422-
this.checkpoint = checkpointModel = loopback.Checkpoint.extend('checkpoint');
422+
this.Checkpoint = checkpointModel = loopback.Checkpoint.extend('checkpoint');
423423
assert(this.dataSource, 'Cannot getCheckpointModel(): ' + this.modelName
424424
+ ' is not attached to a dataSource');
425425
checkpointModel.attachTo(this.dataSource);

common/models/user.js

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -458,6 +458,24 @@ module.exports = function(User) {
458458
}
459459
};
460460

461+
/*!
462+
* Hash the plain password
463+
*/
464+
User.hashPassword = function(plain) {
465+
this.validatePassword(plain);
466+
var salt = bcrypt.genSaltSync(this.settings.saltWorkFactor || SALT_WORK_FACTOR);
467+
return bcrypt.hashSync(plain, salt);
468+
};
469+
470+
User.validatePassword = function(plain) {
471+
if (typeof plain === 'string' && plain) {
472+
return true;
473+
}
474+
var err = new Error('Invalid password: ' + plain);
475+
err.statusCode = 422;
476+
throw err;
477+
};
478+
461479
/*!
462480
* Setup an extended user model.
463481
*/
@@ -469,11 +487,10 @@ module.exports = function(User) {
469487

470488
// max ttl
471489
this.settings.maxTTL = this.settings.maxTTL || DEFAULT_MAX_TTL;
472-
this.settings.ttl = DEFAULT_TTL;
490+
this.settings.ttl = this.settings.ttl || DEFAULT_TTL;
473491

474492
UserModel.setter.password = function(plain) {
475-
var salt = bcrypt.genSaltSync(this.constructor.settings.saltWorkFactor || SALT_WORK_FACTOR);
476-
this.$password = bcrypt.hashSync(plain, salt);
493+
this.$password = this.constructor.hashPassword(plain);
477494
};
478495

479496
// Make sure emailVerified is not set by creation

docs.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
"title": "LoopBack Documentation",
33
"content": [
44
"lib/application.js",
5+
"lib/server-app.js",
56
"lib/loopback.js",
67
"lib/registry.js",
78
"lib/access-context.js",
@@ -14,7 +15,7 @@
1415
"server/middleware/static.js",
1516
"server/middleware/status.js",
1617
"server/middleware/token.js",
17-
"server/middleware/urlNotFound.js",
18+
"server/middleware/url-not-found.js",
1819
{ "title": "Built-in models", "depth": 2 },
1920
"common/models/access-token.js",
2021
"common/models/acl.js",

lib/model.js

Lines changed: 39 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,25 @@ Model._getAccessTypeForMethod = function(method) {
314314

315315
var ACL = Model._ACL();
316316

317+
// Check the explicit setting of accessType
318+
if (method.accessType) {
319+
assert(method.accessType === ACL.READ ||
320+
method.accessType === ACL.WRITE ||
321+
method.accessType === ACL.EXECUTE, 'invalid accessType ' +
322+
method.accessType +
323+
'. It must be "READ", "WRITE", or "EXECUTE"');
324+
return method.accessType;
325+
}
326+
327+
// Default GET requests to READ
328+
var verb = method.http && method.http.verb;
329+
if (typeof verb === 'string') {
330+
verb = verb.toUpperCase();
331+
}
332+
if (verb === 'GET' || verb === 'HEAD') {
333+
return ACL.READ;
334+
}
335+
317336
switch (method.name) {
318337
case'create':
319338
return ACL.WRITE;
@@ -406,6 +425,7 @@ Model.belongsToRemoting = function(relationName, relation, define) {
406425
isStatic: false,
407426
http: {verb: 'get', path: '/' + pathName},
408427
accepts: {arg: 'refresh', type: 'boolean', http: {source: 'query'}},
428+
accessType: 'READ',
409429
description: 'Fetches belongsTo relation ' + relationName,
410430
returns: {arg: relationName, type: modelName, root: true}
411431
}, fn);
@@ -419,6 +439,7 @@ Model.hasOneRemoting = function(relationName, relation, define) {
419439
http: {verb: 'get', path: '/' + pathName},
420440
accepts: {arg: 'refresh', type: 'boolean', http: {source: 'query'}},
421441
description: 'Fetches hasOne relation ' + relationName,
442+
accessType: 'READ',
422443
returns: {arg: relationName, type: relation.modelTo.modelName, root: true}
423444
}, fn);
424445
};
@@ -446,6 +467,7 @@ Model.hasManyRemoting = function(relationName, relation, define) {
446467
description: 'Foreign key for ' + relationName, required: true,
447468
http: {source: 'path'}},
448469
description: 'Find a related item by id for ' + relationName,
470+
accessType: 'READ',
449471
returns: {arg: 'result', type: toModelName, root: true},
450472
rest: {after: convertNullToNotFoundError}
451473
}, findByIdFunc);
@@ -458,6 +480,7 @@ Model.hasManyRemoting = function(relationName, relation, define) {
458480
description: 'Foreign key for ' + relationName, required: true,
459481
http: {source: 'path'}},
460482
description: 'Delete a related item by id for ' + relationName,
483+
accessType: 'WRITE',
461484
returns: []
462485
}, destroyByIdFunc);
463486

@@ -472,6 +495,7 @@ Model.hasManyRemoting = function(relationName, relation, define) {
472495
{arg: 'data', type: toModelName, http: {source: 'body'}}
473496
],
474497
description: 'Update a related item by id for ' + relationName,
498+
accessType: 'WRITE',
475499
returns: {arg: 'result', type: toModelName, root: true}
476500
}, updateByIdFunc);
477501

@@ -492,6 +516,7 @@ Model.hasManyRemoting = function(relationName, relation, define) {
492516
description: 'Foreign key for ' + relationName, required: true,
493517
http: {source: 'path'}}].concat(accepts),
494518
description: 'Add a related item by id for ' + relationName,
519+
accessType: 'WRITE',
495520
returns: {arg: relationName, type: modelThrough.modelName, root: true}
496521
}, addFunc);
497522

@@ -503,6 +528,7 @@ Model.hasManyRemoting = function(relationName, relation, define) {
503528
description: 'Foreign key for ' + relationName, required: true,
504529
http: {source: 'path'}},
505530
description: 'Remove the ' + relationName + ' relation to an item by id',
531+
accessType: 'WRITE',
506532
returns: []
507533
}, removeFunc);
508534

@@ -516,6 +542,7 @@ Model.hasManyRemoting = function(relationName, relation, define) {
516542
description: 'Foreign key for ' + relationName, required: true,
517543
http: {source: 'path'}},
518544
description: 'Check the existence of ' + relationName + ' relation to an item by id',
545+
accessType: 'READ',
519546
returns: {arg: 'exists', type: 'boolean', root: true},
520547
rest: {
521548
// After hook to map exists to 200/404 for HEAD
@@ -558,6 +585,7 @@ Model.scopeRemoting = function(scopeName, scope, define) {
558585
http: {verb: 'get', path: '/' + pathName},
559586
accepts: {arg: 'filter', type: 'object'},
560587
description: 'Queries ' + scopeName + ' of ' + this.modelName + '.',
588+
accessType: 'READ',
561589
returns: {arg: scopeName, type: [toModelName], root: true}
562590
});
563591

@@ -566,20 +594,23 @@ Model.scopeRemoting = function(scopeName, scope, define) {
566594
http: {verb: 'post', path: '/' + pathName},
567595
accepts: {arg: 'data', type: toModelName, http: {source: 'body'}},
568596
description: 'Creates a new instance in ' + scopeName + ' of this model.',
597+
accessType: 'WRITE',
569598
returns: {arg: 'data', type: toModelName, root: true}
570599
});
571600

572601
define('__delete__' + scopeName, {
573602
isStatic: isStatic,
574603
http: {verb: 'delete', path: '/' + pathName},
575-
description: 'Deletes all ' + scopeName + ' of this model.'
604+
description: 'Deletes all ' + scopeName + ' of this model.',
605+
accessType: 'WRITE'
576606
});
577607

578608
define('__count__' + scopeName, {
579609
isStatic: isStatic,
580610
http: {verb: 'get', path: '/' + pathName + '/count'},
581611
accepts: {arg: 'where', type: 'object', description: 'Criteria to match model instances'},
582612
description: 'Counts ' + scopeName + ' of ' + this.modelName + '.',
613+
accessType: 'READ',
583614
returns: {arg: 'count', type: 'number'}
584615
});
585616

@@ -655,8 +686,9 @@ Model.nestRemoting = function(relationName, options, cb) {
655686
opts.accepts = acceptArgs.concat(method.accepts || []);
656687
opts.returns = [].concat(method.returns || []);
657688
opts.description = method.description;
689+
opts.accessType = method.accessType;
658690
opts.rest = extend({}, method.rest || {});
659-
opts.rest.delegateTo = method.name;
691+
opts.rest.delegateTo = method;
660692

661693
opts.http = [];
662694
var routes = [].concat(method.http || []);
@@ -720,18 +752,18 @@ Model.nestRemoting = function(relationName, options, cb) {
720752

721753
sharedClass.methods().forEach(function(method) {
722754
var delegateTo = method.rest && method.rest.delegateTo;
723-
if (delegateTo) {
755+
if (delegateTo && delegateTo.ctor == relation.modelTo) {
724756
var before = method.isStatic ? beforeListeners : beforeListeners['prototype'];
725757
var after = method.isStatic ? afterListeners : afterListeners['prototype'];
726758
var m = method.isStatic ? method.name : 'prototype.' + method.name;
727-
if (before && before[delegateTo]) {
759+
if (before && before[delegateTo.name]) {
728760
self.beforeRemote(m, function(ctx, result, next) {
729-
before[delegateTo]._listeners.call(null, ctx, next);
761+
before[delegateTo.name]._listeners.call(null, ctx, next);
730762
});
731763
}
732-
if (after && after[delegateTo]) {
764+
if (after && after[delegateTo.name]) {
733765
self.afterRemote(m, function(ctx, result, next) {
734-
after[delegateTo]._listeners.call(null, ctx, next);
766+
after[delegateTo.name]._listeners.call(null, ctx, next);
735767
});
736768
}
737769
}

0 commit comments

Comments
 (0)