Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 14 additions & 6 deletions common/models/role-mapping.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

'use strict';
var loopback = require('../../lib/loopback');
var utils = require('../../lib/utils');

/**
* The `RoleMapping` model extends from the built in `loopback.Model` type.
Expand All @@ -26,9 +27,9 @@ module.exports = function(RoleMapping) {
RoleMapping.resolveRelatedModels = function() {
if (!this.userModel) {
var reg = this.registry;
this.roleModel = reg.getModelByType(loopback.Role);
this.userModel = reg.getModelByType(loopback.User);
this.applicationModel = reg.getModelByType(loopback.Application);
this.roleModel = reg.getModelByType('Role');
this.userModel = reg.getModelByType('User');
this.applicationModel = reg.getModelByType('Application');
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this change is required as the use of loopback.Role would lead to inconsistent results given the recent introduction of app-local registry

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense 👍

};

Expand All @@ -39,16 +40,18 @@ module.exports = function(RoleMapping) {
* @param {Application} application
*/
RoleMapping.prototype.application = function(callback) {
callback = callback || utils.createPromiseCallback();
this.constructor.resolveRelatedModels();

if (this.principalType === RoleMapping.APPLICATION) {
var applicationModel = this.constructor.applicationModel;
applicationModel.findById(this.principalId, callback);
} else {
process.nextTick(function() {
if (callback) callback(null, null);
callback(null, null);
});
}
return callback.promise;
};

/**
Expand All @@ -58,15 +61,18 @@ module.exports = function(RoleMapping) {
* @param {User} user
*/
RoleMapping.prototype.user = function(callback) {
callback = callback || utils.createPromiseCallback();
this.constructor.resolveRelatedModels();

if (this.principalType === RoleMapping.USER) {
var userModel = this.constructor.userModel;
userModel.findById(this.principalId, callback);
} else {
process.nextTick(function() {
if (callback) callback(null, null);
callback(null, null);
});
}
return callback.promise;
};

/**
Expand All @@ -76,15 +82,17 @@ module.exports = function(RoleMapping) {
* @param {User} childUser
*/
RoleMapping.prototype.childRole = function(callback) {
callback = callback || utils.createPromiseCallback();
this.constructor.resolveRelatedModels();

if (this.principalType === RoleMapping.ROLE) {
var roleModel = this.constructor.roleModel;
roleModel.findById(this.principalId, callback);
} else {
process.nextTick(function() {
if (callback) callback(null, null);
callback(null, null);
});
}
return callback.promise;
};
};
116 changes: 116 additions & 0 deletions test/role-mapping.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
// Copyright IBM Corp. 2013,2016. All Rights Reserved.
// Node module: loopback
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT

'use strict';
var expect = require('./helpers/expect');
var loopback = require('../');
var Promise = require('bluebird');

describe('role-mapping model', function() {
this.timeout(10000);

var app, oneUser, anApp, aRole;
var models = {};

beforeEach(function() {
app = loopback({localRegistry: true, loadBuiltinModels: true});
app.dataSource('db', {connector: 'memory'});

// setup models
['User', 'Role', 'RoleMapping', 'Application'].map(setupModel);

// create generic instances
return Promise.all([
models.User.create({
username: 'oneUser',
email: 'user@email.com',
password: 'password',
}),
models.Application.create({name: 'anApp'}),
models.Role.create({name: 'aRole'}),
])
.spread(function(u, a, r) {
oneUser = u;
anApp = a;
aRole = r;
});

// helper
function setupModel(modelName) {
var model = app.registry.getModel(modelName);
app.model(model, {dataSource: 'db'});
models[modelName] = model;
}
});

it('supports .user() with a callback', function(done) {
models.RoleMapping.create(
{principalType: 'USER', principalId: oneUser.id},
function(err, mapping) {
if (err) done(err);
mapping.user(function(err, user) {
if (err) done(err);
expect(user.id).to.equal(oneUser.id);
done();
});
});
});

it('supports .user() returning a promise', function() {
return models.RoleMapping.create({principalType: 'USER', principalId: oneUser.id})
.then(function(mapping) {
return mapping.user();
})
.then(function(user) {
expect(user.id).to.equal(oneUser.id);
});
});

it('supports .application() with a callback', function(done) {
models.RoleMapping.create(
{principalType: 'APP', principalId: anApp.id},
function(err, mapping) {
if (err) done(err);
mapping.application(function(err, app) {
if (err) done(err);
expect(app.id).to.equal(anApp.id);
done();
});
});
});

it('supports .application() returning a promise', function() {
return models.RoleMapping.create({principalType: 'APP', principalId: anApp.id})
.then(function(mapping) {
return mapping.application();
})
.then(function(app) {
expect(app.id).to.equal(anApp.id);
});
});

it('supports .childRole() with a callback', function(done) {
models.RoleMapping.create(
{principalType: 'ROLE', principalId: aRole.id},
function(err, mapping) {
if (err) done(err);
mapping.childRole(function(err, role) {
if (err) done(err);
expect(role.id).to.equal(aRole.id);
done();
});
});
});

it('supports .childRole() returning a promise', function() {
return models.RoleMapping.create({principalType: 'ROLE', principalId: aRole.id})
.then(function(mapping) {
return mapping.childRole();
})
.then(function(role) {
expect(role.id).to.equal(aRole.id);
});
});
});