Merge pull request #3728 from strongloop/update-eslint-config
Update eslint and eslint-config to latest
This commit is contained in:
commit
7c030c6900
|
@ -111,8 +111,8 @@ module.exports = function(AccessToken) {
|
|||
// replacement for deprecated req.param()
|
||||
id = req.params && req.params[param] !== undefined ? req.params[param] :
|
||||
req.body && req.body[param] !== undefined ? req.body[param] :
|
||||
req.query && req.query[param] !== undefined ? req.query[param] :
|
||||
undefined;
|
||||
req.query && req.query[param] !== undefined ? req.query[param] :
|
||||
undefined;
|
||||
|
||||
if (typeof id === 'string') {
|
||||
return id;
|
||||
|
@ -227,7 +227,7 @@ module.exports = function(AccessToken) {
|
|||
AccessToken.prototype.validate = function(cb) {
|
||||
try {
|
||||
assert(
|
||||
this.created && typeof this.created.getTime === 'function',
|
||||
this.created && typeof this.created.getTime === 'function',
|
||||
'token.created must be a valid Date'
|
||||
);
|
||||
assert(this.ttl !== 0, 'token.ttl must be not be 0');
|
||||
|
|
|
@ -332,8 +332,8 @@ module.exports = function(ACL) {
|
|||
* @param {AccessRequest} result The resolved access request.
|
||||
*/
|
||||
ACL.checkPermission = function checkPermission(principalType, principalId,
|
||||
model, property, accessType,
|
||||
callback) {
|
||||
model, property, accessType,
|
||||
callback) {
|
||||
if (!callback) callback = utils.createPromiseCallback();
|
||||
if (principalId !== null && principalId !== undefined && (typeof principalId !== 'string')) {
|
||||
principalId = principalId.toString();
|
||||
|
@ -363,15 +363,15 @@ module.exports = function(ACL) {
|
|||
var self = this;
|
||||
this.find({where: {principalType: principalType, principalId: principalId,
|
||||
model: model, property: propertyQuery, accessType: accessTypeQuery}},
|
||||
function(err, dynACLs) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
acls = acls.concat(dynACLs);
|
||||
// resolved is an instance of AccessRequest
|
||||
resolved = self.resolvePermission(acls, req);
|
||||
return callback(null, resolved);
|
||||
});
|
||||
function(err, dynACLs) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
acls = acls.concat(dynACLs);
|
||||
// resolved is an instance of AccessRequest
|
||||
resolved = self.resolvePermission(acls, req);
|
||||
return callback(null, resolved);
|
||||
});
|
||||
return callback.promise;
|
||||
};
|
||||
|
||||
|
|
|
@ -223,7 +223,7 @@ module.exports = function(KeyValueModel) {
|
|||
function throwNotAttached(modelName, methodName) {
|
||||
throw new Error(g.f(
|
||||
'Cannot call %s.%s(). ' +
|
||||
'The %s method has not been setup. ' +
|
||||
'The %s method has not been setup. ' +
|
||||
'The {{KeyValueModel}} has not been correctly attached ' +
|
||||
'to a {{DataSource}}!',
|
||||
modelName, methodName, methodName));
|
||||
|
|
|
@ -539,10 +539,10 @@ module.exports = function(Role) {
|
|||
if (principalType && principalId) {
|
||||
roleMappingModel.findOne({where: {roleId: roleId,
|
||||
principalType: principalType, principalId: principalId}},
|
||||
function(err, result) {
|
||||
debug('Role mapping found: %j', result);
|
||||
done(!err && result); // The only arg is the result
|
||||
});
|
||||
function(err, result) {
|
||||
debug('Role mapping found: %j', result);
|
||||
done(!err && result); // The only arg is the result
|
||||
});
|
||||
} else {
|
||||
process.nextTick(function() {
|
||||
done(false);
|
||||
|
|
|
@ -749,9 +749,9 @@ module.exports = function(User) {
|
|||
displayPort +
|
||||
urlPath +
|
||||
'?' + qs.stringify({
|
||||
uid: '' + verifyOptions.user[pkName],
|
||||
redirect: verifyOptions.redirect,
|
||||
});
|
||||
uid: '' + verifyOptions.user[pkName],
|
||||
redirect: verifyOptions.redirect,
|
||||
});
|
||||
|
||||
verifyOptions.to = verifyOptions.to || user.email;
|
||||
verifyOptions.subject = verifyOptions.subject || g.f('Thanks for Registering');
|
||||
|
|
|
@ -349,9 +349,9 @@ app.enableAuth = function(options) {
|
|||
var modelId = modelInstance && modelInstance.id ||
|
||||
// replacement for deprecated req.param()
|
||||
(req.params && req.params.id !== undefined ? req.params.id :
|
||||
req.body && req.body.id !== undefined ? req.body.id :
|
||||
req.query && req.query.id !== undefined ? req.query.id :
|
||||
undefined);
|
||||
req.body && req.body.id !== undefined ? req.body.id :
|
||||
req.query && req.query.id !== undefined ? req.query.id :
|
||||
undefined);
|
||||
|
||||
var modelName = Model.modelName;
|
||||
|
||||
|
@ -464,7 +464,7 @@ app._verifyAuthModelRelations = function() {
|
|||
console.warn(
|
||||
'The app configuration follows the multiple user models setup ' +
|
||||
'as described in http://ibm.biz/setup-loopback-auth',
|
||||
'The built-in role resolver $owner is not currently compatible ' +
|
||||
'The built-in role resolver $owner is not currently compatible ' +
|
||||
'with this configuration and should not be used in production.');
|
||||
}
|
||||
|
||||
|
|
|
@ -845,7 +845,7 @@ module.exports = function(registry) {
|
|||
],
|
||||
description: format('Counts %s of %s.', scopeName, this.modelName),
|
||||
accessType: 'READ',
|
||||
returns: {arg: 'count', type: 'number'},
|
||||
returns: {arg: 'count', type: 'number'},
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -890,7 +890,7 @@ module.exports = function(registry) {
|
|||
acceptArgs = [
|
||||
{
|
||||
arg: paramName, type: 'any', http: {source: 'path'},
|
||||
description: format('Foreign key for %s.', relation.name),
|
||||
description: format('Foreign key for %s.', relation.name),
|
||||
required: true,
|
||||
},
|
||||
];
|
||||
|
|
|
@ -1485,7 +1485,7 @@ module.exports = function(registry) {
|
|||
|
||||
function applyUpdate(Model, id, current, data, change, conflicts, options, cb) {
|
||||
var Change = Model.getChangeModel();
|
||||
var rev = current ? Change.revisionForInst(current) : null;
|
||||
var rev = current ? Change.revisionForInst(current) : null;
|
||||
|
||||
if (rev !== change.prev) {
|
||||
debug('Detected non-rectified change of %s %j',
|
||||
|
|
|
@ -230,7 +230,7 @@ Registry.prototype.configureModel = function(ModelCtor, config) {
|
|||
// configuration, so that the datasource picks up updated relations
|
||||
if (config.dataSource) {
|
||||
assert(config.dataSource instanceof DataSource,
|
||||
'Cannot configure ' + ModelCtor.modelName +
|
||||
'Cannot configure ' + ModelCtor.modelName +
|
||||
': config.dataSource must be an instance of DataSource');
|
||||
ModelCtor.attachTo(config.dataSource);
|
||||
debug('Attached model `%s` to dataSource `%s`',
|
||||
|
@ -398,7 +398,7 @@ Registry.prototype.memory = function(name) {
|
|||
name = name || 'default';
|
||||
var memory = (
|
||||
this._memoryDataSources || (this._memoryDataSources = {})
|
||||
)[name];
|
||||
)[name];
|
||||
|
||||
if (!memory) {
|
||||
memory = this._memoryDataSources[name] = this.createDataSource({
|
||||
|
|
|
@ -226,7 +226,7 @@ proto._findLayerByHandler = function(handler) {
|
|||
if (this._router.stack[k].handle === handler ||
|
||||
// NewRelic replaces the handle and keeps it as __NR_original
|
||||
this._router.stack[k].handle['__NR_original'] === handler
|
||||
) {
|
||||
) {
|
||||
return this._router.stack[k];
|
||||
} else {
|
||||
// Aggressively check if the original handler has been wrapped
|
||||
|
|
|
@ -68,14 +68,16 @@
|
|||
"cookie-parser": "^1.3.4",
|
||||
"coveralls": "^2.11.15",
|
||||
"dirty-chai": "^1.2.2",
|
||||
"eslint-config-loopback": "^8.0.0",
|
||||
"eslint": "^4.13.1",
|
||||
"eslint-config-loopback": "^10.0.0",
|
||||
"eslint-plugin-mocha": "^4.11.0",
|
||||
"express-session": "^1.14.0",
|
||||
"grunt": "^1.0.1",
|
||||
"grunt-browserify": "^5.0.0",
|
||||
"grunt-cli": "^1.2.0",
|
||||
"grunt-contrib-uglify": "^2.0.0",
|
||||
"grunt-contrib-watch": "^1.0.0",
|
||||
"grunt-eslint": "^19.0.0",
|
||||
"grunt-eslint": "^20.1.0",
|
||||
"grunt-karma": "^2.0.0",
|
||||
"grunt-mocha-test": "^0.12.7",
|
||||
"karma": "^1.1.2",
|
||||
|
|
|
@ -30,7 +30,7 @@ function rewriteUserLiteral(req, currentUserLiteral, next) {
|
|||
// Replace /me/ with /current-user-id/
|
||||
var urlBeforeRewrite = req.url;
|
||||
req.url = req.url.replace(literalRegExp,
|
||||
'/' + req.accessToken.userId + '$1');
|
||||
'/' + req.accessToken.userId + '$1');
|
||||
|
||||
if (req.url !== urlBeforeRewrite) {
|
||||
debug('req.url has been rewritten from %s to %s', urlBeforeRewrite,
|
||||
|
|
|
@ -139,39 +139,39 @@ describe('loopback.token(options)', function() {
|
|||
});
|
||||
|
||||
it('does not search default keys when searchDefaultTokenKeys is false',
|
||||
function(done) {
|
||||
var tokenId = this.token.id;
|
||||
var app = createTestApp(
|
||||
this.token,
|
||||
{token: {searchDefaultTokenKeys: false}},
|
||||
done);
|
||||
var agent = request.agent(app);
|
||||
function(done) {
|
||||
var tokenId = this.token.id;
|
||||
var app = createTestApp(
|
||||
this.token,
|
||||
{token: {searchDefaultTokenKeys: false}},
|
||||
done);
|
||||
var agent = request.agent(app);
|
||||
|
||||
// Set the token cookie
|
||||
agent.get('/token').expect(200).end(function(err, res) {
|
||||
if (err) return done(err);
|
||||
// Set the token cookie
|
||||
agent.get('/token').expect(200).end(function(err, res) {
|
||||
if (err) return done(err);
|
||||
|
||||
// Make a request that sets the token in all places searched by default
|
||||
agent.get('/check-access?access_token=' + tokenId)
|
||||
.set('X-Access-Token', tokenId)
|
||||
.set('authorization', tokenId)
|
||||
// Make a request that sets the token in all places searched by default
|
||||
agent.get('/check-access?access_token=' + tokenId)
|
||||
.set('X-Access-Token', tokenId)
|
||||
.set('authorization', tokenId)
|
||||
// Expect 401 because there is no (non-default) place configured where
|
||||
// the middleware should load the token from
|
||||
.expect(401)
|
||||
.end(done);
|
||||
.expect(401)
|
||||
.end(done);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('populates req.token from an authorization header with bearer token with base64',
|
||||
function(done) {
|
||||
var token = this.token.id;
|
||||
token = 'Bearer ' + new Buffer(token).toString('base64');
|
||||
createTestAppAndRequest(this.token, done)
|
||||
.get('/')
|
||||
.set('authorization', token)
|
||||
.expect(200)
|
||||
.end(done);
|
||||
});
|
||||
function(done) {
|
||||
var token = this.token.id;
|
||||
token = 'Bearer ' + new Buffer(token).toString('base64');
|
||||
createTestAppAndRequest(this.token, done)
|
||||
.get('/')
|
||||
.set('authorization', token)
|
||||
.expect(200)
|
||||
.end(done);
|
||||
});
|
||||
|
||||
it('populates req.token from an authorization header with bearer token', function(done) {
|
||||
var token = this.token.id;
|
||||
|
@ -346,29 +346,29 @@ describe('loopback.token(options)', function() {
|
|||
|
||||
describe('loading multiple instances of token middleware', function() {
|
||||
it('skips when req.token is already present and no further options are set',
|
||||
function(done) {
|
||||
var tokenStub = {id: 'stub id'};
|
||||
app.use(function(req, res, next) {
|
||||
req.accessToken = tokenStub;
|
||||
function(done) {
|
||||
var tokenStub = {id: 'stub id'};
|
||||
app.use(function(req, res, next) {
|
||||
req.accessToken = tokenStub;
|
||||
|
||||
next();
|
||||
});
|
||||
app.use(loopback.token({model: Token}));
|
||||
app.get('/', function(req, res, next) {
|
||||
res.send(req.accessToken);
|
||||
});
|
||||
|
||||
request(app).get('/')
|
||||
.set('Authorization', this.token.id)
|
||||
.expect(200)
|
||||
.end(function(err, res) {
|
||||
if (err) return done(err);
|
||||
|
||||
expect(res.body).to.eql(tokenStub);
|
||||
|
||||
done();
|
||||
next();
|
||||
});
|
||||
});
|
||||
app.use(loopback.token({model: Token}));
|
||||
app.get('/', function(req, res, next) {
|
||||
res.send(req.accessToken);
|
||||
});
|
||||
|
||||
request(app).get('/')
|
||||
.set('Authorization', this.token.id)
|
||||
.expect(200)
|
||||
.end(function(err, res) {
|
||||
if (err) return done(err);
|
||||
|
||||
expect(res.body).to.eql(tokenStub);
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('does not overwrite valid existing token (has "id" property) ' +
|
||||
' when overwriteExistingToken is falsy',
|
||||
|
@ -509,21 +509,21 @@ describe('AccessToken', function() {
|
|||
});
|
||||
|
||||
it('allows eternal tokens when enabled by User.allowEternalTokens',
|
||||
function(done) {
|
||||
var Token = givenLocalTokenModel();
|
||||
function(done) {
|
||||
var Token = givenLocalTokenModel();
|
||||
|
||||
// Overwrite User settings - enable eternal tokens
|
||||
Token.app.models.User.settings.allowEternalTokens = true;
|
||||
// Overwrite User settings - enable eternal tokens
|
||||
Token.app.models.User.settings.allowEternalTokens = true;
|
||||
|
||||
Token.create({userId: '123', ttl: -1}, function(err, token) {
|
||||
if (err) return done(err);
|
||||
token.validate(function(err, isValid) {
|
||||
Token.create({userId: '123', ttl: -1}, function(err, token) {
|
||||
if (err) return done(err);
|
||||
expect(isValid, 'isValid').to.equal(true);
|
||||
done();
|
||||
token.validate(function(err, isValid) {
|
||||
if (err) return done(err);
|
||||
expect(isValid, 'isValid').to.equal(true);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('.findForRequest()', function() {
|
||||
|
@ -649,7 +649,7 @@ describe('app.enableAuth()', function() {
|
|||
});
|
||||
});
|
||||
|
||||
it('prevent remote call with app setting status on denied ACL', function(done) {
|
||||
it('denies remote call with app setting status 403', function(done) {
|
||||
createTestAppAndRequest(this.token, {app: {aclErrorStatus: 403}}, done)
|
||||
.del('/tests/123')
|
||||
.expect(403)
|
||||
|
@ -667,7 +667,7 @@ describe('app.enableAuth()', function() {
|
|||
});
|
||||
});
|
||||
|
||||
it('prevent remote call with app setting status on denied ACL', function(done) {
|
||||
it('denies remote call with app setting status 404', function(done) {
|
||||
createTestAppAndRequest(this.token, {model: {aclErrorStatus: 404}}, done)
|
||||
.del('/tests/123')
|
||||
.expect(404)
|
||||
|
|
296
test/acl.test.js
296
test/acl.test.js
|
@ -50,51 +50,51 @@ describe('security scopes', function() {
|
|||
|
||||
it('should allow access to models for the given scope by wildcard', function() {
|
||||
Scope.create({name: 'userScope', description: 'access user information'},
|
||||
function(err, scope) {
|
||||
ACL.create({
|
||||
principalType: ACL.SCOPE, principalId: scope.id,
|
||||
model: 'User', property: ACL.ALL,
|
||||
accessType: ACL.ALL, permission: ACL.ALLOW,
|
||||
}, function(err, resource) {
|
||||
Scope.checkPermission('userScope', 'User', ACL.ALL, ACL.ALL, checkResult);
|
||||
Scope.checkPermission('userScope', 'User', 'name', ACL.ALL, checkResult);
|
||||
Scope.checkPermission('userScope', 'User', 'name', ACL.READ, checkResult);
|
||||
function(err, scope) {
|
||||
ACL.create({
|
||||
principalType: ACL.SCOPE, principalId: scope.id,
|
||||
model: 'User', property: ACL.ALL,
|
||||
accessType: ACL.ALL, permission: ACL.ALLOW,
|
||||
}, function(err, resource) {
|
||||
Scope.checkPermission('userScope', 'User', ACL.ALL, ACL.ALL, checkResult);
|
||||
Scope.checkPermission('userScope', 'User', 'name', ACL.ALL, checkResult);
|
||||
Scope.checkPermission('userScope', 'User', 'name', ACL.READ, checkResult);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should allow access to models for the given scope', function() {
|
||||
Scope.create({name: 'testModelScope', description: 'access testModel information'},
|
||||
function(err, scope) {
|
||||
ACL.create({
|
||||
principalType: ACL.SCOPE, principalId: scope.id,
|
||||
model: 'testModel', property: 'name',
|
||||
accessType: ACL.READ, permission: ACL.ALLOW,
|
||||
}, function(err, resource) {
|
||||
ACL.create({principalType: ACL.SCOPE, principalId: scope.id,
|
||||
function(err, scope) {
|
||||
ACL.create({
|
||||
principalType: ACL.SCOPE, principalId: scope.id,
|
||||
model: 'testModel', property: 'name',
|
||||
accessType: ACL.WRITE, permission: ACL.DENY,
|
||||
accessType: ACL.READ, permission: ACL.ALLOW,
|
||||
}, function(err, resource) {
|
||||
ACL.create({principalType: ACL.SCOPE, principalId: scope.id,
|
||||
model: 'testModel', property: 'name',
|
||||
accessType: ACL.WRITE, permission: ACL.DENY,
|
||||
}, function(err, resource) {
|
||||
// console.log(resource);
|
||||
Scope.checkPermission('testModelScope', 'testModel', ACL.ALL, ACL.ALL,
|
||||
function(err, perm) {
|
||||
assert(perm.permission === ACL.DENY); // because name.WRITE == DENY
|
||||
});
|
||||
Scope.checkPermission('testModelScope', 'testModel', 'name', ACL.ALL,
|
||||
function(err, perm) {
|
||||
assert(perm.permission === ACL.DENY); // because name.WRITE == DENY
|
||||
});
|
||||
Scope.checkPermission('testModelScope', 'testModel', 'name', ACL.READ,
|
||||
function(err, perm) {
|
||||
assert(perm.permission === ACL.ALLOW);
|
||||
});
|
||||
Scope.checkPermission('testModelScope', 'testModel', 'name', ACL.WRITE,
|
||||
function(err, perm) {
|
||||
assert(perm.permission === ACL.DENY);
|
||||
});
|
||||
Scope.checkPermission('testModelScope', 'testModel', ACL.ALL, ACL.ALL,
|
||||
function(err, perm) {
|
||||
assert(perm.permission === ACL.DENY); // because name.WRITE == DENY
|
||||
});
|
||||
Scope.checkPermission('testModelScope', 'testModel', 'name', ACL.ALL,
|
||||
function(err, perm) {
|
||||
assert(perm.permission === ACL.DENY); // because name.WRITE == DENY
|
||||
});
|
||||
Scope.checkPermission('testModelScope', 'testModel', 'name', ACL.READ,
|
||||
function(err, perm) {
|
||||
assert(perm.permission === ACL.ALLOW);
|
||||
});
|
||||
Scope.checkPermission('testModelScope', 'testModel', 'name', ACL.WRITE,
|
||||
function(err, perm) {
|
||||
assert(perm.permission === ACL.DENY);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -108,12 +108,12 @@ describe('security ACLs', function() {
|
|||
accessType: ACL.ALL,
|
||||
permission: ACL.ALLOW,
|
||||
})
|
||||
.then(function() {
|
||||
return ACL.checkPermission(ACL.USER, 'u001', 'testModel', 'name', ACL.ALL);
|
||||
})
|
||||
.then(function(access) {
|
||||
assert(access.permission === ACL.ALLOW);
|
||||
});
|
||||
.then(function() {
|
||||
return ACL.checkPermission(ACL.USER, 'u001', 'testModel', 'name', ACL.ALL);
|
||||
})
|
||||
.then(function(access) {
|
||||
assert(access.permission === ACL.ALLOW);
|
||||
});
|
||||
});
|
||||
|
||||
it('supports checkAccessForContext() returning a promise', function() {
|
||||
|
@ -129,9 +129,9 @@ describe('security ACLs', function() {
|
|||
model: 'testModel',
|
||||
accessType: ACL.ALL,
|
||||
})
|
||||
.then(function(access) {
|
||||
assert(access.permission === ACL.ALLOW);
|
||||
});
|
||||
.then(function(access) {
|
||||
assert(access.permission === ACL.ALLOW);
|
||||
});
|
||||
});
|
||||
|
||||
it('should order ACL entries based on the matching score', function() {
|
||||
|
@ -256,34 +256,34 @@ describe('security ACLs', function() {
|
|||
accessType: ACL.EXECUTE, permission: ACL.ALLOW,
|
||||
}, function(err, acl) {
|
||||
ACL.checkPermission(ACL.USER, 'u001', 'testModel', 'name', ACL.READ,
|
||||
function(err, perm) {
|
||||
assert(perm.permission === ACL.ALLOW);
|
||||
});
|
||||
function(err, perm) {
|
||||
assert(perm.permission === ACL.ALLOW);
|
||||
});
|
||||
|
||||
ACL.checkPermission(ACL.USER, 'u001', 'testModel', ACL.ALL, ACL.READ,
|
||||
function(err, perm) {
|
||||
assert(perm.permission === ACL.ALLOW);
|
||||
});
|
||||
function(err, perm) {
|
||||
assert(perm.permission === ACL.ALLOW);
|
||||
});
|
||||
|
||||
ACL.checkPermission(ACL.USER, 'u001', 'testModel', 'name', ACL.WRITE,
|
||||
function(err, perm) {
|
||||
assert(perm.permission === ACL.DENY);
|
||||
});
|
||||
function(err, perm) {
|
||||
assert(perm.permission === ACL.DENY);
|
||||
});
|
||||
|
||||
ACL.checkPermission(ACL.USER, 'u001', 'testModel', 'name', ACL.ALL,
|
||||
function(err, perm) {
|
||||
assert(perm.permission === ACL.DENY);
|
||||
});
|
||||
function(err, perm) {
|
||||
assert(perm.permission === ACL.DENY);
|
||||
});
|
||||
|
||||
ACL.checkPermission(ACL.USER, 'u002', 'testModel', 'name', ACL.WRITE,
|
||||
function(err, perm) {
|
||||
assert(perm.permission === ACL.ALLOW);
|
||||
});
|
||||
function(err, perm) {
|
||||
assert(perm.permission === ACL.ALLOW);
|
||||
});
|
||||
|
||||
ACL.checkPermission(ACL.USER, 'u002', 'testModel', 'name', ACL.READ,
|
||||
function(err, perm) {
|
||||
assert(perm.permission === ACL.ALLOW);
|
||||
});
|
||||
function(err, perm) {
|
||||
assert(perm.permission === ACL.ALLOW);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -311,9 +311,9 @@ describe('security ACLs', function() {
|
|||
Customer.settings.defaultPermission = ACL.DENY;
|
||||
|
||||
ACL.checkPermission(ACL.USER, 'u001', 'Customer', 'name', ACL.WRITE,
|
||||
function(err, perm) {
|
||||
assert(perm.permission === ACL.DENY);
|
||||
});
|
||||
function(err, perm) {
|
||||
assert(perm.permission === ACL.DENY);
|
||||
});
|
||||
|
||||
ACL.checkPermission(ACL.USER, 'u001', 'Customer', 'name', ACL.READ, function(err, perm) {
|
||||
assert(perm.permission === ACL.ALLOW);
|
||||
|
@ -353,29 +353,29 @@ describe('security ACLs', function() {
|
|||
*/
|
||||
|
||||
ACL.checkPermission(ACL.USER, 'u001', 'Customer', 'name', ACL.WRITE,
|
||||
function(err, perm) {
|
||||
assert(perm.permission === ACL.DENY);
|
||||
});
|
||||
function(err, perm) {
|
||||
assert(perm.permission === ACL.DENY);
|
||||
});
|
||||
|
||||
ACL.checkPermission(ACL.USER, 'u001', 'Customer', 'name', ACL.READ,
|
||||
function(err, perm) {
|
||||
assert(perm.permission === ACL.ALLOW);
|
||||
});
|
||||
function(err, perm) {
|
||||
assert(perm.permission === ACL.ALLOW);
|
||||
});
|
||||
|
||||
ACL.checkPermission(ACL.USER, 'u001', 'Customer', 'name', ACL.ALL,
|
||||
function(err, perm) {
|
||||
assert(perm.permission === ACL.ALLOW);
|
||||
});
|
||||
function(err, perm) {
|
||||
assert(perm.permission === ACL.ALLOW);
|
||||
});
|
||||
|
||||
ACL.checkPermission(ACL.USER, 'u002', 'Customer', 'name', ACL.READ,
|
||||
function(err, perm) {
|
||||
assert(perm.permission === ACL.ALLOW);
|
||||
});
|
||||
function(err, perm) {
|
||||
assert(perm.permission === ACL.ALLOW);
|
||||
});
|
||||
|
||||
ACL.checkPermission(ACL.USER, 'u003', 'Customer', 'name', ACL.WRITE,
|
||||
function(err, perm) {
|
||||
assert(perm.permission === ACL.DENY);
|
||||
});
|
||||
function(err, perm) {
|
||||
assert(perm.permission === ACL.DENY);
|
||||
});
|
||||
});
|
||||
|
||||
it('should filter static ACLs by model/property', function() {
|
||||
|
@ -451,39 +451,39 @@ describe('security ACLs', function() {
|
|||
log('Role: ', myRole.toObject());
|
||||
|
||||
myRole.principals.create({principalType: RoleMapping.USER, principalId: userId},
|
||||
function(err, p) {
|
||||
log('Principal added to role: ', p.toObject());
|
||||
function(err, p) {
|
||||
log('Principal added to role: ', p.toObject());
|
||||
|
||||
ACL.create({
|
||||
principalType: ACL.ROLE, principalId: 'MyRole',
|
||||
model: 'Customer', property: ACL.ALL,
|
||||
accessType: ACL.READ, permission: ACL.DENY,
|
||||
}, function(err, acl) {
|
||||
log('ACL 2: ', acl.toObject());
|
||||
ACL.create({
|
||||
principalType: ACL.ROLE, principalId: 'MyRole',
|
||||
model: 'Customer', property: ACL.ALL,
|
||||
accessType: ACL.READ, permission: ACL.DENY,
|
||||
}, function(err, acl) {
|
||||
log('ACL 2: ', acl.toObject());
|
||||
|
||||
ACL.checkAccessForContext({
|
||||
principals: [
|
||||
{type: ACL.USER, id: userId},
|
||||
],
|
||||
model: 'Customer',
|
||||
property: 'name',
|
||||
accessType: ACL.READ,
|
||||
}, function(err, access) {
|
||||
assert(!err && access.permission === ACL.ALLOW);
|
||||
});
|
||||
ACL.checkAccessForContext({
|
||||
principals: [
|
||||
{type: ACL.USER, id: userId},
|
||||
],
|
||||
model: 'Customer',
|
||||
property: 'name',
|
||||
accessType: ACL.READ,
|
||||
}, function(err, access) {
|
||||
assert(!err && access.permission === ACL.ALLOW);
|
||||
});
|
||||
|
||||
ACL.checkAccessForContext({
|
||||
principals: [
|
||||
{type: ACL.ROLE, id: Role.EVERYONE},
|
||||
],
|
||||
model: 'Customer',
|
||||
property: 'name',
|
||||
accessType: ACL.READ,
|
||||
}, function(err, access) {
|
||||
assert(!err && access.permission === ACL.DENY);
|
||||
ACL.checkAccessForContext({
|
||||
principals: [
|
||||
{type: ACL.ROLE, id: Role.EVERYONE},
|
||||
],
|
||||
model: 'Customer',
|
||||
property: 'name',
|
||||
accessType: ACL.READ,
|
||||
}, function(err, access) {
|
||||
assert(!err && access.permission === ACL.DENY);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -543,35 +543,35 @@ describe('authorized roles propagation in RemotingContext', function() {
|
|||
{permission: ACL.ALLOW, principalId: '$authenticated'},
|
||||
{permission: ACL.ALLOW, principalId: 'myRole'},
|
||||
])
|
||||
.then(makeAuthorizedHttpRequestOnMyTestModel)
|
||||
.then(function() {
|
||||
var ctx = models.MyTestModel.lastRemotingContext;
|
||||
expect(ctx.args.options.authorizedRoles).to.eql(
|
||||
{
|
||||
$everyone: true,
|
||||
$authenticated: true,
|
||||
myRole: true,
|
||||
}
|
||||
);
|
||||
});
|
||||
.then(makeAuthorizedHttpRequestOnMyTestModel)
|
||||
.then(function() {
|
||||
var ctx = models.MyTestModel.lastRemotingContext;
|
||||
expect(ctx.args.options.authorizedRoles).to.eql(
|
||||
{
|
||||
$everyone: true,
|
||||
$authenticated: true,
|
||||
myRole: true,
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it('does not contain any denied role even if query is allowed', function() {
|
||||
return createACLs('MyTestModel', [
|
||||
{permission: ACL.ALLOW, principalId: '$everyone'},
|
||||
{permission: ACL.DENY, principalId: '$authenticated'},
|
||||
{permission: ACL.DENY, principalId: '$authenticated'},
|
||||
{permission: ACL.ALLOW, principalId: 'myRole'},
|
||||
])
|
||||
.then(makeAuthorizedHttpRequestOnMyTestModel)
|
||||
.then(function() {
|
||||
var ctx = models.MyTestModel.lastRemotingContext;
|
||||
expect(ctx.args.options.authorizedRoles).to.eql(
|
||||
{
|
||||
$everyone: true,
|
||||
myRole: true,
|
||||
}
|
||||
);
|
||||
});
|
||||
.then(makeAuthorizedHttpRequestOnMyTestModel)
|
||||
.then(function() {
|
||||
var ctx = models.MyTestModel.lastRemotingContext;
|
||||
expect(ctx.args.options.authorizedRoles).to.eql(
|
||||
{
|
||||
$everyone: true,
|
||||
myRole: true,
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it('honors default permission setting', function() {
|
||||
|
@ -580,17 +580,17 @@ describe('authorized roles propagation in RemotingContext', function() {
|
|||
|
||||
return createACLs('MyTestModel', [
|
||||
{permission: ACL.DEFAULT, principalId: '$everyone'},
|
||||
{permission: ACL.DENY, principalId: '$authenticated'},
|
||||
{permission: ACL.ALLOW, principalId: 'myRole'},
|
||||
{permission: ACL.DENY, principalId: '$authenticated'},
|
||||
{permission: ACL.ALLOW, principalId: 'myRole'},
|
||||
])
|
||||
.then(makeAuthorizedHttpRequestOnMyTestModel)
|
||||
.then(function() {
|
||||
var ctx = models.MyTestModel.lastRemotingContext;
|
||||
expect(ctx.args.options.authorizedRoles).to.eql(
|
||||
.then(makeAuthorizedHttpRequestOnMyTestModel)
|
||||
.then(function() {
|
||||
var ctx = models.MyTestModel.lastRemotingContext;
|
||||
expect(ctx.args.options.authorizedRoles).to.eql(
|
||||
// '$everyone' is not expected as default permission is DENY
|
||||
{myRole: true}
|
||||
);
|
||||
});
|
||||
{myRole: true}
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
// helpers
|
||||
|
@ -619,15 +619,15 @@ describe('authorized roles propagation in RemotingContext', function() {
|
|||
models.User.create({username: 'myUser', email: 'myuser@example.com', password: 'pass'}),
|
||||
models.Role.create({name: 'myRole'}),
|
||||
])
|
||||
.spread(function(myUser, myRole) {
|
||||
return Promise.all([
|
||||
myRole.principals.create({principalType: 'USER', principalId: myUser.id}),
|
||||
models.User.login({username: 'myUser', password: 'pass'}),
|
||||
]);
|
||||
})
|
||||
.spread(function(role, token) {
|
||||
accessToken = token;
|
||||
});
|
||||
.spread(function(myUser, myRole) {
|
||||
return Promise.all([
|
||||
myRole.principals.create({principalType: 'USER', principalId: myUser.id}),
|
||||
models.User.login({username: 'myUser', password: 'pass'}),
|
||||
]);
|
||||
})
|
||||
.spread(function(role, token) {
|
||||
accessToken = token;
|
||||
});
|
||||
}
|
||||
|
||||
function createACLs(model, acls) {
|
||||
|
|
|
@ -523,7 +523,7 @@ describe('app', function() {
|
|||
});
|
||||
});
|
||||
|
||||
it('scopes middleware to a list of scopes', function(done) {
|
||||
it('scopes middleware from config to a list of scopes', function(done) {
|
||||
var steps = [];
|
||||
app.middlewareFromConfig(
|
||||
function factory() {
|
||||
|
|
|
@ -157,12 +157,12 @@ describe('Change', function() {
|
|||
beforeEach(function(done) {
|
||||
var test = this;
|
||||
Change.findOrCreateChange(this.modelName, this.modelId)
|
||||
.then(function(result) {
|
||||
test.result = result;
|
||||
.then(function(result) {
|
||||
test.result = result;
|
||||
|
||||
done();
|
||||
})
|
||||
.catch(done);
|
||||
done();
|
||||
})
|
||||
.catch(done);
|
||||
});
|
||||
|
||||
it('should create an entry', function(done) {
|
||||
|
@ -352,12 +352,12 @@ describe('Change', function() {
|
|||
});
|
||||
|
||||
change.currentRevision()
|
||||
.then(function(rev) {
|
||||
assert.equal(rev, test.revisionForModel);
|
||||
.then(function(rev) {
|
||||
assert.equal(rev, test.revisionForModel);
|
||||
|
||||
done();
|
||||
})
|
||||
.catch(done);
|
||||
done();
|
||||
})
|
||||
.catch(done);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -78,13 +78,13 @@ describe('Checkpoint', function() {
|
|||
});
|
||||
|
||||
it('Checkpoint.current() for non existing checkpoint should initialize checkpoint',
|
||||
function(done) {
|
||||
Checkpoint.current(function(err, seq) {
|
||||
expect(seq).to.equal(1);
|
||||
function(done) {
|
||||
Checkpoint.current(function(err, seq) {
|
||||
expect(seq).to.equal(1);
|
||||
|
||||
done(err);
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('bumpLastSeq() works when singleton instance does not exists yet', function(done) {
|
||||
Checkpoint.bumpLastSeq(function(err, cp) {
|
||||
|
|
|
@ -44,17 +44,17 @@ describe('hidden properties', function() {
|
|||
|
||||
it('should hide a property remotely', function(done) {
|
||||
request(this.app)
|
||||
.get('/products')
|
||||
.expect('Content-Type', /json/)
|
||||
.expect(200)
|
||||
.end(function(err, res) {
|
||||
if (err) return done(err);
|
||||
.get('/products')
|
||||
.expect('Content-Type', /json/)
|
||||
.expect(200)
|
||||
.end(function(err, res) {
|
||||
if (err) return done(err);
|
||||
|
||||
var product = res.body[0];
|
||||
assert.equal(product.secret, undefined);
|
||||
var product = res.body[0];
|
||||
assert.equal(product.secret, undefined);
|
||||
|
||||
done();
|
||||
});
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should hide a property of nested models', function(done) {
|
||||
|
|
|
@ -58,23 +58,23 @@ describe('KeyValueModel', function() {
|
|||
});
|
||||
|
||||
it('provides "expire(key, ttl)" at "PUT /key/expire"',
|
||||
function(done) {
|
||||
CacheItem.set('expire-key', AN_OBJECT_VALUE, function(err) {
|
||||
if (err) return done(err);
|
||||
request.put('/CacheItems/expire-key/expire')
|
||||
.send({ttl: 10})
|
||||
.end(function(err, res) {
|
||||
if (err) return done(err);
|
||||
setTimeout(function() {
|
||||
CacheItem.get('set-key-ttl', function(err, value) {
|
||||
if (err) return done(err);
|
||||
expect(value).to.equal(null);
|
||||
done();
|
||||
});
|
||||
}, 20);
|
||||
});
|
||||
function(done) {
|
||||
CacheItem.set('expire-key', AN_OBJECT_VALUE, function(err) {
|
||||
if (err) return done(err);
|
||||
request.put('/CacheItems/expire-key/expire')
|
||||
.send({ttl: 10})
|
||||
.end(function(err, res) {
|
||||
if (err) return done(err);
|
||||
setTimeout(function() {
|
||||
CacheItem.get('set-key-ttl', function(err, value) {
|
||||
if (err) return done(err);
|
||||
expect(value).to.equal(null);
|
||||
done();
|
||||
});
|
||||
}, 20);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('returns 404 when expiring a key that does not exist', function(done) {
|
||||
request.put('/CacheItems/key-does-not-exist/expire')
|
||||
|
@ -96,32 +96,32 @@ describe('KeyValueModel', function() {
|
|||
});
|
||||
|
||||
it('returns 204 when getting TTL for a key that does not have TTL set',
|
||||
function(done) {
|
||||
request.put('/CacheItems/ttl-key')
|
||||
.end(function(err, res) {
|
||||
if (err) return done(err);
|
||||
request.get('/CacheItems/ttl-key/ttl')
|
||||
.expect(204, done);
|
||||
});
|
||||
});
|
||||
|
||||
it('returns 404 when getting TTL for a key when TTL has expired',
|
||||
function(done) {
|
||||
request.put('/CacheItems/ttl-key?ttl=10')
|
||||
.end(function(err, res) {
|
||||
setTimeout(function() {
|
||||
function(done) {
|
||||
request.put('/CacheItems/ttl-key')
|
||||
.end(function(err, res) {
|
||||
if (err) return done(err);
|
||||
request.get('/CacheItems/ttl-key/ttl')
|
||||
.expect(404, done);
|
||||
}, 20);
|
||||
});
|
||||
});
|
||||
.expect(204, done);
|
||||
});
|
||||
});
|
||||
|
||||
it('returns 404 when getting TTL for a key when TTL has expired',
|
||||
function(done) {
|
||||
request.put('/CacheItems/ttl-key?ttl=10')
|
||||
.end(function(err, res) {
|
||||
setTimeout(function() {
|
||||
if (err) return done(err);
|
||||
request.get('/CacheItems/ttl-key/ttl')
|
||||
.expect(404, done);
|
||||
}, 20);
|
||||
});
|
||||
});
|
||||
|
||||
it('returns 404 when getting TTL for a key that does not exist',
|
||||
function(done) {
|
||||
request.get('/CacheItems/key-does-not-exist/ttl')
|
||||
.expect(404, done);
|
||||
});
|
||||
function(done) {
|
||||
request.get('/CacheItems/key-does-not-exist/ttl')
|
||||
.expect(404, done);
|
||||
});
|
||||
|
||||
it('provides "keys(filter)" at "GET /keys"', function(done) {
|
||||
CacheItem.set('list-key', AN_OBJECT_VALUE, function(err) {
|
||||
|
|
|
@ -15,7 +15,7 @@ describe('Application', function() {
|
|||
Application.attachTo(loopback.memory());
|
||||
});
|
||||
|
||||
it('honors `application.register` - promise variant', function(done) {
|
||||
it('honors `application.register` - callback variant', function(done) {
|
||||
Application.register('rfeng', 'MyTestApp',
|
||||
{description: 'My test application'}, function(err, result) {
|
||||
var app = result;
|
||||
|
@ -89,31 +89,31 @@ describe('Application', function() {
|
|||
serverApiKey: 'serverKey',
|
||||
},
|
||||
}},
|
||||
function(err, result) {
|
||||
var app = result;
|
||||
assert.deepEqual(app.pushSettings.toObject(), {
|
||||
apns: {
|
||||
production: false,
|
||||
certData: 'cert',
|
||||
keyData: 'key',
|
||||
pushOptions: {
|
||||
gateway: 'gateway.sandbox.push.apple.com',
|
||||
port: 2195,
|
||||
},
|
||||
feedbackOptions: {
|
||||
gateway: 'feedback.sandbox.push.apple.com',
|
||||
port: 2196,
|
||||
interval: 300,
|
||||
batchFeedback: true,
|
||||
},
|
||||
function(err, result) {
|
||||
var app = result;
|
||||
assert.deepEqual(app.pushSettings.toObject(), {
|
||||
apns: {
|
||||
production: false,
|
||||
certData: 'cert',
|
||||
keyData: 'key',
|
||||
pushOptions: {
|
||||
gateway: 'gateway.sandbox.push.apple.com',
|
||||
port: 2195,
|
||||
},
|
||||
gcm: {
|
||||
serverApiKey: 'serverKey',
|
||||
feedbackOptions: {
|
||||
gateway: 'feedback.sandbox.push.apple.com',
|
||||
port: 2196,
|
||||
interval: 300,
|
||||
batchFeedback: true,
|
||||
},
|
||||
});
|
||||
|
||||
done(err, result);
|
||||
},
|
||||
gcm: {
|
||||
serverApiKey: 'serverKey',
|
||||
},
|
||||
});
|
||||
|
||||
done(err, result);
|
||||
});
|
||||
});
|
||||
|
||||
beforeEach(function(done) {
|
||||
|
@ -164,32 +164,32 @@ describe('Application', function() {
|
|||
|
||||
it('Reset keys - promise variant', function(done) {
|
||||
Application.resetKeys(registeredApp.id)
|
||||
.then(function(result) {
|
||||
var app = result;
|
||||
assert.equal(app.owner, 'rfeng');
|
||||
assert.equal(app.name, 'MyApp2');
|
||||
assert.equal(app.description, 'My second mobile application');
|
||||
assert(app.clientKey);
|
||||
assert(app.javaScriptKey);
|
||||
assert(app.restApiKey);
|
||||
assert(app.windowsKey);
|
||||
assert(app.masterKey);
|
||||
.then(function(result) {
|
||||
var app = result;
|
||||
assert.equal(app.owner, 'rfeng');
|
||||
assert.equal(app.name, 'MyApp2');
|
||||
assert.equal(app.description, 'My second mobile application');
|
||||
assert(app.clientKey);
|
||||
assert(app.javaScriptKey);
|
||||
assert(app.restApiKey);
|
||||
assert(app.windowsKey);
|
||||
assert(app.masterKey);
|
||||
|
||||
assert(app.clientKey !== registeredApp.clientKey);
|
||||
assert(app.javaScriptKey !== registeredApp.javaScriptKey);
|
||||
assert(app.restApiKey !== registeredApp.restApiKey);
|
||||
assert(app.windowsKey !== registeredApp.windowsKey);
|
||||
assert(app.masterKey !== registeredApp.masterKey);
|
||||
assert(app.clientKey !== registeredApp.clientKey);
|
||||
assert(app.javaScriptKey !== registeredApp.javaScriptKey);
|
||||
assert(app.restApiKey !== registeredApp.restApiKey);
|
||||
assert(app.windowsKey !== registeredApp.windowsKey);
|
||||
assert(app.masterKey !== registeredApp.masterKey);
|
||||
|
||||
assert(app.created);
|
||||
assert(app.modified);
|
||||
registeredApp = app;
|
||||
assert(app.created);
|
||||
assert(app.modified);
|
||||
registeredApp = app;
|
||||
|
||||
done();
|
||||
})
|
||||
.catch(function(err) {
|
||||
done(err);
|
||||
});
|
||||
done();
|
||||
})
|
||||
.catch(function(err) {
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
|
||||
it('Reset keys without create a new instance', function(done) {
|
||||
|
@ -205,17 +205,17 @@ describe('Application', function() {
|
|||
|
||||
it('Reset keys without create a new instance - promise variant', function(done) {
|
||||
Application.resetKeys(registeredApp.id)
|
||||
.then(function(result) {
|
||||
var app = result;
|
||||
assert(app.id);
|
||||
assert(app.id === registeredApp.id);
|
||||
registeredApp = app;
|
||||
.then(function(result) {
|
||||
var app = result;
|
||||
assert(app.id);
|
||||
assert(app.id === registeredApp.id);
|
||||
registeredApp = app;
|
||||
|
||||
done();
|
||||
})
|
||||
.catch(function(err) {
|
||||
done(err);
|
||||
});
|
||||
done();
|
||||
})
|
||||
.catch(function(err) {
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
|
||||
it('Authenticate with application id & clientKey', function(done) {
|
||||
|
@ -231,15 +231,15 @@ describe('Application', function() {
|
|||
it('Authenticate with application id & clientKey - promise variant',
|
||||
function(done) {
|
||||
Application.authenticate(registeredApp.id, registeredApp.clientKey)
|
||||
.then(function(result) {
|
||||
assert.equal(result.application.id, registeredApp.id);
|
||||
assert.equal(result.keyType, 'clientKey');
|
||||
.then(function(result) {
|
||||
assert.equal(result.application.id, registeredApp.id);
|
||||
assert.equal(result.keyType, 'clientKey');
|
||||
|
||||
done();
|
||||
})
|
||||
.catch(function(err) {
|
||||
done(err);
|
||||
});
|
||||
done();
|
||||
})
|
||||
.catch(function(err) {
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
|
||||
it('Authenticate with application id & javaScriptKey', function(done) {
|
||||
|
@ -293,15 +293,15 @@ describe('Application', function() {
|
|||
|
||||
it('Fail to authenticate with application id - promise variant', function(done) {
|
||||
Application.authenticate(registeredApp.id, 'invalid-key')
|
||||
.then(function(result) {
|
||||
assert(!result);
|
||||
.then(function(result) {
|
||||
assert(!result);
|
||||
|
||||
done();
|
||||
})
|
||||
.catch(function(err) {
|
||||
done(err);
|
||||
throw new Error('Error should NOT be thrown');
|
||||
});
|
||||
done();
|
||||
})
|
||||
.catch(function(err) {
|
||||
done(err);
|
||||
throw new Error('Error should NOT be thrown');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -68,15 +68,15 @@ describe('Multiple users with custom principalType', function() {
|
|||
AnotherUser.create(commonCredentials),
|
||||
Role.create({name: 'userRole'}),
|
||||
])
|
||||
.spread(function(u1, u2, r) {
|
||||
userFromOneModel = u1;
|
||||
userFromAnotherModel = u2;
|
||||
userRole = r;
|
||||
userOneBaseContext = {
|
||||
principalType: OneUser.modelName,
|
||||
principalId: userFromOneModel.id,
|
||||
};
|
||||
});
|
||||
.spread(function(u1, u2, r) {
|
||||
userFromOneModel = u1;
|
||||
userFromAnotherModel = u2;
|
||||
userRole = r;
|
||||
userOneBaseContext = {
|
||||
principalType: OneUser.modelName,
|
||||
principalId: userFromOneModel.id,
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
describe('User.login', function() {
|
||||
|
@ -118,29 +118,29 @@ describe('Multiple users with custom principalType', function() {
|
|||
|
||||
describe('User.logout', function() {
|
||||
it('logs out a user from user model 1 without logging out user from model 2',
|
||||
function() {
|
||||
var tokenOfOneUser;
|
||||
return Promise.all([
|
||||
OneUser.login(commonCredentials),
|
||||
AnotherUser.login(commonCredentials),
|
||||
])
|
||||
.spread(function(t1, t2) {
|
||||
tokenOfOneUser = t1;
|
||||
return OneUser.logout(tokenOfOneUser.id);
|
||||
})
|
||||
.then(function() {
|
||||
return AccessToken.find({});
|
||||
})
|
||||
.then(function(allTokens) {
|
||||
var data = allTokens.map(function(token) {
|
||||
return {userId: token.userId, principalType: token.principalType};
|
||||
});
|
||||
expect(data).to.eql([
|
||||
// no token for userFromAnotherModel
|
||||
{userId: userFromAnotherModel.id, principalType: 'AnotherUser'},
|
||||
]);
|
||||
function() {
|
||||
var tokenOfOneUser;
|
||||
return Promise.all([
|
||||
OneUser.login(commonCredentials),
|
||||
AnotherUser.login(commonCredentials),
|
||||
])
|
||||
.spread(function(t1, t2) {
|
||||
tokenOfOneUser = t1;
|
||||
return OneUser.logout(tokenOfOneUser.id);
|
||||
})
|
||||
.then(function() {
|
||||
return AccessToken.find({});
|
||||
})
|
||||
.then(function(allTokens) {
|
||||
var data = allTokens.map(function(token) {
|
||||
return {userId: token.userId, principalType: token.principalType};
|
||||
});
|
||||
expect(data).to.eql([
|
||||
// no token for userFromAnotherModel
|
||||
{userId: userFromAnotherModel.id, principalType: 'AnotherUser'},
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Password Reset', function() {
|
||||
|
@ -151,23 +151,23 @@ describe('Multiple users with custom principalType', function() {
|
|||
};
|
||||
|
||||
it('creates a temp accessToken to allow a user to change password',
|
||||
function() {
|
||||
return Promise.all([
|
||||
OneUser.resetPassword({email: options.email}),
|
||||
waitForResetRequestAndVerify,
|
||||
]);
|
||||
});
|
||||
function() {
|
||||
return Promise.all([
|
||||
OneUser.resetPassword({email: options.email}),
|
||||
waitForResetRequestAndVerify,
|
||||
]);
|
||||
});
|
||||
|
||||
function waitForResetRequestAndVerify() {
|
||||
return waitForEvent(OneUser, 'resetPasswordRequest')
|
||||
.then(function(info) {
|
||||
assertGoodToken(info.accessToken, userFromOneModel);
|
||||
return info.accessToken.user.getAsync();
|
||||
})
|
||||
.then(function(user) {
|
||||
expect(user).to.have.property('id', userFromOneModel.id);
|
||||
expect(user).to.have.property('email', userFromOneModel.email);
|
||||
});
|
||||
.then(function(info) {
|
||||
assertGoodToken(info.accessToken, userFromOneModel);
|
||||
return info.accessToken.user.getAsync();
|
||||
})
|
||||
.then(function(user) {
|
||||
expect(user).to.have.property('id', userFromOneModel.id);
|
||||
expect(user).to.have.property('email', userFromOneModel.email);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
@ -214,51 +214,51 @@ describe('Multiple users with custom principalType', function() {
|
|||
|
||||
describe('getUser()', function() {
|
||||
it('returns user although principals contain non USER principals',
|
||||
function() {
|
||||
return Promise.try(function() {
|
||||
addToAccessContext([
|
||||
{type: Principal.ROLE},
|
||||
{type: Principal.APP},
|
||||
{type: Principal.SCOPE},
|
||||
{type: OneUser.modelName, id: userFromOneModel.id},
|
||||
]);
|
||||
var user = accessContext.getUser();
|
||||
expect(user).to.eql({
|
||||
id: userFromOneModel.id,
|
||||
principalType: OneUser.modelName,
|
||||
function() {
|
||||
return Promise.try(function() {
|
||||
addToAccessContext([
|
||||
{type: Principal.ROLE},
|
||||
{type: Principal.APP},
|
||||
{type: Principal.SCOPE},
|
||||
{type: OneUser.modelName, id: userFromOneModel.id},
|
||||
]);
|
||||
var user = accessContext.getUser();
|
||||
expect(user).to.eql({
|
||||
id: userFromOneModel.id,
|
||||
principalType: OneUser.modelName,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('returns user although principals contain invalid principals',
|
||||
function() {
|
||||
return Promise.try(function() {
|
||||
addToAccessContext([
|
||||
{type: 'AccessToken'},
|
||||
{type: 'invalidModelName'},
|
||||
{type: OneUser.modelName, id: userFromOneModel.id},
|
||||
]);
|
||||
var user = accessContext.getUser();
|
||||
expect(user).to.eql({
|
||||
id: userFromOneModel.id,
|
||||
principalType: OneUser.modelName,
|
||||
function() {
|
||||
return Promise.try(function() {
|
||||
addToAccessContext([
|
||||
{type: 'AccessToken'},
|
||||
{type: 'invalidModelName'},
|
||||
{type: OneUser.modelName, id: userFromOneModel.id},
|
||||
]);
|
||||
var user = accessContext.getUser();
|
||||
expect(user).to.eql({
|
||||
id: userFromOneModel.id,
|
||||
principalType: OneUser.modelName,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('supports any level of built-in User model inheritance',
|
||||
function() {
|
||||
ThirdUser = createUserModel(app, 'ThirdUser', {base: 'OneUser'});
|
||||
return ThirdUser.create(commonCredentials)
|
||||
.then(function(userFromThirdModel) {
|
||||
accessContext.addPrincipal(ThirdUser.modelName, userFromThirdModel.id);
|
||||
var user = accessContext.getUser();
|
||||
expect(user).to.eql({
|
||||
id: userFromThirdModel.id,
|
||||
principalType: ThirdUser.modelName,
|
||||
});
|
||||
function() {
|
||||
ThirdUser = createUserModel(app, 'ThirdUser', {base: 'OneUser'});
|
||||
return ThirdUser.create(commonCredentials)
|
||||
.then(function(userFromThirdModel) {
|
||||
accessContext.addPrincipal(ThirdUser.modelName, userFromThirdModel.id);
|
||||
var user = accessContext.getUser();
|
||||
expect(user).to.eql({
|
||||
id: userFromThirdModel.id,
|
||||
principalType: ThirdUser.modelName,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// helper
|
||||
|
@ -347,7 +347,7 @@ describe('Multiple users with custom principalType', function() {
|
|||
|
||||
it('supports getRoles()', function() {
|
||||
return Role.getRoles(
|
||||
userOneBaseContext)
|
||||
userOneBaseContext)
|
||||
.then(function(roles) {
|
||||
expect(roles).to.eql([
|
||||
Role.AUTHENTICATED,
|
||||
|
@ -390,18 +390,18 @@ describe('Multiple users with custom principalType', function() {
|
|||
app.model(Album, {dataSource: 'db'});
|
||||
|
||||
return Album.create({name: 'album', userId: userFromOneModel.id})
|
||||
.then(function(album) {
|
||||
var validContext = {
|
||||
principalType: OneUser.modelName,
|
||||
principalId: userFromOneModel.id,
|
||||
model: Album,
|
||||
id: album.id,
|
||||
};
|
||||
return Role.isInRole(Role.OWNER, validContext);
|
||||
})
|
||||
.then(function(isOwner) {
|
||||
expect(isOwner).to.be.true();
|
||||
});
|
||||
.then(function(album) {
|
||||
var validContext = {
|
||||
principalType: OneUser.modelName,
|
||||
principalId: userFromOneModel.id,
|
||||
model: Album,
|
||||
id: album.id,
|
||||
};
|
||||
return Role.isInRole(Role.OWNER, validContext);
|
||||
})
|
||||
.then(function(isOwner) {
|
||||
expect(isOwner).to.be.true();
|
||||
});
|
||||
});
|
||||
|
||||
// With multiple users config, we cannot resolve a user based just on
|
||||
|
@ -419,18 +419,18 @@ describe('Multiple users with custom principalType', function() {
|
|||
userId: userFromOneModel.id,
|
||||
owner: userFromOneModel.id,
|
||||
})
|
||||
.then(function(album) {
|
||||
var authContext = {
|
||||
principalType: OneUser.modelName,
|
||||
principalId: userFromOneModel.id,
|
||||
model: Album,
|
||||
id: album.id,
|
||||
};
|
||||
return Role.isInRole(Role.OWNER, authContext);
|
||||
})
|
||||
.then(function(isOwner) {
|
||||
expect(isOwner).to.be.false();
|
||||
});
|
||||
.then(function(album) {
|
||||
var authContext = {
|
||||
principalType: OneUser.modelName,
|
||||
principalId: userFromOneModel.id,
|
||||
model: Album,
|
||||
id: album.id,
|
||||
};
|
||||
return Role.isInRole(Role.OWNER, authContext);
|
||||
})
|
||||
.then(function(isOwner) {
|
||||
expect(isOwner).to.be.false();
|
||||
});
|
||||
});
|
||||
|
||||
it('legacy behavior resolves false if owner has incorrect principalType', function() {
|
||||
|
@ -449,106 +449,106 @@ describe('Multiple users with custom principalType', function() {
|
|||
app.model(Album, {dataSource: 'db'});
|
||||
|
||||
return Album.create({name: 'album', userId: userFromOneModel.id})
|
||||
.then(function(album) {
|
||||
var invalidPrincipalTypes = [
|
||||
'invalidContextName',
|
||||
'USER',
|
||||
AnotherUser.modelName,
|
||||
];
|
||||
var invalidContexts = invalidPrincipalTypes.map(principalType => {
|
||||
return {
|
||||
principalType,
|
||||
principalId: userFromOneModel.id,
|
||||
model: Album,
|
||||
id: album.id,
|
||||
};
|
||||
.then(function(album) {
|
||||
var invalidPrincipalTypes = [
|
||||
'invalidContextName',
|
||||
'USER',
|
||||
AnotherUser.modelName,
|
||||
];
|
||||
var invalidContexts = invalidPrincipalTypes.map(principalType => {
|
||||
return {
|
||||
principalType,
|
||||
principalId: userFromOneModel.id,
|
||||
model: Album,
|
||||
id: album.id,
|
||||
};
|
||||
});
|
||||
return Promise.map(invalidContexts, context => {
|
||||
return Role.isInRole(Role.OWNER, context)
|
||||
.then(isOwner => {
|
||||
return {
|
||||
principalType: context.principalType,
|
||||
isOwner,
|
||||
};
|
||||
});
|
||||
});
|
||||
})
|
||||
.then(result => {
|
||||
expect(result).to.eql([
|
||||
{principalType: 'invalidContextName', isOwner: false},
|
||||
{principalType: 'USER', isOwner: false},
|
||||
{principalType: AnotherUser.modelName, isOwner: false},
|
||||
]);
|
||||
});
|
||||
return Promise.map(invalidContexts, context => {
|
||||
return Role.isInRole(Role.OWNER, context)
|
||||
.then(isOwner => {
|
||||
return {
|
||||
principalType: context.principalType,
|
||||
isOwner,
|
||||
};
|
||||
});
|
||||
});
|
||||
})
|
||||
.then(result => {
|
||||
expect(result).to.eql([
|
||||
{principalType: 'invalidContextName', isOwner: false},
|
||||
{principalType: 'USER', isOwner: false},
|
||||
{principalType: AnotherUser.modelName, isOwner: false},
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
it.skip('resolves the owner using the corrent belongsTo relation',
|
||||
function() {
|
||||
function() {
|
||||
// passing {ownerRelations: true} will enable the new $owner role resolver
|
||||
// with any belongsTo relation allowing to resolve truthy
|
||||
var Message = createModelWithOptions(
|
||||
'ModelWithAllRelations',
|
||||
{ownerRelations: true}
|
||||
);
|
||||
var Message = createModelWithOptions(
|
||||
'ModelWithAllRelations',
|
||||
{ownerRelations: true}
|
||||
);
|
||||
|
||||
var messages = [
|
||||
{content: 'firstMessage', customerId: userFromOneModel.id},
|
||||
{
|
||||
content: 'secondMessage',
|
||||
customerId: userFromOneModel.id,
|
||||
shopKeeperId: userFromAnotherModel.id,
|
||||
},
|
||||
var messages = [
|
||||
{content: 'firstMessage', customerId: userFromOneModel.id},
|
||||
{
|
||||
content: 'secondMessage',
|
||||
customerId: userFromOneModel.id,
|
||||
shopKeeperId: userFromAnotherModel.id,
|
||||
},
|
||||
|
||||
// this is the incriminated message where two foreignKeys have the
|
||||
// same id but points towards two different user models. Although
|
||||
// customers should come from userFromOneModel and shopKeeperIds should
|
||||
// come from userFromAnotherModel. The inverted situation still resolves
|
||||
// isOwner true for both the customer and the shopKeeper
|
||||
{
|
||||
content: 'thirdMessage',
|
||||
customerId: userFromAnotherModel.id,
|
||||
shopKeeperId: userFromOneModel.id,
|
||||
},
|
||||
// this is the incriminated message where two foreignKeys have the
|
||||
// same id but points towards two different user models. Although
|
||||
// customers should come from userFromOneModel and shopKeeperIds should
|
||||
// come from userFromAnotherModel. The inverted situation still resolves
|
||||
// isOwner true for both the customer and the shopKeeper
|
||||
{
|
||||
content: 'thirdMessage',
|
||||
customerId: userFromAnotherModel.id,
|
||||
shopKeeperId: userFromOneModel.id,
|
||||
},
|
||||
|
||||
{content: 'fourthMessage', customerId: userFromAnotherModel.id},
|
||||
{content: 'fifthMessage'},
|
||||
];
|
||||
return Promise.map(messages, msg => {
|
||||
return Message.create(msg);
|
||||
})
|
||||
.then(messages => {
|
||||
return Promise.all([
|
||||
isOwnerForMessage(userFromOneModel, messages[0]),
|
||||
isOwnerForMessage(userFromAnotherModel, messages[0]),
|
||||
isOwnerForMessage(userFromOneModel, messages[1]),
|
||||
isOwnerForMessage(userFromAnotherModel, messages[1]),
|
||||
{content: 'fourthMessage', customerId: userFromAnotherModel.id},
|
||||
{content: 'fifthMessage'},
|
||||
];
|
||||
return Promise.map(messages, msg => {
|
||||
return Message.create(msg);
|
||||
})
|
||||
.then(messages => {
|
||||
return Promise.all([
|
||||
isOwnerForMessage(userFromOneModel, messages[0]),
|
||||
isOwnerForMessage(userFromAnotherModel, messages[0]),
|
||||
isOwnerForMessage(userFromOneModel, messages[1]),
|
||||
isOwnerForMessage(userFromAnotherModel, messages[1]),
|
||||
|
||||
isOwnerForMessage(userFromOneModel, messages[2]),
|
||||
isOwnerForMessage(userFromAnotherModel, messages[2]),
|
||||
isOwnerForMessage(userFromOneModel, messages[2]),
|
||||
isOwnerForMessage(userFromAnotherModel, messages[2]),
|
||||
|
||||
isOwnerForMessage(userFromAnotherModel, messages[3]),
|
||||
isOwnerForMessage(userFromOneModel, messages[4]),
|
||||
]);
|
||||
})
|
||||
.then(result => {
|
||||
expect(result).to.eql([
|
||||
{userFrom: 'OneUser', msg: 'firstMessage', isOwner: true},
|
||||
{userFrom: 'AnotherUser', msg: 'firstMessage', isOwner: false},
|
||||
{userFrom: 'OneUser', msg: 'secondMessage', isOwner: true},
|
||||
{userFrom: 'AnotherUser', msg: 'secondMessage', isOwner: true},
|
||||
isOwnerForMessage(userFromAnotherModel, messages[3]),
|
||||
isOwnerForMessage(userFromOneModel, messages[4]),
|
||||
]);
|
||||
})
|
||||
.then(result => {
|
||||
expect(result).to.eql([
|
||||
{userFrom: 'OneUser', msg: 'firstMessage', isOwner: true},
|
||||
{userFrom: 'AnotherUser', msg: 'firstMessage', isOwner: false},
|
||||
{userFrom: 'OneUser', msg: 'secondMessage', isOwner: true},
|
||||
{userFrom: 'AnotherUser', msg: 'secondMessage', isOwner: true},
|
||||
|
||||
// these 2 tests fail because we cannot resolve ownership with
|
||||
// multiple owners on a single model instance with a classic
|
||||
// belongsTo relation, we need to use belongsTo with polymorphic
|
||||
// discriminator to distinguish between the 2 models
|
||||
{userFrom: 'OneUser', msg: 'thirdMessage', isOwner: false},
|
||||
{userFrom: 'AnotherUser', msg: 'thirdMessage', isOwner: false},
|
||||
// these 2 tests fail because we cannot resolve ownership with
|
||||
// multiple owners on a single model instance with a classic
|
||||
// belongsTo relation, we need to use belongsTo with polymorphic
|
||||
// discriminator to distinguish between the 2 models
|
||||
{userFrom: 'OneUser', msg: 'thirdMessage', isOwner: false},
|
||||
{userFrom: 'AnotherUser', msg: 'thirdMessage', isOwner: false},
|
||||
|
||||
{userFrom: 'AnotherUser', msg: 'fourthMessage', isOwner: false},
|
||||
{userFrom: 'OneUser', msg: 'fifthMessage', isOwner: false},
|
||||
]);
|
||||
{userFrom: 'AnotherUser', msg: 'fourthMessage', isOwner: false},
|
||||
{userFrom: 'OneUser', msg: 'fifthMessage', isOwner: false},
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// helpers
|
||||
|
@ -608,26 +608,26 @@ describe('Multiple users with custom principalType', function() {
|
|||
});
|
||||
|
||||
it('throws error with code \'INVALID_PRINCIPAL_TYPE\' when principalType is incorrect',
|
||||
function() {
|
||||
return ACL.resolvePrincipal('incorrectPrincipalType', userFromOneModel.id)
|
||||
.then(
|
||||
function onSuccess() {
|
||||
throw new Error('ACL.resolvePrincipal() should have failed');
|
||||
},
|
||||
function onError(err) {
|
||||
expect(err).to.have.property('statusCode', 400);
|
||||
expect(err).to.have.property('code', 'INVALID_PRINCIPAL_TYPE');
|
||||
}
|
||||
);
|
||||
});
|
||||
function() {
|
||||
return ACL.resolvePrincipal('incorrectPrincipalType', userFromOneModel.id)
|
||||
.then(
|
||||
function onSuccess() {
|
||||
throw new Error('ACL.resolvePrincipal() should have failed');
|
||||
},
|
||||
function onError(err) {
|
||||
expect(err).to.have.property('statusCode', 400);
|
||||
expect(err).to.have.property('code', 'INVALID_PRINCIPAL_TYPE');
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('reports isMappedToRole by user.username using custom user principalType',
|
||||
function() {
|
||||
return ACL.isMappedToRole(OneUser.modelName, userFromOneModel.username, 'userRole')
|
||||
.then(function(isMappedToRole) {
|
||||
expect(isMappedToRole).to.be.true();
|
||||
});
|
||||
});
|
||||
function() {
|
||||
return ACL.isMappedToRole(OneUser.modelName, userFromOneModel.username, 'userRole')
|
||||
.then(function(isMappedToRole) {
|
||||
expect(isMappedToRole).to.be.true();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -669,7 +669,7 @@ describe('Multiple users with custom principalType', function() {
|
|||
OneUser.resetPassword({email: commonCredentials.email}),
|
||||
waitForEvent(OneUser, 'resetPasswordRequest'),
|
||||
])
|
||||
.spread((reset, info) => resetToken = info.accessToken);
|
||||
.spread((reset, info) => resetToken = info.accessToken);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -63,15 +63,15 @@ describe('relations - integration', function() {
|
|||
|
||||
test.team = team;
|
||||
app.models.Reader.create({name: 'Reader 1'},
|
||||
function(err, reader) {
|
||||
if (err) return done(err);
|
||||
function(err, reader) {
|
||||
if (err) return done(err);
|
||||
|
||||
test.reader = reader;
|
||||
reader.pictures.create({name: 'Picture 1'});
|
||||
reader.pictures.create({name: 'Picture 2'});
|
||||
reader.team(test.team);
|
||||
reader.save(done);
|
||||
});
|
||||
test.reader = reader;
|
||||
reader.pictures.create({name: 'Picture 1'});
|
||||
reader.pictures.create({name: 'Picture 2'});
|
||||
reader.team(test.team);
|
||||
reader.save(done);
|
||||
});
|
||||
}
|
||||
);
|
||||
});
|
||||
|
@ -157,9 +157,9 @@ describe('relations - integration', function() {
|
|||
beforeEach(function() {
|
||||
debug('GET /api/stores/:id/widgets response: %s' +
|
||||
'\nheaders: %j\nbody string: %s',
|
||||
this.res.statusCode,
|
||||
this.res.headers,
|
||||
this.res.text);
|
||||
this.res.statusCode,
|
||||
this.res.headers,
|
||||
this.res.text);
|
||||
this.widgets = this.res.body;
|
||||
this.widget = this.res.body && this.res.body[0];
|
||||
});
|
||||
|
@ -661,8 +661,8 @@ describe('relations - integration', function() {
|
|||
this.app.remotes()._typeRegistry._options.warnWhenOverridingType = false;
|
||||
|
||||
var product = app.registry.createModel(
|
||||
'product',
|
||||
{id: 'string', name: 'string'}
|
||||
'product',
|
||||
{id: 'string', name: 'string'}
|
||||
);
|
||||
var category = app.registry.createModel(
|
||||
'category',
|
||||
|
@ -996,7 +996,7 @@ describe('relations - integration', function() {
|
|||
});
|
||||
});
|
||||
|
||||
it('returns the embedded models', function(done) {
|
||||
it('includes the created embedded model', function(done) {
|
||||
var url = '/api/todo-lists/' + this.todoList.id + '/items';
|
||||
|
||||
this.get(url)
|
||||
|
@ -1096,7 +1096,7 @@ describe('relations - integration', function() {
|
|||
|
||||
var ingredient = app.registry.createModel(
|
||||
'ingredient',
|
||||
{name: 'string'}
|
||||
{name: 'string'}
|
||||
);
|
||||
app.model(ingredient, {dataSource: 'db'});
|
||||
|
||||
|
@ -1311,7 +1311,7 @@ describe('relations - integration', function() {
|
|||
});
|
||||
});
|
||||
|
||||
it('returns the referenced models - verify', function(done) {
|
||||
it('returns the referenced models without the deleted one', function(done) {
|
||||
var url = '/api/recipes/' + this.recipe.id + '/ingredients';
|
||||
var test = this;
|
||||
|
||||
|
@ -1370,7 +1370,7 @@ describe('relations - integration', function() {
|
|||
});
|
||||
});
|
||||
|
||||
it('returns the referenced models - verify', function(done) {
|
||||
it('returns the referenced models without the unlinked one', function(done) {
|
||||
var url = '/api/recipes/' + this.recipe.id + '/ingredients';
|
||||
var test = this;
|
||||
|
||||
|
@ -1529,17 +1529,17 @@ describe('relations - integration', function() {
|
|||
|
||||
test.book = book;
|
||||
book.pages.create({name: 'Page 1'},
|
||||
function(err, page) {
|
||||
if (err) return done(err);
|
||||
function(err, page) {
|
||||
if (err) return done(err);
|
||||
|
||||
test.page = page;
|
||||
page.notes.create({text: 'Page Note 1'},
|
||||
function(err, note) {
|
||||
test.note = note;
|
||||
test.page = page;
|
||||
page.notes.create({text: 'Page Note 1'},
|
||||
function(err, note) {
|
||||
test.note = note;
|
||||
|
||||
done();
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -228,33 +228,33 @@ describe('With model.settings.replaceOnPUT false', function() {
|
|||
});
|
||||
|
||||
it('should have expected remote methods',
|
||||
function() {
|
||||
var storeClass = findClass('storeWithReplaceOnPUTfalse');
|
||||
var methods = getFormattedMethodsExcludingRelations(storeClass.methods);
|
||||
function() {
|
||||
var storeClass = findClass('storeWithReplaceOnPUTfalse');
|
||||
var methods = getFormattedMethodsExcludingRelations(storeClass.methods);
|
||||
|
||||
var expectedMethods = [
|
||||
'create(data:object:storeWithReplaceOnPUTfalse):storeWithReplaceOnPUTfalse POST /stores-updating',
|
||||
'patchOrCreate(data:object:storeWithReplaceOnPUTfalse):storeWithReplaceOnPUTfalse PUT /stores-updating',
|
||||
'patchOrCreate(data:object:storeWithReplaceOnPUTfalse):storeWithReplaceOnPUTfalse PATCH /stores-updating',
|
||||
'replaceOrCreate(data:object:storeWithReplaceOnPUTfalse):storeWithReplaceOnPUTfalse POST /stores-updating/replaceOrCreate',
|
||||
'upsertWithWhere(where:object,data:object:storeWithReplaceOnPUTfalse):storeWithReplaceOnPUTfalse POST /stores-updating/upsertWithWhere',
|
||||
'exists(id:any):boolean GET /stores-updating/:id/exists',
|
||||
'exists(id:any):boolean HEAD /stores-updating/:id',
|
||||
'findById(id:any,filter:object):storeWithReplaceOnPUTfalse GET /stores-updating/:id',
|
||||
'replaceById(id:any,data:object:storeWithReplaceOnPUTfalse):storeWithReplaceOnPUTfalse POST /stores-updating/:id/replace',
|
||||
'find(filter:object):storeWithReplaceOnPUTfalse GET /stores-updating',
|
||||
'findOne(filter:object):storeWithReplaceOnPUTfalse GET /stores-updating/findOne',
|
||||
'updateAll(where:object,data:object:storeWithReplaceOnPUTfalse):object POST /stores-updating/update',
|
||||
'deleteById(id:any):object DELETE /stores-updating/:id',
|
||||
'count(where:object):number GET /stores-updating/count',
|
||||
'prototype.patchAttributes(data:object:storeWithReplaceOnPUTfalse):storeWithReplaceOnPUTfalse PUT /stores-updating/:id',
|
||||
'prototype.patchAttributes(data:object:storeWithReplaceOnPUTfalse):storeWithReplaceOnPUTfalse PATCH /stores-updating/:id',
|
||||
'createChangeStream(options:object):ReadableStream POST /stores-updating/change-stream',
|
||||
'createChangeStream(options:object):ReadableStream GET /stores-updating/change-stream',
|
||||
];
|
||||
var expectedMethods = [
|
||||
'create(data:object:storeWithReplaceOnPUTfalse):storeWithReplaceOnPUTfalse POST /stores-updating',
|
||||
'patchOrCreate(data:object:storeWithReplaceOnPUTfalse):storeWithReplaceOnPUTfalse PUT /stores-updating',
|
||||
'patchOrCreate(data:object:storeWithReplaceOnPUTfalse):storeWithReplaceOnPUTfalse PATCH /stores-updating',
|
||||
'replaceOrCreate(data:object:storeWithReplaceOnPUTfalse):storeWithReplaceOnPUTfalse POST /stores-updating/replaceOrCreate',
|
||||
'upsertWithWhere(where:object,data:object:storeWithReplaceOnPUTfalse):storeWithReplaceOnPUTfalse POST /stores-updating/upsertWithWhere',
|
||||
'exists(id:any):boolean GET /stores-updating/:id/exists',
|
||||
'exists(id:any):boolean HEAD /stores-updating/:id',
|
||||
'findById(id:any,filter:object):storeWithReplaceOnPUTfalse GET /stores-updating/:id',
|
||||
'replaceById(id:any,data:object:storeWithReplaceOnPUTfalse):storeWithReplaceOnPUTfalse POST /stores-updating/:id/replace',
|
||||
'find(filter:object):storeWithReplaceOnPUTfalse GET /stores-updating',
|
||||
'findOne(filter:object):storeWithReplaceOnPUTfalse GET /stores-updating/findOne',
|
||||
'updateAll(where:object,data:object:storeWithReplaceOnPUTfalse):object POST /stores-updating/update',
|
||||
'deleteById(id:any):object DELETE /stores-updating/:id',
|
||||
'count(where:object):number GET /stores-updating/count',
|
||||
'prototype.patchAttributes(data:object:storeWithReplaceOnPUTfalse):storeWithReplaceOnPUTfalse PUT /stores-updating/:id',
|
||||
'prototype.patchAttributes(data:object:storeWithReplaceOnPUTfalse):storeWithReplaceOnPUTfalse PATCH /stores-updating/:id',
|
||||
'createChangeStream(options:object):ReadableStream POST /stores-updating/change-stream',
|
||||
'createChangeStream(options:object):ReadableStream GET /stores-updating/change-stream',
|
||||
];
|
||||
|
||||
expect(methods).to.eql(expectedMethods);
|
||||
});
|
||||
expect(methods).to.eql(expectedMethods);
|
||||
});
|
||||
});
|
||||
|
||||
describe('With model.settings.replaceOnPUT true', function() {
|
||||
|
@ -265,21 +265,21 @@ describe('With model.settings.replaceOnPUT true', function() {
|
|||
});
|
||||
|
||||
it('should have expected remote methods',
|
||||
function() {
|
||||
var storeClass = findClass('storeWithReplaceOnPUTtrue');
|
||||
var methods = getFormattedMethodsExcludingRelations(storeClass.methods);
|
||||
function() {
|
||||
var storeClass = findClass('storeWithReplaceOnPUTtrue');
|
||||
var methods = getFormattedMethodsExcludingRelations(storeClass.methods);
|
||||
|
||||
var expectedMethods = [
|
||||
'patchOrCreate(data:object:storeWithReplaceOnPUTtrue):storeWithReplaceOnPUTtrue PATCH /stores-replacing',
|
||||
'replaceOrCreate(data:object:storeWithReplaceOnPUTtrue):storeWithReplaceOnPUTtrue POST /stores-replacing/replaceOrCreate',
|
||||
'replaceOrCreate(data:object:storeWithReplaceOnPUTtrue):storeWithReplaceOnPUTtrue PUT /stores-replacing',
|
||||
'replaceById(id:any,data:object:storeWithReplaceOnPUTtrue):storeWithReplaceOnPUTtrue POST /stores-replacing/:id/replace',
|
||||
'replaceById(id:any,data:object:storeWithReplaceOnPUTtrue):storeWithReplaceOnPUTtrue PUT /stores-replacing/:id',
|
||||
'prototype.patchAttributes(data:object:storeWithReplaceOnPUTtrue):storeWithReplaceOnPUTtrue PATCH /stores-replacing/:id',
|
||||
];
|
||||
var expectedMethods = [
|
||||
'patchOrCreate(data:object:storeWithReplaceOnPUTtrue):storeWithReplaceOnPUTtrue PATCH /stores-replacing',
|
||||
'replaceOrCreate(data:object:storeWithReplaceOnPUTtrue):storeWithReplaceOnPUTtrue POST /stores-replacing/replaceOrCreate',
|
||||
'replaceOrCreate(data:object:storeWithReplaceOnPUTtrue):storeWithReplaceOnPUTtrue PUT /stores-replacing',
|
||||
'replaceById(id:any,data:object:storeWithReplaceOnPUTtrue):storeWithReplaceOnPUTtrue POST /stores-replacing/:id/replace',
|
||||
'replaceById(id:any,data:object:storeWithReplaceOnPUTtrue):storeWithReplaceOnPUTtrue PUT /stores-replacing/:id',
|
||||
'prototype.patchAttributes(data:object:storeWithReplaceOnPUTtrue):storeWithReplaceOnPUTtrue PATCH /stores-replacing/:id',
|
||||
];
|
||||
|
||||
expect(methods).to.include.members(expectedMethods);
|
||||
});
|
||||
expect(methods).to.include.members(expectedMethods);
|
||||
});
|
||||
});
|
||||
|
||||
function formatReturns(m) {
|
||||
|
@ -332,12 +332,12 @@ function getFormattedMethodsExcludingRelations(methods) {
|
|||
return methods.filter(function(m) {
|
||||
return m.name.indexOf('__') === -1;
|
||||
})
|
||||
.map(function(m) {
|
||||
return formatMethod(m);
|
||||
})
|
||||
.reduce(function(p, c) {
|
||||
return p.concat(c);
|
||||
});
|
||||
.map(function(m) {
|
||||
return formatMethod(m);
|
||||
})
|
||||
.reduce(function(p, c) {
|
||||
return p.concat(c);
|
||||
});
|
||||
}
|
||||
|
||||
function getCreateMethod(methods) {
|
||||
|
@ -350,22 +350,22 @@ function getFormattedScopeMethods(methods) {
|
|||
return methods.filter(function(m) {
|
||||
return m.name.indexOf('__') === 0;
|
||||
})
|
||||
.map(function(m) {
|
||||
return formatMethod(m);
|
||||
})
|
||||
.reduce(function(p, c) {
|
||||
return p.concat(c);
|
||||
});
|
||||
.map(function(m) {
|
||||
return formatMethod(m);
|
||||
})
|
||||
.reduce(function(p, c) {
|
||||
return p.concat(c);
|
||||
});
|
||||
}
|
||||
|
||||
function getFormattedPrototypeMethods(methods) {
|
||||
return methods.filter(function(m) {
|
||||
return m.name.indexOf('prototype.__') === 0;
|
||||
})
|
||||
.map(function(m) {
|
||||
return formatMethod(m);
|
||||
})
|
||||
.reduce(function(p, c) {
|
||||
return p.concat(c);
|
||||
});
|
||||
.map(function(m) {
|
||||
return formatMethod(m);
|
||||
})
|
||||
.reduce(function(p, c) {
|
||||
return p.concat(c);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -72,8 +72,8 @@ describe('Replication over REST', function() {
|
|||
|
||||
it('allows PETER to WRITE', function(done) {
|
||||
createCar()
|
||||
.set('Authorization', peterToken)
|
||||
.expect(200, done);
|
||||
.set('Authorization', peterToken)
|
||||
.expect(200, done);
|
||||
});
|
||||
|
||||
function listCars() {
|
||||
|
@ -597,7 +597,7 @@ describe('Replication over REST', function() {
|
|||
function(next) {
|
||||
ServerCar.create(
|
||||
[
|
||||
{id: 'Ford-Mustang', maker: 'Ford', model: 'Mustang'},
|
||||
{id: 'Ford-Mustang', maker: 'Ford', model: 'Mustang'},
|
||||
{id: 'Audi-R8', maker: 'Audi', model: 'R8'},
|
||||
],
|
||||
function(err, cars) {
|
||||
|
|
|
@ -170,66 +170,66 @@ describe('Replication / Change APIs', function() {
|
|||
});
|
||||
|
||||
it('rectifyOnDelete for Delete should call rectifyChange instead of rectifyAllChanges',
|
||||
function(done) {
|
||||
var calls = mockTargetModelRectify();
|
||||
async.waterfall([
|
||||
function(callback) {
|
||||
SourceModel.destroyAll({name: 'John'}, callback);
|
||||
},
|
||||
function(data, callback) {
|
||||
SourceModel.replicate(TargetModel, callback);
|
||||
function(done) {
|
||||
var calls = mockTargetModelRectify();
|
||||
async.waterfall([
|
||||
function(callback) {
|
||||
SourceModel.destroyAll({name: 'John'}, callback);
|
||||
},
|
||||
function(data, callback) {
|
||||
SourceModel.replicate(TargetModel, callback);
|
||||
// replicate should call `rectifyOnSave` and then `rectifyChange` not `rectifyAllChanges` through `after save` operation
|
||||
},
|
||||
], function(err, results) {
|
||||
if (err) return done(err);
|
||||
},
|
||||
], function(err, results) {
|
||||
if (err) return done(err);
|
||||
|
||||
expect(calls).to.eql(['rectifyChange']);
|
||||
expect(calls).to.eql(['rectifyChange']);
|
||||
|
||||
done();
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('rectifyOnSave for Update should call rectifyChange instead of rectifyAllChanges',
|
||||
function(done) {
|
||||
var calls = mockTargetModelRectify();
|
||||
var newData = {'name': 'Janie'};
|
||||
async.waterfall([
|
||||
function(callback) {
|
||||
SourceModel.update({name: 'Jane'}, newData, callback);
|
||||
},
|
||||
function(data, callback) {
|
||||
SourceModel.replicate(TargetModel, callback);
|
||||
function(done) {
|
||||
var calls = mockTargetModelRectify();
|
||||
var newData = {'name': 'Janie'};
|
||||
async.waterfall([
|
||||
function(callback) {
|
||||
SourceModel.update({name: 'Jane'}, newData, callback);
|
||||
},
|
||||
function(data, callback) {
|
||||
SourceModel.replicate(TargetModel, callback);
|
||||
// replicate should call `rectifyOnSave` and then `rectifyChange` not `rectifyAllChanges` through `after save` operation
|
||||
},
|
||||
], function(err, result) {
|
||||
if (err) return done(err);
|
||||
},
|
||||
], function(err, result) {
|
||||
if (err) return done(err);
|
||||
|
||||
expect(calls).to.eql(['rectifyChange']);
|
||||
expect(calls).to.eql(['rectifyChange']);
|
||||
|
||||
done();
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('rectifyOnSave for Create should call rectifyChange instead of rectifyAllChanges',
|
||||
function(done) {
|
||||
var calls = mockTargetModelRectify();
|
||||
var newData = [{name: 'Janie', surname: 'Doe'}];
|
||||
async.waterfall([
|
||||
function(callback) {
|
||||
SourceModel.create(newData, callback);
|
||||
},
|
||||
function(data, callback) {
|
||||
SourceModel.replicate(TargetModel, callback);
|
||||
function(done) {
|
||||
var calls = mockTargetModelRectify();
|
||||
var newData = [{name: 'Janie', surname: 'Doe'}];
|
||||
async.waterfall([
|
||||
function(callback) {
|
||||
SourceModel.create(newData, callback);
|
||||
},
|
||||
function(data, callback) {
|
||||
SourceModel.replicate(TargetModel, callback);
|
||||
// replicate should call `rectifyOnSave` and then `rectifyChange` not `rectifyAllChanges` through `after save` operation
|
||||
},
|
||||
], function(err, result) {
|
||||
if (err) return done(err);
|
||||
},
|
||||
], function(err, result) {
|
||||
if (err) return done(err);
|
||||
|
||||
expect(calls).to.eql(['rectifyChange']);
|
||||
expect(calls).to.eql(['rectifyChange']);
|
||||
|
||||
done();
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function mockSourceModelRectify() {
|
||||
var calls = [];
|
||||
|
@ -305,12 +305,12 @@ describe('Replication / Change APIs', function() {
|
|||
if (err) return done(err);
|
||||
|
||||
test.SourceModel.replicate(test.startingCheckpoint, test.TargetModel,
|
||||
options, function(err, conflicts) {
|
||||
if (err) return done(err);
|
||||
options, function(err, conflicts) {
|
||||
if (err) return done(err);
|
||||
|
||||
assertTargetModelEqualsSourceModel(conflicts, test.SourceModel,
|
||||
test.TargetModel, done);
|
||||
});
|
||||
assertTargetModelEqualsSourceModel(conflicts, test.SourceModel,
|
||||
test.TargetModel, done);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -322,7 +322,7 @@ describe('Replication / Change APIs', function() {
|
|||
if (err) return done(err);
|
||||
|
||||
test.SourceModel.replicate(test.startingCheckpoint, test.TargetModel,
|
||||
options)
|
||||
options)
|
||||
.then(function(conflicts) {
|
||||
assertTargetModelEqualsSourceModel(conflicts, test.SourceModel,
|
||||
test.TargetModel, done);
|
||||
|
@ -1280,7 +1280,7 @@ describe('Replication / Change APIs', function() {
|
|||
var ClientA, Server, ClientB;
|
||||
|
||||
beforeEach(function() {
|
||||
ClientA = SourceModel;
|
||||
ClientA = SourceModel;
|
||||
Server = TargetModel;
|
||||
ClientB = AnotherModel;
|
||||
|
||||
|
@ -1625,13 +1625,13 @@ describe('Replication / Change APIs', function() {
|
|||
updates[0].change = data;
|
||||
OptionsSourceModel.bulkUpdate(updates, options, callback);
|
||||
}],
|
||||
function(err, result) {
|
||||
if (err) return done(err);
|
||||
function(err, result) {
|
||||
if (err) return done(err);
|
||||
|
||||
expect(syncPropertyExists).to.eql(true);
|
||||
expect(syncPropertyExists).to.eql(true);
|
||||
|
||||
done();
|
||||
}
|
||||
done();
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
|
@ -1875,7 +1875,7 @@ describe('Replication / Change APIs', function() {
|
|||
}
|
||||
|
||||
function assertTargetModelEqualsSourceModel(conflicts, sourceModel,
|
||||
targetModel, done) {
|
||||
targetModel, done) {
|
||||
var sourceData, targetData;
|
||||
|
||||
assert(conflicts.length === 0);
|
||||
|
|
|
@ -239,12 +239,12 @@ describe('loopback.rest', function() {
|
|||
|
||||
describe('with specific definitions in model-config.json', function() {
|
||||
it('should not be exposed when the definition value is false',
|
||||
function(done) {
|
||||
var app = require(getFixturePath('model-config-defined-false'));
|
||||
request(app)
|
||||
.get('/todos')
|
||||
.expect(404, done);
|
||||
});
|
||||
function(done) {
|
||||
var app = require(getFixturePath('model-config-defined-false'));
|
||||
request(app)
|
||||
.get('/todos')
|
||||
.expect(404, done);
|
||||
});
|
||||
|
||||
it('should be exposed when the definition value is true', function(done) {
|
||||
var app = require(getFixturePath('model-config-defined-true'));
|
||||
|
@ -256,12 +256,12 @@ describe('loopback.rest', function() {
|
|||
|
||||
describe('with default definitions in model-config.json', function() {
|
||||
it('should not be exposed when the definition value is false',
|
||||
function(done) {
|
||||
var app = require(getFixturePath('model-config-default-false'));
|
||||
request(app)
|
||||
.get('/todos')
|
||||
.expect(404, done);
|
||||
});
|
||||
function(done) {
|
||||
var app = require(getFixturePath('model-config-default-false'));
|
||||
request(app)
|
||||
.get('/todos')
|
||||
.expect(404, done);
|
||||
});
|
||||
|
||||
it('should be exposed when the definition value is true', function(done) {
|
||||
var app = require(getFixturePath('model-config-default-true'));
|
||||
|
@ -286,30 +286,30 @@ describe('loopback.rest', function() {
|
|||
|
||||
describe('with specific definitions in config.json', function() {
|
||||
it('should not be exposed when the definition value is false',
|
||||
function(done) {
|
||||
var app = require(getFixturePath('config-defined-false'));
|
||||
request(app)
|
||||
.get('/todos')
|
||||
.expect(404, done);
|
||||
});
|
||||
function(done) {
|
||||
var app = require(getFixturePath('config-defined-false'));
|
||||
request(app)
|
||||
.get('/todos')
|
||||
.expect(404, done);
|
||||
});
|
||||
|
||||
it('should be exposed when the definition value is true',
|
||||
function(done) {
|
||||
var app = require(getFixturePath('config-defined-true'));
|
||||
request(app)
|
||||
.get('/todos')
|
||||
.expect(200, done);
|
||||
});
|
||||
function(done) {
|
||||
var app = require(getFixturePath('config-defined-true'));
|
||||
request(app)
|
||||
.get('/todos')
|
||||
.expect(200, done);
|
||||
});
|
||||
});
|
||||
|
||||
describe('with default definitions in config.json', function() {
|
||||
it('should not be exposed when the definition value is false',
|
||||
function(done) {
|
||||
var app = require(getFixturePath('config-default-false'));
|
||||
request(app)
|
||||
.get('/todos')
|
||||
.expect(404, done);
|
||||
});
|
||||
function(done) {
|
||||
var app = require(getFixturePath('config-default-false'));
|
||||
request(app)
|
||||
.get('/todos')
|
||||
.expect(404, done);
|
||||
});
|
||||
|
||||
it('should be exposed when the definition value is true', function(done) {
|
||||
var app = require(getFixturePath('config-default-true'));
|
||||
|
@ -337,21 +337,21 @@ describe('loopback.rest', function() {
|
|||
// a side effect since tests share the same loopback instance. As a
|
||||
// consequence, this causes the tests in user.integration to fail.
|
||||
describe.skip('with definitions in both config.json and model-config.json',
|
||||
function() {
|
||||
it('should prioritize the settings in model-config.json', function(done) {
|
||||
var app = require(getFixturePath('both-configs-set'));
|
||||
request(app)
|
||||
.del('/todos')
|
||||
.expect(404, done);
|
||||
});
|
||||
|
||||
it('should fall back to config.json settings if setting is not found in' +
|
||||
'model-config.json', function(done) {
|
||||
var app = require(getFixturePath('both-configs-set'));
|
||||
request(app)
|
||||
.get('/todos')
|
||||
.expect(404, done);
|
||||
});
|
||||
function() {
|
||||
it('should prioritize the settings in model-config.json', function(done) {
|
||||
var app = require(getFixturePath('both-configs-set'));
|
||||
request(app)
|
||||
.del('/todos')
|
||||
.expect(404, done);
|
||||
});
|
||||
|
||||
it('should fall back to config.json settings if setting is not found in' +
|
||||
'model-config.json', function(done) {
|
||||
var app = require(getFixturePath('both-configs-set'));
|
||||
request(app)
|
||||
.get('/todos')
|
||||
.expect(404, done);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -31,11 +31,11 @@ describe('role-mapping model', function() {
|
|||
models.Application.create({name: 'anApp'}),
|
||||
models.Role.create({name: 'aRole'}),
|
||||
])
|
||||
.spread(function(u, a, r) {
|
||||
oneUser = u;
|
||||
anApp = a;
|
||||
aRole = r;
|
||||
});
|
||||
.spread(function(u, a, r) {
|
||||
oneUser = u;
|
||||
anApp = a;
|
||||
aRole = r;
|
||||
});
|
||||
|
||||
// helper
|
||||
function setupModel(modelName) {
|
||||
|
|
|
@ -111,36 +111,36 @@ describe('role model', function() {
|
|||
Role.create({name: 'userRole'}, function(err, role) {
|
||||
if (err) return done(err);
|
||||
role.principals.create({principalType: RoleMapping.USER, principalId: user.id},
|
||||
function(err, p) {
|
||||
if (err) return done(err);
|
||||
async.parallel([
|
||||
function(next) {
|
||||
Role.find(function(err, roles) {
|
||||
if (err) return next(err);
|
||||
assert.equal(roles.length, 1);
|
||||
assert.equal(roles[0].name, 'userRole');
|
||||
next();
|
||||
});
|
||||
},
|
||||
function(next) {
|
||||
role.principals(function(err, principals) {
|
||||
if (err) return next(err);
|
||||
assert.equal(principals.length, 1);
|
||||
assert.equal(principals[0].principalType, RoleMapping.USER);
|
||||
assert.equal(principals[0].principalId, user.id);
|
||||
next();
|
||||
});
|
||||
},
|
||||
function(next) {
|
||||
role.users(function(err, users) {
|
||||
if (err) return next(err);
|
||||
assert.equal(users.length, 1);
|
||||
assert.equal(users[0].id, user.id);
|
||||
next();
|
||||
});
|
||||
},
|
||||
], done);
|
||||
});
|
||||
function(err, p) {
|
||||
if (err) return done(err);
|
||||
async.parallel([
|
||||
function(next) {
|
||||
Role.find(function(err, roles) {
|
||||
if (err) return next(err);
|
||||
assert.equal(roles.length, 1);
|
||||
assert.equal(roles[0].name, 'userRole');
|
||||
next();
|
||||
});
|
||||
},
|
||||
function(next) {
|
||||
role.principals(function(err, principals) {
|
||||
if (err) return next(err);
|
||||
assert.equal(principals.length, 1);
|
||||
assert.equal(principals[0].principalType, RoleMapping.USER);
|
||||
assert.equal(principals[0].principalId, user.id);
|
||||
next();
|
||||
});
|
||||
},
|
||||
function(next) {
|
||||
role.users(function(err, users) {
|
||||
if (err) return next(err);
|
||||
assert.equal(users.length, 1);
|
||||
assert.equal(users[0].id, user.id);
|
||||
next();
|
||||
});
|
||||
},
|
||||
], done);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -168,38 +168,38 @@ describe('role model', function() {
|
|||
if (err) return done(err);
|
||||
assert(role.id);
|
||||
role.principals.create({principalType: RoleMapping.USER, principalId: user.id},
|
||||
function(err, p) {
|
||||
if (err) return done(err);
|
||||
assert(p.id);
|
||||
assert.equal(p.roleId, role.id);
|
||||
async.parallel([
|
||||
function(next) {
|
||||
Role.find(function(err, roles) {
|
||||
if (err) return next(err);
|
||||
assert.equal(roles.length, 1);
|
||||
assert.equal(roles[0].name, 'userRole');
|
||||
function(err, p) {
|
||||
if (err) return done(err);
|
||||
assert(p.id);
|
||||
assert.equal(p.roleId, role.id);
|
||||
async.parallel([
|
||||
function(next) {
|
||||
Role.find(function(err, roles) {
|
||||
if (err) return next(err);
|
||||
assert.equal(roles.length, 1);
|
||||
assert.equal(roles[0].name, 'userRole');
|
||||
next();
|
||||
});
|
||||
},
|
||||
function(next) {
|
||||
role.principals(function(err, principals) {
|
||||
if (err) return next(err);
|
||||
assert.equal(principals.length, 1);
|
||||
assert.equal(principals[0].principalType, RoleMapping.USER);
|
||||
assert.equal(principals[0].principalId, user.id);
|
||||
next();
|
||||
});
|
||||
},
|
||||
function(next) {
|
||||
role.users(function(err, users) {
|
||||
if (err) return next(err);
|
||||
assert.equal(users.length, 1);
|
||||
assert.equal(users[0].id, user.id);
|
||||
});
|
||||
next();
|
||||
});
|
||||
},
|
||||
function(next) {
|
||||
role.principals(function(err, principals) {
|
||||
if (err) return next(err);
|
||||
assert.equal(principals.length, 1);
|
||||
assert.equal(principals[0].principalType, RoleMapping.USER);
|
||||
assert.equal(principals[0].principalId, user.id);
|
||||
next();
|
||||
});
|
||||
},
|
||||
function(next) {
|
||||
role.users(function(err, users) {
|
||||
if (err) return next(err);
|
||||
assert.equal(users.length, 1);
|
||||
assert.equal(users[0].id, user.id);
|
||||
});
|
||||
next();
|
||||
},
|
||||
], done);
|
||||
});
|
||||
},
|
||||
], done);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -210,106 +210,106 @@ describe('role model', function() {
|
|||
Role.create({name: 'userRole'}, function(err, role) {
|
||||
if (err) return done(err);
|
||||
role.principals.create({principalType: RoleMapping.USER, principalId: user.id},
|
||||
function(err, p) {
|
||||
if (err) return done(err);
|
||||
async.series([
|
||||
function(next) {
|
||||
Role.isInRole(
|
||||
'userRole',
|
||||
{principalType: RoleMapping.USER, principalId: user.id},
|
||||
function(err, inRole) {
|
||||
if (err) return next(err);
|
||||
// NOTE(bajtos) Apparently isRole is not a boolean,
|
||||
// but the matchin role object instead
|
||||
assert(!!inRole);
|
||||
next();
|
||||
});
|
||||
},
|
||||
function(next) {
|
||||
Role.isInRole(
|
||||
'userRole',
|
||||
{principalType: RoleMapping.APP, principalId: user.id},
|
||||
function(err, inRole) {
|
||||
if (err) return next(err);
|
||||
assert(!inRole);
|
||||
next();
|
||||
});
|
||||
},
|
||||
function(next) {
|
||||
Role.isInRole(
|
||||
'userRole',
|
||||
{principalType: RoleMapping.USER, principalId: 100},
|
||||
function(err, inRole) {
|
||||
if (err) return next(err);
|
||||
assert(!inRole);
|
||||
next();
|
||||
});
|
||||
},
|
||||
function(next) {
|
||||
Role.getRoles(
|
||||
{principalType: RoleMapping.USER, principalId: user.id},
|
||||
function(err, roles) {
|
||||
if (err) return next(err);
|
||||
expect(roles).to.eql([
|
||||
Role.AUTHENTICATED,
|
||||
Role.EVERYONE,
|
||||
role.id,
|
||||
]);
|
||||
next();
|
||||
});
|
||||
},
|
||||
function(next) {
|
||||
Role.getRoles(
|
||||
{principalType: RoleMapping.USER, principalId: user.id},
|
||||
{returnOnlyRoleNames: true},
|
||||
function(err, roles) {
|
||||
if (err) return next(err);
|
||||
expect(roles).to.eql([
|
||||
Role.AUTHENTICATED,
|
||||
Role.EVERYONE,
|
||||
role.name,
|
||||
]);
|
||||
next();
|
||||
});
|
||||
},
|
||||
function(next) {
|
||||
Role.getRoles(
|
||||
{principalType: RoleMapping.APP, principalId: user.id},
|
||||
function(err, roles) {
|
||||
if (err) return next(err);
|
||||
expect(roles).to.eql([
|
||||
Role.AUTHENTICATED,
|
||||
Role.EVERYONE,
|
||||
]);
|
||||
next();
|
||||
});
|
||||
},
|
||||
function(next) {
|
||||
Role.getRoles(
|
||||
{principalType: RoleMapping.USER, principalId: 100},
|
||||
function(err, roles) {
|
||||
if (err) return next(err);
|
||||
expect(roles).to.eql([
|
||||
Role.AUTHENTICATED,
|
||||
Role.EVERYONE,
|
||||
]);
|
||||
next();
|
||||
});
|
||||
},
|
||||
function(next) {
|
||||
Role.getRoles(
|
||||
{principalType: RoleMapping.USER, principalId: null},
|
||||
function(err, roles) {
|
||||
if (err) return next(err);
|
||||
expect(roles).to.eql([
|
||||
Role.UNAUTHENTICATED,
|
||||
Role.EVERYONE,
|
||||
]);
|
||||
next();
|
||||
});
|
||||
},
|
||||
], done);
|
||||
});
|
||||
function(err, p) {
|
||||
if (err) return done(err);
|
||||
async.series([
|
||||
function(next) {
|
||||
Role.isInRole(
|
||||
'userRole',
|
||||
{principalType: RoleMapping.USER, principalId: user.id},
|
||||
function(err, inRole) {
|
||||
if (err) return next(err);
|
||||
// NOTE(bajtos) Apparently isRole is not a boolean,
|
||||
// but the matchin role object instead
|
||||
assert(!!inRole);
|
||||
next();
|
||||
});
|
||||
},
|
||||
function(next) {
|
||||
Role.isInRole(
|
||||
'userRole',
|
||||
{principalType: RoleMapping.APP, principalId: user.id},
|
||||
function(err, inRole) {
|
||||
if (err) return next(err);
|
||||
assert(!inRole);
|
||||
next();
|
||||
});
|
||||
},
|
||||
function(next) {
|
||||
Role.isInRole(
|
||||
'userRole',
|
||||
{principalType: RoleMapping.USER, principalId: 100},
|
||||
function(err, inRole) {
|
||||
if (err) return next(err);
|
||||
assert(!inRole);
|
||||
next();
|
||||
});
|
||||
},
|
||||
function(next) {
|
||||
Role.getRoles(
|
||||
{principalType: RoleMapping.USER, principalId: user.id},
|
||||
function(err, roles) {
|
||||
if (err) return next(err);
|
||||
expect(roles).to.eql([
|
||||
Role.AUTHENTICATED,
|
||||
Role.EVERYONE,
|
||||
role.id,
|
||||
]);
|
||||
next();
|
||||
});
|
||||
},
|
||||
function(next) {
|
||||
Role.getRoles(
|
||||
{principalType: RoleMapping.USER, principalId: user.id},
|
||||
{returnOnlyRoleNames: true},
|
||||
function(err, roles) {
|
||||
if (err) return next(err);
|
||||
expect(roles).to.eql([
|
||||
Role.AUTHENTICATED,
|
||||
Role.EVERYONE,
|
||||
role.name,
|
||||
]);
|
||||
next();
|
||||
});
|
||||
},
|
||||
function(next) {
|
||||
Role.getRoles(
|
||||
{principalType: RoleMapping.APP, principalId: user.id},
|
||||
function(err, roles) {
|
||||
if (err) return next(err);
|
||||
expect(roles).to.eql([
|
||||
Role.AUTHENTICATED,
|
||||
Role.EVERYONE,
|
||||
]);
|
||||
next();
|
||||
});
|
||||
},
|
||||
function(next) {
|
||||
Role.getRoles(
|
||||
{principalType: RoleMapping.USER, principalId: 100},
|
||||
function(err, roles) {
|
||||
if (err) return next(err);
|
||||
expect(roles).to.eql([
|
||||
Role.AUTHENTICATED,
|
||||
Role.EVERYONE,
|
||||
]);
|
||||
next();
|
||||
});
|
||||
},
|
||||
function(next) {
|
||||
Role.getRoles(
|
||||
{principalType: RoleMapping.USER, principalId: null},
|
||||
function(err, roles) {
|
||||
if (err) return next(err);
|
||||
expect(roles).to.eql([
|
||||
Role.UNAUTHENTICATED,
|
||||
Role.EVERYONE,
|
||||
]);
|
||||
next();
|
||||
});
|
||||
},
|
||||
], done);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -380,44 +380,44 @@ describe('role model', function() {
|
|||
Role.create({name: 'userRole'}, function(err, role) {
|
||||
if (err) return done(err);
|
||||
role.principals.create({principalType: RoleMapping.USER, principalId: user.id},
|
||||
function(err, p) {
|
||||
if (err) return done(err);
|
||||
async.series([
|
||||
function(next) {
|
||||
Role.isInRole(
|
||||
'userRole',
|
||||
{principalType: RoleMapping.USER, principalId: user.id},
|
||||
function(err, inRole) {
|
||||
if (err) return next(err);
|
||||
assert(!!inRole);
|
||||
next();
|
||||
});
|
||||
},
|
||||
function(next) {
|
||||
Role.isInRole(
|
||||
'userRole',
|
||||
{principalType: RoleMapping.APP, principalId: user.id},
|
||||
function(err, inRole) {
|
||||
if (err) return next(err);
|
||||
assert(!inRole);
|
||||
next();
|
||||
});
|
||||
},
|
||||
function(next) {
|
||||
Role.getRoles(
|
||||
{principalType: RoleMapping.USER, principalId: user.id},
|
||||
function(err, roles) {
|
||||
if (err) return next(err);
|
||||
expect(roles).to.eql([
|
||||
Role.AUTHENTICATED,
|
||||
Role.EVERYONE,
|
||||
role.id,
|
||||
]);
|
||||
next();
|
||||
});
|
||||
},
|
||||
], done);
|
||||
});
|
||||
function(err, p) {
|
||||
if (err) return done(err);
|
||||
async.series([
|
||||
function(next) {
|
||||
Role.isInRole(
|
||||
'userRole',
|
||||
{principalType: RoleMapping.USER, principalId: user.id},
|
||||
function(err, inRole) {
|
||||
if (err) return next(err);
|
||||
assert(!!inRole);
|
||||
next();
|
||||
});
|
||||
},
|
||||
function(next) {
|
||||
Role.isInRole(
|
||||
'userRole',
|
||||
{principalType: RoleMapping.APP, principalId: user.id},
|
||||
function(err, inRole) {
|
||||
if (err) return next(err);
|
||||
assert(!inRole);
|
||||
next();
|
||||
});
|
||||
},
|
||||
function(next) {
|
||||
Role.getRoles(
|
||||
{principalType: RoleMapping.USER, principalId: user.id},
|
||||
function(err, roles) {
|
||||
if (err) return next(err);
|
||||
expect(roles).to.eql([
|
||||
Role.AUTHENTICATED,
|
||||
Role.EVERYONE,
|
||||
role.id,
|
||||
]);
|
||||
next();
|
||||
});
|
||||
},
|
||||
], done);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -566,19 +566,19 @@ describe('role model', function() {
|
|||
app.model(Album, {dataSource: 'db'});
|
||||
|
||||
return User.create({email: 'test@example.com', password: 'pass'})
|
||||
.then(u => {
|
||||
user = u;
|
||||
return Album.create({name: 'Album 1', userId: user.id});
|
||||
})
|
||||
.then(album => {
|
||||
return Role.isInRole(Role.OWNER, {
|
||||
principalType: ACL.USER,
|
||||
principalId: user.id,
|
||||
model: Album,
|
||||
id: album.id,
|
||||
});
|
||||
})
|
||||
.then(isInRole => expect(isInRole).to.be.true());
|
||||
.then(u => {
|
||||
user = u;
|
||||
return Album.create({name: 'Album 1', userId: user.id});
|
||||
})
|
||||
.then(album => {
|
||||
return Role.isInRole(Role.OWNER, {
|
||||
principalType: ACL.USER,
|
||||
principalId: user.id,
|
||||
model: Album,
|
||||
id: album.id,
|
||||
});
|
||||
})
|
||||
.then(isInRole => expect(isInRole).to.be.true());
|
||||
});
|
||||
|
||||
it('resolves the owner via property "owner"', function() {
|
||||
|
@ -590,9 +590,73 @@ describe('role model', function() {
|
|||
app.model(Album, {dataSource: 'db'});
|
||||
|
||||
return User.create({email: 'test@example.com', password: 'pass'})
|
||||
.then(u => {
|
||||
user = u;
|
||||
return Album.create({name: 'Album 1', owner: user.id});
|
||||
})
|
||||
.then(album => {
|
||||
return Role.isInRole(Role.OWNER, {
|
||||
principalType: ACL.USER,
|
||||
principalId: user.id,
|
||||
model: Album,
|
||||
id: album.id,
|
||||
});
|
||||
})
|
||||
.then(isInRole => expect(isInRole).to.be.true());
|
||||
});
|
||||
|
||||
it('resolves the owner via a belongsTo relation', function() {
|
||||
// passing no options will result calling
|
||||
// the legacy $owner role resolver behavior
|
||||
var Message = givenModelWithSenderReceiverRelations('ModelWithNoOptions');
|
||||
|
||||
return givenUsers()
|
||||
.then(() => {
|
||||
var messages = [
|
||||
{content: 'firstMessage', senderId: sender.id},
|
||||
{content: 'secondMessage', receiverId: receiver.id},
|
||||
{content: 'thirdMessage'},
|
||||
];
|
||||
return Promise.map(messages, msg => {
|
||||
return Message.create(msg);
|
||||
});
|
||||
})
|
||||
.then(messages => {
|
||||
return Promise.all([
|
||||
isOwnerForMessage(sender, messages[0]),
|
||||
isOwnerForMessage(receiver, messages[1]),
|
||||
isOwnerForMessage(receiver, messages[2]),
|
||||
]);
|
||||
})
|
||||
.then(result => {
|
||||
expect(result).to.eql([
|
||||
{user: 'sender', msg: 'firstMessage', isOwner: true},
|
||||
{user: 'receiver', msg: 'secondMessage', isOwner: false},
|
||||
{user: 'receiver', msg: 'thirdMessage', isOwner: false},
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('resolves as false without belongsTo relation', function() {
|
||||
var user;
|
||||
var Album = app.registry.createModel(
|
||||
'Album',
|
||||
{
|
||||
name: String,
|
||||
userId: Number,
|
||||
owner: Number,
|
||||
},
|
||||
// passing {ownerRelations: true} will enable the new $owner role resolver
|
||||
// and hence resolve false when no belongsTo relation is defined
|
||||
{ownerRelations: true}
|
||||
);
|
||||
app.model(Album, {dataSource: 'db'});
|
||||
|
||||
return User.create({email: 'test@example.com', password: 'pass'})
|
||||
.then(u => {
|
||||
user = u;
|
||||
return Album.create({name: 'Album 1', owner: user.id});
|
||||
return Album.create({name: 'Album 1', userId: user.id, owner: user.id});
|
||||
})
|
||||
.then(album => {
|
||||
return Role.isInRole(Role.OWNER, {
|
||||
|
@ -602,15 +666,18 @@ describe('role model', function() {
|
|||
id: album.id,
|
||||
});
|
||||
})
|
||||
.then(isInRole => expect(isInRole).to.be.true());
|
||||
});
|
||||
.then(isInRole => expect(isInRole).to.be.false());
|
||||
});
|
||||
|
||||
it('resolves the owner via a belongsTo relation', function() {
|
||||
// passing no options will result calling
|
||||
// the legacy $owner role resolver behavior
|
||||
var Message = givenModelWithSenderReceiverRelations('ModelWithNoOptions');
|
||||
it('resolves the owner using the corrent belongsTo relation', function() {
|
||||
// passing {ownerRelations: true} will enable the new $owner role resolver
|
||||
// with any belongsTo relation allowing to resolve truthy
|
||||
var Message = givenModelWithSenderReceiverRelations(
|
||||
'ModelWithAllRelations',
|
||||
{ownerRelations: true}
|
||||
);
|
||||
|
||||
return givenUsers()
|
||||
return givenUsers()
|
||||
.then(() => {
|
||||
var messages = [
|
||||
{content: 'firstMessage', senderId: sender.id},
|
||||
|
@ -631,124 +698,57 @@ describe('role model', function() {
|
|||
.then(result => {
|
||||
expect(result).to.eql([
|
||||
{user: 'sender', msg: 'firstMessage', isOwner: true},
|
||||
{user: 'receiver', msg: 'secondMessage', isOwner: false},
|
||||
{user: 'receiver', msg: 'secondMessage', isOwner: true},
|
||||
{user: 'receiver', msg: 'thirdMessage', isOwner: false},
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('resolves as false without belongsTo relation', function() {
|
||||
var user;
|
||||
var Album = app.registry.createModel(
|
||||
'Album',
|
||||
{
|
||||
name: String,
|
||||
userId: Number,
|
||||
owner: Number,
|
||||
},
|
||||
// passing {ownerRelations: true} will enable the new $owner role resolver
|
||||
// and hence resolve false when no belongsTo relation is defined
|
||||
{ownerRelations: true}
|
||||
);
|
||||
app.model(Album, {dataSource: 'db'});
|
||||
|
||||
return User.create({email: 'test@example.com', password: 'pass'})
|
||||
.then(u => {
|
||||
user = u;
|
||||
return Album.create({name: 'Album 1', userId: user.id, owner: user.id});
|
||||
})
|
||||
.then(album => {
|
||||
return Role.isInRole(Role.OWNER, {
|
||||
principalType: ACL.USER,
|
||||
principalId: user.id,
|
||||
model: Album,
|
||||
id: album.id,
|
||||
});
|
||||
})
|
||||
.then(isInRole => expect(isInRole).to.be.false());
|
||||
});
|
||||
|
||||
it('resolves the owner using the corrent belongsTo relation', function() {
|
||||
// passing {ownerRelations: true} will enable the new $owner role resolver
|
||||
// with any belongsTo relation allowing to resolve truthy
|
||||
var Message = givenModelWithSenderReceiverRelations(
|
||||
'ModelWithAllRelations',
|
||||
{ownerRelations: true}
|
||||
);
|
||||
|
||||
return givenUsers()
|
||||
.then(() => {
|
||||
var messages = [
|
||||
{content: 'firstMessage', senderId: sender.id},
|
||||
{content: 'secondMessage', receiverId: receiver.id},
|
||||
{content: 'thirdMessage'},
|
||||
];
|
||||
return Promise.map(messages, msg => {
|
||||
return Message.create(msg);
|
||||
});
|
||||
})
|
||||
.then(messages => {
|
||||
return Promise.all([
|
||||
isOwnerForMessage(sender, messages[0]),
|
||||
isOwnerForMessage(receiver, messages[1]),
|
||||
isOwnerForMessage(receiver, messages[2]),
|
||||
]);
|
||||
})
|
||||
.then(result => {
|
||||
expect(result).to.eql([
|
||||
{user: 'sender', msg: 'firstMessage', isOwner: true},
|
||||
{user: 'receiver', msg: 'secondMessage', isOwner: true},
|
||||
{user: 'receiver', msg: 'thirdMessage', isOwner: false},
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
it('allows fine-grained control of which relations grant ownership',
|
||||
function() {
|
||||
function() {
|
||||
// passing {ownerRelations: true} will enable the new $owner role resolver
|
||||
// with a specified list of belongsTo relations allowing to resolve truthy
|
||||
var Message = givenModelWithSenderReceiverRelations(
|
||||
'ModelWithCoercedRelations',
|
||||
{ownerRelations: ['receiver']}
|
||||
);
|
||||
var Message = givenModelWithSenderReceiverRelations(
|
||||
'ModelWithCoercedRelations',
|
||||
{ownerRelations: ['receiver']}
|
||||
);
|
||||
|
||||
return givenUsers()
|
||||
.then(() => {
|
||||
var messages = [
|
||||
{content: 'firstMessage', senderId: sender.id},
|
||||
{content: 'secondMessage', receiverId: receiver.id},
|
||||
{content: 'thirdMessage'},
|
||||
];
|
||||
return Promise.map(messages, msg => {
|
||||
return Message.create(msg);
|
||||
});
|
||||
})
|
||||
.then(messages => {
|
||||
return Promise.all([
|
||||
isOwnerForMessage(sender, messages[0]),
|
||||
isOwnerForMessage(receiver, messages[1]),
|
||||
isOwnerForMessage(receiver, messages[2]),
|
||||
]);
|
||||
})
|
||||
.then(result => {
|
||||
expect(result).to.eql([
|
||||
{user: 'sender', msg: 'firstMessage', isOwner: false},
|
||||
{user: 'receiver', msg: 'secondMessage', isOwner: true},
|
||||
{user: 'receiver', msg: 'thirdMessage', isOwner: false},
|
||||
]);
|
||||
return givenUsers()
|
||||
.then(() => {
|
||||
var messages = [
|
||||
{content: 'firstMessage', senderId: sender.id},
|
||||
{content: 'secondMessage', receiverId: receiver.id},
|
||||
{content: 'thirdMessage'},
|
||||
];
|
||||
return Promise.map(messages, msg => {
|
||||
return Message.create(msg);
|
||||
});
|
||||
})
|
||||
.then(messages => {
|
||||
return Promise.all([
|
||||
isOwnerForMessage(sender, messages[0]),
|
||||
isOwnerForMessage(receiver, messages[1]),
|
||||
isOwnerForMessage(receiver, messages[2]),
|
||||
]);
|
||||
})
|
||||
.then(result => {
|
||||
expect(result).to.eql([
|
||||
{user: 'sender', msg: 'firstMessage', isOwner: false},
|
||||
{user: 'receiver', msg: 'secondMessage', isOwner: true},
|
||||
{user: 'receiver', msg: 'thirdMessage', isOwner: false},
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// helpers
|
||||
function givenUsers() {
|
||||
return Promise.map(users, user => {
|
||||
return User.create(user);
|
||||
})
|
||||
.then(users => {
|
||||
sender = users[0];
|
||||
receiver = users[1];
|
||||
});
|
||||
.then(users => {
|
||||
sender = users[0];
|
||||
receiver = users[1];
|
||||
});
|
||||
}
|
||||
|
||||
function isOwnerForMessage(user, msg) {
|
||||
|
@ -977,16 +977,6 @@ describe('role model', function() {
|
|||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should report isMappedToRole by app.name', function(done) {
|
||||
ACL.isMappedToRole(ACL.APP, app.name, 'admin', function(err, flag) {
|
||||
if (err) return done(err);
|
||||
|
||||
expect(flag).to.eql(true);
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('listByPrincipalType', function() {
|
||||
|
@ -1019,18 +1009,18 @@ describe('role model', function() {
|
|||
Role.create({name: uniqueRoleName}, function(err, role) {
|
||||
if (err) return done(err);
|
||||
role.principals.create({principalType: principalType, principalId: model.id},
|
||||
function(err, p) {
|
||||
if (err) return done(err);
|
||||
var pluralName = Model.pluralModelName.toLowerCase();
|
||||
role[pluralName](function(err, models) {
|
||||
function(err, p) {
|
||||
if (err) return done(err);
|
||||
assert.equal(models.length, 1);
|
||||
var pluralName = Model.pluralModelName.toLowerCase();
|
||||
role[pluralName](function(err, models) {
|
||||
if (err) return done(err);
|
||||
assert.equal(models.length, 1);
|
||||
|
||||
if (++runs === mappings.length) {
|
||||
done();
|
||||
}
|
||||
if (++runs === mappings.length) {
|
||||
done();
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -1052,13 +1042,13 @@ describe('role model', function() {
|
|||
// Create models
|
||||
function(next) {
|
||||
Model.create([
|
||||
{name: 'test', email: 'x@y.com', password: 'foobar'},
|
||||
{name: 'test2', email: 'f@v.com', password: 'bargoo'},
|
||||
{name: 'test3', email: 'd@t.com', password: 'bluegoo'}],
|
||||
function(err, models) {
|
||||
if (err) return next(err);
|
||||
next(null, models);
|
||||
});
|
||||
{name: 'test', email: 'x@y.com', password: 'foobar'},
|
||||
{name: 'test2', email: 'f@v.com', password: 'bargoo'},
|
||||
{name: 'test3', email: 'd@t.com', password: 'bluegoo'}],
|
||||
function(err, models) {
|
||||
if (err) return next(err);
|
||||
next(null, models);
|
||||
});
|
||||
},
|
||||
|
||||
// Create Roles
|
||||
|
@ -1066,12 +1056,12 @@ describe('role model', function() {
|
|||
var uniqueRoleName = 'testRoleFor' + principalType;
|
||||
var otherUniqueRoleName = 'otherTestRoleFor' + principalType;
|
||||
Role.create([
|
||||
{name: uniqueRoleName},
|
||||
{name: otherUniqueRoleName}],
|
||||
function(err, roles) {
|
||||
if (err) return next(err);
|
||||
next(null, models, roles);
|
||||
});
|
||||
{name: uniqueRoleName},
|
||||
{name: otherUniqueRoleName}],
|
||||
function(err, roles) {
|
||||
if (err) return next(err);
|
||||
next(null, models, roles);
|
||||
});
|
||||
},
|
||||
|
||||
// Create principles
|
||||
|
@ -1120,19 +1110,19 @@ describe('role model', function() {
|
|||
Role.create({name: 'userRole'}, function(err, role) {
|
||||
if (err) return done(err);
|
||||
role.principals.create({principalType: RoleMapping.USER, principalId: user.id},
|
||||
function(err, p) {
|
||||
if (err) return done(err);
|
||||
var query = {fields: ['id', 'name']};
|
||||
sandbox.spy(User, 'find');
|
||||
role.users(query, function(err, users) {
|
||||
function(err, p) {
|
||||
if (err) return done(err);
|
||||
assert.equal(users.length, 1);
|
||||
assert.equal(users[0].id, user.id);
|
||||
assert(User.find.calledWith(query));
|
||||
var query = {fields: ['id', 'name']};
|
||||
sandbox.spy(User, 'find');
|
||||
role.users(query, function(err, users) {
|
||||
if (err) return done(err);
|
||||
assert.equal(users.length, 1);
|
||||
assert.equal(users[0].id, user.id);
|
||||
assert(User.find.calledWith(query));
|
||||
|
||||
done();
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -207,7 +207,7 @@ describe('User.password', () => {
|
|||
User.resetPassword({email: credentials.email}),
|
||||
waitForEvent(User, 'resetPasswordRequest'),
|
||||
])
|
||||
.spread((reset, info) => resetToken = info.accessToken);
|
||||
.spread((reset, info) => resetToken = info.accessToken);
|
||||
}
|
||||
|
||||
function changeName(token) {
|
||||
|
|
|
@ -313,6 +313,6 @@ describe('users - integration', function() {
|
|||
User.resetPassword({email: email}),
|
||||
waitForEvent(app.models.User, 'resetPasswordRequest'),
|
||||
])
|
||||
.spread((reset, info) => info);
|
||||
.spread((reset, info) => info);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -216,7 +216,7 @@ describe('User', function() {
|
|||
|
||||
it('Requires a unique username', function(done) {
|
||||
User.create({email: 'a@b.com', username: 'abc', password: 'foobar'}, function() {
|
||||
User.create({email: 'b@b.com', username: 'abc', password: 'batbaz'}, function(err) {
|
||||
User.create({email: 'b@b.com', username: 'abc', password: 'batbaz'}, function(err) {
|
||||
assert(err, 'should error because the username is not unique!');
|
||||
|
||||
done();
|
||||
|
@ -270,7 +270,7 @@ describe('User', function() {
|
|||
});
|
||||
},
|
||||
function(next) {
|
||||
User.findById(usersId, function(err, userFound) {
|
||||
User.findById(usersId, function(err, userFound) {
|
||||
if (err) return next(err);
|
||||
expect(userFound).to.equal(null);
|
||||
AccessToken.find({where: {userId: usersId}}, function(err, tokens) {
|
||||
|
@ -322,7 +322,7 @@ describe('User', function() {
|
|||
});
|
||||
},
|
||||
function(next) {
|
||||
User.find({where: {name: 'myname'}}, function(err, userFound) {
|
||||
User.find({where: {name: 'myname'}}, function(err, userFound) {
|
||||
if (err) return next(err);
|
||||
expect(userFound.length).to.equal(0);
|
||||
AccessToken.find({where: {userId: {inq: userIds}}}, function(err, tokens) {
|
||||
|
@ -471,7 +471,7 @@ describe('User', function() {
|
|||
it('accepts passwords that are exactly 72 characters long', function(done) {
|
||||
User.create({email: 'b@c.com', password: pass72Char}, function(err, user) {
|
||||
if (err) return done(err);
|
||||
User.findById(user.pk, function(err, userFound) {
|
||||
User.findById(user.pk, function(err, userFound) {
|
||||
if (err) return done(err);
|
||||
assert(userFound);
|
||||
done();
|
||||
|
@ -867,21 +867,21 @@ describe('User', function() {
|
|||
});
|
||||
|
||||
it('allows login with password too long but created in old LB version',
|
||||
function(done) {
|
||||
var bcrypt = require('bcryptjs');
|
||||
var longPassword = new Array(80).join('a');
|
||||
var oldHash = bcrypt.hashSync(longPassword, bcrypt.genSaltSync(1));
|
||||
function(done) {
|
||||
var bcrypt = require('bcryptjs');
|
||||
var longPassword = new Array(80).join('a');
|
||||
var oldHash = bcrypt.hashSync(longPassword, bcrypt.genSaltSync(1));
|
||||
|
||||
User.create({email: 'b@c.com', password: oldHash}, function(err) {
|
||||
if (err) return done(err);
|
||||
User.login({email: 'b@c.com', password: longPassword}, function(err, accessToken) {
|
||||
User.create({email: 'b@c.com', password: oldHash}, function(err) {
|
||||
if (err) return done(err);
|
||||
assert(accessToken.id);
|
||||
// we are logged in, the test passed
|
||||
done();
|
||||
User.login({email: 'b@c.com', password: longPassword}, function(err, accessToken) {
|
||||
if (err) return done(err);
|
||||
assert(accessToken.id);
|
||||
// we are logged in, the test passed
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function assertGoodToken(accessToken, user) {
|
||||
|
@ -919,21 +919,21 @@ describe('User', function() {
|
|||
});
|
||||
|
||||
it('requires valid and complete credentials for email verification - promise variant',
|
||||
function(done) {
|
||||
User.login({email: validCredentialsEmail})
|
||||
.then(function(accessToken) {
|
||||
done();
|
||||
})
|
||||
.catch(function(err) {
|
||||
// strongloop/loopback#931
|
||||
// error message should be "login failed" and not "login failed as the email has not been verified"
|
||||
assert(err && !/verified/.test(err.message),
|
||||
'expecting "login failed" error message, received: "' + err.message + '"');
|
||||
assert.equal(err.code, 'LOGIN_FAILED');
|
||||
assert.equal(err.details, undefined);
|
||||
done();
|
||||
function(done) {
|
||||
User.login({email: validCredentialsEmail})
|
||||
.then(function(accessToken) {
|
||||
done();
|
||||
})
|
||||
.catch(function(err) {
|
||||
// strongloop/loopback#931
|
||||
// error message should be "login failed" and not "login failed as the email has not been verified"
|
||||
assert(err && !/verified/.test(err.message),
|
||||
'expecting "login failed" error message, received: "' + err.message + '"');
|
||||
assert.equal(err.code, 'LOGIN_FAILED');
|
||||
assert.equal(err.details, undefined);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('does not login a user with unverified email but provides userId', function() {
|
||||
return User.login(validCredentials).then(
|
||||
|
@ -1234,21 +1234,21 @@ describe('User', function() {
|
|||
});
|
||||
|
||||
it('Logout a user by providing the current accessToken id (using node) - promise variant',
|
||||
function(done) {
|
||||
login(logout);
|
||||
function(done) {
|
||||
login(logout);
|
||||
|
||||
function login(fn) {
|
||||
User.login(validCredentials, fn);
|
||||
}
|
||||
function login(fn) {
|
||||
User.login(validCredentials, fn);
|
||||
}
|
||||
|
||||
function logout(err, accessToken) {
|
||||
User.logout(accessToken.id)
|
||||
.then(function() {
|
||||
verify(accessToken.id, done);
|
||||
})
|
||||
.catch(done(err));
|
||||
}
|
||||
});
|
||||
function logout(err, accessToken) {
|
||||
User.logout(accessToken.id)
|
||||
.then(function() {
|
||||
verify(accessToken.id, done);
|
||||
})
|
||||
.catch(done(err));
|
||||
}
|
||||
});
|
||||
|
||||
it('Logout a user by providing the current accessToken id (over rest)', function(done) {
|
||||
login(logout);
|
||||
|
@ -2056,23 +2056,23 @@ describe('User', function() {
|
|||
});
|
||||
|
||||
it('verifies that verifyOptions.templateFn receives verifyOptions.verificationToken',
|
||||
function() {
|
||||
let actualVerificationToken;
|
||||
function() {
|
||||
let actualVerificationToken;
|
||||
|
||||
Object.assign(verifyOptions, {
|
||||
redirect: '#/some-path?a=1&b=2',
|
||||
templateFn: (verifyOptions, cb) => {
|
||||
actualVerificationToken = verifyOptions.verificationToken;
|
||||
cb(null, 'dummy body');
|
||||
},
|
||||
});
|
||||
|
||||
return user.verify(verifyOptions)
|
||||
.then(() => actualVerificationToken)
|
||||
.then(token => {
|
||||
expect(token).to.exist();
|
||||
Object.assign(verifyOptions, {
|
||||
redirect: '#/some-path?a=1&b=2',
|
||||
templateFn: (verifyOptions, cb) => {
|
||||
actualVerificationToken = verifyOptions.verificationToken;
|
||||
cb(null, 'dummy body');
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
return user.verify(verifyOptions)
|
||||
.then(() => actualVerificationToken)
|
||||
.then(token => {
|
||||
expect(token).to.exist();
|
||||
});
|
||||
});
|
||||
|
||||
it('forwards the "options" argument to user.save() ' +
|
||||
'when adding verification token', function() {
|
||||
|
@ -2722,10 +2722,10 @@ describe('User', function() {
|
|||
function(err, accessToken2) {
|
||||
if (err) return next(err);
|
||||
User.login({email: 'user3@example.com', password: 'u3pass'},
|
||||
function(err, accessToken3) {
|
||||
if (err) return next(err);
|
||||
next();
|
||||
});
|
||||
function(err, accessToken3) {
|
||||
if (err) return next(err);
|
||||
next();
|
||||
});
|
||||
});
|
||||
});
|
||||
},
|
||||
|
@ -2760,12 +2760,12 @@ describe('User', function() {
|
|||
async.series([
|
||||
function createSpecialUser(next) {
|
||||
User.create(
|
||||
{email: 'special@example.com', password: 'pass1', name: 'Special'},
|
||||
function(err, specialInstance) {
|
||||
if (err) return next(err);
|
||||
userSpecial = specialInstance;
|
||||
next();
|
||||
});
|
||||
{email: 'special@example.com', password: 'pass1', name: 'Special'},
|
||||
function(err, specialInstance) {
|
||||
if (err) return next(err);
|
||||
userSpecial = specialInstance;
|
||||
next();
|
||||
});
|
||||
},
|
||||
function loginSpecialUser(next) {
|
||||
User.login({email: 'special@example.com', password: 'pass1'}, function(err, ats) {
|
||||
|
@ -2775,11 +2775,11 @@ describe('User', function() {
|
|||
},
|
||||
function updateSpecialUser(next) {
|
||||
User.updateAll(
|
||||
{name: 'Special'},
|
||||
{email: 'superspecial@example.com'}, function(err, info) {
|
||||
if (err) return next(err);
|
||||
next();
|
||||
});
|
||||
{name: 'Special'},
|
||||
{email: 'superspecial@example.com'}, function(err, info) {
|
||||
if (err) return next(err);
|
||||
next();
|
||||
});
|
||||
},
|
||||
function verifyTokensOfSpecialUser(next) {
|
||||
AccessToken.find({where: {userId: userSpecial.pk}}, function(err, tokens1) {
|
||||
|
@ -2942,48 +2942,48 @@ describe('User', function() {
|
|||
beforeEach(createOriginalUser);
|
||||
|
||||
it('sets verification to false after email update if verification is required',
|
||||
function(done) {
|
||||
User.settings.emailVerificationRequired = true;
|
||||
async.series([
|
||||
function updateUser(next) {
|
||||
userInstance.updateAttribute('email', NEW_EMAIL, function(err, info) {
|
||||
if (err) return next(err);
|
||||
assert.equal(info.email, NEW_EMAIL);
|
||||
next();
|
||||
});
|
||||
},
|
||||
function findUser(next) {
|
||||
User.findById(userInstance.pk, function(err, info) {
|
||||
if (err) return next(err);
|
||||
assert.equal(info.email, NEW_EMAIL);
|
||||
assert.equal(info.emailVerified, false);
|
||||
next();
|
||||
});
|
||||
},
|
||||
], done);
|
||||
});
|
||||
function(done) {
|
||||
User.settings.emailVerificationRequired = true;
|
||||
async.series([
|
||||
function updateUser(next) {
|
||||
userInstance.updateAttribute('email', NEW_EMAIL, function(err, info) {
|
||||
if (err) return next(err);
|
||||
assert.equal(info.email, NEW_EMAIL);
|
||||
next();
|
||||
});
|
||||
},
|
||||
function findUser(next) {
|
||||
User.findById(userInstance.pk, function(err, info) {
|
||||
if (err) return next(err);
|
||||
assert.equal(info.email, NEW_EMAIL);
|
||||
assert.equal(info.emailVerified, false);
|
||||
next();
|
||||
});
|
||||
},
|
||||
], done);
|
||||
});
|
||||
|
||||
it('leaves verification as is after email update if verification is not required',
|
||||
function(done) {
|
||||
User.settings.emailVerificationRequired = false;
|
||||
async.series([
|
||||
function updateUser(next) {
|
||||
userInstance.updateAttribute('email', NEW_EMAIL, function(err, info) {
|
||||
if (err) return next(err);
|
||||
assert.equal(info.email, NEW_EMAIL);
|
||||
next();
|
||||
});
|
||||
},
|
||||
function findUser(next) {
|
||||
User.findById(userInstance.pk, function(err, info) {
|
||||
if (err) return next(err);
|
||||
assert.equal(info.email, NEW_EMAIL);
|
||||
assert.equal(info.emailVerified, true);
|
||||
next();
|
||||
});
|
||||
},
|
||||
], done);
|
||||
});
|
||||
function(done) {
|
||||
User.settings.emailVerificationRequired = false;
|
||||
async.series([
|
||||
function updateUser(next) {
|
||||
userInstance.updateAttribute('email', NEW_EMAIL, function(err, info) {
|
||||
if (err) return next(err);
|
||||
assert.equal(info.email, NEW_EMAIL);
|
||||
next();
|
||||
});
|
||||
},
|
||||
function findUser(next) {
|
||||
User.findById(userInstance.pk, function(err, info) {
|
||||
if (err) return next(err);
|
||||
assert.equal(info.email, NEW_EMAIL);
|
||||
assert.equal(info.emailVerified, true);
|
||||
next();
|
||||
});
|
||||
},
|
||||
], done);
|
||||
});
|
||||
|
||||
it('should not set verification to false after something other than email is updated',
|
||||
function(done) {
|
||||
|
@ -3023,39 +3023,39 @@ describe('User', function() {
|
|||
|
||||
describe('password reset with/without email verification', function() {
|
||||
it('allows resetPassword by email if email verification is required and done',
|
||||
function(done) {
|
||||
User.settings.emailVerificationRequired = true;
|
||||
var email = validCredentialsEmailVerified.email;
|
||||
function(done) {
|
||||
User.settings.emailVerificationRequired = true;
|
||||
var email = validCredentialsEmailVerified.email;
|
||||
|
||||
User.resetPassword({email: email}, function(err, info) {
|
||||
if (err) return done(err);
|
||||
done();
|
||||
User.resetPassword({email: email}, function(err, info) {
|
||||
if (err) return done(err);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('disallows resetPassword by email if email verification is required and not done',
|
||||
function(done) {
|
||||
User.settings.emailVerificationRequired = true;
|
||||
var email = validCredentialsEmail;
|
||||
function(done) {
|
||||
User.settings.emailVerificationRequired = true;
|
||||
var email = validCredentialsEmail;
|
||||
|
||||
User.resetPassword({email: email}, function(err) {
|
||||
assert(err);
|
||||
assert.equal(err.code, 'RESET_FAILED_EMAIL_NOT_VERIFIED');
|
||||
assert.equal(err.statusCode, 401);
|
||||
done();
|
||||
User.resetPassword({email: email}, function(err) {
|
||||
assert(err);
|
||||
assert.equal(err.code, 'RESET_FAILED_EMAIL_NOT_VERIFIED');
|
||||
assert.equal(err.statusCode, 401);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('allows resetPassword by email if email verification is not required',
|
||||
function(done) {
|
||||
User.settings.emailVerificationRequired = false;
|
||||
var email = validCredentialsEmail;
|
||||
function(done) {
|
||||
User.settings.emailVerificationRequired = false;
|
||||
var email = validCredentialsEmail;
|
||||
|
||||
User.resetPassword({email: email}, function(err) {
|
||||
if (err) return done(err);
|
||||
done();
|
||||
User.resetPassword({email: email}, function(err) {
|
||||
if (err) return done(err);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('ctor', function() {
|
||||
|
@ -3085,6 +3085,6 @@ describe('User', function() {
|
|||
User.resetPassword({email: email}),
|
||||
waitForEvent(User, 'resetPasswordRequest'),
|
||||
])
|
||||
.spread((reset, info) => info);
|
||||
.spread((reset, info) => info);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -96,7 +96,7 @@ module.exports = function defineModelTestsWithDataSource(options) {
|
|||
var foo = new User({domain: 'www'});
|
||||
var bar = new User({domain: 'billing'});
|
||||
var bat = new User({domain: 'admin'});
|
||||
assert(foo.isValid() === false);
|
||||
assert(foo.isValid() === false);
|
||||
assert(bar.isValid() === false);
|
||||
assert(bat.isValid() === false);
|
||||
assert(foo.errors.domain, 'model should have a domain error');
|
||||
|
@ -139,13 +139,13 @@ module.exports = function defineModelTestsWithDataSource(options) {
|
|||
|
||||
describe('Model.create([data], [callback])', function() {
|
||||
it('Create an instance of Model with given data and save to the attached data source',
|
||||
function(done) {
|
||||
User.create({first: 'Joe', last: 'Bob'}, function(err, user) {
|
||||
assert(user instanceof User);
|
||||
function(done) {
|
||||
User.create({first: 'Joe', last: 'Bob'}, function(err, user) {
|
||||
assert(user instanceof User);
|
||||
|
||||
done();
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('model.save([options], [callback])', function() {
|
||||
|
|
Loading…
Reference in New Issue