Use eslint with loopback config
Drop jshint and jscs in favour of eslint. Fix style violations. While we are at this, reduce the max line length from 150 to 100.
This commit is contained in:
parent
2a86e9535b
commit
f9702b0ace
|
@ -0,0 +1,2 @@
|
|||
dist
|
||||
coverage
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"extends": "loopback",
|
||||
"rules": {
|
||||
"max-len": ["error", 100, 4, {
|
||||
"ignoreComments": true,
|
||||
"ignoreUrls": true,
|
||||
"ignorePattern": "^\\s*var\\s.+=\\s*(require\\s*\\()|(/)"
|
||||
}]
|
||||
}
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
node_modules
|
34
.jshintrc
34
.jshintrc
|
@ -1,34 +0,0 @@
|
|||
{
|
||||
"node": true,
|
||||
"camelcase": true,
|
||||
"eqnull": true,
|
||||
"indent": 2,
|
||||
"undef": true,
|
||||
"quotmark": "single",
|
||||
"newcap": true,
|
||||
"nonew": true,
|
||||
"sub": true,
|
||||
"laxcomma": true,
|
||||
"laxbreak": true,
|
||||
"globals": {
|
||||
/* mocha */
|
||||
"after": true,
|
||||
"afterEach": true,
|
||||
"assert": true,
|
||||
"before": true,
|
||||
"beforeEach": true,
|
||||
"context": true,
|
||||
"describe": true,
|
||||
"expect": true,
|
||||
"it": true,
|
||||
|
||||
/* loopback */
|
||||
"app": true,
|
||||
"assertValidDataSource": true,
|
||||
"GeoPoint": true,
|
||||
"loopback": true,
|
||||
"memoryConnector": true,
|
||||
"request": true,
|
||||
"TaskEmitter": true
|
||||
}
|
||||
}
|
98
Gruntfile.js
98
Gruntfile.js
|
@ -1,6 +1,5 @@
|
|||
/*global module:false*/
|
||||
module.exports = function(grunt) {
|
||||
|
||||
// Do not report warnings from unit-tests exercising deprecated paths
|
||||
process.env.NO_DEPRECATION = 'loopback';
|
||||
|
||||
|
@ -18,58 +17,59 @@ module.exports = function(grunt) {
|
|||
// Task configuration.
|
||||
uglify: {
|
||||
options: {
|
||||
banner: '<%= banner %>'
|
||||
banner: '<%= banner %>',
|
||||
},
|
||||
dist: {
|
||||
files: {
|
||||
'dist/loopback.min.js': ['dist/loopback.js']
|
||||
}
|
||||
}
|
||||
'dist/loopback.min.js': ['dist/loopback.js'],
|
||||
},
|
||||
jshint: {
|
||||
options: {
|
||||
jshintrc: true
|
||||
},
|
||||
},
|
||||
eslint: {
|
||||
gruntfile: {
|
||||
src: 'Gruntfile.js'
|
||||
src: 'Gruntfile.js',
|
||||
},
|
||||
lib: {
|
||||
src: ['lib/**/*.js']
|
||||
src: ['lib/**/*.js'],
|
||||
},
|
||||
common: {
|
||||
src: ['common/**/*.js']
|
||||
src: ['common/**/*.js'],
|
||||
},
|
||||
browser: {
|
||||
src: ['browser/**/*.js']
|
||||
src: ['browser/**/*.js'],
|
||||
},
|
||||
server: {
|
||||
src: ['server/**/*.js']
|
||||
src: ['server/**/*.js'],
|
||||
},
|
||||
test: {
|
||||
src: ['test/**/*.js']
|
||||
}
|
||||
src: ['test/**/*.js'],
|
||||
},
|
||||
jscs: {
|
||||
gruntfile: 'Gruntfile.js',
|
||||
lib: ['lib/**/*.js'],
|
||||
common: ['common/**/*.js'],
|
||||
server: ['server/**/*.js'],
|
||||
browser: ['browser/**/*.js'],
|
||||
test: ['test/**/*.js']
|
||||
},
|
||||
watch: {
|
||||
gruntfile: {
|
||||
files: '<%= jshint.gruntfile.src %>',
|
||||
tasks: ['jshint:gruntfile']
|
||||
files: '<%= eslint.gruntfile.src %>',
|
||||
tasks: ['eslint:gruntfile'],
|
||||
},
|
||||
browser: {
|
||||
files: ['<%= eslint.browser.src %>'],
|
||||
tasks: ['eslint:browser'],
|
||||
},
|
||||
common: {
|
||||
files: ['<%= eslint.common.src %>'],
|
||||
tasks: ['eslint:common'],
|
||||
},
|
||||
lib: {
|
||||
files: ['<%= jshint.lib.src %>'],
|
||||
tasks: ['jshint:lib']
|
||||
files: ['<%= eslint.lib.src %>'],
|
||||
tasks: ['eslint:lib'],
|
||||
},
|
||||
server: {
|
||||
files: ['<%= eslint.server.src %>'],
|
||||
tasks: ['eslint:server'],
|
||||
},
|
||||
test: {
|
||||
files: ['<%= jshint.test.src %>'],
|
||||
tasks: ['jshint:test']
|
||||
}
|
||||
files: ['<%= eslint.test.src %>'],
|
||||
tasks: ['eslint:test'],
|
||||
},
|
||||
},
|
||||
browserify: {
|
||||
dist: {
|
||||
|
@ -78,24 +78,24 @@ module.exports = function(grunt) {
|
|||
},
|
||||
options: {
|
||||
ignore: ['nodemailer', 'passport', 'bcrypt'],
|
||||
standalone: 'loopback'
|
||||
}
|
||||
}
|
||||
standalone: 'loopback',
|
||||
},
|
||||
},
|
||||
},
|
||||
mochaTest: {
|
||||
'unit': {
|
||||
src: 'test/*.js',
|
||||
options: {
|
||||
reporter: 'dot',
|
||||
}
|
||||
},
|
||||
},
|
||||
'unit-xml': {
|
||||
src: 'test/*.js',
|
||||
options: {
|
||||
reporter: 'xunit',
|
||||
captureFile: 'xunit.xml'
|
||||
}
|
||||
}
|
||||
captureFile: 'xunit.xml',
|
||||
},
|
||||
},
|
||||
},
|
||||
karma: {
|
||||
'unit-once': {
|
||||
|
@ -109,7 +109,7 @@ module.exports = function(grunt) {
|
|||
|
||||
// CI friendly test output
|
||||
junitReporter: {
|
||||
outputFile: 'karma-xunit.xml'
|
||||
outputFile: 'karma-xunit.xml',
|
||||
},
|
||||
|
||||
browserify: {
|
||||
|
@ -117,8 +117,8 @@ module.exports = function(grunt) {
|
|||
// Fatal error: Maximum call stack size exceeded
|
||||
debug: false,
|
||||
// Disable watcher, grunt will exit after the first run
|
||||
watch: false
|
||||
}
|
||||
watch: false,
|
||||
},
|
||||
},
|
||||
unit: {
|
||||
configFile: 'test/karma.conf.js',
|
||||
|
@ -134,7 +134,7 @@ module.exports = function(grunt) {
|
|||
// list of files / patterns to load in the browser
|
||||
files: [
|
||||
'test/e2e/remote-connector.e2e.js',
|
||||
'test/e2e/replication.e2e.js'
|
||||
'test/e2e/replication.e2e.js',
|
||||
],
|
||||
|
||||
// list of files to exclude
|
||||
|
@ -171,7 +171,7 @@ module.exports = function(grunt) {
|
|||
// - PhantomJS
|
||||
// - IE (only Windows)
|
||||
browsers: [
|
||||
'Chrome'
|
||||
'Chrome',
|
||||
],
|
||||
|
||||
// If browser does not capture in given timeout [ms], kill it
|
||||
|
@ -190,7 +190,7 @@ module.exports = function(grunt) {
|
|||
'passport-local',
|
||||
'superagent',
|
||||
'supertest',
|
||||
'bcrypt'
|
||||
'bcrypt',
|
||||
],
|
||||
// transform: ['coffeeify'],
|
||||
// debug: true,
|
||||
|
@ -199,19 +199,18 @@ module.exports = function(grunt) {
|
|||
},
|
||||
|
||||
// Add browserify to preprocessors
|
||||
preprocessors: {'test/e2e/*': ['browserify']}
|
||||
}
|
||||
}
|
||||
}
|
||||
preprocessors: { 'test/e2e/*': ['browserify'] },
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
});
|
||||
|
||||
// These plugins provide necessary tasks.
|
||||
grunt.loadNpmTasks('grunt-browserify');
|
||||
grunt.loadNpmTasks('grunt-contrib-uglify');
|
||||
grunt.loadNpmTasks('grunt-contrib-jshint');
|
||||
grunt.loadNpmTasks('grunt-eslint');
|
||||
grunt.loadNpmTasks('grunt-contrib-watch');
|
||||
grunt.loadNpmTasks('grunt-jscs');
|
||||
grunt.loadNpmTasks('grunt-karma');
|
||||
|
||||
grunt.registerTask('e2e-server', function() {
|
||||
|
@ -229,8 +228,7 @@ module.exports = function(grunt) {
|
|||
grunt.registerTask('default', ['browserify']);
|
||||
|
||||
grunt.registerTask('test', [
|
||||
'jscs',
|
||||
'jshint',
|
||||
'eslint',
|
||||
process.env.JENKINS_HOME ? 'mochaTest:unit-xml' : 'mochaTest:unit',
|
||||
'karma:unit-once']);
|
||||
|
||||
|
|
|
@ -27,7 +27,6 @@ var DEFAULT_TOKEN_LEN = 64;
|
|||
*/
|
||||
|
||||
module.exports = function(AccessToken) {
|
||||
|
||||
// Workaround for https://github.com/strongloop/loopback/issues/292
|
||||
AccessToken.definition.rawProperties.created.default =
|
||||
AccessToken.definition.properties.created.default = function() {
|
||||
|
@ -165,8 +164,7 @@ module.exports = function(AccessToken) {
|
|||
var headers = options.headers || [];
|
||||
var cookies = options.cookies || [];
|
||||
var i = 0;
|
||||
var length;
|
||||
var id;
|
||||
var length, id;
|
||||
|
||||
// https://github.com/strongloop/loopback/issues/1326
|
||||
if (options.searchDefaultTokenKeys !== false) {
|
||||
|
|
|
@ -78,7 +78,6 @@ assert(Role, 'Role model must be defined before ACL model');
|
|||
*/
|
||||
|
||||
module.exports = function(ACL) {
|
||||
|
||||
ACL.ALL = AccessContext.ALL;
|
||||
|
||||
ACL.DEFAULT = AccessContext.DEFAULT; // Not specified
|
||||
|
@ -112,7 +111,8 @@ module.exports = function(ACL) {
|
|||
score = score * 4;
|
||||
var ruleValue = rule[props[i]] || ACL.ALL;
|
||||
var requestedValue = req[props[i]] || ACL.ALL;
|
||||
var isMatchingMethodName = props[i] === 'property' && req.methodNames.indexOf(ruleValue) !== -1;
|
||||
var isMatchingMethodName = props[i] === 'property' &&
|
||||
req.methodNames.indexOf(ruleValue) !== -1;
|
||||
|
||||
var isMatchingAccessType = ruleValue === requestedValue;
|
||||
if (props[i] === 'accessType' && !isMatchingAccessType) {
|
||||
|
@ -278,7 +278,7 @@ module.exports = function(ACL) {
|
|||
principalType: acl.principalType,
|
||||
principalId: acl.principalId, // TODO: Should it be a name?
|
||||
accessType: acl.accessType || ACL.ALL,
|
||||
permission: acl.permission
|
||||
permission: acl.permission,
|
||||
}));
|
||||
}
|
||||
});
|
||||
|
@ -300,7 +300,7 @@ module.exports = function(ACL) {
|
|||
principalType: acl.principalType,
|
||||
principalId: acl.principalId,
|
||||
accessType: acl.accessType,
|
||||
permission: acl.permission
|
||||
permission: acl.permission,
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
@ -327,7 +327,8 @@ module.exports = function(ACL) {
|
|||
property = property || ACL.ALL;
|
||||
var propertyQuery = (property === ACL.ALL) ? undefined : { inq: [property, ACL.ALL] };
|
||||
accessType = accessType || ACL.ALL;
|
||||
var accessTypeQuery = (accessType === ACL.ALL) ? undefined : {inq: [accessType, ACL.ALL, ACL.EXECUTE]};
|
||||
var accessTypeQuery = (accessType === ACL.ALL) ? undefined :
|
||||
{ inq: [accessType, ACL.ALL, ACL.EXECUTE] };
|
||||
|
||||
var req = new AccessRequest(model, property, accessType);
|
||||
|
||||
|
@ -485,7 +486,7 @@ module.exports = function(ACL) {
|
|||
model: model,
|
||||
property: method,
|
||||
method: method,
|
||||
modelId: modelId
|
||||
modelId: modelId,
|
||||
});
|
||||
|
||||
this.checkAccessForContext(context, function(err, access) {
|
||||
|
@ -559,8 +560,8 @@ module.exports = function(ACL) {
|
|||
where: {
|
||||
roleId: role.id,
|
||||
principalType: principalType,
|
||||
principalId: String(principalId)
|
||||
}
|
||||
principalId: String(principalId),
|
||||
},
|
||||
}, function(err, result) {
|
||||
if (err) return cb(err);
|
||||
return cb(null, !!result);
|
||||
|
|
|
@ -65,7 +65,6 @@ function generateKey(hmacKey, algorithm, encoding) {
|
|||
*/
|
||||
|
||||
module.exports = function(Application) {
|
||||
|
||||
// Workaround for https://github.com/strongloop/loopback/issues/292
|
||||
Application.definition.rawProperties.created.default =
|
||||
Application.definition.properties.created.default = function() {
|
||||
|
@ -195,7 +194,7 @@ module.exports = function(Application) {
|
|||
if (app[keyNames[i]] === key) {
|
||||
result = {
|
||||
application: app,
|
||||
keyType: keyNames[i]
|
||||
keyType: keyNames[i],
|
||||
};
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -31,7 +31,6 @@ var deprecate = require('depd')('loopback');
|
|||
*/
|
||||
|
||||
module.exports = function(Change) {
|
||||
|
||||
/*!
|
||||
* Constants
|
||||
*/
|
||||
|
@ -154,7 +153,7 @@ module.exports = function(Change) {
|
|||
var ch = new Change({
|
||||
id: id,
|
||||
modelName: modelName,
|
||||
modelId: modelId
|
||||
modelId: modelId,
|
||||
});
|
||||
ch.debug('creating change');
|
||||
Change.updateOrCreate(ch, callback);
|
||||
|
@ -415,8 +414,8 @@ module.exports = function(Change) {
|
|||
this.find({
|
||||
where: {
|
||||
modelName: modelName,
|
||||
modelId: {inq: modelIds}
|
||||
}
|
||||
modelId: { inq: modelIds },
|
||||
},
|
||||
}, function(err, allLocalChanges) {
|
||||
if (err) return callback(err);
|
||||
var deltas = [];
|
||||
|
@ -462,7 +461,7 @@ module.exports = function(Change) {
|
|||
|
||||
callback(null, {
|
||||
deltas: deltas,
|
||||
conflicts: conflicts
|
||||
conflicts: conflicts,
|
||||
});
|
||||
});
|
||||
return callback.promise;
|
||||
|
@ -586,12 +585,11 @@ module.exports = function(Change) {
|
|||
var conflict = this;
|
||||
var SourceModel = this.SourceModel;
|
||||
var TargetModel = this.TargetModel;
|
||||
var source;
|
||||
var target;
|
||||
var source, target;
|
||||
|
||||
async.parallel([
|
||||
getSourceModel,
|
||||
getTargetModel
|
||||
getTargetModel,
|
||||
], done);
|
||||
|
||||
function getSourceModel(cb) {
|
||||
|
@ -627,12 +625,11 @@ module.exports = function(Change) {
|
|||
|
||||
Conflict.prototype.changes = function(cb) {
|
||||
var conflict = this;
|
||||
var sourceChange;
|
||||
var targetChange;
|
||||
var sourceChange, targetChange;
|
||||
|
||||
async.parallel([
|
||||
getSourceChange,
|
||||
getTargetChange
|
||||
getTargetChange,
|
||||
], done);
|
||||
|
||||
function getSourceChange(cb) {
|
||||
|
|
|
@ -16,7 +16,6 @@ var assert = require('assert');
|
|||
*/
|
||||
|
||||
module.exports = function(Checkpoint) {
|
||||
|
||||
// Workaround for https://github.com/strongloop/loopback/issues/292
|
||||
Checkpoint.definition.rawProperties.time.default =
|
||||
Checkpoint.definition.properties.time.default = function() {
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
*/
|
||||
|
||||
module.exports = function(Email) {
|
||||
|
||||
/**
|
||||
* Send an email with the given `options`.
|
||||
*
|
||||
|
|
|
@ -15,7 +15,6 @@ assert(RoleMapping, 'RoleMapping model must be defined before Role model');
|
|||
* @header Role object
|
||||
*/
|
||||
module.exports = function(Role) {
|
||||
|
||||
// Workaround for https://github.com/strongloop/loopback/issues/292
|
||||
Role.definition.rawProperties.created.default =
|
||||
Role.definition.properties.created.default = function() {
|
||||
|
@ -39,7 +38,6 @@ module.exports = function(Role) {
|
|||
|
||||
// Set up the connection to users/applications/roles once the model
|
||||
Role.once('dataSourceAttached', function(roleModel) {
|
||||
|
||||
['users', 'applications', 'roles'].forEach(function(rel) {
|
||||
/**
|
||||
* Fetch all users assigned to this role
|
||||
|
@ -64,14 +62,14 @@ module.exports = function(Role) {
|
|||
var relsToModels = {
|
||||
users: roleModel.userModel,
|
||||
applications: roleModel.applicationModel,
|
||||
roles: roleModel
|
||||
roles: roleModel,
|
||||
};
|
||||
|
||||
var ACL = loopback.ACL;
|
||||
var relsToTypes = {
|
||||
users: ACL.USER,
|
||||
applications: ACL.APP,
|
||||
roles: ACL.ROLE
|
||||
roles: ACL.ROLE,
|
||||
};
|
||||
|
||||
var model = relsToModels[rel];
|
||||
|
@ -94,7 +92,7 @@ module.exports = function(Role) {
|
|||
}
|
||||
|
||||
roleModel.roleMappingModel.find({
|
||||
where: {roleId: this.id, principalType: principalType}
|
||||
where: { roleId: this.id, principalType: principalType },
|
||||
}, function(err, mappings) {
|
||||
var ids;
|
||||
if (err) {
|
||||
|
@ -110,7 +108,6 @@ module.exports = function(Role) {
|
|||
});
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
// Special roles
|
||||
|
@ -305,7 +302,6 @@ module.exports = function(Role) {
|
|||
}
|
||||
|
||||
var inRole = context.principals.some(function(p) {
|
||||
|
||||
var principalType = p.type || undefined;
|
||||
var principalId = p.id || undefined;
|
||||
|
||||
|
@ -338,8 +334,9 @@ module.exports = function(Role) {
|
|||
var principalType = p.type || undefined;
|
||||
var principalId = p.id || undefined;
|
||||
var roleId = result.id.toString();
|
||||
var principalIdIsString = typeof principalId === 'string';
|
||||
|
||||
if (principalId !== null && principalId !== undefined && (typeof principalId !== 'string')) {
|
||||
if (principalId !== null && principalId !== undefined && !principalIdIsString) {
|
||||
principalId = principalId.toString();
|
||||
}
|
||||
|
||||
|
@ -360,7 +357,6 @@ module.exports = function(Role) {
|
|||
if (callback) callback(null, inRole);
|
||||
});
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -69,7 +69,6 @@ var debug = require('debug')('loopback:user');
|
|||
*/
|
||||
|
||||
module.exports = function(User) {
|
||||
|
||||
/**
|
||||
* Create access token for the logged in user. This method can be overridden to
|
||||
* customize how access tokens are generated
|
||||
|
@ -99,7 +98,7 @@ module.exports = function(User) {
|
|||
var userModel = this.constructor;
|
||||
ttl = Math.min(ttl || userModel.settings.ttl, userModel.settings.maxTTL);
|
||||
this.accessTokens.create({
|
||||
ttl: ttl
|
||||
ttl: ttl,
|
||||
}, cb);
|
||||
return cb.promise;
|
||||
};
|
||||
|
@ -369,11 +368,14 @@ module.exports = function(User) {
|
|||
assert(typeof options === 'object', 'options required when calling user.verify()');
|
||||
assert(options.type, 'You must supply a verification type (options.type)');
|
||||
assert(options.type === 'email', 'Unsupported verification type');
|
||||
assert(options.to || this.email, 'Must include options.to when calling user.verify() or the user must have an email property');
|
||||
assert(options.to || this.email,
|
||||
'Must include options.to when calling user.verify() ' +
|
||||
'or the user must have an email property');
|
||||
assert(options.from, 'Must include options.from when calling user.verify()');
|
||||
|
||||
options.redirect = options.redirect || '/';
|
||||
options.template = path.resolve(options.template || path.join(__dirname, '..', '..', 'templates', 'verify.ejs'));
|
||||
var defaultTemplate = path.join(__dirname, '..', '..', 'templates', 'verify.ejs');
|
||||
options.template = path.resolve(options.template || defaultTemplate);
|
||||
options.user = this;
|
||||
options.protocol = options.protocol || 'http';
|
||||
|
||||
|
@ -423,7 +425,8 @@ module.exports = function(User) {
|
|||
function sendEmail(user) {
|
||||
options.verifyHref += '&token=' + user.verificationToken;
|
||||
|
||||
options.text = options.text || 'Please verify your email by opening this link in a web browser:\n\t{href}';
|
||||
options.text = options.text || 'Please verify your email by opening ' +
|
||||
'this link in a web browser:\n\t{href}';
|
||||
|
||||
options.text = options.text.replace('{href}', options.verifyHref);
|
||||
|
||||
|
@ -551,7 +554,7 @@ module.exports = function(User) {
|
|||
UserModel.emit('resetPasswordRequest', {
|
||||
email: options.email,
|
||||
accessToken: accessToken,
|
||||
user: user
|
||||
user: user,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -636,7 +639,7 @@ module.exports = function(User) {
|
|||
{ arg: 'credentials', type: 'object', required: true, http: { source: 'body' }},
|
||||
{ arg: 'include', type: ['string'], http: { source: 'query' },
|
||||
description: 'Related objects to include in the response. ' +
|
||||
'See the description of return value for more details.'}
|
||||
'See the description of return value for more details.' },
|
||||
],
|
||||
returns: {
|
||||
arg: 'accessToken', type: 'object', root: true,
|
||||
|
@ -644,9 +647,9 @@ module.exports = function(User) {
|
|||
'The response body contains properties of the AccessToken created on login.\n' +
|
||||
'Depending on the value of `include` parameter, the body may contain ' +
|
||||
'additional properties:\n\n' +
|
||||
' - `user` - `{User}` - Data of the currently logged in user. (`include=user`)\n\n'
|
||||
' - `user` - `{User}` - Data of the currently logged in user. (`include=user`)\n\n',
|
||||
},
|
||||
http: {verb: 'post'}
|
||||
http: { verb: 'post' },
|
||||
}
|
||||
);
|
||||
|
||||
|
@ -662,10 +665,10 @@ module.exports = function(User) {
|
|||
|
||||
return tokenID;
|
||||
}, description: 'Do not supply this argument, it is automatically extracted ' +
|
||||
'from request headers.'
|
||||
}
|
||||
'from request headers.',
|
||||
},
|
||||
],
|
||||
http: {verb: 'all'}
|
||||
http: { verb: 'all' },
|
||||
}
|
||||
);
|
||||
|
||||
|
@ -676,9 +679,9 @@ module.exports = function(User) {
|
|||
accepts: [
|
||||
{ arg: 'uid', type: 'string', required: true },
|
||||
{ arg: 'token', type: 'string', required: true },
|
||||
{arg: 'redirect', type: 'string'}
|
||||
{ arg: 'redirect', type: 'string' },
|
||||
],
|
||||
http: {verb: 'get', path: '/confirm'}
|
||||
http: { verb: 'get', path: '/confirm' },
|
||||
}
|
||||
);
|
||||
|
||||
|
@ -687,9 +690,9 @@ module.exports = function(User) {
|
|||
{
|
||||
description: 'Reset password for a user with email.',
|
||||
accepts: [
|
||||
{arg: 'options', type: 'object', required: true, http: {source: 'body'}}
|
||||
{ arg: 'options', type: 'object', required: true, http: { source: 'body' }},
|
||||
],
|
||||
http: {verb: 'post', path: '/reset'}
|
||||
http: { verb: 'post', path: '/reset' },
|
||||
}
|
||||
);
|
||||
|
||||
|
@ -730,5 +733,4 @@ module.exports = function(User) {
|
|||
*/
|
||||
|
||||
User.setup();
|
||||
|
||||
};
|
||||
|
|
|
@ -3,7 +3,7 @@ var client = loopback();
|
|||
var CartItem = require('./models').CartItem;
|
||||
var remote = loopback.createDataSource({
|
||||
connector: loopback.Remote,
|
||||
url: 'http://localhost:3000'
|
||||
url: 'http://localhost:3000',
|
||||
});
|
||||
|
||||
client.model(CartItem);
|
||||
|
|
|
@ -5,7 +5,7 @@ var CartItem = exports.CartItem = loopback.PersistedModel.extend('CartItem', {
|
|||
price: Number,
|
||||
item: String,
|
||||
qty: { type: Number, default: 0 },
|
||||
cartId: Number
|
||||
cartId: Number,
|
||||
});
|
||||
|
||||
CartItem.sum = function(cartId, callback) {
|
||||
|
@ -20,15 +20,15 @@ CartItem.sum = function(cartId, callback) {
|
|||
|
||||
callback(null, total);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
CartItem.remoteMethod('sum',
|
||||
{
|
||||
accepts: { arg: 'cartId', type: 'number' },
|
||||
returns: {arg: 'total', type: 'number'}
|
||||
returns: { arg: 'total', type: 'number' },
|
||||
}
|
||||
);
|
||||
|
||||
CartItem.prototype.total = function() {
|
||||
return this.price * this.qty * 1 + this.tax;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -2,7 +2,7 @@ var loopback = require('../../');
|
|||
var server = module.exports = loopback();
|
||||
var CartItem = require('./models').CartItem;
|
||||
var memory = loopback.createDataSource({
|
||||
connector: loopback.Memory
|
||||
connector: loopback.Memory,
|
||||
});
|
||||
|
||||
server.use(loopback.rest());
|
||||
|
@ -14,7 +14,7 @@ CartItem.attachTo(memory);
|
|||
CartItem.create([
|
||||
{ item: 'red hat', qty: 6, price: 19.99, cartId: 1 },
|
||||
{ item: 'green shirt', qty: 1, price: 14.99, cartId: 1 },
|
||||
{item: 'orange pants', qty: 58, price: 9.99, cartId: 1}
|
||||
{ item: 'orange pants', qty: 58, price: 9.99, cartId: 1 },
|
||||
]);
|
||||
|
||||
CartItem.sum(1, function(err, total) {
|
||||
|
|
|
@ -4,7 +4,7 @@ var app = loopback();
|
|||
app.use(loopback.rest());
|
||||
|
||||
var schema = {
|
||||
name: String
|
||||
name: String,
|
||||
};
|
||||
|
||||
var Color = app.model('color', schema);
|
||||
|
|
|
@ -13,30 +13,31 @@ app.model(Application);
|
|||
|
||||
|
||||
var data = { pushSettings: [
|
||||
{ "platform": "apns",
|
||||
"apns": {
|
||||
"pushOptions": {
|
||||
"gateway": "gateway.sandbox.push.apple.com",
|
||||
"cert": "credentials/apns_cert_dev.pem",
|
||||
"key": "credentials/apns_key_dev.pem"
|
||||
{ 'platform': 'apns',
|
||||
'apns': {
|
||||
'pushOptions': {
|
||||
'gateway': 'gateway.sandbox.push.apple.com',
|
||||
'cert': 'credentials/apns_cert_dev.pem',
|
||||
'key': 'credentials/apns_key_dev.pem',
|
||||
},
|
||||
|
||||
"feedbackOptions": {
|
||||
"gateway": "feedback.sandbox.push.apple.com",
|
||||
"cert": "credentials/apns_cert_dev.pem",
|
||||
"key": "credentials/apns_key_dev.pem",
|
||||
"batchFeedback": true,
|
||||
"interval": 300
|
||||
}
|
||||
}}
|
||||
]}
|
||||
'feedbackOptions': {
|
||||
'gateway': 'feedback.sandbox.push.apple.com',
|
||||
'cert': 'credentials/apns_cert_dev.pem',
|
||||
'key': 'credentials/apns_key_dev.pem',
|
||||
'batchFeedback': true,
|
||||
'interval': 300,
|
||||
},
|
||||
}},
|
||||
] };
|
||||
|
||||
Application.create(data, function(err, data) {
|
||||
console.log('Created: ', data.toObject());
|
||||
});
|
||||
|
||||
|
||||
Application.register('rfeng', 'MyApp', {description: 'My first mobile application'}, function (err, result) {
|
||||
Application.register('rfeng', 'MyApp', { description: 'My first mobile application' },
|
||||
function(err, result) {
|
||||
console.log(result.toObject());
|
||||
|
||||
result.resetKeys(function(err, result) {
|
||||
|
|
|
@ -56,7 +56,7 @@ var steps = [
|
|||
|
||||
replicateSourceToTarget,
|
||||
list.bind(this, source, 'current SOURCE data'),
|
||||
list.bind(this, target, 'current TARGET data')
|
||||
list.bind(this, target, 'current TARGET data'),
|
||||
];
|
||||
|
||||
run(steps);
|
||||
|
@ -65,7 +65,7 @@ function createSomeInitialSourceData() {
|
|||
Color.create([
|
||||
{ name: 'red' },
|
||||
{ name: 'blue' },
|
||||
{name: 'green'}
|
||||
{ name: 'green' },
|
||||
]);
|
||||
}
|
||||
|
||||
|
@ -113,7 +113,7 @@ function createSomeNewSourceData() {
|
|||
Color.create([
|
||||
{ name: 'violet' },
|
||||
{ name: 'amber' },
|
||||
{name: 'olive'}
|
||||
{ name: 'olive' },
|
||||
]);
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ app.use(loopback.rest());
|
|||
var dataSource = app.dataSource('db', { adapter: 'memory' });
|
||||
|
||||
var Color = dataSource.define('color', {
|
||||
'name': String
|
||||
'name': String,
|
||||
});
|
||||
|
||||
Color.create({ name: 'red' });
|
||||
|
|
|
@ -91,7 +91,7 @@ AccessContext.permissionOrder = {
|
|||
ALLOW: 1,
|
||||
ALARM: 2,
|
||||
AUDIT: 3,
|
||||
DENY: 4
|
||||
DENY: 4,
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -326,7 +326,7 @@ app.enableAuth = function(options) {
|
|||
|
||||
app.model(Model, {
|
||||
dataSource: options.dataSource,
|
||||
public: m === 'User'
|
||||
public: m === 'User',
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -365,20 +365,19 @@ app.enableAuth = function(options) {
|
|||
} else if (allowed) {
|
||||
next();
|
||||
} else {
|
||||
|
||||
var messages = {
|
||||
403: {
|
||||
message: 'Access Denied',
|
||||
code: 'ACCESS_DENIED'
|
||||
code: 'ACCESS_DENIED',
|
||||
},
|
||||
404: {
|
||||
message: ('could not find ' + modelName + ' with id ' + modelId),
|
||||
code: 'MODEL_NOT_FOUND'
|
||||
code: 'MODEL_NOT_FOUND',
|
||||
},
|
||||
401: {
|
||||
message: 'Authorization Required',
|
||||
code: 'AUTHORIZATION_REQUIRED'
|
||||
}
|
||||
code: 'AUTHORIZATION_REQUIRED',
|
||||
},
|
||||
};
|
||||
|
||||
var e = new Error(messages[errStatusCode].message || messages[403].message);
|
||||
|
|
|
@ -47,7 +47,7 @@ module.exports = function(registry) {
|
|||
|
||||
var dataSourceTypes = {
|
||||
DB: 'db',
|
||||
MAIL: 'mail'
|
||||
MAIL: 'mail',
|
||||
};
|
||||
|
||||
registry.Email.autoAttach = dataSourceTypes.MAIL;
|
||||
|
|
|
@ -18,7 +18,6 @@ module.exports = MailConnector;
|
|||
*/
|
||||
|
||||
function MailConnector(settings) {
|
||||
|
||||
assert(typeof settings === 'object', 'cannot initialize MailConnector without a settings object');
|
||||
|
||||
var transports = settings.transports;
|
||||
|
@ -156,7 +155,8 @@ Mailer.send = function(options, fn) {
|
|||
}
|
||||
|
||||
if (transport) {
|
||||
assert(transport.sendMail, 'You must supply an Email.settings.transports containing a valid transport');
|
||||
assert(transport.sendMail,
|
||||
'You must supply an Email.settings.transports containing a valid transport');
|
||||
transport.sendMail(options, fn);
|
||||
} else {
|
||||
console.warn('Warning: No email transport specified for sending email.' +
|
||||
|
|
|
@ -32,7 +32,7 @@ var middlewareModules = {
|
|||
'favicon': 'serve-favicon',
|
||||
'directory': 'serve-index',
|
||||
// 'static': 'serve-static',
|
||||
'vhost': 'vhost'
|
||||
'vhost': 'vhost',
|
||||
};
|
||||
|
||||
middlewares.bodyParser = safeRequire('body-parser');
|
||||
|
|
|
@ -52,17 +52,17 @@ loopback.registry = new Registry();
|
|||
|
||||
Object.defineProperties(loopback, {
|
||||
Model: {
|
||||
get: function() { return this.registry.getModel('Model'); }
|
||||
get: function() { return this.registry.getModel('Model'); },
|
||||
},
|
||||
PersistedModel: {
|
||||
get: function() { return this.registry.getModel('PersistedModel'); }
|
||||
get: function() { return this.registry.getModel('PersistedModel'); },
|
||||
},
|
||||
defaultDataSources: {
|
||||
get: function() { return this.registry.defaultDataSources; }
|
||||
get: function() { return this.registry.defaultDataSources; },
|
||||
},
|
||||
modelBuilder: {
|
||||
get: function() { return this.registry.modelBuilder; }
|
||||
}
|
||||
get: function() { return this.registry.modelBuilder; },
|
||||
},
|
||||
});
|
||||
|
||||
/*!
|
||||
|
@ -213,7 +213,7 @@ loopback.template = function(file) {
|
|||
var templates = this._templates || (this._templates = {});
|
||||
var str = templates[file] || (templates[file] = fs.readFileSync(file, 'utf8'));
|
||||
return ejs.compile(str, {
|
||||
filename: file
|
||||
filename: file,
|
||||
});
|
||||
};
|
||||
|
||||
|
|
57
lib/model.js
57
lib/model.js
|
@ -7,7 +7,6 @@ var SharedClass = require('strong-remoting').SharedClass;
|
|||
var extend = require('util')._extend;
|
||||
|
||||
module.exports = function(registry) {
|
||||
|
||||
/**
|
||||
* The base class for **all models**.
|
||||
*
|
||||
|
@ -177,12 +176,12 @@ module.exports = function(registry) {
|
|||
var idDesc = ModelCtor.modelName + ' id';
|
||||
ModelCtor.sharedCtor.accepts = [
|
||||
{ arg: 'id', type: 'any', required: true, http: { source: 'path' },
|
||||
description: idDesc}
|
||||
description: idDesc },
|
||||
// {arg: 'instance', type: 'object', http: {source: 'body'}}
|
||||
];
|
||||
|
||||
ModelCtor.sharedCtor.http = [
|
||||
{path: '/:id'}
|
||||
{ path: '/:id' },
|
||||
];
|
||||
|
||||
ModelCtor.sharedCtor.returns = { root: true };
|
||||
|
@ -227,7 +226,6 @@ module.exports = function(registry) {
|
|||
|
||||
// resolve relation functions
|
||||
sharedClass.resolve(function resolver(define) {
|
||||
|
||||
var relations = ModelCtor.relations || {};
|
||||
|
||||
// get the relations
|
||||
|
@ -250,9 +248,11 @@ module.exports = function(registry) {
|
|||
|
||||
// handle scopes
|
||||
var scopes = ModelCtor.scopes || {};
|
||||
/* eslint-disable one-var */
|
||||
for (var scopeName in scopes) {
|
||||
ModelCtor.scopeRemoting(scopeName, scopes[scopeName], define);
|
||||
}
|
||||
/* eslint-enable one-var */
|
||||
});
|
||||
|
||||
return ModelCtor;
|
||||
|
@ -307,7 +307,7 @@ module.exports = function(registry) {
|
|||
sharedMethod: sharedMethod,
|
||||
modelId: modelId,
|
||||
accessType: this._getAccessTypeForMethod(sharedMethod),
|
||||
remotingContext: ctx
|
||||
remotingContext: ctx,
|
||||
}, function(err, accessRequest) {
|
||||
if (err) return callback(err);
|
||||
callback(null, accessRequest.isAllowed());
|
||||
|
@ -446,7 +446,7 @@ module.exports = function(registry) {
|
|||
accepts: { arg: 'refresh', type: 'boolean', http: { source: 'query' }},
|
||||
accessType: 'READ',
|
||||
description: 'Fetches belongsTo relation ' + relationName + '.',
|
||||
returns: {arg: relationName, type: modelName, root: true}
|
||||
returns: { arg: relationName, type: modelName, root: true },
|
||||
}, fn);
|
||||
};
|
||||
|
||||
|
@ -472,7 +472,7 @@ module.exports = function(registry) {
|
|||
description: 'Fetches hasOne relation ' + relationName + '.',
|
||||
accessType: 'READ',
|
||||
returns: { arg: relationName, type: relation.modelTo.modelName, root: true },
|
||||
rest: {after: convertNullToNotFoundError.bind(null, toModelName)}
|
||||
rest: { after: convertNullToNotFoundError.bind(null, toModelName) },
|
||||
});
|
||||
|
||||
define('__create__' + relationName, {
|
||||
|
@ -481,7 +481,7 @@ module.exports = function(registry) {
|
|||
accepts: { arg: 'data', type: toModelName, http: { source: 'body' }},
|
||||
description: 'Creates a new instance in ' + relationName + ' of this model.',
|
||||
accessType: 'WRITE',
|
||||
returns: {arg: 'data', type: toModelName, root: true}
|
||||
returns: { arg: 'data', type: toModelName, root: true },
|
||||
});
|
||||
|
||||
define('__update__' + relationName, {
|
||||
|
@ -490,14 +490,14 @@ module.exports = function(registry) {
|
|||
accepts: { arg: 'data', type: toModelName, http: { source: 'body' }},
|
||||
description: 'Update ' + relationName + ' of this model.',
|
||||
accessType: 'WRITE',
|
||||
returns: {arg: 'data', type: toModelName, root: true}
|
||||
returns: { arg: 'data', type: toModelName, root: true },
|
||||
});
|
||||
|
||||
define('__destroy__' + relationName, {
|
||||
isStatic: false,
|
||||
http: { verb: 'delete', path: '/' + pathName },
|
||||
description: 'Deletes ' + relationName + ' of this model.',
|
||||
accessType: 'WRITE'
|
||||
accessType: 'WRITE',
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -515,7 +515,7 @@ module.exports = function(registry) {
|
|||
description: 'Find a related item by id for ' + relationName + '.',
|
||||
accessType: 'READ',
|
||||
returns: { arg: 'result', type: toModelName, root: true },
|
||||
rest: {after: convertNullToNotFoundError.bind(null, toModelName)}
|
||||
rest: { after: convertNullToNotFoundError.bind(null, toModelName) },
|
||||
}, findByIdFunc);
|
||||
|
||||
var destroyByIdFunc = this.prototype['__destroyById__' + relationName];
|
||||
|
@ -527,7 +527,7 @@ module.exports = function(registry) {
|
|||
http: { source: 'path' }},
|
||||
description: 'Delete a related item by id for ' + relationName + '.',
|
||||
accessType: 'WRITE',
|
||||
returns: []
|
||||
returns: [],
|
||||
}, destroyByIdFunc);
|
||||
|
||||
var updateByIdFunc = this.prototype['__updateById__' + relationName];
|
||||
|
@ -538,11 +538,11 @@ module.exports = function(registry) {
|
|||
{ arg: 'fk', type: 'any',
|
||||
description: 'Foreign key for ' + relationName, required: true,
|
||||
http: { source: 'path' }},
|
||||
{arg: 'data', type: toModelName, http: {source: 'body'}}
|
||||
{ arg: 'data', type: toModelName, http: { source: 'body' }},
|
||||
],
|
||||
description: 'Update a related item by id for ' + relationName + '.',
|
||||
accessType: 'WRITE',
|
||||
returns: {arg: 'result', type: toModelName, root: true}
|
||||
returns: { arg: 'result', type: toModelName, root: true },
|
||||
}, updateByIdFunc);
|
||||
|
||||
if (relation.modelThrough || relation.type === 'referencesMany') {
|
||||
|
@ -563,7 +563,7 @@ module.exports = function(registry) {
|
|||
http: { source: 'path' }}].concat(accepts),
|
||||
description: 'Add a related item by id for ' + relationName + '.',
|
||||
accessType: 'WRITE',
|
||||
returns: {arg: relationName, type: modelThrough.modelName, root: true}
|
||||
returns: { arg: relationName, type: modelThrough.modelName, root: true },
|
||||
}, addFunc);
|
||||
|
||||
var removeFunc = this.prototype['__unlink__' + relationName];
|
||||
|
@ -575,7 +575,7 @@ module.exports = function(registry) {
|
|||
http: { source: 'path' }},
|
||||
description: 'Remove the ' + relationName + ' relation to an item by id.',
|
||||
accessType: 'WRITE',
|
||||
returns: []
|
||||
returns: [],
|
||||
}, removeFunc);
|
||||
|
||||
// FIXME: [rfeng] How to map a function with callback(err, true|false) to HEAD?
|
||||
|
@ -604,8 +604,8 @@ module.exports = function(registry) {
|
|||
} else {
|
||||
cb();
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
}, existsFunc);
|
||||
}
|
||||
};
|
||||
|
@ -632,7 +632,7 @@ module.exports = function(registry) {
|
|||
accepts: { arg: 'filter', type: 'object' },
|
||||
description: 'Queries ' + scopeName + ' of ' + this.modelName + '.',
|
||||
accessType: 'READ',
|
||||
returns: {arg: scopeName, type: [toModelName], root: true}
|
||||
returns: { arg: scopeName, type: [toModelName], root: true },
|
||||
});
|
||||
|
||||
define('__create__' + scopeName, {
|
||||
|
@ -641,14 +641,14 @@ module.exports = function(registry) {
|
|||
accepts: { arg: 'data', type: toModelName, http: { source: 'body' }},
|
||||
description: 'Creates a new instance in ' + scopeName + ' of this model.',
|
||||
accessType: 'WRITE',
|
||||
returns: {arg: 'data', type: toModelName, root: true}
|
||||
returns: { arg: 'data', type: toModelName, root: true },
|
||||
});
|
||||
|
||||
define('__delete__' + scopeName, {
|
||||
isStatic: isStatic,
|
||||
http: { verb: 'delete', path: '/' + pathName },
|
||||
description: 'Deletes all ' + scopeName + ' of this model.',
|
||||
accessType: 'WRITE'
|
||||
accessType: 'WRITE',
|
||||
});
|
||||
|
||||
define('__count__' + scopeName, {
|
||||
|
@ -657,9 +657,8 @@ module.exports = function(registry) {
|
|||
accepts: { arg: 'where', type: 'object', description: 'Criteria to match model instances' },
|
||||
description: 'Counts ' + scopeName + ' of ' + this.modelName + '.',
|
||||
accessType: 'READ',
|
||||
returns: {arg: 'count', type: 'number'}
|
||||
returns: { arg: 'count', type: 'number' },
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -696,8 +695,7 @@ module.exports = function(registry) {
|
|||
var paramName = options.paramName || 'nk';
|
||||
|
||||
var http = [].concat(sharedToClass.http || [])[0];
|
||||
var httpPath;
|
||||
var acceptArgs;
|
||||
var httpPath, acceptArgs;
|
||||
|
||||
if (relation.multiple) {
|
||||
httpPath = pathName + '/:' + paramName;
|
||||
|
@ -705,8 +703,8 @@ module.exports = function(registry) {
|
|||
{
|
||||
arg: paramName, type: 'any', http: { source: 'path' },
|
||||
description: 'Foreign key for ' + relation.name + '.',
|
||||
required: true
|
||||
}
|
||||
required: true,
|
||||
},
|
||||
];
|
||||
} else {
|
||||
httpPath = pathName;
|
||||
|
@ -830,9 +828,10 @@ module.exports = function(registry) {
|
|||
}
|
||||
});
|
||||
});
|
||||
|
||||
} else {
|
||||
throw new Error('Relation `' + relationName + '` does not exist for model `' + this.modelName + '`');
|
||||
var msg = 'Relation `' + relationName +
|
||||
'` does not exist for model `' + this.modelName + '`';
|
||||
throw new Error(msg);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -555,18 +555,20 @@ module.exports = function(registry) {
|
|||
setRemoting(PersistedModel, 'create', {
|
||||
description: 'Create a new instance of the model and persist it into the data source.',
|
||||
accessType: 'WRITE',
|
||||
accepts: {arg: 'data', type: 'object', description: 'Model instance data', http: {source: 'body'}},
|
||||
accepts: { arg: 'data', type: 'object', http: { source: 'body' }, description:
|
||||
'Model instance data' },
|
||||
returns: { arg: 'data', type: typeName, root: true },
|
||||
http: {verb: 'post', path: '/'}
|
||||
http: { verb: 'post', path: '/' },
|
||||
});
|
||||
|
||||
setRemoting(PersistedModel, 'upsert', {
|
||||
aliases: ['updateOrCreate'],
|
||||
description: 'Update an existing model instance or insert a new one into the data source.',
|
||||
accessType: 'WRITE',
|
||||
accepts: {arg: 'data', type: 'object', description: 'Model instance data', http: {source: 'body'}},
|
||||
accepts: { arg: 'data', type: 'object', http: { source: 'body' }, description:
|
||||
'Model instance data' },
|
||||
returns: { arg: 'data', type: typeName, root: true },
|
||||
http: {verb: 'put', path: '/'}
|
||||
http: { verb: 'put', path: '/' },
|
||||
});
|
||||
|
||||
setRemoting(PersistedModel, 'exists', {
|
||||
|
@ -576,7 +578,7 @@ module.exports = function(registry) {
|
|||
returns: { arg: 'exists', type: 'boolean' },
|
||||
http: [
|
||||
{ verb: 'get', path: '/:id/exists' },
|
||||
{verb: 'head', path: '/:id'}
|
||||
{ verb: 'head', path: '/:id' },
|
||||
],
|
||||
rest: {
|
||||
// After hook to map exists to 200/404 for HEAD
|
||||
|
@ -596,8 +598,8 @@ module.exports = function(registry) {
|
|||
} else {
|
||||
cb();
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
setRemoting(PersistedModel, 'findById', {
|
||||
|
@ -607,28 +609,30 @@ module.exports = function(registry) {
|
|||
{ arg: 'id', type: 'any', description: 'Model id', required: true,
|
||||
http: { source: 'path' }},
|
||||
{ arg: 'filter', type: 'object',
|
||||
description: 'Filter defining fields and include'}
|
||||
description: 'Filter defining fields and include' },
|
||||
],
|
||||
returns: { arg: 'data', type: typeName, root: true },
|
||||
http: { verb: 'get', path: '/:id' },
|
||||
rest: {after: convertNullToNotFoundError}
|
||||
rest: { after: convertNullToNotFoundError },
|
||||
});
|
||||
|
||||
setRemoting(PersistedModel, 'find', {
|
||||
description: 'Find all instances of the model matched by filter from the data source.',
|
||||
accessType: 'READ',
|
||||
accepts: {arg: 'filter', type: 'object', description: 'Filter defining fields, where, include, order, offset, and limit'},
|
||||
accepts: { arg: 'filter', type: 'object', description:
|
||||
'Filter defining fields, where, include, order, offset, and limit' },
|
||||
returns: { arg: 'data', type: [typeName], root: true },
|
||||
http: {verb: 'get', path: '/'}
|
||||
http: { verb: 'get', path: '/' },
|
||||
});
|
||||
|
||||
setRemoting(PersistedModel, 'findOne', {
|
||||
description: 'Find first instance of the model matched by filter from the data source.',
|
||||
accessType: 'READ',
|
||||
accepts: {arg: 'filter', type: 'object', description: 'Filter defining fields, where, include, order, offset, and limit'},
|
||||
accepts: { arg: 'filter', type: 'object', description:
|
||||
'Filter defining fields, where, include, order, offset, and limit' },
|
||||
returns: { arg: 'data', type: typeName, root: true },
|
||||
http: { verb: 'get', path: '/findOne' },
|
||||
rest: {after: convertNullToNotFoundError}
|
||||
rest: { after: convertNullToNotFoundError },
|
||||
});
|
||||
|
||||
setRemoting(PersistedModel, 'destroyAll', {
|
||||
|
@ -639,10 +643,10 @@ module.exports = function(registry) {
|
|||
arg: 'count',
|
||||
type: 'object',
|
||||
description: 'The number of instances deleted',
|
||||
root: true
|
||||
root: true,
|
||||
},
|
||||
http: { verb: 'del', path: '/' },
|
||||
shared: false
|
||||
shared: false,
|
||||
});
|
||||
|
||||
setRemoting(PersistedModel, 'updateAll', {
|
||||
|
@ -659,9 +663,9 @@ module.exports = function(registry) {
|
|||
arg: 'count',
|
||||
description: 'The number of instances updated',
|
||||
type: 'object',
|
||||
root: true
|
||||
root: true,
|
||||
},
|
||||
http: {verb: 'post', path: '/update'}
|
||||
http: { verb: 'post', path: '/update' },
|
||||
});
|
||||
|
||||
setRemoting(PersistedModel, 'deleteById', {
|
||||
|
@ -671,7 +675,7 @@ module.exports = function(registry) {
|
|||
accepts: { arg: 'id', type: 'any', description: 'Model id', required: true,
|
||||
http: { source: 'path' }},
|
||||
http: { verb: 'del', path: '/:id' },
|
||||
returns: {arg: 'count', type: 'object', root: true}
|
||||
returns: { arg: 'count', type: 'object', root: true },
|
||||
});
|
||||
|
||||
setRemoting(PersistedModel, 'count', {
|
||||
|
@ -679,7 +683,7 @@ module.exports = function(registry) {
|
|||
accessType: 'READ',
|
||||
accepts: { arg: 'where', type: 'object', description: 'Criteria to match model instances' },
|
||||
returns: { arg: 'count', type: 'number' },
|
||||
http: {verb: 'get', path: '/count'}
|
||||
http: { verb: 'get', path: '/count' },
|
||||
});
|
||||
|
||||
setRemoting(PersistedModel.prototype, 'updateAttributes', {
|
||||
|
@ -687,7 +691,7 @@ module.exports = function(registry) {
|
|||
accessType: 'WRITE',
|
||||
accepts: { arg: 'data', type: 'object', http: { source: 'body' }, description: 'An object of model property name/value pairs' },
|
||||
returns: { arg: 'data', type: typeName, root: true },
|
||||
http: {verb: 'put', path: '/'}
|
||||
http: { verb: 'put', path: '/' },
|
||||
});
|
||||
|
||||
if (options.trackChanges || options.enableRemoteReplication) {
|
||||
|
@ -697,10 +701,10 @@ module.exports = function(registry) {
|
|||
accepts: [
|
||||
{ arg: 'since', type: 'number', description: 'Find deltas since this checkpoint' },
|
||||
{ arg: 'remoteChanges', type: 'array', description: 'an array of change objects',
|
||||
http: {source: 'body'}}
|
||||
http: { source: 'body' }},
|
||||
],
|
||||
returns: { arg: 'result', type: 'object', root: true },
|
||||
http: {verb: 'post', path: '/diff'}
|
||||
http: { verb: 'post', path: '/diff' },
|
||||
});
|
||||
|
||||
setRemoting(PersistedModel, 'changes', {
|
||||
|
@ -708,11 +712,13 @@ module.exports = function(registry) {
|
|||
'Provide a filter object to reduce the number of results returned.',
|
||||
accessType: 'READ',
|
||||
accepts: [
|
||||
{arg: 'since', type: 'number', description: 'Only return changes since this checkpoint'},
|
||||
{arg: 'filter', type: 'object', description: 'Only include changes that match this filter'}
|
||||
{ arg: 'since', type: 'number', description:
|
||||
'Only return changes since this checkpoint' },
|
||||
{ arg: 'filter', type: 'object', description:
|
||||
'Only include changes that match this filter' },
|
||||
],
|
||||
returns: { arg: 'changes', type: 'array', root: true },
|
||||
http: {verb: 'get', path: '/changes'}
|
||||
http: { verb: 'get', path: '/changes' },
|
||||
});
|
||||
|
||||
setRemoting(PersistedModel, 'checkpoint', {
|
||||
|
@ -723,14 +729,14 @@ module.exports = function(registry) {
|
|||
// WRITE permissions.
|
||||
accessType: 'REPLICATE',
|
||||
returns: { arg: 'checkpoint', type: 'object', root: true },
|
||||
http: {verb: 'post', path: '/checkpoint'}
|
||||
http: { verb: 'post', path: '/checkpoint' },
|
||||
});
|
||||
|
||||
setRemoting(PersistedModel, 'currentCheckpoint', {
|
||||
description: 'Get the current checkpoint.',
|
||||
accessType: 'READ',
|
||||
returns: { arg: 'checkpoint', type: 'object', root: true },
|
||||
http: {verb: 'get', path: '/checkpoint'}
|
||||
http: { verb: 'get', path: '/checkpoint' },
|
||||
});
|
||||
|
||||
setRemoting(PersistedModel, 'createUpdates', {
|
||||
|
@ -741,14 +747,14 @@ module.exports = function(registry) {
|
|||
accessType: 'READ',
|
||||
accepts: { arg: 'deltas', type: 'array', http: { source: 'body' }},
|
||||
returns: { arg: 'updates', type: 'array', root: true },
|
||||
http: {verb: 'post', path: '/create-updates'}
|
||||
http: { verb: 'post', path: '/create-updates' },
|
||||
});
|
||||
|
||||
setRemoting(PersistedModel, 'bulkUpdate', {
|
||||
description: 'Run multiple updates at once. Note: this is not atomic.',
|
||||
accessType: 'WRITE',
|
||||
accepts: { arg: 'updates', type: 'array' },
|
||||
http: {verb: 'post', path: '/bulk-update'}
|
||||
http: { verb: 'post', path: '/bulk-update' },
|
||||
});
|
||||
|
||||
setRemoting(PersistedModel, 'findLastChange', {
|
||||
|
@ -756,30 +762,30 @@ module.exports = function(registry) {
|
|||
accessType: 'READ',
|
||||
accepts: {
|
||||
arg: 'id', type: 'any', required: true, http: { source: 'path' },
|
||||
description: 'Model id'
|
||||
description: 'Model id',
|
||||
},
|
||||
returns: { arg: 'result', type: this.Change.modelName, root: true },
|
||||
http: { verb: 'get', path: '/:id/changes/last' }
|
||||
http: { verb: 'get', path: '/:id/changes/last' },
|
||||
});
|
||||
|
||||
setRemoting(PersistedModel, 'updateLastChange', {
|
||||
description: [
|
||||
'Update the properties of the most recent change record',
|
||||
'kept for this instance.'
|
||||
'kept for this instance.',
|
||||
],
|
||||
accessType: 'WRITE',
|
||||
accepts: [
|
||||
{
|
||||
arg: 'id', type: 'any', required: true, http: { source: 'path' },
|
||||
description: 'Model id'
|
||||
description: 'Model id',
|
||||
},
|
||||
{
|
||||
arg: 'data', type: 'object', http: { source: 'body' },
|
||||
description: 'An object of Change property name/value pairs'
|
||||
description: 'An object of Change property name/value pairs',
|
||||
},
|
||||
],
|
||||
returns: { arg: 'result', type: this.Change.modelName, root: true },
|
||||
http: { verb: 'put', path: '/:id/changes/last' }
|
||||
http: { verb: 'put', path: '/:id/changes/last' },
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -789,14 +795,14 @@ module.exports = function(registry) {
|
|||
setRemoting(PersistedModel, 'rectifyAllChanges', {
|
||||
description: 'Rectify all Model changes.',
|
||||
accessType: 'WRITE',
|
||||
http: {verb: 'post', path: '/rectify-all'}
|
||||
http: { verb: 'post', path: '/rectify-all' },
|
||||
});
|
||||
|
||||
setRemoting(PersistedModel, 'rectifyChange', {
|
||||
description: 'Tell loopback that a change to the model with the given id has occurred.',
|
||||
accessType: 'WRITE',
|
||||
accepts: { arg: 'id', type: 'any', http: { source: 'path' }},
|
||||
http: {verb: 'post', path: '/:id/rectify-change'}
|
||||
http: { verb: 'post', path: '/:id/rectify-change' },
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -805,17 +811,17 @@ module.exports = function(registry) {
|
|||
accessType: 'READ',
|
||||
http: [
|
||||
{ verb: 'post', path: '/change-stream' },
|
||||
{verb: 'get', path: '/change-stream'}
|
||||
{ verb: 'get', path: '/change-stream' },
|
||||
],
|
||||
accepts: {
|
||||
arg: 'options',
|
||||
type: 'object'
|
||||
type: 'object',
|
||||
},
|
||||
returns: {
|
||||
arg: 'changes',
|
||||
type: 'ReadableStream',
|
||||
json: true
|
||||
}
|
||||
json: true,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -870,7 +876,7 @@ module.exports = function(registry) {
|
|||
// TODO(ritch) this whole thing could be optimized a bit more
|
||||
Change.find({ where: {
|
||||
checkpoint: { gte: since },
|
||||
modelName: this.modelName
|
||||
modelName: this.modelName,
|
||||
}}, function(err, changes) {
|
||||
if (err) return callback(err);
|
||||
if (!Array.isArray(changes) || changes.length === 0) return callback(null, []);
|
||||
|
@ -1004,16 +1010,14 @@ module.exports = function(registry) {
|
|||
'You must enable change tracking before replicating'
|
||||
);
|
||||
|
||||
var diff;
|
||||
var updates;
|
||||
var newSourceCp, newTargetCp;
|
||||
var diff, updates, newSourceCp, newTargetCp;
|
||||
|
||||
var tasks = [
|
||||
checkpoints,
|
||||
getSourceChanges,
|
||||
getDiffFromTarget,
|
||||
createSourceUpdates,
|
||||
bulkUpdate
|
||||
bulkUpdate,
|
||||
];
|
||||
|
||||
async.waterfall(tasks, done);
|
||||
|
@ -1521,7 +1525,7 @@ module.exports = function(registry) {
|
|||
this.Change = BaseChangeModel.extend(this.modelName + '-change',
|
||||
{},
|
||||
{
|
||||
trackModel: this
|
||||
trackModel: this,
|
||||
}
|
||||
);
|
||||
|
||||
|
@ -1661,7 +1665,7 @@ module.exports = function(registry) {
|
|||
var change = {
|
||||
target: target,
|
||||
where: where,
|
||||
data: data
|
||||
data: data,
|
||||
};
|
||||
|
||||
switch (type) {
|
||||
|
|
|
@ -89,7 +89,6 @@ function Registry() {
|
|||
*/
|
||||
|
||||
Registry.prototype.createModel = function(name, properties, options) {
|
||||
|
||||
if (arguments.length === 1 && typeof name === 'object') {
|
||||
var config = name;
|
||||
name = config.name;
|
||||
|
@ -208,7 +207,7 @@ Registry.prototype.configureModel = function(ModelCtor, config) {
|
|||
'super': true,
|
||||
relations: true,
|
||||
acls: true,
|
||||
dataSource: true
|
||||
dataSource: true,
|
||||
};
|
||||
if (typeof config.options === 'object' && config.options !== null) {
|
||||
for (var p in config.options) {
|
||||
|
@ -390,7 +389,7 @@ Registry.prototype.memory = function(name) {
|
|||
|
||||
if (!memory) {
|
||||
memory = this._memoryDataSources[name] = this.createDataSource({
|
||||
connector: 'memory'
|
||||
connector: 'memory',
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -265,7 +265,7 @@ proto.lazyrouter = function() {
|
|||
|
||||
self._requestHandlingPhases = [
|
||||
'initial', 'session', 'auth', 'parse',
|
||||
'routes', 'files', 'final'
|
||||
'routes', 'files', 'final',
|
||||
];
|
||||
};
|
||||
|
||||
|
|
|
@ -63,13 +63,13 @@
|
|||
"browserify": "^10.0.0",
|
||||
"chai": "^2.1.1",
|
||||
"es5-shim": "^4.1.0",
|
||||
"eslint-config-loopback": "^1.0.0",
|
||||
"grunt": "^0.4.5",
|
||||
"grunt-browserify": "^3.5.0",
|
||||
"grunt-cli": "^0.1.13",
|
||||
"grunt-contrib-jshint": "^0.11.0",
|
||||
"grunt-contrib-uglify": "^0.9.1",
|
||||
"grunt-contrib-watch": "^0.6.1",
|
||||
"grunt-jscs": "^1.5.0",
|
||||
"grunt-eslint": "^18.0.0",
|
||||
"grunt-karma": "^0.10.1",
|
||||
"grunt-mocha-test": "^0.12.7",
|
||||
"karma": "^0.12.31",
|
||||
|
|
|
@ -4,7 +4,6 @@ var cls = require('continuation-local-storage');
|
|||
var domain = require('domain');
|
||||
|
||||
module.exports = function(loopback) {
|
||||
|
||||
/**
|
||||
* Get the current context object. The context is preserved
|
||||
* across async calls, it behaves like a thread-local storage.
|
||||
|
|
|
@ -23,7 +23,7 @@ function status() {
|
|||
return function(req, res) {
|
||||
res.send({
|
||||
started: started,
|
||||
uptime: (Date.now() - Number(started)) / 1000
|
||||
uptime: (Date.now() - Number(started)) / 1000,
|
||||
});
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
/*jshint -W030 */
|
||||
|
||||
var loopback = require('../');
|
||||
var lt = require('./helpers/loopback-testing-helper');
|
||||
var path = require('path');
|
||||
|
@ -11,7 +9,6 @@ var CURRENT_USER = {email: 'current@test.test', password: 'test'};
|
|||
var debug = require('debug')('loopback:test:access-control.integration');
|
||||
|
||||
describe('access control - integration', function() {
|
||||
|
||||
lt.beforeEach.withApp(app);
|
||||
|
||||
/*
|
||||
|
@ -61,7 +58,6 @@ describe('access control - integration', function() {
|
|||
*/
|
||||
|
||||
describe('/users', function() {
|
||||
|
||||
lt.beforeEach.givenModel('user', USER, 'randomUser');
|
||||
|
||||
lt.it.shouldBeDeniedWhenCalledAnonymously('GET', '/api/users');
|
||||
|
@ -128,7 +124,7 @@ describe('access control - integration', function() {
|
|||
userCounter = userCounter ? ++userCounter : 1;
|
||||
return {
|
||||
email: 'new-' + userCounter + '@test.test',
|
||||
password: 'test'
|
||||
password: 'test',
|
||||
};
|
||||
}
|
||||
});
|
||||
|
@ -200,13 +196,13 @@ describe('access control - integration', function() {
|
|||
// Create an account under the given user
|
||||
app.models.account.create({
|
||||
userId: self.user.id,
|
||||
balance: 100
|
||||
balance: 100,
|
||||
}, function(err, act) {
|
||||
self.url = '/api/accounts/' + act.id;
|
||||
done();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
lt.describe.whenCalledRemotely('PUT', '/api/accounts/:id', function() {
|
||||
lt.it.shouldBeAllowed();
|
||||
});
|
||||
|
@ -226,5 +222,4 @@ describe('access control - integration', function() {
|
|||
return '/api/accounts/' + this.account.id;
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
|
|
@ -227,7 +227,7 @@ describe('AccessToken', function() {
|
|||
it('supports two-arg variant with no options', function(done) {
|
||||
var expectedTokenId = this.token.id;
|
||||
var req = mockRequest({
|
||||
headers: { 'authorization': expectedTokenId }
|
||||
headers: { 'authorization': expectedTokenId },
|
||||
});
|
||||
|
||||
Token.findForRequest(req, function(err, token) {
|
||||
|
@ -247,7 +247,7 @@ describe('AccessToken', function() {
|
|||
|
||||
// express helpers
|
||||
param: function(name) { return this._params[name]; },
|
||||
header: function(name) { return this.headers[name]; }
|
||||
header: function(name) { return this.headers[name]; },
|
||||
},
|
||||
opts);
|
||||
}
|
||||
|
@ -328,7 +328,7 @@ describe('app.enableAuth()', function() {
|
|||
};
|
||||
TestModel.remoteMethod('getToken', {
|
||||
returns: { arg: 'token', type: 'object' },
|
||||
http: { verb: 'GET', path: '/token' }
|
||||
http: { verb: 'GET', path: '/token' },
|
||||
});
|
||||
|
||||
var app = loopback();
|
||||
|
@ -376,7 +376,7 @@ function createTestApp(testToken, settings, done) {
|
|||
var modelSettings = settings.model || {};
|
||||
var tokenSettings = extend({
|
||||
model: Token,
|
||||
currentUserLiteral: 'me'
|
||||
currentUserLiteral: 'me',
|
||||
}, settings.token);
|
||||
|
||||
var app = loopback();
|
||||
|
@ -423,9 +423,9 @@ function createTestApp(testToken, settings, done) {
|
|||
principalId: '$everyone',
|
||||
accessType: ACL.ALL,
|
||||
permission: ACL.DENY,
|
||||
property: 'deleteById'
|
||||
}
|
||||
]
|
||||
property: 'deleteById',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
Object.keys(modelSettings).forEach(function(key) {
|
||||
|
|
220
test/acl.test.js
220
test/acl.test.js
|
@ -30,45 +30,53 @@ describe('security scopes', function() {
|
|||
});
|
||||
|
||||
it('should allow access to models for the given scope by wildcard', function() {
|
||||
Scope.create({name: 'userScope', description: 'access user information'}, function(err, scope) {
|
||||
ACL.create({principalType: ACL.SCOPE, principalId: scope.id, model: 'User', property: ACL.ALL,
|
||||
accessType: ACL.ALL, permission: ACL.ALLOW},
|
||||
function(err, resource) {
|
||||
Scope.create({ name: 'userScope', description: 'access user information' },
|
||||
function(err, scope) {
|
||||
ACL.create({
|
||||
principalType: ACL.SCOPE, principalId: scope.id,
|
||||
model: 'User', property: ACL.ALL,
|
||||
accessType: ACL.ALL, permission: ACL.ALLOW,
|
||||
}, function(err, resource) {
|
||||
Scope.checkPermission('userScope', 'User', ACL.ALL, ACL.ALL, checkResult);
|
||||
Scope.checkPermission('userScope', 'User', 'name', ACL.ALL, checkResult);
|
||||
Scope.checkPermission('userScope', 'User', 'name', ACL.READ, checkResult);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
it('should allow access to models for the given scope', function() {
|
||||
Scope.create({name: 'testModelScope', description: 'access testModel information'}, function(err, scope) {
|
||||
Scope.create({ name: 'testModelScope', description: 'access testModel information' },
|
||||
function(err, scope) {
|
||||
ACL.create({
|
||||
principalType: ACL.SCOPE, principalId: scope.id,
|
||||
model: 'testModel', property: 'name',
|
||||
accessType: ACL.READ, permission: ACL.ALLOW,
|
||||
}, function(err, resource) {
|
||||
ACL.create({ principalType: ACL.SCOPE, principalId: scope.id,
|
||||
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', accessType: ACL.WRITE, permission: ACL.DENY},
|
||||
function(err, resource) {
|
||||
model: 'testModel', property: 'name',
|
||||
accessType: ACL.WRITE, permission: ACL.DENY,
|
||||
}, function(err, resource) {
|
||||
// console.log(resource);
|
||||
Scope.checkPermission('testModelScope', 'testModel', ACL.ALL, ACL.ALL, function(err, perm) {
|
||||
Scope.checkPermission('testModelScope', 'testModel', ACL.ALL, ACL.ALL,
|
||||
function(err, perm) {
|
||||
assert(perm.permission === ACL.DENY); // because name.WRITE == DENY
|
||||
});
|
||||
Scope.checkPermission('testModelScope', 'testModel', 'name', ACL.ALL, function(err, perm) {
|
||||
Scope.checkPermission('testModelScope', 'testModel', 'name', ACL.ALL,
|
||||
function(err, perm) {
|
||||
assert(perm.permission === ACL.DENY); // because name.WRITE == DENY
|
||||
});
|
||||
Scope.checkPermission('testModelScope', 'testModel', 'name', ACL.READ, function(err, perm) {
|
||||
Scope.checkPermission('testModelScope', 'testModel', 'name', ACL.READ,
|
||||
function(err, perm) {
|
||||
assert(perm.permission === ACL.ALLOW);
|
||||
});
|
||||
Scope.checkPermission('testModelScope', 'testModel', 'name', ACL.WRITE, function(err, perm) {
|
||||
Scope.checkPermission('testModelScope', 'testModel', 'name', ACL.WRITE,
|
||||
function(err, perm) {
|
||||
assert(perm.permission === ACL.DENY);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('security ACLs', function() {
|
||||
|
@ -79,26 +87,26 @@ describe('security ACLs', function() {
|
|||
'accessType': '*',
|
||||
'permission': 'DENY',
|
||||
'principalType': 'ROLE',
|
||||
'principalId': '$everyone'
|
||||
'principalId': '$everyone',
|
||||
},
|
||||
{
|
||||
'model': 'account',
|
||||
'accessType': '*',
|
||||
'permission': 'ALLOW',
|
||||
'principalType': 'ROLE',
|
||||
'principalId': '$owner'
|
||||
'principalId': '$owner',
|
||||
},
|
||||
{
|
||||
'model': 'account',
|
||||
'accessType': 'READ',
|
||||
'permission': 'ALLOW',
|
||||
'principalType': 'ROLE',
|
||||
'principalId': '$everyone'
|
||||
'principalId': '$everyone',
|
||||
}];
|
||||
var req = {
|
||||
model: 'account',
|
||||
property: 'find',
|
||||
accessType: 'WRITE'
|
||||
accessType: 'WRITE',
|
||||
};
|
||||
|
||||
acls = acls.map(function(a) { return new ACL(a); });
|
||||
|
@ -113,12 +121,14 @@ describe('security ACLs', function() {
|
|||
|
||||
it('should allow access to models for the given principal by wildcard', function() {
|
||||
// jscs:disable validateIndentation
|
||||
ACL.create({principalType: ACL.USER, principalId: 'u001', model: 'User', property: ACL.ALL,
|
||||
accessType: ACL.ALL, permission: ACL.ALLOW}, function(err, acl) {
|
||||
|
||||
ACL.create({principalType: ACL.USER, principalId: 'u001', model: 'User', property: ACL.ALL,
|
||||
accessType: ACL.READ, permission: ACL.DENY}, function(err, acl) {
|
||||
|
||||
ACL.create({
|
||||
principalType: ACL.USER, principalId: 'u001', model: 'User', property: ACL.ALL,
|
||||
accessType: ACL.ALL, permission: ACL.ALLOW,
|
||||
}, function(err, acl) {
|
||||
ACL.create({
|
||||
principalType: ACL.USER, principalId: 'u001', model: 'User', property: ACL.ALL,
|
||||
accessType: ACL.READ, permission: ACL.DENY,
|
||||
}, function(err, acl) {
|
||||
ACL.checkPermission(ACL.USER, 'u001', 'User', 'name', ACL.READ, function(err, perm) {
|
||||
assert(perm.permission === ACL.DENY);
|
||||
});
|
||||
|
@ -126,52 +136,55 @@ describe('security ACLs', function() {
|
|||
ACL.checkPermission(ACL.USER, 'u001', 'User', 'name', ACL.ALL, function(err, perm) {
|
||||
assert(perm.permission === ACL.DENY);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
it('should allow access to models by exception', function() {
|
||||
ACL.create({principalType: ACL.USER, principalId: 'u001', model: 'testModel', property: ACL.ALL,
|
||||
accessType: ACL.ALL, permission: ACL.DENY}, function(err, acl) {
|
||||
|
||||
ACL.create({principalType: ACL.USER, principalId: 'u001', model: 'testModel', property: ACL.ALL,
|
||||
accessType: ACL.READ, permission: ACL.ALLOW}, function(err, acl) {
|
||||
|
||||
ACL.create({principalType: ACL.USER, principalId: 'u002', model: 'testModel', property: ACL.ALL,
|
||||
accessType: ACL.EXECUTE, permission: ACL.ALLOW}, function(err, acl) {
|
||||
|
||||
ACL.checkPermission(ACL.USER, 'u001', 'testModel', 'name', ACL.READ, function(err, perm) {
|
||||
ACL.create({
|
||||
principalType: ACL.USER, principalId: 'u001', model: 'testModel', property: ACL.ALL,
|
||||
accessType: ACL.ALL, permission: ACL.DENY,
|
||||
}, function(err, acl) {
|
||||
ACL.create({
|
||||
principalType: ACL.USER, principalId: 'u001', model: 'testModel', property: ACL.ALL,
|
||||
accessType: ACL.READ, permission: ACL.ALLOW,
|
||||
}, function(err, acl) {
|
||||
ACL.create({
|
||||
principalType: ACL.USER, principalId: 'u002', model: 'testModel', property: ACL.ALL,
|
||||
accessType: ACL.EXECUTE, permission: ACL.ALLOW,
|
||||
}, function(err, acl) {
|
||||
ACL.checkPermission(ACL.USER, 'u001', 'testModel', 'name', ACL.READ,
|
||||
function(err, perm) {
|
||||
assert(perm.permission === ACL.ALLOW);
|
||||
});
|
||||
|
||||
ACL.checkPermission(ACL.USER, 'u001', 'testModel', ACL.ALL, ACL.READ, function(err, perm) {
|
||||
ACL.checkPermission(ACL.USER, 'u001', 'testModel', ACL.ALL, ACL.READ,
|
||||
function(err, perm) {
|
||||
assert(perm.permission === ACL.ALLOW);
|
||||
});
|
||||
|
||||
ACL.checkPermission(ACL.USER, 'u001', 'testModel', 'name', ACL.WRITE, function(err, perm) {
|
||||
ACL.checkPermission(ACL.USER, 'u001', 'testModel', 'name', ACL.WRITE,
|
||||
function(err, perm) {
|
||||
assert(perm.permission === ACL.DENY);
|
||||
});
|
||||
|
||||
ACL.checkPermission(ACL.USER, 'u001', 'testModel', 'name', ACL.ALL, function(err, perm) {
|
||||
ACL.checkPermission(ACL.USER, 'u001', 'testModel', 'name', ACL.ALL,
|
||||
function(err, perm) {
|
||||
assert(perm.permission === ACL.DENY);
|
||||
});
|
||||
|
||||
ACL.checkPermission(ACL.USER, 'u002', 'testModel', 'name', ACL.WRITE, function(err, perm) {
|
||||
ACL.checkPermission(ACL.USER, 'u002', 'testModel', 'name', ACL.WRITE,
|
||||
function(err, perm) {
|
||||
assert(perm.permission === ACL.ALLOW);
|
||||
});
|
||||
|
||||
ACL.checkPermission(ACL.USER, 'u002', 'testModel', 'name', ACL.READ, function(err, perm) {
|
||||
ACL.checkPermission(ACL.USER, 'u002', 'testModel', 'name', ACL.READ,
|
||||
function(err, perm) {
|
||||
assert(perm.permission === ACL.ALLOW);
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
it('should honor defaultPermission from the model', function() {
|
||||
|
@ -179,19 +192,23 @@ describe('security ACLs', function() {
|
|||
name: {
|
||||
type: String,
|
||||
acls: [
|
||||
{principalType: ACL.USER, principalId: 'u001', accessType: ACL.WRITE, permission: ACL.DENY},
|
||||
{principalType: ACL.USER, principalId: 'u001', accessType: ACL.ALL, permission: ACL.ALLOW}
|
||||
]
|
||||
}
|
||||
{ principalType: ACL.USER, principalId: 'u001',
|
||||
accessType: ACL.WRITE, permission: ACL.DENY },
|
||||
{ principalType: ACL.USER, principalId: 'u001',
|
||||
accessType: ACL.ALL, permission: ACL.ALLOW },
|
||||
],
|
||||
},
|
||||
}, {
|
||||
acls: [
|
||||
{principalType: ACL.USER, principalId: 'u001', accessType: ACL.ALL, permission: ACL.ALLOW}
|
||||
]
|
||||
{ principalType: ACL.USER, principalId: 'u001',
|
||||
accessType: ACL.ALL, permission: ACL.ALLOW },
|
||||
],
|
||||
});
|
||||
|
||||
Customer.settings.defaultPermission = ACL.DENY;
|
||||
|
||||
ACL.checkPermission(ACL.USER, 'u001', 'Customer', 'name', ACL.WRITE, function(err, perm) {
|
||||
ACL.checkPermission(ACL.USER, 'u001', 'Customer', 'name', ACL.WRITE,
|
||||
function(err, perm) {
|
||||
assert(perm.permission === ACL.DENY);
|
||||
});
|
||||
|
||||
|
@ -202,7 +219,6 @@ describe('security ACLs', function() {
|
|||
ACL.checkPermission(ACL.USER, 'u002', 'Customer', 'name', ACL.WRITE, function(err, perm) {
|
||||
assert(perm.permission === ACL.DENY);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
it('should honor static ACLs from the model', function() {
|
||||
|
@ -210,16 +226,21 @@ describe('security ACLs', function() {
|
|||
name: {
|
||||
type: String,
|
||||
acls: [
|
||||
{principalType: ACL.USER, principalId: 'u001', accessType: ACL.WRITE, permission: ACL.DENY},
|
||||
{principalType: ACL.USER, principalId: 'u001', accessType: ACL.ALL, permission: ACL.ALLOW}
|
||||
]
|
||||
}
|
||||
{ principalType: ACL.USER, principalId: 'u001',
|
||||
accessType: ACL.WRITE, permission: ACL.DENY },
|
||||
{ principalType: ACL.USER, principalId: 'u001',
|
||||
accessType: ACL.ALL, permission: ACL.ALLOW },
|
||||
],
|
||||
},
|
||||
}, {
|
||||
acls: [
|
||||
{principalType: ACL.USER, principalId: 'u001', accessType: ACL.ALL, permission: ACL.ALLOW},
|
||||
{principalType: ACL.USER, principalId: 'u002', accessType: ACL.EXECUTE, permission: ACL.ALLOW},
|
||||
{principalType: ACL.USER, principalId: 'u003', accessType: ACL.EXECUTE, permission: ACL.DENY}
|
||||
]
|
||||
{ principalType: ACL.USER, principalId: 'u001',
|
||||
accessType: ACL.ALL, permission: ACL.ALLOW },
|
||||
{ principalType: ACL.USER, principalId: 'u002',
|
||||
accessType: ACL.EXECUTE, permission: ACL.ALLOW },
|
||||
{ principalType: ACL.USER, principalId: 'u003',
|
||||
accessType: ACL.EXECUTE, permission: ACL.DENY },
|
||||
],
|
||||
});
|
||||
|
||||
/*
|
||||
|
@ -228,26 +249,30 @@ describe('security ACLs', function() {
|
|||
];
|
||||
*/
|
||||
|
||||
ACL.checkPermission(ACL.USER, 'u001', 'Customer', 'name', ACL.WRITE, function(err, perm) {
|
||||
ACL.checkPermission(ACL.USER, 'u001', 'Customer', 'name', ACL.WRITE,
|
||||
function(err, perm) {
|
||||
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);
|
||||
});
|
||||
|
||||
ACL.checkPermission(ACL.USER, 'u001', 'Customer', 'name', ACL.ALL, function(err, perm) {
|
||||
ACL.checkPermission(ACL.USER, 'u001', 'Customer', 'name', ACL.ALL,
|
||||
function(err, perm) {
|
||||
assert(perm.permission === ACL.ALLOW);
|
||||
});
|
||||
|
||||
ACL.checkPermission(ACL.USER, 'u002', 'Customer', 'name', ACL.READ, function(err, perm) {
|
||||
ACL.checkPermission(ACL.USER, 'u002', 'Customer', 'name', ACL.READ,
|
||||
function(err, perm) {
|
||||
assert(perm.permission === ACL.ALLOW);
|
||||
});
|
||||
|
||||
ACL.checkPermission(ACL.USER, 'u003', 'Customer', 'name', ACL.WRITE, function(err, perm) {
|
||||
ACL.checkPermission(ACL.USER, 'u003', 'Customer', 'name', ACL.WRITE,
|
||||
function(err, perm) {
|
||||
assert(perm.permission === ACL.DENY);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
it('should filter static ACLs by model/property', function() {
|
||||
|
@ -258,9 +283,9 @@ describe('security ACLs', function() {
|
|||
{ principalType: ACL.USER, principalId: 'u001',
|
||||
accessType: ACL.WRITE, permission: ACL.DENY },
|
||||
{ principalType: ACL.USER, principalId: 'u001',
|
||||
accessType: ACL.ALL, permission: ACL.ALLOW}
|
||||
]
|
||||
}
|
||||
accessType: ACL.ALL, permission: ACL.ALLOW },
|
||||
],
|
||||
},
|
||||
}, {
|
||||
acls: [
|
||||
{ principalType: ACL.USER, principalId: 'u001', property: 'name',
|
||||
|
@ -268,8 +293,8 @@ describe('security ACLs', function() {
|
|||
{ principalType: ACL.USER, principalId: 'u002', property: 'findOne',
|
||||
accessType: ACL.ALL, permission: ACL.ALLOW },
|
||||
{ principalType: ACL.USER, principalId: 'u003', property: ['findOne', 'findById'],
|
||||
accessType: ACL.ALL, permission: ACL.ALLOW}
|
||||
]
|
||||
accessType: ACL.ALL, permission: ACL.ALLOW },
|
||||
],
|
||||
});
|
||||
|
||||
var staticACLs = ACL.getStaticACLs('Model1', 'name');
|
||||
|
@ -289,7 +314,6 @@ describe('security ACLs', function() {
|
|||
|
||||
// Create
|
||||
User.create({ name: 'Raymond', email: 'x@y.com', password: 'foobar' }, function(err, user) {
|
||||
|
||||
log('User: ', user.toObject());
|
||||
|
||||
var userId = user.id;
|
||||
|
@ -299,56 +323,62 @@ describe('security ACLs', function() {
|
|||
name: {
|
||||
type: String,
|
||||
acls: [
|
||||
{principalType: ACL.USER, principalId: userId, accessType: ACL.WRITE, permission: ACL.DENY},
|
||||
{principalType: ACL.USER, principalId: userId, accessType: ACL.ALL, permission: ACL.ALLOW}
|
||||
]
|
||||
}
|
||||
{ principalType: ACL.USER, principalId: userId,
|
||||
accessType: ACL.WRITE, permission: ACL.DENY },
|
||||
{ principalType: ACL.USER, principalId: userId,
|
||||
accessType: ACL.ALL, permission: ACL.ALLOW },
|
||||
],
|
||||
},
|
||||
}, {
|
||||
acls: [
|
||||
{principalType: ACL.USER, principalId: userId, accessType: ACL.ALL, permission: ACL.ALLOW}
|
||||
{ principalType: ACL.USER, principalId: userId,
|
||||
accessType: ACL.ALL, permission: ACL.ALLOW },
|
||||
],
|
||||
defaultPermission: 'DENY'
|
||||
defaultPermission: 'DENY',
|
||||
});
|
||||
|
||||
ACL.create({principalType: ACL.USER, principalId: userId, model: 'Customer', property: ACL.ALL,
|
||||
accessType: ACL.ALL, permission: ACL.ALLOW}, function(err, acl) {
|
||||
|
||||
ACL.create({
|
||||
principalType: ACL.USER, principalId: userId,
|
||||
model: 'Customer', property: ACL.ALL,
|
||||
accessType: ACL.ALL, permission: ACL.ALLOW,
|
||||
}, function(err, acl) {
|
||||
log('ACL 1: ', acl.toObject());
|
||||
|
||||
Role.create({ name: 'MyRole' }, function(err, myRole) {
|
||||
log('Role: ', myRole.toObject());
|
||||
|
||||
myRole.principals.create({principalType: RoleMapping.USER, principalId: userId}, function(err, p) {
|
||||
|
||||
myRole.principals.create({ principalType: RoleMapping.USER, principalId: userId },
|
||||
function(err, p) {
|
||||
log('Principal added to role: ', p.toObject());
|
||||
|
||||
ACL.create({principalType: ACL.ROLE, principalId: 'MyRole', model: 'Customer', property: ACL.ALL,
|
||||
accessType: ACL.READ, permission: ACL.DENY}, function(err, acl) {
|
||||
|
||||
ACL.create({
|
||||
principalType: ACL.ROLE, principalId: 'MyRole',
|
||||
model: 'Customer', property: ACL.ALL,
|
||||
accessType: ACL.READ, permission: ACL.DENY,
|
||||
}, function(err, acl) {
|
||||
log('ACL 2: ', acl.toObject());
|
||||
|
||||
ACL.checkAccessForContext({
|
||||
principals: [
|
||||
{type: ACL.USER, id: userId}
|
||||
{ type: ACL.USER, id: userId },
|
||||
],
|
||||
model: 'Customer',
|
||||
property: 'name',
|
||||
accessType: ACL.READ
|
||||
accessType: ACL.READ,
|
||||
}, function(err, access) {
|
||||
assert(!err && access.permission === ACL.ALLOW);
|
||||
});
|
||||
|
||||
ACL.checkAccessForContext({
|
||||
principals: [
|
||||
{type: ACL.ROLE, id: Role.EVERYONE}
|
||||
{ type: ACL.ROLE, id: Role.EVERYONE },
|
||||
],
|
||||
model: 'Customer',
|
||||
property: 'name',
|
||||
accessType: ACL.READ
|
||||
accessType: ACL.READ,
|
||||
}, function(err, access) {
|
||||
assert(!err && access.permission === ACL.DENY);
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
/*jshint -W030 */
|
||||
|
||||
var async = require('async');
|
||||
var path = require('path');
|
||||
|
||||
|
@ -13,8 +11,7 @@ var it = require('./util/it');
|
|||
|
||||
describe('app', function() {
|
||||
describe.onServer('.middleware(phase, handler)', function() {
|
||||
var app;
|
||||
var steps;
|
||||
var app, steps;
|
||||
|
||||
beforeEach(function setup() {
|
||||
app = loopback();
|
||||
|
@ -24,7 +21,7 @@ describe('app', function() {
|
|||
it('runs middleware in phases', function(done) {
|
||||
var PHASES = [
|
||||
'initial', 'session', 'auth', 'parse',
|
||||
'routes', 'files', 'final'
|
||||
'routes', 'files', 'final',
|
||||
];
|
||||
|
||||
PHASES.forEach(function(name) {
|
||||
|
@ -36,7 +33,7 @@ describe('app', function() {
|
|||
if (err) return done(err);
|
||||
expect(steps).to.eql([
|
||||
'initial', 'session', 'auth', 'parse',
|
||||
'main', 'routes', 'files', 'final'
|
||||
'main', 'routes', 'files', 'final',
|
||||
]);
|
||||
done();
|
||||
});
|
||||
|
@ -233,8 +230,7 @@ describe('app', function() {
|
|||
});
|
||||
|
||||
it('exposes express helpers on req and res objects', function(done) {
|
||||
var req;
|
||||
var res;
|
||||
var req, res;
|
||||
|
||||
app.middleware('initial', function(rq, rs, next) {
|
||||
req = rq;
|
||||
|
@ -250,7 +246,7 @@ describe('app', function() {
|
|||
'param',
|
||||
'params',
|
||||
'query',
|
||||
'res'
|
||||
'res',
|
||||
]);
|
||||
|
||||
expect(getObjectAndPrototypeKeys(res), 'response').to.include.members([
|
||||
|
@ -262,7 +258,7 @@ describe('app', function() {
|
|||
'req',
|
||||
'send',
|
||||
'sendFile',
|
||||
'set'
|
||||
'set',
|
||||
]);
|
||||
|
||||
done();
|
||||
|
@ -316,13 +312,12 @@ describe('app', function() {
|
|||
});
|
||||
|
||||
it('correctly mounts express apps', function(done) {
|
||||
var data;
|
||||
var mountWasEmitted;
|
||||
var data, mountWasEmitted;
|
||||
var subapp = express();
|
||||
subapp.use(function(req, res, next) {
|
||||
data = {
|
||||
mountpath: req.app.mountpath,
|
||||
parent: req.app.parent
|
||||
parent: req.app.parent,
|
||||
};
|
||||
next();
|
||||
});
|
||||
|
@ -335,14 +330,13 @@ describe('app', function() {
|
|||
expect(mountWasEmitted, 'mountWasEmitted').to.be.true;
|
||||
expect(data).to.eql({
|
||||
mountpath: '/mountpath',
|
||||
parent: app
|
||||
parent: app,
|
||||
});
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('restores req & res on return from mounted express app', function(done) {
|
||||
// jshint proto:true
|
||||
var expected = {};
|
||||
var actual = {};
|
||||
|
||||
|
@ -414,28 +408,28 @@ describe('app', function() {
|
|||
app.middlewareFromConfig(handlerFactory, {
|
||||
enabled: true,
|
||||
phase: 'session',
|
||||
params: expectedConfig
|
||||
params: expectedConfig,
|
||||
});
|
||||
|
||||
// Config as a value (single arg)
|
||||
app.middlewareFromConfig(handlerFactory, {
|
||||
enabled: true,
|
||||
phase: 'session:before',
|
||||
params: 'before'
|
||||
params: 'before',
|
||||
});
|
||||
|
||||
// Config as a list of args
|
||||
app.middlewareFromConfig(handlerFactory, {
|
||||
enabled: true,
|
||||
phase: 'session:after',
|
||||
params: ['after', 2]
|
||||
params: ['after', 2],
|
||||
});
|
||||
|
||||
// Disabled by configuration
|
||||
app.middlewareFromConfig(handlerFactory, {
|
||||
enabled: false,
|
||||
phase: 'initial',
|
||||
params: null
|
||||
params: null,
|
||||
});
|
||||
|
||||
// This should be triggered with matching verbs
|
||||
|
@ -443,7 +437,7 @@ describe('app', function() {
|
|||
enabled: true,
|
||||
phase: 'routes:before',
|
||||
methods: ['get', 'head'],
|
||||
params: {x: 1}
|
||||
params: { x: 1 },
|
||||
});
|
||||
|
||||
// This should be skipped as the verb doesn't match
|
||||
|
@ -451,7 +445,7 @@ describe('app', function() {
|
|||
enabled: true,
|
||||
phase: 'routes:before',
|
||||
methods: ['post'],
|
||||
params: {x: 2}
|
||||
params: { x: 2 },
|
||||
});
|
||||
|
||||
executeMiddlewareHandlers(app, function(err) {
|
||||
|
@ -460,7 +454,7 @@ describe('app', function() {
|
|||
['before'],
|
||||
[expectedConfig],
|
||||
['after', 2],
|
||||
[{x: 1}]
|
||||
[{ x: 1 }],
|
||||
]);
|
||||
done();
|
||||
});
|
||||
|
@ -477,7 +471,7 @@ describe('app', function() {
|
|||
},
|
||||
{
|
||||
phase: 'initial',
|
||||
paths: ['/scope', /^\/(a|b)/]
|
||||
paths: ['/scope', /^\/(a|b)/],
|
||||
});
|
||||
|
||||
async.eachSeries(
|
||||
|
@ -508,7 +502,7 @@ describe('app', function() {
|
|||
'first',
|
||||
'initial', // this was the original first phase
|
||||
'routes',
|
||||
'subapps'
|
||||
'subapps',
|
||||
], done);
|
||||
});
|
||||
|
||||
|
@ -519,7 +513,7 @@ describe('app', function() {
|
|||
'auth', 'routes',
|
||||
'subapps', // add
|
||||
'final',
|
||||
'last' // add
|
||||
'last', // add
|
||||
]);
|
||||
verifyMiddlewarePhases([
|
||||
'initial',
|
||||
|
@ -527,7 +521,7 @@ describe('app', function() {
|
|||
'auth', 'routes',
|
||||
'subapps', // new
|
||||
'files', 'final',
|
||||
'last' // new
|
||||
'last', // new
|
||||
], done);
|
||||
});
|
||||
|
||||
|
@ -555,8 +549,7 @@ describe('app', function() {
|
|||
});
|
||||
|
||||
describe('app.model(Model)', function() {
|
||||
var app;
|
||||
var db;
|
||||
var app, db;
|
||||
beforeEach(function() {
|
||||
app = loopback();
|
||||
db = loopback.createDataSource({ connector: loopback.Memory });
|
||||
|
@ -628,7 +621,6 @@ describe('app', function() {
|
|||
it('should not require dataSource', function() {
|
||||
app.model('MyTestModel', {});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('app.model(name, config)', function() {
|
||||
|
@ -637,13 +629,13 @@ describe('app', function() {
|
|||
beforeEach(function() {
|
||||
app = loopback();
|
||||
app.dataSource('db', {
|
||||
connector: 'memory'
|
||||
connector: 'memory',
|
||||
});
|
||||
});
|
||||
|
||||
it('Sugar for defining a fully built model', function() {
|
||||
app.model('foo', {
|
||||
dataSource: 'db'
|
||||
dataSource: 'db',
|
||||
});
|
||||
|
||||
var Foo = app.models.foo;
|
||||
|
@ -655,7 +647,7 @@ describe('app', function() {
|
|||
it('interprets extra first-level keys as options', function() {
|
||||
app.model('foo', {
|
||||
dataSource: 'db',
|
||||
base: 'User'
|
||||
base: 'User',
|
||||
});
|
||||
|
||||
expect(app.models.foo.definition.settings.base).to.equal('User');
|
||||
|
@ -666,8 +658,8 @@ describe('app', function() {
|
|||
dataSource: 'db',
|
||||
base: 'User',
|
||||
options: {
|
||||
base: 'Application'
|
||||
}
|
||||
base: 'Application',
|
||||
},
|
||||
});
|
||||
|
||||
expect(app.models.foo.definition.settings.base).to.equal('Application');
|
||||
|
@ -676,7 +668,7 @@ describe('app', function() {
|
|||
it('honors config.public options', function() {
|
||||
app.model('foo', {
|
||||
dataSource: 'db',
|
||||
public: false
|
||||
public: false,
|
||||
});
|
||||
expect(app.models.foo.app).to.equal(app);
|
||||
expect(app.models.foo.shared).to.equal(false);
|
||||
|
@ -684,12 +676,11 @@ describe('app', function() {
|
|||
|
||||
it('defaults config.public to be true', function() {
|
||||
app.model('foo', {
|
||||
dataSource: 'db'
|
||||
dataSource: 'db',
|
||||
});
|
||||
expect(app.models.foo.app).to.equal(app);
|
||||
expect(app.models.foo.shared).to.equal(true);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('app.model(ModelCtor, config)', function() {
|
||||
|
@ -943,8 +934,7 @@ describe('app', function() {
|
|||
});
|
||||
|
||||
describe('normalizeHttpPath option', function() {
|
||||
var app;
|
||||
var db;
|
||||
var app, db;
|
||||
beforeEach(function() {
|
||||
app = loopback();
|
||||
db = loopback.createDataSource({ connector: loopback.Memory });
|
||||
|
@ -955,7 +945,7 @@ describe('app', function() {
|
|||
'UserAccount',
|
||||
{ name: String },
|
||||
{
|
||||
remoting: { normalizeHttpPath: true }
|
||||
remoting: { normalizeHttpPath: true },
|
||||
});
|
||||
app.model(UserAccount);
|
||||
UserAccount.attachTo(db);
|
||||
|
|
|
@ -6,7 +6,7 @@ describe('PersistedModel.createChangeStream()', function() {
|
|||
var ds = app.dataSource('ds', { connector: 'memory' });
|
||||
this.Score = app.model('Score', {
|
||||
dataSource: 'ds',
|
||||
changeDataSource: false // use only local observers
|
||||
changeDataSource: false, // use only local observers
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -34,7 +34,7 @@ describe('PersistedModel.createChangeStream()', function() {
|
|||
done();
|
||||
});
|
||||
newScore.updateAttributes({
|
||||
bat: 'baz'
|
||||
bat: 'baz',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -66,11 +66,11 @@ describe('PersistedModel.createChangeStream()', function() {
|
|||
host: 'localhost',
|
||||
port: '12345',
|
||||
connector: 'pubsub',
|
||||
pubsubAdapter: 'mqtt'
|
||||
pubsubAdapter: 'mqtt',
|
||||
});
|
||||
this.Score = app.model('Score', {
|
||||
dataSource: 'db',
|
||||
changeDataSource: 'ps'
|
||||
changeDataSource: 'ps',
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -1,20 +1,19 @@
|
|||
var async = require('async');
|
||||
var expect = require('chai').expect;
|
||||
|
||||
var Change;
|
||||
var TestModel;
|
||||
var Change, TestModel;
|
||||
|
||||
describe('Change', function() {
|
||||
beforeEach(function() {
|
||||
var memory = loopback.createDataSource({
|
||||
connector: loopback.Memory
|
||||
connector: loopback.Memory,
|
||||
});
|
||||
TestModel = loopback.PersistedModel.extend('ChangeTestModel',
|
||||
{
|
||||
id: { id: true, type: 'string', defaultFn: 'guid' }
|
||||
id: { id: true, type: 'string', defaultFn: 'guid' },
|
||||
},
|
||||
{
|
||||
trackChanges: true
|
||||
trackChanges: true,
|
||||
});
|
||||
this.modelName = TestModel.modelName;
|
||||
TestModel.attachTo(memory);
|
||||
|
@ -24,7 +23,7 @@ describe('Change', function() {
|
|||
beforeEach(function(done) {
|
||||
var test = this;
|
||||
test.data = {
|
||||
foo: 'bar'
|
||||
foo: 'bar',
|
||||
};
|
||||
TestModel.create(test.data, function(err, model) {
|
||||
if (err) return done(err);
|
||||
|
@ -46,7 +45,7 @@ describe('Change', function() {
|
|||
var change = new Change({
|
||||
rev: 'abc',
|
||||
modelName: 'foo',
|
||||
modelId: 'bar'
|
||||
modelId: 'bar',
|
||||
});
|
||||
|
||||
var hash = Change.hash([change.modelName, change.modelId].join('-'));
|
||||
|
@ -115,7 +114,6 @@ describe('Change', function() {
|
|||
});
|
||||
|
||||
describe('Change.findOrCreateChange(modelName, modelId, callback)', function() {
|
||||
|
||||
describe('when a change doesnt exist', function() {
|
||||
beforeEach(function(done) {
|
||||
var test = this;
|
||||
|
@ -162,7 +160,7 @@ describe('Change', function() {
|
|||
var test = this;
|
||||
Change.create({
|
||||
modelName: test.modelName,
|
||||
modelId: test.modelId
|
||||
modelId: test.modelId,
|
||||
}, function(err, change) {
|
||||
test.existingChange = change;
|
||||
done();
|
||||
|
@ -192,7 +190,7 @@ describe('Change', function() {
|
|||
Change.findOrCreate(
|
||||
{
|
||||
modelName: this.modelName,
|
||||
modelId: this.modelId
|
||||
modelId: this.modelId,
|
||||
},
|
||||
function(err, ch) {
|
||||
change = ch;
|
||||
|
@ -228,7 +226,7 @@ describe('Change', function() {
|
|||
expect(change.prev, 'prev').to.equal(originalRev);
|
||||
expect(change.rev, 'rev').to.equal(test.revisionForModel);
|
||||
next();
|
||||
}
|
||||
},
|
||||
], done);
|
||||
|
||||
function rectify(next) {
|
||||
|
@ -299,7 +297,7 @@ describe('Change', function() {
|
|||
var test = this;
|
||||
var change = new Change({
|
||||
modelName: this.modelName,
|
||||
modelId: this.modelId
|
||||
modelId: this.modelId,
|
||||
});
|
||||
|
||||
change.currentRevision(function(err, rev) {
|
||||
|
@ -314,7 +312,7 @@ describe('Change', function() {
|
|||
var test = this;
|
||||
var change = new Change({
|
||||
modelName: this.modelName,
|
||||
modelId: this.modelId
|
||||
modelId: this.modelId,
|
||||
});
|
||||
|
||||
change.currentRevision()
|
||||
|
@ -341,14 +339,14 @@ describe('Change', function() {
|
|||
var a = {
|
||||
b: {
|
||||
b: ['c', 'd'],
|
||||
c: ['d', 'e']
|
||||
}
|
||||
c: ['d', 'e'],
|
||||
},
|
||||
};
|
||||
var b = {
|
||||
b: {
|
||||
c: ['d', 'e'],
|
||||
b: ['c', 'd']
|
||||
}
|
||||
b: ['c', 'd'],
|
||||
},
|
||||
};
|
||||
|
||||
var aRev = Change.revisionForInst(a);
|
||||
|
@ -360,20 +358,20 @@ describe('Change', function() {
|
|||
describe('change.type()', function() {
|
||||
it('CREATE', function() {
|
||||
var change = new Change({
|
||||
rev: this.revisionForModel
|
||||
rev: this.revisionForModel,
|
||||
});
|
||||
assert.equal(Change.CREATE, change.type());
|
||||
});
|
||||
it('UPDATE', function() {
|
||||
var change = new Change({
|
||||
rev: this.revisionForModel,
|
||||
prev: this.revisionForModel
|
||||
prev: this.revisionForModel,
|
||||
});
|
||||
assert.equal(Change.UPDATE, change.type());
|
||||
});
|
||||
it('DELETE', function() {
|
||||
var change = new Change({
|
||||
prev: this.revisionForModel
|
||||
prev: this.revisionForModel,
|
||||
});
|
||||
assert.equal(Change.DELETE, change.type());
|
||||
});
|
||||
|
@ -386,7 +384,7 @@ describe('Change', function() {
|
|||
describe('change.getModelCtor()', function() {
|
||||
it('should get the correct model class', function() {
|
||||
var change = new Change({
|
||||
modelName: this.modelName
|
||||
modelName: this.modelName,
|
||||
});
|
||||
|
||||
assert.equal(change.getModelCtor(), TestModel);
|
||||
|
@ -396,11 +394,11 @@ describe('Change', function() {
|
|||
describe('change.equals(otherChange)', function() {
|
||||
it('should return true when the change is equal', function() {
|
||||
var change = new Change({
|
||||
rev: this.revisionForModel
|
||||
rev: this.revisionForModel,
|
||||
});
|
||||
|
||||
var otherChange = new Change({
|
||||
rev: this.revisionForModel
|
||||
rev: this.revisionForModel,
|
||||
});
|
||||
|
||||
assert.equal(change.equals(otherChange), true);
|
||||
|
@ -415,7 +413,7 @@ describe('Change', function() {
|
|||
|
||||
var otherChange = new Change({
|
||||
rev: undefined,
|
||||
prev: REV
|
||||
prev: REV,
|
||||
});
|
||||
|
||||
assert.equal(change.type(), Change.DELETE);
|
||||
|
@ -428,11 +426,11 @@ describe('Change', function() {
|
|||
describe('change.isBasedOn(otherChange)', function() {
|
||||
it('should return true when the change is based on the other', function() {
|
||||
var change = new Change({
|
||||
prev: this.revisionForModel
|
||||
prev: this.revisionForModel,
|
||||
});
|
||||
|
||||
var otherChange = new Change({
|
||||
rev: this.revisionForModel
|
||||
rev: this.revisionForModel,
|
||||
});
|
||||
|
||||
assert.equal(change.isBasedOn(otherChange), true);
|
||||
|
@ -491,7 +489,7 @@ describe('Change', function() {
|
|||
prev: 'foo',
|
||||
modelName: this.modelName,
|
||||
modelId: '9',
|
||||
checkpoint: 2
|
||||
checkpoint: 2,
|
||||
};
|
||||
Change.diff(this.modelName, 0, [updateRecord], function(err, diff) {
|
||||
if (err) return done(err);
|
||||
|
@ -516,7 +514,7 @@ describe('Change', function() {
|
|||
prev: 'foo-prev',
|
||||
modelName: this.modelName,
|
||||
modelId: '9',
|
||||
checkpoint: 2
|
||||
checkpoint: 2,
|
||||
};
|
||||
// IMPORTANT: the diff call excludes the local change
|
||||
// with rev=foo CP=1
|
||||
|
@ -543,7 +541,7 @@ describe('Change', function() {
|
|||
prev: 'new-prev',
|
||||
modelName: this.modelName,
|
||||
modelId: 'new-id',
|
||||
checkpoint: 2
|
||||
checkpoint: 2,
|
||||
};
|
||||
|
||||
Change.diff(this.modelName, 0, [updateRecord], function(err, diff) {
|
||||
|
|
|
@ -8,7 +8,7 @@ describe('Checkpoint', function() {
|
|||
describe('bumpLastSeq() and current()', function() {
|
||||
beforeEach(function() {
|
||||
var memory = loopback.createDataSource({
|
||||
connector: loopback.Memory
|
||||
connector: loopback.Memory,
|
||||
});
|
||||
Checkpoint.attachTo(memory);
|
||||
});
|
||||
|
@ -23,14 +23,14 @@ describe('Checkpoint', function() {
|
|||
expect(seq).to.equal(3);
|
||||
next();
|
||||
});
|
||||
}
|
||||
},
|
||||
], done);
|
||||
});
|
||||
|
||||
it('Should be no race condition for current() when calling in parallel', function(done) {
|
||||
async.parallel([
|
||||
function(next) { Checkpoint.current(next); },
|
||||
function(next) { Checkpoint.current(next); }
|
||||
function(next) { Checkpoint.current(next); },
|
||||
], function(err, list) {
|
||||
if (err) return done(err);
|
||||
Checkpoint.find(function(err, data) {
|
||||
|
@ -44,7 +44,7 @@ describe('Checkpoint', function() {
|
|||
it('Should be no race condition for bumpLastSeq() when calling in parallel', function(done) {
|
||||
async.parallel([
|
||||
function(next) { Checkpoint.bumpLastSeq(next); },
|
||||
function(next) { Checkpoint.bumpLastSeq(next); }
|
||||
function(next) { Checkpoint.bumpLastSeq(next); },
|
||||
], function(err, list) {
|
||||
if (err) return done(err);
|
||||
Checkpoint.find(function(err, data) {
|
||||
|
@ -64,7 +64,8 @@ describe('Checkpoint', function() {
|
|||
});
|
||||
});
|
||||
|
||||
it('Checkpoint.current() for non existing checkpoint should initialize checkpoint', function(done) {
|
||||
it('Checkpoint.current() for non existing checkpoint should initialize checkpoint',
|
||||
function(done) {
|
||||
Checkpoint.current(function(err, seq) {
|
||||
expect(seq).to.equal(1);
|
||||
done(err);
|
||||
|
|
|
@ -3,7 +3,7 @@ describe('DataSource', function() {
|
|||
|
||||
beforeEach(function() {
|
||||
memory = loopback.createDataSource({
|
||||
connector: loopback.Memory
|
||||
connector: loopback.Memory,
|
||||
});
|
||||
|
||||
assertValidDataSource(memory);
|
||||
|
@ -56,14 +56,13 @@ describe('DataSource', function() {
|
|||
};
|
||||
|
||||
var ds = loopback.createDataSource({
|
||||
connector: new Connector()
|
||||
connector: new Connector(),
|
||||
});
|
||||
|
||||
var Color = ds.createModel('color', { name: String });
|
||||
assert(Color.prototype instanceof Color.registry.getModel('Model'));
|
||||
assert.equal(Color.base.modelName, 'PersistedModel');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe.skip('PersistedModel Methods', function() {
|
||||
|
@ -103,7 +102,9 @@ describe('DataSource', function() {
|
|||
var fn = scope[name];
|
||||
var actuallyEnabled = Model.getRemoteMethod(name);
|
||||
assert(fn, name + ' should be defined!');
|
||||
assert(actuallyEnabled === isRemoteEnabled, name + ' ' + (isRemoteEnabled ? 'should' : 'should not') + ' be remote enabled');
|
||||
assert(actuallyEnabled === isRemoteEnabled,
|
||||
name + ' ' + (isRemoteEnabled ? 'should' : 'should not') +
|
||||
' be remote enabled');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
|
@ -9,14 +9,14 @@ describe('RemoteConnector', function() {
|
|||
// setup the remote connector
|
||||
var ds = loopback.createDataSource({
|
||||
url: 'http://127.0.0.1:3000/api',
|
||||
connector: loopback.Remote
|
||||
connector: loopback.Remote,
|
||||
});
|
||||
TestModel.attachTo(ds);
|
||||
});
|
||||
|
||||
it('should be able to call create', function(done) {
|
||||
TestModel.create({
|
||||
foo: 'bar'
|
||||
foo: 'bar',
|
||||
}, function(err, inst) {
|
||||
if (err) return done(err);
|
||||
assert(inst.id);
|
||||
|
@ -26,7 +26,7 @@ describe('RemoteConnector', function() {
|
|||
|
||||
it('should be able to call save', function(done) {
|
||||
var m = new TestModel({
|
||||
foo: 'bar'
|
||||
foo: 'bar',
|
||||
});
|
||||
m.save(function(err, data) {
|
||||
if (err) return done(err);
|
||||
|
|
|
@ -3,7 +3,7 @@ var loopback = require('../../');
|
|||
var models = require('../fixtures/e2e/models');
|
||||
var TestModel = models.TestModel;
|
||||
var LocalTestModel = TestModel.extend('LocalTestModel', {}, {
|
||||
trackChanges: true
|
||||
trackChanges: true,
|
||||
});
|
||||
var assert = require('assert');
|
||||
|
||||
|
@ -12,7 +12,7 @@ describe('Replication', function() {
|
|||
// setup the remote connector
|
||||
var ds = loopback.createDataSource({
|
||||
url: 'http://127.0.0.1:3000/api',
|
||||
connector: loopback.Remote
|
||||
connector: loopback.Remote,
|
||||
});
|
||||
TestModel.attachTo(ds);
|
||||
var memory = loopback.memory();
|
||||
|
@ -23,7 +23,7 @@ describe('Replication', function() {
|
|||
var RANDOM = Math.random();
|
||||
|
||||
LocalTestModel.create({
|
||||
n: RANDOM
|
||||
n: RANDOM,
|
||||
}, function(err, created) {
|
||||
LocalTestModel.replicate(0, TestModel, function() {
|
||||
if (err) return done(err);
|
||||
|
|
|
@ -6,33 +6,32 @@ var MailConnector = require('../lib/connectors/mail');
|
|||
describe('Email connector', function() {
|
||||
it('should set up SMTP', function() {
|
||||
var connector = new MailConnector({ transports: [
|
||||
{type: 'smtp', service: 'gmail'}
|
||||
{ type: 'smtp', service: 'gmail' },
|
||||
] });
|
||||
assert(connector.transportForName('smtp'));
|
||||
});
|
||||
|
||||
it('should set up DIRECT', function() {
|
||||
var connector = new MailConnector({ transports: [
|
||||
{type: 'direct', name: 'localhost'}
|
||||
{ type: 'direct', name: 'localhost' },
|
||||
] });
|
||||
assert(connector.transportForName('direct'));
|
||||
});
|
||||
|
||||
it('should set up STUB', function() {
|
||||
var connector = new MailConnector({ transports: [
|
||||
{type: 'stub', service: 'gmail'}
|
||||
{ type: 'stub', service: 'gmail' },
|
||||
] });
|
||||
assert(connector.transportForName('stub'));
|
||||
});
|
||||
|
||||
it('should set up a single transport for SMTP', function() {
|
||||
var connector = new MailConnector({ transport:
|
||||
{type: 'smtp', service: 'gmail'}
|
||||
{ type: 'smtp', service: 'gmail' },
|
||||
});
|
||||
|
||||
assert(connector.transportForName('smtp'));
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('Email and SMTP', function() {
|
||||
|
@ -53,7 +52,7 @@ describe('Email and SMTP', function() {
|
|||
from: 'from@from.com',
|
||||
subject: 'subject',
|
||||
text: 'text',
|
||||
html: '<h1>html</h1>'
|
||||
html: '<h1>html</h1>',
|
||||
};
|
||||
|
||||
MyEmail.send(options, function(err, mail) {
|
||||
|
@ -71,7 +70,7 @@ describe('Email and SMTP', function() {
|
|||
from: 'from@from.com',
|
||||
subject: 'subject',
|
||||
text: 'text',
|
||||
html: '<h1>html</h1>'
|
||||
html: '<h1>html</h1>',
|
||||
});
|
||||
|
||||
message.send(function(err, mail) {
|
||||
|
|
|
@ -4,9 +4,7 @@ var assert = require('assert');
|
|||
var request = require('supertest');
|
||||
|
||||
describe('loopback.errorHandler(options)', function() {
|
||||
|
||||
it('should return default middleware when options object is not present', function(done) {
|
||||
|
||||
//arrange
|
||||
var app = loopback();
|
||||
app.use(loopback.urlNotFound());
|
||||
|
@ -22,7 +20,6 @@ describe('loopback.errorHandler(options)', function() {
|
|||
});
|
||||
|
||||
it('should delete stack when options.includeStack is false', function(done) {
|
||||
|
||||
//arrange
|
||||
var app = loopback();
|
||||
app.use(loopback.urlNotFound());
|
||||
|
@ -47,7 +44,7 @@ describe('loopback.errorHandler(options)', function() {
|
|||
includeStack: false,
|
||||
log: function customLogger(err, str, req) {
|
||||
errorLogged = err;
|
||||
}
|
||||
},
|
||||
}));
|
||||
|
||||
//act
|
||||
|
@ -58,6 +55,5 @@ describe('loopback.errorHandler(options)', function() {
|
|||
.to.have.property('message', 'Cannot GET /url-does-not-exist');
|
||||
done();
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
|
|
@ -2,5 +2,5 @@ var loopback = require('../../../../index');
|
|||
var PersistedModel = loopback.PersistedModel;
|
||||
|
||||
exports.TestModel = PersistedModel.extend('TestModel', {}, {
|
||||
trackChanges: true
|
||||
trackChanges: true,
|
||||
});
|
||||
|
|
|
@ -43,11 +43,11 @@ describe('GeoPoint', function() {
|
|||
});
|
||||
it('Create as Model property', function() {
|
||||
var Model = loopback.createModel('geo-model', {
|
||||
geo: {type: 'GeoPoint'}
|
||||
geo: { type: 'GeoPoint' },
|
||||
});
|
||||
|
||||
var m = new Model({
|
||||
geo: '1.222,3.444'
|
||||
geo: '1.222,3.444',
|
||||
});
|
||||
|
||||
assert(m.geo instanceof GeoPoint);
|
||||
|
|
|
@ -4,7 +4,7 @@ var _beforeEach = {};
|
|||
var helpers = {
|
||||
describe: _describe,
|
||||
it: _it,
|
||||
beforeEach: _beforeEach
|
||||
beforeEach: _beforeEach,
|
||||
};
|
||||
module.exports = helpers;
|
||||
|
||||
|
@ -145,7 +145,9 @@ _describe.whenCalledRemotely = function(verb, url, data, cb) {
|
|||
if (methodForVerb === 'delete') methodForVerb = 'del';
|
||||
|
||||
if (this.request === undefined) {
|
||||
throw new Error('App is not specified. Please use lt.beforeEach.withApp to specify the app.');
|
||||
var msg = 'App is not specified. ' +
|
||||
'Please use lt.beforeEach.withApp to specify the app.';
|
||||
throw new Error(msg);
|
||||
}
|
||||
|
||||
this.http = this.request[methodForVerb](this.url);
|
||||
|
|
|
@ -18,11 +18,11 @@ describe('hidden properties', function() {
|
|||
app.use(loopback.rest());
|
||||
|
||||
Category.create({
|
||||
name: 'my category'
|
||||
name: 'my category',
|
||||
}, function(err, category) {
|
||||
category.products.create({
|
||||
name: 'pencil',
|
||||
secret: 'a secret'
|
||||
secret: 'a secret',
|
||||
}, done);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -24,7 +24,7 @@ describe('loopback application', function() {
|
|||
function setupAppWithStreamingMethod() {
|
||||
app.dataSource('db', {
|
||||
connector: loopback.Memory,
|
||||
defaultForType: 'db'
|
||||
defaultForType: 'db',
|
||||
});
|
||||
var db = app.datasources.db;
|
||||
|
||||
|
@ -53,8 +53,8 @@ describe('loopback application', function() {
|
|||
http: { method: 'post' },
|
||||
accepts: [
|
||||
{ arg: 'req', type: 'Object', http: { source: 'req' }},
|
||||
{ arg: 'res', type: 'Object', http: { source: 'res' } }
|
||||
]
|
||||
{ arg: 'res', type: 'Object', http: { source: 'res' }},
|
||||
],
|
||||
});
|
||||
|
||||
app.enableAuth();
|
||||
|
|
|
@ -26,7 +26,7 @@ module.exports = function(config) {
|
|||
'test/replication.test.js',
|
||||
'test/change.test.js',
|
||||
'test/checkpoint.test.js',
|
||||
'test/app.test.js'
|
||||
'test/app.test.js',
|
||||
],
|
||||
|
||||
// list of files / patterns to exclude
|
||||
|
@ -52,7 +52,7 @@ module.exports = function(config) {
|
|||
// - PhantomJS
|
||||
// - IE (only Windows)
|
||||
browsers: [
|
||||
'Chrome'
|
||||
'Chrome',
|
||||
],
|
||||
|
||||
// Which plugins to enable
|
||||
|
@ -61,7 +61,7 @@ module.exports = function(config) {
|
|||
'karma-mocha',
|
||||
'karma-phantomjs-launcher',
|
||||
'karma-chrome-launcher',
|
||||
'karma-junit-reporter'
|
||||
'karma-junit-reporter',
|
||||
],
|
||||
|
||||
// If browser does not capture in given timeout [ms], kill it
|
||||
|
@ -97,7 +97,7 @@ module.exports = function(config) {
|
|||
'passport',
|
||||
'passport-local',
|
||||
'superagent',
|
||||
'supertest'
|
||||
'supertest',
|
||||
],
|
||||
// transform: ['coffeeify'],
|
||||
debug: true,
|
||||
|
@ -106,6 +106,6 @@ module.exports = function(config) {
|
|||
},
|
||||
|
||||
// Add browserify to preprocessors
|
||||
preprocessors: {'test/*': ['browserify']}
|
||||
preprocessors: { 'test/*': ['browserify'] },
|
||||
});
|
||||
};
|
||||
|
|
|
@ -105,7 +105,7 @@ describe('loopback', function() {
|
|||
'urlNotFound',
|
||||
'urlencoded',
|
||||
'version',
|
||||
'vhost'
|
||||
'vhost',
|
||||
];
|
||||
|
||||
var actual = Object.getOwnPropertyNames(loopback);
|
||||
|
@ -135,7 +135,7 @@ describe('loopback', function() {
|
|||
describe('loopback.createDataSource(options)', function() {
|
||||
it('Create a data source with a connector.', function() {
|
||||
var dataSource = loopback.createDataSource({
|
||||
connector: loopback.Memory
|
||||
connector: loopback.Memory,
|
||||
});
|
||||
assert(dataSource.connector);
|
||||
});
|
||||
|
@ -144,7 +144,7 @@ describe('loopback', function() {
|
|||
describe('data source created by loopback', function() {
|
||||
it('should create model extending Model by default', function() {
|
||||
var dataSource = loopback.createDataSource({
|
||||
connector: loopback.Memory
|
||||
connector: loopback.Memory,
|
||||
});
|
||||
var m1 = dataSource.createModel('m1', {});
|
||||
assert(m1.prototype instanceof loopback.Model);
|
||||
|
@ -161,14 +161,14 @@ describe('loopback', function() {
|
|||
describe('loopback.autoAttach', function() {
|
||||
it('doesn\'t overwrite model with datasource configured', function() {
|
||||
var ds1 = loopback.createDataSource('db1', {
|
||||
connector: loopback.Memory
|
||||
connector: loopback.Memory,
|
||||
});
|
||||
|
||||
// setup default data sources
|
||||
loopback.setDefaultDataSourceForType('db', ds1);
|
||||
|
||||
var ds2 = loopback.createDataSource('db2', {
|
||||
connector: loopback.Memory
|
||||
connector: loopback.Memory,
|
||||
});
|
||||
|
||||
var model1 = ds2.createModel('m1', {});
|
||||
|
@ -196,7 +196,7 @@ describe('loopback', function() {
|
|||
Product.stats,
|
||||
{
|
||||
returns: { arg: 'stats', type: 'array' },
|
||||
http: {path: '/info', verb: 'get'}
|
||||
http: { path: '/info', verb: 'get' },
|
||||
}
|
||||
);
|
||||
|
||||
|
@ -213,14 +213,14 @@ describe('loopback', function() {
|
|||
it('should extend from options.base', function() {
|
||||
var MyModel = loopback.createModel('MyModel', {}, {
|
||||
foo: {
|
||||
bar: 'bat'
|
||||
}
|
||||
bar: 'bat',
|
||||
},
|
||||
});
|
||||
var MyCustomModel = loopback.createModel('MyCustomModel', {}, {
|
||||
base: 'MyModel',
|
||||
foo: {
|
||||
bat: 'baz'
|
||||
}
|
||||
bat: 'baz',
|
||||
},
|
||||
});
|
||||
assert(MyCustomModel.super_ === MyModel);
|
||||
assert.deepEqual(MyCustomModel.settings.foo, { bar: 'bat', bat: 'baz' });
|
||||
|
@ -232,14 +232,14 @@ describe('loopback', function() {
|
|||
it('should be able to get model by name', function() {
|
||||
var MyModel = loopback.createModel('MyModel', {}, {
|
||||
foo: {
|
||||
bar: 'bat'
|
||||
}
|
||||
bar: 'bat',
|
||||
},
|
||||
});
|
||||
var MyCustomModel = loopback.createModel('MyCustomModel', {}, {
|
||||
base: 'MyModel',
|
||||
foo: {
|
||||
bat: 'baz'
|
||||
}
|
||||
bat: 'baz',
|
||||
},
|
||||
});
|
||||
assert(loopback.getModel('MyModel') === MyModel);
|
||||
assert(loopback.getModel('MyCustomModel') === MyCustomModel);
|
||||
|
@ -249,14 +249,14 @@ describe('loopback', function() {
|
|||
it('should be able to get model by type', function() {
|
||||
var MyModel = loopback.createModel('MyModel', {}, {
|
||||
foo: {
|
||||
bar: 'bat'
|
||||
}
|
||||
bar: 'bat',
|
||||
},
|
||||
});
|
||||
var MyCustomModel = loopback.createModel('MyCustomModel', {}, {
|
||||
base: 'MyModel',
|
||||
foo: {
|
||||
bat: 'baz'
|
||||
}
|
||||
bat: 'baz',
|
||||
},
|
||||
});
|
||||
assert(loopback.getModelByType(MyModel) === MyCustomModel);
|
||||
assert(loopback.getModelByType(MyCustomModel) === MyCustomModel);
|
||||
|
@ -273,13 +273,13 @@ describe('loopback', function() {
|
|||
methods: {
|
||||
staticMethod: {
|
||||
isStatic: true,
|
||||
http: { path: '/static' }
|
||||
http: { path: '/static' },
|
||||
},
|
||||
instanceMethod: {
|
||||
isStatic: false,
|
||||
http: { path: '/instance' }
|
||||
}
|
||||
}
|
||||
http: { path: '/instance' },
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
var methodNames = TestModel.sharedClass.methods().map(function(m) {
|
||||
|
@ -288,7 +288,7 @@ describe('loopback', function() {
|
|||
|
||||
expect(methodNames).to.include.members([
|
||||
'staticMethod',
|
||||
'prototype.instanceMethod'
|
||||
'prototype.instanceMethod',
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
@ -296,7 +296,7 @@ describe('loopback', function() {
|
|||
describe('loopback.createModel(config)', function() {
|
||||
it('creates the model', function() {
|
||||
var model = loopback.createModel({
|
||||
name: uniqueModelName
|
||||
name: uniqueModelName,
|
||||
});
|
||||
|
||||
expect(model.prototype).to.be.instanceof(loopback.Model);
|
||||
|
@ -305,7 +305,7 @@ describe('loopback', function() {
|
|||
it('interprets extra first-level keys as options', function() {
|
||||
var model = loopback.createModel({
|
||||
name: uniqueModelName,
|
||||
base: 'User'
|
||||
base: 'User',
|
||||
});
|
||||
|
||||
expect(model.prototype).to.be.instanceof(loopback.User);
|
||||
|
@ -316,8 +316,8 @@ describe('loopback', function() {
|
|||
name: uniqueModelName,
|
||||
base: 'User',
|
||||
options: {
|
||||
base: 'Application'
|
||||
}
|
||||
base: 'Application',
|
||||
},
|
||||
});
|
||||
|
||||
expect(model.prototype).to.be.instanceof(loopback.Application);
|
||||
|
@ -333,9 +333,9 @@ describe('loopback', function() {
|
|||
relations: {
|
||||
owner: {
|
||||
type: 'belongsTo',
|
||||
model: 'User'
|
||||
}
|
||||
}
|
||||
model: 'User',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
expect(model.settings.relations).to.have.property('owner');
|
||||
|
@ -346,23 +346,23 @@ describe('loopback', function() {
|
|||
relations: {
|
||||
owner: {
|
||||
type: 'belongsTo',
|
||||
model: 'User'
|
||||
}
|
||||
}
|
||||
model: 'User',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
loopback.configureModel(model, {
|
||||
dataSource: false,
|
||||
relations: {
|
||||
owner: {
|
||||
model: 'Application'
|
||||
}
|
||||
}
|
||||
model: 'Application',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
expect(model.settings.relations.owner).to.eql({
|
||||
type: 'belongsTo',
|
||||
model: 'Application'
|
||||
model: 'Application',
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -375,9 +375,9 @@ describe('loopback', function() {
|
|||
relations: {
|
||||
owner: {
|
||||
type: 'belongsTo',
|
||||
model: 'User'
|
||||
}
|
||||
}
|
||||
model: 'User',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
var owner = model.prototype.owner;
|
||||
|
@ -393,9 +393,9 @@ describe('loopback', function() {
|
|||
accessType: 'EXECUTE',
|
||||
principalType: 'ROLE',
|
||||
principalId: '$everyone',
|
||||
permission: 'DENY'
|
||||
}
|
||||
]
|
||||
permission: 'DENY',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
loopback.configureModel(model, {
|
||||
|
@ -406,9 +406,9 @@ describe('loopback', function() {
|
|||
accessType: 'EXECUTE',
|
||||
principalType: 'ROLE',
|
||||
principalId: 'admin',
|
||||
permission: 'ALLOW'
|
||||
}
|
||||
]
|
||||
permission: 'ALLOW',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
expect(model.settings.acls).eql([
|
||||
|
@ -417,15 +417,15 @@ describe('loopback', function() {
|
|||
accessType: 'EXECUTE',
|
||||
principalType: 'ROLE',
|
||||
principalId: '$everyone',
|
||||
permission: 'DENY'
|
||||
permission: 'DENY',
|
||||
},
|
||||
{
|
||||
property: 'find',
|
||||
accessType: 'EXECUTE',
|
||||
principalType: 'ROLE',
|
||||
principalId: 'admin',
|
||||
permission: 'ALLOW'
|
||||
}
|
||||
permission: 'ALLOW',
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
|
@ -437,9 +437,9 @@ describe('loopback', function() {
|
|||
accessType: 'EXECUTE',
|
||||
principalType: 'ROLE',
|
||||
principalId: '$everyone',
|
||||
permission: 'DENY'
|
||||
}
|
||||
]
|
||||
permission: 'DENY',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
loopback.configureModel(model, {
|
||||
|
@ -450,9 +450,9 @@ describe('loopback', function() {
|
|||
accessType: 'EXECUTE',
|
||||
principalType: 'ROLE',
|
||||
principalId: '$everyone',
|
||||
permission: 'ALLOW'
|
||||
}
|
||||
]
|
||||
permission: 'ALLOW',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
expect(model.settings.acls).eql([
|
||||
|
@ -461,15 +461,15 @@ describe('loopback', function() {
|
|||
accessType: 'EXECUTE',
|
||||
principalType: 'ROLE',
|
||||
principalId: '$everyone',
|
||||
permission: 'ALLOW'
|
||||
}
|
||||
permission: 'ALLOW',
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it('updates existing settings', function() {
|
||||
var model = loopback.Model.extend(uniqueModelName, {}, {
|
||||
ttl: 10,
|
||||
emailVerificationRequired: false
|
||||
emailVerificationRequired: false,
|
||||
});
|
||||
|
||||
var baseName = model.settings.base.name;
|
||||
|
@ -479,8 +479,8 @@ describe('loopback', function() {
|
|||
options: {
|
||||
ttl: 20,
|
||||
realmRequired: true,
|
||||
base: 'X'
|
||||
}
|
||||
base: 'X',
|
||||
},
|
||||
});
|
||||
|
||||
expect(model.settings).to.have.property('ttl', 20);
|
||||
|
@ -499,13 +499,13 @@ describe('loopback', function() {
|
|||
methods: {
|
||||
staticMethod: {
|
||||
isStatic: true,
|
||||
http: { path: '/static' }
|
||||
http: { path: '/static' },
|
||||
},
|
||||
instanceMethod: {
|
||||
isStatic: false,
|
||||
http: { path: '/instance' }
|
||||
}
|
||||
}
|
||||
http: { path: '/instance' },
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
var methodNames = TestModel.sharedClass.methods().map(function(m) {
|
||||
|
@ -514,7 +514,7 @@ describe('loopback', function() {
|
|||
|
||||
expect(methodNames).to.include.members([
|
||||
'staticMethod',
|
||||
'prototype.instanceMethod'
|
||||
'prototype.instanceMethod',
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
@ -538,7 +538,7 @@ describe('loopback', function() {
|
|||
'ACL',
|
||||
'Scope',
|
||||
'Change',
|
||||
'Checkpoint'
|
||||
'Checkpoint',
|
||||
];
|
||||
|
||||
expect(Object.keys(loopback)).to.include.members(expectedModelNames);
|
||||
|
@ -551,8 +551,7 @@ describe('loopback', function() {
|
|||
});
|
||||
|
||||
describe.onServer('loopback.getCurrentContext', function() {
|
||||
var runInOtherDomain;
|
||||
var runnerInterval;
|
||||
var runInOtherDomain, runnerInterval;
|
||||
|
||||
before(function setupRunInOtherDomain() {
|
||||
var emitterInOtherDomain = new EventEmitter();
|
||||
|
@ -594,7 +593,7 @@ describe('loopback', function() {
|
|||
TestModel.remoteMethod('test', {
|
||||
accepts: { arg: 'inst', type: uniqueModelName },
|
||||
returns: { root: true },
|
||||
http: { path: '/test', verb: 'get' }
|
||||
http: { path: '/test', verb: 'get' },
|
||||
});
|
||||
|
||||
// after remote hook
|
||||
|
@ -645,9 +644,9 @@ describe('loopback', function() {
|
|||
dataSource: null,
|
||||
methods: {
|
||||
staticMethod: {
|
||||
http: { path: '/static' }
|
||||
}
|
||||
}
|
||||
http: { path: '/static' },
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
var methodNames = getAllMethodNamesWithoutClassName(TestModel);
|
||||
|
@ -661,9 +660,9 @@ describe('loopback', function() {
|
|||
dataSource: null,
|
||||
methods: {
|
||||
'prototype.instanceMethod': {
|
||||
http: { path: '/instance' }
|
||||
}
|
||||
}
|
||||
http: { path: '/instance' },
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
var methodNames = getAllMethodNamesWithoutClassName(TestModel);
|
||||
|
@ -673,15 +672,17 @@ describe('loopback', function() {
|
|||
|
||||
it('throws an error when "isStatic:true" and method name starts with "prototype."', function() {
|
||||
var TestModel = loopback.createModel(uniqueModelName);
|
||||
expect(function() { loopback.configureModel(TestModel, {
|
||||
expect(function() {
|
||||
loopback.configureModel(TestModel, {
|
||||
dataSource: null,
|
||||
methods: {
|
||||
'prototype.instanceMethod': {
|
||||
isStatic: true,
|
||||
http: { path: '/instance' }
|
||||
}
|
||||
}
|
||||
});}).to.throw(Error, new Error('Remoting metadata for' + TestModel.modelName +
|
||||
http: { path: '/instance' },
|
||||
},
|
||||
},
|
||||
});
|
||||
}).to.throw(Error, new Error('Remoting metadata for' + TestModel.modelName +
|
||||
' "isStatic" does not match new method name-based style.'));
|
||||
});
|
||||
|
||||
|
@ -692,9 +693,9 @@ describe('loopback', function() {
|
|||
methods: {
|
||||
staticMethod: {
|
||||
isStatic: true,
|
||||
http: { path: '/static' }
|
||||
}
|
||||
}
|
||||
http: { path: '/static' },
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
var methodNames = getAllMethodNamesWithoutClassName(TestModel);
|
||||
|
@ -709,9 +710,9 @@ describe('loopback', function() {
|
|||
methods: {
|
||||
'prototype.instanceMethod': {
|
||||
isStatic: false,
|
||||
http: { path: '/instance' }
|
||||
}
|
||||
}
|
||||
http: { path: '/instance' },
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
var methodNames = getAllMethodNamesWithoutClassName(TestModel);
|
||||
|
|
|
@ -7,14 +7,14 @@ describe('Memory Connector', function() {
|
|||
// or create it using the standard
|
||||
// data source creation api
|
||||
memory = loopback.createDataSource({
|
||||
connector: loopback.Memory
|
||||
connector: loopback.Memory,
|
||||
});
|
||||
|
||||
// create a model using the
|
||||
// memory data source
|
||||
var properties = {
|
||||
name: String,
|
||||
price: Number
|
||||
price: Number,
|
||||
};
|
||||
|
||||
var Product = memory.createModel('product', properties);
|
||||
|
|
|
@ -62,18 +62,18 @@ describe('Application', function() {
|
|||
keyData: 'key',
|
||||
pushOptions: {
|
||||
gateway: 'gateway.sandbox.push.apple.com',
|
||||
port: 2195
|
||||
port: 2195,
|
||||
},
|
||||
feedbackOptions: {
|
||||
gateway: 'feedback.sandbox.push.apple.com',
|
||||
port: 2196,
|
||||
interval: 300,
|
||||
batchFeedback: true
|
||||
}
|
||||
batchFeedback: true,
|
||||
},
|
||||
},
|
||||
gcm: {
|
||||
serverApiKey: 'serverKey'
|
||||
}
|
||||
serverApiKey: 'serverKey',
|
||||
},
|
||||
}},
|
||||
function(err, result) {
|
||||
var app = result;
|
||||
|
@ -84,18 +84,18 @@ describe('Application', function() {
|
|||
keyData: 'key',
|
||||
pushOptions: {
|
||||
gateway: 'gateway.sandbox.push.apple.com',
|
||||
port: 2195
|
||||
port: 2195,
|
||||
},
|
||||
feedbackOptions: {
|
||||
gateway: 'feedback.sandbox.push.apple.com',
|
||||
port: 2196,
|
||||
interval: 300,
|
||||
batchFeedback: true
|
||||
}
|
||||
batchFeedback: true,
|
||||
},
|
||||
},
|
||||
gcm: {
|
||||
serverApiKey: 'serverKey'
|
||||
}
|
||||
serverApiKey: 'serverKey',
|
||||
},
|
||||
});
|
||||
done(err, result);
|
||||
});
|
||||
|
|
|
@ -10,8 +10,8 @@ var describe = require('./util/describe');
|
|||
describe('Model / PersistedModel', function() {
|
||||
defineModelTestsWithDataSource({
|
||||
dataSource: {
|
||||
connector: loopback.Memory
|
||||
}
|
||||
connector: loopback.Memory,
|
||||
},
|
||||
});
|
||||
|
||||
describe('Model.validatesUniquenessOf(property, options)', function() {
|
||||
|
@ -23,11 +23,11 @@ describe('Model / PersistedModel', function() {
|
|||
'password': String,
|
||||
'gender': String,
|
||||
'domain': String,
|
||||
'email': String
|
||||
'email': String,
|
||||
});
|
||||
|
||||
var dataSource = loopback.createDataSource({
|
||||
connector: loopback.Memory
|
||||
connector: loopback.Memory,
|
||||
});
|
||||
|
||||
User.attachTo(dataSource);
|
||||
|
@ -52,23 +52,21 @@ describe('Model / PersistedModel', function() {
|
|||
it('Attach a model to a [DataSource](#data-source)', function() {
|
||||
var MyModel = loopback.createModel('my-model', { name: String });
|
||||
var dataSource = loopback.createDataSource({
|
||||
connector: loopback.Memory
|
||||
connector: loopback.Memory,
|
||||
});
|
||||
|
||||
MyModel.attachTo(dataSource);
|
||||
|
||||
MyModel.find(function(err, results) {
|
||||
assert(results.length === 0, 'should have data access methods after attaching to a data source');
|
||||
assert(results.length === 0,
|
||||
'should have data access methods after attaching to a data source');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe.onServer('Remote Methods', function() {
|
||||
|
||||
var User, Post;
|
||||
var dataSource;
|
||||
var app;
|
||||
var User, Post, dataSource, app;
|
||||
|
||||
beforeEach(function() {
|
||||
User = PersistedModel.extend('user', {
|
||||
|
@ -79,21 +77,21 @@ describe.onServer('Remote Methods', function() {
|
|||
'password': String,
|
||||
'gender': String,
|
||||
'domain': String,
|
||||
'email': String
|
||||
'email': String,
|
||||
}, {
|
||||
trackChanges: true
|
||||
trackChanges: true,
|
||||
});
|
||||
|
||||
Post = PersistedModel.extend('post', {
|
||||
id: { id: true, type: String, defaultFn: 'guid' },
|
||||
title: String,
|
||||
content: String
|
||||
content: String,
|
||||
}, {
|
||||
trackChanges: true
|
||||
trackChanges: true,
|
||||
});
|
||||
|
||||
dataSource = loopback.createDataSource({
|
||||
connector: loopback.Memory
|
||||
connector: loopback.Memory,
|
||||
});
|
||||
|
||||
User.attachTo(dataSource);
|
||||
|
@ -114,10 +112,10 @@ describe.onServer('Remote Methods', function() {
|
|||
{
|
||||
accepts: [
|
||||
{ arg: 'username', type: 'string', required: true },
|
||||
{arg: 'password', type: 'string', required: true}
|
||||
{ arg: 'password', type: 'string', required: true },
|
||||
],
|
||||
returns: { arg: 'sessionId', type: 'any', root: true },
|
||||
http: {path: '/sign-in', verb: 'get'}
|
||||
http: { path: '/sign-in', verb: 'get' },
|
||||
}
|
||||
);
|
||||
|
||||
|
@ -230,7 +228,6 @@ describe.onServer('Remote Methods', function() {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('Model.beforeRemote(name, fn)', function() {
|
||||
|
@ -399,7 +396,7 @@ describe.onServer('Remote Methods', function() {
|
|||
n: { type: 'Number' },
|
||||
o: { type: 'String', min: 10, max: 100 },
|
||||
d: Date,
|
||||
g: loopback.GeoPoint
|
||||
g: loopback.GeoPoint,
|
||||
};
|
||||
|
||||
var MyModel = loopback.createModel('foo', props);
|
||||
|
@ -426,7 +423,7 @@ describe.onServer('Remote Methods', function() {
|
|||
describe('Model.extend()', function() {
|
||||
it('Create a new model by extending an existing model', function() {
|
||||
var User = loopback.PersistedModel.extend('test-user', {
|
||||
email: String
|
||||
email: String,
|
||||
});
|
||||
|
||||
User.foo = function() {
|
||||
|
@ -439,7 +436,7 @@ describe.onServer('Remote Methods', function() {
|
|||
|
||||
var MyUser = User.extend('my-user', {
|
||||
a: String,
|
||||
b: String
|
||||
b: String,
|
||||
});
|
||||
|
||||
assert.equal(MyUser.prototype.bar, User.prototype.bar);
|
||||
|
@ -448,7 +445,7 @@ describe.onServer('Remote Methods', function() {
|
|||
var user = new MyUser({
|
||||
email: 'foo@bar.com',
|
||||
a: 'foo',
|
||||
b: 'bar'
|
||||
b: 'bar',
|
||||
});
|
||||
|
||||
assert.equal(user.email, 'foo@bar.com');
|
||||
|
@ -461,11 +458,11 @@ describe.onServer('Remote Methods', function() {
|
|||
it('create isolated emitters for subclasses', function() {
|
||||
var User1 = loopback.createModel('User1', {
|
||||
'first': String,
|
||||
'last': String
|
||||
'last': String,
|
||||
});
|
||||
|
||||
var User2 = loopback.createModel('User2', {
|
||||
'name': String
|
||||
'name': String,
|
||||
});
|
||||
|
||||
var user1Triggered = false;
|
||||
|
@ -486,7 +483,6 @@ describe.onServer('Remote Methods', function() {
|
|||
assert(user1Triggered);
|
||||
assert(!user2Triggered);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('Model.checkAccessTypeForMethod(remoteMethod)', function() {
|
||||
|
@ -538,10 +534,9 @@ describe.onServer('Remote Methods', function() {
|
|||
var Checkpoint = User.getChangeModel().getCheckpointModel();
|
||||
var tasks = [
|
||||
getCurrentCheckpoint,
|
||||
checkpoint
|
||||
checkpoint,
|
||||
];
|
||||
var result;
|
||||
var current;
|
||||
var result, current;
|
||||
|
||||
async.series(tasks, function(err) {
|
||||
if (err) return done(err);
|
||||
|
@ -615,7 +610,7 @@ describe.onServer('Remote Methods', function() {
|
|||
'removeById',
|
||||
'count',
|
||||
'prototype.updateAttributes',
|
||||
'createChangeStream'
|
||||
'createChangeStream',
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
/*jshint -W030 */
|
||||
|
||||
var loopback = require('../');
|
||||
var lt = require('./helpers/loopback-testing-helper');
|
||||
var path = require('path');
|
||||
|
@ -11,14 +9,13 @@ var debug = require('debug')('loopback:test:relations.integration');
|
|||
var async = require('async');
|
||||
|
||||
describe('relations - integration', function() {
|
||||
|
||||
lt.beforeEach.withApp(app);
|
||||
|
||||
lt.beforeEach.givenModel('store');
|
||||
beforeEach(function(done) {
|
||||
this.widgetName = 'foo';
|
||||
this.store.widgets.create({
|
||||
name: this.widgetName
|
||||
name: this.widgetName,
|
||||
}, function() {
|
||||
done();
|
||||
});
|
||||
|
@ -28,36 +25,35 @@ describe('relations - integration', function() {
|
|||
});
|
||||
|
||||
describe('polymorphicHasMany', function() {
|
||||
|
||||
before(function defineProductAndCategoryModels() {
|
||||
var Team = app.model(
|
||||
'Team',
|
||||
{ properties: { name: 'string' },
|
||||
dataSource: 'db'
|
||||
dataSource: 'db',
|
||||
}
|
||||
);
|
||||
var Reader = app.model(
|
||||
'Reader',
|
||||
{ properties: { name: 'string' },
|
||||
dataSource: 'db'
|
||||
dataSource: 'db',
|
||||
}
|
||||
);
|
||||
var Picture = app.model(
|
||||
'Picture',
|
||||
{ properties: { name: 'string', imageableId: 'number', imageableType: 'string' },
|
||||
dataSource: 'db'
|
||||
dataSource: 'db',
|
||||
}
|
||||
);
|
||||
|
||||
Reader.hasMany(Picture, { polymorphic: { // alternative syntax
|
||||
as: 'imageable', // if not set, default to: reference
|
||||
foreignKey: 'imageableId', // defaults to 'as + Id'
|
||||
discriminator: 'imageableType' // defaults to 'as + Type'
|
||||
discriminator: 'imageableType', // defaults to 'as + Type'
|
||||
}});
|
||||
|
||||
Picture.belongsTo('imageable', { polymorphic: {
|
||||
foreignKey: 'imageableId',
|
||||
discriminator: 'imageableType'
|
||||
discriminator: 'imageableType',
|
||||
}});
|
||||
|
||||
Reader.belongsTo(Team);
|
||||
|
@ -119,7 +115,10 @@ describe('relations - integration', function() {
|
|||
it('includes related models scoped to the related parent model', function(done) {
|
||||
var url = '/api/pictures';
|
||||
this.get(url)
|
||||
.query({'filter': {'include' : {'relation': 'imageable', 'scope': { 'include' : 'team'}}}})
|
||||
.query({ 'filter': { 'include': {
|
||||
'relation': 'imageable',
|
||||
'scope': { 'include': 'team' },
|
||||
}}})
|
||||
.expect(200, function(err, res) {
|
||||
if (err) return done(err);
|
||||
expect(res.body[0].name).to.be.equal('Picture 1');
|
||||
|
@ -129,7 +128,6 @@ describe('relations - integration', function() {
|
|||
done();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('/store/superStores', function() {
|
||||
|
@ -148,7 +146,6 @@ describe('relations - integration', function() {
|
|||
this.url = '/api/stores/' + this.store.id + '/widgets';
|
||||
});
|
||||
lt.describe.whenCalledRemotely('GET', '/api/stores/:id/widgets', function() {
|
||||
|
||||
it('should succeed with statusCode 200', function() {
|
||||
assert.equal(this.res.statusCode, 200);
|
||||
});
|
||||
|
@ -180,7 +177,7 @@ describe('relations - integration', function() {
|
|||
beforeEach(function() {
|
||||
this.newWidgetName = 'baz';
|
||||
this.newWidget = {
|
||||
name: this.newWidgetName
|
||||
name: this.newWidgetName,
|
||||
};
|
||||
});
|
||||
beforeEach(function(done) {
|
||||
|
@ -212,7 +209,7 @@ describe('relations - integration', function() {
|
|||
});
|
||||
it('should have a single widget with storeId', function(done) {
|
||||
this.app.models.widget.count({
|
||||
storeId: this.store.id
|
||||
storeId: this.store.id,
|
||||
}, function(err, count) {
|
||||
if (err) return done(err);
|
||||
assert.equal(count, 2);
|
||||
|
@ -226,7 +223,7 @@ describe('relations - integration', function() {
|
|||
beforeEach(function(done) {
|
||||
var self = this;
|
||||
this.store.widgets.create({
|
||||
name: this.widgetName
|
||||
name: this.widgetName,
|
||||
}, function(err, widget) {
|
||||
self.widget = widget;
|
||||
self.url = '/api/stores/' + self.store.id + '/widgets/' + widget.id;
|
||||
|
@ -299,7 +296,7 @@ describe('relations - integration', function() {
|
|||
beforeEach(function(done) {
|
||||
var self = this;
|
||||
this.store.widgets.create({
|
||||
name: this.widgetName
|
||||
name: this.widgetName,
|
||||
}, function(err, widget) {
|
||||
self.widget = widget;
|
||||
self.url = '/api/widgets/' + self.widget.id + '/store';
|
||||
|
@ -315,7 +312,6 @@ describe('relations - integration', function() {
|
|||
});
|
||||
|
||||
describe('hasMany through', function() {
|
||||
|
||||
function setup(connecting, cb) {
|
||||
var root = {};
|
||||
|
||||
|
@ -334,7 +330,7 @@ describe('relations - integration', function() {
|
|||
// Create a physician
|
||||
function(done) {
|
||||
app.models.physician.create({
|
||||
name: 'ph1'
|
||||
name: 'ph1',
|
||||
}, function(err, physician) {
|
||||
root.physician = physician;
|
||||
done();
|
||||
|
@ -344,7 +340,7 @@ describe('relations - integration', function() {
|
|||
// Create a patient
|
||||
connecting ? function(done) {
|
||||
root.physician.patients.create({
|
||||
name: 'pa1'
|
||||
name: 'pa1',
|
||||
}, function(err, patient) {
|
||||
root.patient = patient;
|
||||
root.relUrl = '/api/physicians/' + root.physician.id +
|
||||
|
@ -353,7 +349,7 @@ describe('relations - integration', function() {
|
|||
});
|
||||
} : function(done) {
|
||||
app.models.patient.create({
|
||||
name: 'pa1'
|
||||
name: 'pa1',
|
||||
}, function(err, patient) {
|
||||
root.patient = patient;
|
||||
root.relUrl = '/api/physicians/' + root.physician.id +
|
||||
|
@ -366,7 +362,6 @@ describe('relations - integration', function() {
|
|||
}
|
||||
|
||||
describe('PUT /physicians/:id/patients/rel/:fk', function() {
|
||||
|
||||
before(function(done) {
|
||||
var self = this;
|
||||
setup(false, function(err, root) {
|
||||
|
@ -405,7 +400,6 @@ describe('relations - integration', function() {
|
|||
});
|
||||
|
||||
describe('PUT /physicians/:id/patients/rel/:fk with data', function() {
|
||||
|
||||
before(function(done) {
|
||||
var self = this;
|
||||
setup(false, function(err, root) {
|
||||
|
@ -450,7 +444,6 @@ describe('relations - integration', function() {
|
|||
});
|
||||
|
||||
describe('HEAD /physicians/:id/patients/rel/:fk', function() {
|
||||
|
||||
before(function(done) {
|
||||
var self = this;
|
||||
setup(true, function(err, root) {
|
||||
|
@ -469,7 +462,6 @@ describe('relations - integration', function() {
|
|||
});
|
||||
|
||||
describe('HEAD /physicians/:id/patients/rel/:fk that does not exist', function() {
|
||||
|
||||
before(function(done) {
|
||||
var self = this;
|
||||
setup(true, function(err, root) {
|
||||
|
@ -489,7 +481,6 @@ describe('relations - integration', function() {
|
|||
});
|
||||
|
||||
describe('DELETE /physicians/:id/patients/rel/:fk', function() {
|
||||
|
||||
before(function(done) {
|
||||
var self = this;
|
||||
setup(true, function(err, root) {
|
||||
|
@ -543,7 +534,6 @@ describe('relations - integration', function() {
|
|||
});
|
||||
|
||||
describe('GET /physicians/:id/patients/:fk', function() {
|
||||
|
||||
before(function(done) {
|
||||
var self = this;
|
||||
setup(true, function(err, root) {
|
||||
|
@ -564,7 +554,6 @@ describe('relations - integration', function() {
|
|||
});
|
||||
|
||||
describe('DELETE /physicians/:id/patients/:fk', function() {
|
||||
|
||||
before(function(done) {
|
||||
var self = this;
|
||||
setup(true, function(err, root) {
|
||||
|
@ -605,7 +594,6 @@ describe('relations - integration', function() {
|
|||
done();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -630,7 +618,7 @@ describe('relations - integration', function() {
|
|||
beforeEach(function createProductsInCategory(done) {
|
||||
var test = this;
|
||||
this.category.products.create({
|
||||
name: 'a-product'
|
||||
name: 'a-product',
|
||||
}, function(err, product) {
|
||||
if (err) return done(err);
|
||||
test.product = product;
|
||||
|
@ -659,8 +647,8 @@ describe('relations - integration', function() {
|
|||
expect(res.body).to.eql([
|
||||
{
|
||||
id: expectedProduct.id,
|
||||
name: expectedProduct.name
|
||||
}
|
||||
name: expectedProduct.name,
|
||||
},
|
||||
]);
|
||||
done();
|
||||
});
|
||||
|
@ -674,8 +662,8 @@ describe('relations - integration', function() {
|
|||
expect(res.body).to.eql([
|
||||
{
|
||||
id: expectedProduct.id,
|
||||
name: expectedProduct.name
|
||||
}
|
||||
name: expectedProduct.name,
|
||||
},
|
||||
]);
|
||||
done();
|
||||
});
|
||||
|
@ -693,8 +681,8 @@ describe('relations - integration', function() {
|
|||
expect(res.body.products).to.eql([
|
||||
{
|
||||
id: expectedProduct.id,
|
||||
name: expectedProduct.name
|
||||
}
|
||||
name: expectedProduct.name,
|
||||
},
|
||||
]);
|
||||
done();
|
||||
});
|
||||
|
@ -713,8 +701,8 @@ describe('relations - integration', function() {
|
|||
expect(res.body.products).to.eql([
|
||||
{
|
||||
id: expectedProduct.id,
|
||||
name: expectedProduct.name
|
||||
}
|
||||
name: expectedProduct.name,
|
||||
},
|
||||
]);
|
||||
done();
|
||||
});
|
||||
|
@ -722,13 +710,12 @@ describe('relations - integration', function() {
|
|||
});
|
||||
|
||||
describe('embedsOne', function() {
|
||||
|
||||
before(function defineGroupAndPosterModels() {
|
||||
var group = app.model(
|
||||
'group',
|
||||
{ properties: { name: 'string' },
|
||||
dataSource: 'db',
|
||||
plural: 'groups'
|
||||
plural: 'groups',
|
||||
}
|
||||
);
|
||||
var poster = app.model(
|
||||
|
@ -825,17 +812,15 @@ describe('relations - integration', function() {
|
|||
var url = '/api/groups/' + this.group.id + '/cover';
|
||||
this.get(url).expect(404, done);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('embedsMany', function() {
|
||||
|
||||
before(function defineProductAndCategoryModels() {
|
||||
var todoList = app.model(
|
||||
'todoList',
|
||||
{ properties: { name: 'string' },
|
||||
dataSource: 'db',
|
||||
plural: 'todo-lists'
|
||||
plural: 'todo-lists',
|
||||
}
|
||||
);
|
||||
var todoItem = app.model(
|
||||
|
@ -870,7 +855,7 @@ describe('relations - integration', function() {
|
|||
expect(res.body.name).to.be.equal('List A');
|
||||
expect(res.body.todoItems).to.be.eql([
|
||||
{ content: 'Todo 1', id: 1 },
|
||||
{ content: 'Todo 2', id: 2 }
|
||||
{ content: 'Todo 2', id: 2 },
|
||||
]);
|
||||
done();
|
||||
});
|
||||
|
@ -884,7 +869,7 @@ describe('relations - integration', function() {
|
|||
if (err) return done(err);
|
||||
expect(res.body).to.be.eql([
|
||||
{ content: 'Todo 1', id: 1 },
|
||||
{ content: 'Todo 2', id: 2 }
|
||||
{ content: 'Todo 2', id: 2 },
|
||||
]);
|
||||
done();
|
||||
});
|
||||
|
@ -898,7 +883,7 @@ describe('relations - integration', function() {
|
|||
.expect(200, function(err, res) {
|
||||
if (err) return done(err);
|
||||
expect(res.body).to.be.eql([
|
||||
{ content: 'Todo 2', id: 2 }
|
||||
{ content: 'Todo 2', id: 2 },
|
||||
]);
|
||||
done();
|
||||
});
|
||||
|
@ -926,7 +911,7 @@ describe('relations - integration', function() {
|
|||
expect(res.body).to.be.eql([
|
||||
{ content: 'Todo 1', id: 1 },
|
||||
{ content: 'Todo 2', id: 2 },
|
||||
{ content: 'Todo 3', id: 3 }
|
||||
{ content: 'Todo 3', id: 3 },
|
||||
]);
|
||||
done();
|
||||
});
|
||||
|
@ -963,7 +948,7 @@ describe('relations - integration', function() {
|
|||
if (err) return done(err);
|
||||
expect(res.body).to.be.eql([
|
||||
{ content: 'Todo 1', id: 1 },
|
||||
{ content: 'Todo 3', id: 3 }
|
||||
{ content: 'Todo 3', id: 3 },
|
||||
]);
|
||||
done();
|
||||
});
|
||||
|
@ -997,11 +982,9 @@ describe('relations - integration', function() {
|
|||
done();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('referencesMany', function() {
|
||||
|
||||
before(function defineProductAndCategoryModels() {
|
||||
var recipe = app.model(
|
||||
'recipe',
|
||||
|
@ -1018,7 +1001,7 @@ describe('relations - integration', function() {
|
|||
recipe.referencesMany(ingredient);
|
||||
// contrived example for test:
|
||||
recipe.hasOne(photo, { as: 'picture', options: {
|
||||
http: { path: 'image' }
|
||||
http: { path: 'image' },
|
||||
}});
|
||||
});
|
||||
|
||||
|
@ -1090,7 +1073,7 @@ describe('relations - integration', function() {
|
|||
expect(res.body).to.be.eql([
|
||||
{ name: 'Chocolate', id: test.ingredient1 },
|
||||
{ name: 'Sugar', id: test.ingredient2 },
|
||||
{ name: 'Butter', id: test.ingredient3 }
|
||||
{ name: 'Butter', id: test.ingredient3 },
|
||||
]);
|
||||
done();
|
||||
});
|
||||
|
@ -1105,7 +1088,7 @@ describe('relations - integration', function() {
|
|||
if (err) return done(err);
|
||||
expect(res.body).to.be.eql([
|
||||
{ name: 'Chocolate', id: test.ingredient1 },
|
||||
{ name: 'Butter', id: test.ingredient3 }
|
||||
{ name: 'Butter', id: test.ingredient3 },
|
||||
]);
|
||||
done();
|
||||
});
|
||||
|
@ -1120,7 +1103,7 @@ describe('relations - integration', function() {
|
|||
.expect(200, function(err, res) {
|
||||
if (err) return done(err);
|
||||
expect(res.body).to.be.eql([
|
||||
{ name: 'Butter', id: test.ingredient3 }
|
||||
{ name: 'Butter', id: test.ingredient3 },
|
||||
]);
|
||||
done();
|
||||
});
|
||||
|
@ -1135,11 +1118,11 @@ describe('relations - integration', function() {
|
|||
.expect(200, function(err, res) {
|
||||
if (err) return done(err);
|
||||
expect(res.body.ingredientIds).to.eql([
|
||||
test.ingredient1, test.ingredient3
|
||||
test.ingredient1, test.ingredient3,
|
||||
]);
|
||||
expect(res.body.ingredients).to.eql([
|
||||
{ name: 'Chocolate', id: test.ingredient1 },
|
||||
{ name: 'Butter', id: test.ingredient3 }
|
||||
{ name: 'Butter', id: test.ingredient3 },
|
||||
]);
|
||||
done();
|
||||
});
|
||||
|
@ -1195,7 +1178,7 @@ describe('relations - integration', function() {
|
|||
if (err) return done(err);
|
||||
expect(res.body).to.be.eql([
|
||||
{ name: 'Chocolate', id: test.ingredient1 },
|
||||
{ name: 'Sugar', id: test.ingredient2 }
|
||||
{ name: 'Sugar', id: test.ingredient2 },
|
||||
]);
|
||||
done();
|
||||
});
|
||||
|
@ -1209,7 +1192,7 @@ describe('relations - integration', function() {
|
|||
.expect(200, function(err, res) {
|
||||
if (err) return done(err);
|
||||
expect(res.body).to.be.eql([
|
||||
{ name: 'Chocolate', id: test.ingredient1 }
|
||||
{ name: 'Chocolate', id: test.ingredient1 },
|
||||
]);
|
||||
done();
|
||||
});
|
||||
|
@ -1238,7 +1221,7 @@ describe('relations - integration', function() {
|
|||
if (err) return done(err);
|
||||
expect(res.body).to.be.eql([
|
||||
{ name: 'Chocolate', id: test.ingredient1 },
|
||||
{ name: 'Sugar', id: test.ingredient2 }
|
||||
{ name: 'Sugar', id: test.ingredient2 },
|
||||
]);
|
||||
done();
|
||||
});
|
||||
|
@ -1263,7 +1246,7 @@ describe('relations - integration', function() {
|
|||
.expect(200, function(err, res) {
|
||||
if (err) return done(err);
|
||||
expect(res.body).to.be.eql([
|
||||
{ name: 'Sugar', id: test.ingredient2 }
|
||||
{ name: 'Sugar', id: test.ingredient2 },
|
||||
]);
|
||||
done();
|
||||
});
|
||||
|
@ -1278,7 +1261,7 @@ describe('relations - integration', function() {
|
|||
if (err) return done(err);
|
||||
expect(res.body).to.be.eql([
|
||||
{ name: 'Chocolate', id: test.ingredient1 },
|
||||
{ name: 'Sugar', id: test.ingredient2 }
|
||||
{ name: 'Sugar', id: test.ingredient2 },
|
||||
]);
|
||||
done();
|
||||
});
|
||||
|
@ -1315,11 +1298,9 @@ describe('relations - integration', function() {
|
|||
done();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('nested relations', function() {
|
||||
|
||||
before(function defineModels() {
|
||||
var Book = app.model(
|
||||
'Book',
|
||||
|
@ -1375,7 +1356,6 @@ describe('relations - integration', function() {
|
|||
ctx.res.set('x-after', 'after');
|
||||
next();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
before(function createBook(done) {
|
||||
|
@ -1636,5 +1616,4 @@ describe('relations - integration', function() {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
|
|
@ -2,8 +2,7 @@ var loopback = require('../');
|
|||
var defineModelTestsWithDataSource = require('./util/model-tests');
|
||||
|
||||
describe('RemoteConnector', function() {
|
||||
var remoteApp;
|
||||
var remote;
|
||||
var remoteApp, remote;
|
||||
|
||||
defineModelTestsWithDataSource({
|
||||
beforeEach: function(done) {
|
||||
|
@ -14,7 +13,7 @@ describe('RemoteConnector', function() {
|
|||
test.dataSource = loopback.createDataSource({
|
||||
host: 'localhost',
|
||||
port: remoteApp.get('port'),
|
||||
connector: loopback.Remote
|
||||
connector: loopback.Remote,
|
||||
});
|
||||
done();
|
||||
});
|
||||
|
@ -23,10 +22,10 @@ describe('RemoteConnector', function() {
|
|||
var RemoteModel = Model.extend('Remote' + Model.modelName, {},
|
||||
{ plural: Model.pluralModelName });
|
||||
RemoteModel.attachTo(loopback.createDataSource({
|
||||
connector: loopback.Memory
|
||||
connector: loopback.Memory,
|
||||
}));
|
||||
remoteApp.model(RemoteModel);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
beforeEach(function(done) {
|
||||
|
@ -41,7 +40,7 @@ describe('RemoteConnector', function() {
|
|||
test.remote = loopback.createDataSource({
|
||||
host: 'localhost',
|
||||
port: remoteApp.get('port'),
|
||||
connector: loopback.Remote
|
||||
connector: loopback.Remote,
|
||||
});
|
||||
done();
|
||||
});
|
||||
|
|
|
@ -16,14 +16,14 @@ describe('remoting coercion', function() {
|
|||
};
|
||||
TestModel.remoteMethod('test', {
|
||||
accepts: { arg: 'inst', type: 'TestModel', http: { source: 'body' }},
|
||||
http: {path: '/test', verb: 'post'}
|
||||
http: { path: '/test', verb: 'post' },
|
||||
});
|
||||
|
||||
request(app)
|
||||
.post('/TestModels/test')
|
||||
.set('Content-Type', 'application/json')
|
||||
.send({
|
||||
foo: 'bar'
|
||||
foo: 'bar',
|
||||
})
|
||||
.end(function(err) {
|
||||
if (err) return done(err);
|
||||
|
|
|
@ -6,7 +6,6 @@ var app = require(path.join(SIMPLE_APP, 'server/server.js'));
|
|||
var assert = require('assert');
|
||||
|
||||
describe('remoting - integration', function() {
|
||||
|
||||
lt.beforeEach.withApp(app);
|
||||
lt.beforeEach.givenModel('store');
|
||||
|
||||
|
@ -34,7 +33,7 @@ describe('remoting - integration', function() {
|
|||
}
|
||||
this.http = this.post('/api/stores');
|
||||
this.http.send({
|
||||
'name': name
|
||||
'name': name,
|
||||
});
|
||||
this.http.end(function(err) {
|
||||
if (err) return done(err);
|
||||
|
@ -53,7 +52,7 @@ describe('remoting - integration', function() {
|
|||
}
|
||||
this.http = this.post('/api/stores');
|
||||
this.http.send({
|
||||
'name': name
|
||||
'name': name,
|
||||
});
|
||||
this.http.end(function(err) {
|
||||
if (err) return done(err);
|
||||
|
@ -88,7 +87,7 @@ describe('remoting - integration', function() {
|
|||
' ',
|
||||
m.getHttpMethod(),
|
||||
' ',
|
||||
m.getFullPath()
|
||||
m.getFullPath(),
|
||||
].join('');
|
||||
}
|
||||
|
||||
|
@ -121,7 +120,7 @@ describe('remoting - integration', function() {
|
|||
'deleteById(id:any):object DELETE /stores/:id',
|
||||
'count(where:object):number GET /stores/count',
|
||||
'prototype.updateAttributes(data:object):store PUT /stores/:id',
|
||||
'createChangeStream(options:object):ReadableStream POST /stores/change-stream'
|
||||
'createChangeStream(options:object):ReadableStream POST /stores/change-stream',
|
||||
];
|
||||
|
||||
// The list of methods is from docs:
|
||||
|
@ -143,7 +142,7 @@ describe('remoting - integration', function() {
|
|||
'__get__superStores(filter:object):store GET /stores/superStores',
|
||||
'__create__superStores(data:store):store POST /stores/superStores',
|
||||
'__delete__superStores() DELETE /stores/superStores',
|
||||
'__count__superStores(where:object):number GET /stores/superStores/count'
|
||||
'__count__superStores(where:object):number GET /stores/superStores/count',
|
||||
];
|
||||
|
||||
expect(methods).to.include.members(expectedMethods);
|
||||
|
@ -151,7 +150,6 @@ describe('remoting - integration', function() {
|
|||
|
||||
it('should have correct signatures for belongsTo methods',
|
||||
function() {
|
||||
|
||||
var widgetClass = findClass('widget');
|
||||
var methods = widgetClass.methods
|
||||
.filter(function(m) {
|
||||
|
@ -163,14 +161,13 @@ describe('remoting - integration', function() {
|
|||
|
||||
var expectedMethods = [
|
||||
'prototype.__get__store(refresh:boolean):store ' +
|
||||
'GET /widgets/:id/store'
|
||||
'GET /widgets/:id/store',
|
||||
];
|
||||
expect(methods).to.include.members(expectedMethods);
|
||||
});
|
||||
|
||||
it('should have correct signatures for hasMany methods',
|
||||
function() {
|
||||
|
||||
var physicianClass = findClass('store');
|
||||
var methods = physicianClass.methods
|
||||
.filter(function(m) {
|
||||
|
@ -194,14 +191,13 @@ describe('remoting - integration', function() {
|
|||
'prototype.__delete__widgets() ' +
|
||||
'DELETE /stores/:id/widgets',
|
||||
'prototype.__count__widgets(where:object):number ' +
|
||||
'GET /stores/:id/widgets/count'
|
||||
'GET /stores/:id/widgets/count',
|
||||
];
|
||||
expect(methods).to.include.members(expectedMethods);
|
||||
});
|
||||
|
||||
it('should have correct signatures for hasMany-through methods',
|
||||
function() { // jscs:disable validateIndentation
|
||||
|
||||
var physicianClass = findClass('physician');
|
||||
var methods = physicianClass.methods
|
||||
.filter(function(m) {
|
||||
|
@ -231,10 +227,9 @@ describe('remoting - integration', function() {
|
|||
'prototype.__delete__patients() ' +
|
||||
'DELETE /physicians/:id/patients',
|
||||
'prototype.__count__patients(where:object):number ' +
|
||||
'GET /physicians/:id/patients/count'
|
||||
'GET /physicians/:id/patients/count',
|
||||
];
|
||||
expect(methods).to.include.members(expectedMethods);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
|
|
@ -10,10 +10,12 @@ describe('Replication over REST', function() {
|
|||
var PETER = { id: 'p', username: 'peter', email: 'p@t.io', password: 'p' };
|
||||
var EMERY = { id: 'e', username: 'emery', email: 'e@t.io', password: 'p' };
|
||||
|
||||
/* eslint-disable one-var */
|
||||
var serverApp, serverUrl, ServerUser, ServerCar, serverCars;
|
||||
var aliceId, peterId, aliceToken, peterToken, emeryToken, request;
|
||||
var clientApp, LocalUser, LocalCar, RemoteUser, RemoteCar, clientCars;
|
||||
var conflictedCarId;
|
||||
/* eslint-enable one-var */
|
||||
|
||||
before(setupServer);
|
||||
before(setupClient);
|
||||
|
@ -322,7 +324,7 @@ describe('Replication over REST', function() {
|
|||
.to.have.property('fullname', 'Alice Smith');
|
||||
next();
|
||||
});
|
||||
}
|
||||
},
|
||||
], done);
|
||||
});
|
||||
|
||||
|
@ -347,7 +349,7 @@ describe('Replication over REST', function() {
|
|||
.to.not.have.property('fullname');
|
||||
next();
|
||||
});
|
||||
}
|
||||
},
|
||||
], done);
|
||||
});
|
||||
|
||||
|
@ -367,7 +369,7 @@ describe('Replication over REST', function() {
|
|||
});
|
||||
|
||||
var USER_PROPS = {
|
||||
id: { type: 'string', id: true }
|
||||
id: { type: 'string', id: true },
|
||||
};
|
||||
|
||||
var USER_OPTS = {
|
||||
|
@ -375,13 +377,13 @@ describe('Replication over REST', function() {
|
|||
plural: 'Users', // use the same REST path in all models
|
||||
trackChanges: true,
|
||||
strict: 'throw',
|
||||
persistUndefinedAsNull: true
|
||||
persistUndefinedAsNull: true,
|
||||
};
|
||||
|
||||
var CAR_PROPS = {
|
||||
id: { type: 'string', id: true, defaultFn: 'guid' },
|
||||
model: { type: 'string', required: true },
|
||||
maker: { type: 'string' }
|
||||
maker: { type: 'string' },
|
||||
};
|
||||
|
||||
var CAR_OPTS = {
|
||||
|
@ -395,30 +397,30 @@ describe('Replication over REST', function() {
|
|||
{
|
||||
principalType: 'ROLE',
|
||||
principalId: '$everyone',
|
||||
permission: 'DENY'
|
||||
permission: 'DENY',
|
||||
},
|
||||
// allow all authenticated users to read data
|
||||
{
|
||||
principalType: 'ROLE',
|
||||
principalId: '$authenticated',
|
||||
permission: 'ALLOW',
|
||||
accessType: 'READ'
|
||||
accessType: 'READ',
|
||||
},
|
||||
// allow Alice to pull changes
|
||||
{
|
||||
principalType: 'USER',
|
||||
principalId: ALICE.id,
|
||||
permission: 'ALLOW',
|
||||
accessType: 'REPLICATE'
|
||||
accessType: 'REPLICATE',
|
||||
},
|
||||
// allow Peter to write data
|
||||
{
|
||||
principalType: 'USER',
|
||||
principalId: PETER.id,
|
||||
permission: 'ALLOW',
|
||||
accessType: 'WRITE'
|
||||
}
|
||||
]
|
||||
accessType: 'WRITE',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
function setupServer(done) {
|
||||
|
@ -435,9 +437,9 @@ describe('Replication over REST', function() {
|
|||
user: {
|
||||
type: 'belongsTo',
|
||||
model: 'ServerUser',
|
||||
foreignKey: 'userId'
|
||||
}
|
||||
}
|
||||
foreignKey: 'userId',
|
||||
},
|
||||
},
|
||||
});
|
||||
serverApp.model(ServerToken, { dataSource: 'db', public: false });
|
||||
serverApp.model(loopback.ACL, { dataSource: 'db', public: false });
|
||||
|
@ -448,7 +450,7 @@ describe('Replication over REST', function() {
|
|||
serverApp.model(ServerUser, {
|
||||
dataSource: 'db',
|
||||
public: true,
|
||||
relations: { accessTokens: { model: 'ServerToken' } }
|
||||
relations: { accessTokens: { model: 'ServerToken' }},
|
||||
});
|
||||
|
||||
ServerCar = loopback.createModel('ServerCar', CAR_PROPS, CAR_OPTS);
|
||||
|
@ -476,7 +478,7 @@ describe('Replication over REST', function() {
|
|||
clientApp.dataSource('db', { connector: 'memory' });
|
||||
clientApp.dataSource('remote', {
|
||||
connector: 'remote',
|
||||
url: serverUrl
|
||||
url: serverUrl,
|
||||
});
|
||||
|
||||
// NOTE(bajtos) At the moment, all models share the same Checkpoint
|
||||
|
@ -510,7 +512,7 @@ describe('Replication over REST', function() {
|
|||
trackChanges: false,
|
||||
// Enable remote replication in order to get remoting API metadata
|
||||
// used by the remoting connector
|
||||
enableRemoteReplication: true
|
||||
enableRemoteReplication: true,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -548,14 +550,14 @@ describe('Replication over REST', function() {
|
|||
ServerCar.create(
|
||||
[
|
||||
{ id: 'Ford-Mustang', maker: 'Ford', model: 'Mustang' },
|
||||
{ id: 'Audi-R8', maker: 'Audi', model: 'R8' }
|
||||
{ id: 'Audi-R8', maker: 'Audi', model: 'R8' },
|
||||
],
|
||||
function(err, cars) {
|
||||
if (err) return next(err);
|
||||
serverCars = cars.map(carToString);
|
||||
next();
|
||||
});
|
||||
}
|
||||
},
|
||||
], done);
|
||||
}
|
||||
|
||||
|
@ -600,7 +602,7 @@ describe('Replication over REST', function() {
|
|||
function setAccessToken(token) {
|
||||
clientApp.dataSources.remote.connector.remotes.auth = {
|
||||
bearer: new Buffer(token).toString('base64'),
|
||||
sendImmediately: true
|
||||
sendImmediately: true,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -8,8 +8,7 @@ var expect = require('chai').expect;
|
|||
var debug = require('debug')('test');
|
||||
|
||||
describe('Replication / Change APIs', function() {
|
||||
var dataSource, SourceModel, TargetModel;
|
||||
var useSinceFilter;
|
||||
var dataSource, SourceModel, TargetModel, useSinceFilter;
|
||||
var tid = 0; // per-test unique id used e.g. to build unique model names
|
||||
|
||||
beforeEach(function() {
|
||||
|
@ -17,7 +16,7 @@ describe('Replication / Change APIs', function() {
|
|||
useSinceFilter = false;
|
||||
var test = this;
|
||||
dataSource = this.dataSource = loopback.createDataSource({
|
||||
connector: loopback.Memory
|
||||
connector: loopback.Memory,
|
||||
});
|
||||
SourceModel = this.SourceModel = PersistedModel.extend(
|
||||
'SourceModel-' + tid,
|
||||
|
@ -85,7 +84,8 @@ describe('Replication / Change APIs', function() {
|
|||
});
|
||||
});
|
||||
|
||||
it('rectifyOnDelete for Delete should call rectifyChange instead of rectifyAllChanges', function(done) {
|
||||
it('rectifyOnDelete for Delete should call rectifyChange instead of rectifyAllChanges',
|
||||
function(done) {
|
||||
var calls = mockTargetModelRectify();
|
||||
async.waterfall([
|
||||
function(callback) {
|
||||
|
@ -94,7 +94,7 @@ describe('Replication / Change APIs', function() {
|
|||
function(data, callback) {
|
||||
SourceModel.replicate(TargetModel, callback);
|
||||
// replicate should call `rectifyOnSave` and then `rectifyChange` not `rectifyAllChanges` through `after save` operation
|
||||
}
|
||||
},
|
||||
], function(err, results) {
|
||||
if (err) return done(err);
|
||||
expect(calls).to.eql(['rectifyChange']);
|
||||
|
@ -102,7 +102,8 @@ describe('Replication / Change APIs', function() {
|
|||
});
|
||||
});
|
||||
|
||||
it('rectifyOnSave for Update should call rectifyChange instead of rectifyAllChanges', function(done) {
|
||||
it('rectifyOnSave for Update should call rectifyChange instead of rectifyAllChanges',
|
||||
function(done) {
|
||||
var calls = mockTargetModelRectify();
|
||||
var newData = { 'name': 'Janie' };
|
||||
async.waterfall([
|
||||
|
@ -112,7 +113,7 @@ describe('Replication / Change APIs', function() {
|
|||
function(data, callback) {
|
||||
SourceModel.replicate(TargetModel, callback);
|
||||
// replicate should call `rectifyOnSave` and then `rectifyChange` not `rectifyAllChanges` through `after save` operation
|
||||
}
|
||||
},
|
||||
], function(err, result) {
|
||||
if (err) return done(err);
|
||||
expect(calls).to.eql(['rectifyChange']);
|
||||
|
@ -120,7 +121,8 @@ describe('Replication / Change APIs', function() {
|
|||
});
|
||||
});
|
||||
|
||||
it('rectifyOnSave for Create should call rectifyChange instead of rectifyAllChanges', function(done) {
|
||||
it('rectifyOnSave for Create should call rectifyChange instead of rectifyAllChanges',
|
||||
function(done) {
|
||||
var calls = mockTargetModelRectify();
|
||||
var newData = [{ name: 'Janie', surname: 'Doe' }];
|
||||
async.waterfall([
|
||||
|
@ -130,7 +132,7 @@ describe('Replication / Change APIs', function() {
|
|||
function(data, callback) {
|
||||
SourceModel.replicate(TargetModel, callback);
|
||||
// replicate should call `rectifyOnSave` and then `rectifyChange` not `rectifyAllChanges` through `after save` operation
|
||||
}
|
||||
},
|
||||
], function(err, result) {
|
||||
if (err) return done(err);
|
||||
expect(calls).to.eql(['rectifyChange']);
|
||||
|
@ -192,7 +194,6 @@ describe('Replication / Change APIs', function() {
|
|||
if (err) return done(err);
|
||||
SourceModel.changes(FUTURE_CHECKPOINT, {}, function(err, changes) {
|
||||
if (err) return done(err);
|
||||
/*jshint -W030 */
|
||||
expect(changes).to.be.empty;
|
||||
done();
|
||||
});
|
||||
|
@ -201,11 +202,9 @@ describe('Replication / Change APIs', function() {
|
|||
});
|
||||
|
||||
describe('Model.replicate(since, targetModel, options, callback)', function() {
|
||||
|
||||
function assertTargetModelEqualsSourceModel(conflicts, sourceModel,
|
||||
targetModel, done) {
|
||||
var sourceData;
|
||||
var targetData;
|
||||
var sourceData, targetData;
|
||||
|
||||
assert(conflicts.length === 0);
|
||||
async.parallel([
|
||||
|
@ -222,7 +221,7 @@ describe('Replication / Change APIs', function() {
|
|||
targetData = result;
|
||||
cb();
|
||||
});
|
||||
}
|
||||
},
|
||||
], function(err) {
|
||||
if (err) return done(err);
|
||||
|
||||
|
@ -289,7 +288,7 @@ describe('Replication / Change APIs', function() {
|
|||
expect(getIds(list)).to.eql(['2']);
|
||||
next();
|
||||
});
|
||||
}
|
||||
},
|
||||
], done);
|
||||
});
|
||||
|
||||
|
@ -321,7 +320,7 @@ describe('Replication / Change APIs', function() {
|
|||
expect(getIds(list)).to.eql(['2']);
|
||||
next();
|
||||
});
|
||||
}
|
||||
},
|
||||
], done);
|
||||
});
|
||||
|
||||
|
@ -433,7 +432,7 @@ describe('Replication / Change APIs', function() {
|
|||
expect(getIds(list), 'target ids').to.eql(['init', 'racer']);
|
||||
next();
|
||||
});
|
||||
}
|
||||
},
|
||||
], done);
|
||||
});
|
||||
|
||||
|
@ -453,11 +452,11 @@ describe('Replication / Change APIs', function() {
|
|||
expect(conflicts, 'conflicts').to.eql([]);
|
||||
expect(newCheckpoints, 'currentCheckpoints').to.eql({
|
||||
source: sourceCp + 1,
|
||||
target: targetCp + 1
|
||||
target: targetCp + 1,
|
||||
});
|
||||
cb();
|
||||
});
|
||||
}
|
||||
},
|
||||
], done);
|
||||
|
||||
function bumpSourceCheckpoint(cb) {
|
||||
|
@ -494,7 +493,7 @@ describe('Replication / Change APIs', function() {
|
|||
done();
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
], done);
|
||||
});
|
||||
|
||||
|
@ -540,7 +539,7 @@ describe('Replication / Change APIs', function() {
|
|||
},
|
||||
|
||||
replicateExpectingSuccess(),
|
||||
verifyInstanceWasReplicated(SourceModel, TargetModel, '1')
|
||||
verifyInstanceWasReplicated(SourceModel, TargetModel, '1'),
|
||||
], done);
|
||||
});
|
||||
|
||||
|
@ -581,7 +580,7 @@ describe('Replication / Change APIs', function() {
|
|||
},
|
||||
|
||||
replicateExpectingSuccess(),
|
||||
verifyInstanceWasReplicated(SourceModel, TargetModel, '1')
|
||||
verifyInstanceWasReplicated(SourceModel, TargetModel, '1'),
|
||||
], done);
|
||||
});
|
||||
|
||||
|
@ -626,7 +625,7 @@ describe('Replication / Change APIs', function() {
|
|||
},
|
||||
|
||||
replicateExpectingSuccess(),
|
||||
verifyInstanceWasReplicated(SourceModel, TargetModel, '1')
|
||||
verifyInstanceWasReplicated(SourceModel, TargetModel, '1'),
|
||||
], done);
|
||||
});
|
||||
|
||||
|
@ -657,7 +656,7 @@ describe('Replication / Change APIs', function() {
|
|||
next();
|
||||
},
|
||||
replicateExpectingSuccess(),
|
||||
verifyInstanceWasReplicated(SourceModel, TargetModel, '1')
|
||||
verifyInstanceWasReplicated(SourceModel, TargetModel, '1'),
|
||||
], done);
|
||||
});
|
||||
});
|
||||
|
@ -686,7 +685,7 @@ describe('Replication / Change APIs', function() {
|
|||
inst.name = 'target update';
|
||||
inst.save(cb);
|
||||
});
|
||||
}
|
||||
},
|
||||
], function(err) {
|
||||
if (err) return done(err);
|
||||
SourceModel.replicate(TargetModel, function(err, conflicts) {
|
||||
|
@ -724,11 +723,11 @@ describe('Replication / Change APIs', function() {
|
|||
this.conflict.models(function(err, source, target) {
|
||||
assert.deepEqual(source.toJSON(), {
|
||||
id: test.model.id,
|
||||
name: 'source update'
|
||||
name: 'source update',
|
||||
});
|
||||
assert.deepEqual(target.toJSON(), {
|
||||
id: test.model.id,
|
||||
name: 'target update'
|
||||
name: 'target update',
|
||||
});
|
||||
done();
|
||||
});
|
||||
|
@ -758,7 +757,7 @@ describe('Replication / Change APIs', function() {
|
|||
inst.name = 'target update';
|
||||
inst.save(cb);
|
||||
});
|
||||
}
|
||||
},
|
||||
], function(err) {
|
||||
if (err) return done(err);
|
||||
SourceModel.replicate(TargetModel, function(err, conflicts) {
|
||||
|
@ -797,7 +796,7 @@ describe('Replication / Change APIs', function() {
|
|||
assert.equal(source, null);
|
||||
assert.deepEqual(target.toJSON(), {
|
||||
id: test.model.id,
|
||||
name: 'target update'
|
||||
name: 'target update',
|
||||
});
|
||||
done();
|
||||
});
|
||||
|
@ -827,7 +826,7 @@ describe('Replication / Change APIs', function() {
|
|||
if (err) return cb(err);
|
||||
inst.remove(cb);
|
||||
});
|
||||
}
|
||||
},
|
||||
], function(err) {
|
||||
if (err) return done(err);
|
||||
SourceModel.replicate(TargetModel, function(err, conflicts) {
|
||||
|
@ -866,7 +865,7 @@ describe('Replication / Change APIs', function() {
|
|||
assert.equal(target, null);
|
||||
assert.deepEqual(source.toJSON(), {
|
||||
id: test.model.id,
|
||||
name: 'source update'
|
||||
name: 'source update',
|
||||
});
|
||||
done();
|
||||
});
|
||||
|
@ -895,7 +894,7 @@ describe('Replication / Change APIs', function() {
|
|||
if (err) return cb(err);
|
||||
inst.remove(cb);
|
||||
});
|
||||
}
|
||||
},
|
||||
], function(err) {
|
||||
if (err) return done(err);
|
||||
SourceModel.replicate(TargetModel, function(err, conflicts) {
|
||||
|
@ -1070,7 +1069,7 @@ describe('Replication / Change APIs', function() {
|
|||
});
|
||||
},
|
||||
replicateExpectingSuccess(),
|
||||
verifySourceWasReplicated()
|
||||
verifySourceWasReplicated(),
|
||||
], done);
|
||||
});
|
||||
|
||||
|
@ -1107,7 +1106,7 @@ describe('Replication / Change APIs', function() {
|
|||
expect(getIds(list)).to.not.contain(sourceInstance.id);
|
||||
next();
|
||||
});
|
||||
}
|
||||
},
|
||||
], done);
|
||||
});
|
||||
|
||||
|
@ -1119,7 +1118,7 @@ describe('Replication / Change APIs', function() {
|
|||
updateSourceInstanceNameTo('updated'),
|
||||
updateSourceInstanceNameTo('again'),
|
||||
replicateExpectingSuccess(),
|
||||
verifySourceWasReplicated()
|
||||
verifySourceWasReplicated(),
|
||||
], done);
|
||||
});
|
||||
|
||||
|
@ -1141,7 +1140,7 @@ describe('Replication / Change APIs', function() {
|
|||
async.series([
|
||||
// Note that ClientA->Server was already replicated during setup
|
||||
replicateExpectingSuccess(Server, ClientB),
|
||||
verifySourceWasReplicated(ClientB)
|
||||
verifySourceWasReplicated(ClientB),
|
||||
], done);
|
||||
});
|
||||
|
||||
|
@ -1158,7 +1157,7 @@ describe('Replication / Change APIs', function() {
|
|||
replicateExpectingSuccess(ClientA, Server),
|
||||
|
||||
replicateExpectingSuccess(Server, ClientB),
|
||||
verifySourceWasReplicated(ClientB)
|
||||
verifySourceWasReplicated(ClientB),
|
||||
], done);
|
||||
});
|
||||
|
||||
|
@ -1167,7 +1166,7 @@ describe('Replication / Change APIs', function() {
|
|||
deleteSourceInstance(),
|
||||
replicateExpectingSuccess(ClientA, Server),
|
||||
replicateExpectingSuccess(Server, ClientB),
|
||||
verifySourceWasReplicated(ClientB)
|
||||
verifySourceWasReplicated(ClientB),
|
||||
], done);
|
||||
});
|
||||
|
||||
|
@ -1183,7 +1182,7 @@ describe('Replication / Change APIs', function() {
|
|||
it('propagates CREATE', function(done) {
|
||||
async.series([
|
||||
sync(ClientA, Server),
|
||||
sync(ClientB, Server)
|
||||
sync(ClientB, Server),
|
||||
], done);
|
||||
});
|
||||
|
||||
|
@ -1207,7 +1206,6 @@ describe('Replication / Change APIs', function() {
|
|||
// ClientB fetches the created & updated instance from the server
|
||||
sync(ClientB, Server),
|
||||
], done);
|
||||
|
||||
});
|
||||
|
||||
it('does not report false conflicts', function(done) {
|
||||
|
@ -1227,7 +1225,7 @@ describe('Replication / Change APIs', function() {
|
|||
sync(ClientB, Server),
|
||||
|
||||
// client A fetches the changes
|
||||
sync(ClientA, Server)
|
||||
sync(ClientA, Server),
|
||||
], done);
|
||||
});
|
||||
|
||||
|
@ -1325,7 +1323,7 @@ describe('Replication / Change APIs', function() {
|
|||
// and sync back to ClientA too
|
||||
sync(ClientA, Server),
|
||||
|
||||
verifyInstanceWasReplicated(ClientB, ClientA, sourceInstanceId)
|
||||
verifyInstanceWasReplicated(ClientB, ClientA, sourceInstanceId),
|
||||
], cb);
|
||||
}
|
||||
|
||||
|
@ -1363,7 +1361,7 @@ describe('Replication / Change APIs', function() {
|
|||
// and sync back to ClientA too
|
||||
sync(ClientA, Server),
|
||||
|
||||
verifyInstanceWasReplicated(ClientB, ClientA, sourceInstanceId)
|
||||
verifyInstanceWasReplicated(ClientB, ClientA, sourceInstanceId),
|
||||
], cb);
|
||||
}
|
||||
|
||||
|
@ -1383,11 +1381,10 @@ describe('Replication / Change APIs', function() {
|
|||
// NOTE(bajtos) It's important to replicate from the client to the
|
||||
// server first, so that we can resolve any conflicts at the client
|
||||
replicateExpectingSuccess(client, server),
|
||||
replicateExpectingSuccess(server, client)
|
||||
replicateExpectingSuccess(server, client),
|
||||
], next);
|
||||
};
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
function updateSourceInstanceNameTo(value) {
|
||||
|
|
|
@ -120,7 +120,7 @@ describe('loopback.rest', function() {
|
|||
var ds = app.dataSource('db', { connector: loopback.Memory });
|
||||
var CustomModel = ds.createModel('CustomModel',
|
||||
{ name: String },
|
||||
{ http: { 'path': 'domain1/CustomModelPath' }
|
||||
{ http: { 'path': 'domain1/CustomModelPath' },
|
||||
});
|
||||
|
||||
app.model(CustomModel);
|
||||
|
@ -133,7 +133,7 @@ describe('loopback.rest', function() {
|
|||
var ds = app.dataSource('db', { connector: loopback.Memory });
|
||||
var CustomModel = ds.createModel('CustomModel',
|
||||
{ name: String },
|
||||
{ http: { path: 'domain%20one/CustomModelPath' }
|
||||
{ http: { path: 'domain%20one/CustomModelPath' },
|
||||
});
|
||||
|
||||
app.model(CustomModel);
|
||||
|
@ -164,7 +164,7 @@ describe('loopback.rest', function() {
|
|||
};
|
||||
loopback.remoteMethod(User.getToken, {
|
||||
accepts: [{ type: 'object', http: { source: 'req' }}],
|
||||
returns: [{ type: 'object', name: 'id' }]
|
||||
returns: [{ type: 'object', name: 'id' }],
|
||||
});
|
||||
|
||||
app.use(loopback.rest());
|
||||
|
@ -247,8 +247,8 @@ describe('loopback.rest', function() {
|
|||
loopback.remoteMethod(User.getToken, {
|
||||
accepts: [],
|
||||
returns: [
|
||||
{ type: 'object', name: 'id' }
|
||||
]
|
||||
{ type: 'object', name: 'id' },
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -312,8 +312,8 @@ describe('loopback.rest', function() {
|
|||
loopback.remoteMethod(User.getToken, {
|
||||
accepts: [],
|
||||
returns: [
|
||||
{ type: 'object', name: 'id' }
|
||||
]
|
||||
{ type: 'object', name: 'id' },
|
||||
],
|
||||
});
|
||||
|
||||
invokeGetToken(done);
|
||||
|
@ -326,9 +326,9 @@ describe('loopback.rest', function() {
|
|||
// the global model registry
|
||||
app.model('accessToken', {
|
||||
options: {
|
||||
base: 'AccessToken'
|
||||
base: 'AccessToken',
|
||||
},
|
||||
dataSource: 'db'
|
||||
dataSource: 'db',
|
||||
});
|
||||
return app.model('user', {
|
||||
options: {
|
||||
|
@ -337,11 +337,11 @@ describe('loopback.rest', function() {
|
|||
accessTokens: {
|
||||
model: 'accessToken',
|
||||
type: 'hasMany',
|
||||
foreignKey: 'userId'
|
||||
}
|
||||
}
|
||||
foreignKey: 'userId',
|
||||
},
|
||||
dataSource: 'db'
|
||||
},
|
||||
},
|
||||
dataSource: 'db',
|
||||
});
|
||||
}
|
||||
function givenLoggedInUser(cb, done) {
|
||||
|
@ -391,7 +391,7 @@ describe('loopback.rest', function() {
|
|||
app.models.Todo.create([
|
||||
{ content: 'a' },
|
||||
{ content: 'b' },
|
||||
{content: 'c'}
|
||||
{ content: 'c' },
|
||||
], function() {
|
||||
request(app)
|
||||
.del('/todos')
|
||||
|
@ -437,7 +437,7 @@ describe('loopback.rest', function() {
|
|||
app.models.Todo.create([
|
||||
{ content: 'a' },
|
||||
{ content: 'b' },
|
||||
{content: 'c'}
|
||||
{ content: 'c' },
|
||||
], function() {
|
||||
request(app)
|
||||
.del('/todos')
|
||||
|
|
|
@ -38,7 +38,8 @@ describe('role model', function() {
|
|||
it('should define role/role relations', function() {
|
||||
Role.create({ name: 'user' }, function(err, userRole) {
|
||||
Role.create({ name: 'admin' }, function(err, adminRole) {
|
||||
userRole.principals.create({principalType: RoleMapping.ROLE, principalId: adminRole.id}, function(err, mapping) {
|
||||
userRole.principals.create({ principalType: RoleMapping.ROLE, principalId: adminRole.id },
|
||||
function(err, mapping) {
|
||||
Role.find(function(err, roles) {
|
||||
assert.equal(roles.length, 2);
|
||||
});
|
||||
|
@ -56,15 +57,14 @@ describe('role model', function() {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
it('should define role/user relations', function() {
|
||||
|
||||
User.create({ name: 'Raymond', email: 'x@y.com', password: 'foobar' }, function(err, user) {
|
||||
// console.log('User: ', user.id);
|
||||
Role.create({ name: 'userRole' }, function(err, role) {
|
||||
role.principals.create({principalType: RoleMapping.USER, principalId: user.id}, function(err, p) {
|
||||
role.principals.create({ principalType: RoleMapping.USER, principalId: user.id },
|
||||
function(err, p) {
|
||||
Role.find(function(err, roles) {
|
||||
assert(!err);
|
||||
assert.equal(roles.length, 1);
|
||||
|
@ -85,16 +85,15 @@ describe('role model', function() {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
it('should automatically generate role id', function() {
|
||||
|
||||
User.create({ name: 'Raymond', email: 'x@y.com', password: 'foobar' }, function(err, user) {
|
||||
// console.log('User: ', user.id);
|
||||
Role.create({ name: 'userRole' }, function(err, role) {
|
||||
assert(role.id);
|
||||
role.principals.create({principalType: RoleMapping.USER, principalId: user.id}, function(err, p) {
|
||||
role.principals.create({ principalType: RoleMapping.USER, principalId: user.id },
|
||||
function(err, p) {
|
||||
assert(p.id);
|
||||
assert.equal(p.roleId, role.id);
|
||||
Role.find(function(err, roles) {
|
||||
|
@ -117,45 +116,52 @@ describe('role model', function() {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
it('should support getRoles() and isInRole()', function() {
|
||||
User.create({ name: 'Raymond', email: 'x@y.com', password: 'foobar' }, function(err, user) {
|
||||
// console.log('User: ', user.id);
|
||||
Role.create({ name: 'userRole' }, function(err, role) {
|
||||
role.principals.create({principalType: RoleMapping.USER, principalId: user.id}, function(err, p) {
|
||||
role.principals.create({ principalType: RoleMapping.USER, principalId: user.id },
|
||||
function(err, p) {
|
||||
// Role.find(console.log);
|
||||
// role.principals(console.log);
|
||||
Role.isInRole('userRole', {principalType: RoleMapping.USER, principalId: user.id}, function(err, exists) {
|
||||
Role.isInRole('userRole', { principalType: RoleMapping.USER, principalId: user.id },
|
||||
function(err, exists) {
|
||||
assert(!err && exists === true);
|
||||
});
|
||||
|
||||
Role.isInRole('userRole', {principalType: RoleMapping.APP, principalId: user.id}, function(err, exists) {
|
||||
Role.isInRole('userRole', { principalType: RoleMapping.APP, principalId: user.id },
|
||||
function(err, exists) {
|
||||
assert(!err && exists === false);
|
||||
});
|
||||
|
||||
Role.isInRole('userRole', {principalType: RoleMapping.USER, principalId: 100}, function(err, exists) {
|
||||
Role.isInRole('userRole', { principalType: RoleMapping.USER, principalId: 100 },
|
||||
function(err, exists) {
|
||||
assert(!err && exists === false);
|
||||
});
|
||||
|
||||
Role.getRoles({principalType: RoleMapping.USER, principalId: user.id}, function(err, roles) {
|
||||
Role.getRoles({ principalType: RoleMapping.USER, principalId: user.id },
|
||||
function(err, roles) {
|
||||
assert.equal(roles.length, 3); // everyone, authenticated, userRole
|
||||
assert(roles.indexOf(role.id) >= 0);
|
||||
assert(roles.indexOf(Role.EVERYONE) >= 0);
|
||||
assert(roles.indexOf(Role.AUTHENTICATED) >= 0);
|
||||
});
|
||||
Role.getRoles({principalType: RoleMapping.APP, principalId: user.id}, function(err, roles) {
|
||||
Role.getRoles({ principalType: RoleMapping.APP, principalId: user.id },
|
||||
function(err, roles) {
|
||||
assert.equal(roles.length, 2);
|
||||
assert(roles.indexOf(Role.EVERYONE) >= 0);
|
||||
assert(roles.indexOf(Role.AUTHENTICATED) >= 0);
|
||||
});
|
||||
Role.getRoles({principalType: RoleMapping.USER, principalId: 100}, function(err, roles) {
|
||||
Role.getRoles({ principalType: RoleMapping.USER, principalId: 100 },
|
||||
function(err, roles) {
|
||||
assert.equal(roles.length, 2);
|
||||
assert(roles.indexOf(Role.EVERYONE) >= 0);
|
||||
assert(roles.indexOf(Role.AUTHENTICATED) >= 0);
|
||||
});
|
||||
Role.getRoles({principalType: RoleMapping.USER, principalId: null}, function(err, roles) {
|
||||
Role.getRoles({ principalType: RoleMapping.USER, principalId: null },
|
||||
function(err, roles) {
|
||||
assert.equal(roles.length, 2);
|
||||
assert(roles.indexOf(Role.EVERYONE) >= 0);
|
||||
assert(roles.indexOf(Role.UNAUTHENTICATED) >= 0);
|
||||
|
@ -163,54 +169,60 @@ describe('role model', function() {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
it('should support owner role resolver', function() {
|
||||
|
||||
var Album = ds.createModel('Album', {
|
||||
name: String,
|
||||
userId: Number
|
||||
userId: Number,
|
||||
}, {
|
||||
relations: {
|
||||
user: {
|
||||
type: 'belongsTo',
|
||||
model: 'User',
|
||||
foreignKey: 'userId'
|
||||
}
|
||||
}
|
||||
foreignKey: 'userId',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
User.create({ name: 'Raymond', email: 'x@y.com', password: 'foobar' }, function(err, user) {
|
||||
Role.isInRole(Role.AUTHENTICATED, {principalType: ACL.USER, principalId: user.id}, function(err, yes) {
|
||||
Role.isInRole(Role.AUTHENTICATED, { principalType: ACL.USER, principalId: user.id },
|
||||
function(err, yes) {
|
||||
assert(!err && yes);
|
||||
});
|
||||
Role.isInRole(Role.AUTHENTICATED, {principalType: ACL.USER, principalId: null}, function(err, yes) {
|
||||
Role.isInRole(Role.AUTHENTICATED, { principalType: ACL.USER, principalId: null },
|
||||
function(err, yes) {
|
||||
assert(!err && !yes);
|
||||
});
|
||||
|
||||
Role.isInRole(Role.UNAUTHENTICATED, {principalType: ACL.USER, principalId: user.id}, function(err, yes) {
|
||||
Role.isInRole(Role.UNAUTHENTICATED, { principalType: ACL.USER, principalId: user.id },
|
||||
function(err, yes) {
|
||||
assert(!err && !yes);
|
||||
});
|
||||
Role.isInRole(Role.UNAUTHENTICATED, {principalType: ACL.USER, principalId: null}, function(err, yes) {
|
||||
Role.isInRole(Role.UNAUTHENTICATED, { principalType: ACL.USER, principalId: null },
|
||||
function(err, yes) {
|
||||
assert(!err && yes);
|
||||
});
|
||||
|
||||
Role.isInRole(Role.EVERYONE, {principalType: ACL.USER, principalId: user.id}, function(err, yes) {
|
||||
Role.isInRole(Role.EVERYONE, { principalType: ACL.USER, principalId: user.id },
|
||||
function(err, yes) {
|
||||
assert(!err && yes);
|
||||
});
|
||||
|
||||
Role.isInRole(Role.EVERYONE, {principalType: ACL.USER, principalId: null}, function(err, yes) {
|
||||
Role.isInRole(Role.EVERYONE, { principalType: ACL.USER, principalId: null },
|
||||
function(err, yes) {
|
||||
assert(!err && yes);
|
||||
});
|
||||
|
||||
// console.log('User: ', user.id);
|
||||
Album.create({ name: 'Album 1', userId: user.id }, function(err, album1) {
|
||||
Role.isInRole(Role.OWNER, {principalType: ACL.USER, principalId: user.id, model: Album, id: album1.id}, function(err, yes) {
|
||||
var role = { principalType: ACL.USER, principalId: user.id, model: Album, id: album1.id };
|
||||
Role.isInRole(Role.OWNER, role, function(err, yes) {
|
||||
assert(!err && yes);
|
||||
});
|
||||
Album.create({ name: 'Album 2' }, function(err, album2) {
|
||||
Role.isInRole(Role.OWNER, {principalType: ACL.USER, principalId: user.id, model: Album, id: album2.id}, function(err, yes) {
|
||||
role = { principalType: ACL.USER, principalId: user.id, model: Album, id: album2.id };
|
||||
Role.isInRole(Role.OWNER, role, function(err, yes) {
|
||||
assert(!err && !yes);
|
||||
});
|
||||
});
|
||||
|
@ -225,35 +237,35 @@ describe('role model', function() {
|
|||
User.create({
|
||||
username: 'john',
|
||||
email: 'john@gmail.com',
|
||||
password: 'jpass'
|
||||
password: 'jpass',
|
||||
}, function(err, u) {
|
||||
if (err) return done(err);
|
||||
user = u;
|
||||
User.create({
|
||||
username: 'mary',
|
||||
email: 'mary@gmail.com',
|
||||
password: 'mpass'
|
||||
password: 'mpass',
|
||||
}, function(err, u) {
|
||||
if (err) return done(err);
|
||||
Application.create({
|
||||
name: 'demo'
|
||||
name: 'demo',
|
||||
}, function(err, a) {
|
||||
if (err) return done(err);
|
||||
app = a;
|
||||
Role.create({
|
||||
name: 'admin'
|
||||
name: 'admin',
|
||||
}, function(err, r) {
|
||||
if (err) return done(err);
|
||||
role = r;
|
||||
var principals = [
|
||||
{
|
||||
principalType: ACL.USER,
|
||||
principalId: user.id
|
||||
principalId: user.id,
|
||||
},
|
||||
{
|
||||
principalType: ACL.APP,
|
||||
principalId: app.id
|
||||
}
|
||||
principalId: app.id,
|
||||
},
|
||||
];
|
||||
async.each(principals, function(p, done) {
|
||||
role.principals.create(p, done);
|
||||
|
@ -344,7 +356,6 @@ describe('role model', function() {
|
|||
done();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('listByPrincipalType', function() {
|
||||
|
@ -373,7 +384,8 @@ describe('role model', function() {
|
|||
var Model = principalTypesToModels[principalType];
|
||||
Model.create({ name: 'test', email: 'x@y.com', password: 'foobar' }, function(err, model) {
|
||||
Role.create({ name: 'testRole' }, function(err, role) {
|
||||
role.principals.create({principalType: principalType, principalId: model.id}, function(err, p) {
|
||||
role.principals.create({ principalType: principalType, principalId: model.id },
|
||||
function(err, p) {
|
||||
var pluralName = Model.pluralModelName.toLowerCase();
|
||||
role[pluralName](function(err, models) {
|
||||
assert(!err);
|
||||
|
@ -391,7 +403,8 @@ describe('role model', function() {
|
|||
it('should apply query', function(done) {
|
||||
User.create({ name: 'Raymond', email: 'x@y.com', password: 'foobar' }, function(err, user) {
|
||||
Role.create({ name: 'userRole' }, function(err, role) {
|
||||
role.principals.create({principalType: RoleMapping.USER, principalId: user.id}, function(err, p) {
|
||||
role.principals.create({ principalType: RoleMapping.USER, principalId: user.id },
|
||||
function(err, p) {
|
||||
var query = { fields: ['id', 'name'] };
|
||||
sandbox.spy(User, 'find');
|
||||
role.users(query, function(err, users) {
|
||||
|
@ -406,5 +419,4 @@ describe('role model', function() {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
|
|
@ -21,14 +21,14 @@ beforeEach(function() {
|
|||
|
||||
// setup default data sources
|
||||
loopback.setDefaultDataSourceForType('db', {
|
||||
connector: loopback.Memory
|
||||
connector: loopback.Memory,
|
||||
});
|
||||
|
||||
loopback.setDefaultDataSourceForType('mail', {
|
||||
connector: loopback.Mail,
|
||||
transports: [
|
||||
{type: 'STUB'}
|
||||
]
|
||||
{ type: 'STUB' },
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
/*jshint -W030 */
|
||||
var loopback = require('../');
|
||||
var lt = require('./helpers/loopback-testing-helper');
|
||||
var path = require('path');
|
||||
|
@ -7,7 +6,6 @@ var app = require(path.join(SIMPLE_APP, 'server/server.js'));
|
|||
var expect = require('chai').expect;
|
||||
|
||||
describe('users - integration', function() {
|
||||
|
||||
lt.beforeEach.withApp(app);
|
||||
|
||||
before(function(done) {
|
||||
|
@ -30,8 +28,7 @@ describe('users - integration', function() {
|
|||
});
|
||||
|
||||
describe('base-user', function() {
|
||||
var userId;
|
||||
var accessToken;
|
||||
var userId, accessToken;
|
||||
|
||||
it('should create a new user', function(done) {
|
||||
this.post('/api/users')
|
||||
|
@ -93,8 +90,7 @@ describe('users - integration', function() {
|
|||
});
|
||||
|
||||
describe('sub-user', function() {
|
||||
var userId;
|
||||
var accessToken;
|
||||
var userId, accessToken;
|
||||
|
||||
it('should create a new user', function(done) {
|
||||
var url = '/api/myUsers';
|
||||
|
@ -157,6 +153,4 @@ describe('users - integration', function() {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
|
|
@ -1,20 +1,22 @@
|
|||
require('./support');
|
||||
var loopback = require('../');
|
||||
var User;
|
||||
var AccessToken;
|
||||
var User, AccessToken;
|
||||
var MailConnector = require('../lib/connectors/mail');
|
||||
|
||||
var userMemory = loopback.createDataSource({
|
||||
connector: 'memory'
|
||||
connector: 'memory',
|
||||
});
|
||||
|
||||
describe('User', function() {
|
||||
var validCredentialsEmail = 'foo@bar.com';
|
||||
var validCredentials = { email: validCredentialsEmail, password: 'bar' };
|
||||
var validCredentialsEmailVerified = {email: 'foo1@bar.com', password: 'bar1', emailVerified: true};
|
||||
var validCredentialsEmailVerifiedOverREST = {email: 'foo2@bar.com', password: 'bar2', emailVerified: true};
|
||||
var validCredentialsEmailVerified = {
|
||||
email: 'foo1@bar.com', password: 'bar1', emailVerified: true };
|
||||
var validCredentialsEmailVerifiedOverREST = {
|
||||
email: 'foo2@bar.com', password: 'bar2', emailVerified: true };
|
||||
var validCredentialsWithTTL = { email: 'foo@bar.com', password: 'bar', ttl: 3600 };
|
||||
var validCredentialsWithTTLAndScope = {email: 'foo@bar.com', password: 'bar', ttl: 3600, scope: 'all'};
|
||||
var validCredentialsWithTTLAndScope = {
|
||||
email: 'foo@bar.com', password: 'bar', ttl: 3600, scope: 'all' };
|
||||
var validMixedCaseEmailCredentials = { email: 'Foo@bar.com', password: 'bar' };
|
||||
var invalidCredentials = { email: 'foo1@bar.com', password: 'invalid' };
|
||||
var incompleteCredentials = { password: 'bar1' };
|
||||
|
@ -37,7 +39,6 @@ describe('User', function() {
|
|||
|
||||
// allow many User.afterRemote's to be called
|
||||
User.setMaxListeners(0);
|
||||
|
||||
});
|
||||
|
||||
beforeEach(function(done) {
|
||||
|
@ -91,7 +92,7 @@ describe('User', function() {
|
|||
it('credentials/challenges are object types', function(done) {
|
||||
User.create({ email: 'f1@b.com', password: 'bar1',
|
||||
credentials: { cert: 'xxxxx', key: '111' },
|
||||
challenges: {x: 'X', a: 1}
|
||||
challenges: { x: 'X', a: 1 },
|
||||
}, function(err, user) {
|
||||
assert(!err);
|
||||
User.findById(user.id, function(err, user) {
|
||||
|
@ -112,7 +113,7 @@ describe('User', function() {
|
|||
assert.equal(err.details.context, User.modelName);
|
||||
assert.deepEqual(err.details.codes.email, [
|
||||
'presence',
|
||||
'format.null'
|
||||
'format.null',
|
||||
]);
|
||||
|
||||
done();
|
||||
|
@ -199,8 +200,7 @@ describe('User', function() {
|
|||
});
|
||||
|
||||
describe('custom password hash', function() {
|
||||
var defaultHashPassword;
|
||||
var defaultValidatePassword;
|
||||
var defaultHashPassword, defaultValidatePassword;
|
||||
|
||||
beforeEach(function() {
|
||||
defaultHashPassword = User.hashPassword;
|
||||
|
@ -575,14 +575,17 @@ describe('User', function() {
|
|||
it('Require valid and complete credentials for email verification error', function(done) {
|
||||
User.login({ email: validCredentialsEmail }, function(err, accessToken) {
|
||||
// strongloop/loopback#931
|
||||
// error message should be "login failed" and not "login failed as the email has not been verified"
|
||||
assert(err && !/verified/.test(err.message), ('expecting "login failed" error message, received: "' + err.message + '"'));
|
||||
// error message should be "login failed"
|
||||
// and not "login failed as the email has not been verified"
|
||||
assert(err && !/verified/.test(err.message),
|
||||
'expecting "login failed" error message, received: "' + err.message + '"');
|
||||
assert.equal(err.code, 'LOGIN_FAILED');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('Require valid and complete credentials for email verification error - promise variant', function(done) {
|
||||
it('Require valid and complete credentials for email verification error - promise variant',
|
||||
function(done) {
|
||||
User.login({ email: validCredentialsEmail })
|
||||
.then(function(accessToken) {
|
||||
done();
|
||||
|
@ -590,7 +593,8 @@ describe('User', function() {
|
|||
.catch(function(err) {
|
||||
// strongloop/loopback#931
|
||||
// error message should be "login failed" and not "login failed as the email has not been verified"
|
||||
assert(err && !/verified/.test(err.message), ('expecting "login failed" error message, received: "' + err.message + '"'));
|
||||
assert(err && !/verified/.test(err.message),
|
||||
'expecting "login failed" error message, received: "' + err.message + '"');
|
||||
assert.equal(err.code, 'LOGIN_FAILED');
|
||||
done();
|
||||
});
|
||||
|
@ -653,7 +657,9 @@ describe('User', function() {
|
|||
});
|
||||
});
|
||||
|
||||
it('Login a user over REST require complete and valid credentials for email verification error message', function(done) {
|
||||
it('Login user over REST require complete and valid credentials ' +
|
||||
'for email verification error message',
|
||||
function(done) {
|
||||
request(app)
|
||||
.post('/test-users/login')
|
||||
.expect('Content-Type', /json/)
|
||||
|
@ -664,9 +670,11 @@ describe('User', function() {
|
|||
return done(err);
|
||||
}
|
||||
// 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"
|
||||
var errorResponse = res.body.error;
|
||||
assert(errorResponse && !/verified/.test(errorResponse.message), ('expecting "login failed" error message, received: "' + errorResponse.message + '"'));
|
||||
assert(errorResponse && !/verified/.test(errorResponse.message),
|
||||
'expecting "login failed" error message, received: "' + errorResponse.message + '"');
|
||||
assert.equal(errorResponse.code, 'LOGIN_FAILED');
|
||||
done();
|
||||
});
|
||||
|
@ -687,12 +695,10 @@ describe('User', function() {
|
|||
done();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('User.login requiring realm', function() {
|
||||
var User;
|
||||
var AccessToken;
|
||||
var User, AccessToken;
|
||||
|
||||
before(function() {
|
||||
User = loopback.User.extend('RealmUser', {},
|
||||
|
@ -713,53 +719,53 @@ describe('User', function() {
|
|||
realm: 'realm1',
|
||||
username: 'foo100',
|
||||
email: 'foo100@bar.com',
|
||||
password: 'pass100'
|
||||
password: 'pass100',
|
||||
};
|
||||
|
||||
var realm2User = {
|
||||
realm: 'realm2',
|
||||
username: 'foo100',
|
||||
email: 'foo100@bar.com',
|
||||
password: 'pass200'
|
||||
password: 'pass200',
|
||||
};
|
||||
|
||||
var credentialWithoutRealm = {
|
||||
username: 'foo100',
|
||||
email: 'foo100@bar.com',
|
||||
password: 'pass100'
|
||||
password: 'pass100',
|
||||
};
|
||||
|
||||
var credentialWithBadPass = {
|
||||
realm: 'realm1',
|
||||
username: 'foo100',
|
||||
email: 'foo100@bar.com',
|
||||
password: 'pass001'
|
||||
password: 'pass001',
|
||||
};
|
||||
|
||||
var credentialWithBadRealm = {
|
||||
realm: 'realm3',
|
||||
username: 'foo100',
|
||||
email: 'foo100@bar.com',
|
||||
password: 'pass100'
|
||||
password: 'pass100',
|
||||
};
|
||||
|
||||
var credentialWithRealm = {
|
||||
realm: 'realm1',
|
||||
username: 'foo100',
|
||||
password: 'pass100'
|
||||
password: 'pass100',
|
||||
};
|
||||
|
||||
var credentialRealmInUsername = {
|
||||
username: 'realm1:foo100',
|
||||
password: 'pass100'
|
||||
password: 'pass100',
|
||||
};
|
||||
|
||||
var credentialRealmInEmail = {
|
||||
email: 'realm1:foo100@bar.com',
|
||||
password: 'pass100'
|
||||
password: 'pass100',
|
||||
};
|
||||
|
||||
var user1;
|
||||
var user1 = null;
|
||||
beforeEach(function(done) {
|
||||
User.create(realm1User, function(err, u) {
|
||||
if (err) {
|
||||
|
@ -868,7 +874,8 @@ describe('User', function() {
|
|||
}
|
||||
});
|
||||
|
||||
it('Logout a user by providing the current accessToken id (using node) - promise variant', function(done) {
|
||||
it('Logout a user by providing the current accessToken id (using node) - promise variant',
|
||||
function(done) {
|
||||
login(logout);
|
||||
|
||||
function login(fn) {
|
||||
|
@ -989,7 +996,6 @@ describe('User', function() {
|
|||
});
|
||||
|
||||
describe('Verification', function() {
|
||||
|
||||
describe('user.verify(options, fn)', function() {
|
||||
it('Verify a user\'s email address', function(done) {
|
||||
User.afterRemote('create', function(ctx, user, next) {
|
||||
|
@ -1001,7 +1007,7 @@ describe('User', function() {
|
|||
from: 'noreply@myapp.org',
|
||||
redirect: '/',
|
||||
protocol: ctx.req.protocol,
|
||||
host: ctx.req.get('host')
|
||||
host: ctx.req.get('host'),
|
||||
};
|
||||
|
||||
user.verify(options, function(err, result) {
|
||||
|
@ -1037,7 +1043,7 @@ describe('User', function() {
|
|||
from: 'noreply@myapp.org',
|
||||
redirect: '/',
|
||||
protocol: ctx.req.protocol,
|
||||
host: ctx.req.get('host')
|
||||
host: ctx.req.get('host'),
|
||||
};
|
||||
|
||||
user.verify(options)
|
||||
|
@ -1078,7 +1084,7 @@ describe('User', function() {
|
|||
redirect: '/',
|
||||
protocol: ctx.req.protocol,
|
||||
host: ctx.req.get('host'),
|
||||
headers: {'message-id':'custom-header-value'}
|
||||
headers: { 'message-id': 'custom-header-value' },
|
||||
};
|
||||
|
||||
user.verify(options, function(err, result) {
|
||||
|
@ -1120,7 +1126,7 @@ describe('User', function() {
|
|||
process.nextTick(function() {
|
||||
cb(null, 'token-123456');
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
user.verify(options, function(err, result) {
|
||||
|
@ -1162,7 +1168,7 @@ describe('User', function() {
|
|||
process.nextTick(function() {
|
||||
cb(new Error('Fake error'));
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
user.verify(options, function(err, result) {
|
||||
|
@ -1197,7 +1203,7 @@ describe('User', function() {
|
|||
redirect: '/',
|
||||
protocol: 'http',
|
||||
host: 'myapp.org',
|
||||
port: 3000
|
||||
port: 3000,
|
||||
};
|
||||
|
||||
user.verify(options, function(err, result) {
|
||||
|
@ -1230,7 +1236,7 @@ describe('User', function() {
|
|||
redirect: '/',
|
||||
protocol: 'http',
|
||||
host: 'myapp.org',
|
||||
port: 80
|
||||
port: 80,
|
||||
};
|
||||
|
||||
user.verify(options, function(err, result) {
|
||||
|
@ -1263,7 +1269,7 @@ describe('User', function() {
|
|||
redirect: '/',
|
||||
protocol: 'https',
|
||||
host: 'myapp.org',
|
||||
port: 3000
|
||||
port: 3000,
|
||||
};
|
||||
|
||||
user.verify(options, function(err, result) {
|
||||
|
@ -1296,7 +1302,7 @@ describe('User', function() {
|
|||
redirect: '/',
|
||||
protocol: 'https',
|
||||
host: 'myapp.org',
|
||||
port: 443
|
||||
port: 443,
|
||||
};
|
||||
|
||||
user.verify(options, function(err, result) {
|
||||
|
@ -1320,7 +1326,11 @@ describe('User', function() {
|
|||
});
|
||||
|
||||
it('should hide verification tokens from user JSON', function(done) {
|
||||
var user = new User({email: 'bar@bat.com', password: 'bar', verificationToken: 'a-token' });
|
||||
var user = new User({
|
||||
email: 'bar@bat.com',
|
||||
password: 'bar',
|
||||
verificationToken: 'a-token',
|
||||
});
|
||||
var data = user.toJSON();
|
||||
assert(!('verificationToken' in data));
|
||||
done();
|
||||
|
@ -1340,7 +1350,7 @@ describe('User', function() {
|
|||
from: 'noreply@myapp.org',
|
||||
redirect: 'http://foo.com/bar',
|
||||
protocol: ctx.req.protocol,
|
||||
host: ctx.req.get('host')
|
||||
host: ctx.req.get('host'),
|
||||
};
|
||||
|
||||
user.verify(options, function(err, result) {
|
||||
|
@ -1478,7 +1488,7 @@ describe('User', function() {
|
|||
var calledBack = false;
|
||||
|
||||
User.resetPassword({
|
||||
email: email
|
||||
email: email,
|
||||
}, function() {
|
||||
calledBack = true;
|
||||
});
|
||||
|
|
|
@ -7,11 +7,8 @@ var PersistedModel = loopback.PersistedModel;
|
|||
var RemoteObjects = require('strong-remoting');
|
||||
|
||||
module.exports = function defineModelTestsWithDataSource(options) {
|
||||
|
||||
describe('Model Tests', function() {
|
||||
|
||||
var User;
|
||||
var dataSource;
|
||||
var User, dataSource;
|
||||
|
||||
if (options.beforeEach) {
|
||||
beforeEach(options.beforeEach);
|
||||
|
@ -44,9 +41,9 @@ module.exports = function defineModelTestsWithDataSource(options) {
|
|||
'password': String,
|
||||
'gender': String,
|
||||
'domain': String,
|
||||
'email': String
|
||||
'email': String,
|
||||
}, {
|
||||
trackChanges: true
|
||||
trackChanges: true,
|
||||
});
|
||||
|
||||
User.attachTo(dataSource);
|
||||
|
@ -131,7 +128,8 @@ module.exports = function defineModelTestsWithDataSource(options) {
|
|||
});
|
||||
|
||||
describe('Model.create([data], [callback])', function() {
|
||||
it('Create an instance of Model with given data and save to the attached data source', function(done) {
|
||||
it('Create an instance of Model with given data and save to the attached data source',
|
||||
function(done) {
|
||||
User.create({ first: 'Joe', last: 'Bob' }, function(err, user) {
|
||||
assert(user instanceof User);
|
||||
done();
|
||||
|
@ -159,7 +157,7 @@ module.exports = function defineModelTestsWithDataSource(options) {
|
|||
|
||||
user.updateAttributes({
|
||||
first: 'updatedFirst',
|
||||
last: 'updatedLast'
|
||||
last: 'updatedLast',
|
||||
}, function(err, updatedUser) {
|
||||
assert(!err);
|
||||
assert.equal(updatedUser.first, 'updatedFirst');
|
||||
|
@ -247,7 +245,5 @@ module.exports = function defineModelTestsWithDataSource(options) {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue