Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
5974c6a
Pull in API doc fix from PR into master #1910
Jan 9, 2016
8deec2e
Checkpoint speedup
Dec 17, 2015
17bd101
ensure app is booted before integration tests
rmg Jan 1, 2016
aff49ff
test: fail on error instead of crash
rmg Jan 1, 2016
db0678b
test: use ephemeral port for e2e server
rmg Jan 7, 2016
870e101
Merge pull request #2032 from strongloop/safer-tests-step1-2.x
bajtos Feb 4, 2016
a0a1083
Hide verificationToken
bajtos Jan 26, 2016
015e9cb
Correct JSDoc findOrCreate() callback in PersistedModel
bajtos Jan 26, 2016
4753373
Travis: drop iojs, add v4.x and v5.x
bajtos Feb 4, 2016
d123e95
Merge pull request #2033 from strongloop/fix/travis-platforms-2.x
bajtos Feb 4, 2016
76ec49c
Fix race condition in error handler test
bajtos Feb 4, 2016
7d3d4f1
Merge pull request #2034 from strongloop/fix/ci
bajtos Feb 4, 2016
7a54da5
Promisify Model Change
jannyHou Jan 27, 2016
a0806ea
test: remove errant console.log from test
rmg Feb 4, 2016
e98ed99
Fix race condition in replication tests
bajtos Feb 5, 2016
70aec01
Remove sl-blip from dependency
0candy Feb 18, 2016
97f376c
2.27.0
bajtos Feb 19, 2016
a4c643e
application: correct spelling of "cannont"
sam-github Feb 19, 2016
50e3578
Improve error message on connector init error
bajtos Feb 26, 2016
e4b2752
Allow built-in token middleware to run repeatedly
Feb 29, 2016
4678cb4
Merge pull request #2204 from strongloop/backport/pr2108
bajtos Apr 6, 2016
1ea1cd6
Fix typo in Model.nestRemoting
Jan 17, 2016
2498c02
Add new feature to emit a `remoteMethodDisabled` event when disabling…
supasate Apr 27, 2016
091c71d
Merge pull request #2271 from strongloop/backport-emit-disable-remote…
superkhau Apr 30, 2016
6d73869
2.28.0
bajtos May 2, 2016
845c59e
test/user: use local registry
bajtos May 2, 2016
cae9786
Fix role.isOwner to support app-local registry
bajtos May 2, 2016
53cd449
test/rest.middleware: use local registry
bajtos May 2, 2016
6c59390
Disable DEBUG output for eslint on Jenkins CI
bajtos May 3, 2016
c2ad201
Merge pull request #2282 from strongloop/feature/remove-auto-attach-2.x
bajtos May 3, 2016
bd7f2b6
travis: drop node@5, add node@6
bajtos May 3, 2016
da2fb0a
app: send port:0 instead of port:undefined
bajtos May 3, 2016
e2b1f78
Upgrade phantomjs to 2.x
bajtos May 3, 2016
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@ language: node_js
node_js:
- "0.10"
- "0.12"
- "iojs"
- "4"
- "6"

52 changes: 44 additions & 8 deletions CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,47 @@
2016-05-02, Version 2.28.0
==========================

* Add new feature to emit a `remoteMethodDisabled` event when disabling a remote method. (Supasate Choochaisri)

* Fix typo in Model.nestRemoting (Tim Needham)

* Allow built-in token middleware to run repeatedly (Benjamin Kröger)

* Improve error message on connector init error (Miroslav Bajtoš)

* application: correct spelling of "cannont" (Sam Roberts)


2016-02-19, Version 2.27.0
==========================

* Remove sl-blip from dependency (Candy)

* Fix race condition in replication tests (Miroslav Bajtoš)

* test: remove errant console.log from test (Ryan Graham)

* Promisify Model Change (Jue Hou)

* Fix race condition in error handler test (Miroslav Bajtoš)

* Travis: drop iojs, add v4.x and v5.x (Miroslav Bajtoš)

* Correct JSDoc findOrCreate() callback in PersistedModel (Miroslav Bajtoš)

* Hide verificationToken (Miroslav Bajtoš)

* test: use ephemeral port for e2e server (Ryan Graham)

* test: fail on error instead of crash (Ryan Graham)

* ensure app is booted before integration tests (Ryan Graham)

* Checkpoint speedup (Amir Jafarian)

* Pull in API doc fix from PR into master #1910 (crandmck)


2015-12-22, Version 2.26.2
==========================

Expand Down Expand Up @@ -989,8 +1033,6 @@
2014-07-15, Version 2.0.0-beta6
===============================

* 2.0.0-beta6 (Miroslav Bajtoš)

* lib/application: publish Change models to REST API (Miroslav Bajtoš)

* models/change: fix typo (Miroslav Bajtoš)
Expand All @@ -1001,8 +1043,6 @@
2014-07-03, Version 2.0.0-beta5
===============================

* 2.0.0-beta5 (Miroslav Bajtoš)

* app: update `url` on `listening` event (Miroslav Bajtoš)

* Fix "ReferenceError: loopback is not defined" in registry.memory(). (Guilherme Cirne)
Expand All @@ -1021,8 +1061,6 @@
2014-06-26, Version 2.0.0-beta4
===============================

* 2.0.0-beta4 (Miroslav Bajtoš)

* package: upgrade juggler to 2.0.0-beta2 (Miroslav Bajtoš)

* Fix loopback in PhantomJS, fix karma tests (Miroslav Bajtoš)
Expand Down Expand Up @@ -1149,8 +1187,6 @@
2014-05-28, Version 2.0.0-beta3
===============================

* 2.0.0-beta3 (Miroslav Bajtoš)

* package.json: fix malformed json (Miroslav Bajtoš)

* 2.0.0-beta2 (Ritchie Martori)
Expand Down
5 changes: 4 additions & 1 deletion Gruntfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,10 @@ module.exports = function(grunt) {
grunt.registerTask('e2e-server', function() {
var done = this.async();
var app = require('./test/fixtures/e2e/app');
app.listen(3000, done);
app.listen(0, function() {
process.env.PORT = this.address().port;
done();
});
});

grunt.registerTask('e2e', ['e2e-server', 'karma:e2e']);
Expand Down
19 changes: 15 additions & 4 deletions common/models/change.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

var PersistedModel = require('../../lib/loopback').PersistedModel;
var loopback = require('../../lib/loopback');
var utils = require('../../lib/utils');
var crypto = require('crypto');
var CJSON = {stringify: require('canonical-json')};
var async = require('async');
Expand Down Expand Up @@ -77,6 +78,8 @@ module.exports = function(Change) {
var Change = this;
var errors = [];

callback = callback || utils.createPromiseCallback();

var tasks = modelIds.map(function(id) {
return function(cb) {
Change.findOrCreateChange(modelName, id, function(err, change) {
Expand Down Expand Up @@ -111,6 +114,7 @@ module.exports = function(Change) {
}
callback();
});
return callback.promise;
};

/**
Expand Down Expand Up @@ -138,6 +142,7 @@ module.exports = function(Change) {

Change.findOrCreateChange = function(modelName, modelId, callback) {
assert(loopback.findModel(modelName), modelName + ' does not exist');
callback = callback || utils.createPromiseCallback();
var id = this.idForModel(modelName, modelId);
var Change = this;

Expand All @@ -155,6 +160,7 @@ module.exports = function(Change) {
Change.updateOrCreate(ch, callback);
}
});
return callback.promise;
};

/**
Expand All @@ -171,9 +177,7 @@ module.exports = function(Change) {

change.debug('rectify change');

cb = cb || function(err) {
if (err) throw new Error(err);
};
cb = cb || utils.createPromiseCallback();

change.currentRevision(function(err, rev) {
if (err) return cb(err);
Expand All @@ -194,6 +198,7 @@ module.exports = function(Change) {
}
);
});
return cb.promise;

function doRectify(checkpoint, rev) {
if (rev) {
Expand Down Expand Up @@ -248,6 +253,7 @@ module.exports = function(Change) {
*/

Change.prototype.currentRevision = function(cb) {
cb = cb || utils.createPromiseCallback();
var model = this.getModelCtor();
var id = this.getModelId();
model.findById(id, function(err, inst) {
Expand All @@ -258,6 +264,7 @@ module.exports = function(Change) {
cb(null, null);
}
});
return cb.promise;
};

/**
Expand Down Expand Up @@ -390,8 +397,11 @@ module.exports = function(Change) {
*/

Change.diff = function(modelName, since, remoteChanges, callback) {
callback = callback || utils.createPromiseCallback();

if (!Array.isArray(remoteChanges) || remoteChanges.length === 0) {
return callback(null, {deltas: [], conflicts: []});
callback(null, {deltas: [], conflicts: []});
return callback.promise;
}
var remoteChangeIndex = {};
var modelIds = [];
Expand Down Expand Up @@ -455,6 +465,7 @@ module.exports = function(Change) {
conflicts: conflicts
});
});
return callback.promise;
};

/**
Expand Down
64 changes: 33 additions & 31 deletions common/models/checkpoint.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,43 +27,45 @@ module.exports = function(Checkpoint) {
* Get the current checkpoint id
* @callback {Function} callback
* @param {Error} err
* @param {Number} checkpointId The current checkpoint id
* @param {Number} checkpoint The current checkpoint seq
*/

Checkpoint.current = function(cb) {
var Checkpoint = this;
this.find({
limit: 1,
order: 'seq DESC'
}, function(err, checkpoints) {
if (err) return cb(err);
var checkpoint = checkpoints[0];
if (checkpoint) {
cb(null, checkpoint.seq);
} else {
Checkpoint.create({ seq: 1 }, function(err, checkpoint) {
if (err) return cb(err);
cb(null, checkpoint.seq);
});
}
Checkpoint._getSingleton(function(err, cp) {
cb(err, cp.seq);
});
};

Checkpoint.observe('before save', function(ctx, next) {
if (!ctx.instance) {
// Example: Checkpoint.updateAll() and Checkpoint.updateOrCreate()
return next(new Error('Checkpoint does not support partial updates.'));
}
Checkpoint._getSingleton = function(cb) {
var query = {limit: 1}; // match all instances, return only one
var initialData = {seq: 1};
this.findOrCreate(query, initialData, cb);
};

var model = ctx.instance;
if (!model.getId() && model.seq === undefined) {
model.constructor.current(function(err, seq) {
if (err) return next(err);
model.seq = seq + 1;
next();
/**
* Increase the current checkpoint if it already exists otherwise initialize it
* @callback {Function} callback
* @param {Error} err
* @param {Object} checkpoint The current checkpoint
*/
Checkpoint.bumpLastSeq = function(cb) {
var Checkpoint = this;
Checkpoint._getSingleton(function(err, cp) {
if (err) return cb(err);
var originalSeq = cp.seq;
cp.seq++;
// 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) {
if (err) return cb(err);
// possible outcomes
// 1) seq was updated to seq+1 - exactly what we wanted!
// 2) somebody else already updated seq to seq+1 and our call was a no-op.
// That should be ok, checkpoints are time based, so we reuse the one created just now
// 3) seq was bumped more than once, so we will be using a value that is behind the latest seq.
// @bajtos is not entirely sure if this is ok, but since it wasn't handled by the current implementation either,
// he thinks we can keep it this way.
cb(null, cp);
});
} else {
next();
}
});
});
};
};
10 changes: 4 additions & 6 deletions common/models/role.js
Original file line number Diff line number Diff line change
Expand Up @@ -147,12 +147,10 @@ module.exports = function(Role) {
});

function isUserClass(modelClass) {
if (modelClass) {
return modelClass === loopback.User ||
modelClass.prototype instanceof loopback.User;
} else {
return false;
}
if (!modelClass) return false;
var User = modelClass.modelBuilder.models.User;
if (!User) return false;
return modelClass == User || modelClass.prototype instanceof User;
}

/*!
Expand Down
2 changes: 1 addition & 1 deletion common/models/user.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
"options": {
"caseSensitiveEmail": true
},
"hidden": ["password"],
"hidden": ["password", "verificationToken"],
"acls": [
{
"principalType": "ROLE",
Expand Down
33 changes: 26 additions & 7 deletions lib/application.js
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,11 @@ app.model = function(Model, config) {
this.emit('modelRemoted', Model.sharedClass);
}

var self = this;
Model.on('remoteMethodDisabled', function(model, methodName) {
self.emit('remoteMethodDisabled', model, methodName);
});

Model.shared = isPublic;
Model.app = this;
Model.emit('attached', this);
Expand Down Expand Up @@ -219,11 +224,19 @@ app.models = function() {
* @param {Object} config The data source config
*/
app.dataSource = function(name, config) {
var ds = dataSourcesFromConfig(name, config, this.connectors, this.registry);
this.dataSources[name] =
this.dataSources[classify(name)] =
this.dataSources[camelize(name)] = ds;
return ds;
try {
var ds = dataSourcesFromConfig(name, config, this.connectors, this.registry);
this.dataSources[name] =
this.dataSources[classify(name)] =
this.dataSources[camelize(name)] = ds;
return ds;
} catch (err) {
if (err.message) {
err.message = 'Cannot create data source ' + JSON.stringify(name) +
': ' + err.message;
}
throw err;
}
};

/**
Expand Down Expand Up @@ -397,7 +410,7 @@ function dataSourcesFromConfig(name, config, connectorRegistry, registry) {
var connectorPath;

assert(typeof config === 'object',
'cannont create data source without config object');
'can not create data source without config object');

if (typeof config.connector === 'string') {
name = config.connector;
Expand All @@ -410,6 +423,8 @@ function dataSourcesFromConfig(name, config, connectorRegistry, registry) {
config.connector = require(connectorPath);
}
}
if (!config.connector.name)
config.connector.name = name;
}

return registry.createDataSource(config);
Expand Down Expand Up @@ -551,7 +566,11 @@ app.listen = function(cb) {
(arguments.length == 1 && typeof arguments[0] == 'function');

if (useAppConfig) {
server.listen(this.get('port'), this.get('host'), cb);
var port = this.get('port');
// NOTE(bajtos) port:undefined no longer works on node@6,
// we must pass port:0 explicitly
if (port === undefined) port = 0;
server.listen(port, this.get('host'), cb);
} else {
server.listen.apply(server, arguments);
}
Expand Down
5 changes: 3 additions & 2 deletions lib/model.js
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,7 @@ module.exports = function(registry) {

Model.disableRemoteMethod = function(name, isStatic) {
this.sharedClass.disableMethod(name, isStatic || false);
this.emit('remoteMethodDisabled', this.sharedClass, name);
};

Model.belongsToRemoting = function(relationName, relation, define) {
Expand Down Expand Up @@ -806,8 +807,8 @@ module.exports = function(registry) {
listenerTree.before = listenerTree.before || {};
listenerTree.after = listenerTree.after || {};

var beforeListeners = remotes.listenerTree.before[toModelName] || {};
var afterListeners = remotes.listenerTree.after[toModelName] || {};
var beforeListeners = listenerTree.before[toModelName] || {};
var afterListeners = listenerTree.after[toModelName] || {};

sharedClass.methods().forEach(function(method) {
var delegateTo = method.rest && method.rest.delegateTo;
Expand Down
Loading