Update eslint to loopback config v5

Notable side-effects:
 - loopback no longer exports "caller" and "arguments" properties
 - kv-memory connector is now properly added to the connector registry
 - the file "test/support.js" was finally removed
This commit is contained in:
Loay 2016-11-15 16:46:23 -05:00 committed by Miroslav Bajtoš
parent ef0478cc97
commit 06cb481c3f
113 changed files with 1275 additions and 1151 deletions

View File

@ -5,6 +5,7 @@
"ignoreComments": true, "ignoreComments": true,
"ignoreUrls": true, "ignoreUrls": true,
"ignorePattern": "^\\s*var\\s.+=\\s*(require\\s*\\()|(/)" "ignorePattern": "^\\s*var\\s.+=\\s*(require\\s*\\()|(/)"
}] }],
"no-unused-expressions": "off",
} }
} }

View File

@ -4,6 +4,7 @@
// License text available at https://opensource.org/licenses/MIT // License text available at https://opensource.org/licenses/MIT
/*global module:false*/ /*global module:false*/
'use strict';
module.exports = function(grunt) { module.exports = function(grunt) {
// Do not report warnings from unit-tests exercising deprecated paths // Do not report warnings from unit-tests exercising deprecated paths
process.env.NO_DEPRECATION = 'loopback'; process.env.NO_DEPRECATION = 'loopback';
@ -201,7 +202,7 @@ module.exports = function(grunt) {
}, },
// Add browserify to preprocessors // Add browserify to preprocessors
preprocessors: { 'test/e2e/*': ['browserify'] }, preprocessors: {'test/e2e/*': ['browserify']},
}, },
}, },
}, },

View File

@ -7,6 +7,7 @@
* Module Dependencies. * Module Dependencies.
*/ */
'use strict';
var g = require('../../lib/globalize'); var g = require('../../lib/globalize');
var loopback = require('../../lib/loopback'); var loopback = require('../../lib/loopback');
var assert = require('assert'); var assert = require('assert');
@ -47,7 +48,7 @@ module.exports = function(AccessToken) {
* ``` * ```
*/ */
AccessToken.ANONYMOUS = new AccessToken({ id: '$anonymous' }); AccessToken.ANONYMOUS = new AccessToken({id: '$anonymous'});
/** /**
* Create a cryptographically random access token id. * Create a cryptographically random access token id.

View File

@ -3,13 +3,11 @@
// This file is licensed under the MIT License. // This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT // License text available at https://opensource.org/licenses/MIT
'use strict';
/*! /*!
Schema ACL options Schema ACL options
Object level permissions, for example, an album owned by a user Object level permissions, for example, an album owned by a user
Factors to be authorized against: Factors to be authorized against:
* model name: Album * model name: Album
* model instance properties: userId of the album, friends, shared * model instance properties: userId of the album, friends, shared
* methods * methods
@ -21,19 +19,15 @@
** none ** none
** everyone ** everyone
** relations: owner/friend/granted ** relations: owner/friend/granted
Class level permissions, for example, Album Class level permissions, for example, Album
* model name: Album * model name: Album
* methods * methods
URL/Route level permissions URL/Route level permissions
* url pattern * url pattern
* application id * application id
* ip addresses * ip addresses
* http headers * http headers
Map to oAuth 2.0 scopes Map to oAuth 2.0 scopes
*/ */
var g = require('../../lib/globalize'); var g = require('../../lib/globalize');
@ -331,10 +325,10 @@ module.exports = function(ACL) {
principalId = principalId.toString(); principalId = principalId.toString();
} }
property = property || ACL.ALL; property = property || ACL.ALL;
var propertyQuery = (property === ACL.ALL) ? undefined : { inq: [property, ACL.ALL] }; var propertyQuery = (property === ACL.ALL) ? undefined : {inq: [property, ACL.ALL]};
accessType = accessType || ACL.ALL; accessType = accessType || ACL.ALL;
var accessTypeQuery = (accessType === ACL.ALL) ? undefined : var accessTypeQuery = (accessType === ACL.ALL) ? undefined :
{ inq: [accessType, ACL.ALL, ACL.EXECUTE] }; {inq: [accessType, ACL.ALL, ACL.EXECUTE]};
var req = new AccessRequest(model, property, accessType); var req = new AccessRequest(model, property, accessType);
@ -352,8 +346,8 @@ module.exports = function(ACL) {
} }
var self = this; var self = this;
this.find({ where: { principalType: principalType, principalId: principalId, this.find({where: {principalType: principalType, principalId: principalId,
model: model, property: propertyQuery, accessType: accessTypeQuery }}, model: model, property: propertyQuery, accessType: accessTypeQuery}},
function(err, dynACLs) { function(err, dynACLs) {
if (err) { if (err) {
if (callback) callback(err); if (callback) callback(err);
@ -408,21 +402,21 @@ module.exports = function(ACL) {
var modelName = context.modelName; var modelName = context.modelName;
var methodNames = context.methodNames; var methodNames = context.methodNames;
var propertyQuery = (property === ACL.ALL) ? undefined : { inq: methodNames.concat([ACL.ALL]) }; var propertyQuery = (property === ACL.ALL) ? undefined : {inq: methodNames.concat([ACL.ALL])};
var accessTypeQuery = (accessType === ACL.ALL) ? var accessTypeQuery = (accessType === ACL.ALL) ?
undefined : undefined :
(accessType === ACL.REPLICATE) ? (accessType === ACL.REPLICATE) ?
{ inq: [ACL.REPLICATE, ACL.WRITE, ACL.ALL] } : {inq: [ACL.REPLICATE, ACL.WRITE, ACL.ALL]} :
{ inq: [accessType, ACL.ALL] }; {inq: [accessType, ACL.ALL]};
var req = new AccessRequest(modelName, property, accessType, ACL.DEFAULT, methodNames); var req = new AccessRequest(modelName, property, accessType, ACL.DEFAULT, methodNames);
var effectiveACLs = []; var effectiveACLs = [];
var staticACLs = self.getStaticACLs(model.modelName, property); var staticACLs = self.getStaticACLs(model.modelName, property);
this.find({ where: { model: model.modelName, property: propertyQuery, this.find({where: {model: model.modelName, property: propertyQuery,
accessType: accessTypeQuery }}, function(err, acls) { accessType: accessTypeQuery}}, function(err, acls) {
if (err) { if (err) {
if (callback) callback(err); if (callback) callback(err);
return; return;
@ -525,15 +519,15 @@ module.exports = function(ACL) {
this.resolveRelatedModels(); this.resolveRelatedModels();
switch (type) { switch (type) {
case ACL.ROLE: case ACL.ROLE:
this.roleModel.findOne({ where: { or: [{ name: id }, { id: id }] }}, cb); this.roleModel.findOne({where: {or: [{name: id}, {id: id}]}}, cb);
break; break;
case ACL.USER: case ACL.USER:
this.userModel.findOne( this.userModel.findOne(
{ where: { or: [{ username: id }, { email: id }, { id: id }] }}, cb); {where: {or: [{username: id}, {email: id}, {id: id}]}}, cb);
break; break;
case ACL.APP: case ACL.APP:
this.applicationModel.findOne( this.applicationModel.findOne(
{ where: { or: [{ name: id }, { email: id }, { id: id }] }}, cb); {where: {or: [{name: id}, {email: id}, {id: id}]}}, cb);
break; break;
default: default:
process.nextTick(function() { process.nextTick(function() {

View File

@ -3,6 +3,7 @@
// This file is licensed under the MIT License. // This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT // License text available at https://opensource.org/licenses/MIT
'use strict';
var assert = require('assert'); var assert = require('assert');
var utils = require('../../lib/utils'); var utils = require('../../lib/utils');
@ -70,18 +71,6 @@ function generateKey(hmacKey, algorithm, encoding) {
*/ */
module.exports = function(Application) { module.exports = function(Application) {
// Workaround for https://github.com/strongloop/loopback/issues/292
Application.definition.rawProperties.created.default =
Application.definition.properties.created.default = function() {
return new Date();
};
// Workaround for https://github.com/strongloop/loopback/issues/292
Application.definition.rawProperties.modified.default =
Application.definition.properties.modified.default = function() {
return new Date();
};
/*! /*!
* A hook to generate keys before creation * A hook to generate keys before creation
* @param next * @param next
@ -126,7 +115,7 @@ module.exports = function(Application) {
} }
cb = cb || utils.createPromiseCallback(); cb = cb || utils.createPromiseCallback();
var props = { owner: owner, name: name }; var props = {owner: owner, name: name};
for (var p in options) { for (var p in options) {
if (!(p in props)) { if (!(p in props)) {
props[p] = options[p]; props[p] = options[p];

View File

@ -118,7 +118,13 @@
"description": "Status of the application, production/sandbox/disabled" "description": "Status of the application, production/sandbox/disabled"
}, },
"created": "date", "created": {
"modified": "date" "type": "date",
"defaultFn": "now"
},
"modified": {
"type": "date",
"defaultFn": "now"
}
} }
} }

View File

@ -7,12 +7,13 @@
* Module Dependencies. * Module Dependencies.
*/ */
'use strict';
var g = require('../../lib/globalize'); var g = require('../../lib/globalize');
var PersistedModel = require('../../lib/loopback').PersistedModel; var PersistedModel = require('../../lib/loopback').PersistedModel;
var loopback = require('../../lib/loopback'); var loopback = require('../../lib/loopback');
var utils = require('../../lib/utils'); var utils = require('../../lib/utils');
var crypto = require('crypto'); var crypto = require('crypto');
var CJSON = { stringify: require('canonical-json') }; var CJSON = {stringify: require('canonical-json')};
var async = require('async'); var async = require('async');
var assert = require('assert'); var assert = require('assert');
var debug = require('debug')('loopback:change'); var debug = require('debug')('loopback:change');
@ -113,7 +114,7 @@ module.exports = function(Change) {
var msg = g.f('Cannot rectify %s changes:\n%s', modelName, desc); var msg = g.f('Cannot rectify %s changes:\n%s', modelName, desc);
err = new Error(msg); err = new Error(msg);
err.details = { errors: errors }; err.details = {errors: errors};
return callback(err); return callback(err);
} }
callback(); callback();
@ -404,7 +405,7 @@ module.exports = function(Change) {
callback = callback || utils.createPromiseCallback(); callback = callback || utils.createPromiseCallback();
if (!Array.isArray(remoteChanges) || remoteChanges.length === 0) { if (!Array.isArray(remoteChanges) || remoteChanges.length === 0) {
callback(null, { deltas: [], conflicts: [] }); callback(null, {deltas: [], conflicts: []});
return callback.promise; return callback.promise;
} }
var remoteChangeIndex = {}; var remoteChangeIndex = {};
@ -419,7 +420,7 @@ module.exports = function(Change) {
this.find({ this.find({
where: { where: {
modelName: modelName, modelName: modelName,
modelId: { inq: modelIds }, modelId: {inq: modelIds},
}, },
}, function(err, allLocalChanges) { }, function(err, allLocalChanges) {
if (err) return callback(err); if (err) return callback(err);
@ -674,7 +675,7 @@ module.exports = function(Change) {
if (err) return cb(err); if (err) return cb(err);
conflict.SourceModel.updateLastChange( conflict.SourceModel.updateLastChange(
conflict.modelId, conflict.modelId,
{ prev: targetChange.rev }, {prev: targetChange.rev},
cb); cb);
}); });
}; };
@ -708,7 +709,7 @@ module.exports = function(Change) {
} }
var inst = new conflict.SourceModel( var inst = new conflict.SourceModel(
target.toObject(), target.toObject(),
{ persisted: true }); {persisted: true});
inst.save(done); inst.save(done);
}); });

View File

@ -7,6 +7,7 @@
* Module Dependencies. * Module Dependencies.
*/ */
'use strict';
var assert = require('assert'); var assert = require('assert');
/** /**
@ -41,8 +42,8 @@ module.exports = function(Checkpoint) {
}; };
Checkpoint._getSingleton = function(cb) { Checkpoint._getSingleton = function(cb) {
var query = { limit: 1 }; // match all instances, return only one var query = {limit: 1}; // match all instances, return only one
var initialData = { seq: 1 }; var initialData = {seq: 1};
this.findOrCreate(query, initialData, cb); this.findOrCreate(query, initialData, cb);
}; };
@ -59,7 +60,7 @@ module.exports = function(Checkpoint) {
var originalSeq = cp.seq; var originalSeq = cp.seq;
cp.seq++; cp.seq++;
// Update the checkpoint but only if it was not changed under our hands // Update the checkpoint but only if it was not changed under our hands
Checkpoint.updateAll({ id: cp.id, seq: originalSeq }, { seq: cp.seq }, function(err, info) { Checkpoint.updateAll({id: cp.id, seq: originalSeq}, {seq: cp.seq}, function(err, info) {
if (err) return cb(err); if (err) return cb(err);
// possible outcomes // possible outcomes
// 1) seq was updated to seq+1 - exactly what we wanted! // 1) seq was updated to seq+1 - exactly what we wanted!

View File

@ -3,20 +3,21 @@
// This file is licensed under the MIT License. // This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT // License text available at https://opensource.org/licenses/MIT
/** 'use strict';
* Email model. Extends LoopBack base [Model](#model-new-model).
* @property {String} to Email addressee. Required.
* @property {String} from Email sender address. Required.
* @property {String} subject Email subject string. Required.
* @property {String} text Text body of email.
* @property {String} html HTML body of email.
*
* @class Email
* @inherits {Model}
*/
var g = require('../../lib/globalize'); var g = require('../../lib/globalize');
/**
* Email model. Extends LoopBack base [Model](#model-new-model).
* @property {String} to Email addressee. Required.
* @property {String} from Email sender address. Required.
* @property {String} subject Email subject string. Required.
* @property {String} text Text body of email.
* @property {String} html HTML body of email.
*
* @class Email
* @inherits {Model}
*/
module.exports = function(Email) { module.exports = function(Email) {
/** /**
* Send an email with the given `options`. * Send an email with the given `options`.

View File

@ -1,3 +1,9 @@
// Copyright IBM Corp. 2014,2016. All Rights Reserved.
// Node module: loopback
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
var g = require('../../lib/globalize'); var g = require('../../lib/globalize');
/** /**
@ -164,52 +170,52 @@ module.exports = function(KeyValueModel) {
this.remoteMethod('get', { this.remoteMethod('get', {
accepts: { accepts: {
arg: 'key', type: 'string', required: true, arg: 'key', type: 'string', required: true,
http: { source: 'path' }, http: {source: 'path'},
}, },
returns: { arg: 'value', type: 'any', root: true }, returns: {arg: 'value', type: 'any', root: true},
http: { path: '/:key', verb: 'get' }, http: {path: '/:key', verb: 'get'},
rest: { after: convertNullToNotFoundError }, rest: {after: convertNullToNotFoundError},
}); });
this.remoteMethod('set', { this.remoteMethod('set', {
accepts: [ accepts: [
{ arg: 'key', type: 'string', required: true, {arg: 'key', type: 'string', required: true,
http: { source: 'path' }}, http: {source: 'path'}},
{ arg: 'value', type: 'any', required: true, {arg: 'value', type: 'any', required: true,
http: { source: 'body' }}, http: {source: 'body'}},
{ arg: 'ttl', type: 'number', {arg: 'ttl', type: 'number',
http: { source: 'query' }, http: {source: 'query'},
description: 'time to live in milliseconds' }, description: 'time to live in milliseconds'},
], ],
http: { path: '/:key', verb: 'put' }, http: {path: '/:key', verb: 'put'},
}); });
this.remoteMethod('expire', { this.remoteMethod('expire', {
accepts: [ accepts: [
{ arg: 'key', type: 'string', required: true, {arg: 'key', type: 'string', required: true,
http: { source: 'path' }}, http: {source: 'path'}},
{ arg: 'ttl', type: 'number', required: true, {arg: 'ttl', type: 'number', required: true,
http: { source: 'form' }}, http: {source: 'form'}},
], ],
http: { path: '/:key/expire', verb: 'put' }, http: {path: '/:key/expire', verb: 'put'},
}); });
this.remoteMethod('ttl', { this.remoteMethod('ttl', {
accepts: { accepts: {
arg: 'key', type: 'string', required: true, arg: 'key', type: 'string', required: true,
http: { source: 'path' }, http: {source: 'path'},
}, },
returns: { arg: 'value', type: 'any', root: true }, returns: {arg: 'value', type: 'any', root: true},
http: { path: '/:key/ttl', verb: 'get' }, http: {path: '/:key/ttl', verb: 'get'},
}); });
this.remoteMethod('keys', { this.remoteMethod('keys', {
accepts: { accepts: {
arg: 'filter', type: 'object', required: false, arg: 'filter', type: 'object', required: false,
http: { source: 'query' }, http: {source: 'query'},
}, },
returns: { arg: 'keys', type: ['string'], root: true }, returns: {arg: 'keys', type: ['string'], root: true},
http: { path: '/keys', verb: 'get' }, http: {path: '/keys', verb: 'get'},
}); });
}; };
}; };

View File

@ -3,6 +3,7 @@
// This file is licensed under the MIT License. // This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT // License text available at https://opensource.org/licenses/MIT
'use strict';
var loopback = require('../../lib/loopback'); var loopback = require('../../lib/loopback');
/** /**

View File

@ -3,6 +3,7 @@
// This file is licensed under the MIT License. // This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT // License text available at https://opensource.org/licenses/MIT
'use strict';
var loopback = require('../../lib/loopback'); var loopback = require('../../lib/loopback');
var debug = require('debug')('loopback:security:role'); var debug = require('debug')('loopback:security:role');
var assert = require('assert'); var assert = require('assert');
@ -20,18 +21,6 @@ assert(RoleMapping, 'RoleMapping model must be defined before Role model');
* @header Role object * @header Role object
*/ */
module.exports = function(Role) { module.exports = function(Role) {
// Workaround for https://github.com/strongloop/loopback/issues/292
Role.definition.rawProperties.created.default =
Role.definition.properties.created.default = function() {
return new Date();
};
// Workaround for https://github.com/strongloop/loopback/issues/292
Role.definition.rawProperties.modified.default =
Role.definition.properties.modified.default = function() {
return new Date();
};
Role.resolveRelatedModels = function() { Role.resolveRelatedModels = function() {
if (!this.userModel) { if (!this.userModel) {
var reg = this.registry; var reg = this.registry;
@ -98,7 +87,7 @@ module.exports = function(Role) {
} }
roleModel.roleMappingModel.find({ roleModel.roleMappingModel.find({
where: { roleId: context.id, principalType: principalType }, where: {roleId: context.id, principalType: principalType},
}, function(err, mappings) { }, function(err, mappings) {
var ids; var ids;
if (err) { if (err) {
@ -108,7 +97,7 @@ module.exports = function(Role) {
return m.principalId; return m.principalId;
}); });
query.where = query.where || {}; query.where = query.where || {};
query.where.id = { inq: ids }; query.where.id = {inq: ids};
model.find(query, function(err, models) { model.find(query, function(err, models) {
callback(err, models); callback(err, models);
}); });
@ -330,7 +319,7 @@ module.exports = function(Role) {
} }
var roleMappingModel = this.roleMappingModel; var roleMappingModel = this.roleMappingModel;
this.findOne({ where: { name: role }}, function(err, result) { this.findOne({where: {name: role}}, function(err, result) {
if (err) { if (err) {
if (callback) callback(err); if (callback) callback(err);
return; return;
@ -353,8 +342,8 @@ module.exports = function(Role) {
} }
if (principalType && principalId) { if (principalType && principalId) {
roleMappingModel.findOne({ where: { roleId: roleId, roleMappingModel.findOne({where: {roleId: roleId,
principalType: principalType, principalId: principalId }}, principalType: principalType, principalId: principalId}},
function(err, result) { function(err, result) {
debug('Role mapping found: %j', result); debug('Role mapping found: %j', result);
done(!err && result); // The only arg is the result done(!err && result); // The only arg is the result
@ -429,8 +418,8 @@ module.exports = function(Role) {
if (principalType && principalId) { if (principalType && principalId) {
// Please find() treat undefined matches all values // Please find() treat undefined matches all values
inRoleTasks.push(function(done) { inRoleTasks.push(function(done) {
roleMappingModel.find({ where: { principalType: principalType, roleMappingModel.find({where: {principalType: principalType,
principalId: principalId }}, function(err, mappings) { principalId: principalId}}, function(err, mappings) {
debug('Role mappings found: %s %j', err, mappings); debug('Role mappings found: %s %j', err, mappings);
if (err) { if (err) {
if (done) done(err); if (done) done(err);
@ -451,5 +440,5 @@ module.exports = function(Role) {
}); });
}; };
Role.validatesUniquenessOf('name', { message: 'already exists' }); Role.validatesUniquenessOf('name', {message: 'already exists'});
}; };

View File

@ -13,8 +13,12 @@
}, },
"description": "string", "description": "string",
"created": "date", "created": {
"modified": "date" "defaultFn": "now"
},
"modified": {
"defaultFn": "now"
}
}, },
"relations": { "relations": {
"principals": { "principals": {

View File

@ -3,6 +3,7 @@
// This file is licensed under the MIT License. // This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT // License text available at https://opensource.org/licenses/MIT
'use strict';
var assert = require('assert'); var assert = require('assert');
var loopback = require('../../lib/loopback'); var loopback = require('../../lib/loopback');
@ -41,7 +42,7 @@ module.exports = function(Scope) {
assert(aclModel, assert(aclModel,
'ACL model must be defined before Scope.checkPermission is called'); 'ACL model must be defined before Scope.checkPermission is called');
this.findOne({ where: { name: scope }}, function(err, scope) { this.findOne({where: {name: scope}}, function(err, scope) {
if (err) { if (err) {
if (callback) callback(err); if (callback) callback(err);
} else { } else {

View File

@ -7,6 +7,7 @@
* Module Dependencies. * Module Dependencies.
*/ */
'use strict';
var g = require('../../lib/globalize'); var g = require('../../lib/globalize');
var isEmail = require('isemail'); var isEmail = require('isemail');
var loopback = require('../../lib/loopback'); var loopback = require('../../lib/loopback');
@ -219,7 +220,7 @@ module.exports = function(User) {
return fn.promise; return fn.promise;
} }
self.findOne({ where: query }, function(err, user) { self.findOne({where: query}, function(err, user) {
var defaultError = new Error(g.f('login failed')); var defaultError = new Error(g.f('login failed'));
defaultError.statusCode = 401; defaultError.statusCode = 401;
defaultError.code = 'LOGIN_FAILED'; defaultError.code = 'LOGIN_FAILED';
@ -306,14 +307,14 @@ module.exports = function(User) {
User.observe('before delete', function(ctx, next) { User.observe('before delete', function(ctx, next) {
var AccessToken = ctx.Model.relations.accessTokens.modelTo; var AccessToken = ctx.Model.relations.accessTokens.modelTo;
var pkName = ctx.Model.definition.idName() || 'id'; var pkName = ctx.Model.definition.idName() || 'id';
ctx.Model.find({ where: ctx.where, fields: [pkName] }, function(err, list) { ctx.Model.find({where: ctx.where, fields: [pkName]}, function(err, list) {
if (err) return next(err); if (err) return next(err);
var ids = list.map(function(u) { return u[pkName]; }); var ids = list.map(function(u) { return u[pkName]; });
ctx.where = {}; ctx.where = {};
ctx.where[pkName] = { inq: ids }; ctx.where[pkName] = {inq: ids};
AccessToken.destroyAll({ userId: { inq: ids }}, next); AccessToken.destroyAll({userId: {inq: ids}}, next);
}); });
}); });
@ -431,7 +432,8 @@ module.exports = function(User) {
options.templateFn = options.templateFn || createVerificationEmailBody; options.templateFn = options.templateFn || createVerificationEmailBody;
// Email model // Email model
var Email = options.mailer || this.constructor.email || registry.getModelByType(loopback.Email); var Email =
options.mailer || this.constructor.email || registry.getModelByType(loopback.Email);
// Set a default token generation function if one is not provided // Set a default token generation function if one is not provided
var tokenGenerator = options.generateVerificationToken || User.generateVerificationToken; var tokenGenerator = options.generateVerificationToken || User.generateVerificationToken;
@ -479,7 +481,7 @@ module.exports = function(User) {
if (err) { if (err) {
fn(err); fn(err);
} else { } else {
fn(null, { email: email, token: user.verificationToken, uid: user.id }); fn(null, {email: email, token: user.verificationToken, uid: user.id});
} }
}); });
} }
@ -493,7 +495,6 @@ module.exports = function(User) {
cb(null, body); cb(null, body);
} }
/** /**
* A default verification token generator which accepts the user the token is * A default verification token generator which accepts the user the token is
* being generated for and a callback function to indicate completion. * being generated for and a callback function to indicate completion.
@ -584,7 +585,7 @@ module.exports = function(User) {
} catch (err) { } catch (err) {
return cb(err); return cb(err);
} }
UserModel.findOne({ where: { email: options.email }}, function(err, user) { UserModel.findOne({where: {email: options.email}}, function(err, user) {
if (err) { if (err) {
return cb(err); return cb(err);
} }
@ -603,7 +604,7 @@ module.exports = function(User) {
return cb(err); return cb(err);
} }
user.accessTokens.create({ ttl: ttl }, function(err, accessToken) { user.accessTokens.create({ttl: ttl}, function(err, accessToken) {
if (err) { if (err) {
return cb(err); return cb(err);
} }
@ -699,11 +700,11 @@ module.exports = function(User) {
UserModel.observe('before save', function beforeEmailUpdate(ctx, next) { UserModel.observe('before save', function beforeEmailUpdate(ctx, next) {
if (ctx.isNewInstance) return next(); if (ctx.isNewInstance) return next();
if (!ctx.where && !ctx.instance) return next(); if (!ctx.where && !ctx.instance) return next();
var where = ctx.where || { id: ctx.instance.id }; var where = ctx.where || {id: ctx.instance.id};
ctx.Model.find({ where: where }, function(err, userInstances) { ctx.Model.find({where: where}, function(err, userInstances) {
if (err) return next(err); if (err) return next(err);
ctx.hookState.originalUserData = userInstances.map(function(u) { ctx.hookState.originalUserData = userInstances.map(function(u) {
return { id: u.id, email: u.email }; return {id: u.id, email: u.email};
}); });
if (ctx.instance) { if (ctx.instance) {
var emailChanged = ctx.instance.email !== ctx.hookState.originalUserData[0].email; var emailChanged = ctx.instance.email !== ctx.hookState.originalUserData[0].email;
@ -735,7 +736,7 @@ module.exports = function(User) {
return u.id; return u.id;
}); });
if (!idsToExpire.length) return next(); if (!idsToExpire.length) return next();
AccessToken.deleteAll({ userId: { inq: idsToExpire }}, next); AccessToken.deleteAll({userId: {inq: idsToExpire}}, next);
}); });
UserModel.remoteMethod( UserModel.remoteMethod(
@ -743,10 +744,10 @@ module.exports = function(User) {
{ {
description: 'Login a user with username/email and password.', description: 'Login a user with username/email and password.',
accepts: [ accepts: [
{ arg: 'credentials', type: 'object', required: true, http: { source: 'body' }}, {arg: 'credentials', type: 'object', required: true, http: {source: 'body'}},
{ arg: 'include', type: ['string'], http: { source: 'query' }, {arg: 'include', type: ['string'], http: {source: 'query'},
description: 'Related objects to include in the response. ' + 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: { returns: {
arg: 'accessToken', type: 'object', root: true, arg: 'accessToken', type: 'object', root: true,
@ -757,7 +758,7 @@ module.exports = function(User) {
' - `user` - `U+007BUserU+007D` - Data of the currently logged in user. ' + ' - `user` - `U+007BUserU+007D` - Data of the currently logged in user. ' +
'{{(`include=user`)}}\n\n'), '{{(`include=user`)}}\n\n'),
}, },
http: { verb: 'post' }, http: {verb: 'post'},
} }
); );
@ -766,7 +767,7 @@ module.exports = function(User) {
{ {
description: 'Logout a user with access token.', description: 'Logout a user with access token.',
accepts: [ accepts: [
{ arg: 'access_token', type: 'string', required: true, http: function(ctx) { {arg: 'access_token', type: 'string', required: true, http: function(ctx) {
var req = ctx && ctx.req; var req = ctx && ctx.req;
var accessToken = req && req.accessToken; var accessToken = req && req.accessToken;
var tokenID = accessToken && accessToken.id; var tokenID = accessToken && accessToken.id;
@ -776,7 +777,7 @@ module.exports = function(User) {
'from request headers.', 'from request headers.',
}, },
], ],
http: { verb: 'all' }, http: {verb: 'all'},
} }
); );
@ -785,11 +786,11 @@ module.exports = function(User) {
{ {
description: 'Confirm a user registration with email verification token.', description: 'Confirm a user registration with email verification token.',
accepts: [ accepts: [
{ arg: 'uid', type: 'string', required: true }, {arg: 'uid', type: 'string', required: true},
{ arg: 'token', 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'},
} }
); );
@ -798,9 +799,9 @@ module.exports = function(User) {
{ {
description: 'Reset password for a user with email.', description: 'Reset password for a user with email.',
accepts: [ 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'},
} }
); );
@ -838,8 +839,8 @@ module.exports = function(User) {
}); });
} else { } else {
// Regular(Non-realm) users validation // Regular(Non-realm) users validation
UserModel.validatesUniquenessOf('email', { message: 'Email already exists' }); UserModel.validatesUniquenessOf('email', {message: 'Email already exists'});
UserModel.validatesUniquenessOf('username', { message: 'User already exists' }); UserModel.validatesUniquenessOf('username', {message: 'User already exists'});
} }
return UserModel; return UserModel;

View File

@ -3,6 +3,7 @@
// This file is licensed under the MIT License. // This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT // License text available at https://opensource.org/licenses/MIT
'use strict';
var g = require('../../lib/globalize'); var g = require('../../lib/globalize');
var loopback = require('../../'); var loopback = require('../../');
var client = loopback(); var client = loopback();

View File

@ -3,18 +3,19 @@
// This file is licensed under the MIT License. // This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT // License text available at https://opensource.org/licenses/MIT
'use strict';
var loopback = require('../../'); var loopback = require('../../');
var CartItem = exports.CartItem = loopback.PersistedModel.extend('CartItem', { var CartItem = exports.CartItem = loopback.PersistedModel.extend('CartItem', {
tax: { type: Number, default: 0.1 }, tax: {type: Number, default: 0.1},
price: Number, price: Number,
item: String, item: String,
qty: { type: Number, default: 0 }, qty: {type: Number, default: 0},
cartId: Number, cartId: Number,
}); });
CartItem.sum = function(cartId, callback) { CartItem.sum = function(cartId, callback) {
this.find({ where: { cartId: 1 }}, function(err, items) { this.find({where: {cartId: 1}}, function(err, items) {
var total = items var total = items
.map(function(item) { .map(function(item) {
return item.total(); return item.total();
@ -29,8 +30,8 @@ CartItem.sum = function(cartId, callback) {
CartItem.remoteMethod('sum', CartItem.remoteMethod('sum',
{ {
accepts: { arg: 'cartId', type: 'number' }, accepts: {arg: 'cartId', type: 'number'},
returns: { arg: 'total', type: 'number' }, returns: {arg: 'total', type: 'number'},
} }
); );

View File

@ -3,6 +3,7 @@
// This file is licensed under the MIT License. // This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT // License text available at https://opensource.org/licenses/MIT
'use strict';
var loopback = require('../../'); var loopback = require('../../');
var server = module.exports = loopback(); var server = module.exports = loopback();
var CartItem = require('./models').CartItem; var CartItem = require('./models').CartItem;
@ -17,9 +18,9 @@ CartItem.attachTo(memory);
// test data // test data
CartItem.create([ CartItem.create([
{ item: 'red hat', qty: 6, price: 19.99, cartId: 1 }, {item: 'red hat', qty: 6, price: 19.99, cartId: 1},
{ item: 'green shirt', qty: 1, price: 14.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) { CartItem.sum(1, function(err, total) {

View File

@ -3,6 +3,7 @@
// This file is licensed under the MIT License. // This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT // License text available at https://opensource.org/licenses/MIT
'use strict';
var g = require('../../lib/globalize'); var g = require('../../lib/globalize');
var loopback = require('../../'); var loopback = require('../../');
var app = loopback(); var app = loopback();
@ -13,13 +14,13 @@ var schema = {
name: String, name: String,
}; };
app.dataSource('db', { connector: 'memory' }); app.dataSource('db', {connector: 'memory'});
var Color = app.registry.createModel('color', schema); var Color = app.registry.createModel('color', schema);
app.model(Color, { dataSource: 'db' }); app.model(Color, {dataSource: 'db'});
Color.create({ name: 'red' }); Color.create({name: 'red'});
Color.create({ name: 'green' }); Color.create({name: 'green'});
Color.create({ name: 'blue' }); Color.create({name: 'blue'});
app.listen(3000); app.listen(3000);

View File

@ -3,6 +3,7 @@
// This file is licensed under the MIT License. // This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT // License text available at https://opensource.org/licenses/MIT
'use strict';
var g = require('../../lib/globalize'); var g = require('../../lib/globalize');
var loopback = require('../../'); var loopback = require('../../');
var app = loopback(); var app = loopback();
@ -19,7 +20,7 @@ app.use(function saveHostToContext(req, res, next) {
app.use(loopback.rest()); app.use(loopback.rest());
var Color = loopback.createModel('color', { 'name': String }); var Color = loopback.createModel('color', {'name': String});
Color.beforeRemote('**', function(ctx, unused, next) { Color.beforeRemote('**', function(ctx, unused, next) {
// Inside LoopBack code, you can read the property from the context // Inside LoopBack code, you can read the property from the context
var ns = loopback.getCurrentContext(); var ns = loopback.getCurrentContext();
@ -27,8 +28,8 @@ Color.beforeRemote('**', function(ctx, unused, next) {
next(); next();
}); });
app.dataSource('db', { connector: 'memory' }); app.dataSource('db', {connector: 'memory'});
app.model(Color, { dataSource: 'db' }); app.model(Color, {dataSource: 'db'});
app.listen(3000, function() { app.listen(3000, function() {
g.log('A list of colors is available at {{http://localhost:3000/colors}}'); g.log('A list of colors is available at {{http://localhost:3000/colors}}');

View File

@ -3,6 +3,7 @@
// This file is licensed under the MIT License. // This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT // License text available at https://opensource.org/licenses/MIT
'use strict';
var g = require('../../lib/globalize'); var g = require('../../lib/globalize');
var models = require('../../lib/models'); var models = require('../../lib/models');
var loopback = require('../../'); var loopback = require('../../');
@ -10,15 +11,14 @@ var app = loopback();
app.use(loopback.rest()); app.use(loopback.rest());
var dataSource = loopback.createDataSource('db', { connector: loopback.Memory }); var dataSource = loopback.createDataSource('db', {connector: loopback.Memory});
var Application = models.Application(dataSource); var Application = models.Application(dataSource);
app.model(Application); app.model(Application);
var data = {pushSettings: [
var data = { pushSettings: [ {'platform': 'apns',
{ 'platform': 'apns',
'apns': { 'apns': {
'pushOptions': { 'pushOptions': {
'gateway': 'gateway.sandbox.push.apple.com', 'gateway': 'gateway.sandbox.push.apple.com',
@ -34,14 +34,13 @@ var data = { pushSettings: [
'interval': 300, 'interval': 300,
}, },
}}, }},
] }; ]};
Application.create(data, function(err, data) { Application.create(data, function(err, data) {
g.log('Created: %s', data.toObject()); g.log('Created: %s', data.toObject());
}); });
Application.register('rfeng', 'MyApp', {description: g.f('My first mobile application')},
Application.register('rfeng', 'MyApp', { description: g.f('My first mobile application') },
function(err, result) { function(err, result) {
console.log(result.toObject()); console.log(result.toObject());

View File

@ -3,13 +3,14 @@
// This file is licensed under the MIT License. // This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT // License text available at https://opensource.org/licenses/MIT
'use strict';
var loopback = require('../../'); var loopback = require('../../');
var app = loopback(); var app = loopback();
var db = app.dataSource('db', { connector: 'memory' }); var db = app.dataSource('db', {connector: 'memory'});
var Color = app.registry.createModel('color', {}, { trackChanges: true }); var Color = app.registry.createModel('color', {}, {trackChanges: true});
app.model(Color, { dataSource: 'db' }); app.model(Color, {dataSource: 'db'});
var Color2 = app.registry.createModel('color2', {}, { trackChanges: true }); var Color2 = app.registry.createModel('color2', {}, {trackChanges: true});
app.model(Color2, { dataSource: 'db' }); app.model(Color2, {dataSource: 'db'});
var target = Color2; var target = Color2;
var source = Color; var source = Color;
var SPEED = process.env.SPEED || 100; var SPEED = process.env.SPEED || 100;
@ -70,9 +71,9 @@ run(steps);
function createSomeInitialSourceData() { function createSomeInitialSourceData() {
Color.create([ Color.create([
{ name: 'red' }, {name: 'red'},
{ name: 'blue' }, {name: 'blue'},
{ name: 'green' }, {name: 'green'},
]); ]);
} }
@ -98,11 +99,11 @@ function updateSomeTargetData() {
} }
function createMoreSourceData() { function createMoreSourceData() {
Color.create({ name: 'orange' }); Color.create({name: 'orange'});
} }
function createEvenMoreSourceData() { function createEvenMoreSourceData() {
Color.create({ name: 'black' }); Color.create({name: 'black'});
} }
function updateSomeSourceDataCausingAConflict() { function updateSomeSourceDataCausingAConflict() {
@ -118,9 +119,9 @@ function deleteAllSourceData() {
function createSomeNewSourceData() { function createSomeNewSourceData() {
Color.create([ Color.create([
{ name: 'violet' }, {name: 'violet'},
{ name: 'amber' }, {name: 'amber'},
{ name: 'olive' }, {name: 'olive'},
]); ]);
} }

View File

@ -3,22 +3,22 @@
// This file is licensed under the MIT License. // This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT // License text available at https://opensource.org/licenses/MIT
'use strict';
var g = require('../../lib/globalize'); var g = require('../../lib/globalize');
var loopback = require('../../'); var loopback = require('../../');
var app = loopback(); var app = loopback();
app.use(loopback.rest()); app.use(loopback.rest());
var dataSource = app.dataSource('db', {adapter: 'memory'});
var dataSource = app.dataSource('db', { adapter: 'memory' });
var Color = dataSource.define('color', { var Color = dataSource.define('color', {
'name': String, 'name': String,
}); });
Color.create({ name: 'red' }); Color.create({name: 'red'});
Color.create({ name: 'green' }); Color.create({name: 'green'});
Color.create({ name: 'blue' }); Color.create({name: 'blue'});
Color.all(function() { Color.all(function() {
console.log(arguments); console.log(arguments);

View File

@ -3,6 +3,7 @@
// This file is licensed under the MIT License. // This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT // License text available at https://opensource.org/licenses/MIT
'use strict';
/** /**
* loopback ~ public api * loopback ~ public api
*/ */

View File

@ -3,6 +3,7 @@
// This file is licensed under the MIT License. // This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT // License text available at https://opensource.org/licenses/MIT
'use strict';
var assert = require('assert'); var assert = require('assert');
var loopback = require('./loopback'); var loopback = require('./loopback');
var debug = require('debug')('loopback:security:access-context'); var debug = require('debug')('loopback:security:access-context');

View File

@ -7,6 +7,7 @@
* Module dependencies. * Module dependencies.
*/ */
'use strict';
var g = require('./globalize'); var g = require('./globalize');
var DataSource = require('loopback-datasource-juggler').DataSource; var DataSource = require('loopback-datasource-juggler').DataSource;
var Registry = require('./registry'); var Registry = require('./registry');
@ -484,7 +485,7 @@ function setSharedMethodSharedProperties(model, app, modelConfigs) {
}); });
// set sharedMethod.shared using the merged settings // set sharedMethod.shared using the merged settings
var sharedMethods = model.sharedClass.methods({ includeDisabled: true }); var sharedMethods = model.sharedClass.methods({includeDisabled: true});
sharedMethods.forEach(function(sharedMethod) { sharedMethods.forEach(function(sharedMethod) {
// use the specific setting if it exists // use the specific setting if it exists
var hasSpecificSetting = settings.hasOwnProperty(sharedMethod.name); var hasSpecificSetting = settings.hasOwnProperty(sharedMethod.name);

View File

@ -3,6 +3,7 @@
// This file is licensed under the MIT License. // This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT // License text available at https://opensource.org/licenses/MIT
'use strict';
var EventEmitter = require('events').EventEmitter; var EventEmitter = require('events').EventEmitter;
var util = require('util'); var util = require('util');

View File

@ -3,6 +3,7 @@
// This file is licensed under the MIT License. // This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT // License text available at https://opensource.org/licenses/MIT
'use strict';
module.exports = function(registry) { module.exports = function(registry) {
// NOTE(bajtos) we must use static require() due to browserify limitations // NOTE(bajtos) we must use static require() due to browserify limitations

View File

@ -7,6 +7,7 @@
* Expose `Connector`. * Expose `Connector`.
*/ */
'use strict';
module.exports = Connector; module.exports = Connector;
/** /**

View File

@ -7,6 +7,7 @@
* Dependencies. * Dependencies.
*/ */
'use strict';
var g = require('../globalize'); var g = require('../globalize');
var mailer = require('nodemailer'); var mailer = require('nodemailer');
var assert = require('assert'); var assert = require('assert');

View File

@ -7,6 +7,7 @@
* Expose `Memory`. * Expose `Memory`.
*/ */
'use strict';
module.exports = Memory; module.exports = Memory;
/** /**

View File

@ -3,6 +3,7 @@
// This file is licensed under the MIT License. // This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT // License text available at https://opensource.org/licenses/MIT
'use strict';
var g = require('./globalize'); var g = require('./globalize');
var juggler = require('loopback-datasource-juggler'); var juggler = require('loopback-datasource-juggler');
var remoting = require('strong-remoting'); var remoting = require('strong-remoting');

View File

@ -3,8 +3,9 @@
// This file is licensed under the MIT License. // This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT // License text available at https://opensource.org/licenses/MIT
'use strict';
var path = require('path'); var path = require('path');
var SG = require('strong-globalize'); var SG = require('strong-globalize');
SG.SetRootDir(path.join(__dirname, '..'), { autonomousMsgLoading: 'all' }); SG.SetRootDir(path.join(__dirname, '..'), {autonomousMsgLoading: 'all'});
module.exports = SG(); module.exports = SG();

View File

@ -7,6 +7,7 @@
* Module dependencies. * Module dependencies.
*/ */
'use strict';
var express = require('express'); var express = require('express');
var loopbackExpress = require('./server-app'); var loopbackExpress = require('./server-app');
var proto = require('./application'); var proto = require('./application');
@ -93,6 +94,8 @@ function createApplication(options) {
// and thus browserify can process them (include connectors in the bundle) // and thus browserify can process them (include connectors in the bundle)
app.connector('memory', loopback.Memory); app.connector('memory', loopback.Memory);
app.connector('remote', loopback.Remote); app.connector('remote', loopback.Remote);
app.connector('kv-memory',
require('loopback-datasource-juggler/lib/connectors/kv-memory'));
if (loopback.localRegistry || options && options.localRegistry === true) { if (loopback.localRegistry || options && options.localRegistry === true) {
// setup the app registry // setup the app registry
@ -179,7 +182,7 @@ loopback.remoteMethod = function(fn, options) {
fn[key] = options[key]; fn[key] = options[key];
}); });
} }
fn.http = fn.http || { verb: 'get' }; fn.http = fn.http || {verb: 'get'};
}; };
/** /**

View File

@ -6,7 +6,7 @@
/*! /*!
* Module Dependencies. * Module Dependencies.
*/ */
'use strict';
var g = require('./globalize'); var g = require('./globalize');
var assert = require('assert'); var assert = require('assert');
var RemoteObjects = require('strong-remoting'); var RemoteObjects = require('strong-remoting');
@ -180,16 +180,16 @@ module.exports = function(registry) {
var idDesc = ModelCtor.modelName + ' id'; var idDesc = ModelCtor.modelName + ' id';
ModelCtor.sharedCtor.accepts = [ ModelCtor.sharedCtor.accepts = [
{ arg: 'id', type: 'any', required: true, http: { source: 'path' }, {arg: 'id', type: 'any', required: true, http: {source: 'path'},
description: idDesc }, description: idDesc},
// {arg: 'instance', type: 'object', http: {source: 'body'}} // {arg: 'instance', type: 'object', http: {source: 'body'}}
]; ];
ModelCtor.sharedCtor.http = [ ModelCtor.sharedCtor.http = [
{ path: '/:id' }, {path: '/:id'},
]; ];
ModelCtor.sharedCtor.returns = { root: true }; ModelCtor.sharedCtor.returns = {root: true};
// before remote hook // before remote hook
ModelCtor.beforeRemote = function(name, fn) { ModelCtor.beforeRemote = function(name, fn) {
@ -326,7 +326,7 @@ module.exports = function(registry) {
Model._getAccessTypeForMethod = function(method) { Model._getAccessTypeForMethod = function(method) {
if (typeof method === 'string') { if (typeof method === 'string') {
method = { name: method }; method = {name: method};
} }
assert( assert(
typeof method === 'object', typeof method === 'object',
@ -463,11 +463,11 @@ module.exports = function(registry) {
var pathName = (relation.options.http && relation.options.http.path) || relationName; var pathName = (relation.options.http && relation.options.http.path) || relationName;
define('__get__' + relationName, { define('__get__' + relationName, {
isStatic: false, isStatic: false,
http: { verb: 'get', path: '/' + pathName }, http: {verb: 'get', path: '/' + pathName},
accepts: { arg: 'refresh', type: 'boolean', http: { source: 'query' }}, accepts: {arg: 'refresh', type: 'boolean', http: {source: 'query'}},
accessType: 'READ', accessType: 'READ',
description: format('Fetches belongsTo relation %s.', relationName), description: format('Fetches belongsTo relation %s.', relationName),
returns: { arg: relationName, type: modelName, root: true }, returns: {arg: relationName, type: modelName, root: true},
}, fn); }, fn);
}; };
@ -488,35 +488,35 @@ module.exports = function(registry) {
define('__get__' + relationName, { define('__get__' + relationName, {
isStatic: false, isStatic: false,
http: { verb: 'get', path: '/' + pathName }, http: {verb: 'get', path: '/' + pathName},
accepts: { arg: 'refresh', type: 'boolean', http: { source: 'query' }}, accepts: {arg: 'refresh', type: 'boolean', http: {source: 'query'}},
description: format('Fetches hasOne relation %s.', relationName), description: format('Fetches hasOne relation %s.', relationName),
accessType: 'READ', accessType: 'READ',
returns: { arg: relationName, type: relation.modelTo.modelName, root: true }, returns: {arg: relationName, type: relation.modelTo.modelName, root: true},
rest: { after: convertNullToNotFoundError.bind(null, toModelName) }, rest: {after: convertNullToNotFoundError.bind(null, toModelName)},
}); });
define('__create__' + relationName, { define('__create__' + relationName, {
isStatic: false, isStatic: false,
http: { verb: 'post', path: '/' + pathName }, http: {verb: 'post', path: '/' + pathName},
accepts: { arg: 'data', type: 'object', model: toModelName, http: { source: 'body' }}, accepts: {arg: 'data', type: 'object', model: toModelName, http: {source: 'body'}},
description: format('Creates a new instance in %s of this model.', relationName), description: format('Creates a new instance in %s of this model.', relationName),
accessType: 'WRITE', accessType: 'WRITE',
returns: { arg: 'data', type: toModelName, root: true }, returns: {arg: 'data', type: toModelName, root: true},
}); });
define('__update__' + relationName, { define('__update__' + relationName, {
isStatic: false, isStatic: false,
http: { verb: 'put', path: '/' + pathName }, http: {verb: 'put', path: '/' + pathName},
accepts: { arg: 'data', type: 'object', model: toModelName, http: { source: 'body' }}, accepts: {arg: 'data', type: 'object', model: toModelName, http: {source: 'body'}},
description: format('Update %s of this model.', relationName), description: format('Update %s of this model.', relationName),
accessType: 'WRITE', accessType: 'WRITE',
returns: { arg: 'data', type: toModelName, root: true }, returns: {arg: 'data', type: toModelName, root: true},
}); });
define('__destroy__' + relationName, { define('__destroy__' + relationName, {
isStatic: false, isStatic: false,
http: { verb: 'delete', path: '/' + pathName }, http: {verb: 'delete', path: '/' + pathName},
description: format('Deletes %s of this model.', relationName), description: format('Deletes %s of this model.', relationName),
accessType: 'WRITE', accessType: 'WRITE',
}); });
@ -529,25 +529,25 @@ module.exports = function(registry) {
var findByIdFunc = this.prototype['__findById__' + relationName]; var findByIdFunc = this.prototype['__findById__' + relationName];
define('__findById__' + relationName, { define('__findById__' + relationName, {
isStatic: false, isStatic: false,
http: { verb: 'get', path: '/' + pathName + '/:fk' }, http: {verb: 'get', path: '/' + pathName + '/:fk'},
accepts: { arg: 'fk', type: 'any', accepts: {arg: 'fk', type: 'any',
description: format('Foreign key for %s', relationName), description: format('Foreign key for %s', relationName),
required: true, required: true,
http: { source: 'path' }}, http: {source: 'path'}},
description: format('Find a related item by id for %s.', relationName), description: format('Find a related item by id for %s.', relationName),
accessType: 'READ', accessType: 'READ',
returns: { arg: 'result', type: toModelName, root: true }, returns: {arg: 'result', type: toModelName, root: true},
rest: { after: convertNullToNotFoundError.bind(null, toModelName) }, rest: {after: convertNullToNotFoundError.bind(null, toModelName)},
}, findByIdFunc); }, findByIdFunc);
var destroyByIdFunc = this.prototype['__destroyById__' + relationName]; var destroyByIdFunc = this.prototype['__destroyById__' + relationName];
define('__destroyById__' + relationName, { define('__destroyById__' + relationName, {
isStatic: false, isStatic: false,
http: { verb: 'delete', path: '/' + pathName + '/:fk' }, http: {verb: 'delete', path: '/' + pathName + '/:fk'},
accepts: { arg: 'fk', type: 'any', accepts: {arg: 'fk', type: 'any',
description: format('Foreign key for %s', relationName), description: format('Foreign key for %s', relationName),
required: true, required: true,
http: { source: 'path' }}, http: {source: 'path'}},
description: format('Delete a related item by id for %s.', relationName), description: format('Delete a related item by id for %s.', relationName),
accessType: 'WRITE', accessType: 'WRITE',
returns: [], returns: [],
@ -556,17 +556,17 @@ module.exports = function(registry) {
var updateByIdFunc = this.prototype['__updateById__' + relationName]; var updateByIdFunc = this.prototype['__updateById__' + relationName];
define('__updateById__' + relationName, { define('__updateById__' + relationName, {
isStatic: false, isStatic: false,
http: { verb: 'put', path: '/' + pathName + '/:fk' }, http: {verb: 'put', path: '/' + pathName + '/:fk'},
accepts: [ accepts: [
{ arg: 'fk', type: 'any', {arg: 'fk', type: 'any',
description: format('Foreign key for %s', relationName), description: format('Foreign key for %s', relationName),
required: true, required: true,
http: { source: 'path' }}, http: {source: 'path'}},
{ arg: 'data', type: 'object', model: toModelName, http: { source: 'body' }}, {arg: 'data', type: 'object', model: toModelName, http: {source: 'body'}},
], ],
description: format('Update a related item by id for %s.', relationName), description: format('Update a related item by id for %s.', relationName),
accessType: 'WRITE', accessType: 'WRITE',
returns: { arg: 'result', type: toModelName, root: true }, returns: {arg: 'result', type: toModelName, root: true},
}, updateByIdFunc); }, updateByIdFunc);
if (relation.modelThrough || relation.type === 'referencesMany') { if (relation.modelThrough || relation.type === 'referencesMany') {
@ -577,31 +577,31 @@ module.exports = function(registry) {
// Restrict: only hasManyThrough relation can have additional properties // Restrict: only hasManyThrough relation can have additional properties
accepts.push({ accepts.push({
arg: 'data', type: 'object', model: modelThrough.modelName, arg: 'data', type: 'object', model: modelThrough.modelName,
http: { source: 'body' }, http: {source: 'body'},
}); });
} }
var addFunc = this.prototype['__link__' + relationName]; var addFunc = this.prototype['__link__' + relationName];
define('__link__' + relationName, { define('__link__' + relationName, {
isStatic: false, isStatic: false,
http: { verb: 'put', path: '/' + pathName + '/rel/:fk' }, http: {verb: 'put', path: '/' + pathName + '/rel/:fk'},
accepts: [{ arg: 'fk', type: 'any', accepts: [{arg: 'fk', type: 'any',
description: format('Foreign key for %s', relationName), description: format('Foreign key for %s', relationName),
required: true, required: true,
http: { source: 'path' }}].concat(accepts), http: {source: 'path'}}].concat(accepts),
description: format('Add a related item by id for %s.', relationName), description: format('Add a related item by id for %s.', relationName),
accessType: 'WRITE', accessType: 'WRITE',
returns: { arg: relationName, type: modelThrough.modelName, root: true }, returns: {arg: relationName, type: modelThrough.modelName, root: true},
}, addFunc); }, addFunc);
var removeFunc = this.prototype['__unlink__' + relationName]; var removeFunc = this.prototype['__unlink__' + relationName];
define('__unlink__' + relationName, { define('__unlink__' + relationName, {
isStatic: false, isStatic: false,
http: { verb: 'delete', path: '/' + pathName + '/rel/:fk' }, http: {verb: 'delete', path: '/' + pathName + '/rel/:fk'},
accepts: { arg: 'fk', type: 'any', accepts: {arg: 'fk', type: 'any',
description: format('Foreign key for %s', relationName), description: format('Foreign key for %s', relationName),
required: true, required: true,
http: { source: 'path' }}, http: {source: 'path'}},
description: format('Remove the %s relation to an item by id.', relationName), description: format('Remove the %s relation to an item by id.', relationName),
accessType: 'WRITE', accessType: 'WRITE',
returns: [], returns: [],
@ -612,14 +612,14 @@ module.exports = function(registry) {
var existsFunc = this.prototype['__exists__' + relationName]; var existsFunc = this.prototype['__exists__' + relationName];
define('__exists__' + relationName, { define('__exists__' + relationName, {
isStatic: false, isStatic: false,
http: { verb: 'head', path: '/' + pathName + '/rel/:fk' }, http: {verb: 'head', path: '/' + pathName + '/rel/:fk'},
accepts: { arg: 'fk', type: 'any', accepts: {arg: 'fk', type: 'any',
description: format('Foreign key for %s', relationName), description: format('Foreign key for %s', relationName),
required: true, required: true,
http: { source: 'path' }}, http: {source: 'path'}},
description: format('Check the existence of %s relation to an item by id.', relationName), description: format('Check the existence of %s relation to an item by id.', relationName),
accessType: 'READ', accessType: 'READ',
returns: { arg: 'exists', type: 'boolean', root: true }, returns: {arg: 'exists', type: 'boolean', root: true},
rest: { rest: {
// After hook to map exists to 200/404 for HEAD // After hook to map exists to 200/404 for HEAD
after: function(ctx, cb) { after: function(ctx, cb) {
@ -658,37 +658,37 @@ module.exports = function(registry) {
define('__get__' + scopeName, { define('__get__' + scopeName, {
isStatic: isStatic, isStatic: isStatic,
http: { verb: 'get', path: '/' + pathName }, http: {verb: 'get', path: '/' + pathName},
accepts: { arg: 'filter', type: 'object' }, accepts: {arg: 'filter', type: 'object'},
description: format('Queries %s of %s.', scopeName, this.modelName), description: format('Queries %s of %s.', scopeName, this.modelName),
accessType: 'READ', accessType: 'READ',
returns: { arg: scopeName, type: [toModelName], root: true }, returns: {arg: scopeName, type: [toModelName], root: true},
}); });
define('__create__' + scopeName, { define('__create__' + scopeName, {
isStatic: isStatic, isStatic: isStatic,
http: { verb: 'post', path: '/' + pathName }, http: {verb: 'post', path: '/' + pathName},
accepts: { arg: 'data', type: 'object', model: toModelName, http: { source: 'body' }}, accepts: {arg: 'data', type: 'object', model: toModelName, http: {source: 'body'}},
description: format('Creates a new instance in %s of this model.', scopeName), description: format('Creates a new instance in %s of this model.', scopeName),
accessType: 'WRITE', accessType: 'WRITE',
returns: { arg: 'data', type: toModelName, root: true }, returns: {arg: 'data', type: toModelName, root: true},
}); });
define('__delete__' + scopeName, { define('__delete__' + scopeName, {
isStatic: isStatic, isStatic: isStatic,
http: { verb: 'delete', path: '/' + pathName }, http: {verb: 'delete', path: '/' + pathName},
description: format('Deletes all %s of this model.', scopeName), description: format('Deletes all %s of this model.', scopeName),
accessType: 'WRITE', accessType: 'WRITE',
}); });
define('__count__' + scopeName, { define('__count__' + scopeName, {
isStatic: isStatic, isStatic: isStatic,
http: { verb: 'get', path: '/' + pathName + '/count' }, http: {verb: 'get', path: '/' + pathName + '/count'},
accepts: { arg: 'where', type: 'object', accepts: {arg: 'where', type: 'object',
description: 'Criteria to match model instances' }, description: 'Criteria to match model instances'},
description: format('Counts %s of %s.', scopeName, this.modelName), description: format('Counts %s of %s.', scopeName, this.modelName),
accessType: 'READ', accessType: 'READ',
returns: { arg: 'count', type: 'number' }, returns: {arg: 'count', type: 'number'},
}); });
}; };
@ -732,7 +732,7 @@ module.exports = function(registry) {
httpPath = pathName + '/:' + paramName; httpPath = pathName + '/:' + paramName;
acceptArgs = [ acceptArgs = [
{ {
arg: paramName, type: 'any', http: { source: 'path' }, arg: paramName, type: 'any', http: {source: 'path'},
description: format('Foreign key for %s.', relation.name), description: format('Foreign key for %s.', relation.name),
required: true, required: true,
}, },

View File

@ -6,7 +6,7 @@
/*! /*!
* Module Dependencies. * Module Dependencies.
*/ */
'use strict';
var g = require('./globalize'); var g = require('./globalize');
var runtime = require('./runtime'); var runtime = require('./runtime');
var assert = require('assert'); var assert = require('assert');
@ -642,10 +642,10 @@ module.exports = function(registry) {
accepts: { accepts: {
arg: 'data', type: 'object', model: typeName, allowArray: true, arg: 'data', type: 'object', model: typeName, allowArray: true,
description: 'Model instance data', description: 'Model instance data',
http: { source: 'body' }, http: {source: 'body'},
}, },
returns: { arg: 'data', type: typeName, root: true }, returns: {arg: 'data', type: typeName, root: true},
http: { verb: 'post', path: '/' }, http: {verb: 'post', path: '/'},
}); });
var upsertOptions = { var upsertOptions = {
@ -654,15 +654,15 @@ module.exports = function(registry) {
'into the data source.', 'into the data source.',
accessType: 'WRITE', accessType: 'WRITE',
accepts: { accepts: {
arg: 'data', type: 'object', model: typeName, http: { source: 'body' }, arg: 'data', type: 'object', model: typeName, http: {source: 'body'},
description: 'Model instance data', description: 'Model instance data',
}, },
returns: { arg: 'data', type: typeName, root: true }, returns: {arg: 'data', type: typeName, root: true},
http: [{ verb: 'patch', path: '/' }], http: [{verb: 'patch', path: '/'}],
}; };
if (!options.replaceOnPUT) { if (!options.replaceOnPUT) {
upsertOptions.http.unshift({ verb: 'put', path: '/' }); upsertOptions.http.unshift({verb: 'put', path: '/'});
} }
setRemoting(PersistedModel, 'patchOrCreate', upsertOptions); setRemoting(PersistedModel, 'patchOrCreate', upsertOptions);
@ -671,15 +671,15 @@ module.exports = function(registry) {
accessType: 'WRITE', accessType: 'WRITE',
accepts: { accepts: {
arg: 'data', type: 'object', model: typeName, arg: 'data', type: 'object', model: typeName,
http: { source: 'body' }, http: {source: 'body'},
description: 'Model instance data', description: 'Model instance data',
}, },
returns: { arg: 'data', type: typeName, root: true }, returns: {arg: 'data', type: typeName, root: true},
http: [{ verb: 'post', path: '/replaceOrCreate' }], http: [{verb: 'post', path: '/replaceOrCreate'}],
}; };
if (options.replaceOnPUT) { if (options.replaceOnPUT) {
replaceOrCreateOptions.http.push({ verb: 'put', path: '/' }); replaceOrCreateOptions.http.push({verb: 'put', path: '/'});
} }
setRemoting(PersistedModel, 'replaceOrCreate', replaceOrCreateOptions); setRemoting(PersistedModel, 'replaceOrCreate', replaceOrCreateOptions);
@ -690,23 +690,23 @@ module.exports = function(registry) {
'the data source based on the where criteria.', 'the data source based on the where criteria.',
accessType: 'WRITE', accessType: 'WRITE',
accepts: [ accepts: [
{ arg: 'where', type: 'object', http: { source: 'query' }, {arg: 'where', type: 'object', http: {source: 'query'},
description: 'Criteria to match model instances' }, description: 'Criteria to match model instances'},
{ arg: 'data', type: 'object', model: typeName, http: { source: 'body' }, {arg: 'data', type: 'object', model: typeName, http: {source: 'body'},
description: 'An object of model property name/value pairs' }, description: 'An object of model property name/value pairs'},
], ],
returns: { arg: 'data', type: typeName, root: true }, returns: {arg: 'data', type: typeName, root: true},
http: { verb: 'post', path: '/upsertWithWhere' }, http: {verb: 'post', path: '/upsertWithWhere'},
}); });
setRemoting(PersistedModel, 'exists', { setRemoting(PersistedModel, 'exists', {
description: 'Check whether a model instance exists in the data source.', description: 'Check whether a model instance exists in the data source.',
accessType: 'READ', accessType: 'READ',
accepts: { arg: 'id', type: 'any', description: 'Model id', required: true }, accepts: {arg: 'id', type: 'any', description: 'Model id', required: true},
returns: { arg: 'exists', type: 'boolean' }, returns: {arg: 'exists', type: 'boolean'},
http: [ http: [
{ verb: 'get', path: '/:id/exists' }, {verb: 'get', path: '/:id/exists'},
{ verb: 'head', path: '/:id' }, {verb: 'head', path: '/:id'},
], ],
rest: { rest: {
// After hook to map exists to 200/404 for HEAD // After hook to map exists to 200/404 for HEAD
@ -734,66 +734,65 @@ module.exports = function(registry) {
description: 'Find a model instance by {{id}} from the data source.', description: 'Find a model instance by {{id}} from the data source.',
accessType: 'READ', accessType: 'READ',
accepts: [ accepts: [
{ arg: 'id', type: 'any', description: 'Model id', required: true, {arg: 'id', type: 'any', description: 'Model id', required: true,
http: { source: 'path' }}, http: {source: 'path'}},
{ arg: 'filter', type: 'object', {arg: 'filter', type: 'object',
description: 'Filter defining fields and include' }, description: 'Filter defining fields and include'},
], ],
returns: { arg: 'data', type: typeName, root: true }, returns: {arg: 'data', type: typeName, root: true},
http: { verb: 'get', path: '/:id' }, http: {verb: 'get', path: '/:id'},
rest: { after: convertNullToNotFoundError }, rest: {after: convertNullToNotFoundError},
}); });
var replaceByIdOptions = { var replaceByIdOptions = {
description: 'Replace attributes for a model instance and persist it into the data source.', description: 'Replace attributes for a model instance and persist it into the data source.',
accessType: 'WRITE', accessType: 'WRITE',
accepts: [ accepts: [
{ arg: 'id', type: 'any', description: 'Model id', required: true, {arg: 'id', type: 'any', description: 'Model id', required: true,
http: { source: 'path' }}, http: {source: 'path'}},
{ arg: 'data', type: 'object', model: typeName, http: { source: 'body' }, description: {arg: 'data', type: 'object', model: typeName, http: {source: 'body'}, description:
'Model instance data' }, 'Model instance data'},
], ],
returns: { arg: 'data', type: typeName, root: true }, returns: {arg: 'data', type: typeName, root: true},
http: [{ verb: 'post', path: '/:id/replace' }], http: [{verb: 'post', path: '/:id/replace'}],
}; };
if (options.replaceOnPUT) { if (options.replaceOnPUT) {
replaceByIdOptions.http.push({ verb: 'put', path: '/:id' }); replaceByIdOptions.http.push({verb: 'put', path: '/:id'});
} }
setRemoting(PersistedModel, 'replaceById', replaceByIdOptions); setRemoting(PersistedModel, 'replaceById', replaceByIdOptions);
setRemoting(PersistedModel, 'find', { setRemoting(PersistedModel, 'find', {
description: 'Find all instances of the model matched by filter from the data source.', description: 'Find all instances of the model matched by filter from the data source.',
accessType: 'READ', accessType: 'READ',
accepts: { arg: 'filter', type: 'object', description: accepts: {arg: 'filter', type: 'object', description:
'Filter defining fields, where, include, order, offset, and limit' }, 'Filter defining fields, where, include, order, offset, and limit'},
returns: { arg: 'data', type: [typeName], root: true }, returns: {arg: 'data', type: [typeName], root: true},
http: { verb: 'get', path: '/' }, http: {verb: 'get', path: '/'},
}); });
setRemoting(PersistedModel, 'findOne', { setRemoting(PersistedModel, 'findOne', {
description: 'Find first instance of the model matched by filter from the data source.', description: 'Find first instance of the model matched by filter from the data source.',
accessType: 'READ', accessType: 'READ',
accepts: { arg: 'filter', type: 'object', description: accepts: {arg: 'filter', type: 'object', description:
'Filter defining fields, where, include, order, offset, and limit' }, 'Filter defining fields, where, include, order, offset, and limit'},
returns: { arg: 'data', type: typeName, root: true }, returns: {arg: 'data', type: typeName, root: true},
http: { verb: 'get', path: '/findOne' }, http: {verb: 'get', path: '/findOne'},
rest: { after: convertNullToNotFoundError }, rest: {after: convertNullToNotFoundError},
}); });
setRemoting(PersistedModel, 'destroyAll', { setRemoting(PersistedModel, 'destroyAll', {
description: 'Delete all matching records.', description: 'Delete all matching records.',
accessType: 'WRITE', accessType: 'WRITE',
accepts: { arg: 'where', type: 'object', description: 'filter.where object' }, accepts: {arg: 'where', type: 'object', description: 'filter.where object'},
returns: { returns: {
arg: 'count', arg: 'count',
type: 'object', type: 'object',
description: 'The number of instances deleted', description: 'The number of instances deleted',
root: true, root: true,
}, },
http: { verb: 'del', path: '/' }, http: {verb: 'del', path: '/'},
shared: false, shared: false,
}); });
@ -802,10 +801,10 @@ module.exports = function(registry) {
description: 'Update instances of the model matched by {{where}} from the data source.', description: 'Update instances of the model matched by {{where}} from the data source.',
accessType: 'WRITE', accessType: 'WRITE',
accepts: [ accepts: [
{ arg: 'where', type: 'object', http: { source: 'query' }, {arg: 'where', type: 'object', http: {source: 'query'},
description: 'Criteria to match model instances' }, description: 'Criteria to match model instances'},
{ arg: 'data', type: 'object', model: typeName, http: { source: 'body' }, {arg: 'data', type: 'object', model: typeName, http: {source: 'body'},
description: 'An object of model property name/value pairs' }, description: 'An object of model property name/value pairs'},
], ],
returns: { returns: {
arg: 'info', arg: 'info',
@ -818,25 +817,25 @@ module.exports = function(registry) {
}, },
root: true, root: true,
}, },
http: { verb: 'post', path: '/update' }, http: {verb: 'post', path: '/update'},
}); });
setRemoting(PersistedModel, 'deleteById', { setRemoting(PersistedModel, 'deleteById', {
aliases: ['destroyById', 'removeById'], aliases: ['destroyById', 'removeById'],
description: 'Delete a model instance by {{id}} from the data source.', description: 'Delete a model instance by {{id}} from the data source.',
accessType: 'WRITE', accessType: 'WRITE',
accepts: { arg: 'id', type: 'any', description: 'Model id', required: true, accepts: {arg: 'id', type: 'any', description: 'Model id', required: true,
http: { source: 'path' }}, http: {source: 'path'}},
http: { verb: 'del', path: '/:id' }, http: {verb: 'del', path: '/:id'},
returns: { arg: 'count', type: 'object', root: true }, returns: {arg: 'count', type: 'object', root: true},
}); });
setRemoting(PersistedModel, 'count', { setRemoting(PersistedModel, 'count', {
description: 'Count instances of the model matched by where from the data source.', description: 'Count instances of the model matched by where from the data source.',
accessType: 'READ', accessType: 'READ',
accepts: { arg: 'where', type: 'object', description: 'Criteria to match model instances' }, accepts: {arg: 'where', type: 'object', description: 'Criteria to match model instances'},
returns: { arg: 'count', type: 'number' }, returns: {arg: 'count', type: 'number'},
http: { verb: 'get', path: '/count' }, http: {verb: 'get', path: '/count'},
}); });
var updateAttributesOptions = { var updateAttributesOptions = {
@ -846,17 +845,17 @@ module.exports = function(registry) {
accessType: 'WRITE', accessType: 'WRITE',
accepts: { accepts: {
arg: 'data', type: 'object', model: typeName, arg: 'data', type: 'object', model: typeName,
http: { source: 'body' }, http: {source: 'body'},
description: 'An object of model property name/value pairs', description: 'An object of model property name/value pairs',
}, },
returns: { arg: 'data', type: typeName, root: true }, returns: {arg: 'data', type: typeName, root: true},
http: [{ verb: 'patch', path: '/' }], http: [{verb: 'patch', path: '/'}],
}; };
setRemoting(PersistedModel.prototype, 'patchAttributes', updateAttributesOptions); setRemoting(PersistedModel.prototype, 'patchAttributes', updateAttributesOptions);
if (!options.replaceOnPUT) { if (!options.replaceOnPUT) {
updateAttributesOptions.http.unshift({ verb: 'put', path: '/' }); updateAttributesOptions.http.unshift({verb: 'put', path: '/'});
} }
if (options.trackChanges || options.enableRemoteReplication) { if (options.trackChanges || options.enableRemoteReplication) {
@ -864,12 +863,12 @@ module.exports = function(registry) {
description: 'Get a set of deltas and conflicts since the given checkpoint.', description: 'Get a set of deltas and conflicts since the given checkpoint.',
accessType: 'READ', accessType: 'READ',
accepts: [ accepts: [
{ arg: 'since', type: 'number', description: 'Find deltas since this checkpoint' }, {arg: 'since', type: 'number', description: 'Find deltas since this checkpoint'},
{ arg: 'remoteChanges', type: 'array', description: 'an array of change objects', {arg: 'remoteChanges', type: 'array', description: 'an array of change objects',
http: { source: 'body' }}, http: {source: 'body'}},
], ],
returns: { arg: 'result', type: 'object', root: true }, returns: {arg: 'result', type: 'object', root: true},
http: { verb: 'post', path: '/diff' }, http: {verb: 'post', path: '/diff'},
}); });
setRemoting(PersistedModel, 'changes', { setRemoting(PersistedModel, 'changes', {
@ -877,13 +876,13 @@ module.exports = function(registry) {
'Provide a filter object to reduce the number of results returned.', 'Provide a filter object to reduce the number of results returned.',
accessType: 'READ', accessType: 'READ',
accepts: [ accepts: [
{ arg: 'since', type: 'number', description: {arg: 'since', type: 'number', description:
'Only return changes since this checkpoint' }, 'Only return changes since this checkpoint'},
{ arg: 'filter', type: 'object', description: {arg: 'filter', type: 'object', description:
'Only include changes that match this filter' }, 'Only include changes that match this filter'},
], ],
returns: { arg: 'changes', type: 'array', root: true }, returns: {arg: 'changes', type: 'array', root: true},
http: { verb: 'get', path: '/changes' }, http: {verb: 'get', path: '/changes'},
}); });
setRemoting(PersistedModel, 'checkpoint', { setRemoting(PersistedModel, 'checkpoint', {
@ -893,15 +892,15 @@ module.exports = function(registry) {
// We need to allow this method for users that don't have full // We need to allow this method for users that don't have full
// WRITE permissions. // WRITE permissions.
accessType: 'REPLICATE', accessType: 'REPLICATE',
returns: { arg: 'checkpoint', type: 'object', root: true }, returns: {arg: 'checkpoint', type: 'object', root: true},
http: { verb: 'post', path: '/checkpoint' }, http: {verb: 'post', path: '/checkpoint'},
}); });
setRemoting(PersistedModel, 'currentCheckpoint', { setRemoting(PersistedModel, 'currentCheckpoint', {
description: 'Get the current checkpoint.', description: 'Get the current checkpoint.',
accessType: 'READ', accessType: 'READ',
returns: { arg: 'checkpoint', type: 'object', root: true }, returns: {arg: 'checkpoint', type: 'object', root: true},
http: { verb: 'get', path: '/checkpoint' }, http: {verb: 'get', path: '/checkpoint'},
}); });
setRemoting(PersistedModel, 'createUpdates', { setRemoting(PersistedModel, 'createUpdates', {
@ -910,27 +909,27 @@ module.exports = function(registry) {
// It is called by the replication algorithm to compile a list // It is called by the replication algorithm to compile a list
// of changes to apply on the target. // of changes to apply on the target.
accessType: 'READ', accessType: 'READ',
accepts: { arg: 'deltas', type: 'array', http: { source: 'body' }}, accepts: {arg: 'deltas', type: 'array', http: {source: 'body'}},
returns: { arg: 'updates', type: 'array', root: true }, returns: {arg: 'updates', type: 'array', root: true},
http: { verb: 'post', path: '/create-updates' }, http: {verb: 'post', path: '/create-updates'},
}); });
setRemoting(PersistedModel, 'bulkUpdate', { setRemoting(PersistedModel, 'bulkUpdate', {
description: 'Run multiple updates at once. Note: this is not atomic.', description: 'Run multiple updates at once. Note: this is not atomic.',
accessType: 'WRITE', accessType: 'WRITE',
accepts: { arg: 'updates', type: 'array' }, accepts: {arg: 'updates', type: 'array'},
http: { verb: 'post', path: '/bulk-update' }, http: {verb: 'post', path: '/bulk-update'},
}); });
setRemoting(PersistedModel, 'findLastChange', { setRemoting(PersistedModel, 'findLastChange', {
description: 'Get the most recent change record for this instance.', description: 'Get the most recent change record for this instance.',
accessType: 'READ', accessType: 'READ',
accepts: { accepts: {
arg: 'id', type: 'any', required: true, http: { source: 'path' }, arg: 'id', type: 'any', required: true, http: {source: 'path'},
description: 'Model id', description: 'Model id',
}, },
returns: { arg: 'result', type: this.Change.modelName, root: true }, 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', { setRemoting(PersistedModel, 'updateLastChange', {
@ -940,16 +939,16 @@ module.exports = function(registry) {
accessType: 'WRITE', accessType: 'WRITE',
accepts: [ accepts: [
{ {
arg: 'id', type: 'any', required: true, http: { source: 'path' }, arg: 'id', type: 'any', required: true, http: {source: 'path'},
description: 'Model id', description: 'Model id',
}, },
{ {
arg: 'data', type: 'object', model: typeName, http: { source: 'body' }, arg: 'data', type: 'object', model: typeName, 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 }, returns: {arg: 'result', type: this.Change.modelName, root: true},
http: { verb: 'put', path: '/:id/changes/last' }, http: {verb: 'put', path: '/:id/changes/last'},
}); });
} }
@ -957,8 +956,8 @@ module.exports = function(registry) {
description: 'Create a change stream.', description: 'Create a change stream.',
accessType: 'READ', accessType: 'READ',
http: [ http: [
{ verb: 'post', path: '/change-stream' }, {verb: 'post', path: '/change-stream'},
{ verb: 'get', path: '/change-stream' }, {verb: 'get', path: '/change-stream'},
], ],
accepts: { accepts: {
arg: 'options', arg: 'options',
@ -1021,8 +1020,8 @@ module.exports = function(registry) {
filter.fields[idName] = true; filter.fields[idName] = true;
// TODO(ritch) this whole thing could be optimized a bit more // TODO(ritch) this whole thing could be optimized a bit more
Change.find({ where: { Change.find({where: {
checkpoint: { gte: since }, checkpoint: {gte: since},
modelName: this.modelName, modelName: this.modelName,
}}, function(err, changes) { }}, function(err, changes) {
if (err) return callback(err); if (err) return callback(err);
@ -1030,7 +1029,7 @@ module.exports = function(registry) {
var ids = changes.map(function(change) { var ids = changes.map(function(change) {
return change.getModelId(); return change.getModelId();
}); });
filter.where[idName] = { inq: ids }; filter.where[idName] = {inq: ids};
model.find(filter, function(err, models) { model.find(filter, function(err, models) {
if (err) return callback(err); if (err) return callback(err);
var modelIds = models.map(function(m) { var modelIds = models.map(function(m) {
@ -1097,7 +1096,7 @@ module.exports = function(registry) {
} }
if (typeof since !== 'object') { if (typeof since !== 'object') {
since = { source: since, target: since }; since = {source: since, target: since};
} }
if (typeof options === 'function') { if (typeof options === 'function') {
@ -1268,7 +1267,7 @@ module.exports = function(registry) {
} }
if (callback) { if (callback) {
var newCheckpoints = { source: newSourceCp, target: newTargetCp }; var newCheckpoints = {source: newSourceCp, target: newTargetCp};
callback(null, conflicts, newCheckpoints, updates); callback(null, conflicts, newCheckpoints, updates);
} }
} }
@ -1291,7 +1290,7 @@ module.exports = function(registry) {
deltas.forEach(function(change) { deltas.forEach(function(change) {
change = new Change(change); change = new Change(change);
var type = change.type(); var type = change.type();
var update = { type: type, change: change }; var update = {type: type, change: change};
switch (type) { switch (type) {
case Change.CREATE: case Change.CREATE:
case Change.UPDATE: case Change.UPDATE:
@ -1383,7 +1382,7 @@ module.exports = function(registry) {
if (conflicts.length) { if (conflicts.length) {
err = new Error(g.f('Conflict')); err = new Error(g.f('Conflict'));
err.statusCode = 409; err.statusCode = 409;
err.details = { conflicts: conflicts }; err.details = {conflicts: conflicts};
return callback(err); return callback(err);
} }
callback(); callback();
@ -1395,8 +1394,8 @@ module.exports = function(registry) {
var idName = Model.dataSource.idName(Model.modelName); var idName = Model.dataSource.idName(Model.modelName);
var affectedIds = updates.map(function(u) { return u.change.modelId; }); var affectedIds = updates.map(function(u) { return u.change.modelId; });
var whereAffected = {}; var whereAffected = {};
whereAffected[idName] = { inq: affectedIds }; whereAffected[idName] = {inq: affectedIds};
Model.find({ where: whereAffected }, function(err, affectedList) { Model.find({where: whereAffected}, function(err, affectedList) {
if (err) return callback(err); if (err) return callback(err);
var dataLookup = {}; var dataLookup = {};
affectedList.forEach(function(it) { affectedList.forEach(function(it) {
@ -1742,7 +1741,7 @@ module.exports = function(registry) {
PersistedModel.findLastChange = function(id, cb) { PersistedModel.findLastChange = function(id, cb) {
var Change = this.getChangeModel(); var Change = this.getChangeModel();
Change.findOne({ where: { modelId: id }}, cb); Change.findOne({where: {modelId: id}}, cb);
}; };
PersistedModel.updateLastChange = function(id, data, cb) { PersistedModel.updateLastChange = function(id, data, cb) {
@ -1778,7 +1777,7 @@ module.exports = function(registry) {
var idName = this.getIdName(); var idName = this.getIdName();
var Model = this; var Model = this;
var changes = new PassThrough({ objectMode: true }); var changes = new PassThrough({objectMode: true});
var writeable = true; var writeable = true;
changes.destroy = function() { changes.destroy = function() {

View File

@ -3,6 +3,7 @@
// This file is licensed under the MIT License. // This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT // License text available at https://opensource.org/licenses/MIT
'use strict';
var g = require('./globalize'); var g = require('./globalize');
var assert = require('assert'); var assert = require('assert');
var extend = require('util')._extend; var extend = require('util')._extend;

View File

@ -9,6 +9,7 @@
* @private * @private
*/ */
'use strict';
var runtime = exports; var runtime = exports;
/** /**

View File

@ -3,6 +3,7 @@
// This file is licensed under the MIT License. // This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT // License text available at https://opensource.org/licenses/MIT
'use strict';
var g = require('./globalize'); var g = require('./globalize');
var assert = require('assert'); var assert = require('assert');
var express = require('express'); var express = require('express');
@ -11,7 +12,7 @@ var mergePhaseNameLists = require('loopback-phase').mergePhaseNameLists;
var debug = require('debug')('loopback:app'); var debug = require('debug')('loopback:app');
var stableSortInPlace = require('stable').inplace; var stableSortInPlace = require('stable').inplace;
var BUILTIN_MIDDLEWARE = { builtin: true }; var BUILTIN_MIDDLEWARE = {builtin: true};
var proto = {}; var proto = {};

View File

@ -3,6 +3,7 @@
// This file is licensed under the MIT License. // This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT // License text available at https://opensource.org/licenses/MIT
'use strict';
exports.createPromiseCallback = createPromiseCallback; exports.createPromiseCallback = createPromiseCallback;
var Promise = require('bluebird'); var Promise = require('bluebird');

View File

@ -67,7 +67,7 @@
"chai": "^3.5.0", "chai": "^3.5.0",
"cookie-parser": "^1.3.4", "cookie-parser": "^1.3.4",
"es5-shim": "^4.1.0", "es5-shim": "^4.1.0",
"eslint-config-loopback": "^1.0.0", "eslint-config-loopback": "^5.0.0",
"express-session": "^1.14.0", "express-session": "^1.14.0",
"grunt": "^1.0.1", "grunt": "^1.0.1",
"grunt-browserify": "^5.0.0", "grunt-browserify": "^5.0.0",

View File

@ -3,6 +3,7 @@
// This file is licensed under the MIT License. // This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT // License text available at https://opensource.org/licenses/MIT
'use strict';
var g = require('../../lib/globalize'); var g = require('../../lib/globalize');
module.exports = function() { module.exports = function() {

View File

@ -3,6 +3,7 @@
// This file is licensed under the MIT License. // This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT // License text available at https://opensource.org/licenses/MIT
'use strict';
module.exports = function(options) { module.exports = function(options) {
throw new Error('loopback.errorHandler is no longer available.' + throw new Error('loopback.errorHandler is no longer available.' +
' Please use the module "strong-error-handler" instead.'); ' Please use the module "strong-error-handler" instead.');

View File

@ -3,6 +3,7 @@
// This file is licensed under the MIT License. // This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT // License text available at https://opensource.org/licenses/MIT
'use strict';
var favicon = require('serve-favicon'); var favicon = require('serve-favicon');
var path = require('path'); var path = require('path');

View File

@ -7,6 +7,7 @@
* Module dependencies. * Module dependencies.
*/ */
'use strict';
var g = require('../../lib/globalize'); var g = require('../../lib/globalize');
var loopback = require('../../lib/loopback'); var loopback = require('../../lib/loopback');
var async = require('async'); var async = require('async');
@ -49,7 +50,7 @@ function rest() {
if (app.isAuthEnabled) { if (app.isAuthEnabled) {
var AccessToken = registry.getModelByType('AccessToken'); var AccessToken = registry.getModelByType('AccessToken');
handlers.push(loopback.token({ model: AccessToken, app: app })); handlers.push(loopback.token({model: AccessToken, app: app}));
} }
handlers.push(function(req, res, next) { handlers.push(function(req, res, next) {

View File

@ -13,4 +13,5 @@
* for the full list of available options. * for the full list of available options.
* @header loopback.static(root, [options]) * @header loopback.static(root, [options])
*/ */
'use strict';
module.exports = require('express').static; module.exports = require('express').static;

View File

@ -7,6 +7,7 @@
* Export the middleware. * Export the middleware.
*/ */
'use strict';
module.exports = status; module.exports = status;
/** /**

View File

@ -7,6 +7,7 @@
* Module dependencies. * Module dependencies.
*/ */
'use strict';
var loopback = require('../../lib/loopback'); var loopback = require('../../lib/loopback');
var assert = require('assert'); var assert = require('assert');
var debug = require('debug')('loopback:middleware:token'); var debug = require('debug')('loopback:middleware:token');

View File

@ -8,6 +8,7 @@
* See discussion in Connect pull request #954 for more details * See discussion in Connect pull request #954 for more details
* https://github.com/senchalabs/connect/pull/954. * https://github.com/senchalabs/connect/pull/954.
*/ */
'use strict';
module.exports = urlNotFound; module.exports = urlNotFound;
/** /**

View File

@ -3,14 +3,15 @@
// This file is licensed under the MIT License. // This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT // License text available at https://opensource.org/licenses/MIT
'use strict';
var loopback = require('../'); var loopback = require('../');
var lt = require('./helpers/loopback-testing-helper'); var lt = require('./helpers/loopback-testing-helper');
var path = require('path'); var path = require('path');
var ACCESS_CONTROL_APP = path.join(__dirname, 'fixtures', 'access-control'); var ACCESS_CONTROL_APP = path.join(__dirname, 'fixtures', 'access-control');
var app = require(path.join(ACCESS_CONTROL_APP, 'server/server.js')); var app = require(path.join(ACCESS_CONTROL_APP, 'server/server.js'));
var assert = require('assert'); var assert = require('assert');
var USER = { email: 'test@test.test', password: 'test' }; var USER = {email: 'test@test.test', password: 'test'};
var CURRENT_USER = { email: 'current@test.test', password: 'test' }; var CURRENT_USER = {email: 'current@test.test', password: 'test'};
var debug = require('debug')('loopback:test:access-control.integration'); var debug = require('debug')('loopback:test:access-control.integration');
describe('access control - integration', function() { describe('access control - integration', function() {
@ -146,7 +147,7 @@ describe('access control - integration', function() {
}); });
describe('/banks', function() { describe('/banks', function() {
var SPECIAL_USER = { email: 'special@test.test', password: 'test' }; var SPECIAL_USER = {email: 'special@test.test', password: 'test'};
// define dynamic role that would only grant access when the authenticated user's email is equal to // define dynamic role that would only grant access when the authenticated user's email is equal to
// SPECIAL_USER's email // SPECIAL_USER's email

View File

@ -3,15 +3,20 @@
// This file is licensed under the MIT License. // This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT // License text available at https://opensource.org/licenses/MIT
'use strict';
var assert = require('assert');
var expect = require('chai').expect;
var cookieParser = require('cookie-parser'); var cookieParser = require('cookie-parser');
var LoopBackContext = require('loopback-context'); var LoopBackContext = require('loopback-context');
var contextMiddleware = require('loopback-context').perRequest; var contextMiddleware = require('loopback-context').perRequest;
var loopback = require('../'); var loopback = require('../');
var extend = require('util')._extend; var extend = require('util')._extend;
var session = require('express-session'); var session = require('express-session');
var request = require('supertest');
var app = loopback();
var Token = loopback.AccessToken.extend('MyToken'); var Token = loopback.AccessToken.extend('MyToken');
var ds = loopback.createDataSource({ connector: loopback.Memory }); var ds = loopback.createDataSource({connector: loopback.Memory});
Token.attachTo(ds); Token.attachTo(ds);
var ACL = loopback.ACL; var ACL = loopback.ACL;
@ -50,7 +55,7 @@ describe('loopback.token(options)', function() {
var tokenId = this.token.id; var tokenId = this.token.id;
var app = createTestApp( var app = createTestApp(
this.token, this.token,
{ token: { searchDefaultTokenKeys: false }}, {token: {searchDefaultTokenKeys: false}},
done); done);
var agent = request.agent(app); var agent = request.agent(app);
@ -158,7 +163,7 @@ describe('loopback.token(options)', function() {
.set('authorization', id) .set('authorization', id)
.end(function(err, res) { .end(function(err, res) {
assert(!err); assert(!err);
assert.deepEqual(res.body, { userId: userId }); assert.deepEqual(res.body, {userId: userId});
done(); done();
}); });
@ -174,7 +179,7 @@ describe('loopback.token(options)', function() {
.set('authorization', id) .set('authorization', id)
.end(function(err, res) { .end(function(err, res) {
assert(!err); assert(!err);
assert.deepEqual(res.body, { userId: userId, state: 1 }); assert.deepEqual(res.body, {userId: userId, state: 1});
done(); done();
}); });
@ -190,20 +195,20 @@ describe('loopback.token(options)', function() {
.set('authorization', id) .set('authorization', id)
.end(function(err, res) { .end(function(err, res) {
assert(!err); assert(!err);
assert.deepEqual(res.body, { userId: userId, state: 1 }); assert.deepEqual(res.body, {userId: userId, state: 1});
done(); done();
}); });
}); });
it('should skip when req.token is already present', function(done) { it('should skip when req.token is already present', function(done) {
var tokenStub = { id: 'stub id' }; var tokenStub = {id: 'stub id'};
app.use(function(req, res, next) { app.use(function(req, res, next) {
req.accessToken = tokenStub; req.accessToken = tokenStub;
next(); next();
}); });
app.use(loopback.token({ model: Token })); app.use(loopback.token({model: Token}));
app.get('/', function(req, res, next) { app.get('/', function(req, res, next) {
res.send(req.accessToken); res.send(req.accessToken);
}); });
@ -223,13 +228,13 @@ describe('loopback.token(options)', function() {
describe('loading multiple instances of token middleware', function() { describe('loading multiple instances of token middleware', function() {
it('should skip when req.token is already present and no further options are set', it('should skip when req.token is already present and no further options are set',
function(done) { function(done) {
var tokenStub = { id: 'stub id' }; var tokenStub = {id: 'stub id'};
app.use(function(req, res, next) { app.use(function(req, res, next) {
req.accessToken = tokenStub; req.accessToken = tokenStub;
next(); next();
}); });
app.use(loopback.token({ model: Token })); app.use(loopback.token({model: Token}));
app.get('/', function(req, res, next) { app.get('/', function(req, res, next) {
res.send(req.accessToken); res.send(req.accessToken);
}); });
@ -249,7 +254,7 @@ describe('loopback.token(options)', function() {
it('should not overwrite valid existing token (has "id" property) ' + it('should not overwrite valid existing token (has "id" property) ' +
' when overwriteExistingToken is falsy', ' when overwriteExistingToken is falsy',
function(done) { function(done) {
var tokenStub = { id: 'stub id' }; var tokenStub = {id: 'stub id'};
app.use(function(req, res, next) { app.use(function(req, res, next) {
req.accessToken = tokenStub; req.accessToken = tokenStub;
@ -279,7 +284,7 @@ describe('loopback.token(options)', function() {
' when enableDoubkecheck is true', ' when enableDoubkecheck is true',
function(done) { function(done) {
var token = this.token; var token = this.token;
var app = loopback();
app.use(function(req, res, next) { app.use(function(req, res, next) {
req.accessToken = null; req.accessToken = null;
next(); next();
@ -313,8 +318,8 @@ describe('loopback.token(options)', function() {
'and overwriteExistingToken options are truthy', 'and overwriteExistingToken options are truthy',
function(done) { function(done) {
var token = this.token; var token = this.token;
var tokenStub = { id: 'stub id' }; var tokenStub = {id: 'stub id'};
var app = loopback();
app.use(function(req, res, next) { app.use(function(req, res, next) {
req.accessToken = tokenStub; req.accessToken = tokenStub;
@ -385,7 +390,7 @@ describe('AccessToken', function() {
// Overwrite User settings - enable eternal tokens // Overwrite User settings - enable eternal tokens
Token.app.models.User.settings.allowEternalTokens = true; Token.app.models.User.settings.allowEternalTokens = true;
Token.create({ userId: '123', ttl: -1 }, function(err, token) { Token.create({userId: '123', ttl: -1}, function(err, token) {
if (err) return done(err); if (err) return done(err);
token.validate(function(err, isValid) { token.validate(function(err, isValid) {
if (err) return done(err); if (err) return done(err);
@ -402,7 +407,7 @@ describe('AccessToken', function() {
it('supports two-arg variant with no options', function(done) { it('supports two-arg variant with no options', function(done) {
var expectedTokenId = this.token.id; var expectedTokenId = this.token.id;
var req = mockRequest({ var req = mockRequest({
headers: { 'authorization': expectedTokenId }, headers: {'authorization': expectedTokenId},
}); });
Token.findForRequest(req, function(err, token) { Token.findForRequest(req, function(err, token) {
@ -435,7 +440,7 @@ describe('app.enableAuth()', function() {
var app; var app;
beforeEach(function setupAuthWithModels() { beforeEach(function setupAuthWithModels() {
app = loopback(); app = loopback();
app.enableAuth({ dataSource: ds }); app.enableAuth({dataSource: ds});
}); });
beforeEach(createTestingToken); beforeEach(createTestingToken);
@ -458,7 +463,7 @@ describe('app.enableAuth()', function() {
}); });
it('prevent remote call with app setting status on denied ACL', function(done) { it('prevent remote call with app setting status on denied ACL', function(done) {
createTestAppAndRequest(this.token, { app: { aclErrorStatus: 403 }}, done) createTestAppAndRequest(this.token, {app: {aclErrorStatus: 403}}, done)
.del('/tests/123') .del('/tests/123')
.expect(403) .expect(403)
.set('authorization', this.token.id) .set('authorization', this.token.id)
@ -476,7 +481,7 @@ describe('app.enableAuth()', function() {
}); });
it('prevent remote call with app setting status on denied ACL', function(done) { it('prevent remote call with app setting status on denied ACL', function(done) {
createTestAppAndRequest(this.token, { model: { aclErrorStatus: 404 }}, done) createTestAppAndRequest(this.token, {model: {aclErrorStatus: 404}}, done)
.del('/tests/123') .del('/tests/123')
.expect(404) .expect(404)
.set('authorization', this.token.id) .set('authorization', this.token.id)
@ -512,22 +517,22 @@ describe('app.enableAuth()', function() {
}); });
it('stores token in the context', function(done) { it('stores token in the context', function(done) {
var TestModel = loopback.createModel('TestModel', { base: 'Model' }); var TestModel = loopback.createModel('TestModel', {base: 'Model'});
TestModel.getToken = function(cb) { TestModel.getToken = function(cb) {
var ctx = LoopBackContext.getCurrentContext(); var ctx = LoopBackContext.getCurrentContext();
cb(null, ctx && ctx.get('accessToken') || null); cb(null, ctx && ctx.get('accessToken') || null);
}; };
TestModel.remoteMethod('getToken', { TestModel.remoteMethod('getToken', {
returns: { arg: 'token', type: 'object' }, returns: {arg: 'token', type: 'object'},
http: { verb: 'GET', path: '/token' }, http: {verb: 'GET', path: '/token'},
}); });
var app = loopback(); var app = loopback();
app.model(TestModel, { dataSource: null }); app.model(TestModel, {dataSource: null});
app.enableAuth(); app.enableAuth();
app.use(contextMiddleware()); app.use(contextMiddleware());
app.use(loopback.token({ model: Token })); app.use(loopback.token({model: Token}));
app.use(loopback.rest()); app.use(loopback.rest());
var token = this.token; var token = this.token;
@ -556,7 +561,7 @@ describe('app.enableAuth()', function() {
saveUninitialized: true, saveUninitialized: true,
resave: true, resave: true,
})); }));
app.use(loopback.token({ model: Token })); app.use(loopback.token({model: Token}));
app.get('/', function(req, res) { res.send('OK'); }); app.get('/', function(req, res) { res.send('OK'); });
app.use(loopback.rest()); app.use(loopback.rest());
@ -572,7 +577,7 @@ describe('app.enableAuth()', function() {
function createTestingToken(done) { function createTestingToken(done) {
var test = this; var test = this;
Token.create({ userId: '123' }, function(err, token) { Token.create({userId: '123'}, function(err, token) {
if (err) return done(err); if (err) return done(err);
test.token = token; test.token = token;
@ -602,10 +607,10 @@ function createTestApp(testToken, settings, done) {
app.use(cookieParser('secret')); app.use(cookieParser('secret'));
app.use(loopback.token(tokenSettings)); app.use(loopback.token(tokenSettings));
app.set('remoting', { errorHandler: { debug: true, log: false }}); app.set('remoting', {errorHandler: {debug: true, log: false}});
app.get('/token', function(req, res) { app.get('/token', function(req, res) {
res.cookie('authorization', testToken.id, { signed: true }); res.cookie('authorization', testToken.id, {signed: true});
res.cookie('access_token', testToken.id, { signed: true }); res.cookie('access_token', testToken.id, {signed: true});
res.end(); res.end();
}); });
app.get('/', function(req, res) { app.get('/', function(req, res) {
@ -621,7 +626,7 @@ function createTestApp(testToken, settings, done) {
res.status(req.accessToken ? 200 : 401).end(); res.status(req.accessToken ? 200 : 401).end();
}); });
app.use('/users/:uid', function(req, res) { app.use('/users/:uid', function(req, res) {
var result = { userId: req.params.uid }; var result = {userId: req.params.uid};
if (req.query.state) { if (req.query.state) {
result.state = req.query.state; result.state = req.query.state;
} else if (req.url !== '/') { } else if (req.url !== '/') {
@ -661,14 +666,14 @@ function createTestApp(testToken, settings, done) {
} }
function givenLocalTokenModel() { function givenLocalTokenModel() {
var app = loopback({ localRegistry: true, loadBuiltinModels: true }); var app = loopback({localRegistry: true, loadBuiltinModels: true});
app.dataSource('db', { connector: 'memory' }); app.dataSource('db', {connector: 'memory'});
var User = app.registry.getModel('User'); var User = app.registry.getModel('User');
app.model(User, { dataSource: 'db' }); app.model(User, {dataSource: 'db'});
var Token = app.registry.getModel('AccessToken'); var Token = app.registry.getModel('AccessToken');
app.model(Token, { dataSource: 'db' }); app.model(Token, {dataSource: 'db'});
return Token; return Token;
} }

View File

@ -3,15 +3,20 @@
// This file is licensed under the MIT License. // This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT // License text available at https://opensource.org/licenses/MIT
'use strict';
var assert = require('assert'); var assert = require('assert');
var loopback = require('../index'); var loopback = require('../index');
var Scope = loopback.Scope; var Scope = loopback.Scope;
var ACL = loopback.ACL; var ACL = loopback.ACL;
var request = require('supertest');
var Role = loopback.Role; var Role = loopback.Role;
var RoleMapping = loopback.RoleMapping; var RoleMapping = loopback.RoleMapping;
var User = loopback.User; var User = loopback.User;
var testModel; var testModel;
// Speed up the password hashing algorithm for tests
User.settings.saltWorkFactor = 4;
function checkResult(err, result) { function checkResult(err, result) {
// console.log(err, result); // console.log(err, result);
assert(!err); assert(!err);
@ -19,12 +24,12 @@ function checkResult(err, result) {
var ds = null; var ds = null;
before(function() { before(function() {
ds = loopback.createDataSource({ connector: loopback.Memory }); ds = loopback.createDataSource({connector: loopback.Memory});
}); });
describe('security scopes', function() { describe('security scopes', function() {
beforeEach(function() { beforeEach(function() {
var ds = this.ds = loopback.createDataSource({ connector: loopback.Memory }); var ds = this.ds = loopback.createDataSource({connector: loopback.Memory});
testModel = loopback.PersistedModel.extend('testModel'); testModel = loopback.PersistedModel.extend('testModel');
ACL.attachTo(ds); ACL.attachTo(ds);
Role.attachTo(ds); Role.attachTo(ds);
@ -35,7 +40,7 @@ describe('security scopes', function() {
}); });
it('should allow access to models for the given scope by wildcard', function() { it('should allow access to models for the given scope by wildcard', function() {
Scope.create({ name: 'userScope', description: 'access user information' }, Scope.create({name: 'userScope', description: 'access user information'},
function(err, scope) { function(err, scope) {
ACL.create({ ACL.create({
principalType: ACL.SCOPE, principalId: scope.id, principalType: ACL.SCOPE, principalId: scope.id,
@ -50,14 +55,14 @@ describe('security scopes', function() {
}); });
it('should allow access to models for the given scope', function() { it('should allow access to models for the given scope', function() {
Scope.create({ name: 'testModelScope', description: 'access testModel information' }, Scope.create({name: 'testModelScope', description: 'access testModel information'},
function(err, scope) { function(err, scope) {
ACL.create({ ACL.create({
principalType: ACL.SCOPE, principalId: scope.id, principalType: ACL.SCOPE, principalId: scope.id,
model: 'testModel', property: 'name', model: 'testModel', property: 'name',
accessType: ACL.READ, permission: ACL.ALLOW, accessType: ACL.READ, permission: ACL.ALLOW,
}, function(err, resource) { }, function(err, resource) {
ACL.create({ principalType: ACL.SCOPE, principalId: scope.id, ACL.create({principalType: ACL.SCOPE, principalId: scope.id,
model: 'testModel', property: 'name', model: 'testModel', property: 'name',
accessType: ACL.WRITE, permission: ACL.DENY, accessType: ACL.WRITE, permission: ACL.DENY,
}, function(err, resource) { }, function(err, resource) {
@ -117,11 +122,11 @@ describe('security ACLs', function() {
acls = acls.map(function(a) { return new ACL(a); }); acls = acls.map(function(a) { return new ACL(a); });
var perm = ACL.resolvePermission(acls, req); var perm = ACL.resolvePermission(acls, req);
assert.deepEqual(perm, { model: 'account', assert.deepEqual(perm, {model: 'account',
property: 'find', property: 'find',
accessType: 'WRITE', accessType: 'WRITE',
permission: 'ALLOW', permission: 'ALLOW',
methodNames: [] }); methodNames: []});
}); });
it('should allow access to models for the given principal by wildcard', function() { it('should allow access to models for the given principal by wildcard', function() {
@ -197,16 +202,16 @@ describe('security ACLs', function() {
name: { name: {
type: String, type: String,
acls: [ acls: [
{ principalType: ACL.USER, principalId: 'u001', {principalType: ACL.USER, principalId: 'u001',
accessType: ACL.WRITE, permission: ACL.DENY }, accessType: ACL.WRITE, permission: ACL.DENY},
{ principalType: ACL.USER, principalId: 'u001', {principalType: ACL.USER, principalId: 'u001',
accessType: ACL.ALL, permission: ACL.ALLOW }, accessType: ACL.ALL, permission: ACL.ALLOW},
], ],
}, },
}, { }, {
acls: [ acls: [
{ principalType: ACL.USER, principalId: 'u001', {principalType: ACL.USER, principalId: 'u001',
accessType: ACL.ALL, permission: ACL.ALLOW }, accessType: ACL.ALL, permission: ACL.ALLOW},
], ],
}); });
@ -231,20 +236,20 @@ describe('security ACLs', function() {
name: { name: {
type: String, type: String,
acls: [ acls: [
{ principalType: ACL.USER, principalId: 'u001', {principalType: ACL.USER, principalId: 'u001',
accessType: ACL.WRITE, permission: ACL.DENY }, accessType: ACL.WRITE, permission: ACL.DENY},
{ principalType: ACL.USER, principalId: 'u001', {principalType: ACL.USER, principalId: 'u001',
accessType: ACL.ALL, permission: ACL.ALLOW }, accessType: ACL.ALL, permission: ACL.ALLOW},
], ],
}, },
}, { }, {
acls: [ acls: [
{ principalType: ACL.USER, principalId: 'u001', {principalType: ACL.USER, principalId: 'u001',
accessType: ACL.ALL, permission: ACL.ALLOW }, accessType: ACL.ALL, permission: ACL.ALLOW},
{ principalType: ACL.USER, principalId: 'u002', {principalType: ACL.USER, principalId: 'u002',
accessType: ACL.EXECUTE, permission: ACL.ALLOW }, accessType: ACL.EXECUTE, permission: ACL.ALLOW},
{ principalType: ACL.USER, principalId: 'u003', {principalType: ACL.USER, principalId: 'u003',
accessType: ACL.EXECUTE, permission: ACL.DENY }, accessType: ACL.EXECUTE, permission: ACL.DENY},
], ],
}); });
@ -285,20 +290,20 @@ describe('security ACLs', function() {
name: { name: {
type: String, type: String,
acls: [ acls: [
{ principalType: ACL.USER, principalId: 'u001', {principalType: ACL.USER, principalId: 'u001',
accessType: ACL.WRITE, permission: ACL.DENY }, accessType: ACL.WRITE, permission: ACL.DENY},
{ principalType: ACL.USER, principalId: 'u001', {principalType: ACL.USER, principalId: 'u001',
accessType: ACL.ALL, permission: ACL.ALLOW }, accessType: ACL.ALL, permission: ACL.ALLOW},
], ],
}, },
}, { }, {
acls: [ acls: [
{ principalType: ACL.USER, principalId: 'u001', property: 'name', {principalType: ACL.USER, principalId: 'u001', property: 'name',
accessType: ACL.ALL, permission: ACL.ALLOW }, accessType: ACL.ALL, permission: ACL.ALLOW},
{ principalType: ACL.USER, principalId: 'u002', property: 'findOne', {principalType: ACL.USER, principalId: 'u002', property: 'findOne',
accessType: ACL.ALL, permission: ACL.ALLOW }, accessType: ACL.ALL, permission: ACL.ALLOW},
{ principalType: ACL.USER, principalId: 'u003', property: ['findOne', 'findById'], {principalType: ACL.USER, principalId: 'u003', property: ['findOne', 'findById'],
accessType: ACL.ALL, permission: ACL.ALLOW }, accessType: ACL.ALL, permission: ACL.ALLOW},
], ],
}); });
@ -318,7 +323,7 @@ describe('security ACLs', function() {
var log = function() {}; var log = function() {};
// Create // Create
User.create({ name: 'Raymond', email: 'x@y.com', password: 'foobar' }, function(err, user) { User.create({name: 'Raymond', email: 'x@y.com', password: 'foobar'}, function(err, user) {
log('User: ', user.toObject()); log('User: ', user.toObject());
var userId = user.id; var userId = user.id;
@ -328,16 +333,16 @@ describe('security ACLs', function() {
name: { name: {
type: String, type: String,
acls: [ acls: [
{ principalType: ACL.USER, principalId: userId, {principalType: ACL.USER, principalId: userId,
accessType: ACL.WRITE, permission: ACL.DENY }, accessType: ACL.WRITE, permission: ACL.DENY},
{ principalType: ACL.USER, principalId: userId, {principalType: ACL.USER, principalId: userId,
accessType: ACL.ALL, permission: ACL.ALLOW }, accessType: ACL.ALL, permission: ACL.ALLOW},
], ],
}, },
}, { }, {
acls: [ acls: [
{ principalType: ACL.USER, principalId: userId, {principalType: ACL.USER, principalId: userId,
accessType: ACL.ALL, permission: ACL.ALLOW }, accessType: ACL.ALL, permission: ACL.ALLOW},
], ],
defaultPermission: 'DENY', defaultPermission: 'DENY',
}); });
@ -349,10 +354,10 @@ describe('security ACLs', function() {
}, function(err, acl) { }, function(err, acl) {
log('ACL 1: ', acl.toObject()); log('ACL 1: ', acl.toObject());
Role.create({ name: 'MyRole' }, function(err, myRole) { Role.create({name: 'MyRole'}, function(err, myRole) {
log('Role: ', myRole.toObject()); log('Role: ', myRole.toObject());
myRole.principals.create({ principalType: RoleMapping.USER, principalId: userId }, myRole.principals.create({principalType: RoleMapping.USER, principalId: userId},
function(err, p) { function(err, p) {
log('Principal added to role: ', p.toObject()); log('Principal added to role: ', p.toObject());
@ -365,7 +370,7 @@ describe('security ACLs', function() {
ACL.checkAccessForContext({ ACL.checkAccessForContext({
principals: [ principals: [
{ type: ACL.USER, id: userId }, {type: ACL.USER, id: userId},
], ],
model: 'Customer', model: 'Customer',
property: 'name', property: 'name',
@ -376,7 +381,7 @@ describe('security ACLs', function() {
ACL.checkAccessForContext({ ACL.checkAccessForContext({
principals: [ principals: [
{ type: ACL.ROLE, id: Role.EVERYONE }, {type: ACL.ROLE, id: Role.EVERYONE},
], ],
model: 'Customer', model: 'Customer',
property: 'name', property: 'name',
@ -400,10 +405,10 @@ describe('access check', function() {
var beforeHookCalled = false; var beforeHookCalled = false;
app.use(loopback.rest()); app.use(loopback.rest());
app.set('remoting', { errorHandler: { debug: true, log: false }}); app.set('remoting', {errorHandler: {debug: true, log: false}});
app.enableAuth(); app.enableAuth();
app.dataSource('test', { connector: 'memory' }); app.dataSource('test', {connector: 'memory'});
app.model(MyTestModel, { dataSource: 'test' }); app.model(MyTestModel, {dataSource: 'test'});
// fake / spy on the checkAccess method // fake / spy on the checkAccess method
MyTestModel.checkAccess = function() { MyTestModel.checkAccess = function() {

View File

@ -3,6 +3,8 @@
// This file is licensed under the MIT License. // This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT // License text available at https://opensource.org/licenses/MIT
'use strict';
var assert = require('assert');
var async = require('async'); var async = require('async');
var path = require('path'); var path = require('path');
@ -14,6 +16,7 @@ var PersistedModel = loopback.PersistedModel;
var describe = require('./util/describe'); var describe = require('./util/describe');
var expect = require('chai').expect; var expect = require('chai').expect;
var it = require('./util/it'); var it = require('./util/it');
var request = require('supertest');
describe('app', function() { describe('app', function() {
var app; var app;
@ -309,7 +312,7 @@ describe('app', function() {
it('sets req.baseUrl and req.originalUrl', function(done) { it('sets req.baseUrl and req.originalUrl', function(done) {
var reqProps; var reqProps;
app.middleware('initial', function(req, res, next) { app.middleware('initial', function(req, res, next) {
reqProps = { baseUrl: req.baseUrl, originalUrl: req.originalUrl }; reqProps = {baseUrl: req.baseUrl, originalUrl: req.originalUrl};
next(); next();
}); });
@ -317,7 +320,7 @@ describe('app', function() {
executeMiddlewareHandlers(app, '/test/url', function(err) { executeMiddlewareHandlers(app, '/test/url', function(err) {
if (err) return done(err); if (err) return done(err);
expect(reqProps).to.eql({ baseUrl: '', originalUrl: '/test/url' }); expect(reqProps).to.eql({baseUrl: '', originalUrl: '/test/url'});
done(); done();
}); });
@ -451,7 +454,7 @@ describe('app', function() {
describe.onServer('.middlewareFromConfig', function() { describe.onServer('.middlewareFromConfig', function() {
it('provides API for loading middleware from JSON config', function(done) { it('provides API for loading middleware from JSON config', function(done) {
var steps = []; var steps = [];
var expectedConfig = { key: 'value' }; var expectedConfig = {key: 'value'};
var handlerFactory = function() { var handlerFactory = function() {
var args = Array.prototype.slice.apply(arguments); var args = Array.prototype.slice.apply(arguments);
@ -495,7 +498,7 @@ describe('app', function() {
enabled: true, enabled: true,
phase: 'routes:before', phase: 'routes:before',
methods: ['get', 'head'], methods: ['get', 'head'],
params: { x: 1 }, params: {x: 1},
}); });
// This should be skipped as the verb doesn't match // This should be skipped as the verb doesn't match
@ -503,7 +506,7 @@ describe('app', function() {
enabled: true, enabled: true,
phase: 'routes:before', phase: 'routes:before',
methods: ['post'], methods: ['post'],
params: { x: 2 }, params: {x: 2},
}); });
executeMiddlewareHandlers(app, function(err) { executeMiddlewareHandlers(app, function(err) {
@ -513,7 +516,7 @@ describe('app', function() {
['before'], ['before'],
[expectedConfig], [expectedConfig],
['after', 2], ['after', 2],
[{ x: 1 }], [{x: 1}],
]); ]);
done(); done();
@ -618,13 +621,13 @@ describe('app', function() {
var app, db, MyTestModel; var app, db, MyTestModel;
beforeEach(function() { beforeEach(function() {
app = loopback(); app = loopback();
app.set('remoting', { errorHandler: { debug: true, log: false }}); app.set('remoting', {errorHandler: {debug: true, log: false}});
db = loopback.createDataSource({ connector: loopback.Memory }); db = loopback.createDataSource({connector: loopback.Memory});
MyTestModel = app.registry.createModel('MyTestModel'); MyTestModel = app.registry.createModel('MyTestModel');
}); });
it('Expose a `Model` to remote clients', function() { it('Expose a `Model` to remote clients', function() {
var Color = PersistedModel.extend('color', { name: String }); var Color = PersistedModel.extend('color', {name: String});
app.model(Color); app.model(Color);
Color.attachTo(db); Color.attachTo(db);
@ -632,14 +635,14 @@ describe('app', function() {
}); });
it('uses singular name as app.remoteObjects() key', function() { it('uses singular name as app.remoteObjects() key', function() {
var Color = PersistedModel.extend('color', { name: String }); var Color = PersistedModel.extend('color', {name: String});
app.model(Color); app.model(Color);
Color.attachTo(db); Color.attachTo(db);
expect(app.remoteObjects()).to.eql({ color: Color }); expect(app.remoteObjects()).to.eql({color: Color});
}); });
it('uses singular name as shared class name', function() { it('uses singular name as shared class name', function() {
var Color = PersistedModel.extend('color', { name: String }); var Color = PersistedModel.extend('color', {name: String});
app.model(Color); app.model(Color);
Color.attachTo(db); Color.attachTo(db);
var classes = app.remotes().classes().map(function(c) { return c.name; }); var classes = app.remotes().classes().map(function(c) { return c.name; });
@ -647,7 +650,7 @@ describe('app', function() {
}); });
it('registers existing models to app.models', function() { it('registers existing models to app.models', function() {
var Color = db.createModel('color', { name: String }); var Color = db.createModel('color', {name: String});
app.model(Color); app.model(Color);
expect(Color.app).to.be.equal(app); expect(Color.app).to.be.equal(app);
expect(Color.shared).to.equal(true); expect(Color.shared).to.equal(true);
@ -656,7 +659,7 @@ describe('app', function() {
}); });
it('emits a `modelRemoted` event', function() { it('emits a `modelRemoted` event', function() {
var Color = PersistedModel.extend('color', { name: String }); var Color = PersistedModel.extend('color', {name: String});
Color.shared = true; Color.shared = true;
var remotedClass; var remotedClass;
app.on('modelRemoted', function(sharedClass) { app.on('modelRemoted', function(sharedClass) {
@ -668,7 +671,7 @@ describe('app', function() {
}); });
it('emits a `remoteMethodDisabled` event', function() { it('emits a `remoteMethodDisabled` event', function() {
var Color = PersistedModel.extend('color', { name: String }); var Color = PersistedModel.extend('color', {name: String});
Color.shared = true; Color.shared = true;
var remoteMethodDisabledClass, disabledRemoteMethod; var remoteMethodDisabledClass, disabledRemoteMethod;
app.on('remoteMethodDisabled', function(sharedClass, methodName) { app.on('remoteMethodDisabled', function(sharedClass, methodName) {
@ -687,7 +690,7 @@ describe('app', function() {
app.use(loopback.rest()); app.use(loopback.rest());
request(app).get('/colors').expect(404, function(err, res) { request(app).get('/colors').expect(404, function(err, res) {
if (err) return done(err); if (err) return done(err);
var Color = PersistedModel.extend('color', { name: String }); var Color = PersistedModel.extend('color', {name: String});
app.model(Color); app.model(Color);
Color.attachTo(db); Color.attachTo(db);
request(app).get('/colors').expect(200, done); request(app).get('/colors').expect(200, done);
@ -695,13 +698,13 @@ describe('app', function() {
}); });
it('accepts null dataSource', function(done) { it('accepts null dataSource', function(done) {
app.model(MyTestModel, { dataSource: null }); app.model(MyTestModel, {dataSource: null});
expect(MyTestModel.dataSource).to.eql(null); expect(MyTestModel.dataSource).to.eql(null);
done(); done();
}); });
it('accepts false dataSource', function(done) { it('accepts false dataSource', function(done) {
app.model(MyTestModel, { dataSource: false }); app.model(MyTestModel, {dataSource: false});
expect(MyTestModel.getDataSource()).to.eql(null); expect(MyTestModel.getDataSource()).to.eql(null);
done(); done();
}); });
@ -720,7 +723,7 @@ describe('app', function() {
describe('app.model(ModelCtor, config)', function() { describe('app.model(ModelCtor, config)', function() {
it('attaches the model to a datasource', function() { it('attaches the model to a datasource', function() {
var previousModel = loopback.registry.findModel('TestModel'); var previousModel = loopback.registry.findModel('TestModel');
app.dataSource('db', { connector: 'memory' }); app.dataSource('db', {connector: 'memory'});
if (previousModel) { if (previousModel) {
delete previousModel.dataSource; delete previousModel.dataSource;
@ -728,16 +731,16 @@ describe('app', function() {
assert(!previousModel || !previousModel.dataSource); assert(!previousModel || !previousModel.dataSource);
var TestModel = app.registry.createModel('TestModel'); var TestModel = app.registry.createModel('TestModel');
app.model(TestModel, { dataSource: 'db' }); app.model(TestModel, {dataSource: 'db'});
expect(app.models.TestModel.dataSource).to.equal(app.dataSources.db); expect(app.models.TestModel.dataSource).to.equal(app.dataSources.db);
}); });
}); });
describe('app.models', function() { describe('app.models', function() {
it('is unique per app instance', function() { it('is unique per app instance', function() {
app.dataSource('db', { connector: 'memory' }); app.dataSource('db', {connector: 'memory'});
var Color = app.registry.createModel('Color'); var Color = app.registry.createModel('Color');
app.model(Color, { dataSource: 'db' }); app.model(Color, {dataSource: 'db'});
expect(app.models.Color).to.equal(Color); expect(app.models.Color).to.equal(Color);
var anotherApp = loopback(); var anotherApp = loopback();
expect(anotherApp.models.Color).to.equal(undefined); expect(anotherApp.models.Color).to.equal(undefined);
@ -746,7 +749,7 @@ describe('app', function() {
describe('app.dataSources', function() { describe('app.dataSources', function() {
it('is unique per app instance', function() { it('is unique per app instance', function() {
app.dataSource('ds', { connector: 'memory' }); app.dataSource('ds', {connector: 'memory'});
expect(app.datasources.ds).to.not.equal(undefined); expect(app.datasources.ds).to.not.equal(undefined);
var anotherApp = loopback(); var anotherApp = loopback();
expect(anotherApp.datasources.ds).to.equal(undefined); expect(anotherApp.datasources.ds).to.equal(undefined);
@ -756,7 +759,7 @@ describe('app', function() {
describe('app.dataSource', function() { describe('app.dataSource', function() {
it('looks up the connector in `app.connectors`', function() { it('looks up the connector in `app.connectors`', function() {
app.connector('custom', loopback.Memory); app.connector('custom', loopback.Memory);
app.dataSource('custom', { connector: 'custom' }); app.dataSource('custom', {connector: 'custom'});
expect(app.dataSources.custom.name).to.equal(loopback.Memory.name); expect(app.dataSources.custom.name).to.equal(loopback.Memory.name);
}); });
@ -766,12 +769,12 @@ describe('app', function() {
}); });
expect(function() { expect(function() {
app.dataSource('bad-ds', { connector: 'throwing' }); app.dataSource('bad-ds', {connector: 'throwing'});
}).to.throw(/bad-ds.*throwing/); }).to.throw(/bad-ds.*throwing/);
}); });
it('adds app reference to the data source object', function() { it('adds app reference to the data source object', function() {
app.dataSource('ds', { connector: 'memory' }); app.dataSource('ds', {connector: 'memory'});
expect(app.datasources.ds.app).to.not.equal(undefined); expect(app.datasources.ds.app).to.not.equal(undefined);
expect(app.datasources.ds.app).to.equal(app); expect(app.datasources.ds.app).to.equal(app);
}); });
@ -864,11 +867,11 @@ describe('app', function() {
it('auto-configures required models to provided dataSource', function() { it('auto-configures required models to provided dataSource', function() {
var AUTH_MODELS = ['User', 'ACL', 'AccessToken', 'Role', 'RoleMapping']; var AUTH_MODELS = ['User', 'ACL', 'AccessToken', 'Role', 'RoleMapping'];
var app = loopback({ localRegistry: true, loadBuiltinModels: true }); var app = loopback({localRegistry: true, loadBuiltinModels: true});
require('../lib/builtin-models')(app.registry); require('../lib/builtin-models')(app.registry);
var db = app.dataSource('db', { connector: 'memory' }); var db = app.dataSource('db', {connector: 'memory'});
app.enableAuth({ dataSource: 'db' }); app.enableAuth({dataSource: 'db'});
expect(Object.keys(app.models)).to.include.members(AUTH_MODELS); expect(Object.keys(app.models)).to.include.members(AUTH_MODELS);
@ -880,12 +883,12 @@ describe('app', function() {
}); });
it('detects already configured subclass of a required model', function() { it('detects already configured subclass of a required model', function() {
var app = loopback({ localRegistry: true, loadBuiltinModels: true }); var app = loopback({localRegistry: true, loadBuiltinModels: true});
var db = app.dataSource('db', { connector: 'memory' }); var db = app.dataSource('db', {connector: 'memory'});
var Customer = app.registry.createModel('Customer', {}, { base: 'User' }); var Customer = app.registry.createModel('Customer', {}, {base: 'User'});
app.model(Customer, { dataSource: 'db' }); app.model(Customer, {dataSource: 'db'});
app.enableAuth({ dataSource: 'db' }); app.enableAuth({dataSource: 'db'});
expect(Object.keys(app.models)).to.not.include('User'); expect(Object.keys(app.models)).to.not.include('User');
}); });
@ -980,15 +983,15 @@ describe('app', function() {
var app, db; var app, db;
beforeEach(function() { beforeEach(function() {
app = loopback(); app = loopback();
db = loopback.createDataSource({ connector: loopback.Memory }); db = loopback.createDataSource({connector: loopback.Memory});
}); });
it.onServer('normalizes the http path', function(done) { it.onServer('normalizes the http path', function(done) {
var UserAccount = PersistedModel.extend( var UserAccount = PersistedModel.extend(
'UserAccount', 'UserAccount',
{ name: String }, {name: String},
{ {
remoting: { normalizeHttpPath: true }, remoting: {normalizeHttpPath: true},
}); });
app.model(UserAccount); app.model(UserAccount);
UserAccount.attachTo(db); UserAccount.attachTo(db);

View File

@ -3,12 +3,16 @@
// This file is licensed under the MIT License. // This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT // License text available at https://opensource.org/licenses/MIT
'use strict';
var expect = require('chai').expect;
var loopback = require('../');
describe('PersistedModel.createChangeStream()', function() { describe('PersistedModel.createChangeStream()', function() {
describe('configured to source changes locally', function() { describe('configured to source changes locally', function() {
before(function() { before(function() {
var test = this; var test = this;
var app = loopback({ localRegistry: true }); var app = loopback({localRegistry: true});
var ds = app.dataSource('ds', { connector: 'memory' }); var ds = app.dataSource('ds', {connector: 'memory'});
var Score = app.registry.createModel('Score'); var Score = app.registry.createModel('Score');
this.Score = app.model(Score, { this.Score = app.model(Score, {
dataSource: 'ds', dataSource: 'ds',
@ -27,13 +31,13 @@ describe('PersistedModel.createChangeStream()', function() {
done(); done();
}); });
Score.create({ team: 'foo' }); Score.create({team: 'foo'});
}); });
}); });
it('should detect update', function(done) { it('should detect update', function(done) {
var Score = this.Score; var Score = this.Score;
Score.create({ team: 'foo' }, function(err, newScore) { Score.create({team: 'foo'}, function(err, newScore) {
Score.createChangeStream(function(err, changes) { Score.createChangeStream(function(err, changes) {
changes.on('data', function(change) { changes.on('data', function(change) {
expect(change.type).to.equal('update'); expect(change.type).to.equal('update');
@ -50,7 +54,7 @@ describe('PersistedModel.createChangeStream()', function() {
it('should detect delete', function(done) { it('should detect delete', function(done) {
var Score = this.Score; var Score = this.Score;
Score.create({ team: 'foo' }, function(err, newScore) { Score.create({team: 'foo'}, function(err, newScore) {
Score.createChangeStream(function(err, changes) { Score.createChangeStream(function(err, changes) {
changes.on('data', function(change) { changes.on('data', function(change) {
expect(change.type).to.equal('remove'); expect(change.type).to.equal('remove');
@ -69,8 +73,8 @@ describe('PersistedModel.createChangeStream()', function() {
describe.skip('configured to source changes using pubsub', function() { describe.skip('configured to source changes using pubsub', function() {
before(function() { before(function() {
var test = this; var test = this;
var app = loopback({ localRegistry: true }); var app = loopback({localRegistry: true});
var db = app.dataSource('ds', { connector: 'memory' }); var db = app.dataSource('ds', {connector: 'memory'});
var ps = app.dataSource('ps', { var ps = app.dataSource('ps', {
host: 'localhost', host: 'localhost',
port: '12345', port: '12345',

View File

@ -3,8 +3,11 @@
// This file is licensed under the MIT License. // This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT // License text available at https://opensource.org/licenses/MIT
'use strict';
var assert = require('assert');
var async = require('async'); var async = require('async');
var expect = require('chai').expect; var expect = require('chai').expect;
var loopback = require('../');
var Change, TestModel; var Change, TestModel;
@ -15,7 +18,7 @@ describe('Change', function() {
}); });
TestModel = loopback.PersistedModel.extend('ChangeTestModel', TestModel = loopback.PersistedModel.extend('ChangeTestModel',
{ {
id: { id: true, type: 'string', defaultFn: 'guid' }, id: {id: true, type: 'string', defaultFn: 'guid'},
}, },
{ {
trackChanges: true, trackChanges: true,
@ -475,20 +478,20 @@ describe('Change', function() {
describe('Change.diff(modelName, since, remoteChanges, callback)', function() { describe('Change.diff(modelName, since, remoteChanges, callback)', function() {
beforeEach(function(done) { beforeEach(function(done) {
Change.create([ Change.create([
{ rev: 'foo', modelName: this.modelName, modelId: 9, checkpoint: 1 }, {rev: 'foo', modelName: this.modelName, modelId: 9, checkpoint: 1},
{ rev: 'bar', modelName: this.modelName, modelId: 10, checkpoint: 1 }, {rev: 'bar', modelName: this.modelName, modelId: 10, checkpoint: 1},
{ rev: 'bat', modelName: this.modelName, modelId: 11, checkpoint: 1 }, {rev: 'bat', modelName: this.modelName, modelId: 11, checkpoint: 1},
], done); ], done);
}); });
it('should return delta and conflict lists', function(done) { it('should return delta and conflict lists', function(done) {
var remoteChanges = [ var remoteChanges = [
// an update => should result in a delta // an update => should result in a delta
{ rev: 'foo2', prev: 'foo', modelName: this.modelName, modelId: 9, checkpoint: 1 }, {rev: 'foo2', prev: 'foo', modelName: this.modelName, modelId: 9, checkpoint: 1},
// no change => should not result in a delta / conflict // no change => should not result in a delta / conflict
{ rev: 'bar', prev: 'bar', modelName: this.modelName, modelId: 10, checkpoint: 1 }, {rev: 'bar', prev: 'bar', modelName: this.modelName, modelId: 10, checkpoint: 1},
// a conflict => should result in a conflict // a conflict => should result in a conflict
{ rev: 'bat2', prev: 'bat0', modelName: this.modelName, modelId: 11, checkpoint: 1 }, {rev: 'bat2', prev: 'bat0', modelName: this.modelName, modelId: 11, checkpoint: 1},
]; ];
Change.diff(this.modelName, 0, remoteChanges, function(err, diff) { Change.diff(this.modelName, 0, remoteChanges, function(err, diff) {
@ -504,11 +507,11 @@ describe('Change', function() {
it('should return delta and conflict lists - promise variant', function(done) { it('should return delta and conflict lists - promise variant', function(done) {
var remoteChanges = [ var remoteChanges = [
// an update => should result in a delta // an update => should result in a delta
{ rev: 'foo2', prev: 'foo', modelName: this.modelName, modelId: 9, checkpoint: 1 }, {rev: 'foo2', prev: 'foo', modelName: this.modelName, modelId: 9, checkpoint: 1},
// no change => should not result in a delta / conflict // no change => should not result in a delta / conflict
{ rev: 'bar', prev: 'bar', modelName: this.modelName, modelId: 10, checkpoint: 1 }, {rev: 'bar', prev: 'bar', modelName: this.modelName, modelId: 10, checkpoint: 1},
// a conflict => should result in a conflict // a conflict => should result in a conflict
{ rev: 'bat2', prev: 'bat0', modelName: this.modelName, modelId: 11, checkpoint: 1 }, {rev: 'bat2', prev: 'bat0', modelName: this.modelName, modelId: 11, checkpoint: 1},
]; ];
Change.diff(this.modelName, 0, remoteChanges) Change.diff(this.modelName, 0, remoteChanges)

View File

@ -3,6 +3,7 @@
// This file is licensed under the MIT License. // This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT // License text available at https://opensource.org/licenses/MIT
'use strict';
var async = require('async'); var async = require('async');
var loopback = require('../'); var loopback = require('../');
var expect = require('chai').expect; var expect = require('chai').expect;

View File

@ -3,6 +3,10 @@
// This file is licensed under the MIT License. // This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT // License text available at https://opensource.org/licenses/MIT
'use strict';
var assert = require('assert');
var loopback = require('../');
describe('DataSource', function() { describe('DataSource', function() {
var memory; var memory;
@ -16,7 +20,7 @@ describe('DataSource', function() {
describe('dataSource.createModel(name, properties, settings)', function() { describe('dataSource.createModel(name, properties, settings)', function() {
it('Define a model and attach it to a `DataSource`', function() { it('Define a model and attach it to a `DataSource`', function() {
var Color = memory.createModel('color', { name: String }); var Color = memory.createModel('color', {name: String});
assert.isFunc(Color, 'find'); assert.isFunc(Color, 'find');
assert.isFunc(Color, 'findById'); assert.isFunc(Color, 'findById');
assert.isFunc(Color, 'findOne'); assert.isFunc(Color, 'findOne');
@ -42,13 +46,13 @@ describe('DataSource', function() {
it('should honor settings.base', function() { it('should honor settings.base', function() {
var Base = memory.createModel('base'); var Base = memory.createModel('base');
var Color = memory.createModel('color', { name: String }, { base: Base }); var Color = memory.createModel('color', {name: String}, {base: Base});
assert(Color.prototype instanceof Base); assert(Color.prototype instanceof Base);
assert.equal(Color.base, Base); assert.equal(Color.base, Base);
}); });
it('should use loopback.PersistedModel as the base for DBs', function() { it('should use loopback.PersistedModel as the base for DBs', function() {
var Color = memory.createModel('color', { name: String }); var Color = memory.createModel('color', {name: String});
assert(Color.prototype instanceof loopback.PersistedModel); assert(Color.prototype instanceof loopback.PersistedModel);
assert.equal(Color.base, loopback.PersistedModel); assert.equal(Color.base, loopback.PersistedModel);
}); });
@ -65,7 +69,7 @@ describe('DataSource', function() {
connector: new Connector(), connector: new Connector(),
}); });
var Color = ds.createModel('color', { name: String }); var Color = ds.createModel('color', {name: String});
assert(Color.prototype instanceof Color.registry.getModel('Model')); assert(Color.prototype instanceof Color.registry.getModel('Model'));
assert.equal(Color.base.modelName, 'PersistedModel'); assert.equal(Color.base.modelName, 'PersistedModel');
}); });
@ -116,3 +120,19 @@ describe('DataSource', function() {
}); });
}); });
}); });
var assertValidDataSource = function(dataSource) {
// has methods
assert.isFunc(dataSource, 'createModel');
assert.isFunc(dataSource, 'discoverModelDefinitions');
assert.isFunc(dataSource, 'discoverSchema');
assert.isFunc(dataSource, 'enableRemote');
assert.isFunc(dataSource, 'disableRemote');
assert.isFunc(dataSource, 'defineOperation');
assert.isFunc(dataSource, 'operations');
};
assert.isFunc = function(obj, name) {
assert(obj, 'cannot assert function ' + name + ' on object that doesnt exist');
assert(typeof obj[name] === 'function', name + ' is not a function');
};

View File

@ -3,6 +3,7 @@
// This file is licensed under the MIT License. // This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT // License text available at https://opensource.org/licenses/MIT
'use strict';
var path = require('path'); var path = require('path');
var loopback = require('../../'); var loopback = require('../../');
var models = require('../fixtures/e2e/models'); var models = require('../fixtures/e2e/models');

View File

@ -3,6 +3,7 @@
// This file is licensed under the MIT License. // This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT // License text available at https://opensource.org/licenses/MIT
'use strict';
var path = require('path'); var path = require('path');
var loopback = require('../../'); var loopback = require('../../');
var models = require('../fixtures/e2e/models'); var models = require('../fixtures/e2e/models');
@ -33,7 +34,7 @@ describe('Replication', function() {
LocalTestModel.replicate(0, TestModel, function() { LocalTestModel.replicate(0, TestModel, function() {
if (err) return done(err); if (err) return done(err);
TestModel.findOne({ n: RANDOM }, function(err, found) { TestModel.findOne({n: RANDOM}, function(err, found) {
assert.equal(created.id, found.id); assert.equal(created.id, found.id);
done(); done();

View File

@ -3,6 +3,7 @@
// This file is licensed under the MIT License. // This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT // License text available at https://opensource.org/licenses/MIT
'use strict';
var loopback = require('../'); var loopback = require('../');
var MyEmail; var MyEmail;
var assert = require('assert'); var assert = require('assert');
@ -10,37 +11,37 @@ var MailConnector = require('../lib/connectors/mail');
describe('Email connector', function() { describe('Email connector', function() {
it('should set up SMTP', function() { it('should set up SMTP', function() {
var connector = new MailConnector({ transports: [ var connector = new MailConnector({transports: [
{ type: 'smtp', service: 'gmail' }, {type: 'smtp', service: 'gmail'},
] }); ]});
assert(connector.transportForName('smtp')); assert(connector.transportForName('smtp'));
}); });
it('should set up DIRECT', function() { it('should set up DIRECT', function() {
var connector = new MailConnector({ transports: [ var connector = new MailConnector({transports: [
{ type: 'direct', name: 'localhost' }, {type: 'direct', name: 'localhost'},
] }); ]});
assert(connector.transportForName('direct')); assert(connector.transportForName('direct'));
}); });
it('should set up STUB', function() { it('should set up STUB', function() {
var connector = new MailConnector({ transports: [ var connector = new MailConnector({transports: [
{ type: 'stub', service: 'gmail' }, {type: 'stub', service: 'gmail'},
] }); ]});
assert(connector.transportForName('stub')); assert(connector.transportForName('stub'));
}); });
it('should set up a single transport for SMTP', function() { it('should set up a single transport for SMTP', function() {
var connector = new MailConnector({ transport: var connector = new MailConnector({transport:
{ type: 'smtp', service: 'gmail' }, {type: 'smtp', service: 'gmail'},
}); });
assert(connector.transportForName('smtp')); assert(connector.transportForName('smtp'));
}); });
it('should set up a aliased transport for SMTP', function() { it('should set up a aliased transport for SMTP', function() {
var connector = new MailConnector({ transport: var connector = new MailConnector({transport:
{ type: 'smtp', service: 'ses-us-east-1', alias: 'ses-smtp' }, {type: 'smtp', service: 'ses-us-east-1', alias: 'ses-smtp'},
}); });
assert(connector.transportForName('ses-smtp')); assert(connector.transportForName('ses-smtp'));
@ -52,7 +53,7 @@ describe('Email and SMTP', function() {
MyEmail = loopback.Email.extend('my-email'); MyEmail = loopback.Email.extend('my-email');
var ds = loopback.createDataSource('email', { var ds = loopback.createDataSource('email', {
connector: loopback.Mail, connector: loopback.Mail,
transports: [{ type: 'STUB' }], transports: [{type: 'STUB'}],
}); });
MyEmail.attachTo(ds); MyEmail.attachTo(ds);
}); });

View File

@ -3,6 +3,7 @@
// This file is licensed under the MIT License. // This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT // License text available at https://opensource.org/licenses/MIT
'use strict';
var loopback = require('../'); var loopback = require('../');
var app; var app;
var assert = require('assert'); var assert = require('assert');

View File

@ -3,6 +3,7 @@
// This file is licensed under the MIT License. // This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT // License text available at https://opensource.org/licenses/MIT
'use strict';
var loopback = require('../../../..'); var loopback = require('../../../..');
var boot = require('loopback-boot'); var boot = require('loopback-boot');
var app = module.exports = loopback({ var app = module.exports = loopback({
@ -14,7 +15,7 @@ var errorHandler = require('strong-error-handler');
boot(app, __dirname); boot(app, __dirname);
var apiPath = '/api'; var apiPath = '/api';
app.use(loopback.token({ model: app.models.accessToken })); app.use(loopback.token({model: app.models.accessToken}));
app.use(apiPath, loopback.rest()); app.use(apiPath, loopback.rest());
app.use(loopback.urlNotFound()); app.use(loopback.urlNotFound());

View File

@ -3,6 +3,7 @@
// This file is licensed under the MIT License. // This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT // License text available at https://opensource.org/licenses/MIT
'use strict';
var loopback = require('../../../../index'); var loopback = require('../../../../index');
var PersistedModel = loopback.PersistedModel; var PersistedModel = loopback.PersistedModel;

View File

@ -3,8 +3,9 @@
// This file is licensed under the MIT License. // This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT // License text available at https://opensource.org/licenses/MIT
'use strict';
var loopback = require('../../../../index'); var loopback = require('../../../../index');
var app = module.exports = loopback({ localRegistry: true }); var app = module.exports = loopback({localRegistry: true});
var models = require('./models'); var models = require('./models');
var TestModel = models.TestModel; var TestModel = models.TestModel;

View File

@ -3,6 +3,7 @@
// This file is licensed under the MIT License. // This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT // License text available at https://opensource.org/licenses/MIT
'use strict';
module.exports = function(Todo) { module.exports = function(Todo) {
}; };

View File

@ -3,6 +3,7 @@
// This file is licensed under the MIT License. // This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT // License text available at https://opensource.org/licenses/MIT
'use strict';
var boot = require('loopback-boot'); var boot = require('loopback-boot');
var loopback = require('../../../../../index'); var loopback = require('../../../../../index');

View File

@ -3,6 +3,7 @@
// This file is licensed under the MIT License. // This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT // License text available at https://opensource.org/licenses/MIT
'use strict';
module.exports = function(Todo) { module.exports = function(Todo) {
}; };

View File

@ -3,6 +3,7 @@
// This file is licensed under the MIT License. // This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT // License text available at https://opensource.org/licenses/MIT
'use strict';
var boot = require('loopback-boot'); var boot = require('loopback-boot');
var loopback = require('../../../../../index'); var loopback = require('../../../../../index');

View File

@ -3,6 +3,7 @@
// This file is licensed under the MIT License. // This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT // License text available at https://opensource.org/licenses/MIT
'use strict';
module.exports = function(Todo) { module.exports = function(Todo) {
}; };

View File

@ -3,6 +3,7 @@
// This file is licensed under the MIT License. // This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT // License text available at https://opensource.org/licenses/MIT
'use strict';
var boot = require('loopback-boot'); var boot = require('loopback-boot');
var loopback = require('../../../../../index'); var loopback = require('../../../../../index');

View File

@ -3,6 +3,7 @@
// This file is licensed under the MIT License. // This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT // License text available at https://opensource.org/licenses/MIT
'use strict';
module.exports = function(Todo) { module.exports = function(Todo) {
}; };

View File

@ -3,6 +3,7 @@
// This file is licensed under the MIT License. // This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT // License text available at https://opensource.org/licenses/MIT
'use strict';
var boot = require('loopback-boot'); var boot = require('loopback-boot');
var loopback = require('../../../../../index'); var loopback = require('../../../../../index');

View File

@ -3,6 +3,7 @@
// This file is licensed under the MIT License. // This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT // License text available at https://opensource.org/licenses/MIT
'use strict';
module.exports = function(Todo) { module.exports = function(Todo) {
}; };

View File

@ -3,6 +3,7 @@
// This file is licensed under the MIT License. // This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT // License text available at https://opensource.org/licenses/MIT
'use strict';
var boot = require('loopback-boot'); var boot = require('loopback-boot');
var loopback = require('../../../../../index'); var loopback = require('../../../../../index');

View File

@ -3,6 +3,7 @@
// This file is licensed under the MIT License. // This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT // License text available at https://opensource.org/licenses/MIT
'use strict';
module.exports = function(Todo) { module.exports = function(Todo) {
}; };

View File

@ -3,6 +3,7 @@
// This file is licensed under the MIT License. // This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT // License text available at https://opensource.org/licenses/MIT
'use strict';
var boot = require('loopback-boot'); var boot = require('loopback-boot');
var loopback = require('../../../../../index'); var loopback = require('../../../../../index');

View File

@ -3,6 +3,7 @@
// This file is licensed under the MIT License. // This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT // License text available at https://opensource.org/licenses/MIT
'use strict';
module.exports = function(Todo) { module.exports = function(Todo) {
}; };

View File

@ -3,6 +3,7 @@
// This file is licensed under the MIT License. // This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT // License text available at https://opensource.org/licenses/MIT
'use strict';
var boot = require('loopback-boot'); var boot = require('loopback-boot');
var loopback = require('../../../../../index'); var loopback = require('../../../../../index');

View File

@ -3,6 +3,7 @@
// This file is licensed under the MIT License. // This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT // License text available at https://opensource.org/licenses/MIT
'use strict';
module.exports = function(Todo) { module.exports = function(Todo) {
}; };

View File

@ -3,6 +3,7 @@
// This file is licensed under the MIT License. // This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT // License text available at https://opensource.org/licenses/MIT
'use strict';
var boot = require('loopback-boot'); var boot = require('loopback-boot');
var loopback = require('../../../../../index'); var loopback = require('../../../../../index');

View File

@ -3,6 +3,7 @@
// This file is licensed under the MIT License. // This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT // License text available at https://opensource.org/licenses/MIT
'use strict';
module.exports = function(Todo) { module.exports = function(Todo) {
}; };

View File

@ -3,6 +3,7 @@
// This file is licensed under the MIT License. // This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT // License text available at https://opensource.org/licenses/MIT
'use strict';
var boot = require('loopback-boot'); var boot = require('loopback-boot');
var loopback = require('../../../../../index'); var loopback = require('../../../../../index');

View File

@ -3,4 +3,5 @@
// This file is licensed under the MIT License. // This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT // License text available at https://opensource.org/licenses/MIT
'use strict';
process.loadedFooJS = true; process.loadedFooJS = true;

View File

@ -3,6 +3,7 @@
// This file is licensed under the MIT License. // This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT // License text available at https://opensource.org/licenses/MIT
'use strict';
module.exports = function(Bar) { module.exports = function(Bar) {
process.loadedBarJS = true; process.loadedBarJS = true;
}; };

View File

@ -3,9 +3,10 @@
// This file is licensed under the MIT License. // This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT // License text available at https://opensource.org/licenses/MIT
'use strict';
var loopback = require('../../../../index'); var loopback = require('../../../../index');
var boot = require('loopback-boot'); var boot = require('loopback-boot');
var app = module.exports = loopback({ localRegistry: true }); var app = module.exports = loopback({localRegistry: true});
var errorHandler = require('strong-error-handler'); var errorHandler = require('strong-error-handler');
boot(app, __dirname); boot(app, __dirname);

View File

@ -14,5 +14,6 @@
"principalType": "ROLE", "principalType": "ROLE",
"principalId": "$owner" "principalId": "$owner"
} }
] ],
} "saltWorkFactor": 4
}

View File

@ -3,6 +3,7 @@
// This file is licensed under the MIT License. // This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT // License text available at https://opensource.org/licenses/MIT
'use strict';
var loopback = require('../../../../index'); var loopback = require('../../../../index');
var boot = require('loopback-boot'); var boot = require('loopback-boot');
var app = module.exports = loopback({ var app = module.exports = loopback({
@ -13,7 +14,7 @@ var errorHandler = require('strong-error-handler');
app.enableAuth(); app.enableAuth();
boot(app, __dirname); boot(app, __dirname);
app.use(loopback.token({ model: app.models.AccessToken })); app.use(loopback.token({model: app.models.AccessToken}));
var apiPath = '/api'; var apiPath = '/api';
app.use(apiPath, loopback.rest()); app.use(apiPath, loopback.rest());
app.use(loopback.urlNotFound()); app.use(loopback.urlNotFound());

View File

@ -3,12 +3,17 @@
// This file is licensed under the MIT License. // This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT // License text available at https://opensource.org/licenses/MIT
'use strict';
var assert = require('assert');
var loopback = require('../');
var GeoPoint = loopback.GeoPoint;
describe('GeoPoint', function() { describe('GeoPoint', function() {
describe('geoPoint.distanceTo(geoPoint, options)', function() { describe('geoPoint.distanceTo(geoPoint, options)', function() {
it('Get the distance to another `GeoPoint`', function() { it('Get the distance to another `GeoPoint`', function() {
var here = new GeoPoint({ lat: 10, lng: 10 }); var here = new GeoPoint({lat: 10, lng: 10});
var there = new GeoPoint({ lat: 5, lng: 5 }); var there = new GeoPoint({lat: 5, lng: 5});
var distance = here.distanceTo(there, { type: 'meters' }); var distance = here.distanceTo(there, {type: 'meters'});
assert.equal(Math.floor(distance), 782777); assert.equal(Math.floor(distance), 782777);
}); });
@ -16,9 +21,9 @@ describe('GeoPoint', function() {
describe('GeoPoint.distanceBetween(a, b, options)', function() { describe('GeoPoint.distanceBetween(a, b, options)', function() {
it('Get the distance between two points', function() { it('Get the distance between two points', function() {
var here = new GeoPoint({ lat: 10, lng: 10 }); var here = new GeoPoint({lat: 10, lng: 10});
var there = new GeoPoint({ lat: 5, lng: 5 }); var there = new GeoPoint({lat: 5, lng: 5});
var distance = GeoPoint.distanceBetween(here, there, { type: 'feet' }); var distance = GeoPoint.distanceBetween(here, there, {type: 'feet'});
assert.equal(Math.floor(distance), 2568169); assert.equal(Math.floor(distance), 2568169);
}); });
@ -48,7 +53,7 @@ describe('GeoPoint', function() {
}); });
it('Create as Model property', function() { it('Create as Model property', function() {
var Model = loopback.createModel('geo-model', { var Model = loopback.createModel('geo-model', {
geo: { type: 'GeoPoint' }, geo: {type: 'GeoPoint'},
}); });
var m = new Model({ var m = new Model({

View File

@ -3,6 +3,7 @@
// This file is licensed under the MIT License. // This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT // License text available at https://opensource.org/licenses/MIT
'use strict';
var _describe = {}; var _describe = {};
var _it = {}; var _it = {};
var _beforeEach = {}; var _beforeEach = {};
@ -68,7 +69,7 @@ _beforeEach.givenModel = function(modelName, attrs, optionalHandler) {
var app = this.app; var app = this.app;
var model = app.models[modelName]; var model = app.models[modelName];
app.set('remoting', { errorHandler: { debug: true, log: false }}); app.set('remoting', {errorHandler: {debug: true, log: false}});
assert(model, 'cannot get model of name ' + modelName + ' from app.models'); assert(model, 'cannot get model of name ' + modelName + ' from app.models');
assert(model.dataSource, 'cannot test model ' + modelName + assert(model.dataSource, 'cannot test model ' + modelName +
' without attached dataSource'); ' without attached dataSource');
@ -135,7 +136,7 @@ _beforeEach.givenAnUnauthenticatedToken = function(attrs, optionalHandler) {
}; };
_beforeEach.givenAnAnonymousToken = function(attrs, optionalHandler) { _beforeEach.givenAnAnonymousToken = function(attrs, optionalHandler) {
_beforeEach.givenModel('accessToken', { id: '$anonymous' }, optionalHandler); _beforeEach.givenModel('accessToken', {id: '$anonymous'}, optionalHandler);
}; };
_describe.whenCalledRemotely = function(verb, url, data, cb) { _describe.whenCalledRemotely = function(verb, url, data, cb) {

View File

@ -3,14 +3,17 @@
// This file is licensed under the MIT License. // This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT // License text available at https://opensource.org/licenses/MIT
'use strict';
var assert = require('assert');
var loopback = require('../'); var loopback = require('../');
var request = require('supertest');
describe('hidden properties', function() { describe('hidden properties', function() {
beforeEach(function(done) { beforeEach(function(done) {
var app = this.app = loopback(); var app = this.app = loopback();
var Product = this.Product = loopback.PersistedModel.extend('product', var Product = this.Product = loopback.PersistedModel.extend('product',
{}, {},
{ hidden: ['secret'] } {hidden: ['secret']}
); );
Product.attachTo(loopback.memory()); Product.attachTo(loopback.memory());

View File

@ -3,7 +3,11 @@
// This file is licensed under the MIT License. // This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT // License text available at https://opensource.org/licenses/MIT
'use strict';
var expect = require('chai').expect;
var loopback = require('../');
var net = require('net'); var net = require('net');
describe('loopback application', function() { describe('loopback application', function() {
it('pauses request stream during authentication', function(done) { it('pauses request stream during authentication', function(done) {
// This test reproduces the issue reported in // This test reproduces the issue reported in
@ -38,10 +42,10 @@ describe('loopback application', function() {
loopback.AccessToken.attachTo(db); loopback.AccessToken.attachTo(db);
loopback.Role.attachTo(db); loopback.Role.attachTo(db);
loopback.ACL.attachTo(db); loopback.ACL.attachTo(db);
loopback.User.hasMany(loopback.AccessToken, { as: 'accessTokens' }); loopback.User.hasMany(loopback.AccessToken, {as: 'accessTokens'});
var Streamer = app.registry.createModel('Streamer'); var Streamer = app.registry.createModel('Streamer');
app.model(Streamer, { dataSource: 'db' }); app.model(Streamer, {dataSource: 'db'});
Streamer.read = function(req, res, cb) { Streamer.read = function(req, res, cb) {
var body = new Buffer(0); var body = new Buffer(0);
req.on('data', function(chunk) { req.on('data', function(chunk) {
@ -57,15 +61,15 @@ describe('loopback application', function() {
}); });
}; };
loopback.remoteMethod(Streamer.read, { loopback.remoteMethod(Streamer.read, {
http: { method: 'post' }, http: {method: 'post'},
accepts: [ accepts: [
{ arg: 'req', type: 'Object', http: { source: 'req' }}, {arg: 'req', type: 'Object', http: {source: 'req'}},
{ arg: 'res', type: 'Object', http: { source: 'res' }}, {arg: 'res', type: 'Object', http: {source: 'res'}},
], ],
}); });
app.enableAuth(); app.enableAuth();
app.use(loopback.token({ model: app.models.accessToken })); app.use(loopback.token({model: app.models.accessToken}));
app.use(loopback.rest()); app.use(loopback.rest());
} }

View File

@ -6,6 +6,7 @@
// Karma configuration // Karma configuration
// http://karma-runner.github.io/0.12/config/configuration-file.html // http://karma-runner.github.io/0.12/config/configuration-file.html
'use strict';
module.exports = function(config) { module.exports = function(config) {
config.set({ config.set({
// enable / disable watching file and executing tests whenever any file changes // enable / disable watching file and executing tests whenever any file changes
@ -111,6 +112,6 @@ module.exports = function(config) {
}, },
// Add browserify to preprocessors // Add browserify to preprocessors
preprocessors: { 'test/*': ['browserify'] }, preprocessors: {'test/*': ['browserify']},
}); });
}; };

View File

@ -1,9 +1,10 @@
'use strict';
var expect = require('chai').expect; var expect = require('chai').expect;
var http = require('http'); var http = require('http');
var loopback = require('..'); var loopback = require('..');
var supertest = require('supertest'); var supertest = require('supertest');
var AN_OBJECT_VALUE = { name: 'an-object' }; var AN_OBJECT_VALUE = {name: 'an-object'};
describe('KeyValueModel', function() { describe('KeyValueModel', function() {
var request, app, CacheItem; var request, app, CacheItem;
@ -61,7 +62,7 @@ describe('KeyValueModel', function() {
CacheItem.set('expire-key', AN_OBJECT_VALUE, function(err) { CacheItem.set('expire-key', AN_OBJECT_VALUE, function(err) {
if (err) return done(err); if (err) return done(err);
request.put('/CacheItems/expire-key/expire') request.put('/CacheItems/expire-key/expire')
.send({ ttl: 10 }) .send({ttl: 10})
.end(function(err, res) { .end(function(err, res) {
if (err) return done(err); if (err) return done(err);
setTimeout(function() { setTimeout(function() {
@ -77,7 +78,7 @@ describe('KeyValueModel', function() {
it('returns 404 when expiring a key that does not exist', function(done) { it('returns 404 when expiring a key that does not exist', function(done) {
request.put('/CacheItems/key-does-not-exist/expire') request.put('/CacheItems/key-does-not-exist/expire')
.send({ ttl: 10 }) .send({ttl: 10})
.expect(404, done); .expect(404, done);
}); });
@ -138,7 +139,7 @@ describe('KeyValueModel', function() {
}); });
function setupAppAndCacheItem() { function setupAppAndCacheItem() {
app = loopback({ localRegistry: true, loadBuiltinModels: true }); app = loopback({localRegistry: true, loadBuiltinModels: true});
app.use(loopback.rest()); app.use(loopback.rest());
CacheItem = app.registry.createModel({ CacheItem = app.registry.createModel({
@ -146,8 +147,8 @@ describe('KeyValueModel', function() {
base: 'KeyValueModel', base: 'KeyValueModel',
}); });
app.dataSource('kv', { connector: 'kv-memory' }); app.dataSource('kv', {connector: 'kv-memory'});
app.model(CacheItem, { dataSource: 'kv' }); app.model(CacheItem, {dataSource: 'kv'});
} }
var _server, _requestHandler; // eslint-disable-line one-var var _server, _requestHandler; // eslint-disable-line one-var

View File

@ -3,6 +3,7 @@
// This file is licensed under the MIT License. // This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT // License text available at https://opensource.org/licenses/MIT
'use strict';
var it = require('./util/it'); var it = require('./util/it');
var describe = require('./util/describe'); var describe = require('./util/describe');
var Domain = require('domain'); var Domain = require('domain');
@ -61,8 +62,6 @@ describe('loopback', function() {
'User', 'User',
'ValidationError', 'ValidationError',
'application', 'application',
'arguments',
'caller',
'configureModel', 'configureModel',
'context', 'context',
'createContext', 'createContext',
@ -106,17 +105,17 @@ describe('loopback', function() {
describe('loopback(options)', function() { describe('loopback(options)', function() {
it('supports localRegistry:true', function() { it('supports localRegistry:true', function() {
var app = loopback({ localRegistry: true }); var app = loopback({localRegistry: true});
expect(app.registry).to.not.equal(loopback.registry); expect(app.registry).to.not.equal(loopback.registry);
}); });
it('does not load builtin models into the local registry', function() { it('does not load builtin models into the local registry', function() {
var app = loopback({ localRegistry: true }); var app = loopback({localRegistry: true});
expect(app.registry.findModel('User')).to.equal(undefined); expect(app.registry.findModel('User')).to.equal(undefined);
}); });
it('supports loadBuiltinModels:true', function() { it('supports loadBuiltinModels:true', function() {
var app = loopback({ localRegistry: true, loadBuiltinModels: true }); var app = loopback({localRegistry: true, loadBuiltinModels: true});
expect(app.registry.findModel('User')) expect(app.registry.findModel('User'))
.to.have.property('modelName', 'User'); .to.have.property('modelName', 'User');
}); });
@ -150,7 +149,7 @@ describe('loopback', function() {
describe('loopback.remoteMethod(Model, fn, [options]);', function() { describe('loopback.remoteMethod(Model, fn, [options]);', function() {
it('Setup a remote method.', function() { it('Setup a remote method.', function() {
var Product = loopback.createModel('product', { price: Number }); var Product = loopback.createModel('product', {price: Number});
Product.stats = function(fn) { Product.stats = function(fn) {
// ... // ...
@ -159,8 +158,8 @@ describe('loopback', function() {
loopback.remoteMethod( loopback.remoteMethod(
Product.stats, Product.stats,
{ {
returns: { arg: 'stats', type: 'array' }, returns: {arg: 'stats', type: 'array'},
http: { path: '/info', verb: 'get' }, http: {path: '/info', verb: 'get'},
} }
); );
@ -187,7 +186,7 @@ describe('loopback', function() {
}, },
}); });
assert(MyCustomModel.super_ === MyModel); assert(MyCustomModel.super_ === MyModel);
assert.deepEqual(MyCustomModel.settings.foo, { bar: 'bat', bat: 'baz' }); assert.deepEqual(MyCustomModel.settings.foo, {bar: 'bat', bat: 'baz'});
assert(MyCustomModel.super_.modelName === MyModel.modelName); assert(MyCustomModel.super_.modelName === MyModel.modelName);
}); });
}); });
@ -237,11 +236,11 @@ describe('loopback', function() {
methods: { methods: {
staticMethod: { staticMethod: {
isStatic: true, isStatic: true,
http: { path: '/static' }, http: {path: '/static'},
}, },
instanceMethod: { instanceMethod: {
isStatic: false, isStatic: false,
http: { path: '/instance' }, http: {path: '/instance'},
}, },
}, },
}); });
@ -331,7 +330,7 @@ describe('loopback', function() {
}); });
it('updates relations before attaching to a dataSource', function() { it('updates relations before attaching to a dataSource', function() {
var db = loopback.createDataSource({ connector: loopback.Memory }); var db = loopback.createDataSource({connector: loopback.Memory});
var model = loopback.Model.extend(uniqueModelName); var model = loopback.Model.extend(uniqueModelName);
// This test used to work because User model was already attached // This test used to work because User model was already attached
@ -471,11 +470,11 @@ describe('loopback', function() {
methods: { methods: {
staticMethod: { staticMethod: {
isStatic: true, isStatic: true,
http: { path: '/static' }, http: {path: '/static'},
}, },
instanceMethod: { instanceMethod: {
isStatic: false, isStatic: false,
http: { path: '/instance' }, http: {path: '/instance'},
}, },
}, },
}); });
@ -535,7 +534,7 @@ describe('loopback', function() {
dataSource: null, dataSource: null,
methods: { methods: {
staticMethod: { staticMethod: {
http: { path: '/static' }, http: {path: '/static'},
}, },
}, },
}); });
@ -551,7 +550,7 @@ describe('loopback', function() {
dataSource: null, dataSource: null,
methods: { methods: {
'prototype.instanceMethod': { 'prototype.instanceMethod': {
http: { path: '/instance' }, http: {path: '/instance'},
}, },
}, },
}); });
@ -569,7 +568,7 @@ describe('loopback', function() {
methods: { methods: {
'prototype.instanceMethod': { 'prototype.instanceMethod': {
isStatic: true, isStatic: true,
http: { path: '/instance' }, http: {path: '/instance'},
}, },
}, },
}); });
@ -584,7 +583,7 @@ describe('loopback', function() {
methods: { methods: {
staticMethod: { staticMethod: {
isStatic: true, isStatic: true,
http: { path: '/static' }, http: {path: '/static'},
}, },
}, },
}); });
@ -601,7 +600,7 @@ describe('loopback', function() {
methods: { methods: {
'prototype.instanceMethod': { 'prototype.instanceMethod': {
isStatic: false, isStatic: false,
http: { path: '/instance' }, http: {path: '/instance'},
}, },
}, },
}); });
@ -621,7 +620,7 @@ describe('loopback', function() {
var Base = app.registry.createModel('Base', {}, { var Base = app.registry.createModel('Base', {}, {
methods: { methods: {
greet: { greet: {
http: { path: '/greet' }, http: {path: '/greet'},
}, },
}, },
}); });
@ -630,7 +629,7 @@ describe('loopback', function() {
base: 'Base', base: 'Base',
methods: { methods: {
hello: { hello: {
http: { path: '/hello' }, http: {path: '/hello'},
}, },
}, },
}); });
@ -644,7 +643,7 @@ describe('loopback', function() {
var Base = app.registry.createModel('Base', {}, { var Base = app.registry.createModel('Base', {}, {
methods: { methods: {
greet: { greet: {
http: { path: '/greet' }, http: {path: '/greet'},
}, },
}, },
}); });
@ -653,7 +652,7 @@ describe('loopback', function() {
base: 'Base', base: 'Base',
methods: { methods: {
greet: { greet: {
http: { path: '/hello' }, http: {path: '/hello'},
}, },
}, },
}); });
@ -662,13 +661,13 @@ describe('loopback', function() {
var customMethod = MyCustomModel.sharedClass.findMethodByName('greet'); var customMethod = MyCustomModel.sharedClass.findMethodByName('greet');
// Base Method // Base Method
expect(baseMethod.http).to.eql({ path: '/greet' }); expect(baseMethod.http).to.eql({path: '/greet'});
expect(baseMethod.http.path).to.equal('/greet'); expect(baseMethod.http.path).to.equal('/greet');
expect(baseMethod.http.path).to.not.equal('/hello'); expect(baseMethod.http.path).to.not.equal('/hello');
// Custom Method // Custom Method
expect(methodNames).to.include('greet'); expect(methodNames).to.include('greet');
expect(customMethod.http).to.eql({ path: '/hello' }); expect(customMethod.http).to.eql({path: '/hello'});
expect(customMethod.http.path).to.equal('/hello'); expect(customMethod.http.path).to.equal('/hello');
expect(customMethod.http.path).to.not.equal('/greet'); expect(customMethod.http.path).to.not.equal('/greet');
}); });
@ -679,7 +678,7 @@ describe('loopback', function() {
dataSource: null, dataSource: null,
methods: { methods: {
greet: { greet: {
http: { path: '/greet' }, http: {path: '/greet'},
}, },
}, },
}); });
@ -688,7 +687,7 @@ describe('loopback', function() {
base: 'Base', base: 'Base',
methods: { methods: {
hello: { hello: {
http: { path: '/hello' }, http: {path: '/hello'},
}, },
}, },
}); });
@ -709,7 +708,7 @@ describe('loopback', function() {
dataSource: null, dataSource: null,
methods: { methods: {
greet: { greet: {
http: { path: '/greet' }, http: {path: '/greet'},
}, },
}, },
}); });
@ -718,7 +717,7 @@ describe('loopback', function() {
dataSource: null, dataSource: null,
methods: { methods: {
hello: { hello: {
http: { path: '/hello' }, http: {path: '/hello'},
}, },
}, },
}); });
@ -731,7 +730,7 @@ describe('loopback', function() {
}); });
function setupLoopback() { function setupLoopback() {
app = loopback({ localRegistry: true }); app = loopback({localRegistry: true});
} }
function getAllMethodNamesWithoutClassName(Model) { function getAllMethodNamesWithoutClassName(Model) {

View File

@ -3,6 +3,10 @@
// This file is licensed under the MIT License. // This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT // License text available at https://opensource.org/licenses/MIT
'use strict';
var assert = require('assert');
var loopback = require('../');
describe('Memory Connector', function() { describe('Memory Connector', function() {
it('Create a model using the memory connector', function(done) { it('Create a model using the memory connector', function(done) {
// use the built in memory function // use the built in memory function
@ -25,9 +29,9 @@ describe('Memory Connector', function() {
var Product = memory.createModel('product', properties); var Product = memory.createModel('product', properties);
Product.create([ Product.create([
{ name: 'apple', price: 0.79 }, {name: 'apple', price: 0.79},
{ name: 'pear', price: 1.29 }, {name: 'pear', price: 1.29},
{ name: 'orange', price: 0.59 }, {name: 'orange', price: 0.59},
], count); ], count);
function count() { function count() {

View File

@ -1 +0,0 @@
--require ./test/support.js

View File

@ -3,6 +3,7 @@
// This file is licensed under the MIT License. // This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT // License text available at https://opensource.org/licenses/MIT
'use strict';
var loopback = require(('../')); var loopback = require(('../'));
var assert = require('assert'); var assert = require('assert');
var Application = loopback.Application; var Application = loopback.Application;
@ -16,7 +17,7 @@ describe('Application', function() {
it('honors `application.register` - promise variant', function(done) { it('honors `application.register` - promise variant', function(done) {
Application.register('rfeng', 'MyTestApp', Application.register('rfeng', 'MyTestApp',
{ description: 'My test application' }, function(err, result) { {description: 'My test application'}, function(err, result) {
var app = result; var app = result;
assert.equal(app.owner, 'rfeng'); assert.equal(app.owner, 'rfeng');
assert.equal(app.name, 'MyTestApp'); assert.equal(app.name, 'MyTestApp');
@ -28,7 +29,7 @@ describe('Application', function() {
it('honors `application.register` - promise variant', function(done) { it('honors `application.register` - promise variant', function(done) {
Application.register('rfeng', 'MyTestApp', Application.register('rfeng', 'MyTestApp',
{ description: 'My test application' }) {description: 'My test application'})
.then(function(result) { .then(function(result) {
var app = result; var app = result;
assert.equal(app.owner, 'rfeng'); assert.equal(app.owner, 'rfeng');
@ -43,9 +44,9 @@ describe('Application', function() {
}); });
it('Create a new application', function(done) { it('Create a new application', function(done) {
Application.create({ owner: 'rfeng', Application.create({owner: 'rfeng',
name: 'MyApp1', name: 'MyApp1',
description: 'My first mobile application' }, function(err, result) { description: 'My first mobile application'}, function(err, result) {
var app = result; var app = result;
assert.equal(app.owner, 'rfeng'); assert.equal(app.owner, 'rfeng');
assert.equal(app.name, 'MyApp1'); assert.equal(app.name, 'MyApp1');
@ -64,7 +65,7 @@ describe('Application', function() {
}); });
it('Create a new application with push settings', function(done) { it('Create a new application with push settings', function(done) {
Application.create({ owner: 'rfeng', Application.create({owner: 'rfeng',
name: 'MyAppWithPush', name: 'MyAppWithPush',
description: 'My push mobile application', description: 'My push mobile application',
pushSettings: { pushSettings: {
@ -116,7 +117,7 @@ describe('Application', function() {
beforeEach(function(done) { beforeEach(function(done) {
Application.register('rfeng', 'MyApp2', Application.register('rfeng', 'MyApp2',
{ description: 'My second mobile application' }, function(err, result) { {description: 'My second mobile application'}, function(err, result) {
var app = result; var app = result;
assert.equal(app.owner, 'rfeng'); assert.equal(app.owner, 'rfeng');
assert.equal(app.name, 'MyApp2'); assert.equal(app.name, 'MyApp2');
@ -306,10 +307,10 @@ describe('Application', function() {
describe('Application subclass', function() { describe('Application subclass', function() {
it('should use subclass model name', function(done) { it('should use subclass model name', function(done) {
var MyApp = Application.extend('MyApp'); var MyApp = Application.extend('MyApp');
var ds = loopback.createDataSource({ connector: loopback.Memory }); var ds = loopback.createDataSource({connector: loopback.Memory});
MyApp.attachTo(ds); MyApp.attachTo(ds);
MyApp.register('rfeng', 'MyApp123', MyApp.register('rfeng', 'MyApp123',
{ description: 'My 123 mobile application' }, function(err, result) { {description: 'My 123 mobile application'}, function(err, result) {
var app = result; var app = result;
assert.equal(app.owner, 'rfeng'); assert.equal(app.owner, 'rfeng');
assert.equal(app.name, 'MyApp123'); assert.equal(app.name, 'MyApp123');

View File

@ -3,6 +3,8 @@
// This file is licensed under the MIT License. // This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT // License text available at https://opensource.org/licenses/MIT
'use strict';
var assert = require('assert');
var async = require('async'); var async = require('async');
var chai = require('chai'); var chai = require('chai');
var describe = require('./util/describe'); var describe = require('./util/describe');
@ -11,6 +13,9 @@ var ACL = loopback.ACL;
var defineModelTestsWithDataSource = require('./util/model-tests'); var defineModelTestsWithDataSource = require('./util/model-tests');
var PersistedModel = loopback.PersistedModel; var PersistedModel = loopback.PersistedModel;
var sinonChai = require('sinon-chai'); var sinonChai = require('sinon-chai');
var Promise = require('bluebird');
var TaskEmitter = require('strong-task-emitter');
var request = require('supertest');
var expect = chai.expect; var expect = chai.expect;
chai.use(sinonChai); chai.use(sinonChai);
@ -40,10 +45,10 @@ describe('Model / PersistedModel', function() {
User.attachTo(dataSource); User.attachTo(dataSource);
User.validatesUniquenessOf('email', { message: 'email is not unique' }); User.validatesUniquenessOf('email', {message: 'email is not unique'});
var joe = new User({ email: 'joe@joe.com' }); var joe = new User({email: 'joe@joe.com'});
var joe2 = new User({ email: 'joe@joe.com' }); var joe2 = new User({email: 'joe@joe.com'});
joe.save(function() { joe.save(function() {
joe2.save(function(err) { joe2.save(function(err) {
@ -58,7 +63,7 @@ describe('Model / PersistedModel', function() {
describe('Model.attachTo(dataSource)', function() { describe('Model.attachTo(dataSource)', function() {
it('Attach a model to a [DataSource](#data-source)', function() { it('Attach a model to a [DataSource](#data-source)', function() {
var MyModel = loopback.createModel('my-model', { name: String }); var MyModel = loopback.createModel('my-model', {name: String});
var dataSource = loopback.createDataSource({ var dataSource = loopback.createDataSource({
connector: loopback.Memory, connector: loopback.Memory,
}); });
@ -77,11 +82,11 @@ describe.onServer('Remote Methods', function() {
var User, Post, dataSource, app; var User, Post, dataSource, app;
beforeEach(function() { beforeEach(function() {
app = loopback({ localRegistry: true, loadBuiltinModels: true }); app = loopback({localRegistry: true, loadBuiltinModels: true});
app.set('remoting', { errorHandler: { debug: true, log: false }}); app.set('remoting', {errorHandler: {debug: true, log: false}});
User = app.registry.createModel('user', { User = app.registry.createModel('user', {
id: { id: true, type: String, defaultFn: 'guid' }, id: {id: true, type: String, defaultFn: 'guid'},
'first': String, 'first': String,
'last': String, 'last': String,
'age': Number, 'age': Number,
@ -94,17 +99,17 @@ describe.onServer('Remote Methods', function() {
}); });
Post = app.registry.createModel('post', { Post = app.registry.createModel('post', {
id: { id: true, type: String, defaultFn: 'guid' }, id: {id: true, type: String, defaultFn: 'guid'},
title: String, title: String,
content: String, content: String,
}, { }, {
trackChanges: true, trackChanges: true,
}); });
dataSource = app.dataSource('db', { connector: 'memory' }); dataSource = app.dataSource('db', {connector: 'memory'});
app.model(User, { dataSource: 'db' }); app.model(User, {dataSource: 'db'});
app.model(Post, { dataSource: 'db' }); app.model(Post, {dataSource: 'db'});
User.hasMany(Post); User.hasMany(Post);
@ -118,11 +123,11 @@ describe.onServer('Remote Methods', function() {
User.remoteMethod('login', { User.remoteMethod('login', {
accepts: [ accepts: [
{ arg: 'username', type: 'string', required: true }, {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 }, returns: {arg: 'sessionId', type: 'any', root: true},
http: { path: '/sign-in', verb: 'get' }, http: {path: '/sign-in', verb: 'get'},
}); });
app.use(loopback.rest()); app.use(loopback.rest());
@ -130,7 +135,7 @@ describe.onServer('Remote Methods', function() {
describe('Model.create(data, callback)', function() { describe('Model.create(data, callback)', function() {
it('creates model', function(done) { it('creates model', function(done) {
var anObject = { first: 'June' }; var anObject = {first: 'June'};
request(app) request(app)
.post('/users') .post('/users')
// sends an object // sends an object
@ -148,7 +153,7 @@ describe.onServer('Remote Methods', function() {
// coercion being done on strong-remoting side // coercion being done on strong-remoting side
it('creates array of models', function(done) { it('creates array of models', function(done) {
var arrayOfObjects = [ var arrayOfObjects = [
{ first: 'John' }, { first: 'Jane' }, {first: 'John'}, {first: 'Jane'},
]; ];
request(app) request(app)
.post('/users') .post('/users')
@ -169,11 +174,11 @@ describe.onServer('Remote Methods', function() {
describe('Model.destroyAll(callback)', function() { describe('Model.destroyAll(callback)', function() {
it('Delete all Model instances from data source', function(done) { it('Delete all Model instances from data source', function(done) {
(new TaskEmitter()) (new TaskEmitter())
.task(User, 'create', { first: 'jill' }) .task(User, 'create', {first: 'jill'})
.task(User, 'create', { first: 'bob' }) .task(User, 'create', {first: 'bob'})
.task(User, 'create', { first: 'jan' }) .task(User, 'create', {first: 'jan'})
.task(User, 'create', { first: 'sam' }) .task(User, 'create', {first: 'sam'})
.task(User, 'create', { first: 'suzy' }) .task(User, 'create', {first: 'suzy'})
.on('done', function() { .on('done', function() {
User.count(function(err, count) { User.count(function(err, count) {
User.destroyAll(function() { User.destroyAll(function() {
@ -192,10 +197,10 @@ describe.onServer('Remote Methods', function() {
it('Updates when a Model instance is retreived from data source', function(done) { it('Updates when a Model instance is retreived from data source', function(done) {
var taskEmitter = new TaskEmitter(); var taskEmitter = new TaskEmitter();
taskEmitter taskEmitter
.task(User, 'create', { first: 'jill', second: 'pill' }) .task(User, 'create', {first: 'jill', second: 'pill'})
.task(User, 'create', { first: 'bob', second: 'sob' }) .task(User, 'create', {first: 'bob', second: 'sob'})
.on('done', function() { .on('done', function() {
User.upsertWithWhere({ second: 'pill' }, { second: 'jones' }, function(err, user) { User.upsertWithWhere({second: 'pill'}, {second: 'jones'}, function(err, user) {
if (err) return done(err); if (err) return done(err);
var id = user.id; var id = user.id;
User.findById(id, function(err, user) { User.findById(id, function(err, user) {
@ -210,9 +215,9 @@ describe.onServer('Remote Methods', function() {
it('Creates when no Model instance is retreived from data source', function(done) { it('Creates when no Model instance is retreived from data source', function(done) {
var taskEmitter = new TaskEmitter(); var taskEmitter = new TaskEmitter();
taskEmitter taskEmitter
.task(User, 'create', { first: 'simon', second: 'somers' }) .task(User, 'create', {first: 'simon', second: 'somers'})
.on('done', function() { .on('done', function() {
User.upsertWithWhere({ first: 'somers' }, { first: 'Simon' }, function(err, user) { User.upsertWithWhere({first: 'somers'}, {first: 'Simon'}, function(err, user) {
if (err) return done(err); if (err) return done(err);
var id = user.id; var id = user.id;
User.findById(id, function(err, user) { User.findById(id, function(err, user) {
@ -258,7 +263,7 @@ describe.onServer('Remote Methods', function() {
it('Call the findById with filter.fields using HTTP / REST', function(done) { it('Call the findById with filter.fields using HTTP / REST', function(done) {
request(app) request(app)
.post('/users') .post('/users')
.send({ first: 'x', last: 'y' }) .send({first: 'x', last: 'y'})
.expect('Content-Type', /json/) .expect('Content-Type', /json/)
.expect(200) .expect(200)
.end(function(err, res) { .end(function(err, res) {
@ -284,7 +289,7 @@ describe.onServer('Remote Methods', function() {
it('Call the findById with filter.include using HTTP / REST', function(done) { it('Call the findById with filter.include using HTTP / REST', function(done) {
request(app) request(app)
.post('/users') .post('/users')
.send({ first: 'x', last: 'y' }) .send({first: 'x', last: 'y'})
.expect('Content-Type', /json/) .expect('Content-Type', /json/)
.expect(200) .expect(200)
.end(function(err, res) { .end(function(err, res) {
@ -294,7 +299,7 @@ describe.onServer('Remote Methods', function() {
assert(userId); assert(userId);
request(app) request(app)
.post('/users/' + userId + '/posts') .post('/users/' + userId + '/posts')
.send({ title: 'T1', content: 'C1' }) .send({title: 'T1', content: 'C1'})
.expect('Content-Type', /json/) .expect('Content-Type', /json/)
.expect(200) .expect(200)
.end(function(err, res) { .end(function(err, res) {
@ -332,7 +337,7 @@ describe.onServer('Remote Methods', function() {
// invoke save // invoke save
request(app) request(app)
.post('/users') .post('/users')
.send({ data: { first: 'foo', last: 'bar' }}) .send({data: {first: 'foo', last: 'bar'}})
.expect('Content-Type', /json/) .expect('Content-Type', /json/)
.expect(200) .expect(200)
.end(function(err, res) { .end(function(err, res) {
@ -360,7 +365,7 @@ describe.onServer('Remote Methods', function() {
// invoke save // invoke save
request(app) request(app)
.post('/users') .post('/users')
.send({ data: { first: 'foo', last: 'bar' }}) .send({data: {first: 'foo', last: 'bar'}})
.expect('Content-Type', /json/) .expect('Content-Type', /json/)
.expect(200) .expect(200)
.end(function(err, res) { .end(function(err, res) {
@ -392,7 +397,7 @@ describe.onServer('Remote Methods', function() {
// invoke save // invoke save
request(app) request(app)
.post('/users') .post('/users')
.send({ data: { first: 'foo', last: 'bar' }}) .send({data: {first: 'foo', last: 'bar'}})
.expect('Content-Type', /json/) .expect('Content-Type', /json/)
.expect(200) .expect(200)
.end(function(err, res) { .end(function(err, res) {
@ -447,7 +452,7 @@ describe.onServer('Remote Methods', function() {
// invoke save // invoke save
request(app) request(app)
.post('/users') .post('/users')
.send({ data: { first: 'foo', last: 'bar' }}) .send({data: {first: 'foo', last: 'bar'}})
.expect('Content-Type', /json/) .expect('Content-Type', /json/)
.expect(200) .expect(200)
.end(function(err, res) { .end(function(err, res) {
@ -479,7 +484,7 @@ describe.onServer('Remote Methods', function() {
// invoke save // invoke save
request(app) request(app)
.post('/users') .post('/users')
.send({ data: { first: 'foo', last: 'bar' }}) .send({data: {first: 'foo', last: 'bar'}})
.expect('Content-Type', /json/) .expect('Content-Type', /json/)
.expect(200) .expect(200)
.end(function(err, res) { .end(function(err, res) {
@ -495,20 +500,20 @@ describe.onServer('Remote Methods', function() {
describe('Model.hasMany(Model)', function() { describe('Model.hasMany(Model)', function() {
it('Define a one to many relationship', function(done) { it('Define a one to many relationship', function(done) {
var Book = dataSource.createModel('book', { title: String, author: String }); var Book = dataSource.createModel('book', {title: String, author: String});
var Chapter = dataSource.createModel('chapter', { title: String }); var Chapter = dataSource.createModel('chapter', {title: String});
// by referencing model // by referencing model
Book.hasMany(Chapter); Book.hasMany(Chapter);
Book.create({ title: 'Into the Wild', author: 'Jon Krakauer' }, function(err, book) { Book.create({title: 'Into the Wild', author: 'Jon Krakauer'}, function(err, book) {
// using 'chapters' scope for build: // using 'chapters' scope for build:
var c = book.chapters.build({ title: 'Chapter 1' }); var c = book.chapters.build({title: 'Chapter 1'});
book.chapters.create({ title: 'Chapter 2' }, function() { book.chapters.create({title: 'Chapter 2'}, function() {
c.save(function() { c.save(function() {
Chapter.count({ bookId: book.id }, function(err, count) { Chapter.count({bookId: book.id}, function(err, count) {
assert.equal(count, 2); assert.equal(count, 2);
book.chapters({ where: { title: 'Chapter 1' }}, function(err, chapters) { book.chapters({where: {title: 'Chapter 1'}}, function(err, chapters) {
assert.equal(chapters.length, 1); assert.equal(chapters.length, 1);
assert.equal(chapters[0].title, 'Chapter 1'); assert.equal(chapters[0].title, 'Chapter 1');
@ -525,8 +530,8 @@ describe.onServer('Remote Methods', function() {
it('Normalized properties passed in originally by loopback.createModel()', function() { it('Normalized properties passed in originally by loopback.createModel()', function() {
var props = { var props = {
s: String, s: String,
n: { type: 'Number' }, n: {type: 'Number'},
o: { type: 'String', min: 10, max: 100 }, o: {type: 'String', min: 10, max: 100},
d: Date, d: Date,
g: loopback.GeoPoint, g: loopback.GeoPoint,
}; };
@ -635,7 +640,7 @@ describe.onServer('Remote Methods', function() {
function shouldReturn(methodName, expectedAccessType) { function shouldReturn(methodName, expectedAccessType) {
describe(methodName, function() { describe(methodName, function() {
it('should return ' + expectedAccessType, function() { it('should return ' + expectedAccessType, function() {
var remoteMethod = { name: methodName }; var remoteMethod = {name: methodName};
assert.equal( assert.equal(
User._getAccessTypeForMethod(remoteMethod), User._getAccessTypeForMethod(remoteMethod),
expectedAccessType expectedAccessType
@ -712,8 +717,8 @@ describe.onServer('Remote Methods', function() {
it('includes all aliases', function() { it('includes all aliases', function() {
var app = loopback(); var app = loopback();
var model = PersistedModel.extend('PersistedModelForAliases'); var model = PersistedModel.extend('PersistedModelForAliases');
app.dataSource('db', { connector: 'memory' }); app.dataSource('db', {connector: 'memory'});
app.model(model, { dataSource: 'db' }); app.model(model, {dataSource: 'db'});
// this code is used by loopback-sdk-angular codegen // this code is used by loopback-sdk-angular codegen
var metadata = app.handler('rest') var metadata = app.handler('rest')
@ -760,8 +765,8 @@ describe.onServer('Remote Methods', function() {
it('emits a `remoteMethodDisabled` event', function() { it('emits a `remoteMethodDisabled` event', function() {
var app = loopback(); var app = loopback();
var model = PersistedModel.extend('TestModelForDisablingRemoteMethod'); var model = PersistedModel.extend('TestModelForDisablingRemoteMethod');
app.dataSource('db', { connector: 'memory' }); app.dataSource('db', {connector: 'memory'});
app.model(model, { dataSource: 'db' }); app.model(model, {dataSource: 'db'});
var callbackSpy = require('sinon').spy(); var callbackSpy = require('sinon').spy();
var TestModel = app.models.TestModelForDisablingRemoteMethod; var TestModel = app.models.TestModelForDisablingRemoteMethod;
@ -774,8 +779,8 @@ describe.onServer('Remote Methods', function() {
it('emits a `remoteMethodDisabled` event from disableRemoteMethodByName', function() { it('emits a `remoteMethodDisabled` event from disableRemoteMethodByName', function() {
var app = loopback(); var app = loopback();
var model = PersistedModel.extend('TestModelForDisablingRemoteMethod'); var model = PersistedModel.extend('TestModelForDisablingRemoteMethod');
app.dataSource('db', { connector: 'memory' }); app.dataSource('db', {connector: 'memory'});
app.model(model, { dataSource: 'db' }); app.model(model, {dataSource: 'db'});
var callbackSpy = require('sinon').spy(); var callbackSpy = require('sinon').spy();
var TestModel = app.models.TestModelForDisablingRemoteMethod; var TestModel = app.models.TestModelForDisablingRemoteMethod;
@ -791,11 +796,11 @@ describe.onServer('Remote Methods', function() {
beforeEach(function setup() { beforeEach(function setup() {
app = loopback(); app = loopback();
TestModel = loopback.createModel('TestModelForGetApp'); // unique name TestModel = loopback.createModel('TestModelForGetApp'); // unique name
app.dataSource('db', { connector: 'memory' }); app.dataSource('db', {connector: 'memory'});
}); });
it('calls the callback when already attached', function(done) { it('calls the callback when already attached', function(done) {
app.model(TestModel, { dataSource: 'db' }); app.model(TestModel, {dataSource: 'db'});
TestModel.getApp(function(err, a) { TestModel.getApp(function(err, a) {
if (err) return done(err); if (err) return done(err);
@ -814,7 +819,7 @@ describe.onServer('Remote Methods', function() {
done(); done();
}); });
app.model(TestModel, { dataSource: 'db' }); app.model(TestModel, {dataSource: 'db'});
// fails on time-out when not implemented correctly // fails on time-out when not implemented correctly
}); });
}); });

View File

@ -3,12 +3,17 @@
// This file is licensed under the MIT License. // This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT // License text available at https://opensource.org/licenses/MIT
'use strict';
var assert = require('assert');
var expect = require('chai').expect;
var loopback = require('../');
describe('Registry', function() { describe('Registry', function() {
describe('createModel', function() { describe('createModel', function() {
it('should throw error upon extending non-exist base model', function() { it('should throw error upon extending non-exist base model', function() {
var app = loopback(); var app = loopback();
var props = {}; var props = {};
var opts = { base: 'nonexistent' }; var opts = {base: 'nonexistent'};
expect(function() { app.registry.createModel('aModel', props, opts); }) expect(function() { app.registry.createModel('aModel', props, opts); })
.to.throw(/model\s`aModel`(.*)unknown\smodel\s`nonexistent`/); .to.throw(/model\s`aModel`(.*)unknown\smodel\s`nonexistent`/);
}); });
@ -20,32 +25,32 @@ describe('Registry', function() {
var appBar = loopback(); var appBar = loopback();
var modelName = 'MyModel'; var modelName = 'MyModel';
var subModelName = 'Sub' + modelName; var subModelName = 'Sub' + modelName;
var settings = { base: 'PersistedModel' }; var settings = {base: 'PersistedModel'};
appFoo.set('perAppRegistries', true); appFoo.set('perAppRegistries', true);
appBar.set('perAppRegistries', true); appBar.set('perAppRegistries', true);
var dsFoo = appFoo.dataSource('dsFoo', { connector: 'memory' }); var dsFoo = appFoo.dataSource('dsFoo', {connector: 'memory'});
var dsBar = appFoo.dataSource('dsBar', { connector: 'memory' }); var dsBar = appFoo.dataSource('dsBar', {connector: 'memory'});
var FooModel = appFoo.registry.createModel(modelName, {}, settings); var FooModel = appFoo.registry.createModel(modelName, {}, settings);
appFoo.model(FooModel, { dataSource: dsFoo }); appFoo.model(FooModel, {dataSource: dsFoo});
var FooSubModel = appFoo.registry.createModel(subModelName, {}, settings); var FooSubModel = appFoo.registry.createModel(subModelName, {}, settings);
appFoo.model(FooSubModel, { dataSource: dsFoo }); appFoo.model(FooSubModel, {dataSource: dsFoo});
var BarModel = appBar.registry.createModel(modelName, {}, settings); var BarModel = appBar.registry.createModel(modelName, {}, settings);
appBar.model(BarModel, { dataSource: dsBar }); appBar.model(BarModel, {dataSource: dsBar});
var BarSubModel = appBar.registry.createModel(subModelName, {}, settings); var BarSubModel = appBar.registry.createModel(subModelName, {}, settings);
appBar.model(BarSubModel, { dataSource: dsBar }); appBar.model(BarSubModel, {dataSource: dsBar});
FooModel.hasMany(FooSubModel); FooModel.hasMany(FooSubModel);
BarModel.hasMany(BarSubModel); BarModel.hasMany(BarSubModel);
expect(appFoo.models[modelName]).to.not.equal(appBar.models[modelName]); expect(appFoo.models[modelName]).to.not.equal(appBar.models[modelName]);
BarModel.create({ name: 'bar' }, function(err, bar) { BarModel.create({name: 'bar'}, function(err, bar) {
assert(!err); assert(!err);
bar.subMyModels.create({ parent: 'bar' }, function(err) { bar.subMyModels.create({parent: 'bar'}, function(err) {
assert(!err); assert(!err);
FooSubModel.find(function(err, foos) { FooSubModel.find(function(err, foos) {
assert(!err); assert(!err);

View File

@ -3,6 +3,7 @@
// This file is licensed under the MIT License. // This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT // License text available at https://opensource.org/licenses/MIT
'use strict';
var loopback = require('../'); var loopback = require('../');
var lt = require('./helpers/loopback-testing-helper'); var lt = require('./helpers/loopback-testing-helper');
var path = require('path'); var path = require('path');
@ -31,22 +32,22 @@ describe('relations - integration', function() {
describe('polymorphicHasMany', function() { describe('polymorphicHasMany', function() {
before(function defineProductAndCategoryModels() { before(function defineProductAndCategoryModels() {
var Team = app.registry.createModel('Team', { name: 'string' }); var Team = app.registry.createModel('Team', {name: 'string'});
var Reader = app.registry.createModel('Reader', { name: 'string' }); var Reader = app.registry.createModel('Reader', {name: 'string'});
var Picture = app.registry.createModel('Picture', var Picture = app.registry.createModel('Picture',
{ name: 'string', imageableId: 'number', imageableType: 'string' }); {name: 'string', imageableId: 'number', imageableType: 'string'});
app.model(Team, { dataSource: 'db' }); app.model(Team, {dataSource: 'db'});
app.model(Reader, { dataSource: 'db' }); app.model(Reader, {dataSource: 'db'});
app.model(Picture, { dataSource: 'db' }); app.model(Picture, {dataSource: 'db'});
Reader.hasMany(Picture, { polymorphic: { // alternative syntax Reader.hasMany(Picture, {polymorphic: { // alternative syntax
as: 'imageable', // if not set, default to: reference as: 'imageable', // if not set, default to: reference
foreignKey: 'imageableId', // defaults to 'as + Id' foreignKey: 'imageableId', // defaults to 'as + Id'
discriminator: 'imageableType', // defaults to 'as + Type' discriminator: 'imageableType', // defaults to 'as + Type'
}}); }});
Picture.belongsTo('imageable', { polymorphic: { Picture.belongsTo('imageable', {polymorphic: {
foreignKey: 'imageableId', foreignKey: 'imageableId',
discriminator: 'imageableType', discriminator: 'imageableType',
}}); }});
@ -56,18 +57,18 @@ describe('relations - integration', function() {
before(function createEvent(done) { before(function createEvent(done) {
var test = this; var test = this;
app.models.Team.create({ name: 'Team 1' }, app.models.Team.create({name: 'Team 1'},
function(err, team) { function(err, team) {
if (err) return done(err); if (err) return done(err);
test.team = team; test.team = team;
app.models.Reader.create({ name: 'Reader 1' }, app.models.Reader.create({name: 'Reader 1'},
function(err, reader) { function(err, reader) {
if (err) return done(err); if (err) return done(err);
test.reader = reader; test.reader = reader;
reader.pictures.create({ name: 'Picture 1' }); reader.pictures.create({name: 'Picture 1'});
reader.pictures.create({ name: 'Picture 2' }); reader.pictures.create({name: 'Picture 2'});
reader.team(test.team); reader.team(test.team);
reader.save(done); reader.save(done);
}); });
@ -82,14 +83,14 @@ describe('relations - integration', function() {
it('includes the related child model', function(done) { it('includes the related child model', function(done) {
var url = '/api/readers/' + this.reader.id; var url = '/api/readers/' + this.reader.id;
this.get(url) this.get(url)
.query({ 'filter': { 'include': 'pictures' }}) .query({'filter': {'include': 'pictures'}})
.expect(200, function(err, res) { .expect(200, function(err, res) {
if (err) return done(err); if (err) return done(err);
expect(res.body.name).to.be.equal('Reader 1'); expect(res.body.name).to.be.equal('Reader 1');
expect(res.body.pictures).to.be.eql([ expect(res.body.pictures).to.be.eql([
{ name: 'Picture 1', id: 1, imageableId: 1, imageableType: 'Reader' }, {name: 'Picture 1', id: 1, imageableId: 1, imageableType: 'Reader'},
{ name: 'Picture 2', id: 2, imageableId: 1, imageableType: 'Reader' }, {name: 'Picture 2', id: 2, imageableId: 1, imageableType: 'Reader'},
]); ]);
done(); done();
@ -99,13 +100,13 @@ describe('relations - integration', function() {
it('includes the related parent model', function(done) { it('includes the related parent model', function(done) {
var url = '/api/pictures'; var url = '/api/pictures';
this.get(url) this.get(url)
.query({ 'filter': { 'include': 'imageable' }}) .query({'filter': {'include': 'imageable'}})
.expect(200, function(err, res) { .expect(200, function(err, res) {
if (err) return done(err); if (err) return done(err);
expect(res.body[0].name).to.be.equal('Picture 1'); expect(res.body[0].name).to.be.equal('Picture 1');
expect(res.body[1].name).to.be.equal('Picture 2'); expect(res.body[1].name).to.be.equal('Picture 2');
expect(res.body[0].imageable).to.be.eql({ name: 'Reader 1', id: 1, teamId: 1 }); expect(res.body[0].imageable).to.be.eql({name: 'Reader 1', id: 1, teamId: 1});
done(); done();
}); });
@ -114,9 +115,9 @@ describe('relations - integration', function() {
it('includes related models scoped to the related parent model', function(done) { it('includes related models scoped to the related parent model', function(done) {
var url = '/api/pictures'; var url = '/api/pictures';
this.get(url) this.get(url)
.query({ 'filter': { 'include': { .query({'filter': {'include': {
'relation': 'imageable', 'relation': 'imageable',
'scope': { 'include': 'team' }, 'scope': {'include': 'team'},
}}}) }}})
.expect(200, function(err, res) { .expect(200, function(err, res) {
if (err) return done(err); if (err) return done(err);
@ -124,7 +125,7 @@ describe('relations - integration', function() {
expect(res.body[0].name).to.be.equal('Picture 1'); expect(res.body[0].name).to.be.equal('Picture 1');
expect(res.body[1].name).to.be.equal('Picture 2'); expect(res.body[1].name).to.be.equal('Picture 2');
expect(res.body[0].imageable.name).to.be.eql('Reader 1'); expect(res.body[0].imageable.name).to.be.eql('Reader 1');
expect(res.body[0].imageable.team).to.be.eql({ name: 'Team 1', id: 1 }); expect(res.body[0].imageable.team).to.be.eql({name: 'Team 1', id: 1});
done(); done();
}); });
@ -239,7 +240,7 @@ describe('relations - integration', function() {
it('does not add default properties to request body', function(done) { it('does not add default properties to request body', function(done) {
var self = this; var self = this;
self.request.put(self.url) self.request.put(self.url)
.send({ active: true }) .send({active: true})
.end(function(err) { .end(function(err) {
if (err) return done(err); if (err) return done(err);
app.models.Widget.findById(self.widget.id, function(err, w) { app.models.Widget.findById(self.widget.id, function(err, w) {
@ -453,7 +454,7 @@ describe('relations - integration', function() {
}); });
var NOW = Date.now(); var NOW = Date.now();
var data = { date: new Date(NOW) }; var data = {date: new Date(NOW)};
lt.describe.whenCalledRemotely('PUT', '/api/physicians/:id/patients/rel/:fk', data, function() { lt.describe.whenCalledRemotely('PUT', '/api/physicians/:id/patients/rel/:fk', data, function() {
it('should succeed with statusCode 200', function() { it('should succeed with statusCode 200', function() {
@ -661,14 +662,14 @@ describe('relations - integration', function() {
var product = app.registry.createModel( var product = app.registry.createModel(
'product', 'product',
{ id: 'string', name: 'string' } {id: 'string', name: 'string'}
); );
var category = app.registry.createModel( var category = app.registry.createModel(
'category', 'category',
{ id: 'string', name: 'string' } {id: 'string', name: 'string'}
); );
app.model(product, { dataSource: 'db' }); app.model(product, {dataSource: 'db'});
app.model(category, { dataSource: 'db' }); app.model(category, {dataSource: 'db'});
product.hasAndBelongsToMany(category); product.hasAndBelongsToMany(category);
category.hasAndBelongsToMany(product); category.hasAndBelongsToMany(product);
@ -690,11 +691,11 @@ describe('relations - integration', function() {
}); });
beforeEach(function createAnotherCategoryAndProduct(done) { beforeEach(function createAnotherCategoryAndProduct(done) {
app.models.category.create({ name: 'another-category' }, app.models.category.create({name: 'another-category'},
function(err, cat) { function(err, cat) {
if (err) return done(err); if (err) return done(err);
cat.products.create({ name: 'another-product' }, done); cat.products.create({name: 'another-product'}, done);
}); });
}); });
@ -784,23 +785,23 @@ describe('relations - integration', function() {
describe('embedsOne', function() { describe('embedsOne', function() {
before(function defineGroupAndPosterModels() { before(function defineGroupAndPosterModels() {
var group = app.registry.createModel('group', var group = app.registry.createModel('group',
{ name: 'string' }, {name: 'string'},
{ plural: 'groups' } {plural: 'groups'}
); );
app.model(group, { dataSource: 'db' }); app.model(group, {dataSource: 'db'});
var poster = app.registry.createModel( var poster = app.registry.createModel(
'poster', 'poster',
{ url: 'string' } {url: 'string'}
); );
app.model(poster, { dataSource: 'db' }); app.model(poster, {dataSource: 'db'});
group.embedsOne(poster, { as: 'cover' }); group.embedsOne(poster, {as: 'cover'});
}); });
before(function createImage(done) { before(function createImage(done) {
var test = this; var test = this;
app.models.group.create({ name: 'Group 1' }, app.models.group.create({name: 'Group 1'},
function(err, group) { function(err, group) {
if (err) return done(err); if (err) return done(err);
@ -818,10 +819,10 @@ describe('relations - integration', function() {
var url = '/api/groups/' + this.group.id + '/cover'; var url = '/api/groups/' + this.group.id + '/cover';
this.post(url) this.post(url)
.send({ url: 'http://image.url' }) .send({url: 'http://image.url'})
.expect(200, function(err, res) { .expect(200, function(err, res) {
expect(res.body).to.be.eql( expect(res.body).to.be.eql(
{ url: 'http://image.url' } {url: 'http://image.url'}
); );
done(); done();
@ -837,7 +838,7 @@ describe('relations - integration', function() {
expect(res.body.name).to.be.equal('Group 1'); expect(res.body.name).to.be.equal('Group 1');
expect(res.body.poster).to.be.eql( expect(res.body.poster).to.be.eql(
{ url: 'http://image.url' } {url: 'http://image.url'}
); );
done(); done();
@ -852,7 +853,7 @@ describe('relations - integration', function() {
if (err) return done(err); if (err) return done(err);
expect(res.body).to.be.eql( expect(res.body).to.be.eql(
{ url: 'http://image.url' } {url: 'http://image.url'}
); );
done(); done();
@ -863,7 +864,7 @@ describe('relations - integration', function() {
var url = '/api/groups/' + this.group.id + '/cover'; var url = '/api/groups/' + this.group.id + '/cover';
this.put(url) this.put(url)
.send({ url: 'http://changed.url' }) .send({url: 'http://changed.url'})
.expect(200, function(err, res) { .expect(200, function(err, res) {
expect(res.body.url).to.be.equal('http://changed.url'); expect(res.body.url).to.be.equal('http://changed.url');
@ -879,7 +880,7 @@ describe('relations - integration', function() {
if (err) return done(err); if (err) return done(err);
expect(res.body).to.be.eql( expect(res.body).to.be.eql(
{ url: 'http://changed.url' } {url: 'http://changed.url'}
); );
done(); done();
@ -901,29 +902,29 @@ describe('relations - integration', function() {
before(function defineProductAndCategoryModels() { before(function defineProductAndCategoryModels() {
var todoList = app.registry.createModel( var todoList = app.registry.createModel(
'todoList', 'todoList',
{ name: 'string' }, {name: 'string'},
{ plural: 'todo-lists' } {plural: 'todo-lists'}
); );
app.model(todoList, { dataSource: 'db' }); app.model(todoList, {dataSource: 'db'});
var todoItem = app.registry.createModel( var todoItem = app.registry.createModel(
'todoItem', 'todoItem',
{ content: 'string' }, { forceId: false } {content: 'string'}, {forceId: false}
); );
app.model(todoItem, { dataSource: 'db' }); app.model(todoItem, {dataSource: 'db'});
todoList.embedsMany(todoItem, { as: 'items' }); todoList.embedsMany(todoItem, {as: 'items'});
}); });
before(function createTodoList(done) { before(function createTodoList(done) {
var test = this; var test = this;
app.models.todoList.create({ name: 'List A' }, app.models.todoList.create({name: 'List A'},
function(err, list) { function(err, list) {
if (err) return done(err); if (err) return done(err);
test.todoList = list; test.todoList = list;
list.items.build({ content: 'Todo 1' }); list.items.build({content: 'Todo 1'});
list.items.build({ content: 'Todo 2' }); list.items.build({content: 'Todo 2'});
list.save(done); list.save(done);
}); });
}); });
@ -941,8 +942,8 @@ describe('relations - integration', function() {
expect(res.body.name).to.be.equal('List A'); expect(res.body.name).to.be.equal('List A');
expect(res.body.todoItems).to.be.eql([ expect(res.body.todoItems).to.be.eql([
{ content: 'Todo 1', id: 1 }, {content: 'Todo 1', id: 1},
{ content: 'Todo 2', id: 2 }, {content: 'Todo 2', id: 2},
]); ]);
done(); done();
@ -957,8 +958,8 @@ describe('relations - integration', function() {
if (err) return done(err); if (err) return done(err);
expect(res.body).to.be.eql([ expect(res.body).to.be.eql([
{ content: 'Todo 1', id: 1 }, {content: 'Todo 1', id: 1},
{ content: 'Todo 2', id: 2 }, {content: 'Todo 2', id: 2},
]); ]);
done(); done();
@ -974,7 +975,7 @@ describe('relations - integration', function() {
if (err) return done(err); if (err) return done(err);
expect(res.body).to.be.eql([ expect(res.body).to.be.eql([
{ content: 'Todo 2', id: 2 }, {content: 'Todo 2', id: 2},
]); ]);
done(); done();
@ -984,10 +985,10 @@ describe('relations - integration', function() {
it('creates embedded models', function(done) { it('creates embedded models', function(done) {
var url = '/api/todo-lists/' + this.todoList.id + '/items'; var url = '/api/todo-lists/' + this.todoList.id + '/items';
var expected = { content: 'Todo 3', id: 3 }; var expected = {content: 'Todo 3', id: 3};
this.post(url) this.post(url)
.send({ content: 'Todo 3' }) .send({content: 'Todo 3'})
.expect(200, function(err, res) { .expect(200, function(err, res) {
expect(res.body).to.be.eql(expected); expect(res.body).to.be.eql(expected);
@ -1003,9 +1004,9 @@ describe('relations - integration', function() {
if (err) return done(err); if (err) return done(err);
expect(res.body).to.be.eql([ expect(res.body).to.be.eql([
{ content: 'Todo 1', id: 1 }, {content: 'Todo 1', id: 1},
{ content: 'Todo 2', id: 2 }, {content: 'Todo 2', id: 2},
{ content: 'Todo 3', id: 3 }, {content: 'Todo 3', id: 3},
]); ]);
done(); done();
@ -1020,7 +1021,7 @@ describe('relations - integration', function() {
if (err) return done(err); if (err) return done(err);
expect(res.body).to.be.eql( expect(res.body).to.be.eql(
{ content: 'Todo 3', id: 3 } {content: 'Todo 3', id: 3}
); );
done(); done();
@ -1045,8 +1046,8 @@ describe('relations - integration', function() {
if (err) return done(err); if (err) return done(err);
expect(res.body).to.be.eql([ expect(res.body).to.be.eql([
{ content: 'Todo 1', id: 1 }, {content: 'Todo 1', id: 1},
{ content: 'Todo 3', id: 3 }, {content: 'Todo 3', id: 3},
]); ]);
done(); done();
@ -1089,48 +1090,48 @@ describe('relations - integration', function() {
before(function defineProductAndCategoryModels() { before(function defineProductAndCategoryModels() {
var recipe = app.registry.createModel( var recipe = app.registry.createModel(
'recipe', 'recipe',
{ name: 'string' } {name: 'string'}
); );
app.model(recipe, { dataSource: 'db' }); app.model(recipe, {dataSource: 'db'});
var ingredient = app.registry.createModel( var ingredient = app.registry.createModel(
'ingredient', 'ingredient',
{ name: 'string' } {name: 'string'}
); );
app.model(ingredient, { dataSource: 'db' }); app.model(ingredient, {dataSource: 'db'});
var photo = app.registry.createModel( var photo = app.registry.createModel(
'photo', 'photo',
{ name: 'string' } {name: 'string'}
); );
app.model(photo, { dataSource: 'db' }); app.model(photo, {dataSource: 'db'});
recipe.referencesMany(ingredient); recipe.referencesMany(ingredient);
// contrived example for test: // contrived example for test:
recipe.hasOne(photo, { as: 'picture', options: { recipe.hasOne(photo, {as: 'picture', options: {
http: { path: 'image' }, http: {path: 'image'},
}}); }});
}); });
before(function createRecipe(done) { before(function createRecipe(done) {
var test = this; var test = this;
app.models.recipe.create({ name: 'Recipe' }, app.models.recipe.create({name: 'Recipe'},
function(err, recipe) { function(err, recipe) {
if (err) return done(err); if (err) return done(err);
test.recipe = recipe; test.recipe = recipe;
recipe.ingredients.create({ recipe.ingredients.create({
name: 'Chocolate' }, name: 'Chocolate'},
function(err, ing) { function(err, ing) {
test.ingredient1 = ing.id; test.ingredient1 = ing.id;
recipe.picture.create({ name: 'Photo 1' }, done); recipe.picture.create({name: 'Photo 1'}, done);
}); });
}); });
}); });
before(function createIngredient(done) { before(function createIngredient(done) {
var test = this; var test = this;
app.models.ingredient.create({ name: 'Sugar' }, function(err, ing) { app.models.ingredient.create({name: 'Sugar'}, function(err, ing) {
test.ingredient2 = ing.id; test.ingredient2 = ing.id;
done(); done();
@ -1166,7 +1167,7 @@ describe('relations - integration', function() {
var test = this; var test = this;
this.post(url) this.post(url)
.send({ name: 'Butter' }) .send({name: 'Butter'})
.expect(200, function(err, res) { .expect(200, function(err, res) {
expect(res.body.name).to.be.eql('Butter'); expect(res.body.name).to.be.eql('Butter');
test.ingredient3 = res.body.id; test.ingredient3 = res.body.id;
@ -1184,9 +1185,9 @@ describe('relations - integration', function() {
if (err) return done(err); if (err) return done(err);
expect(res.body).to.be.eql([ expect(res.body).to.be.eql([
{ name: 'Chocolate', id: test.ingredient1 }, {name: 'Chocolate', id: test.ingredient1},
{ name: 'Sugar', id: test.ingredient2 }, {name: 'Sugar', id: test.ingredient2},
{ name: 'Butter', id: test.ingredient3 }, {name: 'Butter', id: test.ingredient3},
]); ]);
done(); done();
@ -1202,8 +1203,8 @@ describe('relations - integration', function() {
if (err) return done(err); if (err) return done(err);
expect(res.body).to.be.eql([ expect(res.body).to.be.eql([
{ name: 'Chocolate', id: test.ingredient1 }, {name: 'Chocolate', id: test.ingredient1},
{ name: 'Butter', id: test.ingredient3 }, {name: 'Butter', id: test.ingredient3},
]); ]);
done(); done();
@ -1220,7 +1221,7 @@ describe('relations - integration', function() {
if (err) return done(err); if (err) return done(err);
expect(res.body).to.be.eql([ expect(res.body).to.be.eql([
{ name: 'Butter', id: test.ingredient3 }, {name: 'Butter', id: test.ingredient3},
]); ]);
done(); done();
@ -1240,8 +1241,8 @@ describe('relations - integration', function() {
test.ingredient1, test.ingredient3, test.ingredient1, test.ingredient3,
]); ]);
expect(res.body.ingredients).to.eql([ expect(res.body.ingredients).to.eql([
{ name: 'Chocolate', id: test.ingredient1 }, {name: 'Chocolate', id: test.ingredient1},
{ name: 'Butter', id: test.ingredient3 }, {name: 'Butter', id: test.ingredient3},
]); ]);
done(); done();
@ -1258,7 +1259,7 @@ describe('relations - integration', function() {
if (err) return done(err); if (err) return done(err);
expect(res.body).to.be.eql( expect(res.body).to.be.eql(
{ name: 'Butter', id: test.ingredient3 } {name: 'Butter', id: test.ingredient3}
); );
done(); done();
@ -1302,8 +1303,8 @@ describe('relations - integration', function() {
if (err) return done(err); if (err) return done(err);
expect(res.body).to.be.eql([ expect(res.body).to.be.eql([
{ name: 'Chocolate', id: test.ingredient1 }, {name: 'Chocolate', id: test.ingredient1},
{ name: 'Sugar', id: test.ingredient2 }, {name: 'Sugar', id: test.ingredient2},
]); ]);
done(); done();
@ -1319,7 +1320,7 @@ describe('relations - integration', function() {
if (err) return done(err); if (err) return done(err);
expect(res.body).to.be.eql([ expect(res.body).to.be.eql([
{ name: 'Chocolate', id: test.ingredient1 }, {name: 'Chocolate', id: test.ingredient1},
]); ]);
done(); done();
@ -1334,7 +1335,7 @@ describe('relations - integration', function() {
this.put(url) this.put(url)
.expect(200, function(err, res) { .expect(200, function(err, res) {
expect(res.body).to.be.eql( expect(res.body).to.be.eql(
{ name: 'Sugar', id: test.ingredient2 } {name: 'Sugar', id: test.ingredient2}
); );
done(); done();
@ -1350,8 +1351,8 @@ describe('relations - integration', function() {
if (err) return done(err); if (err) return done(err);
expect(res.body).to.be.eql([ expect(res.body).to.be.eql([
{ name: 'Chocolate', id: test.ingredient1 }, {name: 'Chocolate', id: test.ingredient1},
{ name: 'Sugar', id: test.ingredient2 }, {name: 'Sugar', id: test.ingredient2},
]); ]);
done(); done();
@ -1378,7 +1379,7 @@ describe('relations - integration', function() {
if (err) return done(err); if (err) return done(err);
expect(res.body).to.be.eql([ expect(res.body).to.be.eql([
{ name: 'Sugar', id: test.ingredient2 }, {name: 'Sugar', id: test.ingredient2},
]); ]);
done(); done();
@ -1394,8 +1395,8 @@ describe('relations - integration', function() {
if (err) return done(err); if (err) return done(err);
expect(res.body).to.be.eql([ expect(res.body).to.be.eql([
{ name: 'Chocolate', id: test.ingredient1 }, {name: 'Chocolate', id: test.ingredient1},
{ name: 'Sugar', id: test.ingredient2 }, {name: 'Sugar', id: test.ingredient2},
]); ]);
done(); done();
@ -1441,38 +1442,38 @@ describe('relations - integration', function() {
before(function defineModels() { before(function defineModels() {
var Book = app.registry.createModel( var Book = app.registry.createModel(
'Book', 'Book',
{ name: 'string' }, {name: 'string'},
{ plural: 'books' } {plural: 'books'}
); );
app.model(Book, { dataSource: 'db' }); app.model(Book, {dataSource: 'db'});
var Page = app.registry.createModel( var Page = app.registry.createModel(
'Page', 'Page',
{ name: 'string' }, {name: 'string'},
{ plural: 'pages' } {plural: 'pages'}
); );
app.model(Page, { dataSource: 'db' }); app.model(Page, {dataSource: 'db'});
var Image = app.registry.createModel( var Image = app.registry.createModel(
'Image', 'Image',
{ name: 'string' }, {name: 'string'},
{ plural: 'images' } {plural: 'images'}
); );
app.model(Image, { dataSource: 'db' }); app.model(Image, {dataSource: 'db'});
var Note = app.registry.createModel( var Note = app.registry.createModel(
'Note', 'Note',
{ text: 'string' }, {text: 'string'},
{ plural: 'notes' } {plural: 'notes'}
); );
app.model(Note, { dataSource: 'db' }); app.model(Note, {dataSource: 'db'});
var Chapter = app.registry.createModel( var Chapter = app.registry.createModel(
'Chapter', 'Chapter',
{ name: 'string' }, {name: 'string'},
{ plural: 'chapters' } {plural: 'chapters'}
); );
app.model(Chapter, { dataSource: 'db' }); app.model(Chapter, {dataSource: 'db'});
Book.hasMany(Page); Book.hasMany(Page);
Book.hasMany(Chapter); Book.hasMany(Chapter);
@ -1485,7 +1486,7 @@ describe('relations - integration', function() {
throw new Error('This should not crash the app'); throw new Error('This should not crash the app');
}; };
Page.remoteMethod('__throw__errors', { isStatic: false, http: { path: '/throws', verb: 'get' }}); Page.remoteMethod('__throw__errors', {isStatic: false, http: {path: '/throws', verb: 'get'}});
Book.nestRemoting('pages'); Book.nestRemoting('pages');
Book.nestRemoting('chapters'); Book.nestRemoting('chapters');
@ -1509,17 +1510,17 @@ describe('relations - integration', function() {
before(function createBook(done) { before(function createBook(done) {
var test = this; var test = this;
app.models.Book.create({ name: 'Book 1' }, app.models.Book.create({name: 'Book 1'},
function(err, book) { function(err, book) {
if (err) return done(err); if (err) return done(err);
test.book = book; test.book = book;
book.pages.create({ name: 'Page 1' }, book.pages.create({name: 'Page 1'},
function(err, page) { function(err, page) {
if (err) return done(err); if (err) return done(err);
test.page = page; test.page = page;
page.notes.create({ text: 'Page Note 1' }, page.notes.create({text: 'Page Note 1'},
function(err, note) { function(err, note) {
test.note = note; test.note = note;
@ -1531,12 +1532,12 @@ describe('relations - integration', function() {
before(function createChapters(done) { before(function createChapters(done) {
var test = this; var test = this;
test.book.chapters.create({ name: 'Chapter 1' }, test.book.chapters.create({name: 'Chapter 1'},
function(err, chapter) { function(err, chapter) {
if (err) return done(err); if (err) return done(err);
test.chapter = chapter; test.chapter = chapter;
chapter.notes.create({ text: 'Chapter Note 1' }, function(err, note) { chapter.notes.create({text: 'Chapter Note 1'}, function(err, note) {
test.cnote = note; test.cnote = note;
done(); done();
@ -1546,7 +1547,7 @@ describe('relations - integration', function() {
before(function createCover(done) { before(function createCover(done) {
var test = this; var test = this;
app.models.Image.create({ name: 'Cover 1', book: test.book }, app.models.Image.create({name: 'Cover 1', book: test.book},
function(err, image) { function(err, image) {
if (err) return done(err); if (err) return done(err);
@ -1705,7 +1706,7 @@ describe('relations - integration', function() {
before(function createCustomer(done) { before(function createCustomer(done) {
var test = this; var test = this;
app.models.customer.create({ name: 'John' }, function(err, c) { app.models.customer.create({name: 'John'}, function(err, c) {
if (err) return done(err); if (err) return done(err);
cust = c; cust = c;
@ -1727,7 +1728,7 @@ describe('relations - integration', function() {
var url = '/api/customers/' + cust.id + '/profile'; var url = '/api/customers/' + cust.id + '/profile';
this.post(url) this.post(url)
.send({ points: 10 }) .send({points: 10})
.expect(200, function(err, res) { .expect(200, function(err, res) {
if (err) return done(err); if (err) return done(err);
@ -1754,7 +1755,7 @@ describe('relations - integration', function() {
it('should not create the referenced model twice', function(done) { it('should not create the referenced model twice', function(done) {
var url = '/api/customers/' + cust.id + '/profile'; var url = '/api/customers/' + cust.id + '/profile';
this.post(url) this.post(url)
.send({ points: 20 }) .send({points: 20})
.expect(500, function(err, res) { .expect(500, function(err, res) {
done(err); done(err);
}); });
@ -1763,7 +1764,7 @@ describe('relations - integration', function() {
it('should update the referenced model', function(done) { it('should update the referenced model', function(done) {
var url = '/api/customers/' + cust.id + '/profile'; var url = '/api/customers/' + cust.id + '/profile';
this.put(url) this.put(url)
.send({ points: 100 }) .send({points: 100})
.expect(200, function(err, res) { .expect(200, function(err, res) {
if (err) return done(err); if (err) return done(err);

Some files were not shown because too many files have changed in this diff Show More