Merge pull request #745 from strongloop/feature/allow-acls-settings-config
Allows ACLs/settings in model config
This commit is contained in:
commit
747da886c9
|
@ -145,6 +145,25 @@ function buildModelOptionsFromConfig(config) {
|
|||
return options;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add the acl entry to the acls
|
||||
* @param {Object[]} acls
|
||||
* @param {Object} acl
|
||||
*/
|
||||
function addACL(acls, acl) {
|
||||
for (var i = 0, n = acls.length; i < n; i++) {
|
||||
// Check if there is a matching acl to be overriden
|
||||
if (acls[i].property === acl.property &&
|
||||
acls[i].accessType === acl.accessType &&
|
||||
acls[i].principalType === acl.principalType &&
|
||||
acls[i].principalId === acl.principalId) {
|
||||
acls[i] = acl;
|
||||
return;
|
||||
}
|
||||
}
|
||||
acls.push(acl);
|
||||
}
|
||||
|
||||
/**
|
||||
* Alter an existing Model class.
|
||||
* @param {Model} ModelCtor The model constructor to alter.
|
||||
|
@ -157,12 +176,51 @@ function buildModelOptionsFromConfig(config) {
|
|||
|
||||
registry.configureModel = function(ModelCtor, config) {
|
||||
var settings = ModelCtor.settings;
|
||||
var modelName = ModelCtor.modelName;
|
||||
|
||||
if (config.relations) {
|
||||
// Relations
|
||||
if (typeof config.relations === 'object' && config.relations !== null) {
|
||||
var relations = settings.relations = settings.relations || {};
|
||||
Object.keys(config.relations).forEach(function(key) {
|
||||
// FIXME: [rfeng] We probably should check if the relation exists
|
||||
relations[key] = extend(relations[key] || {}, config.relations[key]);
|
||||
});
|
||||
} else if (config.relations != null) {
|
||||
console.warn('The relations property of `%s` configuration ' +
|
||||
'must be an object', modelName);
|
||||
}
|
||||
|
||||
// ACLs
|
||||
if (Array.isArray(config.acls)) {
|
||||
var acls = settings.acls = settings.acls || [];
|
||||
config.acls.forEach(function(acl) {
|
||||
addACL(acls, acl);
|
||||
});
|
||||
} else if (config.acls != null) {
|
||||
console.warn('The acls property of `%s` configuration ' +
|
||||
'must be an array of objects', modelName);
|
||||
}
|
||||
|
||||
// Settings
|
||||
var excludedProperties = {
|
||||
base: true,
|
||||
'super': true,
|
||||
relations: true,
|
||||
acls: true,
|
||||
dataSource: true
|
||||
};
|
||||
if (typeof config.options === 'object' && config.options !== null) {
|
||||
for (var p in config.options) {
|
||||
if (!(p in excludedProperties)) {
|
||||
settings[p] = config.options[p];
|
||||
} else {
|
||||
console.warn('Property `%s` cannot be reconfigured for `%s`',
|
||||
p, modelName);
|
||||
}
|
||||
}
|
||||
} else if (config.options != null) {
|
||||
console.warn('The options property of `%s` configuration ' +
|
||||
'must be an object', modelName);
|
||||
}
|
||||
|
||||
// It's important to attach the datasource after we have updated
|
||||
|
@ -173,17 +231,17 @@ registry.configureModel = function(ModelCtor, config) {
|
|||
': config.dataSource must be an instance of DataSource');
|
||||
ModelCtor.attachTo(config.dataSource);
|
||||
debug('Attached model `%s` to dataSource `%s`',
|
||||
ModelCtor.definition.name, config.dataSource.name);
|
||||
modelName, config.dataSource.name);
|
||||
} else if (config.dataSource === null) {
|
||||
debug('Model `%s` is not attached to any DataSource by configuration.',
|
||||
ModelCtor.definition.name);
|
||||
modelName);
|
||||
} else {
|
||||
debug('Model `%s` is not attached to any DataSource, possibly by a mistake.',
|
||||
ModelCtor.definition.name);
|
||||
modelName);
|
||||
console.warn(
|
||||
'The configuration of `%s` is missing `dataSource` property.\n' +
|
||||
'Use `null` or `false` to mark models not attached to any data source.',
|
||||
ModelCtor.definition.name);
|
||||
modelName);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -249,6 +249,109 @@ describe('loopback', function() {
|
|||
expect(owner, 'model.prototype.owner').to.be.a('function');
|
||||
expect(owner._targetClass).to.equal('User');
|
||||
});
|
||||
|
||||
it('adds new acls', function() {
|
||||
var model = loopback.Model.extend(uniqueModelName, {}, {
|
||||
acls: [
|
||||
{
|
||||
property: 'find',
|
||||
accessType: 'EXECUTE',
|
||||
principalType: 'ROLE',
|
||||
principalId: '$everyone',
|
||||
permission: 'DENY'
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
loopback.configureModel(model, {
|
||||
dataSource: null,
|
||||
acls: [
|
||||
{
|
||||
property: 'find',
|
||||
accessType: 'EXECUTE',
|
||||
principalType: 'ROLE',
|
||||
principalId: 'admin',
|
||||
permission: 'ALLOW'
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
expect(model.settings.acls).eql([
|
||||
{
|
||||
property: 'find',
|
||||
accessType: 'EXECUTE',
|
||||
principalType: 'ROLE',
|
||||
principalId: '$everyone',
|
||||
permission: 'DENY'
|
||||
},
|
||||
{
|
||||
property: 'find',
|
||||
accessType: 'EXECUTE',
|
||||
principalType: 'ROLE',
|
||||
principalId: 'admin',
|
||||
permission: 'ALLOW'
|
||||
}
|
||||
]);
|
||||
});
|
||||
|
||||
it('updates existing acls', function() {
|
||||
var model = loopback.Model.extend(uniqueModelName, {}, {
|
||||
acls: [
|
||||
{
|
||||
property: 'find',
|
||||
accessType: 'EXECUTE',
|
||||
principalType: 'ROLE',
|
||||
principalId: '$everyone',
|
||||
permission: 'DENY'
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
loopback.configureModel(model, {
|
||||
dataSource: null,
|
||||
acls: [
|
||||
{
|
||||
property: 'find',
|
||||
accessType: 'EXECUTE',
|
||||
principalType: 'ROLE',
|
||||
principalId: '$everyone',
|
||||
permission: 'ALLOW'
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
expect(model.settings.acls).eql([
|
||||
{
|
||||
property: 'find',
|
||||
accessType: 'EXECUTE',
|
||||
principalType: 'ROLE',
|
||||
principalId: '$everyone',
|
||||
permission: 'ALLOW'
|
||||
}
|
||||
]);
|
||||
});
|
||||
|
||||
it('updates existing settings', function() {
|
||||
var model = loopback.Model.extend(uniqueModelName, {}, {
|
||||
ttl: 10,
|
||||
emailVerificationRequired: false
|
||||
});
|
||||
|
||||
loopback.configureModel(model, {
|
||||
dataSource: null,
|
||||
options: {
|
||||
ttl: 20,
|
||||
realmRequired: true,
|
||||
base: 'X'
|
||||
}
|
||||
});
|
||||
|
||||
expect(model.settings).to.have.property('ttl', 20);
|
||||
expect(model.settings).to.have.property('emailVerificationRequired',
|
||||
false);
|
||||
expect(model.settings).to.have.property('realmRequired', true);
|
||||
expect(model.settings).to.not.have.property('base');
|
||||
});
|
||||
});
|
||||
|
||||
describe('loopback object', function() {
|
||||
|
|
Loading…
Reference in New Issue