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