Update eslint and eslint-config to latest

This commit is contained in:
Miroslav Bajtoš 2017-12-12 09:33:15 +01:00
parent fdb453943a
commit 73cc950b1b
No known key found for this signature in database
GPG Key ID: 6F2304BA9361C7E3
32 changed files with 1277 additions and 1287 deletions

View File

@ -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');

View File

@ -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;
};

View File

@ -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));

View File

@ -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);

View File

@ -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');

View File

@ -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.');
}

View File

@ -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,
},
];

View File

@ -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',

View File

@ -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({

View File

@ -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

View File

@ -68,14 +68,14 @@
"cookie-parser": "^1.3.4",
"coveralls": "^2.11.15",
"dirty-chai": "^1.2.2",
"eslint-config-loopback": "^8.0.0",
"eslint-config-loopback": "^10.0.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",

View File

@ -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,

View File

@ -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)

View File

@ -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) {

View File

@ -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() {

View File

@ -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);
});
});

View File

@ -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) {

View File

@ -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) {

View File

@ -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) {

View File

@ -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');
});
});
});

View File

@ -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);
}
});

View File

@ -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;
@ -1517,17 +1517,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();
});
});
});
});
});

View File

@ -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);
});
}

View File

@ -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) {

View File

@ -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);

View File

@ -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);
});
});
});
});

View File

@ -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) {

View File

@ -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();
});
});
});
});
});
});

View File

@ -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) {

View File

@ -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);
}
});

View File

@ -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);
}
});

View File

@ -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() {