From 0ccc1e2b73452da501f6f2815820f21429fce476 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miroslav=20Bajto=C5=A1?= Date: Mon, 1 Jun 2015 12:07:15 +0200 Subject: [PATCH 1/2] Add loadBuiltinModels flag to loopback(options) When creating an application with a local registry, the default behaviour is to define only two core models Model & PersistedModel. The new flag `loadBuiltinModels` modifies this behaviour and instructs loopback to define all builtin models in the local registry too. --- lib/loopback.js | 3 +++ test/loopback.test.js | 18 ++++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/lib/loopback.js b/lib/loopback.js index e1b162dc..70529fff 100644 --- a/lib/loopback.js +++ b/lib/loopback.js @@ -99,6 +99,9 @@ function createApplication(options) { if (loopback.localRegistry || options && options.localRegistry === true) { // setup the app registry var registry = app.registry = new Registry(); + if (options && options.loadBuiltinModels === true) { + require('./builtin-models')(registry); + } } else { app.registry = loopback.registry; } diff --git a/test/loopback.test.js b/test/loopback.test.js index 9b39709e..ce45aa14 100644 --- a/test/loopback.test.js +++ b/test/loopback.test.js @@ -115,6 +115,24 @@ describe('loopback', function() { }); }); + describe('loopback(options)', function() { + it('supports localRegistry:true', function() { + var app = loopback({ localRegistry: true }); + expect(app.registry).to.not.equal(loopback.registry); + }); + + it('does not load builtin models into the local registry', function() { + var app = loopback({ localRegistry: true }); + expect(app.registry.findModel('User')).to.equal(undefined); + }); + + it('supports loadBuiltinModels:true', function() { + var app = loopback({ localRegistry: true, loadBuiltinModels: true }); + expect(app.registry.findModel('User')) + .to.have.property('modelName', 'User'); + }); + }); + describe('loopback.createDataSource(options)', function() { it('Create a data source with a connector.', function() { var dataSource = loopback.createDataSource({ From 3115e5055fb493cf260a248e0bf6323f6359ccdc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miroslav=20Bajto=C5=A1?= Date: Tue, 21 Apr 2015 13:46:17 +0200 Subject: [PATCH 2/2] Auto-configure models required by `app.enableAuth` Modify `app.enableAuth` to automaticaly setup all required models that are not attached to the app nor a datasource. Users wishing to use this option must provide the name of the data-source to use for these models. Example usage: var app = loopback(); app.dataSource('db', { connector: 'memory' }); app.enableAuth({ dataSource: 'db' }); app.use(loopback.rest()); app.listen(3000); --- lib/application.js | 29 ++++++++++++++++++++++++++++- test/app.test.js | 28 ++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+), 1 deletion(-) diff --git a/lib/application.js b/lib/application.js index 3d448d67..062394d0 100644 --- a/lib/application.js +++ b/lib/application.js @@ -291,10 +291,37 @@ app.dataSources = app.datasources = {}; * Enable app wide authentication. */ -app.enableAuth = function() { +app.enableAuth = function(options) { + var AUTH_MODELS = ['User', 'AccessToken', 'ACL', 'Role', 'RoleMapping']; + var remotes = this.remotes(); var app = this; + if (options && options.dataSource) { + var appModels = app.registry.modelBuilder.models; + AUTH_MODELS.forEach(function(m) { + var Model = app.registry.findModel(m); + if (!Model) { + throw new Error( + 'Authentication requires model ' + m + ' to be defined.'); + } + + if (m.dataSource || m.app) return; + + for (var name in appModels) { + var candidate = appModels[name]; + var isSubclass = candidate.prototype instanceof Model; + var isAttached = !!candidate.dataSource || !!candidate.app; + if (isSubclass && isAttached) return; + } + + app.model(Model, { + dataSource: options.dataSource, + public: m === 'User' + }); + }); + } + remotes.authorization = function(ctx, next) { var method = ctx.method; var req = ctx.req; diff --git a/test/app.test.js b/test/app.test.js index 78870372..47988ff6 100644 --- a/test/app.test.js +++ b/test/app.test.js @@ -796,6 +796,34 @@ describe('app', function() { app.enableAuth(); expect(app.isAuthEnabled).to.equal(true); }); + + it('auto-configures required models to provided dataSource', function() { + var AUTH_MODELS = ['User', 'ACL', 'AccessToken', 'Role', 'RoleMapping']; + var app = loopback({ localRegistry: true, loadBuiltinModels: true }); + require('../lib/builtin-models')(app.registry); + var db = app.dataSource('db', { connector: 'memory' }); + + app.enableAuth({ dataSource: 'db' }); + + expect(Object.keys(app.models)).to.include.members(AUTH_MODELS); + + AUTH_MODELS.forEach(function(m) { + var Model = app.models[m]; + expect(Model.dataSource, m + '.dataSource').to.equal(db); + expect(Model.shared, m + '.shared').to.equal(m === 'User'); + }); + }); + + it('detects already configured subclass of a required model', function() { + var app = loopback({ localRegistry: true, loadBuiltinModels: true }); + var db = app.dataSource('db', { connector: 'memory' }); + var Customer = app.registry.createModel('Customer', {}, { base: 'User' }); + app.model(Customer, { dataSource: 'db' }); + + app.enableAuth({ dataSource: 'db' }); + + expect(Object.keys(app.models)).to.not.include('User'); + }); }); describe.onServer('app.get(\'/\', loopback.status())', function() {