Skip to content

Commit be0ca7e

Browse files
author
Raymond Feng
committed
Merge branch 'release/1.8.4' into production
2 parents 81d2987 + 68c79ba commit be0ca7e

10 files changed

Lines changed: 243 additions & 41 deletions

File tree

‎README.md‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ For more details, see http://loopback.io/.
1919
In addition to the [main LoopBack module](https://github.com/strongloop/loopback), LoopBack consists of numerous other modules that implement specific functionality,
2020
as illustrated below:
2121

22-
![LoopBack modules](./docs/assets/lb-modules.png "LoopBack modules")
22+
![LoopBack modules](https://github.com/strongloop/loopback/raw/master/docs/assets/lb-modules.png "LoopBack modules")
2323

2424
* Frameworks
2525
* [loopback](https://github.com/strongloop/loopback)
@@ -30,6 +30,7 @@ as illustrated below:
3030
* [loopback-connector-mongodb](https://github.com/strongloop/loopback-connector-mongodb)
3131
* [loopback-connector-mysql](https://github.com/strongloop/loopback-connector-mysql)
3232
* [loopback-connector-oracle](https://github.com/strongloop/loopback-connector-oracle)
33+
* [loopback-connector-mssql](https://github.com/strongloop/loopback-connector-mssql)
3334
* [loopback-connector-postgresql](https://github.com/strongloop/loopback-connector-postgresql)
3435
* [loopback-connector-rest](https://github.com/strongloop/loopback-connector-rest)
3536
* [loopback-connector-soap](https://github.com/strongloop/loopback-connector-soap)
@@ -57,7 +58,7 @@ as illustrated below:
5758
* [loopback-example-access-control](https://github.com/strongloop/loopback-example-access-control)
5859
* [loopback-example-proxy](https://github.com/strongloop/loopback-example-proxy)
5960
* [strongloop-community/loopback-example-datagraph](https://github.com/strongloop-community/loopback-example-datagraph)
60-
* [strongloop-community/loopback-mysql-example](https://github.com/strongloop-community/loopback-mysql-example)
61+
* [strongloop-community/loopback-example-database](https://github.com/strongloop-community/loopback-example-database)
6162
* [strongloop-community/loopback-examples-ios](https://github.com/strongloop-community/loopback-examples-ios)
6263
* [strongloop-community/loopback-example-ssl](https://github.com/strongloop-community/loopback-example-ssl)
6364

‎docs/assets/lb-modules.png‎

386 KB
Loading

‎lib/application.js‎

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ var DataSource = require('loopback-datasource-juggler').DataSource
77
, compat = require('./compat')
88
, assert = require('assert')
99
, fs = require('fs')
10+
, extend = require('util')._extend
1011
, _ = require('underscore')
1112
, RemoteObjects = require('strong-remoting')
1213
, swagger = require('strong-remoting/ext/swagger')
@@ -540,7 +541,10 @@ function dataSourcesFromConfig(config) {
540541
}
541542

542543
function modelFromConfig(name, config, app) {
543-
var ModelCtor = require('./loopback').createModel(name, config.properties, config.options);
544+
var options = buildModelOptionsFromConfig(config);
545+
var properties = config.properties;
546+
547+
var ModelCtor = require('./loopback').createModel(name, properties, options);
544548
var dataSource = config.dataSource;
545549

546550
if(typeof dataSource === 'string') {
@@ -553,6 +557,26 @@ function modelFromConfig(name, config, app) {
553557
return ModelCtor;
554558
}
555559

560+
function buildModelOptionsFromConfig(config) {
561+
var options = extend({}, config.options);
562+
for (var key in config) {
563+
if (['properties', 'options', 'dataSource'].indexOf(key) !== -1) {
564+
// Skip items which have special meaning
565+
continue;
566+
}
567+
568+
if (options[key] !== undefined) {
569+
// When both `config.key` and `config.options.key` are set,
570+
// use the latter one to preserve backwards compatibility
571+
// with loopback 1.x
572+
continue;
573+
}
574+
575+
options[key] = config[key];
576+
}
577+
return options;
578+
}
579+
556580
function requireDir(dir, basenames) {
557581
assert(dir, 'cannot require directory contents without directory name');
558582

‎lib/middleware/rest.js‎

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,37 @@ module.exports = rest;
1515
*/
1616

1717
function rest() {
18+
var tokenParser = null;
1819
return function (req, res, next) {
1920
var app = req.app;
2021
var handler = app.handler('rest');
21-
22+
2223
if(req.url === '/routes') {
2324
res.send(handler.adapter.allRoutes());
2425
} else if(req.url === '/models') {
2526
return res.send(app.remotes().toJSON());
27+
} else if (app.isAuthEnabled) {
28+
if (!tokenParser) {
29+
// NOTE(bajtos) It would be better to search app.models for a model
30+
// of type AccessToken instead of searching all loopback models.
31+
// Unfortunately that's not supported now.
32+
// Related discussions:
33+
// https://github.com/strongloop/loopback/pull/167
34+
// https://github.com/strongloop/loopback/commit/f07446a
35+
var AccessToken = loopback.getModelByType(loopback.AccessToken);
36+
tokenParser = loopback.token({ model: AccessToken });
37+
}
38+
39+
tokenParser(req, res, function(err) {
40+
if (err) {
41+
next(err);
42+
} else {
43+
handler(req, res, next);
44+
}
45+
});
2646
} else {
2747
handler(req, res, next);
2848
}
29-
}
49+
};
3050
}
3151

‎lib/middleware/token.js‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,12 +53,14 @@ function token(options) {
5353
assert(TokenModel, 'loopback.token() middleware requires a AccessToken model');
5454

5555
return function (req, res, next) {
56+
if (req.accessToken !== undefined) return next();
5657
TokenModel.findForRequest(req, options, function(err, token) {
5758
if(err) return next(err);
5859
if(token) {
5960
req.accessToken = token;
6061
next();
6162
} else {
63+
req.accessToken = null;
6264
return next();
6365
}
6466
});

‎package.json‎

Lines changed: 50 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -3,57 +3,80 @@
33
"description": "LoopBack: Open Mobile Platform for Node.js",
44
"homepage": "http://loopback.io",
55
"keywords": [
6+
"framework",
7+
"web",
8+
"API framework",
9+
"REST API",
610
"StrongLoop",
711
"LoopBack",
812
"Mobile",
9-
"Backend",
10-
"Platform",
11-
"mBaaS"
13+
"mBaaS",
14+
"restful",
15+
"rest",
16+
"api",
17+
"app",
18+
"auth",
19+
"security",
20+
"orm",
21+
"database",
22+
"oracle",
23+
"mysql",
24+
"nosql",
25+
"mongo",
26+
"mongodb",
27+
"sqlserver",
28+
"mssql",
29+
"express",
30+
"restify",
31+
"koa",
32+
"postgres",
33+
"postgresql",
34+
"soap"
1235
],
13-
"version": "1.8.3",
36+
"version": "1.8.4",
1437
"scripts": {
1538
"test": "mocha -R spec"
1639
},
1740
"dependencies": {
18-
"debug": "~0.7.4",
19-
"express": "~3.4.8",
20-
"strong-remoting": "~1.3.1",
41+
"debug": "~0.8.1",
42+
"express": "~3.5.0",
43+
"strong-remoting": "~1.4.0",
2144
"inflection": "~1.3.5",
2245
"passport": "~0.2.0",
23-
"passport-local": "~0.1.6",
24-
"nodemailer": "~0.6.0",
25-
"ejs": "~0.8.5",
46+
"passport-local": "~1.0.0",
47+
"nodemailer": "~0.6.5",
48+
"ejs": "~1.0.0",
2649
"bcryptjs": "~0.7.12",
2750
"underscore.string": "~2.3.3",
2851
"underscore": "~1.6.0",
2952
"uid2": "0.0.3",
30-
"async": "~0.2.10"
53+
"async": "~0.9.0"
3154
},
3255
"peerDependencies": {
33-
"loopback-datasource-juggler": "^1.4.0 < 1.6.0"
56+
"loopback-datasource-juggler": ">=1.4.0 <1.6.0"
3457
},
3558
"devDependencies": {
36-
"loopback-datasource-juggler": "^1.4.0 < 1.6.0",
37-
"mocha": "~1.17.1",
59+
"loopback-datasource-juggler": ">=1.4.0 <1.6.0",
60+
"mocha": "~1.18.0",
3861
"strong-task-emitter": "0.0.x",
39-
"supertest": "~0.9.0",
40-
"chai": "~1.9.0",
62+
"supertest": "~0.12.1",
63+
"chai": "~1.9.1",
4164
"loopback-testing": "~0.1.2",
42-
"browserify": "~3.41.0",
43-
"grunt": "~0.4.2",
44-
"grunt-browserify": "~1.3.1",
45-
"grunt-contrib-uglify": "~0.3.2",
46-
"grunt-contrib-jshint": "~0.8.0",
47-
"grunt-contrib-watch": "~0.5.3",
65+
"browserify": "~4.1.5",
66+
"grunt": "~0.4.5",
67+
"grunt-browserify": "~2.1.0",
68+
"grunt-contrib-uglify": "~0.4.0",
69+
"grunt-contrib-jshint": "~0.10.0",
70+
"grunt-contrib-watch": "~0.6.1",
4871
"karma-script-launcher": "~0.1.0",
49-
"karma-chrome-launcher": "~0.1.2",
72+
"karma-chrome-launcher": "~0.1.3",
5073
"karma-firefox-launcher": "~0.1.3",
5174
"karma-html2js-preprocessor": "~0.1.0",
52-
"karma-phantomjs-launcher": "~0.1.2",
53-
"karma": "~0.10.9",
75+
"karma-phantomjs-launcher": "~0.1.4",
76+
"karma": "~0.12.16",
5477
"karma-browserify": "~0.2.0",
55-
"karma-mocha": "~0.1.1",
56-
"grunt-karma": "~0.6.2"
78+
"karma-mocha": "~0.1.3",
79+
"grunt-karma": "~0.8.3"
5780
},
5881
"repository": {
5982
"type": "git",

‎test/access-token.test.js‎

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,27 @@ describe('loopback.token(options)', function() {
3232
.end(done);
3333
});
3434
});
35+
36+
it('should skip when req.token is already present', function(done) {
37+
var tokenStub = { id: 'stub id' };
38+
app.use(function(req, res, next) {
39+
req.accessToken = tokenStub;
40+
next();
41+
});
42+
app.use(loopback.token({ model: Token }));
43+
app.get('/', function(req, res, next) {
44+
res.send(req.accessToken);
45+
});
46+
47+
request(app).get('/')
48+
.set('Authorization', this.token.id)
49+
.expect(200)
50+
.end(function(err, res) {
51+
if (err) return done(err);
52+
expect(res.body).to.eql(tokenStub);
53+
done();
54+
});
55+
});
3556
});
3657

3758
describe('AccessToken', function () {

‎test/acl.test.js‎

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,13 @@ function checkResult(err, result) {
1414
assert(!err);
1515
}
1616

17-
describe('security scopes', function () {
17+
var ds = null;
18+
before(function() {
19+
ds = loopback.createDataSource({connector: loopback.Memory});
20+
});
1821

22+
describe('security scopes', function () {
1923
beforeEach(function() {
20-
var ds = this.ds = loopback.createDataSource({connector: loopback.Memory});
2124
testModel = loopback.Model.extend('testModel');
2225
ACL.attachTo(ds);
2326
Role.attachTo(ds);
@@ -156,7 +159,6 @@ describe('security ACLs', function () {
156159
});
157160

158161
it("should honor defaultPermission from the model", function () {
159-
var ds = this.ds;
160162
var Customer = ds.createModel('Customer', {
161163
name: {
162164
type: String,
@@ -188,7 +190,6 @@ describe('security ACLs', function () {
188190
});
189191

190192
it("should honor static ACLs from the model", function () {
191-
var ds = this.ds;
192193
var Customer = ds.createModel('Customer', {
193194
name: {
194195
type: String,
@@ -226,7 +227,6 @@ describe('security ACLs', function () {
226227
it("should check access against LDL, ACL, and Role", function () {
227228
// var log = console.log;
228229
var log = function() {};
229-
var ds = this.ds;
230230

231231
// Create
232232
User.create({name: 'Raymond', email: 'x@y.com', password: 'foobar'}, function (err, user) {

‎test/app.test.js‎

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,11 @@ describe('app', function() {
6161
});
6262
});
6363

64-
describe('app.model(name, properties, options)', function () {
65-
it('Sugar for defining a fully built model', function () {
66-
var app = loopback();
64+
describe('app.model(name, config)', function () {
65+
var app;
66+
67+
beforeEach(function() {
68+
app = loopback();
6769
app.boot({
6870
app: {port: 3000, host: '127.0.0.1'},
6971
dataSources: {
@@ -72,16 +74,39 @@ describe('app', function() {
7274
}
7375
}
7476
});
77+
});
7578

79+
it('Sugar for defining a fully built model', function () {
7680
app.model('foo', {
7781
dataSource: 'db'
7882
});
7983

8084
var Foo = app.models.foo;
81-
var f = new Foo;
85+
var f = new Foo();
8286

8387
assert(f instanceof loopback.Model);
8488
});
89+
90+
it('interprets extra first-level keys as options', function() {
91+
app.model('foo', {
92+
dataSource: 'db',
93+
base: 'User'
94+
});
95+
96+
expect(app.models.foo.definition.settings.base).to.equal('User');
97+
});
98+
99+
it('prefers config.options.key over config.key', function() {
100+
app.model('foo', {
101+
dataSource: 'db',
102+
base: 'User',
103+
options: {
104+
base: 'Application'
105+
}
106+
});
107+
108+
expect(app.models.foo.definition.settings.base).to.equal('Application');
109+
});
85110
});
86111

87112
describe('app.models', function() {

0 commit comments

Comments
 (0)