2
1
Fork 0
mirror of https://github.com/TryGhost/Ghost.git synced 2023-12-13 21:00:40 +01:00

Replace the when promise library with bluebird.

Closes #968
This commit is contained in:
Jason Williams 2014-08-17 06:17:23 +00:00
parent f7e92d20e2
commit 07ad400ee0
80 changed files with 924 additions and 981 deletions

100
core/bootstrap.js vendored
View file

@ -6,7 +6,7 @@
var fs = require('fs'), var fs = require('fs'),
url = require('url'), url = require('url'),
when = require('when'), Promise = require('bluebird'),
validator = require('validator'), validator = require('validator'),
errors = require('./server/errors'), errors = require('./server/errors'),
config = require('./server/config'), config = require('./server/config'),
@ -20,43 +20,42 @@ function readConfigFile(envVal) {
} }
function writeConfigFile() { function writeConfigFile() {
var written = when.defer();
/* Check for config file and copy from config.example.js /* Check for config file and copy from config.example.js
if one doesn't exist. After that, start the server. */ if one doesn't exist. After that, start the server. */
fs.exists(configExample, function checkTemplate(templateExists) { return new Promise(function (resolve, reject) {
var read, fs.exists(configExample, function checkTemplate(templateExists) {
write, var read,
error; write,
error;
if (!templateExists) { if (!templateExists) {
error = new Error('Could not locate a configuration file.'); error = new Error('Could not locate a configuration file.');
error.context = appRoot; error.context = appRoot;
error.help = 'Please check your deployment for config.js or config.example.js.'; error.help = 'Please check your deployment for config.js or config.example.js.';
return written.reject(error); return reject(error);
} }
// Copy config.example.js => config.js // Copy config.example.js => config.js
read = fs.createReadStream(configExample); read = fs.createReadStream(configExample);
read.on('error', function (err) { read.on('error', function (err) {
errors.logError(new Error('Could not open config.example.js for read.'), appRoot, 'Please check your deployment for config.js or config.example.js.'); errors.logError(new Error('Could not open config.example.js for read.'), appRoot, 'Please check your deployment for config.js or config.example.js.');
return written.reject(err); reject(err);
});
write = fs.createWriteStream(configFile);
write.on('error', function (err) {
errors.logError(new Error('Could not open config.js for write.'), appRoot, 'Please check your deployment for config.js or config.example.js.');
reject(err);
});
write.on('finish', resolve);
read.pipe(write);
}); });
write = fs.createWriteStream(configFile);
write.on('error', function (err) {
errors.logError(new Error('Could not open config.js for write.'), appRoot, 'Please check your deployment for config.js or config.example.js.');
return written.reject(err);
});
write.on('finish', written.resolve);
read.pipe(write);
}); });
return written.promise;
} }
function validateConfigEnvironment() { function validateConfigEnvironment() {
@ -70,7 +69,7 @@ function validateConfigEnvironment() {
config = readConfigFile(envVal); config = readConfigFile(envVal);
} }
catch (e) { catch (e) {
return when.reject(e); return Promise.reject(e);
} }
// Check if we don't even have a config // Check if we don't even have a config
@ -78,14 +77,14 @@ function validateConfigEnvironment() {
errors.logError(new Error('Cannot find the configuration for the current NODE_ENV'), 'NODE_ENV=' + envVal, errors.logError(new Error('Cannot find the configuration for the current NODE_ENV'), 'NODE_ENV=' + envVal,
'Ensure your config.js has a section for the current NODE_ENV value and is formatted properly.'); 'Ensure your config.js has a section for the current NODE_ENV value and is formatted properly.');
return when.reject(new Error('Unable to load config for NODE_ENV=' + envVal)); return Promise.reject(new Error('Unable to load config for NODE_ENV=' + envVal));
} }
// Check that our url is valid // Check that our url is valid
if (!validator.isURL(config.url, { protocols: ['http', 'https'], require_protocol: true })) { if (!validator.isURL(config.url, { protocols: ['http', 'https'], require_protocol: true })) {
errors.logError(new Error('Your site url in config.js is invalid.'), config.url, 'Please make sure this is a valid url before restarting'); errors.logError(new Error('Your site url in config.js is invalid.'), config.url, 'Please make sure this is a valid url before restarting');
return when.reject(new Error('invalid site url')); return Promise.reject(new Error('invalid site url'));
} }
parsedUrl = url.parse(config.url || 'invalid', false, true); parsedUrl = url.parse(config.url || 'invalid', false, true);
@ -93,14 +92,14 @@ function validateConfigEnvironment() {
if (/\/ghost(\/|$)/.test(parsedUrl.pathname)) { if (/\/ghost(\/|$)/.test(parsedUrl.pathname)) {
errors.logError(new Error('Your site url in config.js cannot contain a subdirectory called ghost.'), config.url, 'Please rename the subdirectory before restarting'); errors.logError(new Error('Your site url in config.js cannot contain a subdirectory called ghost.'), config.url, 'Please rename the subdirectory before restarting');
return when.reject(new Error('ghost subdirectory not allowed')); return Promise.reject(new Error('ghost subdirectory not allowed'));
} }
// Check that we have database values // Check that we have database values
if (!config.database || !config.database.client) { if (!config.database || !config.database.client) {
errors.logError(new Error('Your database configuration in config.js is invalid.'), JSON.stringify(config.database), 'Please make sure this is a valid Bookshelf database configuration'); errors.logError(new Error('Your database configuration in config.js is invalid.'), JSON.stringify(config.database), 'Please make sure this is a valid Bookshelf database configuration');
return when.reject(new Error('invalid database configuration')); return Promise.reject(new Error('invalid database configuration'));
} }
hasHostAndPort = config.server && !!config.server.host && !!config.server.port; hasHostAndPort = config.server && !!config.server.host && !!config.server.port;
@ -110,33 +109,32 @@ function validateConfigEnvironment() {
if (!config.server || !(hasHostAndPort || hasSocket)) { if (!config.server || !(hasHostAndPort || hasSocket)) {
errors.logError(new Error('Your server values (socket, or host and port) in config.js are invalid.'), JSON.stringify(config.server), 'Please provide them before restarting.'); errors.logError(new Error('Your server values (socket, or host and port) in config.js are invalid.'), JSON.stringify(config.server), 'Please provide them before restarting.');
return when.reject(new Error('invalid server configuration')); return Promise.reject(new Error('invalid server configuration'));
} }
return when.resolve(config); return Promise.resolve(config);
} }
function loadConfig(configFilePath) { function loadConfig(configFilePath) {
var loaded = when.defer(),
pendingConfig;
// Allow config file path to be taken from, in order of importance:
// environment process, passed in value, default location
configFile = process.env.GHOST_CONFIG || configFilePath || config.paths.config; configFile = process.env.GHOST_CONFIG || configFilePath || config.paths.config;
/* Check for config file and copy from config.example.js /* Check for config file and copy from config.example.js
if one doesn't exist. After that, start the server. */ if one doesn't exist. After that, start the server. */
fs.exists(configFile, function checkConfig(configExists) { return new Promise(function (resolve, reject) {
if (!configExists) { fs.exists(configFile, function (exists) {
pendingConfig = writeConfigFile(); var pendingConfig;
}
when(pendingConfig).then(validateConfigEnvironment).then(function (rawConfig) { if (!exists) {
return config.init(rawConfig).then(loaded.resolve); pendingConfig = writeConfigFile();
}).catch(loaded.reject); }
Promise.resolve(pendingConfig)
.then(validateConfigEnvironment)
.then(function (rawConfig) {
resolve(config.init(rawConfig));
}).catch(reject);
});
}); });
return loaded.promise;
} }
module.exports = loadConfig; module.exports = loadConfig;

View file

@ -2,33 +2,17 @@
// Orchestrates the loading of Ghost // Orchestrates the loading of Ghost
// When run from command line. // When run from command line.
var when = require('when'), var bootstrap = require('./bootstrap'),
bootstrap = require('./bootstrap'),
server = require('./server'); server = require('./server');
process.env.NODE_ENV = process.env.NODE_ENV || 'development'; process.env.NODE_ENV = process.env.NODE_ENV || 'development';
function makeGhost(options) { function makeGhost(options) {
var deferred = when.defer();
options = options || {}; options = options || {};
bootstrap(options.config).then(function () { return bootstrap(options.config).then(function () {
try { return server(options.app);
return server(options.app) });
.then(deferred.resolve)
.catch(function (err) {
// We don't return the rejected promise to stop
// the propagation of the rejection and just
// allow the user to manage what to do.
deferred.reject(err);
});
} catch (e) {
deferred.reject(e);
}
}).catch(deferred.reject);
return deferred.promise;
} }
module.exports = makeGhost; module.exports = makeGhost;

View file

@ -1,4 +1,4 @@
var when = require('when'), var Promise = require('bluebird'),
fs = require('fs'), fs = require('fs'),
semver = require('semver'), semver = require('semver'),
packageInfo = require('../../package.json'), packageInfo = require('../../package.json'),
@ -88,54 +88,59 @@ GhostServer.prototype.logUpgradeWarning = function () {
// Starts the ghost server listening on the configured port // Starts the ghost server listening on the configured port
GhostServer.prototype.start = function () { GhostServer.prototype.start = function () {
var self = this;
// ## Start Ghost App // ## Start Ghost App
var deferred = when.defer(); return new Promise(function (resolve) {
if (config.getSocket()) { if (config.getSocket()) {
// Make sure the socket is gone before trying to create another // Make sure the socket is gone before trying to create another
try { try {
fs.unlinkSync(config.getSocket()); fs.unlinkSync(config.getSocket());
} catch (e) { } catch (e) {
// We can ignore this. // We can ignore this.
}
self.httpServer = self.app.listen(
config.getSocket()
);
fs.chmod(config.getSocket(), '0660');
} else {
self.httpServer = self.app.listen(
config.server.port,
config.server.host
);
} }
this.httpServer = this.app.listen( self.httpServer.on('connection', self.connection.bind(self));
config.getSocket() self.httpServer.on('listening', function () {
); self.logStartMessages();
fs.chmod(config.getSocket(), '0660'); clearTimeout(self.upgradeWarning);
resolve(self);
} else { });
this.httpServer = this.app.listen( });
config.server.port,
config.server.host
);
}
this.httpServer.on('connection', this.connection.bind(this));
this.httpServer.on('listening', function () {
this.logStartMessages();
clearTimeout(this.upgradeWarning);
deferred.resolve(this);
}.bind(this));
return deferred.promise;
}; };
// Returns a promise that will be fulfilled when the server stops. // Returns a promise that will be fulfilled when the server stops.
// If the server has not been started, the promise will be fulfilled // If the server has not been started, the promise will be fulfilled
// immediately // immediately
GhostServer.prototype.stop = function () { GhostServer.prototype.stop = function () {
var deferred = when.defer(); var self = this;
if (this.httpServer === null) { return new Promise(function (resolve) {
deferred.resolve(this); if (self.httpServer === null) {
} else { resolve(self);
this.httpServer.close(function () { } else {
this.httpServer = null; self.httpServer.close(function () {
this.logShutdownMessages(); self.httpServer = null;
deferred.resolve(this); self.logShutdownMessages();
}.bind(this)); resolve(self);
this.closeConnections(); });
}
return deferred.promise; self.closeConnections();
}
});
}; };
// Restarts the ghost application // Restarts the ghost application
@ -146,8 +151,8 @@ GhostServer.prototype.restart = function () {
// To be called after `stop` // To be called after `stop`
GhostServer.prototype.hammertime = function () { GhostServer.prototype.hammertime = function () {
console.log('Can\'t touch this'.green); console.log('Can\'t touch this'.green);
return this;
return Promise.resolve(this);
}; };
module.exports = GhostServer; module.exports = GhostServer;

View file

@ -5,7 +5,7 @@ var _ = require('lodash'),
globalUtils = require('../utils'), globalUtils = require('../utils'),
utils = require('./utils'), utils = require('./utils'),
users = require('./users'), users = require('./users'),
when = require('when'), Promise = require('bluebird'),
errors = require('../errors'), errors = require('../errors'),
config = require('../config'), config = require('../config'),
authentication; authentication;
@ -31,7 +31,7 @@ authentication = {
var setup = result.setup[0].status; var setup = result.setup[0].status;
if (!setup) { if (!setup) {
return when.reject(new errors.NoPermissionError('Setup must be completed before making this request.')); return Promise.reject(new errors.NoPermissionError('Setup must be completed before making this request.'));
} }
return utils.checkObject(object, 'passwordreset'); return utils.checkObject(object, 'passwordreset');
@ -39,13 +39,10 @@ authentication = {
if (checkedPasswordReset.passwordreset[0].email) { if (checkedPasswordReset.passwordreset[0].email) {
email = checkedPasswordReset.passwordreset[0].email; email = checkedPasswordReset.passwordreset[0].email;
} else { } else {
return when.reject(new errors.BadRequestError('No email provided.')); return Promise.reject(new errors.BadRequestError('No email provided.'));
} }
return users.read({ context: {internal: true}, email: email, status: 'active' }).then(function (foundUser) { return users.read({ context: {internal: true}, email: email, status: 'active' }).then(function () {
if (!foundUser) {
when.reject(new errors.NotFound('Invalid email address'));
}
return settings.read({context: {internal: true}, key: 'dbHash'}); return settings.read({context: {internal: true}, key: 'dbHash'});
}).then(function (response) { }).then(function (response) {
var dbHash = response.settings[0].value; var dbHash = response.settings[0].value;
@ -69,9 +66,9 @@ authentication = {
}; };
return mail.send(payload, {context: {internal: true}}); return mail.send(payload, {context: {internal: true}});
}).then(function () { }).then(function () {
return when.resolve({passwordreset: [{message: 'Check your email for further instructions.'}]}); return Promise.resolve({passwordreset: [{message: 'Check your email for further instructions.'}]});
}).otherwise(function (error) { }).catch(function (error) {
return when.reject(error); return Promise.reject(error);
}); });
}); });
}, },
@ -91,7 +88,7 @@ authentication = {
var setup = result.setup[0].status; var setup = result.setup[0].status;
if (!setup) { if (!setup) {
return when.reject(new errors.NoPermissionError('Setup must be completed before making this request.')); return Promise.reject(new errors.NoPermissionError('Setup must be completed before making this request.'));
} }
return utils.checkObject(object, 'passwordreset'); return utils.checkObject(object, 'passwordreset');
@ -104,9 +101,9 @@ authentication = {
var dbHash = response.settings[0].value; var dbHash = response.settings[0].value;
return dataProvider.User.resetPassword(resetToken, newPassword, ne2Password, dbHash); return dataProvider.User.resetPassword(resetToken, newPassword, ne2Password, dbHash);
}).then(function () { }).then(function () {
return when.resolve({passwordreset: [{message: 'Password changed successfully.'}]}); return Promise.resolve({passwordreset: [{message: 'Password changed successfully.'}]});
}).otherwise(function (error) { }).catch(function (error) {
return when.reject(new errors.UnauthorizedError(error.message)); return Promise.reject(new errors.UnauthorizedError(error.message));
}); });
}); });
}, },
@ -127,7 +124,7 @@ authentication = {
var setup = result.setup[0].status; var setup = result.setup[0].status;
if (!setup) { if (!setup) {
return when.reject(new errors.NoPermissionError('Setup must be completed before making this request.')); return Promise.reject(new errors.NoPermissionError('Setup must be completed before making this request.'));
} }
return utils.checkObject(object, 'invitation'); return utils.checkObject(object, 'invitation');
@ -144,9 +141,9 @@ authentication = {
}).then(function (user) { }).then(function (user) {
return dataProvider.User.edit({name: name, email: email}, {id: user.id}); return dataProvider.User.edit({name: name, email: email}, {id: user.id});
}).then(function () { }).then(function () {
return when.resolve({invitation: [{message: 'Invitation accepted.'}]}); return Promise.resolve({invitation: [{message: 'Invitation accepted.'}]});
}).otherwise(function (error) { }).catch(function (error) {
return when.reject(new errors.UnauthorizedError(error.message)); return Promise.reject(new errors.UnauthorizedError(error.message));
}); });
}); });
}, },
@ -156,9 +153,9 @@ authentication = {
qb.whereIn('status', ['active', 'warn-1', 'warn-2', 'warn-3', 'warn-4', 'locked']); qb.whereIn('status', ['active', 'warn-1', 'warn-2', 'warn-3', 'warn-4', 'locked']);
}).fetch().then(function (users) { }).fetch().then(function (users) {
if (users) { if (users) {
return when.resolve({ setup: [{status: true}]}); return Promise.resolve({ setup: [{status: true}]});
} else { } else {
return when.resolve({ setup: [{status: false}]}); return Promise.resolve({ setup: [{status: false}]});
} }
}); });
}, },
@ -171,7 +168,7 @@ authentication = {
var setup = result.setup[0].status; var setup = result.setup[0].status;
if (setup) { if (setup) {
return when.reject(new errors.NoPermissionError('Setup has already been completed.')); return Promise.reject(new errors.NoPermissionError('Setup has already been completed.'));
} }
return utils.checkObject(object, 'setup'); return utils.checkObject(object, 'setup');
@ -226,7 +223,7 @@ authentication = {
}] }]
}; };
return mail.send(payload, {context: {internal: true}}).otherwise(function (error) { return mail.send(payload, {context: {internal: true}}).catch(function (error) {
errors.logError( errors.logError(
error.message, error.message,
"Unable to send welcome email, your blog will continue to function.", "Unable to send welcome email, your blog will continue to function.",
@ -235,7 +232,7 @@ authentication = {
}); });
}).then(function () { }).then(function () {
return when.resolve({ users: [setupUser]}); return Promise.resolve({ users: [setupUser]});
}); });
} }
}; };

View file

@ -4,8 +4,7 @@ var dataExport = require('../data/export'),
dataImport = require('../data/import'), dataImport = require('../data/import'),
dataProvider = require('../models'), dataProvider = require('../models'),
fs = require('fs-extra'), fs = require('fs-extra'),
when = require('when'), Promise = require('bluebird'),
nodefn = require('when/node'),
_ = require('lodash'), _ = require('lodash'),
path = require('path'), path = require('path'),
errors = require('../../server/errors'), errors = require('../../server/errors'),
@ -41,14 +40,14 @@ db = {
// Export data, otherwise send error 500 // Export data, otherwise send error 500
return canThis(options.context).exportContent.db().then(function () { return canThis(options.context).exportContent.db().then(function () {
return dataExport().then(function (exportedData) { return dataExport().then(function (exportedData) {
return when.resolve({ db: [exportedData] }); return { db: [exportedData] };
}).otherwise(function (error) { }).catch(function (error) {
return when.reject(new errors.InternalServerError(error.message || error)); return Promise.reject(new errors.InternalServerError(error.message || error));
});
}, function () {
return Promise.reject(new errors.NoPermissionError('You do not have permission to export data. (no rights)'));
}); });
}, function () {
return when.reject(new errors.NoPermissionError('You do not have permission to export data. (no rights)'));
});
}, },
/** /**
* ### Import Content * ### Import Content
@ -67,16 +66,16 @@ db = {
return canThis(options.context).importContent.db().then(function () { return canThis(options.context).importContent.db().then(function () {
if (!options.importfile || !options.importfile.type || !options.importfile.path) { if (!options.importfile || !options.importfile.type || !options.importfile.path) {
return when.reject(new errors.NoPermissionError('Please select a file to import.')); return Promise.reject(new errors.NoPermissionError('Please select a file to import.'));
} }
type = options.importfile.type; type = options.importfile.type;
ext = path.extname(options.importfile.name).toLowerCase(); ext = path.extname(options.importfile.name).toLowerCase();
filepath = options.importfile.path; filepath = options.importfile.path;
return when(isValidFile(ext)).then(function (result) { return Promise.resolve(isValidFile(ext)).then(function (result) {
if (!result) { if (!result) {
return when.reject(new errors.UnsupportedMediaTypeError('Please select a .json file to import.')); return Promise.reject(new errors.UnsupportedMediaTypeError('Please select a .json file to import.'));
} }
}).then(function () { }).then(function () {
return api.settings.read( return api.settings.read(
@ -84,12 +83,12 @@ db = {
).then(function (response) { ).then(function (response) {
var setting = response.settings[0]; var setting = response.settings[0];
return when(setting.value); return setting.value;
}); });
}).then(function (version) { }).then(function (version) {
databaseVersion = version; databaseVersion = version;
// Read the file contents // Read the file contents
return nodefn.call(fs.readFile, filepath); return Promise.promisify(fs.readFile)(filepath);
}).then(function (fileContents) { }).then(function (fileContents) {
var importData; var importData;
@ -103,11 +102,11 @@ db = {
} }
} catch (e) { } catch (e) {
errors.logError(e, 'API DB import content', 'check that the import file is valid JSON.'); errors.logError(e, 'API DB import content', 'check that the import file is valid JSON.');
return when.reject(new errors.BadRequest('Failed to parse the import JSON file')); return Promise.reject(new errors.BadRequest('Failed to parse the import JSON file'));
} }
if (!importData.meta || !importData.meta.version) { if (!importData.meta || !importData.meta.version) {
return when.reject( return Promise.reject(
new errors.ValidationError('Import data does not specify version', 'meta.version') new errors.ValidationError('Import data does not specify version', 'meta.version')
); );
} }
@ -115,16 +114,14 @@ db = {
// Import for the current version // Import for the current version
return dataImport(databaseVersion, importData); return dataImport(databaseVersion, importData);
}).then(function importSuccess() { }).then(api.settings.updateSettingsCache)
return api.settings.updateSettingsCache(); .return({ db: [] })
}).then(function () { .finally(function () {
return when.resolve({ db: [] });
}).finally(function () {
// Unlink the file after import // Unlink the file after import
return nodefn.call(fs.unlink, filepath); return Promise.promisify(fs.unlink)(filepath);
}); });
}, function () { }, function () {
return when.reject(new errors.NoPermissionError('You do not have permission to import data. (no rights)')); return Promise.reject(new errors.NoPermissionError('You do not have permission to import data. (no rights)'));
}); });
}, },
/** /**
@ -139,14 +136,13 @@ db = {
options = options || {}; options = options || {};
return canThis(options.context).deleteAllContent.db().then(function () { return canThis(options.context).deleteAllContent.db().then(function () {
return when(dataProvider.deleteAllContent()) return Promise.resolve(dataProvider.deleteAllContent())
.then(function () { .return({ db: [] })
return when.resolve({ db: [] }); .catch(function (error) {
}, function (error) { return Promise.reject(new errors.InternalServerError(error.message || error));
return when.reject(new errors.InternalServerError(error.message || error));
}); });
}, function () { }, function () {
return when.reject(new errors.NoPermissionError('You do not have permission to export data. (no rights)')); return Promise.reject(new errors.NoPermissionError('You do not have permission to export data. (no rights)'));
}); });
} }
}; };

View file

@ -5,7 +5,7 @@
// from a theme, an app, or from an external app, you'll use the Ghost JSON API to do so. // from a theme, an app, or from an external app, you'll use the Ghost JSON API to do so.
var _ = require('lodash'), var _ = require('lodash'),
when = require('when'), Promise = require('bluebird'),
config = require('../config'), config = require('../config'),
// Include Endpoints // Include Endpoints
db = require('./db'), db = require('./db'),
@ -90,7 +90,7 @@ cacheInvalidationHeader = function (req, result) {
} }
} }
return when(cacheInvalidate); return Promise.resolve(cacheInvalidate);
}; };
/** /**
@ -122,7 +122,7 @@ locationHeader = function (req, result) {
} }
} }
return when(location); return Promise.resolve(location);
}; };
/** /**
@ -219,7 +219,7 @@ addHeaders = function (apiMethod, req, res, result) {
ops.push(contentDisposition); ops.push(contentDisposition);
} }
return when.all(ops); return Promise.all(ops);
}; };
/** /**

View file

@ -1,7 +1,7 @@
// # Mail API // # Mail API
// API for sending Mail // API for sending Mail
var _ = require('lodash'), var _ = require('lodash'),
when = require('when'), Promise = require('bluebird'),
config = require('../config'), config = require('../config'),
canThis = require('../permissions').canThis, canThis = require('../permissions').canThis,
errors = require('../errors'), errors = require('../errors'),
@ -42,12 +42,12 @@ mail = {
}; };
return object; return object;
}) })
.otherwise(function (error) { .catch(function (error) {
return when.reject(new errors.EmailError(error.message)); return Promise.reject(new errors.EmailError(error.message));
}); });
}, function () { }, function () {
return when.reject(new errors.NoPermissionError('You do not have permission to send mail.')); return Promise.reject(new errors.NoPermissionError('You do not have permission to send mail.'));
}); });
}, },
@ -73,7 +73,7 @@ mail = {
return mail.send(payload, options); return mail.send(payload, options);
}); });
}, function () { }, function () {
return when.reject(new errors.NotFoundError('Could not find the current user')); return Promise.reject(new errors.NotFoundError('Could not find the current user'));
}); });
}, },
@ -95,7 +95,7 @@ mail = {
_.templateSettings.interpolate = /{{([\s\S]+?)}}/g; _.templateSettings.interpolate = /{{([\s\S]+?)}}/g;
//read the proper email body template //read the proper email body template
return when.promise(function (resolve, reject) { return new Promise(function (resolve, reject) {
fs.readFile(templatesDir + '/' + options.template + '.html', {encoding: 'utf8'}, function (err, fileContent) { fs.readFile(templatesDir + '/' + options.template + '.html', {encoding: 'utf8'}, function (err, fileContent) {
if (err) { if (err) {
reject(err); reject(err);

View file

@ -1,6 +1,6 @@
// # Notifications API // # Notifications API
// RESTful API for creating notifications // RESTful API for creating notifications
var when = require('when'), var Promise = require('bluebird'),
_ = require('lodash'), _ = require('lodash'),
canThis = require('../permissions').canThis, canThis = require('../permissions').canThis,
errors = require('../errors'), errors = require('../errors'),
@ -26,9 +26,9 @@ notifications = {
*/ */
browse: function browse(options) { browse: function browse(options) {
return canThis(options.context).browse.notification().then(function () { return canThis(options.context).browse.notification().then(function () {
return when({ 'notifications': notificationsStore }); return { 'notifications': notificationsStore };
}, function () { }, function () {
return when.reject(new errors.NoPermissionError('You do not have permission to browse notifications.')); return Promise.reject(new errors.NoPermissionError('You do not have permission to browse notifications.'));
}); });
}, },
@ -69,10 +69,10 @@ notifications = {
addedNotifications.push(notification); addedNotifications.push(notification);
}); });
return when({ notifications: addedNotifications}); return { notifications: addedNotifications };
}); });
}, function () { }, function () {
return when.reject(new errors.NoPermissionError('You do not have permission to add notifications.')); return Promise.reject(new errors.NoPermissionError('You do not have permission to add notifications.'));
}); });
}, },
@ -90,21 +90,21 @@ notifications = {
}); });
if (notification && !notification.dismissible) { if (notification && !notification.dismissible) {
return when.reject( return Promise.reject(
new errors.NoPermissionError('You do not have permission to dismiss this notification.') new errors.NoPermissionError('You do not have permission to dismiss this notification.')
); );
} }
if (!notification) { if (!notification) {
return when.reject(new errors.NotFoundError('Notification does not exist.')); return Promise.reject(new errors.NotFoundError('Notification does not exist.'));
} }
notificationsStore = _.reject(notificationsStore, function (element) { notificationsStore = _.reject(notificationsStore, function (element) {
return element.id === parseInt(options.id, 10); return element.id === parseInt(options.id, 10);
}); });
return when({notifications: [notification]}); return { notifications: [notification] };
}, function () { }, function () {
return when.reject(new errors.NoPermissionError('You do not have permission to destroy notifications.')); return Promise.reject(new errors.NoPermissionError('You do not have permission to destroy notifications.'));
}); });
}, },
@ -119,9 +119,10 @@ notifications = {
return canThis(options.context).destroy.notification().then(function () { return canThis(options.context).destroy.notification().then(function () {
notificationsStore = []; notificationsStore = [];
notificationCounter = 0; notificationCounter = 0;
return when(notificationsStore);
return notificationsStore;
}, function () { }, function () {
return when.reject(new errors.NoPermissionError('You do not have permission to destroy notifications.')); return Promise.reject(new errors.NoPermissionError('You do not have permission to destroy notifications.'));
}); });
} }
}; };

View file

@ -1,6 +1,6 @@
// # Posts API // # Posts API
// RESTful API for the Post resource // RESTful API for the Post resource
var when = require('when'), var Promise = require('bluebird'),
_ = require('lodash'), _ = require('lodash'),
dataProvider = require('../models'), dataProvider = require('../models'),
canThis = require('../permissions').canThis, canThis = require('../permissions').canThis,
@ -88,8 +88,7 @@ posts = {
return { posts: [ result.toJSON() ]}; return { posts: [ result.toJSON() ]};
} }
return when.reject(new errors.NotFoundError('Post not found.')); return Promise.reject(new errors.NotFoundError('Post not found.'));
}); });
}, },
@ -122,10 +121,10 @@ posts = {
return { posts: [ post ]}; return { posts: [ post ]};
} }
return when.reject(new errors.NotFoundError('Post not found.')); return Promise.reject(new errors.NotFoundError('Post not found.'));
}); });
}, function () { }, function () {
return when.reject(new errors.NoPermissionError('You do not have permission to edit this post.')); return Promise.reject(new errors.NoPermissionError('You do not have permission to edit posts.'));
}); });
}, },
@ -158,7 +157,7 @@ posts = {
return { posts: [ post ]}; return { posts: [ post ]};
}); });
}, function () { }, function () {
return when.reject(new errors.NoPermissionError('You do not have permission to add posts.')); return Promise.reject(new errors.NoPermissionError('You do not have permission to add posts.'));
}); });
}, },
@ -188,7 +187,7 @@ posts = {
}); });
}); });
}, function () { }, function () {
return when.reject(new errors.NoPermissionError('You do not have permission to remove posts.')); return Promise.reject(new errors.NoPermissionError('You do not have permission to remove posts.'));
}); });
} }

View file

@ -1,6 +1,6 @@
// # Roles API // # Roles API
// RESTful API for the Role resource // RESTful API for the Role resource
var when = require('when'), var Promise = require('bluebird'),
_ = require('lodash'), _ = require('lodash'),
canThis = require('../permissions').canThis, canThis = require('../permissions').canThis,
dataProvider = require('../models'), dataProvider = require('../models'),
@ -45,12 +45,12 @@ roles = {
return null; return null;
} }
return role; return role;
}, function () { }).catch(function () {
return null; return null;
})); }));
}); });
return when.all(permissionMap).then(function (resolved) { return Promise.all(permissionMap).then(function (resolved) {
return { roles: _.filter(resolved, function (role) { return { roles: _.filter(resolved, function (role) {
return role !== null; return role !== null;
}) }; }) };

View file

@ -2,7 +2,7 @@
// RESTful API for the Setting resource // RESTful API for the Setting resource
var _ = require('lodash'), var _ = require('lodash'),
dataProvider = require('../models'), dataProvider = require('../models'),
when = require('when'), Promise = require('bluebird'),
config = require('../config'), config = require('../config'),
canThis = require('../permissions').canThis, canThis = require('../permissions').canThis,
errors = require('../errors'), errors = require('../errors'),
@ -44,7 +44,7 @@ updateSettingsCache = function (settings) {
settingsCache[key] = setting; settingsCache[key] = setting;
}); });
return when(settingsCache); return Promise.resolve(settingsCache);
} }
return dataProvider.Settings.findAll() return dataProvider.Settings.findAll()
@ -206,14 +206,14 @@ populateDefaultSetting = function (key) {
}).then(function () { }).then(function () {
// Get the result from the cache with permission checks // Get the result from the cache with permission checks
}); });
}).otherwise(function (err) { }).catch(function (err) {
// Pass along NotFoundError // Pass along NotFoundError
if (typeof err === errors.NotFoundError) { if (typeof err === errors.NotFoundError) {
return when.reject(err); return Promise.reject(err);
} }
// TODO: Different kind of error? // TODO: Different kind of error?
return when.reject(new errors.NotFoundError('Problem finding setting: ' + key)); return Promise.reject(new errors.NotFoundError('Problem finding setting: ' + key));
}); });
}; };
@ -227,13 +227,13 @@ populateDefaultSetting = function (key) {
canEditAllSettings = function (settingsInfo, options) { canEditAllSettings = function (settingsInfo, options) {
var checkSettingPermissions = function (setting) { var checkSettingPermissions = function (setting) {
if (setting.type === 'core' && !(options.context && options.context.internal)) { if (setting.type === 'core' && !(options.context && options.context.internal)) {
return when.reject( return Promise.reject(
new errors.NoPermissionError('Attempted to access core setting from external request') new errors.NoPermissionError('Attempted to access core setting from external request')
); );
} }
return canThis(options.context).edit.setting(setting.key).catch(function () { return canThis(options.context).edit.setting(setting.key).catch(function () {
return when.reject(new errors.NoPermissionError('You do not have permission to edit settings.')); return Promise.reject(new errors.NoPermissionError('You do not have permission to edit settings.'));
}); });
}, },
@ -251,7 +251,7 @@ canEditAllSettings = function (settingsInfo, options) {
return checkSettingPermissions(setting); return checkSettingPermissions(setting);
}); });
return when.all(checks); return Promise.all(checks);
}; };
/** /**
@ -281,7 +281,7 @@ settings = {
// If there is no context, return only blog settings // If there is no context, return only blog settings
if (!options.context) { if (!options.context) {
return when(_.filter(result.settings, function (setting) { return setting.type === 'blog'; })); return Promise.resolve(_.filter(result.settings, function (setting) { return setting.type === 'blog'; }));
} }
// Otherwise return whatever this context is allowed to browse // Otherwise return whatever this context is allowed to browse
@ -312,19 +312,19 @@ settings = {
result[options.key] = setting; result[options.key] = setting;
if (setting.type === 'core' && !(options.context && options.context.internal)) { if (setting.type === 'core' && !(options.context && options.context.internal)) {
return when.reject( return Promise.reject(
new errors.NoPermissionError('Attempted to access core setting from external request') new errors.NoPermissionError('Attempted to access core setting from external request')
); );
} }
if (setting.type === 'blog') { if (setting.type === 'blog') {
return when(settingsResult(result)); return Promise.resolve(settingsResult(result));
} }
return canThis(options.context).read.setting(options.key).then(function () { return canThis(options.context).read.setting(options.key).then(function () {
return settingsResult(result); return settingsResult(result);
}, function () { }, function () {
return when.reject(new errors.NoPermissionError('You do not have permission to read settings.')); return Promise.reject(new errors.NoPermissionError('You do not have permission to read settings.'));
}); });
}; };

View file

@ -3,7 +3,7 @@
var canThis = require('../permissions').canThis, var canThis = require('../permissions').canThis,
dataProvider = require('../models'), dataProvider = require('../models'),
errors = require('../errors'), errors = require('../errors'),
when = require('when'), Promise = require('bluebird'),
slugs, slugs,
allowedTypes; allowedTypes;
@ -35,25 +35,25 @@ slugs = {
return canThis(options.context).generate.slug().then(function () { return canThis(options.context).generate.slug().then(function () {
if (allowedTypes[options.type] === undefined) { if (allowedTypes[options.type] === undefined) {
return when.reject(new errors.BadRequestError('Unknown slug type \'' + options.type + '\'.')); return Promise.reject(new errors.BadRequestError('Unknown slug type \'' + options.type + '\'.'));
} }
return dataProvider.Base.Model.generateSlug(allowedTypes[options.type], options.name, {status: 'all'}).then(function (slug) { return dataProvider.Base.Model.generateSlug(allowedTypes[options.type], options.name, {status: 'all'}).then(function (slug) {
if (!slug) { if (!slug) {
return when.reject(new errors.InternalServerError('Could not generate slug.')); return Promise.reject(new errors.InternalServerError('Could not generate slug.'));
} }
return { slugs: [{ slug: slug }] }; return { slugs: [{ slug: slug }] };
}); });
}).catch(function (err) { }).catch(function (err) {
if (err) { if (err) {
return when.reject(err); return Promise.reject(err);
} }
return when.reject(new errors.NoPermissionError('You do not have permission to generate a slug.')); return Promise.reject(new errors.NoPermissionError('You do not have permission to generate a slug.'));
}); });
} }
}; };
module.exports = slugs; module.exports = slugs;

View file

@ -1,6 +1,6 @@
// # Tag API // # Tag API
// RESTful API for the Tag resource // RESTful API for the Tag resource
var when = require('when'), var Promise = require('bluebird'),
canThis = require('../permissions').canThis, canThis = require('../permissions').canThis,
dataProvider = require('../models'), dataProvider = require('../models'),
errors = require('../errors'), errors = require('../errors'),
@ -24,9 +24,9 @@ tags = {
}); });
}, function () { }, function () {
return when.reject(new errors.NoPermissionError('You do not have permission to browse tags.')); return Promise.reject(new errors.NoPermissionError('You do not have permission to browse tags.'));
}); });
} }
}; };
module.exports = tags; module.exports = tags;

View file

@ -1,12 +1,11 @@
// # Themes API // # Themes API
// RESTful API for Themes // RESTful API for Themes
var when = require('when'), var Promise = require('bluebird'),
_ = require('lodash'), _ = require('lodash'),
canThis = require('../permissions').canThis, canThis = require('../permissions').canThis,
config = require('../config'), config = require('../config'),
errors = require('../errors'), errors = require('../errors'),
settings = require('./settings'), settings = require('./settings'),
when = require('when'),
themes; themes;
/** /**
@ -25,7 +24,7 @@ themes = {
options = options || {}; options = options || {};
return canThis(options.context).browse.theme().then(function () { return canThis(options.context).browse.theme().then(function () {
return when.all([ return Promise.all([
settings.read({key: 'activeTheme', context: {internal: true}}), settings.read({key: 'activeTheme', context: {internal: true}}),
config.paths.availableThemes config.paths.availableThemes
]).then(function (result) { ]).then(function (result) {
@ -57,7 +56,7 @@ themes = {
return { themes: themes }; return { themes: themes };
}); });
}, function () { }, function () {
return when.reject(new errors.NoPermissionError('You do not have permission to browse themes.')); return Promise.reject(new errors.NoPermissionError('You do not have permission to browse themes.'));
}); });
}, },
@ -73,7 +72,7 @@ themes = {
// Check whether the request is properly formatted. // Check whether the request is properly formatted.
if (!_.isArray(object.themes)) { if (!_.isArray(object.themes)) {
return when.reject({type: 'BadRequest', message: 'Invalid request.'}); return Promise.reject({type: 'BadRequest', message: 'Invalid request.'});
} }
themeName = object.themes[0].uuid; themeName = object.themes[0].uuid;
@ -88,7 +87,7 @@ themes = {
}); });
if (!theme) { if (!theme) {
return when.reject(new errors.BadRequestError('Theme does not exist.')); return Promise.reject(new errors.BadRequestError('Theme does not exist.'));
} }
// Activate the theme // Activate the theme
@ -100,7 +99,7 @@ themes = {
}); });
}); });
}, function () { }, function () {
return when.reject(new errors.NoPermissionError('You do not have permission to edit themes.')); return Promise.reject(new errors.NoPermissionError('You do not have permission to edit themes.'));
}); });
} }
}; };

View file

@ -1,14 +1,11 @@
var when = require('when'), var Promise = require('bluebird'),
path = require('path'), path = require('path'),
nodefn = require('when/node'),
fs = require('fs-extra'), fs = require('fs-extra'),
storage = require('../storage'), storage = require('../storage'),
errors = require('../errors'), errors = require('../errors'),
upload; upload;
function isImage(type, ext) { function isImage(type, ext) {
if ((type === 'image/jpeg' || type === 'image/png' || type === 'image/gif' || type === 'image/svg+xml') if ((type === 'image/jpeg' || type === 'image/png' || type === 'image/gif' || type === 'image/svg+xml')
&& (ext === '.jpg' || ext === '.jpeg' || ext === '.png' || ext === '.gif' || ext === '.svg' || ext === '.svgz')) { && (ext === '.jpg' || ext === '.jpeg' || ext === '.png' || ext === '.gif' || ext === '.svg' || ext === '.svgz')) {
@ -17,7 +14,6 @@ function isImage(type, ext) {
return false; return false;
} }
/** /**
* ## Upload API Methods * ## Upload API Methods
* *
@ -32,33 +28,33 @@ upload = {
* @param {{context}} options * @param {{context}} options
* @returns {Promise} Success * @returns {Promise} Success
*/ */
'add': function (options) { add: function (options) {
var store = storage.get_storage(), var store = storage.get_storage(),
type, type,
ext, ext,
filepath; filepath;
if (!options.uploadimage || !options.uploadimage.type || !options.uploadimage.path) { if (!options.uploadimage || !options.uploadimage.type || !options.uploadimage.path) {
return when.reject(new errors.NoPermissionError('Please select an image.')); return Promise.reject(new errors.NoPermissionError('Please select an image.'));
} }
type = options.uploadimage.type; type = options.uploadimage.type;
ext = path.extname(options.uploadimage.name).toLowerCase(); ext = path.extname(options.uploadimage.name).toLowerCase();
filepath = options.uploadimage.path; filepath = options.uploadimage.path;
return when(isImage(type, ext)).then(function (result) { return Promise.resolve(isImage(type, ext)).then(function (result) {
if (!result) { if (!result) {
return when.reject(new errors.UnsupportedMediaTypeError('Please select a valid image.')); return Promise.reject(new errors.UnsupportedMediaTypeError('Please select a valid image.'));
} }
}).then(function () { }).then(function () {
return store.save(options.uploadimage); return store.save(options.uploadimage);
}).then(function (url) { }).then(function (url) {
return when.resolve(url); return url;
}).finally(function () { }).finally(function () {
// Remove uploaded file from tmp location // Remove uploaded file from tmp location
return nodefn.call(fs.unlink, filepath); return Promise.promisify(fs.unlink)(filepath);
}); });
} }
}; };
module.exports = upload; module.exports = upload;

View file

@ -1,6 +1,6 @@
// # Users API // # Users API
// RESTful API for the User resource // RESTful API for the User resource
var when = require('when'), var Promise = require('bluebird'),
_ = require('lodash'), _ = require('lodash'),
dataProvider = require('../models'), dataProvider = require('../models'),
settings = require('./settings'), settings = require('./settings'),
@ -26,7 +26,7 @@ function prepareInclude(include) {
sendInviteEmail = function sendInviteEmail(user) { sendInviteEmail = function sendInviteEmail(user) {
var emailData; var emailData;
return when.join( return Promise.join(
users.read({'id': user.created_by}), users.read({'id': user.created_by}),
settings.read({'key': 'title'}), settings.read({'key': 'title'}),
settings.read({context: {internal: true}, key: 'dbHash'}) settings.read({context: {internal: true}, key: 'dbHash'})
@ -114,7 +114,7 @@ users = {
return { users: [result.toJSON()] }; return { users: [result.toJSON()] };
} }
return when.reject(new errors.NotFoundError('User not found.')); return Promise.reject(new errors.NotFoundError('User not found.'));
}); });
}, },
@ -143,7 +143,7 @@ users = {
return { users: [result.toJSON()]}; return { users: [result.toJSON()]};
} }
return when.reject(new errors.NotFoundError('User not found.')); return Promise.reject(new errors.NotFoundError('User not found.'));
}); });
}; };
@ -160,7 +160,7 @@ users = {
if (roleId !== contextRoleId && if (roleId !== contextRoleId &&
parseInt(options.id, 10) === parseInt(options.context.user, 10)) { parseInt(options.id, 10) === parseInt(options.context.user, 10)) {
return when.reject(new errors.NoPermissionError('You cannot change your own role.')); return Promise.reject(new errors.NoPermissionError('You cannot change your own role.'));
} else if (roleId !== contextRoleId) { } else if (roleId !== contextRoleId) {
return dataProvider.User.findOne({role: 'Owner'}).then(function (result) { return dataProvider.User.findOne({role: 'Owner'}).then(function (result) {
if (parseInt(result.id, 10) !== parseInt(options.id, 10)) { if (parseInt(result.id, 10) !== parseInt(options.id, 10)) {
@ -168,7 +168,7 @@ users = {
return editOperation(); return editOperation();
}); });
} else { } else {
return when.reject(new errors.NoPermissionError('There has to be one owner.')); return Promise.reject(new errors.NoPermissionError('There has to be one owner.'));
} }
}); });
} }
@ -208,7 +208,7 @@ users = {
newUser.password = globalUtils.uid(50); newUser.password = globalUtils.uid(50);
newUser.status = 'invited'; newUser.status = 'invited';
} else { } else {
return when.reject(new errors.BadRequestError('No email provided.')); return Promise.reject(new errors.BadRequestError('No email provided.'));
} }
return dataProvider.User.getByEmail( return dataProvider.User.getByEmail(
@ -221,7 +221,7 @@ users = {
if (foundUser.get('status') === 'invited' || foundUser.get('status') === 'invited-pending') { if (foundUser.get('status') === 'invited' || foundUser.get('status') === 'invited-pending') {
return foundUser; return foundUser;
} else { } else {
return when.reject(new errors.BadRequestError('User is already registered.')); return Promise.reject(new errors.BadRequestError('User is already registered.'));
} }
} }
}).then(function (invitedUser) { }).then(function (invitedUser) {
@ -237,7 +237,7 @@ users = {
}); });
} }
}).then(function () { }).then(function () {
return when.resolve({users: [user]}); return Promise.resolve({users: [user]});
}).catch(function (error) { }).catch(function (error) {
if (error && error.type === 'EmailError') { if (error && error.type === 'EmailError') {
error.message = 'Error sending email: ' + error.message + ' Please check your email settings and resend the invitation.'; error.message = 'Error sending email: ' + error.message + ' Please check your email settings and resend the invitation.';
@ -250,7 +250,7 @@ users = {
}); });
}); });
} }
return when.reject(error); return Promise.reject(error);
}); });
}; };
@ -262,7 +262,7 @@ users = {
// Make sure user is allowed to add a user with this role // Make sure user is allowed to add a user with this role
return dataProvider.Role.findOne({id: roleId}).then(function (role) { return dataProvider.Role.findOne({id: roleId}).then(function (role) {
if (role.get('name') === 'Owner') { if (role.get('name') === 'Owner') {
return when.reject(new errors.NoPermissionError('Not allowed to create an owner user.')); return Promise.reject(new errors.NoPermissionError('Not allowed to create an owner user.'));
} }
return canThis(options.context).assign.role(role); return canThis(options.context).assign.role(role);
@ -300,7 +300,7 @@ users = {
}).then(function () { }).then(function () {
return result; return result;
}, function (error) { }, function (error) {
return when.reject(new errors.InternalServerError(error)); return Promise.reject(new errors.InternalServerError(error));
}); });
}, function (error) { }, function (error) {
return errors.handleAPIError(error); return errors.handleAPIError(error);
@ -327,9 +327,9 @@ users = {
ne2Password = checkedPasswordReset.password[0].ne2Password; ne2Password = checkedPasswordReset.password[0].ne2Password;
return dataProvider.User.changePassword(oldPassword, newPassword, ne2Password, options).then(function () { return dataProvider.User.changePassword(oldPassword, newPassword, ne2Password, options).then(function () {
return when.resolve({password: [{message: 'Password changed successfully.'}]}); return Promise.resolve({password: [{message: 'Password changed successfully.'}]});
}).catch(function (error) { }).catch(function (error) {
return when.reject(new errors.ValidationError(error.message)); return Promise.reject(new errors.ValidationError(error.message));
}); });
}); });
}, },
@ -343,9 +343,9 @@ users = {
}).then(function () { }).then(function () {
return utils.checkObject(object, 'owner').then(function (checkedOwnerTransfer) { return utils.checkObject(object, 'owner').then(function (checkedOwnerTransfer) {
return dataProvider.User.transferOwnership(checkedOwnerTransfer.owner[0], options).then(function (updatedUsers) { return dataProvider.User.transferOwnership(checkedOwnerTransfer.owner[0], options).then(function (updatedUsers) {
return when.resolve({ users: updatedUsers }); return Promise.resolve({ users: updatedUsers });
}).catch(function (error) { }).catch(function (error) {
return when.reject(new errors.ValidationError(error.message)); return Promise.reject(new errors.ValidationError(error.message));
}); });
}); });
}).catch(function (error) { }).catch(function (error) {

View file

@ -1,6 +1,6 @@
// # API Utils // # API Utils
// Shared helpers for working with the API // Shared helpers for working with the API
var when = require('when'), var Promise = require('bluebird'),
_ = require('lodash'), _ = require('lodash'),
errors = require('../errors'), errors = require('../errors'),
utils; utils;
@ -27,8 +27,8 @@ utils = {
delete object.posts[0].author; delete object.posts[0].author;
} }
} }
return when(object); return Promise.resolve(object);
} }
}; };
module.exports = utils; module.exports = utils;

View file

@ -2,7 +2,7 @@
var _ = require('lodash'), var _ = require('lodash'),
fs = require('fs'), fs = require('fs'),
path = require('path'), path = require('path'),
when = require('when'), Promise = require('bluebird'),
spawn = require('child_process').spawn, spawn = require('child_process').spawn,
win32 = process.platform === 'win32'; win32 = process.platform === 'win32';
@ -11,32 +11,33 @@ function AppDependencies(appPath) {
} }
AppDependencies.prototype.install = function installAppDependencies() { AppDependencies.prototype.install = function installAppDependencies() {
var def = when.defer(), var spawnOpts,
spawnOpts; self = this;
fs.exists(path.join(this.appPath, 'package.json'), function (exists) { return new Promise(function (resolve, reject) {
if (!exists) { fs.exists(path.join(self.appPath, 'package.json'), function (exists) {
// Nothing to do, resolve right away? if (!exists) {
def.resolve(); // Nothing to do, resolve right away?
} else { resolve();
// Run npm install in the app directory }
spawnOpts = { else {
cwd: this.appPath // Run npm install in the app directory
}; spawnOpts = {
cwd: self.appPath
};
this.spawnCommand('npm', ['install', '--production'], spawnOpts) self.spawnCommand('npm', ['install', '--production'], spawnOpts)
.on('error', def.reject) .on('error', reject)
.on('exit', function (err) { .on('exit', function (err) {
if (err) { if (err) {
def.reject(err); reject(err);
} }
def.resolve(); resolve();
}); });
} }
}.bind(this)); });
});
return def.promise;
}; };
// Normalize a command across OS and spawn it; taken from yeoman/generator // Normalize a command across OS and spawn it; taken from yeoman/generator
@ -49,4 +50,4 @@ AppDependencies.prototype.spawnCommand = function (command, args, opt) {
return spawn(winCommand, winArgs, _.defaults({ stdio: 'inherit' }, opt)); return spawn(winCommand, winArgs, _.defaults({ stdio: 'inherit' }, opt));
}; };
module.exports = AppDependencies; module.exports = AppDependencies;

View file

@ -1,13 +1,12 @@
var _ = require('lodash'), var _ = require('lodash'),
when = require('when'), Promise = require('bluebird'),
errors = require('../errors'), errors = require('../errors'),
api = require('../api'), api = require('../api'),
loader = require('./loader'), loader = require('./loader'),
// Holds the available apps // Holds the available apps
availableApps = {}; availableApps = {};
function getInstalledApps() { function getInstalledApps() {
return api.settings.read({context: {internal: true}, key: 'installedApps'}).then(function (response) { return api.settings.read({context: {internal: true}, key: 'installedApps'}).then(function (response) {
var installed = response.settings[0]; var installed = response.settings[0];
@ -17,7 +16,7 @@ function getInstalledApps() {
try { try {
installed = JSON.parse(installed.value); installed = JSON.parse(installed.value);
} catch (e) { } catch (e) {
return when.reject(e); return Promise.reject(e);
} }
return installed; return installed;
@ -49,7 +48,8 @@ module.exports = {
'Your apps will not be loaded.', 'Your apps will not be loaded.',
'Check your settings table for typos in the activeApps value. It should look like: ["app-1", "app2"] (double quotes required).' 'Check your settings table for typos in the activeApps value. It should look like: ["app-1", "app2"] (double quotes required).'
); );
return when.resolve();
return Promise.resolve();
} }
// Grab all installed apps, install any not already installed that are in appsToLoad. // Grab all installed apps, install any not already installed that are in appsToLoad.
@ -59,7 +59,7 @@ module.exports = {
// After loading the app, add it to our hash of loaded apps // After loading the app, add it to our hash of loaded apps
loadedApps[name] = loadedApp; loadedApps[name] = loadedApp;
return when.resolve(loadedApp); return Promise.resolve(loadedApp);
}, },
loadPromises = _.map(appsToLoad, function (app) { loadPromises = _.map(appsToLoad, function (app) {
// If already installed, just activate the app // If already installed, just activate the app
@ -77,13 +77,13 @@ module.exports = {
}); });
}); });
return when.all(loadPromises).then(function () { return Promise.all(loadPromises).then(function () {
// Save our installed apps to settings // Save our installed apps to settings
return saveInstalledApps(_.keys(loadedApps)); return saveInstalledApps(_.keys(loadedApps));
}).then(function () { }).then(function () {
// Extend the loadedApps onto the available apps // Extend the loadedApps onto the available apps
_.extend(availableApps, loadedApps); _.extend(availableApps, loadedApps);
}).otherwise(function (err) { }).catch(function (err) {
errors.logError( errors.logError(
err.message || err, err.message || err,
'The app will not be loaded', 'The app will not be loaded',
@ -93,4 +93,4 @@ module.exports = {
}); });
}, },
availableApps: availableApps availableApps: availableApps
}; };

View file

@ -1,7 +1,7 @@
var path = require('path'), var path = require('path'),
_ = require('lodash'), _ = require('lodash'),
when = require('when'), Promise = require('bluebird'),
AppProxy = require('./proxy'), AppProxy = require('./proxy'),
config = require('../config'), config = require('../config'),
AppSandbox = require('./sandbox'), AppSandbox = require('./sandbox'),
@ -64,9 +64,9 @@ loader = {
// Load app permissions // Load app permissions
var perms = new AppPermissions(appPath); var perms = new AppPermissions(appPath);
return perms.read().otherwise(function (err) { return perms.read().catch(function (err) {
// Provide a helpful error about which app // Provide a helpful error about which app
return when.reject(new Error("Error loading app named " + name + "; problem reading permissions: " + err.message)); return Promise.reject(new Error("Error loading app named " + name + "; problem reading permissions: " + err.message));
}); });
}) })
.then(function (appPerms) { .then(function (appPerms) {
@ -76,15 +76,13 @@ loader = {
// Check for an install() method on the app. // Check for an install() method on the app.
if (!_.isFunction(app.install)) { if (!_.isFunction(app.install)) {
return when.reject(new Error("Error loading app named " + name + "; no install() method defined.")); return Promise.reject(new Error("Error loading app named " + name + "; no install() method defined."));
} }
// Run the app.install() method // Run the app.install() method
// Wrapping the install() with a when because it's possible // Wrapping the install() with a when because it's possible
// to not return a promise from it. // to not return a promise from it.
return when(app.install(appProxy)).then(function () { return Promise.resolve(app.install(appProxy)).return(app);
return when.resolve(app);
});
}); });
}, },
@ -99,16 +97,14 @@ loader = {
// Check for an activate() method on the app. // Check for an activate() method on the app.
if (!_.isFunction(app.activate)) { if (!_.isFunction(app.activate)) {
return when.reject(new Error("Error loading app named " + name + "; no activate() method defined.")); return Promise.reject(new Error("Error loading app named " + name + "; no activate() method defined."));
} }
// Wrapping the activate() with a when because it's possible // Wrapping the activate() with a when because it's possible
// to not return a promise from it. // to not return a promise from it.
return when(app.activate(appProxy)).then(function () { return Promise.resolve(app.activate(appProxy)).return(app);
return when.resolve(app);
});
}); });
} }
}; };
module.exports = loader; module.exports = loader;

View file

@ -1,6 +1,6 @@
var fs = require('fs'), var fs = require('fs'),
when = require('when'), Promise = require('bluebird'),
path = require('path'), path = require('path'),
parsePackageJson = require('../require-tree').parsePackageJson; parsePackageJson = require('../require-tree').parsePackageJson;
@ -10,44 +10,35 @@ function AppPermissions(appPath) {
} }
AppPermissions.prototype.read = function () { AppPermissions.prototype.read = function () {
var self = this, var self = this;
def = when.defer();
this.checkPackageContentsExists() return this.checkPackageContentsExists().then(function (exists) {
.then(function (exists) {
if (!exists) { if (!exists) {
// If no package.json, return default permissions // If no package.json, return default permissions
return def.resolve(AppPermissions.DefaultPermissions); return Promise.resolve(AppPermissions.DefaultPermissions);
} }
// Read and parse the package.json // Read and parse the package.json
self.getPackageContents() return self.getPackageContents().then(function (parsed) {
.then(function (parsed) {
// If no permissions in the package.json then return the default permissions. // If no permissions in the package.json then return the default permissions.
if (!(parsed.ghost && parsed.ghost.permissions)) { if (!(parsed.ghost && parsed.ghost.permissions)) {
return def.resolve(AppPermissions.DefaultPermissions); return Promise.resolve(AppPermissions.DefaultPermissions);
} }
// TODO: Validation on permissions object? // TODO: Validation on permissions object?
def.resolve(parsed.ghost.permissions); return Promise.resolve(parsed.ghost.permissions);
}) });
.otherwise(def.reject); });
})
.otherwise(def.reject);
return def.promise;
}; };
AppPermissions.prototype.checkPackageContentsExists = function () { AppPermissions.prototype.checkPackageContentsExists = function () {
// Mostly just broken out for stubbing in unit tests // Mostly just broken out for stubbing in unit tests
var def = when.defer(); return new Promise(function (resolve) {
fs.exists(this.packagePath, function (exists) {
fs.exists(this.packagePath, function (exists) { resolve(exists);
def.resolve(exists); });
}); });
return def.promise;
}; };
// Get the contents of the package.json in the appPath root // Get the contents of the package.json in the appPath root
@ -60,7 +51,7 @@ AppPermissions.prototype.getPackageContents = function () {
return parsePackageJson(this.packagePath, messages) return parsePackageJson(this.packagePath, messages)
.then(function (parsed) { .then(function (parsed) {
if (!parsed) { if (!parsed) {
return when.reject(new Error(messages.errors[0].message)); return Promise.reject(new Error(messages.errors[0].message));
} }
return parsed; return parsed;
@ -72,4 +63,4 @@ AppPermissions.DefaultPermissions = {
posts: ['browse', 'read'] posts: ['browse', 'read']
}; };
module.exports = AppPermissions; module.exports = AppPermissions;

View file

@ -4,7 +4,7 @@
// All other files that need to reference config.js should use this file. // All other files that need to reference config.js should use this file.
var path = require('path'), var path = require('path'),
when = require('when'), Promise = require('bluebird'),
url = require('url'), url = require('url'),
_ = require('lodash'), _ = require('lodash'),
knex = require('knex'), knex = require('knex'),
@ -101,7 +101,7 @@ function initConfig(rawConfig) {
// just the object appropriate for this NODE_ENV // just the object appropriate for this NODE_ENV
updateConfig(rawConfig); updateConfig(rawConfig);
return when.all([requireTree(ghostConfig.paths.themePath), requireTree(ghostConfig.paths.appPath)]).then(function (paths) { return Promise.all([requireTree(ghostConfig.paths.themePath), requireTree(ghostConfig.paths.appPath)]).then(function (paths) {
ghostConfig.paths.availableThemes = paths[0]; ghostConfig.paths.availableThemes = paths[0];
ghostConfig.paths.availableApps = paths[1]; ghostConfig.paths.availableApps = paths[1];
return ghostConfig; return ghostConfig;

View file

@ -1,7 +1,7 @@
// Holds all theme configuration information // Holds all theme configuration information
// that as mostly used by templates and handlebar helpers. // that as mostly used by templates and handlebar helpers.
var when = require('when'), var Promise = require('bluebird'),
// Variables // Variables
themeConfig = {}; themeConfig = {};
@ -18,7 +18,7 @@ function theme() {
// tries to access the config() object before it is created. // tries to access the config() object before it is created.
function update(settings, configUrl) { function update(settings, configUrl) {
// TODO: Pass the context into this method instead of hard coding internal: true? // TODO: Pass the context into this method instead of hard coding internal: true?
return when.all([ return Promise.all([
settings.read('title'), settings.read('title'),
settings.read('description'), settings.read('description'),
settings.read('logo'), settings.read('logo'),
@ -30,7 +30,6 @@ function update(settings, configUrl) {
themeConfig.description = globals[1].settings[0].value; themeConfig.description = globals[1].settings[0].value;
themeConfig.logo = globals[2].settings[0] ? globals[2].settings[0].value : ''; themeConfig.logo = globals[2].settings[0] ? globals[2].settings[0].value : '';
themeConfig.cover = globals[3].settings[0] ? globals[3].settings[0].value : ''; themeConfig.cover = globals[3].settings[0] ? globals[3].settings[0].value : '';
return;
}); });
} }

View file

@ -1,5 +1,4 @@
var _ = require('lodash'), var _ = require('lodash'),
when = require('when'),
api = require('../api'), api = require('../api'),
errors = require('../errors'), errors = require('../errors'),
updateCheck = require('../update-check'), updateCheck = require('../update-check'),
@ -9,7 +8,7 @@ adminControllers = {
// Route: index // Route: index
// Path: /ghost/ // Path: /ghost/
// Method: GET // Method: GET
'index': function (req, res) { index: function (req, res) {
/*jslint unparam:true*/ /*jslint unparam:true*/
function renderIndex() { function renderIndex() {
@ -20,7 +19,7 @@ adminControllers = {
return updateCheck.showUpdateNotification(); return updateCheck.showUpdateNotification();
}).then(function (updateVersion) { }).then(function (updateVersion) {
if (!updateVersion) { if (!updateVersion) {
return when.resolve(); return;
} }
var notification = { var notification = {

View file

@ -8,8 +8,7 @@ var moment = require('moment'),
RSS = require('rss'), RSS = require('rss'),
_ = require('lodash'), _ = require('lodash'),
url = require('url'), url = require('url'),
when = require('when'), Promise = require('bluebird'),
api = require('../api'), api = require('../api'),
config = require('../config'), config = require('../config'),
filters = require('../../server/filters'), filters = require('../../server/filters'),
@ -84,9 +83,7 @@ function formatResponse(post) {
function handleError(next) { function handleError(next) {
return function (err) { return function (err) {
var e = new Error(err.message); return next(err);
e.status = err.code;
return next(e);
}; };
} }
@ -152,7 +149,7 @@ frontendControllers = {
res.render(view, formatPageResponse(posts, page)); res.render(view, formatPageResponse(posts, page));
}); });
}); });
}).otherwise(handleError(next)); }).catch(handleError(next));
}, },
'tag': function (req, res, next) { 'tag': function (req, res, next) {
// Parse the page number // Parse the page number
@ -206,7 +203,7 @@ frontendControllers = {
res.render(view, result); res.render(view, result);
}); });
}); });
}).otherwise(handleError(next)); }).catch(handleError(next));
}, },
'author': function (req, res, next) { 'author': function (req, res, next) {
@ -263,7 +260,7 @@ frontendControllers = {
res.render(view, result); res.render(view, result);
}); });
}); });
}).otherwise(handleError(next)); }).catch(handleError(next));
}, },
'single': function (req, res, next) { 'single': function (req, res, next) {
@ -290,7 +287,7 @@ frontendControllers = {
// If there are still no matches then return. // If there are still no matches then return.
if (staticPostPermalink.match(path) === false) { if (staticPostPermalink.match(path) === false) {
// Reject promise chain with type 'NotFound' // Reject promise chain with type 'NotFound'
return when.reject(new errors.NotFoundError()); return Promise.reject(new errors.NotFoundError());
} }
permalink = staticPostPermalink; permalink = staticPostPermalink;
@ -324,7 +321,7 @@ frontendControllers = {
return res.redirect(config.paths.subdir + '/ghost/editor/' + post.id + '/'); return res.redirect(config.paths.subdir + '/ghost/editor/' + post.id + '/');
} else if (params.edit !== undefined) { } else if (params.edit !== undefined) {
// reject with type: 'NotFound' // reject with type: 'NotFound'
return when.reject(new errors.NotFoundError()); return Promise.reject(new errors.NotFoundError());
} }
setReqCtx(req, post); setReqCtx(req, post);
@ -380,7 +377,7 @@ frontendControllers = {
return render(); return render();
}).otherwise(function (err) { }).catch(function (err) {
// If we've thrown an error message // If we've thrown an error message
// of type: 'NotFound' then we found // of type: 'NotFound' then we found
// no path match. // no path match.
@ -422,13 +419,13 @@ frontendControllers = {
return res.redirect(baseUrl); return res.redirect(baseUrl);
} }
return when.settle([ return Promise.all([
api.settings.read('title'), api.settings.read('title'),
api.settings.read('description'), api.settings.read('description'),
api.settings.read('permalinks') api.settings.read('permalinks')
]).then(function (result) { ]).then(function (result) {
var options = {}; var options = {};
if (pageParam) { options.page = pageParam; } if (pageParam) { options.page = pageParam; }
if (isTag()) { options.tag = slugParam; } if (isTag()) { options.tag = slugParam; }
if (isAuthor()) { options.author = slugParam; } if (isAuthor()) { options.author = slugParam; }
@ -436,16 +433,14 @@ frontendControllers = {
options.include = 'author,tags,fields'; options.include = 'author,tags,fields';
return api.posts.browse(options).then(function (page) { return api.posts.browse(options).then(function (page) {
var title = result[0].settings[0].value,
var title = result[0].value.settings[0].value, description = result[1].settings[0].value,
description = result[1].value.settings[0].value, permalinks = result[2].settings[0],
permalinks = result[2].value.settings[0],
majorMinor = /^(\d+\.)?(\d+)/, majorMinor = /^(\d+\.)?(\d+)/,
trimmedVersion = res.locals.version, trimmedVersion = res.locals.version,
siteUrl = config.urlFor('home', {secure: req.secure}, true), siteUrl = config.urlFor('home', {secure: req.secure}, true),
feedUrl = config.urlFor('rss', {secure: req.secure}, true), feedUrl = config.urlFor('rss', {secure: req.secure}, true),
maxPage = page.meta.pagination.pages, maxPage = page.meta.pagination.pages,
feedItems = [],
feed; feed;
trimmedVersion = trimmedVersion ? trimmedVersion.match(majorMinor)[0] : '?'; trimmedVersion = trimmedVersion ? trimmedVersion.match(majorMinor)[0] : '?';
@ -482,8 +477,7 @@ frontendControllers = {
filters.doFilter('prePostsRender', page.posts).then(function (posts) { filters.doFilter('prePostsRender', page.posts).then(function (posts) {
posts.forEach(function (post) { posts.forEach(function (post) {
var deferred = when.defer(), var item = {
item = {
title: post.title, title: post.title,
guid: post.uuid, guid: post.uuid,
url: config.urlFor('post', {post: post, permalinks: permalinks}, true), url: config.urlFor('post', {post: post, permalinks: permalinks}, true),
@ -499,25 +493,23 @@ frontendControllers = {
p1 = url.resolve(siteUrl, p1); p1 = url.resolve(siteUrl, p1);
return "src='" + p1 + "' "; return "src='" + p1 + "' ";
}); });
//set a href to absolute url //set a href to absolute url
content = content.replace(/href=["|'|\s]?([\w\/\?\$\.\+\-;%:@&=,_]+)["|'|\s]?/gi, function (match, p1) { content = content.replace(/href=["|'|\s]?([\w\/\?\$\.\+\-;%:@&=,_]+)["|'|\s]?/gi, function (match, p1) {
/*jslint unparam:true*/ /*jslint unparam:true*/
p1 = url.resolve(siteUrl, p1); p1 = url.resolve(siteUrl, p1);
return "href='" + p1 + "' "; return "href='" + p1 + "' ";
}); });
item.description = content; item.description = content;
feed.item(item); feed.item(item);
feedItems.push(deferred.promise);
deferred.resolve();
}); });
}); }).then(function () {
when.all(feedItems).then(function () {
res.set('Content-Type', 'text/xml; charset=UTF-8'); res.set('Content-Type', 'text/xml; charset=UTF-8');
res.send(feed.xml()); res.send(feed.xml());
}); });
}); });
}).otherwise(handleError(next)); }).catch(handleError(next));
} }
}; };

View file

@ -1,6 +1,5 @@
var _ = require('lodash'), var _ = require('lodash'),
when = require('when'), Promise = require('bluebird'),
versioning = require('../versioning'), versioning = require('../versioning'),
config = require('../../config'), config = require('../../config'),
utils = require('../utils'), utils = require('../utils'),
@ -28,7 +27,7 @@ exportFileName = function () {
}; };
exporter = function () { exporter = function () {
return when.join(versioning.getDatabaseVersion(), utils.getTables()).then(function (results) { return Promise.join(versioning.getDatabaseVersion(), utils.getTables()).then(function (results) {
var version = results[0], var version = results[0],
tables = results[1], tables = results[1],
selectOps = _.map(tables, function (name) { selectOps = _.map(tables, function (name) {
@ -37,7 +36,7 @@ exporter = function () {
} }
}); });
return when.all(selectOps).then(function (tableData) { return Promise.all(selectOps).then(function (tableData) {
var exportData = { var exportData = {
meta: { meta: {
exported_on: new Date().getTime(), exported_on: new Date().getTime(),
@ -52,7 +51,7 @@ exporter = function () {
exportData.data[name] = tableData[i]; exportData.data[name] = tableData[i];
}); });
return when.resolve(exportData); return exportData;
}).catch(function (err) { }).catch(function (err) {
errors.logAndThrowError(err, 'Error exporting data', ''); errors.logAndThrowError(err, 'Error exporting data', '');
}); });

View file

@ -5,8 +5,8 @@
// rather than abstracted into a migration system. The upgrade function checks that its changes are safe before // rather than abstracted into a migration system. The upgrade function checks that its changes are safe before
// making them. // making them.
var when = require('when'), var Promise = require('bluebird'),
sequence = require('when/sequence'), sequence = require('../../utils/sequence'),
_ = require('lodash'), _ = require('lodash'),
errors = require('../../errors'), errors = require('../../errors'),
utils = require('../../utils'), utils = require('../../utils'),
@ -101,7 +101,7 @@ populate = function () {
}); });
}); });
return when.all(ops).then(function () { return Promise.all(ops).then(function () {
return sequence(relations); return sequence(relations);
}).then(function () { }).then(function () {
return permissions.populate(options); return permissions.populate(options);
@ -150,7 +150,7 @@ to003 = function () {
}); });
ops.push(upgradeOp); ops.push(upgradeOp);
return when.all(ops).then(function () { return Promise.all(ops).then(function () {
return permissions.to003(options); return permissions.to003(options);
}).then(function () { }).then(function () {
return convertAdminToOwner(); return convertAdminToOwner();

View file

@ -1,7 +1,7 @@
// # Permissions Fixtures // # Permissions Fixtures
// Sets up the permissions, and the default permissions_roles relationships // Sets up the permissions, and the default permissions_roles relationships
var when = require('when'), var Promise = require('bluebird'),
sequence = require('when/sequence'), sequence = require('../../../utils/sequence'),
_ = require('lodash'), _ = require('lodash'),
errors = require('../../../errors'), errors = require('../../../errors'),
models = require('../../../models'), models = require('../../../models'),
@ -52,7 +52,7 @@ addAllRolesPermissions = function () {
ops.push(addRolesPermissionsForRole(roleName)); ops.push(addRolesPermissionsForRole(roleName));
}); });
return when.all(ops); return Promise.all(ops);
}; };
@ -100,7 +100,7 @@ to003 = function (options) {
}); });
// Now we can perfom the normal populate // Now we can perfom the normal populate
return when.all(ops).then(function () { return Promise.all(ops).then(function () {
return populate(options); return populate(options);
}); });
}; };

View file

@ -1,7 +1,7 @@
var when = require('when'), var Promise = require('bluebird'),
_ = require('lodash'), _ = require('lodash'),
models = require('../../models'), models = require('../../models'),
utils = require('./utils'), utils = require('./utils'),
Importer000; Importer000;
@ -23,17 +23,15 @@ Importer000.prototype.importData = function (data) {
return this.canImport(data) return this.canImport(data)
.then(function (importerFunc) { .then(function (importerFunc) {
return importerFunc(data); return importerFunc(data);
}, function (reason) {
return when.reject(reason);
}); });
}; };
Importer000.prototype.canImport = function (data) { Importer000.prototype.canImport = function (data) {
if (data.meta && data.meta.version && this.importFrom[data.meta.version]) { if (data.meta && data.meta.version && this.importFrom[data.meta.version]) {
return when.resolve(this.importFrom[data.meta.version]); return Promise.resolve(this.importFrom[data.meta.version]);
} }
return when.reject('Unsupported version of data: ' + data.meta.version); return Promise.reject('Unsupported version of data: ' + data.meta.version);
}; };
@ -49,10 +47,10 @@ Importer000.prototype.loadUsers = function () {
}); });
if (!users.owner) { if (!users.owner) {
return when.reject('Unable to find an owner'); return Promise.reject('Unable to find an owner');
} }
return when.resolve(users); return users;
}); });
}; };
@ -72,12 +70,12 @@ Importer000.prototype.doUserImport = function (t, tableData, users, errors) {
// Import users, deduplicating with already present users // Import users, deduplicating with already present users
userOps = utils.importUsers(tableData.users, users, t); userOps = utils.importUsers(tableData.users, users, t);
return when.settle(userOps).then(function (descriptors) { return Promise.settle(userOps).then(function (descriptors) {
descriptors.forEach(function (d) { descriptors.forEach(function (d) {
if (d.state === 'rejected') { if (d.isRejected()) {
errors = errors.concat(d.reason); errors = errors.concat(d.reason());
} else { } else {
imported.push(d.value.toJSON()); imported.push(d.value().toJSON());
} }
}); });
@ -85,12 +83,12 @@ Importer000.prototype.doUserImport = function (t, tableData, users, errors) {
if (errors.length > 0) { if (errors.length > 0) {
t.rollback(errors); t.rollback(errors);
} else { } else {
return when.resolve(imported); return imported;
} }
}); });
} }
return when.resolve({}); return Promise.resolve({});
}; };
Importer000.prototype.doImport = function (data) { Importer000.prototype.doImport = function (data) {
@ -149,13 +147,12 @@ Importer000.prototype.doImport = function (data) {
*/ */
// Write changes to DB, if successful commit, otherwise rollback // Write changes to DB, if successful commit, otherwise rollback
// when.all() does not work as expected, when.settle() does. Promise.settle(ops).then(function (descriptors) {
when.settle(ops).then(function (descriptors) {
var errors = []; var errors = [];
descriptors.forEach(function (d) { descriptors.forEach(function (d) {
if (d.state === 'rejected') { if (d.isRejected()) {
errors = errors.concat(d.reason); errors = errors.concat(d.reason());
} }
}); });
@ -168,9 +165,7 @@ Importer000.prototype.doImport = function (data) {
}); });
}).then(function () { }).then(function () {
//TODO: could return statistics of imported items //TODO: could return statistics of imported items
return when.resolve(); return Promise.resolve();
}, function (error) {
return when.reject(error);
}); });
}); });
}; };

View file

@ -1,4 +1,4 @@
var when = require('when'), var Promise = require('bluebird'),
_ = require('lodash'), _ = require('lodash'),
validation = require('../validation'), validation = require('../validation'),
errors = require('../../errors'), errors = require('../../errors'),
@ -43,7 +43,7 @@ handleErrors = function handleErrors(errorList) {
var processedErrors = []; var processedErrors = [];
if (!_.isArray(errorList)) { if (!_.isArray(errorList)) {
return when.reject(errorList); return Promise.reject(errorList);
} }
_.each(errorList, function (error) { _.each(errorList, function (error) {
@ -57,7 +57,7 @@ handleErrors = function handleErrors(errorList) {
} }
}); });
return when.reject(processedErrors); return Promise.reject(processedErrors);
}; };
validate = function validate(data) { validate = function validate(data) {
@ -69,20 +69,18 @@ validate = function validate(data) {
}); });
}); });
return when.settle(validateOps).then(function (descriptors) { return Promise.settle(validateOps).then(function (descriptors) {
var errorList = []; var errorList = [];
_.each(descriptors, function (d) { _.each(descriptors, function (d) {
if (d.state === 'rejected') { if (d.isRejected()) {
errorList = errorList.concat(d.reason); errorList = errorList.concat(d.reason());
} }
}); });
if (!_.isEmpty(errorList)) { if (!_.isEmpty(errorList)) {
return when.reject(errorList); return Promise.reject(errorList);
} }
return when.resolve();
}); });
}; };
@ -97,7 +95,7 @@ module.exports = function (version, data) {
} }
if (!importer) { if (!importer) {
return when.reject('No importer found'); return Promise.reject('No importer found');
} }
return importer.importData(data); return importer.importData(data);

View file

@ -1,4 +1,4 @@
var when = require('when'), var Promise = require('bluebird'),
_ = require('lodash'), _ = require('lodash'),
models = require('../../models'), models = require('../../models'),
errors = require('../../errors'), errors = require('../../errors'),
@ -162,10 +162,11 @@ utils = {
return models.Tag.add(tag, _.extend(internal, {transacting: transaction})) return models.Tag.add(tag, _.extend(internal, {transacting: transaction}))
// add pass-through error handling so that bluebird doesn't think we've dropped it // add pass-through error handling so that bluebird doesn't think we've dropped it
.catch(function (error) { .catch(function (error) {
return when.reject({raw: error, model: 'tag', data: tag}); return Promise.reject({raw: error, model: 'tag', data: tag});
}); });
} }
return when.resolve(_tag);
return _tag;
})); }));
}); });
}, },
@ -180,7 +181,7 @@ utils = {
ops.push(models.Post.add(post, _.extend(internal, {transacting: transaction, importing: true})) ops.push(models.Post.add(post, _.extend(internal, {transacting: transaction, importing: true}))
// add pass-through error handling so that bluebird doesn't think we've dropped it // add pass-through error handling so that bluebird doesn't think we've dropped it
.catch(function (error) { .catch(function (error) {
return when.reject({raw: error, model: 'post', data: post}); return Promise.reject({raw: error, model: 'post', data: post});
})); }));
}); });
}, },
@ -207,7 +208,7 @@ utils = {
ops.push(models.User.add(user, _.extend(internal, {transacting: transaction})) ops.push(models.User.add(user, _.extend(internal, {transacting: transaction}))
// add pass-through error handling so that bluebird doesn't think we've dropped it // add pass-through error handling so that bluebird doesn't think we've dropped it
.catch(function (error) { .catch(function (error) {
return when.reject({raw: error, model: 'user', data: user}); return Promise.reject({raw: error, model: 'user', data: user});
})); }));
}); });
@ -233,7 +234,7 @@ utils = {
ops.push(models.Settings.edit(tableData, _.extend(internal, {transacting: transaction})) ops.push(models.Settings.edit(tableData, _.extend(internal, {transacting: transaction}))
// add pass-through error handling so that bluebird doesn't think we've dropped it // add pass-through error handling so that bluebird doesn't think we've dropped it
.catch(function (error) { .catch(function (error) {
return when.reject({raw: error, model: 'setting', data: tableData}); return Promise.reject({raw: error, model: 'setting', data: tableData});
})); }));
}, },
@ -247,13 +248,14 @@ utils = {
return models.App.add(app, _.extend(internal, {transacting: transaction})) return models.App.add(app, _.extend(internal, {transacting: transaction}))
// add pass-through error handling so that bluebird doesn't think we've dropped it // add pass-through error handling so that bluebird doesn't think we've dropped it
.catch(function (error) { .catch(function (error) {
return when.reject({raw: error, model: 'app', data: app}); return Promise.reject({raw: error, model: 'app', data: app});
}); });
} }
return when.resolve(_app);
return _app;
})); }));
}); });
} }
}; };
module.exports = utils; module.exports = utils;

View file

@ -1,11 +1,9 @@
var _ = require('lodash'), var _ = require('lodash'),
when = require('when'), Promise = require('bluebird'),
sequence = require('../../utils/sequence'),
path = require('path'), path = require('path'),
fs = require('fs'), fs = require('fs'),
nodefn = require('when/node'),
errors = require('../../errors'), errors = require('../../errors'),
sequence = require('when/sequence'),
commands = require('./commands'), commands = require('./commands'),
versioning = require('../versioning'), versioning = require('../versioning'),
models = require('../../models'), models = require('../../models'),
@ -47,7 +45,7 @@ backupDatabase = function backupDatabase() {
return dataExport.fileName().then(function (fileName) { return dataExport.fileName().then(function (fileName) {
fileName = path.resolve(config.paths.contentPath + '/data/' + fileName); fileName = path.resolve(config.paths.contentPath + '/data/' + fileName);
return nodefn.call(fs.writeFile, fileName, JSON.stringify(exportedData)).then(function () { return Promise.promisify(fs.writeFile)(fileName, JSON.stringify(exportedData)).then(function () {
logInfo('Database backup written to: ' + fileName); logInfo('Database backup written to: ' + fileName);
}); });
}); });
@ -80,7 +78,7 @@ init = function (tablesOnly) {
if (databaseVersion === defaultVersion) { if (databaseVersion === defaultVersion) {
// 1. The database exists and is up-to-date // 1. The database exists and is up-to-date
logInfo('Up to date at version ' + databaseVersion); logInfo('Up to date at version ' + databaseVersion);
return when.resolve(); return;
} }
if (databaseVersion > defaultVersion) { if (databaseVersion > defaultVersion) {
@ -155,7 +153,7 @@ migrateUp = function (fromVersion, toVersion) {
}).then(function () { }).then(function () {
migrateOps = migrateOps.concat(commands.getDeleteCommands(oldTables, schemaTables)); migrateOps = migrateOps.concat(commands.getDeleteCommands(oldTables, schemaTables));
migrateOps = migrateOps.concat(commands.getAddCommands(oldTables, schemaTables)); migrateOps = migrateOps.concat(commands.getAddCommands(oldTables, schemaTables));
return when.all( return Promise.all(
_.map(oldTables, function (table) { _.map(oldTables, function (table) {
return utils.getIndexes(table).then(function (indexes) { return utils.getIndexes(table).then(function (indexes) {
modifyUniCommands = modifyUniCommands.concat(commands.modifyUniqueCommands(table, indexes)); modifyUniCommands = modifyUniCommands.concat(commands.modifyUniqueCommands(table, indexes));
@ -163,7 +161,7 @@ migrateUp = function (fromVersion, toVersion) {
}) })
); );
}).then(function () { }).then(function () {
return when.all( return Promise.all(
_.map(oldTables, function (table) { _.map(oldTables, function (table) {
return utils.getColumns(table).then(function (columns) { return utils.getColumns(table).then(function (columns) {
migrateOps = migrateOps.concat(commands.addColumnCommands(table, columns)); migrateOps = migrateOps.concat(commands.addColumnCommands(table, columns));
@ -177,9 +175,9 @@ migrateUp = function (fromVersion, toVersion) {
// execute the commands in sequence // execute the commands in sequence
if (!_.isEmpty(migrateOps)) { if (!_.isEmpty(migrateOps)) {
logInfo('Running migrations'); logInfo('Running migrations');
return sequence(migrateOps); return sequence(migrateOps);
} }
return;
}).then(function () { }).then(function () {
return fixtures.update(fromVersion, toVersion); return fixtures.update(fromVersion, toVersion);
}).then(function () { }).then(function () {
@ -192,4 +190,4 @@ module.exports = {
reset: reset, reset: reset,
migrateUp: migrateUp, migrateUp: migrateUp,
migrateUpFreshDb: migrateUpFreshDb migrateUpFreshDb: migrateUpFreshDb
}; };

View file

@ -1,5 +1,4 @@
var _ = require('lodash'), var _ = require('lodash'),
when = require('when'),
config = require('../../../config/index'), config = require('../../../config/index'),
//private //private
@ -43,9 +42,7 @@ checkPostTable = function checkPostTable() {
return config.database.knex.raw('SHOW FIELDS FROM posts where Field ="html" OR Field = "markdown"').then(function (response) { return config.database.knex.raw('SHOW FIELDS FROM posts where Field ="html" OR Field = "markdown"').then(function (response) {
return _.flatten(_.map(response[0], function (entry) { return _.flatten(_.map(response[0], function (entry) {
if (entry.Type.toLowerCase() !== 'mediumtext') { if (entry.Type.toLowerCase() !== 'mediumtext') {
return config.database.knex.raw('ALTER TABLE posts MODIFY ' + entry.Field + ' MEDIUMTEXT').then(function () { return config.database.knex.raw('ALTER TABLE posts MODIFY ' + entry.Field + ' MEDIUMTEXT');
return when.resolve();
});
} }
})); }));
}); });
@ -56,4 +53,4 @@ module.exports = {
getTables: getTables, getTables: getTables,
getIndexes: getIndexes, getIndexes: getIndexes,
getColumns: getColumns getColumns: getColumns
}; };

View file

@ -1,13 +1,13 @@
var _ = require('lodash'), var _ = require('lodash'),
config = require('../../../config/index'), config = require('../../../config/index'),
//private //private
doRaw, doRaw,
// public // public
getTables, getTables,
getIndexes, getIndexes,
getColumns; getColumns;
doRaw = function doRaw(query, fn) { doRaw = function doRaw(query, fn) {

View file

@ -1,5 +1,5 @@
var _ = require('lodash'), var _ = require('lodash'),
when = require('when'), Promise = require('bluebird'),
config = require('../../config'), config = require('../../config'),
schema = require('../schema').tables, schema = require('../schema').tables,
clients = require('./clients'), clients = require('./clients'),
@ -87,7 +87,7 @@ function getTables() {
return clients[client].getTables(); return clients[client].getTables();
} }
return when.reject('No support for database client ' + client); return Promise.reject('No support for database client ' + client);
} }
function getIndexes(table) { function getIndexes(table) {
@ -98,7 +98,7 @@ function getIndexes(table) {
return clients[client].getIndexes(table); return clients[client].getIndexes(table);
} }
return when.reject('No support for database client ' + client); return Promise.reject('No support for database client ' + client);
} }
function getColumns(table) { function getColumns(table) {
@ -109,7 +109,7 @@ function getColumns(table) {
return clients[client].getColumns(table); return clients[client].getColumns(table);
} }
return when.reject('No support for database client ' + client); return Promise.reject('No support for database client ' + client);
} }
function checkTables() { function checkTables() {

View file

@ -1,7 +1,7 @@
var schema = require('../schema').tables, var schema = require('../schema').tables,
_ = require('lodash'), _ = require('lodash'),
validator = require('validator'), validator = require('validator'),
when = require('when'), Promise = require('bluebird'),
errors = require('../../errors'), errors = require('../../errors'),
config = require('../../config'), config = require('../../config'),
requireTree = require('../../require-tree').readAll, requireTree = require('../../require-tree').readAll,
@ -73,10 +73,10 @@ validateSchema = function (tableName, model) {
}); });
if (validationErrors.length !== 0) { if (validationErrors.length !== 0) {
return when.reject(validationErrors); return Promise.reject(validationErrors);
} }
return when.resolve(); return Promise.resolve();
}; };
// Validation for settings // Validation for settings
@ -92,10 +92,10 @@ validateSettings = function (defaultSettings, model) {
} }
if (validationErrors.length !== 0) { if (validationErrors.length !== 0) {
return when.reject(validationErrors); return Promise.reject(validationErrors);
} }
return when.resolve(); return Promise.resolve();
}; };
// A Promise that will resolve to an object with a property for each installed theme. // A Promise that will resolve to an object with a property for each installed theme.
@ -107,15 +107,13 @@ validateActiveTheme = function (themeName) {
// If Ghost is running and its availableThemes collection exists // If Ghost is running and its availableThemes collection exists
// give it priority. // give it priority.
if (config.paths.availableThemes && Object.keys(config.paths.availableThemes).length > 0) { if (config.paths.availableThemes && Object.keys(config.paths.availableThemes).length > 0) {
availableThemes = when(config.paths.availableThemes); availableThemes = Promise.resolve(config.paths.availableThemes);
} }
return availableThemes.then(function (themes) { return availableThemes.then(function (themes) {
if (!themes.hasOwnProperty(themeName)) { if (!themes.hasOwnProperty(themeName)) {
return when.reject(new errors.ValidationError(themeName + ' cannot be activated because it is not currently installed.', 'activeTheme')); return Promise.reject(new errors.ValidationError(themeName + ' cannot be activated because it is not currently installed.', 'activeTheme'));
} }
return when.resolve();
}); });
}; };

View file

@ -3,7 +3,7 @@ var _ = require('lodash'),
colors = require('colors'), colors = require('colors'),
config = require('../config'), config = require('../config'),
path = require('path'), path = require('path'),
when = require('when'), Promise = require('bluebird'),
hbs = require('express-hbs'), hbs = require('express-hbs'),
NotFoundError = require('./notfounderror'), NotFoundError = require('./notfounderror'),
BadRequestError = require('./badrequesterror'), BadRequestError = require('./badrequesterror'),
@ -47,7 +47,7 @@ errors = {
// ## Reject Error // ## Reject Error
// Used to pass through promise errors when we want to handle them at a later time // Used to pass through promise errors when we want to handle them at a later time
rejectError: function (err) { rejectError: function (err) {
return when.reject(err); return Promise.reject(err);
}, },
logInfo: function (component, info) { logInfo: function (component, info) {

View file

@ -1,10 +1,8 @@
var when = require('when'), var Promise = require('bluebird'),
pipeline = require('./utils/pipeline'),
_ = require('lodash'), _ = require('lodash'),
defaults; defaults;
when.pipeline = require('when/pipeline');
// ## Default values // ## Default values
/** /**
* A hash of default values to use instead of 'magic' numbers/strings. * A hash of default values to use instead of 'magic' numbers/strings.
@ -64,7 +62,7 @@ Filters.prototype.doFilter = function (name, args, context) {
// Bug out early if no callbacks by that name // Bug out early if no callbacks by that name
if (!callbacks) { if (!callbacks) {
return when.resolve(args); return Promise.resolve(args);
} }
// For each priorityLevel // For each priorityLevel
@ -75,7 +73,7 @@ Filters.prototype.doFilter = function (name, args, context) {
// Bug out if no handlers on this priority // Bug out if no handlers on this priority
if (!_.isArray(callbacks[priority])) { if (!_.isArray(callbacks[priority])) {
return when.resolve(currentArgs); return Promise.resolve(currentArgs);
} }
callables = _.map(callbacks[priority], function (callback) { callables = _.map(callbacks[priority], function (callback) {
@ -84,11 +82,11 @@ Filters.prototype.doFilter = function (name, args, context) {
}; };
}); });
// Call each handler for this priority level, allowing for promises or values // Call each handler for this priority level, allowing for promises or values
return when.pipeline(callables, currentArgs); return pipeline(callables, currentArgs);
}); });
}); });
return when.pipeline(priorityCallbacks, args); return pipeline(priorityCallbacks, args);
}; };
module.exports = new Filters(); module.exports = new Filters();

View file

@ -2,8 +2,7 @@ var downsize = require('downsize'),
hbs = require('express-hbs'), hbs = require('express-hbs'),
moment = require('moment'), moment = require('moment'),
_ = require('lodash'), _ = require('lodash'),
when = require('when'), Promise = require('bluebird'),
api = require('../api'), api = require('../api'),
config = require('../config'), config = require('../config'),
errors = require('../errors'), errors = require('../errors'),
@ -147,15 +146,15 @@ coreHelpers.url = function (options) {
} }
if (schema.isTag(this)) { if (schema.isTag(this)) {
return when(config.urlFor('tag', {tag: this}, absolute)); return Promise.resolve(config.urlFor('tag', {tag: this}, absolute));
} }
if (schema.isUser(this)) { if (schema.isUser(this)) {
return when(config.urlFor('author', {author: this}, absolute)); return Promise.resolve(config.urlFor('author', {author: this}, absolute));
} }
return when(config.urlFor(this, absolute)); return Promise.resolve(config.urlFor(this, absolute));
}; };
// ### Asset helper // ### Asset helper
@ -786,9 +785,9 @@ function registerAsyncHelper(hbs, name, fn) {
hbs.registerAsyncHelper(name, function (options, cb) { hbs.registerAsyncHelper(name, function (options, cb) {
// Wrap the function passed in with a when.resolve so it can // Wrap the function passed in with a when.resolve so it can
// return either a promise or a value // return either a promise or a value
when.resolve(fn.call(this, options)).then(function (result) { Promise.resolve(fn.call(this, options)).then(function (result) {
cb(result); cb(result);
}).otherwise(function (err) { }).catch(function (err) {
errors.logAndThrowError(err, 'registerAsyncThemeHelper: ' + name); errors.logAndThrowError(err, 'registerAsyncThemeHelper: ' + name);
}); });
}); });

View file

@ -6,7 +6,7 @@ var crypto = require('crypto'),
fs = require('fs'), fs = require('fs'),
uuid = require('node-uuid'), uuid = require('node-uuid'),
_ = require('lodash'), _ = require('lodash'),
when = require('when'), Promise = require('bluebird'),
api = require('./api'), api = require('./api'),
config = require('./config'), config = require('./config'),
@ -24,13 +24,6 @@ var crypto = require('crypto'),
// Variables // Variables
dbHash; dbHash;
// If we're in development mode, require "when/console/monitor"
// for help in seeing swallowed promise errors, and log any
// stderr messages from bluebird promises.
if (process.env.NODE_ENV === 'development') {
require('when/monitor/console');
}
function doFirstRun() { function doFirstRun() {
var firstRunMessage = [ var firstRunMessage = [
'Welcome to Ghost.', 'Welcome to Ghost.',
@ -80,30 +73,29 @@ function builtFilesExist() {
helpers.scriptFiles.production : helpers.scriptFiles.development; helpers.scriptFiles.production : helpers.scriptFiles.development;
function checkExist(fileName) { function checkExist(fileName) {
var deferred = when.defer(), var errorMessage = "Javascript files have not been built.",
errorMessage = "Javascript files have not been built.",
errorHelp = "\nPlease read the getting started instructions at:" + errorHelp = "\nPlease read the getting started instructions at:" +
"\nhttps://github.com/TryGhost/Ghost#getting-started-guide-for-developers"; "\nhttps://github.com/TryGhost/Ghost#getting-started-guide-for-developers";
fs.exists(fileName, function (exists) { return new Promise(function (resolve, reject) {
if (exists) { fs.exists(fileName, function (exists) {
deferred.resolve(true); if (exists) {
} else { resolve(true);
var err = new Error(errorMessage); } else {
var err = new Error(errorMessage);
err.help = errorHelp; err.help = errorHelp;
deferred.reject(err); reject(err);
} }
});
}); });
return deferred.promise;
} }
fileNames.forEach(function (fileName) { fileNames.forEach(function (fileName) {
deferreds.push(checkExist(location + fileName)); deferreds.push(checkExist(location + fileName));
}); });
return when.all(deferreds); return Promise.all(deferreds);
} }
// This is run after every initialization is done, right before starting server. // This is run after every initialization is done, right before starting server.
@ -174,7 +166,7 @@ function init(server) {
// into this method due to circular dependencies. // into this method due to circular dependencies.
return config.theme.update(api.settings, config.url); return config.theme.update(api.settings, config.url);
}).then(function () { }).then(function () {
return when.join( return Promise.join(
// Check for or initialise a dbHash. // Check for or initialise a dbHash.
initDbHashAndFirstRun(), initDbHashAndFirstRun(),
// Initialize mail // Initialize mail
@ -219,7 +211,6 @@ function init(server) {
errors.logWarn(warn.message, warn.context, warn.help); errors.logWarn(warn.message, warn.context, warn.help);
}); });
return new GhostServer(server); return new GhostServer(server);
}); });
} }

View file

@ -1,7 +1,6 @@
var cp = require('child_process'), var cp = require('child_process'),
_ = require('lodash'), _ = require('lodash'),
when = require('when'), Promise = require('bluebird'),
nodefn = require('when/node'),
nodemailer = require('nodemailer'), nodemailer = require('nodemailer'),
config = require('./config'); config = require('./config');
@ -17,7 +16,7 @@ GhostMailer.prototype.init = function () {
self.state = {}; self.state = {};
if (config.mail && config.mail.transport) { if (config.mail && config.mail.transport) {
this.createTransport(); this.createTransport();
return when.resolve(); return Promise.resolve();
} }
// Attempt to detect and fallback to `sendmail` // Attempt to detect and fallback to `sendmail`
@ -26,11 +25,9 @@ GhostMailer.prototype.init = function () {
path: binpath path: binpath
}); });
self.state.usingSendmail = true; self.state.usingSendmail = true;
}, function () { }).catch(function () {
self.state.emailDisabled = true; self.state.emailDisabled = true;
self.transport = null; self.transport = null;
}).ensure(function () {
return when.resolve();
}); });
}; };
@ -40,13 +37,15 @@ GhostMailer.prototype.isWindows = function () {
GhostMailer.prototype.detectSendmail = function () { GhostMailer.prototype.detectSendmail = function () {
if (this.isWindows()) { if (this.isWindows()) {
return when.reject(); return Promise.reject();
} }
return when.promise(function (resolve, reject) {
return new Promise(function (resolve, reject) {
cp.exec('which sendmail', function (err, stdout) { cp.exec('which sendmail', function (err, stdout) {
if (err && !/bin\/sendmail/.test(stdout)) { if (err && !/bin\/sendmail/.test(stdout)) {
return reject(); return reject();
} }
resolve(stdout.toString().replace(/(\n|\r|\r\n)$/, '')); resolve(stdout.toString().replace(/(\n|\r|\r\n)$/, ''));
}); });
}); });
@ -63,7 +62,7 @@ GhostMailer.prototype.fromAddress = function () {
if (!from) { if (!from) {
// Extract the domain name from url set in config.js // Extract the domain name from url set in config.js
domain = config.url.match(new RegExp("^https?://([^/:?#]+)(?:[/:?#]|$)", "i")); domain = config.url.match(new RegExp('^https?://([^/:?#]+)(?:[/:?#]|$)', 'i'));
domain = domain && domain[1]; domain = domain && domain[1];
// Default to ghost@[blog.url] // Default to ghost@[blog.url]
@ -84,12 +83,12 @@ GhostMailer.prototype.send = function (message) {
to = message.to || false; to = message.to || false;
if (!this.transport) { if (!this.transport) {
return when.reject(new Error('Email Error: No e-mail transport configured.')); return Promise.reject(new Error('Email Error: No e-mail transport configured.'));
} }
if (!(message && message.subject && message.html && message.to)) { if (!(message && message.subject && message.html && message.to)) {
return when.reject(new Error('Email Error: Incomplete message data.')); return Promise.reject(new Error('Email Error: Incomplete message data.'));
} }
sendMail = nodefn.lift(self.transport.sendMail.bind(self.transport)); sendMail = Promise.promisify(self.transport.sendMail.bind(self.transport));
message = _.extend(message, { message = _.extend(message, {
from: self.fromAddress(), from: self.fromAddress(),

View file

@ -130,7 +130,7 @@ function updateActiveTheme(req, res, next) {
} }
} }
next(); next();
}).otherwise(function (err) { }).catch(function (err) {
// Trying to start up without the active theme present, setup a simple hbs instance // Trying to start up without the active theme present, setup a simple hbs instance
// and render an error page straight away. // and render an error page straight away.
expressServer.engine('hbs', hbs.express3()); expressServer.engine('hbs', hbs.express3());
@ -147,7 +147,7 @@ function redirectToSetup(req, res, next) {
return res.redirect(config.paths.subdir + '/ghost/setup/'); return res.redirect(config.paths.subdir + '/ghost/setup/');
} }
next(); next();
}).otherwise(function (err) { }).catch(function (err) {
return next(new Error(err)); return next(new Error(err));
}); });
} }

View file

@ -6,7 +6,7 @@
// accesses the models directly. All other parts of Ghost, including the blog frontend, admin UI, and apps are only // accesses the models directly. All other parts of Ghost, including the blog frontend, admin UI, and apps are only
// allowed to access data via the API. // allowed to access data via the API.
var bookshelf = require('bookshelf'), var bookshelf = require('bookshelf'),
when = require('when'), Promise = require('bluebird'),
moment = require('moment'), moment = require('moment'),
_ = require('lodash'), _ = require('lodash'),
uuid = require('node-uuid'), uuid = require('node-uuid'),
@ -55,7 +55,7 @@ ghostBookshelf.Model = ghostBookshelf.Model.extend({
this.on('creating', this.creating, this); this.on('creating', this.creating, this);
this.on('saving', function (model, attributes, options) { this.on('saving', function (model, attributes, options) {
return when(self.saving(model, attributes, options)).then(function () { return Promise.resolve(self.saving(model, attributes, options)).then(function () {
return self.validate(model, attributes, options); return self.validate(model, attributes, options);
}); });
}); });
@ -327,7 +327,7 @@ ghostBookshelf.Model = ghostBookshelf.Model.extend({
var trimSpace; var trimSpace;
if (!found) { if (!found) {
return when.resolve(slugToFind); return slugToFind;
} }
slugTryCount += 1; slugTryCount += 1;

View file

@ -1,5 +1,5 @@
var _ = require('lodash'), var _ = require('lodash'),
when = require('when'), Promise = require('bluebird'),
requireTree = require('../require-tree'), requireTree = require('../require-tree'),
models; models;
@ -48,12 +48,12 @@ models = {
var self = this; var self = this;
return self.Post.findAll().then(function (posts) { return self.Post.findAll().then(function (posts) {
return when.all(_.map(posts.toJSON(), function (post) { return Promise.all(_.map(posts.toJSON(), function (post) {
return self.Post.destroy({id: post.id}); return self.Post.destroy({id: post.id});
})); }));
}).then(function () { }).then(function () {
return self.Tag.findAll().then(function (tags) { return self.Tag.findAll().then(function (tags) {
return when.all(_.map(tags.toJSON(), function (tag) { return Promise.all(_.map(tags.toJSON(), function (tag) {
return self.Tag.destroy({id: tag.id}); return self.Tag.destroy({id: tag.id});
})); }));
}); });

View file

@ -1,7 +1,7 @@
// # Post Model // # Post Model
var _ = require('lodash'), var _ = require('lodash'),
uuid = require('node-uuid'), uuid = require('node-uuid'),
when = require('when'), Promise = require('bluebird'),
errors = require('../errors'), errors = require('../errors'),
Showdown = require('showdown'), Showdown = require('showdown'),
ghostgfm = require('../../shared/lib/showdown/extensions/ghostgfm'), ghostgfm = require('../../shared/lib/showdown/extensions/ghostgfm'),
@ -123,7 +123,7 @@ Post = ghostBookshelf.Model.extend({
tagOps.push(post.tags().detach(null, _.omit(options, 'query'))); tagOps.push(post.tags().detach(null, _.omit(options, 'query')));
if (_.isEmpty(self.myTags)) { if (_.isEmpty(self.myTags)) {
return when.all(tagOps); return Promise.all(tagOps);
} }
return ghostBookshelf.collection('Tags').forge().query('whereIn', 'name', _.pluck(self.myTags, 'name')).fetch(options).then(function (existingTags) { return ghostBookshelf.collection('Tags').forge().query('whereIn', 'name', _.pluck(self.myTags, 'name')).fetch(options).then(function (existingTags) {
@ -157,7 +157,7 @@ Post = ghostBookshelf.Model.extend({
tagOps.push(post.tags().attach(tag.id, _.omit(options, 'query'))); tagOps.push(post.tags().attach(tag.id, _.omit(options, 'query')));
}); });
return when.all(tagOps); return Promise.all(tagOps);
}); });
}); });
}, },
@ -341,7 +341,7 @@ Post = ghostBookshelf.Model.extend({
return false; return false;
} }
return when.join(fetchTagQuery(), fetchAuthorQuery()) return Promise.join(fetchTagQuery(), fetchAuthorQuery())
// Set the limit & offset for the query, fetching // Set the limit & offset for the query, fetching
// with the opts (to specify any eager relations, etc.) // with the opts (to specify any eager relations, etc.)
@ -536,16 +536,16 @@ Post = ghostBookshelf.Model.extend({
options = this.filterOptions(options, 'destroyByAuthor'); options = this.filterOptions(options, 'destroyByAuthor');
if (authorId) { if (authorId) {
return postCollection.query('where', 'author_id', '=', authorId).fetch(options).then(function (results) { return postCollection.query('where', 'author_id', '=', authorId).fetch(options).then(function (results) {
return when.map(results.models, function (post) { return Promise.map(results.models, function (post) {
return post.related('tags').detach(null, options).then(function () { return post.related('tags').detach(null, options).then(function () {
return post.destroy(options); return post.destroy(options);
}); });
}); });
}, function (error) { }, function (error) {
return when.reject(new errors.InternalServerError(error.message || error)); return Promise.reject(new errors.InternalServerError(error.message || error));
}); });
} }
return when.reject(new errors.NotFoundError('No user found')); return Promise.reject(new errors.NotFoundError('No user found'));
}, },
@ -574,10 +574,10 @@ Post = ghostBookshelf.Model.extend({
} }
if (hasUserPermission && hasAppPermission) { if (hasUserPermission && hasAppPermission) {
return when.resolve(); return Promise.resolve();
} }
return when.reject(); return Promise.reject();
} }
}); });

View file

@ -1,7 +1,7 @@
var _ = require('lodash'), var _ = require('lodash'),
errors = require('../errors'), errors = require('../errors'),
ghostBookshelf = require('./base'), ghostBookshelf = require('./base'),
when = require('when'), Promise = require('bluebird'),
Role, Role,
Roles; Roles;
@ -73,9 +73,10 @@ Role = ghostBookshelf.Model.extend({
} }
if (hasUserPermission && hasAppPermission) { if (hasUserPermission && hasAppPermission) {
return when.resolve(); return Promise.resolve();
} }
return when.reject();
return Promise.reject();
} }
}); });

View file

@ -3,7 +3,7 @@ var Settings,
uuid = require('node-uuid'), uuid = require('node-uuid'),
_ = require('lodash'), _ = require('lodash'),
errors = require('../errors'), errors = require('../errors'),
when = require('when'), Promise = require('bluebird'),
validation = require('../data/validation'), validation = require('../data/validation'),
internal = {context: {internal: true}}, internal = {context: {internal: true}},
@ -64,7 +64,7 @@ Settings = ghostBookshelf.Model.extend({
var themeName = setting.value || ''; var themeName = setting.value || '';
if (setting.key !== 'activeTheme') { if (setting.key !== 'activeTheme') {
return when.resolve(); return;
} }
return validation.validateActiveTheme(themeName); return validation.validateActiveTheme(themeName);
@ -87,7 +87,7 @@ Settings = ghostBookshelf.Model.extend({
if (!_.isObject(options)) { if (!_.isObject(options)) {
options = { key: options }; options = { key: options };
} }
return when(ghostBookshelf.Model.findOne.call(this, options)); return Promise.resolve(ghostBookshelf.Model.findOne.call(this, options));
}, },
edit: function (data, options) { edit: function (data, options) {
@ -98,11 +98,11 @@ Settings = ghostBookshelf.Model.extend({
data = [data]; data = [data];
} }
return when.map(data, function (item) { return Promise.map(data, function (item) {
// Accept an array of models as input // Accept an array of models as input
if (item.toJSON) { item = item.toJSON(); } if (item.toJSON) { item = item.toJSON(); }
if (!(_.isString(item.key) && item.key.length > 0)) { if (!(_.isString(item.key) && item.key.length > 0)) {
return when.reject(new errors.ValidationError('Value in [settings.key] cannot be blank.')); return Promise.reject(new errors.ValidationError('Value in [settings.key] cannot be blank.'));
} }
item = self.filterData(item); item = self.filterData(item);
@ -113,7 +113,7 @@ Settings = ghostBookshelf.Model.extend({
return setting.save({value: item.value}, options); return setting.save({value: item.value}, options);
} }
return when.reject(new errors.NotFoundError('Unable to find setting to update: ' + item.key)); return Promise.reject(new errors.NotFoundError('Unable to find setting to update: ' + item.key));
}, errors.logAndThrowError); }, errors.logAndThrowError);
}); });
@ -121,7 +121,7 @@ Settings = ghostBookshelf.Model.extend({
populateDefault: function (key) { populateDefault: function (key) {
if (!getDefaultSettings()[key]) { if (!getDefaultSettings()[key]) {
return when.reject(new errors.NotFoundError('Unable to find default setting: ' + key)); return Promise.reject(new errors.NotFoundError('Unable to find default setting: ' + key));
} }
return this.findOne({ key: key }).then(function (foundSetting) { return this.findOne({ key: key }).then(function (foundSetting) {
@ -153,7 +153,7 @@ Settings = ghostBookshelf.Model.extend({
} }
}); });
return when.all(insertOperations); return Promise.all(insertOperations);
}); });
} }

View file

@ -1,7 +1,6 @@
var _ = require('lodash'), var _ = require('lodash'),
when = require('when'), Promise = require('bluebird'),
errors = require('../errors'), errors = require('../errors'),
nodefn = require('when/node'),
bcrypt = require('bcryptjs'), bcrypt = require('bcryptjs'),
ghostBookshelf = require('./base'), ghostBookshelf = require('./base'),
http = require('http'), http = require('http'),
@ -9,6 +8,10 @@ var _ = require('lodash'),
validator = require('validator'), validator = require('validator'),
validation = require('../data/validation'), validation = require('../data/validation'),
bcryptGenSalt = Promise.promisify(bcrypt.genSalt),
bcryptHash = Promise.promisify(bcrypt.hash),
bcryptCompare = Promise.promisify(bcrypt.compare),
tokenSecurity = {}, tokenSecurity = {},
activeStates = ['active', 'warn-1', 'warn-2', 'warn-3', 'warn-4', 'locked'], activeStates = ['active', 'warn-1', 'warn-2', 'warn-3', 'warn-4', 'locked'],
invitedStates = ['invited', 'invited-pending'], invitedStates = ['invited', 'invited-pending'],
@ -21,16 +24,16 @@ function validatePasswordLength(password) {
throw new Error('Your password must be at least 8 characters long.'); throw new Error('Your password must be at least 8 characters long.');
} }
} catch (error) { } catch (error) {
return when.reject(error); return Promise.reject(error);
} }
return when.resolve(); return Promise.resolve();
} }
function generatePasswordHash(password) { function generatePasswordHash(password) {
// Generate a new salt // Generate a new salt
return nodefn.call(bcrypt.genSalt).then(function (salt) { return bcryptGenSalt().then(function (salt) {
// Hash the provided password with bcrypt // Hash the provided password with bcrypt
return nodefn.call(bcrypt.hash, password, salt); return bcryptHash(password, salt);
}); });
} }
@ -239,7 +242,7 @@ User = ghostBookshelf.Model.extend({
return false; return false;
} }
return when(fetchRoleQuery()) return Promise.resolve(fetchRoleQuery())
.then(function () { .then(function () {
if (roleInstance) { if (roleInstance) {
@ -394,7 +397,7 @@ User = ghostBookshelf.Model.extend({
roleId = parseInt(data.roles[0].id || data.roles[0], 10); roleId = parseInt(data.roles[0].id || data.roles[0], 10);
if (data.roles.length > 1) { if (data.roles.length > 1) {
return when.reject( return Promise.reject(
new errors.ValidationError('Only one role per user is supported at the moment.') new errors.ValidationError('Only one role per user is supported at the moment.')
); );
} }
@ -407,7 +410,7 @@ User = ghostBookshelf.Model.extend({
return ghostBookshelf.model('Role').findOne({id: roleId}); return ghostBookshelf.model('Role').findOne({id: roleId});
}).then(function (roleToAssign) { }).then(function (roleToAssign) {
if (roleToAssign && roleToAssign.get('name') === 'Owner') { if (roleToAssign && roleToAssign.get('name') === 'Owner') {
return when.reject( return Promise.reject(
new errors.ValidationError('This method does not support assigning the owner role') new errors.ValidationError('This method does not support assigning the owner role')
); );
} else { } else {
@ -447,7 +450,7 @@ User = ghostBookshelf.Model.extend({
// check for too many roles // check for too many roles
if (roles.length > 1) { if (roles.length > 1) {
return when.reject(new errors.ValidationError('Only one role per user is supported at the moment.')); return Promise.reject(new errors.ValidationError('Only one role per user is supported at the moment.'));
} }
// remove roles from the object // remove roles from the object
delete data.roles; delete data.roles;
@ -552,7 +555,7 @@ User = ghostBookshelf.Model.extend({
if (action === 'destroy') { if (action === 'destroy') {
// Owner cannot be deleted EVER // Owner cannot be deleted EVER
if (userModel.hasRole('Owner')) { if (userModel.hasRole('Owner')) {
return when.reject(); return Promise.reject();
} }
// Users with the role 'Editor' have complex permissions when the action === 'destroy' // Users with the role 'Editor' have complex permissions when the action === 'destroy'
@ -566,10 +569,10 @@ User = ghostBookshelf.Model.extend({
} }
if (hasUserPermission && hasAppPermission) { if (hasUserPermission && hasAppPermission) {
return when.resolve(); return Promise.resolve();
} }
return when.reject(); return Promise.reject();
}, },
setWarning: function (user, options) { setWarning: function (user, options) {
@ -588,7 +591,7 @@ User = ghostBookshelf.Model.extend({
user.set('status', 'warn-' + level); user.set('status', 'warn-' + level);
} }
} }
return when(user.save(options)).then(function () { return Promise.resolve(user.save(options)).then(function () {
return 5 - level; return 5 - level;
}); });
}, },
@ -599,19 +602,19 @@ User = ghostBookshelf.Model.extend({
s; s;
return this.getByEmail(object.email).then(function (user) { return this.getByEmail(object.email).then(function (user) {
if (!user) { if (!user) {
return when.reject(new errors.NotFoundError('There is no user with that email address.')); return Promise.reject(new errors.NotFoundError('There is no user with that email address.'));
} }
if (user.get('status') === 'invited' || user.get('status') === 'invited-pending' || if (user.get('status') === 'invited' || user.get('status') === 'invited-pending' ||
user.get('status') === 'inactive' user.get('status') === 'inactive'
) { ) {
return when.reject(new Error('The user with that email address is inactive.')); return Promise.reject(new Error('The user with that email address is inactive.'));
} }
if (user.get('status') !== 'locked') { if (user.get('status') !== 'locked') {
return nodefn.call(bcrypt.compare, object.password, user.get('password')).then(function (matched) { return bcryptCompare(object.password, user.get('password')).then(function (matched) {
if (!matched) { if (!matched) {
return when(self.setWarning(user, {validate: false})).then(function (remaining) { return Promise.resolve(self.setWarning(user, {validate: false})).then(function (remaining) {
s = (remaining > 1) ? 's' : ''; s = (remaining > 1) ? 's' : '';
return when.reject(new errors.UnauthorizedError('Your password is incorrect.<br>' + return Promise.reject(new errors.UnauthorizedError('Your password is incorrect.<br>' +
remaining + ' attempt' + s + ' remaining!')); remaining + ' attempt' + s + ' remaining!'));
// Use comma structure, not .catch, because we don't want to catch incorrect passwords // Use comma structure, not .catch, because we don't want to catch incorrect passwords
@ -624,11 +627,11 @@ User = ghostBookshelf.Model.extend({
'Error thrown from user update during login', 'Error thrown from user update during login',
'Visit and save your profile after logging in to check for problems.' 'Visit and save your profile after logging in to check for problems.'
); );
return when.reject(new errors.UnauthorizedError('Your password is incorrect.')); return Promise.reject(new errors.UnauthorizedError('Your password is incorrect.'));
}); });
} }
return when(user.set({status : 'active', last_login : new Date()}).save({validate: false})) return Promise.resolve(user.set({status : 'active', last_login : new Date()}).save({validate: false}))
.catch(function (error) { .catch(function (error) {
// If we get a validation or other error during this save, catch it and log it, but don't // If we get a validation or other error during this save, catch it and log it, but don't
// cause a login error because of it. The user validation is not important here. // cause a login error because of it. The user validation is not important here.
@ -641,16 +644,16 @@ User = ghostBookshelf.Model.extend({
}); });
}, errors.logAndThrowError); }, errors.logAndThrowError);
} }
return when.reject(new errors.NoPermissionError('Your account is locked due to too many ' + return Promise.reject(new errors.NoPermissionError('Your account is locked due to too many ' +
'login attempts. Please reset your password to log in again by clicking ' + 'login attempts. Please reset your password to log in again by clicking ' +
'the "Forgotten password?" link!')); 'the "Forgotten password?" link!'));
}, function (error) { }, function (error) {
if (error.message === 'NotFound' || error.message === 'EmptyResponse') { if (error.message === 'NotFound' || error.message === 'EmptyResponse') {
return when.reject(new errors.NotFoundError('There is no user with that email address.')); return Promise.reject(new errors.NotFoundError('There is no user with that email address.'));
} }
return when.reject(error); return Promise.reject(error);
}); });
}, },
@ -664,21 +667,21 @@ User = ghostBookshelf.Model.extend({
user = null; user = null;
if (newPassword !== ne2Password) { if (newPassword !== ne2Password) {
return when.reject(new Error('Your new passwords do not match')); return Promise.reject(new Error('Your new passwords do not match'));
} }
return validatePasswordLength(newPassword).then(function () { return validatePasswordLength(newPassword).then(function () {
return self.forge({id: userid}).fetch({require: true}); return self.forge({id: userid}).fetch({require: true});
}).then(function (_user) { }).then(function (_user) {
user = _user; user = _user;
return nodefn.call(bcrypt.compare, oldPassword, user.get('password')); return bcryptCompare(oldPassword, user.get('password'));
}).then(function (matched) { }).then(function (matched) {
if (!matched) { if (!matched) {
return when.reject(new Error('Your password is incorrect')); return Promise.reject(new Error('Your password is incorrect'));
} }
return nodefn.call(bcrypt.genSalt); return bcryptGenSalt();
}).then(function (salt) { }).then(function (salt) {
return nodefn.call(bcrypt.hash, newPassword, salt); return bcryptHash(newPassword, salt);
}).then(function (hash) { }).then(function (hash) {
user.save({password: hash}); user.save({password: hash});
return user; return user;
@ -688,7 +691,7 @@ User = ghostBookshelf.Model.extend({
generateResetToken: function (email, expires, dbHash) { generateResetToken: function (email, expires, dbHash) {
return this.getByEmail(email).then(function (foundUser) { return this.getByEmail(email).then(function (foundUser) {
if (!foundUser) { if (!foundUser) {
return when.reject(new errors.NotFoundError('There is no user with that email address.')); return Promise.reject(new errors.NotFoundError('There is no user with that email address.'));
} }
var hash = crypto.createHash('sha256'), var hash = crypto.createHash('sha256'),
@ -720,25 +723,25 @@ User = ghostBookshelf.Model.extend({
// Check if invalid structure // Check if invalid structure
if (!parts || parts.length !== 3) { if (!parts || parts.length !== 3) {
return when.reject(new Error('Invalid token structure')); return Promise.reject(new Error('Invalid token structure'));
} }
expires = parseInt(parts[0], 10); expires = parseInt(parts[0], 10);
email = parts[1]; email = parts[1];
if (isNaN(expires)) { if (isNaN(expires)) {
return when.reject(new Error('Invalid token expiration')); return Promise.reject(new Error('Invalid token expiration'));
} }
// Check if token is expired to prevent replay attacks // Check if token is expired to prevent replay attacks
if (expires < Date.now()) { if (expires < Date.now()) {
return when.reject(new Error('Expired token')); return Promise.reject(new Error('Expired token'));
} }
// to prevent brute force attempts to reset the password the combination of email+expires is only allowed for // to prevent brute force attempts to reset the password the combination of email+expires is only allowed for
// 10 attempts // 10 attempts
if (tokenSecurity[email + '+' + expires] && tokenSecurity[email + '+' + expires].count >= 10) { if (tokenSecurity[email + '+' + expires] && tokenSecurity[email + '+' + expires].count >= 10) {
return when.reject(new Error('Token locked')); return Promise.reject(new Error('Token locked'));
} }
return this.generateResetToken(email, expires, dbHash).then(function (generatedToken) { return this.generateResetToken(email, expires, dbHash).then(function (generatedToken) {
@ -756,14 +759,14 @@ User = ghostBookshelf.Model.extend({
} }
if (diff === 0) { if (diff === 0) {
return when.resolve(email); return email;
} }
// increase the count for email+expires for each failed attempt // increase the count for email+expires for each failed attempt
tokenSecurity[email + '+' + expires] = { tokenSecurity[email + '+' + expires] = {
count: tokenSecurity[email + '+' + expires] ? tokenSecurity[email + '+' + expires].count + 1 : 1 count: tokenSecurity[email + '+' + expires] ? tokenSecurity[email + '+' + expires].count + 1 : 1
}; };
return when.reject(new Error('Invalid token')); return Promise.reject(new Error('Invalid token'));
}); });
}, },
@ -771,7 +774,7 @@ User = ghostBookshelf.Model.extend({
var self = this; var self = this;
if (newPassword !== ne2Password) { if (newPassword !== ne2Password) {
return when.reject(new Error('Your new passwords do not match')); return Promise.reject(new Error('Your new passwords do not match'));
} }
return validatePasswordLength(newPassword).then(function () { return validatePasswordLength(newPassword).then(function () {
@ -779,7 +782,7 @@ User = ghostBookshelf.Model.extend({
return self.validateToken(token, dbHash); return self.validateToken(token, dbHash);
}).then(function (email) { }).then(function (email) {
// Fetch the user by email, and hash the password at the same time. // Fetch the user by email, and hash the password at the same time.
return when.join( return Promise.join(
self.forge({email: email.toLocaleLowerCase()}).fetch({require: true}), self.forge({email: email.toLocaleLowerCase()}).fetch({require: true}),
generatePasswordHash(newPassword) generatePasswordHash(newPassword)
); );
@ -809,7 +812,7 @@ User = ghostBookshelf.Model.extend({
// check if user has the owner role // check if user has the owner role
var currentRoles = ctxUser.toJSON().roles; var currentRoles = ctxUser.toJSON().roles;
if (!_.contains(currentRoles, ownerRole.id)) { if (!_.contains(currentRoles, ownerRole.id)) {
return when.reject(new errors.NoPermissionError('Only owners are able to transfer the owner role.')); return Promise.reject(new errors.NoPermissionError('Only owners are able to transfer the owner role.'));
} }
contextUser = ctxUser; contextUser = ctxUser;
return User.findOne({id: object.id}); return User.findOne({id: object.id});
@ -817,7 +820,7 @@ User = ghostBookshelf.Model.extend({
var currentRoles = user.toJSON().roles; var currentRoles = user.toJSON().roles;
if (!_.contains(currentRoles, adminRole.id)) { if (!_.contains(currentRoles, adminRole.id)) {
return when.reject(new errors.ValidationError('Only administrators can be assigned the owner role.')); return Promise.reject(new errors.ValidationError('Only administrators can be assigned the owner role.'));
} }
assignUser = user; assignUser = user;
@ -838,20 +841,20 @@ User = ghostBookshelf.Model.extend({
gravatarLookup: function (userData) { gravatarLookup: function (userData) {
var gravatarUrl = '//www.gravatar.com/avatar/' + var gravatarUrl = '//www.gravatar.com/avatar/' +
crypto.createHash('md5').update(userData.email.toLowerCase().trim()).digest('hex') + crypto.createHash('md5').update(userData.email.toLowerCase().trim()).digest('hex') +
'?d=404&s=250', '?d=404&s=250';
checkPromise = when.defer();
http.get('http:' + gravatarUrl, function (res) { return new Promise(function (resolve) {
if (res.statusCode !== 404) { http.get('http:' + gravatarUrl, function (res) {
userData.image = gravatarUrl; if (res.statusCode !== 404) {
} userData.image = gravatarUrl;
checkPromise.resolve(userData); }
}).on('error', function () {
//Error making request just continue. resolve(userData);
checkPromise.resolve(userData); }).on('error', function () {
//Error making request just continue.
resolve(userData);
});
}); });
return checkPromise.promise;
}, },
// Get the user by email address, enforces case insensitivity rejects if the user is not found // Get the user by email address, enforces case insensitivity rejects if the user is not found
// When multi-user support is added, email addresses must be deduplicated with case insensitivity, so that // When multi-user support is added, email addresses must be deduplicated with case insensitivity, so that
@ -869,7 +872,7 @@ User = ghostBookshelf.Model.extend({
return user.get('email').toLowerCase() === email.toLowerCase(); return user.get('email').toLowerCase() === email.toLowerCase();
}); });
if (userWithEmail) { if (userWithEmail) {
return when.resolve(userWithEmail); return userWithEmail;
} }
}); });
} }

View file

@ -2,7 +2,7 @@
// canThis(someUser).edit.post(somePost|somePostId) // canThis(someUser).edit.post(somePost|somePostId)
var _ = require('lodash'), var _ = require('lodash'),
when = require('when'), Promise = require('bluebird'),
Models = require('../models'), Models = require('../models'),
effectivePerms = require('./effective'), effectivePerms = require('./effective'),
init, init,
@ -65,7 +65,7 @@ CanThisResult.prototype.buildObjectTypeHandlers = function (obj_types, act_type,
// If it's an internal request, resolve immediately // If it's an internal request, resolve immediately
if (context.internal) { if (context.internal) {
return when.resolve(); return Promise.resolve();
} }
if (_.isNumber(modelOrId) || _.isString(modelOrId)) { if (_.isNumber(modelOrId) || _.isString(modelOrId)) {
@ -127,9 +127,10 @@ CanThisResult.prototype.buildObjectTypeHandlers = function (obj_types, act_type,
} }
if (hasUserPermission && hasAppPermission) { if (hasUserPermission && hasAppPermission) {
return when.resolve(); return;
} }
return when.reject();
return Promise.reject();
}); });
}; };
@ -155,7 +156,7 @@ CanThisResult.prototype.beginCheck = function (context) {
userPermissionLoad = effectivePerms.user(context.user); userPermissionLoad = effectivePerms.user(context.user);
} else { } else {
// Resolve null if no context.user to prevent db call // Resolve null if no context.user to prevent db call
userPermissionLoad = when.resolve(null); userPermissionLoad = Promise.resolve(null);
} }
@ -164,11 +165,11 @@ CanThisResult.prototype.beginCheck = function (context) {
appPermissionLoad = effectivePerms.app(context.app); appPermissionLoad = effectivePerms.app(context.app);
} else { } else {
// Resolve null if no context.app // Resolve null if no context.app
appPermissionLoad = when.resolve(null); appPermissionLoad = Promise.resolve(null);
} }
// Wait for both user and app permissions to load // Wait for both user and app permissions to load
permissionsLoad = when.all([userPermissionLoad, appPermissionLoad]).then(function (result) { permissionsLoad = Promise.all([userPermissionLoad, appPermissionLoad]).then(function (result) {
return { return {
user: result[0], user: result[0],
app: result[1] app: result[1]
@ -232,7 +233,7 @@ init = refresh = function () {
seenActions[action_type][object_type] = true; seenActions[action_type][object_type] = true;
}); });
return when(exported.actionsMap); return exported.actionsMap;
}); });
}; };

View file

@ -1,8 +1,10 @@
var _ = require('lodash'), var _ = require('lodash'),
fs = require('fs'), fs = require('fs'),
keys = require('when/keys'),
path = require('path'), path = require('path'),
when = require('when'), Promise = require('bluebird'),
readdirAsync = Promise.promisify(fs.readdir),
lstatAsync = Promise.promisify(fs.lstat),
parsePackageJson = function (path, messages) { parsePackageJson = function (path, messages) {
// Default the messages if non were passed // Default the messages if non were passed
messages = messages || { messages = messages || {
@ -10,42 +12,42 @@ var _ = require('lodash'),
warns: [] warns: []
}; };
var packageDeferred = when.defer(), var jsonContainer;
packagePromise = packageDeferred.promise,
jsonContainer;
fs.readFile(path, function (error, data) { return new Promise(function (resolve) {
if (error) { fs.readFile(path, function (error, data) {
messages.errors.push({ if (error) {
message: 'Could not read package.json file',
context: path
});
packageDeferred.resolve(false);
return;
}
try {
jsonContainer = JSON.parse(data);
if (jsonContainer.hasOwnProperty('name') && jsonContainer.hasOwnProperty('version')) {
packageDeferred.resolve(jsonContainer);
} else {
messages.errors.push({ messages.errors.push({
message: '"name" or "version" is missing from theme package.json file.', message: 'Could not read package.json file',
context: path
});
resolve(false);
return;
}
try {
jsonContainer = JSON.parse(data);
if (jsonContainer.hasOwnProperty('name') && jsonContainer.hasOwnProperty('version')) {
resolve(jsonContainer);
} else {
messages.errors.push({
message: '"name" or "version" is missing from theme package.json file.',
context: path,
help: 'This will be required in future. Please see http://docs.ghost.org/themes/'
});
resolve(false);
}
} catch (e) {
messages.errors.push({
message: 'Theme package.json file is malformed',
context: path, context: path,
help: 'This will be required in future. Please see http://docs.ghost.org/themes/' help: 'This will be required in future. Please see http://docs.ghost.org/themes/'
}); });
packageDeferred.resolve(false); resolve(false);
} }
} catch (e) { });
messages.errors.push({
message: 'Theme package.json file is malformed',
context: path,
help: 'This will be required in future. Please see http://docs.ghost.org/themes/'
});
packageDeferred.resolve(false);
}
}); });
return when(packagePromise);
}, },
readDir = function (dir, options, depth, messages) { readDir = function (dir, options, depth, messages) {
depth = depth || 0; depth = depth || 0;
messages = messages || { messages = messages || {
@ -58,44 +60,29 @@ var _ = require('lodash'),
}, options); }, options);
if (depth > 1) { if (depth > 1) {
return null; return Promise.resolve(null);
} }
var subtree = {}, return readdirAsync(dir).then(function (files) {
treeDeferred = when.defer(),
treePromise = treeDeferred.promise;
fs.readdir(dir, function (error, files) {
if (error) {
return treeDeferred.reject(error);
}
files = files || []; files = files || [];
files.forEach(function (file) { return Promise.reduce(files, function (results, file) {
var fileDeferred = when.defer(), var fpath = path.join(dir, file);
filePromise = fileDeferred.promise,
fpath = path.join(dir, file); return lstatAsync(fpath).then(function (result) {
subtree[file] = filePromise;
fs.lstat(fpath, function (error, result) {
/*jslint unparam:true*/
if (result.isDirectory()) { if (result.isDirectory()) {
fileDeferred.resolve(readDir(fpath, options, depth + 1, messages)); return readDir(fpath, options, depth + 1, messages);
} else if (depth === 1 && file === 'package.json') { } else if (depth === 1 && file === 'package.json') {
fileDeferred.resolve(parsePackageJson(fpath, messages)); return parsePackageJson(fpath, messages);
} else { } else {
fileDeferred.resolve(fpath); return fpath;
} }
}).then(function (result) {
results[file] = result;
return results;
}); });
}); }, {});
return keys.all(subtree).then(function (theFiles) {
return treeDeferred.resolve(theFiles);
});
});
return when(treePromise).then(function (prom) {
return prom;
}); });
}, },
readAll = function (dir, options, depth) { readAll = function (dir, options, depth) {
@ -105,7 +92,7 @@ var _ = require('lodash'),
warns: [] warns: []
}; };
return when(readDir(dir, options, depth, messages)).then(function (paths) { return readDir(dir, options, depth, messages).then(function (paths) {
// for all contents of the dir, I'm interested in the ones that are directories and within /theme/ // for all contents of the dir, I'm interested in the ones that are directories and within /theme/
if (typeof paths === 'object' && dir.indexOf('theme') !== -1) { if (typeof paths === 'object' && dir.indexOf('theme') !== -1) {
_.each(paths, function (path, index) { _.each(paths, function (path, index) {
@ -118,9 +105,11 @@ var _ = require('lodash'),
} }
}); });
} }
paths._messages = messages; paths._messages = messages;
return paths; return paths;
}).otherwise(function () { }).catch(function () {
return {'_messages': messages}; return {'_messages': messages};
}); });
}; };
@ -129,4 +118,4 @@ module.exports = {
readAll: readAll, readAll: readAll,
readDir: readDir, readDir: readDir,
parsePackageJson: parsePackageJson parsePackageJson: parsePackageJson
}; };

View file

@ -1,6 +1,6 @@
var moment = require('moment'), var moment = require('moment'),
path = require('path'), path = require('path'),
when = require('when'), Promise = require('bluebird'),
baseStore; baseStore;
// TODO: would probably be better to put these on the prototype and have proper constructors etc // TODO: would probably be better to put these on the prototype and have proper constructors etc
@ -34,18 +34,18 @@ baseStore = {
self.generateUnique(store, dir, name, ext, i, done); self.generateUnique(store, dir, name, ext, i, done);
}); });
} else { } else {
done.resolve(filename); done(filename);
} }
}); });
}, },
'getUniqueFileName': function (store, image, targetDir) { 'getUniqueFileName': function (store, image, targetDir) {
var done = when.defer(), var ext = path.extname(image.name),
ext = path.extname(image.name), name = path.basename(image.name, ext).replace(/[\W]/gi, '-'),
name = path.basename(image.name, ext).replace(/[\W]/gi, '-'); self = this;
this.generateUnique(store, targetDir, name, ext, 0, done); return new Promise(function (resolve) {
self.generateUnique(store, targetDir, name, ext, 0, resolve);
return done.promise; });
} }
}; };

View file

@ -4,9 +4,8 @@
var _ = require('lodash'), var _ = require('lodash'),
express = require('express'), express = require('express'),
fs = require('fs-extra'), fs = require('fs-extra'),
nodefn = require('when/node'),
path = require('path'), path = require('path'),
when = require('when'), Promise = require('bluebird'),
errors = require('../errors'), errors = require('../errors'),
config = require('../config'), config = require('../config'),
utils = require('../utils'), utils = require('../utils'),
@ -20,37 +19,31 @@ localFileStore = _.extend(baseStore, {
// - image is the express image object // - image is the express image object
// - returns a promise which ultimately returns the full url to the uploaded image // - returns a promise which ultimately returns the full url to the uploaded image
'save': function (image) { 'save': function (image) {
var saved = when.defer(), var targetDir = this.getTargetDir(config.paths.imagesPath),
targetDir = this.getTargetDir(config.paths.imagesPath),
targetFilename; targetFilename;
this.getUniqueFileName(this, image, targetDir).then(function (filename) { return this.getUniqueFileName(this, image, targetDir).then(function (filename) {
targetFilename = filename; targetFilename = filename;
return nodefn.call(fs.mkdirs, targetDir); return Promise.promisify(fs.mkdirs)(targetDir);
}).then(function () { }).then(function () {
return nodefn.call(fs.copy, image.path, targetFilename); return Promise.promisify(fs.copy)(image.path, targetFilename);
}).then(function () { }).then(function () {
// The src for the image must be in URI format, not a file system path, which in Windows uses \ // The src for the image must be in URI format, not a file system path, which in Windows uses \
// For local file system storage can use relative path so add a slash // For local file system storage can use relative path so add a slash
var fullUrl = (config.paths.subdir + '/' + config.paths.imagesRelPath + '/' + path.relative(config.paths.imagesPath, targetFilename)).replace(new RegExp('\\' + path.sep, 'g'), '/'); var fullUrl = (config.paths.subdir + '/' + config.paths.imagesRelPath + '/' + path.relative(config.paths.imagesPath, targetFilename)).replace(new RegExp('\\' + path.sep, 'g'), '/');
return saved.resolve(fullUrl); return fullUrl;
}).otherwise(function (e) { }).catch(function (e) {
errors.logError(e); errors.logError(e);
return saved.reject(e); return Promise.reject(e);
}); });
return saved.promise;
}, },
'exists': function (filename) { 'exists': function (filename) {
// fs.exists does not play nicely with nodefn because the callback doesn't have an error argument return new Promise(function (resolve) {
var done = when.defer(); fs.exists(filename, function (exists) {
resolve(exists);
fs.exists(filename, function (exists) { });
done.resolve(exists);
}); });
return done.promise;
}, },
// middleware for serving the files // middleware for serving the files

View file

@ -23,8 +23,7 @@ var crypto = require('crypto'),
https = require('https'), https = require('https'),
moment = require('moment'), moment = require('moment'),
semver = require('semver'), semver = require('semver'),
when = require('when'), Promise = require('bluebird'),
nodefn = require('when/node'),
_ = require('lodash'), _ = require('lodash'),
url = require('url'), url = require('url'),
@ -51,8 +50,8 @@ function updateCheckData() {
ops = [], ops = [],
mailConfig = config.mail; mailConfig = config.mail;
ops.push(api.settings.read(_.extend(internal, {key: 'dbHash'})).otherwise(errors.rejectError)); ops.push(api.settings.read(_.extend(internal, {key: 'dbHash'})).catch(errors.rejectError));
ops.push(api.settings.read(_.extend(internal, {key: 'activeTheme'})).otherwise(errors.rejectError)); ops.push(api.settings.read(_.extend(internal, {key: 'activeTheme'})).catch(errors.rejectError));
ops.push(api.settings.read(_.extend(internal, {key: 'activeApps'})) ops.push(api.settings.read(_.extend(internal, {key: 'activeApps'}))
.then(function (response) { .then(function (response) {
var apps = response.settings[0]; var apps = response.settings[0];
@ -63,10 +62,10 @@ function updateCheckData() {
} }
return _.reduce(apps, function (memo, item) { return memo === '' ? memo + item : memo + ', ' + item; }, ''); return _.reduce(apps, function (memo, item) { return memo === '' ? memo + item : memo + ', ' + item; }, '');
}).otherwise(errors.rejectError)); }).catch(errors.rejectError));
ops.push(api.posts.browse().otherwise(errors.rejectError)); ops.push(api.posts.browse().catch(errors.rejectError));
ops.push(api.users.browse(internal).otherwise(errors.rejectError)); ops.push(api.users.browse(internal).catch(errors.rejectError));
ops.push(nodefn.call(exec, 'npm -v').otherwise(errors.rejectError)); ops.push(Promise.promisify(exec)('npm -v').catch(errors.rejectError));
data.ghost_version = currentVersion; data.ghost_version = currentVersion;
data.node_version = process.versions.node; data.node_version = process.versions.node;
@ -74,13 +73,13 @@ function updateCheckData() {
data.database_type = config.database.client; data.database_type = config.database.client;
data.email_transport = mailConfig && (mailConfig.options && mailConfig.options.service ? mailConfig.options.service : mailConfig.transport); data.email_transport = mailConfig && (mailConfig.options && mailConfig.options.service ? mailConfig.options.service : mailConfig.transport);
return when.settle(ops).then(function (descriptors) { return Promise.settle(ops).then(function (descriptors) {
var hash = descriptors[0].value.settings[0], var hash = descriptors[0].value().settings[0],
theme = descriptors[1].value.settings[0], theme = descriptors[1].value().settings[0],
apps = descriptors[2].value, apps = descriptors[2].value(),
posts = descriptors[3].value, posts = descriptors[3].value(),
users = descriptors[4].value, users = descriptors[4].value(),
npm = descriptors[5].value, npm = descriptors[5].value(),
blogUrl = url.parse(config.url), blogUrl = url.parse(config.url),
blogId = blogUrl.hostname + blogUrl.pathname.replace(/\//, '') + hash.value; blogId = blogUrl.hostname + blogUrl.pathname.replace(/\//, '') + hash.value;
@ -93,13 +92,12 @@ function updateCheckData() {
data.npm_version = _.isArray(npm) && npm[0] ? npm[0].toString().replace(/\n/, '') : ''; data.npm_version = _.isArray(npm) && npm[0] ? npm[0].toString().replace(/\n/, '') : '';
return data; return data;
}).otherwise(updateCheckError); }).catch(updateCheckError);
} }
function updateCheckRequest() { function updateCheckRequest() {
return updateCheckData().then(function (reqData) { return updateCheckData().then(function (reqData) {
var deferred = when.defer(), var resData = '',
resData = '',
headers, headers,
req; req;
@ -109,31 +107,31 @@ function updateCheckRequest() {
'Content-Length': reqData.length 'Content-Length': reqData.length
}; };
req = https.request({ return new Promise(function (resolve, reject) {
hostname: checkEndpoint, req = https.request({
method: 'POST', hostname: checkEndpoint,
headers: headers method: 'POST',
}, function (res) { headers: headers
res.on('error', function (error) { deferred.reject(error); }); }, function (res) {
res.on('data', function (chunk) { resData += chunk; }); res.on('error', function (error) { reject(error); });
res.on('end', function () { res.on('data', function (chunk) { resData += chunk; });
try { res.on('end', function () {
resData = JSON.parse(resData); try {
deferred.resolve(resData); resData = JSON.parse(resData);
} catch (e) { resolve(resData);
deferred.reject('Unable to decode update response'); } catch (e) {
} reject('Unable to decode update response');
}
});
});
req.write(reqData);
req.end();
req.on('error', function (error) {
reject(error);
}); });
}); });
req.write(reqData);
req.end();
req.on('error', function (error) {
deferred.reject(error);
});
return deferred.promise;
}); });
} }
@ -149,53 +147,45 @@ function updateCheckResponse(response) {
api.settings.edit( api.settings.edit(
{settings: [{key: 'nextUpdateCheck', value: response.next_check}]}, {settings: [{key: 'nextUpdateCheck', value: response.next_check}]},
internal internal
) ).catch(errors.rejectError),
.otherwise(errors.rejectError),
api.settings.edit( api.settings.edit(
{settings: [{key: 'displayUpdateNotification', value: response.version}]}, {settings: [{key: 'displayUpdateNotification', value: response.version}]},
internal internal
) ).catch(errors.rejectError)
.otherwise(errors.rejectError)
); );
return when.settle(ops).then(function (descriptors) { return Promise.settle(ops).then(function (descriptors) {
descriptors.forEach(function (d) { descriptors.forEach(function (d) {
if (d.state === 'rejected') { if (d.isRejected()) {
errors.rejectError(d.reason); errors.rejectError(d.reason());
} }
}); });
return when.resolve();
}); });
} }
function updateCheck() { function updateCheck() {
var deferred = when.defer();
// The check will not happen if: // The check will not happen if:
// 1. updateCheck is defined as false in config.js // 1. updateCheck is defined as false in config.js
// 2. we've already done a check this session // 2. we've already done a check this session
// 3. we're not in production or development mode // 3. we're not in production or development mode
if (config.updateCheck === false || _.indexOf(allowedCheckEnvironments, process.env.NODE_ENV) === -1) { if (config.updateCheck === false || _.indexOf(allowedCheckEnvironments, process.env.NODE_ENV) === -1) {
// No update check // No update check
deferred.resolve(); return Promise.resolve();
} else { } else {
api.settings.read(_.extend(internal, {key: 'nextUpdateCheck'})).then(function (result) { return api.settings.read(_.extend(internal, {key: 'nextUpdateCheck'})).then(function (result) {
var nextUpdateCheck = result.settings[0]; var nextUpdateCheck = result.settings[0];
if (nextUpdateCheck && nextUpdateCheck.value && nextUpdateCheck.value > moment().unix()) { if (nextUpdateCheck && nextUpdateCheck.value && nextUpdateCheck.value > moment().unix()) {
// It's not time to check yet // It's not time to check yet
deferred.resolve(); return;
} else { } else {
// We need to do a check // We need to do a check
return updateCheckRequest() return updateCheckRequest()
.then(updateCheckResponse) .then(updateCheckResponse)
.otherwise(updateCheckError); .catch(updateCheckError);
} }
}).otherwise(updateCheckError) }).catch(updateCheckError);
.then(deferred.resolve);
} }
return deferred.promise;
} }
function showUpdateNotification() { function showUpdateNotification() {
@ -210,9 +200,10 @@ function showUpdateNotification() {
} }
if (display && display.value && currentVersion && semver.gt(display.value, currentVersion)) { if (display && display.value && currentVersion && semver.gt(display.value, currentVersion)) {
return when(display.value); return display.value;
} }
return when(false);
return false;
}); });
} }

View file

@ -0,0 +1,21 @@
var Promise = require('bluebird');
function pipeline(tasks /* initial arguments */) {
var args = Array.prototype.slice.call(arguments, 1),
runTask = function (task, args) {
runTask = function (task, arg) {
return task(arg);
};
return task.apply(null, args);
};
return Promise.all(tasks).reduce(function (arg, task) {
return Promise.resolve(runTask(task, arg)).then(function (result) {
return result;
});
}, args);
}
module.exports = pipeline;

View file

@ -0,0 +1,13 @@
var Promise = require('bluebird');
function sequence(tasks) {
return Promise.reduce(tasks, function (results, task) {
return task().then(function (result) {
results.push(result);
return results;
});
}, []);
}
module.exports = sequence;

View file

@ -62,7 +62,7 @@ describe('Admin Routing', function () {
}).then(function () { }).then(function () {
done(); done();
}).catch(done); }).catch(done);
}).otherwise(function (e) { }).catch(function (e) {
console.log('Ghost Error: ', e); console.log('Ghost Error: ', e);
console.log(e.stack); console.log(e.stack);
}); });
@ -332,7 +332,7 @@ describe('Admin Routing', function () {
// }); // });
// }).catch(done); // }).catch(done);
// }).otherwise(function (e) { // }).catch(function (e) {
// console.log('Ghost Error: ', e); // console.log('Ghost Error: ', e);
// console.log(e.stack); // console.log(e.stack);
// }); // });

View file

@ -334,7 +334,8 @@ describe('User API', function () {
var jsonResponse = res.body, var jsonResponse = res.body,
changedValue = 'joe-bloggs.ghost.org'; changedValue = 'joe-bloggs.ghost.org';
jsonResponse.users[0].should.exist;
should.exist(jsonResponse.users[0]);
jsonResponse.users[0].website = changedValue; jsonResponse.users[0].website = changedValue;
request.put(testUtils.API.getApiQuery('users/me/')) request.put(testUtils.API.getApiQuery('users/me/'))

View file

@ -2,7 +2,7 @@
/*jshint expr:true*/ /*jshint expr:true*/
var testUtils = require('../../utils'), var testUtils = require('../../utils'),
should = require('should'), should = require('should'),
when = require('when'), Promise = require('bluebird'),
rewire = require('rewire'), rewire = require('rewire'),
// Stuff we are testing // Stuff we are testing
@ -43,7 +43,7 @@ describe('Authentication API', function () {
send = mail.__get__('mail.send'); send = mail.__get__('mail.send');
mail.__set__('mail.send', function () { mail.__set__('mail.send', function () {
return when.resolve(); return Promise.resolve();
}); });
AuthAPI.setup({ setup: [setupData] }).then(function (result) { AuthAPI.setup({ setup: [setupData] }).then(function (result) {

View file

@ -5,7 +5,7 @@ var _ = require('lodash'),
rewire = require('rewire'), rewire = require('rewire'),
should = require('should'), should = require('should'),
sinon = require('sinon'), sinon = require('sinon'),
when = require('when'), Promise = require('bluebird'),
// Stuff we are testing // Stuff we are testing
SettingsAPI = require('../../../server/api/settings'), SettingsAPI = require('../../../server/api/settings'),
@ -30,11 +30,11 @@ describe('Themes API', function () {
beforeEach(function () { beforeEach(function () {
// Override settings.read for activeTheme // Override settings.read for activeTheme
sandbox.stub(SettingsAPI, 'read', function () { sandbox.stub(SettingsAPI, 'read', function () {
return when({ settings: [{value: 'casper'}] }); return Promise.resolve({ settings: [{value: 'casper'}] });
}); });
sandbox.stub(SettingsAPI, 'edit', function () { sandbox.stub(SettingsAPI, 'edit', function () {
return when({ settings: [{value: 'rasper'}] }); return Promise.resolve({ settings: [{value: 'rasper'}] });
}); });
configStub = { configStub = {

View file

@ -3,7 +3,7 @@
var fs = require('fs-extra'), var fs = require('fs-extra'),
should = require('should'), should = require('should'),
sinon = require('sinon'), sinon = require('sinon'),
when = require('when'), Promise = require('bluebird'),
storage = require('../../../server/storage'), storage = require('../../../server/storage'),
// Stuff we are testing // Stuff we are testing
@ -23,9 +23,9 @@ describe('Upload API', function () {
beforeEach(function () { beforeEach(function () {
store = sinon.stub(); store = sinon.stub();
store.save = sinon.stub().returns(when('URL')); store.save = sinon.stub().returns(Promise.resolve('URL'));
store.exists = sinon.stub().returns(when(true)); store.exists = sinon.stub().returns(Promise.resolve(true));
store.destroy = sinon.stub().returns(when()); store.destroy = sinon.stub().returns(Promise.resolve());
sinon.stub(storage, 'get_storage').returns(store); sinon.stub(storage, 'get_storage').returns(store);
sinon.stub(fs, 'unlink').yields(); sinon.stub(fs, 'unlink').yields();
}); });

View file

@ -3,7 +3,7 @@
var testUtils = require('../../utils'), var testUtils = require('../../utils'),
should = require('should'), should = require('should'),
sinon = require('sinon'), sinon = require('sinon'),
when = require('when'), Promise = require('bluebird'),
_ = require('lodash'), _ = require('lodash'),
// Stuff we are testing // Stuff we are testing
@ -340,11 +340,11 @@ describe('Users API', function () {
newUser = _.clone(testUtils.DataGenerator.forKnex.createUser(testUtils.DataGenerator.Content.users[4])); newUser = _.clone(testUtils.DataGenerator.forKnex.createUser(testUtils.DataGenerator.Content.users[4]));
sandbox.stub(ModelUser.User, 'gravatarLookup', function (userData) { sandbox.stub(ModelUser.User, 'gravatarLookup', function (userData) {
return when.resolve(userData); return Promise.resolve(userData);
}); });
sandbox.stub(mail, 'send', function () { sandbox.stub(mail, 'send', function () {
return when.resolve(); return Promise.resolve();
}); });
}); });
afterEach(function () { afterEach(function () {
@ -933,11 +933,11 @@ describe('Users API', function () {
{name: newName, roles: [roleIdFor.admin]} {name: newName, roles: [roleIdFor.admin]}
]}, _.extend({}, context.editor, {id: userIdFor.author}, {include: 'roles'}) ]}, _.extend({}, context.editor, {id: userIdFor.author}, {include: 'roles'})
).then(function (response) { ).then(function (response) {
done(new Error('Editor should not be able to upgrade the role of authors')); done(new Error('Editor should not be able to upgrade the role of authors'));
}, function (error) { }).catch(function (error) {
error.type.should.eql('NoPermissionError'); error.type.should.eql('NoPermissionError');
done(); done();
}).catch(done); }).catch(done);
}); });
}); });

View file

@ -3,7 +3,7 @@
var testUtils = require('../utils/index'), var testUtils = require('../utils/index'),
should = require('should'), should = require('should'),
sinon = require('sinon'), sinon = require('sinon'),
when = require('when'), Promise = require('bluebird'),
_ = require('lodash'), _ = require('lodash'),
// Stuff we are testing // Stuff we are testing
@ -25,7 +25,7 @@ describe('Exporter', function () {
it('exports data', function (done) { it('exports data', function (done) {
// Stub migrations to return 000 as the current database version // Stub migrations to return 000 as the current database version
var versioningStub = sandbox.stub(versioning, 'getDatabaseVersion', function () { var versioningStub = sandbox.stub(versioning, 'getDatabaseVersion', function () {
return when.resolve('003'); return Promise.resolve('003');
}); });
exporter().then(function (exportData) { exporter().then(function (exportData) {

View file

@ -3,7 +3,7 @@
var testUtils = require('../utils/index'), var testUtils = require('../utils/index'),
should = require('should'), should = require('should'),
sinon = require('sinon'), sinon = require('sinon'),
when = require('when'), Promise = require('bluebird'),
assert = require('assert'), assert = require('assert'),
_ = require('lodash'), _ = require('lodash'),
rewire = require('rewire'), rewire = require('rewire'),
@ -48,7 +48,7 @@ describe('Import', function () {
it('resolves 000', function (done) { it('resolves 000', function (done) {
var importStub = sandbox.stub(Importer000, 'importData', function () { var importStub = sandbox.stub(Importer000, 'importData', function () {
return when.resolve(); return Promise.resolve();
}), }),
fakeData = { test: true }; fakeData = { test: true };
@ -63,7 +63,7 @@ describe('Import', function () {
it('resolves 001', function (done) { it('resolves 001', function (done) {
var importStub = sandbox.stub(Importer001, 'importData', function () { var importStub = sandbox.stub(Importer001, 'importData', function () {
return when.resolve(); return Promise.resolve();
}), }),
fakeData = { test: true }; fakeData = { test: true };
@ -78,7 +78,7 @@ describe('Import', function () {
it('resolves 002', function (done) { it('resolves 002', function (done) {
var importStub = sandbox.stub(Importer002, 'importData', function () { var importStub = sandbox.stub(Importer002, 'importData', function () {
return when.resolve(); return Promise.resolve();
}), }),
fakeData = { test: true }; fakeData = { test: true };
@ -93,7 +93,7 @@ describe('Import', function () {
it('resolves 003', function (done) { it('resolves 003', function (done) {
var importStub = sandbox.stub(Importer003, 'importData', function () { var importStub = sandbox.stub(Importer003, 'importData', function () {
return when.resolve(); return Promise.resolve();
}), }),
fakeData = { test: true }; fakeData = { test: true };
@ -118,7 +118,7 @@ describe('Import', function () {
it('imports data from 000', function (done) { it('imports data from 000', function (done) {
var exportData, var exportData,
versioningStub = sandbox.stub(versioning, 'getDatabaseVersion', function () { versioningStub = sandbox.stub(versioning, 'getDatabaseVersion', function () {
return when.resolve('000'); return Promise.resolve('000');
}); });
testUtils.fixtures.loadExportFixture('export-000').then(function (exported) { testUtils.fixtures.loadExportFixture('export-000').then(function (exported) {
@ -127,7 +127,7 @@ describe('Import', function () {
return importer('000', exportData); return importer('000', exportData);
}).then(function () { }).then(function () {
// Grab the data from tables // Grab the data from tables
return when.all([ return Promise.all([
knex('users').select(), knex('users').select(),
knex('posts').select(), knex('posts').select(),
knex('settings').select(), knex('settings').select(),
@ -186,7 +186,7 @@ describe('Import', function () {
return importer('001', exportData); return importer('001', exportData);
}).then(function () { }).then(function () {
// Grab the data from tables // Grab the data from tables
return when.all([ return Promise.all([
knex('users').select(), knex('users').select(),
knex('posts').select(), knex('posts').select(),
knex('settings').select(), knex('settings').select(),
@ -261,7 +261,7 @@ describe('Import', function () {
error[0].message.should.eql('Value in [posts.title] exceeds maximum length of 150 characters.'); error[0].message.should.eql('Value in [posts.title] exceeds maximum length of 150 characters.');
error[0].type.should.eql('ValidationError'); error[0].type.should.eql('ValidationError');
when.all([ Promise.all([
knex('users').select(), knex('users').select(),
knex('posts').select(), knex('posts').select(),
knex('settings').select(), knex('settings').select(),
@ -310,7 +310,7 @@ describe('Import', function () {
error[0].message.should.eql('Value in [settings.key] cannot be blank.'); error[0].message.should.eql('Value in [settings.key] cannot be blank.');
error[0].type.should.eql('ValidationError'); error[0].type.should.eql('ValidationError');
when.all([ Promise.all([
knex('users').select(), knex('users').select(),
knex('posts').select(), knex('posts').select(),
knex('settings').select(), knex('settings').select(),
@ -367,7 +367,7 @@ describe('Import', function () {
return importer('002', exportData); return importer('002', exportData);
}).then(function () { }).then(function () {
// Grab the data from tables // Grab the data from tables
return when.all([ return Promise.all([
knex('users').select(), knex('users').select(),
knex('posts').select(), knex('posts').select(),
knex('settings').select(), knex('settings').select(),
@ -443,7 +443,7 @@ describe('Import', function () {
error[0].message.should.eql('Value in [posts.title] exceeds maximum length of 150 characters.'); error[0].message.should.eql('Value in [posts.title] exceeds maximum length of 150 characters.');
error[0].type.should.eql('ValidationError'); error[0].type.should.eql('ValidationError');
when.all([ Promise.all([
knex('users').select(), knex('users').select(),
knex('posts').select(), knex('posts').select(),
knex('settings').select(), knex('settings').select(),
@ -489,7 +489,7 @@ describe('Import', function () {
error[0].message.should.eql('Value in [settings.key] cannot be blank.'); error[0].message.should.eql('Value in [settings.key] cannot be blank.');
error[0].type.should.eql('ValidationError'); error[0].type.should.eql('ValidationError');
when.all([ Promise.all([
knex('users').select(), knex('users').select(),
knex('posts').select(), knex('posts').select(),
knex('settings').select(), knex('settings').select(),
@ -537,7 +537,7 @@ describe('Import', function () {
return importer('003', exportData); return importer('003', exportData);
}).then(function () { }).then(function () {
// Grab the data from tables // Grab the data from tables
return when.all([ return Promise.all([
knex('users').select(), knex('users').select(),
knex('posts').select(), knex('posts').select(),
knex('settings').select(), knex('settings').select(),
@ -704,7 +704,7 @@ describe('Import (new test structure)', function () {
after(testUtils.teardown); after(testUtils.teardown);
it('gets the right data', function (done) { it('gets the right data', function (done) {
var fetchImported = when.join( var fetchImported = Promise.join(
knex('posts').select(), knex('posts').select(),
knex('settings').select(), knex('settings').select(),
knex('tags').select() knex('tags').select()
@ -755,7 +755,7 @@ describe('Import (new test structure)', function () {
}); });
it('imports users with correct roles and status', function (done) { it('imports users with correct roles and status', function (done) {
var fetchImported = when.join( var fetchImported = Promise.join(
knex('users').select(), knex('users').select(),
knex('roles_users').select() knex('roles_users').select()
); );
@ -829,7 +829,7 @@ describe('Import (new test structure)', function () {
}); });
it('imports posts & tags with correct authors, owners etc', function (done) { it('imports posts & tags with correct authors, owners etc', function (done) {
var fetchImported = when.join( var fetchImported = Promise.join(
knex('users').select(), knex('users').select(),
knex('posts').select(), knex('posts').select(),
knex('tags').select() knex('tags').select()
@ -931,7 +931,7 @@ describe('Import (new test structure)', function () {
after(testUtils.teardown); after(testUtils.teardown);
it('gets the right data', function (done) { it('gets the right data', function (done) {
var fetchImported = when.join( var fetchImported = Promise.join(
knex('posts').select(), knex('posts').select(),
knex('settings').select(), knex('settings').select(),
knex('tags').select() knex('tags').select()
@ -982,7 +982,7 @@ describe('Import (new test structure)', function () {
}); });
it('imports users with correct roles and status', function (done) { it('imports users with correct roles and status', function (done) {
var fetchImported = when.join( var fetchImported = Promise.join(
knex('users').select(), knex('users').select(),
knex('roles_users').select() knex('roles_users').select()
); );
@ -1056,7 +1056,7 @@ describe('Import (new test structure)', function () {
}); });
it('imports posts & tags with correct authors, owners etc', function (done) { it('imports posts & tags with correct authors, owners etc', function (done) {
var fetchImported = when.join( var fetchImported = Promise.join(
knex('users').select(), knex('users').select(),
knex('posts').select(), knex('posts').select(),
knex('tags').select() knex('tags').select()
@ -1159,7 +1159,7 @@ describe('Import (new test structure)', function () {
after(testUtils.teardown); after(testUtils.teardown);
it('gets the right data', function (done) { it('gets the right data', function (done) {
var fetchImported = when.join( var fetchImported = Promise.join(
knex('posts').select(), knex('posts').select(),
knex('settings').select(), knex('settings').select(),
knex('tags').select() knex('tags').select()
@ -1221,7 +1221,7 @@ describe('Import (new test structure)', function () {
}); });
it('imports users with correct roles and status', function (done) { it('imports users with correct roles and status', function (done) {
var fetchImported = when.join( var fetchImported = Promise.join(
knex('users').select(), knex('users').select(),
knex('roles_users').select() knex('roles_users').select()
); );
@ -1290,7 +1290,7 @@ describe('Import (new test structure)', function () {
}); });
it('imports posts & tags with correct authors, owners etc', function (done) { it('imports posts & tags with correct authors, owners etc', function (done) {
var fetchImported = when.join( var fetchImported = Promise.join(
knex('users').select(), knex('users').select(),
knex('posts').select(), knex('posts').select(),
knex('tags').select() knex('tags').select()

View file

@ -2,7 +2,8 @@
/*jshint expr:true*/ /*jshint expr:true*/
var testUtils = require('../../utils'), var testUtils = require('../../utils'),
should = require('should'), should = require('should'),
sequence = require('when/sequence'), Promise = require('bluebird'),
sequence = require('../../../server/utils/sequence'),
_ = require('lodash'), _ = require('lodash'),
// Stuff we are testing // Stuff we are testing

View file

@ -2,7 +2,8 @@
/*jshint expr:true*/ /*jshint expr:true*/
var testUtils = require('../../utils'), var testUtils = require('../../utils'),
should = require('should'), should = require('should'),
sequence = require('when/sequence'), Promise = require('bluebird'),
sequence = require('../../../server/utils/sequence'),
_ = require('lodash'), _ = require('lodash'),
// Stuff we are testing // Stuff we are testing
@ -541,6 +542,6 @@ describe('Post Model', function () {
// }).then(function (saved) { // }).then(function (saved) {
// saved.get('title').should.eql("&lt;/title&gt;&lt;/head>&lt;body&gt;[removed]alert&#40;'blogtitle'&#41;;[removed]"); // saved.get('title').should.eql("&lt;/title&gt;&lt;/head>&lt;body&gt;[removed]alert&#40;'blogtitle'&#41;;[removed]");
// done(); // done();
// }).otherwise(done); // }).catch(done);
// }); // });
}); });

View file

@ -2,7 +2,7 @@
/*jshint expr:true*/ /*jshint expr:true*/
var testUtils = require('../../utils'), var testUtils = require('../../utils'),
should = require('should'), should = require('should'),
when = require('when'), Promise = require('bluebird'),
_ = require('lodash'), _ = require('lodash'),
// Stuff we are testing // Stuff we are testing
@ -44,7 +44,7 @@ describe('Tag Model', function () {
newTag = testUtils.DataGenerator.forModel.tags[0], newTag = testUtils.DataGenerator.forModel.tags[0],
createdPostID; createdPostID;
when.all([ Promise.all([
PostModel.add(newPost, context), PostModel.add(newPost, context),
TagModel.add(newTag, context) TagModel.add(newTag, context)
]).then(function (models) { ]).then(function (models) {
@ -71,7 +71,7 @@ describe('Tag Model', function () {
createdTagID, createdTagID,
createdPostID; createdPostID;
when.all([ Promise.all([
PostModel.add(newPost, context), PostModel.add(newPost, context),
TagModel.add(newTag, context) TagModel.add(newTag, context)
]).then(function (models) { ]).then(function (models) {
@ -106,7 +106,7 @@ describe('Tag Model', function () {
var tagModels = tagNames.map(function (tagName) { return TagModel.add({name: tagName}, context); }); var tagModels = tagNames.map(function (tagName) { return TagModel.add({name: tagName}, context); });
createOperations = createOperations.concat(tagModels); createOperations = createOperations.concat(tagModels);
return when.all(createOperations).then(function (models) { return Promise.all(createOperations).then(function (models) {
var postModel = models[0], var postModel = models[0],
attachOperations; attachOperations;
@ -115,7 +115,7 @@ describe('Tag Model', function () {
attachOperations.push(postModel.tags().attach(models[i])); attachOperations.push(postModel.tags().attach(models[i]));
} }
return when.all(attachOperations).then(function () { return Promise.all(attachOperations).then(function () {
return postModel; return postModel;
}); });
}).then(function (postModel) { }).then(function (postModel) {

View file

@ -2,7 +2,7 @@
/*jshint expr:true*/ /*jshint expr:true*/
var testUtils = require('../../utils'), var testUtils = require('../../utils'),
should = require('should'), should = require('should'),
when = require('when'), Promise = require('bluebird'),
sinon = require('sinon'), sinon = require('sinon'),
uuid = require('node-uuid'), uuid = require('node-uuid'),
_ = require('lodash'), _ = require('lodash'),
@ -33,7 +33,7 @@ describe('User Model', function run() {
var userData = testUtils.DataGenerator.forModel.users[0]; var userData = testUtils.DataGenerator.forModel.users[0];
sandbox.stub(UserModel, 'gravatarLookup', function (userData) { sandbox.stub(UserModel, 'gravatarLookup', function (userData) {
return when.resolve(userData); return Promise.resolve(userData);
}); });
UserModel.add(userData, context).then(function (createdUser) { UserModel.add(userData, context).then(function (createdUser) {
@ -50,7 +50,7 @@ describe('User Model', function run() {
var userData = testUtils.DataGenerator.forModel.users[2]; var userData = testUtils.DataGenerator.forModel.users[2];
sandbox.stub(UserModel, 'gravatarLookup', function (userData) { sandbox.stub(UserModel, 'gravatarLookup', function (userData) {
return when.resolve(userData); return Promise.resolve(userData);
}); });
UserModel.add(userData, context).then(function (createdUser) { UserModel.add(userData, context).then(function (createdUser) {
@ -66,7 +66,7 @@ describe('User Model', function run() {
sandbox.stub(UserModel, 'gravatarLookup', function (userData) { sandbox.stub(UserModel, 'gravatarLookup', function (userData) {
userData.image = 'http://www.gravatar.com/avatar/2fab21a4c4ed88e76add10650c73bae1?d=404'; userData.image = 'http://www.gravatar.com/avatar/2fab21a4c4ed88e76add10650c73bae1?d=404';
return when.resolve(userData); return Promise.resolve(userData);
}); });
UserModel.add(userData, context).then(function (createdUser) { UserModel.add(userData, context).then(function (createdUser) {
@ -83,7 +83,7 @@ describe('User Model', function run() {
var userData = testUtils.DataGenerator.forModel.users[0]; var userData = testUtils.DataGenerator.forModel.users[0];
sandbox.stub(UserModel, 'gravatarLookup', function (userData) { sandbox.stub(UserModel, 'gravatarLookup', function (userData) {
return when.resolve(userData); return Promise.resolve(userData);
}); });
UserModel.add(userData, context).then(function (createdUser) { UserModel.add(userData, context).then(function (createdUser) {
@ -271,7 +271,7 @@ describe('User Model', function run() {
var userData = testUtils.DataGenerator.forModel.users[4]; var userData = testUtils.DataGenerator.forModel.users[4];
sandbox.stub(UserModel, 'gravatarLookup', function (userData) { sandbox.stub(UserModel, 'gravatarLookup', function (userData) {
return when.resolve(userData); return Promise.resolve(userData);
}); });
RoleModel.findOne().then(function (role) { RoleModel.findOne().then(function (role) {

View file

@ -5,7 +5,7 @@ var path = require('path'),
should = require('should'), should = require('should'),
sinon = require('sinon'), sinon = require('sinon'),
_ = require('lodash'), _ = require('lodash'),
when = require('when'), Promise = require('bluebird'),
helpers = require('../../server/helpers'), helpers = require('../../server/helpers'),
filters = require('../../server/filters'), filters = require('../../server/filters'),
@ -432,7 +432,7 @@ describe('Apps', function () {
var perms = new AppPermissions("test"); var perms = new AppPermissions("test");
// No package.json in this directory // No package.json in this directory
sandbox.stub(perms, "checkPackageContentsExists").returns(when.resolve(false)); sandbox.stub(perms, "checkPackageContentsExists").returns(Promise.resolve(false));
perms.read().then(function (readPerms) { perms.read().then(function (readPerms) {
should.exist(readPerms); should.exist(readPerms);
@ -447,9 +447,9 @@ describe('Apps', function () {
noGhostPackageJsonContents = JSON.stringify(noGhostPackageJson, null, 2); noGhostPackageJsonContents = JSON.stringify(noGhostPackageJson, null, 2);
// package.json IS in this directory // package.json IS in this directory
sandbox.stub(perms, "checkPackageContentsExists").returns(when.resolve(true)); sandbox.stub(perms, "checkPackageContentsExists").returns(Promise.resolve(true));
// no ghost property on package // no ghost property on package
sandbox.stub(perms, "getPackageContents").returns(when.resolve(noGhostPackageJsonContents)); sandbox.stub(perms, "getPackageContents").returns(Promise.resolve(noGhostPackageJsonContents));
perms.read().then(function (readPerms) { perms.read().then(function (readPerms) {
should.exist(readPerms); should.exist(readPerms);
@ -463,9 +463,9 @@ describe('Apps', function () {
var perms = new AppPermissions("test"); var perms = new AppPermissions("test");
// package.json IS in this directory // package.json IS in this directory
sandbox.stub(perms, "checkPackageContentsExists").returns(when.resolve(true)); sandbox.stub(perms, "checkPackageContentsExists").returns(Promise.resolve(true));
// malformed JSON on package // malformed JSON on package
sandbox.stub(perms, "getPackageContents").returns(when.reject(new Error('package.json file is malformed'))); sandbox.stub(perms, "getPackageContents").returns(Promise.reject(new Error('package.json file is malformed')));
perms.read().then(function (readPerms) { perms.read().then(function (readPerms) {
/*jshint unused:false*/ /*jshint unused:false*/
@ -480,9 +480,9 @@ describe('Apps', function () {
validGhostPackageJsonContents = validGhostPackageJson; validGhostPackageJsonContents = validGhostPackageJson;
// package.json IS in this directory // package.json IS in this directory
sandbox.stub(perms, "checkPackageContentsExists").returns(when.resolve(true)); sandbox.stub(perms, "checkPackageContentsExists").returns(Promise.resolve(true));
// valid ghost property on package // valid ghost property on package
sandbox.stub(perms, "getPackageContents").returns(when.resolve(validGhostPackageJsonContents)); sandbox.stub(perms, "getPackageContents").returns(Promise.resolve(validGhostPackageJsonContents));
perms.read().then(function (readPerms) { perms.read().then(function (readPerms) {
should.exist(readPerms); should.exist(readPerms);

View file

@ -2,7 +2,7 @@
/*jshint expr:true*/ /*jshint expr:true*/
var should = require('should'), var should = require('should'),
sinon = require('sinon'), sinon = require('sinon'),
when = require('when'), Promise = require('bluebird'),
path = require('path'), path = require('path'),
fs = require('fs'), fs = require('fs'),
_ = require('lodash'), _ = require('lodash'),
@ -62,13 +62,10 @@ describe('Bootstrap', function () {
it('creates the config file if one does not exist', function (done) { it('creates the config file if one does not exist', function (done) {
var deferred = when.defer(),
// trick bootstrap into thinking that the config file doesn't exist yet // trick bootstrap into thinking that the config file doesn't exist yet
existsStub = sandbox.stub(fs, 'exists', function (file, cb) { return cb(false); }), var existsStub = sandbox.stub(fs, 'exists', function (file, cb) { return cb(false); }),
// create a method which will return a pre-resolved promise // create a method which will return a pre-resolved promise
resolvedPromise = sandbox.stub().returns(deferred.promise); resolvedPromise = sandbox.stub().returns(Promise.resolve());
deferred.resolve();
// ensure that the file creation is a stub, the tests shouldn't really create a file // ensure that the file creation is a stub, the tests shouldn't really create a file
bootstrap.__set__('writeConfigFile', resolvedPromise); bootstrap.__set__('writeConfigFile', resolvedPromise);

View file

@ -2,7 +2,7 @@
/*jshint expr:true*/ /*jshint expr:true*/
var should = require('should'), var should = require('should'),
sinon = require('sinon'), sinon = require('sinon'),
when = require('when'), Promise = require('bluebird'),
path = require('path'), path = require('path'),
_ = require('lodash'), _ = require('lodash'),
rewire = require('rewire'), rewire = require('rewire'),
@ -32,7 +32,7 @@ describe('Config', function () {
settings = {'read': function read() {}}; settings = {'read': function read() {}};
settingsStub = sandbox.stub(settings, 'read', function () { settingsStub = sandbox.stub(settings, 'read', function () {
return when({ settings: [{value: 'casper'}] }); return Promise.resolve({ settings: [{value: 'casper'}] });
}); });
theme.update(settings, 'http://my-ghost-blog.com') theme.update(settings, 'http://my-ghost-blog.com')
@ -270,7 +270,7 @@ describe('Config', function () {
it('should output correct url for post', function (done) { it('should output correct url for post', function (done) {
var settings = {'read': function read() {}}, var settings = {'read': function read() {}},
settingsStub = sandbox.stub(settings, 'read', function () { settingsStub = sandbox.stub(settings, 'read', function () {
return when({ settings: [{value: '/:slug/'}] }); return Promise.resolve({ settings: [{value: '/:slug/'}] });
}), }),
/*jshint unused:false*/ /*jshint unused:false*/
testData = testUtils.DataGenerator.Content.posts[2], testData = testUtils.DataGenerator.Content.posts[2],
@ -308,7 +308,7 @@ describe('Config', function () {
it('should output correct url for post with date permalink', function (done) { it('should output correct url for post with date permalink', function (done) {
var settings = {'read': function read() {}}, var settings = {'read': function read() {}},
settingsStub = sandbox.stub(settings, 'read', function () { settingsStub = sandbox.stub(settings, 'read', function () {
return when({ settings: [{value: '/:year/:month/:day/:slug/'}] }); return Promise.resolve({ settings: [{value: '/:year/:month/:day/:slug/'}] });
}), }),
/*jshint unused:false*/ /*jshint unused:false*/
testData = testUtils.DataGenerator.Content.posts[2], testData = testUtils.DataGenerator.Content.posts[2],
@ -349,7 +349,7 @@ describe('Config', function () {
it('should output correct url for page with date permalink', function (done) { it('should output correct url for page with date permalink', function (done) {
var settings = {'read': function read() {}}, var settings = {'read': function read() {}},
settingsStub = sandbox.stub(settings, 'read', function () { settingsStub = sandbox.stub(settings, 'read', function () {
return when({ settings: [{value: '/:year/:month/:day/:slug/'}] }); return Promise.resolve({ settings: [{value: '/:year/:month/:day/:slug/'}] });
}), }),
/*jshint unused:false*/ /*jshint unused:false*/
testData = testUtils.DataGenerator.Content.posts[5], testData = testUtils.DataGenerator.Content.posts[5],

View file

@ -1,7 +1,7 @@
/*globals describe, after, before, beforeEach, afterEach, it*/ /*globals describe, after, before, beforeEach, afterEach, it*/
/*jshint expr:true*/ /*jshint expr:true*/
var should = require('should'), var should = require('should'),
when = require('when'), Promise = require('bluebird'),
sinon = require('sinon'), sinon = require('sinon'),
express = require('express'), express = require('express'),
rewire = require('rewire'), rewire = require('rewire'),
@ -181,9 +181,7 @@ describe('Error handling', function () {
}); });
it('logs promise errors and redirects', function (done) { it('logs promise errors and redirects', function (done) {
var def = when.defer(), var req = null,
prom = def.promise,
req = null,
res = { res = {
redirect: function () { redirect: function () {
return; return;
@ -192,11 +190,11 @@ describe('Error handling', function () {
redirectStub = sinon.stub(res, 'redirect'); redirectStub = sinon.stub(res, 'redirect');
// give environment a value that will console log // give environment a value that will console log
prom.then(function () { Promise.reject().then(function () {
throw new Error('Ran success handler'); throw new Error('Ran success handler');
}, errors.logErrorWithRedirect('test1', null, null, '/testurl', req, res)); }, errors.logErrorWithRedirect('test1', null, null, '/testurl', req, res));
prom.otherwise(function () { Promise.reject().catch(function () {
logStub.calledWith('\nERROR:'.red, 'test1'.red).should.equal(true); logStub.calledWith('\nERROR:'.red, 'test1'.red).should.equal(true);
logStub.restore(); logStub.restore();
@ -205,7 +203,6 @@ describe('Error handling', function () {
done(); done();
}); });
def.reject();
}); });
}); });

View file

@ -2,7 +2,7 @@
/*jshint expr:true*/ /*jshint expr:true*/
var should = require('should'), var should = require('should'),
sinon = require('sinon'), sinon = require('sinon'),
when = require('when'), Promise = require('bluebird'),
_ = require('lodash'), _ = require('lodash'),
// Stuff we are testing // Stuff we are testing
@ -85,7 +85,7 @@ describe('Filters', function () {
it('executes filters that return a promise', function (done) { it('executes filters that return a promise', function (done) {
var filterName = 'testprioritypromise', var filterName = 'testprioritypromise',
testFilterHandler1 = sinon.spy(function (args) { testFilterHandler1 = sinon.spy(function (args) {
return when.promise(function (resolve) { return new Promise(function (resolve) {
process.nextTick(function () { process.nextTick(function () {
args.filter1 = true; args.filter1 = true;
@ -99,7 +99,7 @@ describe('Filters', function () {
return args; return args;
}), }),
testFilterHandler3 = sinon.spy(function (args) { testFilterHandler3 = sinon.spy(function (args) {
return when.promise(function (resolve) { return new Promise(function (resolve) {
process.nextTick(function () { process.nextTick(function () {
args.filter3 = true; args.filter3 = true;

View file

@ -4,7 +4,7 @@ var assert = require('assert'),
moment = require('moment'), moment = require('moment'),
should = require('should'), should = require('should'),
sinon = require('sinon'), sinon = require('sinon'),
when = require('when'), Promise = require('bluebird'),
rewire = require('rewire'), rewire = require('rewire'),
_ = require('lodash'), _ = require('lodash'),
@ -53,11 +53,11 @@ describe('Frontend Controller', function () {
}; };
sandbox.stub(api.posts, 'browse', function () { sandbox.stub(api.posts, 'browse', function () {
return when({posts: {}, meta: {pagination: { pages: 3}}}); return Promise.resolve({posts: {}, meta: {pagination: { pages: 3}}});
}); });
apiSettingsStub = sandbox.stub(api.settings, 'read'); apiSettingsStub = sandbox.stub(api.settings, 'read');
apiSettingsStub.withArgs('postsPerPage').returns(when({ apiSettingsStub.withArgs('postsPerPage').returns(Promise.resolve({
settings: [{ settings: [{
'key': 'postsPerPage', 'key': 'postsPerPage',
'value': 5 'value': 5
@ -156,7 +156,7 @@ describe('Frontend Controller', function () {
beforeEach(function () { beforeEach(function () {
sandbox.stub(api.posts, 'browse', function () { sandbox.stub(api.posts, 'browse', function () {
return when({ return Promise.resolve({
posts: [], posts: [],
meta: { meta: {
pagination: { pagination: {
@ -169,14 +169,14 @@ describe('Frontend Controller', function () {
apiSettingsStub = sandbox.stub(api.settings, 'read'); apiSettingsStub = sandbox.stub(api.settings, 'read');
apiSettingsStub.withArgs(sinon.match.has('key', 'activeTheme')).returns(when({ apiSettingsStub.withArgs(sinon.match.has('key', 'activeTheme')).returns(Promise.resolve({
settings: [{ settings: [{
'key': 'activeTheme', 'key': 'activeTheme',
'value': 'casper' 'value': 'casper'
}] }]
})); }));
apiSettingsStub.withArgs('postsPerPage').returns(when({ apiSettingsStub.withArgs('postsPerPage').returns(Promise.resolve({
settings: [{ settings: [{
'key': 'postsPerPage', 'key': 'postsPerPage',
'value': '10' 'value': '10'
@ -306,7 +306,7 @@ describe('Frontend Controller', function () {
beforeEach(function () { beforeEach(function () {
sandbox.stub(api.posts, 'browse', function () { sandbox.stub(api.posts, 'browse', function () {
return when({ return Promise.resolve({
posts: mockPosts, posts: mockPosts,
meta: { meta: {
pagination: { pagination: {
@ -322,14 +322,14 @@ describe('Frontend Controller', function () {
apiSettingsStub = sandbox.stub(api.settings, 'read'); apiSettingsStub = sandbox.stub(api.settings, 'read');
apiSettingsStub.withArgs(sinon.match.has('key', 'activeTheme')).returns(when({ apiSettingsStub.withArgs(sinon.match.has('key', 'activeTheme')).returns(Promise.resolve({
settings: [{ settings: [{
'key': 'activeTheme', 'key': 'activeTheme',
'value': 'casper' 'value': 'casper'
}] }]
})); }));
apiSettingsStub.withArgs('postsPerPage').returns(when({ apiSettingsStub.withArgs('postsPerPage').returns(Promise.resolve({
settings: [{ settings: [{
'key': 'postsPerPage', 'key': 'postsPerPage',
'value': '10' 'value': '10'
@ -355,7 +355,7 @@ describe('Frontend Controller', function () {
describe('custom tag template', function () { describe('custom tag template', function () {
beforeEach(function () { beforeEach(function () {
apiSettingsStub.withArgs('permalinks').returns(when({ apiSettingsStub.withArgs('permalinks').returns(Promise.resolve({
settings: [{ settings: [{
key: 'permalinks', key: 'permalinks',
value: '/tag/:slug/' value: '/tag/:slug/'
@ -392,11 +392,11 @@ describe('Frontend Controller', function () {
}; };
sandbox.stub(api.posts, 'browse', function () { sandbox.stub(api.posts, 'browse', function () {
return when({posts: {}, meta: {pagination: { pages: 3}}}); return Promise.resolve({posts: {}, meta: {pagination: { pages: 3}}});
}); });
apiSettingsStub = sandbox.stub(api.settings, 'read'); apiSettingsStub = sandbox.stub(api.settings, 'read');
apiSettingsStub.withArgs('postsPerPage').returns(when({ apiSettingsStub.withArgs('postsPerPage').returns(Promise.resolve({
settings: [{ settings: [{
'key': 'postsPerPage', 'key': 'postsPerPage',
'value': 5 'value': 5
@ -542,14 +542,14 @@ describe('Frontend Controller', function () {
beforeEach(function () { beforeEach(function () {
sandbox.stub(api.posts, 'read', function (args) { sandbox.stub(api.posts, 'read', function (args) {
return when(_.find(mockPosts, function(mock) { return Promise.resolve(_.find(mockPosts, function(mock) {
return mock.posts[0].slug === args.slug; return mock.posts[0].slug === args.slug;
})); }));
}); });
apiSettingsStub = sandbox.stub(api.settings, 'read'); apiSettingsStub = sandbox.stub(api.settings, 'read');
apiSettingsStub.withArgs(sinon.match.has('key', 'activeTheme')).returns(when({ apiSettingsStub.withArgs(sinon.match.has('key', 'activeTheme')).returns(Promise.resolve({
settings: [{ settings: [{
'key': 'activeTheme', 'key': 'activeTheme',
'value': 'casper' 'value': 'casper'
@ -577,7 +577,7 @@ describe('Frontend Controller', function () {
describe('custom page templates', function () { describe('custom page templates', function () {
beforeEach(function () { beforeEach(function () {
apiSettingsStub.withArgs('permalinks').returns(when({ apiSettingsStub.withArgs('permalinks').returns(Promise.resolve({
settings: [{ settings: [{
value: '/:slug/' value: '/:slug/'
}] }]
@ -602,7 +602,7 @@ describe('Frontend Controller', function () {
describe('permalink set to slug', function () { describe('permalink set to slug', function () {
beforeEach(function () { beforeEach(function () {
apiSettingsStub.withArgs('permalinks').returns(when({ apiSettingsStub.withArgs('permalinks').returns(Promise.resolve({
settings: [{ settings: [{
value: '/:slug/' value: '/:slug/'
}] }]
@ -674,7 +674,7 @@ describe('Frontend Controller', function () {
describe('permalink set to date', function () { describe('permalink set to date', function () {
beforeEach(function () { beforeEach(function () {
apiSettingsStub.withArgs('permalinks').returns(when({ apiSettingsStub.withArgs('permalinks').returns(Promise.resolve({
settings: [{ settings: [{
value: '/:year/:month/:day/:slug/' value: '/:year/:month/:day/:slug/'
}] }]
@ -747,7 +747,7 @@ describe('Frontend Controller', function () {
describe('post', function () { describe('post', function () {
describe('permalink set to slug', function () { describe('permalink set to slug', function () {
beforeEach(function () { beforeEach(function () {
apiSettingsStub.withArgs('permalinks').returns(when({ apiSettingsStub.withArgs('permalinks').returns(Promise.resolve({
settings: [{ settings: [{
value: '/:slug' value: '/:slug'
}] }]
@ -821,7 +821,7 @@ describe('Frontend Controller', function () {
describe('permalink set to date', function () { describe('permalink set to date', function () {
beforeEach(function () { beforeEach(function () {
apiSettingsStub.withArgs('permalinks').returns(when({ apiSettingsStub.withArgs('permalinks').returns(Promise.resolve({
settings: [{ settings: [{
value: '/:year/:month/:day/:slug' value: '/:year/:month/:day/:slug'
}] }]
@ -912,7 +912,7 @@ describe('Frontend Controller', function () {
describe('permalink set to custom format', function () { describe('permalink set to custom format', function () {
beforeEach(function () { beforeEach(function () {
apiSettingsStub.withArgs('permalinks').returns(when({ apiSettingsStub.withArgs('permalinks').returns(Promise.resolve({
settings: [{ settings: [{
value: '/:year/:slug' value: '/:year/:slug'
}] }]
@ -1035,25 +1035,25 @@ describe('Frontend Controller', function () {
}; };
sandbox.stub(api.posts, 'browse', function () { sandbox.stub(api.posts, 'browse', function () {
return when({posts: {}, meta: {pagination: { pages: 3}}}); return Promise.resolve({posts: {}, meta: {pagination: { pages: 3}}});
}); });
apiUsersStub = sandbox.stub(api.users, 'read').returns(when({})); apiUsersStub = sandbox.stub(api.users, 'read').returns(Promise.resolve({}));
apiSettingsStub = sandbox.stub(api.settings, 'read'); apiSettingsStub = sandbox.stub(api.settings, 'read');
apiSettingsStub.withArgs('title').returns(when({ apiSettingsStub.withArgs('title').returns(Promise.resolve({
settings: [{ settings: [{
'key': 'title', 'key': 'title',
'value': 'Test' 'value': 'Test'
}] }]
})); }));
apiSettingsStub.withArgs('description').returns(when({ apiSettingsStub.withArgs('description').returns(Promise.resolve({
settings: [{ settings: [{
'key': 'description', 'key': 'description',
'value': 'Some Text' 'value': 'Some Text'
}] }]
})); }));
apiSettingsStub.withArgs('permalinks').returns(when({ apiSettingsStub.withArgs('permalinks').returns(Promise.resolve({
settings: [{ settings: [{
'key': 'permalinks', 'key': 'permalinks',
'value': '/:slug/' 'value': '/:slug/'

View file

@ -2,7 +2,7 @@
/*jshint expr:true*/ /*jshint expr:true*/
var should = require('should'), var should = require('should'),
sinon = require('sinon'), sinon = require('sinon'),
when = require('when'), Promise = require('bluebird'),
_ = require('lodash'), _ = require('lodash'),
rewire = require('rewire'), rewire = require('rewire'),
@ -61,7 +61,7 @@ describe('Mail', function () {
}); });
sandbox.stub(mailer, 'detectSendmail', function () { sandbox.stub(mailer, 'detectSendmail', function () {
return when.resolve(fakeSendmail); return Promise.resolve(fakeSendmail);
}); });
}); });
@ -119,7 +119,7 @@ describe('Mail', function () {
it('should disable transport if config is empty & sendmail not found', function (done) { it('should disable transport if config is empty & sendmail not found', function (done) {
overrideConfig({mail: {}}); overrideConfig({mail: {}});
mailer.detectSendmail.restore(); mailer.detectSendmail.restore();
sandbox.stub(mailer, 'detectSendmail', when.reject); sandbox.stub(mailer, 'detectSendmail', Promise.reject);
mailer.init().then(function () { mailer.init().then(function () {
should.not.exist(mailer.transport); should.not.exist(mailer.transport);
done(); done();
@ -141,7 +141,7 @@ describe('Mail', function () {
it('should fail to send messages when no transport is set', function (done) { it('should fail to send messages when no transport is set', function (done) {
mailer.detectSendmail.restore(); mailer.detectSendmail.restore();
sandbox.stub(mailer, 'detectSendmail', when.reject); sandbox.stub(mailer, 'detectSendmail', Promise.reject);
mailer.init().then(function () { mailer.init().then(function () {
mailer.send().then(function () { mailer.send().then(function () {
should.fail(); should.fail();
@ -154,15 +154,15 @@ describe('Mail', function () {
}); });
it('should fail to send messages when given insufficient data', function (done) { it('should fail to send messages when given insufficient data', function (done) {
when.settle([ Promise.settle([
mailer.send(), mailer.send(),
mailer.send({}), mailer.send({}),
mailer.send({ subject: '123' }), mailer.send({ subject: '123' }),
mailer.send({ subject: '', html: '123' }) mailer.send({ subject: '', html: '123' })
]).then(function (descriptors) { ]).then(function (descriptors) {
descriptors.forEach(function (d) { descriptors.forEach(function (d) {
d.state.should.equal('rejected'); d.isRejected().should.be.true;
d.reason.should.be.an.instanceOf(Error); d.reason().should.be.an.instanceOf(Error);
}); });
done(); done();
}).catch(done); }).catch(done);

View file

@ -3,7 +3,7 @@
var testUtils = require('../utils'), var testUtils = require('../utils'),
should = require('should'), should = require('should'),
sinon = require('sinon'), sinon = require('sinon'),
when = require('when'), Promise = require('bluebird'),
_ = require('lodash'), _ = require('lodash'),
// Stuff we are testing // Stuff we are testing
@ -31,7 +31,7 @@ describe('Permissions', function () {
}); });
sandbox.stub(Models.Permission, 'findAll', function () { sandbox.stub(Models.Permission, 'findAll', function () {
return when(Models.Permissions.forge(permissions)); return Promise.resolve(Models.Permissions.forge(permissions));
}); });
}); });
@ -112,7 +112,7 @@ describe('Permissions', function () {
// it('can use permissible function on Model to allow something', function (done) { // it('can use permissible function on Model to allow something', function (done) {
// var testUser, // var testUser,
// permissibleStub = sandbox.stub(Models.Post, 'permissible', function () { // permissibleStub = sandbox.stub(Models.Post, 'permissible', function () {
// return when.resolve(); // return Promise.resolve();
// }); // });
// //
// testUtils.insertAuthorUser() // testUtils.insertAuthorUser()
@ -141,7 +141,7 @@ describe('Permissions', function () {
// it('can use permissible function on Model to forbid something', function (done) { // it('can use permissible function on Model to forbid something', function (done) {
// var testUser, // var testUser,
// permissibleStub = sandbox.stub(Models.Post, 'permissible', function () { // permissibleStub = sandbox.stub(Models.Post, 'permissible', function () {
// return when.reject(); // return Promise.reject();
// }); // });
// //
// testUtils.insertAuthorUser() // testUtils.insertAuthorUser()
@ -203,7 +203,7 @@ describe('Permissions', function () {
// //
// return newPerm.save(null, context).then(function () { // return newPerm.save(null, context).then(function () {
// return foundUser.permissions().attach(newPerm).then(function () { // return foundUser.permissions().attach(newPerm).then(function () {
// return when.all([updatedPost, foundUser]); // return Promise.all([updatedPost, foundUser]);
// }); // });
// }); // });
// }); // });

View file

@ -2,7 +2,7 @@
/*jshint expr:true*/ /*jshint expr:true*/
var should = require('should'), var should = require('should'),
sinon = require('sinon'), sinon = require('sinon'),
when = require('when'), Promise = require('bluebird'),
_ = require('lodash'), _ = require('lodash'),
rewire = require('rewire'), rewire = require('rewire'),
moment = require('moment'), moment = require('moment'),
@ -30,7 +30,7 @@ describe('Core Helpers', function () {
helpers = rewire('../../server/helpers'); helpers = rewire('../../server/helpers');
sandbox = sinon.sandbox.create(); sandbox = sinon.sandbox.create();
apiStub = sandbox.stub(api.settings, 'read', function () { apiStub = sandbox.stub(api.settings, 'read', function () {
return when({ return Promise.resolve({
settings: [{value: 'casper'}] settings: [{value: 'casper'}]
}); });
}); });
@ -393,7 +393,7 @@ describe('Core Helpers', function () {
}); });
it('can render class string for context', function (done) { it('can render class string for context', function (done) {
when.all([ Promise.all([
helpers.body_class.call({relativeUrl: '/'}), helpers.body_class.call({relativeUrl: '/'}),
helpers.body_class.call({relativeUrl: '/a-post-title', post: {}}), helpers.body_class.call({relativeUrl: '/a-post-title', post: {}}),
helpers.body_class.call({relativeUrl: '/page/4'}), helpers.body_class.call({relativeUrl: '/page/4'}),
@ -762,7 +762,7 @@ describe('Core Helpers', function () {
beforeEach(function () { beforeEach(function () {
apiStub.restore(); apiStub.restore();
apiStub = sandbox.stub(api.settings, 'read', function () { apiStub = sandbox.stub(api.settings, 'read', function () {
return when({ settings: [{ value: '/:slug/' }] }); return Promise.resolve({ settings: [{ value: '/:slug/' }] });
}); });
}); });

View file

@ -5,7 +5,7 @@ var nock = require('nock'),
should = require('should'), should = require('should'),
sinon = require('sinon'), sinon = require('sinon'),
testUtils = require('../utils'), testUtils = require('../utils'),
when = require('when'), Promise = require('bluebird'),
xmlrpc = require('../../server/xmlrpc'), xmlrpc = require('../../server/xmlrpc'),
// storing current environment // storing current environment
currentEnv = process.env.NODE_ENV; currentEnv = process.env.NODE_ENV;
@ -34,7 +34,7 @@ describe('XMLRPC', function () {
ping2 = nock('http://rpc.pingomatic.com').post('/').reply(200), ping2 = nock('http://rpc.pingomatic.com').post('/').reply(200),
testPost = testUtils.DataGenerator.Content.posts[2], testPost = testUtils.DataGenerator.Content.posts[2],
settingsStub = sandbox.stub(settings, 'read', function () { settingsStub = sandbox.stub(settings, 'read', function () {
return when({ settings: [{value: '/:slug/'}] }); return Promise.resolve({ settings: [{value: '/:slug/'}] });
}); });
/*jshint unused:false */ /*jshint unused:false */

View file

@ -3,33 +3,39 @@ var cp = require('child_process'),
fs = require('fs'), fs = require('fs'),
url = require('url'), url = require('url'),
net = require('net'), net = require('net'),
when = require('when'), Promise = require('bluebird'),
path = require('path'), path = require('path'),
config = require('../../server/config'); config = require('../../server/config');
function findFreePort(port) { function findFreePort(port) {
var deferred = when.defer(); return new Promise(function (resolve, reject) {
if (typeof port === 'string') {
if (typeof port === 'string') port = parseInt(port); port = parseInt(port);
if (typeof port !== 'number') port = 2368;
port = port + 1;
var server = net.createServer();
server.on('error', function(e) {
if (e.code === 'EADDRINUSE') {
when.chain(findFreePort(port), deferred);
} else {
deferred.reject(e);
} }
});
server.listen(port, function() { if (typeof port !== 'number') {
var listenPort = server.address().port; port = 2368;
server.close(function() { }
deferred.resolve(listenPort);
port = port + 1;
var server = net.createServer();
server.on('error', function(e) {
if (e.code === 'EADDRINUSE') {
resolve(findFreePort(port));
} else {
reject(e);
}
});
server.listen(port, function() {
var listenPort = server.address().port;
server.close(function() {
resolve(listenPort);
});
}); });
}); });
return deferred.promise;
} }
// Get a copy of current config object from file, to be modified before // Get a copy of current config object from file, to be modified before
@ -43,85 +49,87 @@ function forkConfig() {
// Creates a new fork of Ghost process with a given config // Creates a new fork of Ghost process with a given config
// Useful for tests that want to verify certain config options // Useful for tests that want to verify certain config options
function forkGhost(newConfig, envName) { function forkGhost(newConfig, envName) {
var deferred = when.defer();
envName = envName || 'forked'; envName = envName || 'forked';
findFreePort(newConfig.server ? newConfig.server.port : undefined)
return findFreePort(newConfig.server ? newConfig.server.port : undefined)
.then(function(port) { .then(function(port) {
newConfig.server = newConfig.server || {}; newConfig.server = newConfig.server || {};
newConfig.server.port = port; newConfig.server.port = port;
newConfig.url = url.format(_.extend(url.parse(newConfig.url), {port: port, host: null})); newConfig.url = url.format(_.extend(url.parse(newConfig.url), {port: port, host: null}));
var newConfigFile = path.join(config.paths.appRoot, 'config.test' + port + '.js'); var newConfigFile = path.join(config.paths.appRoot, 'config.test' + port + '.js');
fs.writeFile(newConfigFile, 'module.exports = {' + envName + ': ' + JSON.stringify(newConfig) + '}', function(err) {
if (err) throw err; return new Promise(function (resolve, reject) {
fs.writeFile(newConfigFile, 'module.exports = {' + envName + ': ' + JSON.stringify(newConfig) + '}', function(err) {
// setup process environment for the forked Ghost to use the new config file if (err) {
var env = _.clone(process.env); return reject(err);
env['GHOST_CONFIG'] = newConfigFile;
env['NODE_ENV'] = envName;
var child = cp.fork(path.join(config.paths.appRoot, 'index.js'), {env: env});
var pingTries = 0;
var pingCheck;
var pingStop = function() {
if (pingCheck) {
clearInterval(pingCheck);
pingCheck = undefined;
return true;
} }
return false;
}; // setup process environment for the forked Ghost to use the new config file
// periodic check until forked Ghost is running and is listening on the port var env = _.clone(process.env);
pingCheck = setInterval(function() { env['GHOST_CONFIG'] = newConfigFile;
var socket = net.connect(port); env['NODE_ENV'] = envName;
socket.on('connect', function() { var child = cp.fork(path.join(config.paths.appRoot, 'index.js'), {env: env});
socket.end();
if (pingStop()) { var pingTries = 0;
deferred.resolve(child); var pingCheck;
var pingStop = function() {
if (pingCheck) {
clearInterval(pingCheck);
pingCheck = undefined;
return true;
} }
}); return false;
socket.on('error', function(err) { };
// continue checking // periodic check until forked Ghost is running and is listening on the port
if (++pingTries >= 20 && pingStop()) { pingCheck = setInterval(function() {
deferred.reject(new Error("Timed out waiting for child process")); var socket = net.connect(port);
} socket.on('connect', function() {
}); socket.end();
}, 200); if (pingStop()) {
resolve(child);
child.on('exit', function(code, signal) { }
child.exited = true;
if (pingStop()) {
deferred.reject(new Error("Child process exit code: " + code));
}
// cleanup the temporary config file
fs.unlink(newConfigFile);
});
// override kill() to have an async callback
var baseKill = child.kill;
child.kill = function(signal, cb) {
if (typeof signal === 'function') {
cb = signal;
signal = undefined;
}
if (cb) {
child.on('exit', function() {
cb();
}); });
} socket.on('error', function(err) {
// continue checking
if (++pingTries >= 20 && pingStop()) {
reject(new Error("Timed out waiting for child process"));
}
});
}, 200);
if (child.exited) { child.on('exit', function(code, signal) {
process.nextTick(cb); child.exited = true;
} else { if (pingStop()) {
baseKill.apply(child, [signal]); reject(new Error("Child process exit code: " + code));
} }
}; // cleanup the temporary config file
fs.unlink(newConfigFile);
});
// override kill() to have an async callback
var baseKill = child.kill;
child.kill = function(signal, cb) {
if (typeof signal === 'function') {
cb = signal;
signal = undefined;
}
if (cb) {
child.on('exit', function() {
cb();
});
}
if (child.exited) {
process.nextTick(cb);
} else {
baseKill.apply(child, [signal]);
}
};
});
}); });
}) });
.otherwise(deferred.reject);
return deferred.promise;
} }
module.exports.ghost = forkGhost; module.exports.ghost = forkGhost;

View file

@ -1,6 +1,5 @@
var when = require('when'), var Promise = require('bluebird'),
sequence = require('when/sequence'), sequence = require('../../server/utils/sequence'),
nodefn = require('when/node'),
_ = require('lodash'), _ = require('lodash'),
fs = require('fs-extra'), fs = require('fs-extra'),
path = require('path'), path = require('path'),
@ -32,7 +31,7 @@ var when = require('when'),
fixtures = { fixtures = {
insertPosts: function insertPosts() { insertPosts: function insertPosts() {
var knex = config.database.knex; var knex = config.database.knex;
return when(knex('posts').insert(DataGenerator.forKnex.posts)).then(function () { return Promise.resolve(knex('posts').insert(DataGenerator.forKnex.posts)).then(function () {
return knex('tags').insert(DataGenerator.forKnex.tags); return knex('tags').insert(DataGenerator.forKnex.tags);
}).then(function () { }).then(function () {
return knex('posts_tags').insert(DataGenerator.forKnex.posts_tags); return knex('posts_tags').insert(DataGenerator.forKnex.posts_tags);
@ -49,7 +48,7 @@ fixtures = {
max = max || 50; max = max || 50;
// insert users of different roles // insert users of different roles
return when(fixtures.createUsersWithRoles()).then(function (results) { return Promise.resolve(fixtures.createUsersWithRoles()).then(function (results) {
// create the tags // create the tags
return knex('tags').insert(DataGenerator.forKnex.tags); return knex('tags').insert(DataGenerator.forKnex.tags);
}).then(function (results) { }).then(function (results) {
@ -72,7 +71,7 @@ fixtures = {
}; };
})); }));
}).then(function () { }).then(function () {
return when.all([ return Promise.all([
// PostgreSQL can return results in any order // PostgreSQL can return results in any order
knex('posts').orderBy('id', 'asc').select('id'), knex('posts').orderBy('id', 'asc').select('id'),
knex('tags').select('id') knex('tags').select('id')
@ -84,7 +83,7 @@ fixtures = {
i; i;
if (max > posts.length) { if (max > posts.length) {
throw new Error('Trying to add more posts_tags than the number of posts.'); throw new Error('Trying to add more posts_tags than the number of posts. ' + max + ' ' + posts.length);
} }
for (i = 0; i < max; i += 1) { for (i = 0; i < max; i += 1) {
@ -133,7 +132,7 @@ fixtures = {
var knex = config.database.knex; var knex = config.database.knex;
return when.all([ return Promise.all([
// PostgreSQL can return results in any order // PostgreSQL can return results in any order
knex('posts').orderBy('id', 'asc').select('id'), knex('posts').orderBy('id', 'asc').select('id'),
knex('tags').select('id', 'name') knex('tags').select('id', 'name')
@ -268,16 +267,17 @@ fixtures = {
}, },
loadExportFixture: function loadExportFixture(filename) { loadExportFixture: function loadExportFixture(filename) {
var filepath = path.resolve(__dirname + '/fixtures/' + filename + '.json'); var filepath = path.resolve(__dirname + '/fixtures/' + filename + '.json'),
readFile = Promise.promisify(fs.readFile);
return nodefn.call(fs.readFile, filepath).then(function (fileContents) { return readFile(filepath).then(function (fileContents) {
var data; var data;
// Parse the json data // Parse the json data
try { try {
data = JSON.parse(fileContents); data = JSON.parse(fileContents);
} catch (e) { } catch (e) {
return when.reject(new Error('Failed to parse the file')); return new Error('Failed to parse the file');
} }
return data; return data;
@ -451,7 +451,6 @@ setup = function setup() {
// TODO make this do the DB init as well // TODO make this do the DB init as well
doAuth = function doAuth() { doAuth = function doAuth() {
var options = arguments, var options = arguments,
deferred = when.defer(),
request = arguments[0], request = arguments[0],
user = DataGenerator.forModel.users[0], user = DataGenerator.forModel.users[0],
fixtureOps; fixtureOps;
@ -466,19 +465,19 @@ doAuth = function doAuth() {
fixtureOps = getFixtureOps(options); fixtureOps = getFixtureOps(options);
sequence(fixtureOps).then(function () { return new Promise(function (resolve, reject) {
request.post('/ghost/api/v0.1/authentication/token/') return sequence(fixtureOps).then(function () {
.send({ grant_type: 'password', username: user.email, password: user.password, client_id: 'ghost-admin'}) request.post('/ghost/api/v0.1/authentication/token/')
.end(function (err, res) { .send({ grant_type: 'password', username: user.email, password: user.password, client_id: 'ghost-admin'})
if (err) { .end(function (err, res) {
deferred.reject(err); if (err) {
} return reject(err);
}
deferred.resolve(res.body.access_token); resolve(res.body.access_token);
}); });
});
}); });
return deferred.promise;
}; };
teardown = function teardown(done) { teardown = function teardown(done) {

View file

@ -32,6 +32,7 @@
"engineStrict": true, "engineStrict": true,
"dependencies": { "dependencies": {
"bcryptjs": "0.7.10", "bcryptjs": "0.7.10",
"bluebird": "2.3.0",
"body-parser": "1.6.3", "body-parser": "1.6.3",
"bookshelf": "0.7.6", "bookshelf": "0.7.6",
"busboy": "0.2.3", "busboy": "0.2.3",
@ -63,7 +64,6 @@
"static-favicon": "1.0.2", "static-favicon": "1.0.2",
"unidecode": "0.1.3", "unidecode": "0.1.3",
"validator": "3.4.0", "validator": "3.4.0",
"when": "3.2.3",
"xml": "0.0.12" "xml": "0.0.12"
}, },
"optionalDependencies": { "optionalDependencies": {