Ghost/core/server/api.js
Gabor Javorszky 071f9769c6 Users can change password
Closes #282
* Added a new route
* Added new methods
* Triple security!
* Passwords are actually changed
* Also added a change password button, because 'save' has too much baggage.

On security: checks whether you're logged in. Then checks whether your old password is actually the one that belongs to you (gets value from the email field for the email, see caveat no2). Checks the new passwords for === and length > 6 on client and server side as well. And THEN changes passwords.

Caveats:
* didn't add a test, as mocha fails spectacularly on my machine. SQLITE_CORRUPT: database disk image is malformed. Cute, huh?
* Because we don't have / I'm not aware of / could not find a "currentuser" variable, I need to get the email address of the user we want to change from the email field. Theoretically if they replace that with another user's email address, and supply their pw, they will change THEIR password instead of their own.
2013-08-06 00:49:06 +01:00

202 lines
6.0 KiB
JavaScript

// # Ghost Data API
// Provides access to the data model
/**
* This is intended to replace the old dataProvider files and should access & manipulate the models directly
*/
var Ghost = require('../ghost'),
_ = require('underscore'),
when = require('when'),
errors = require('./errorHandling'),
ghost = new Ghost(),
dataProvider = ghost.dataProvider,
posts,
users,
notifications,
settings,
requestHandler,
cachedSettingsRequestHandler,
settingsObject,
settingsCollection;
// # Posts
posts = {
// takes filter / pagination parameters
// returns a page of posts in a json response
browse: function browse(options) {
return dataProvider.Post.findPage(options);
},
// takes an identifier (id or slug?)
// returns a single post in a json response
read: function read(args) {
return dataProvider.Post.findOne(args);
},
// takes a json object with all the properties which should be updated
// returns the resulting post in a json response
edit: function edit(postData) {
return dataProvider.Post.edit(postData);
},
// takes a json object representing a post,
// returns the resulting post in a json response
add: function add(postData) {
return dataProvider.Post.add(postData);
},
// takes an identifier (id or slug?)
// returns a json response with the id of the deleted post
destroy: function destroy(args) {
return dataProvider.Post.destroy(args.id);
}
};
// # Users
users = {
browse: function browse(options) {
return dataProvider.User.browse(options);
},
read: function read(args) {
return dataProvider.User.read(args);
},
edit: function edit(postData) {
return dataProvider.User.edit(postData);
},
add: function add(postData) {
return dataProvider.User.add(postData);
},
check: function check(postData) {
return dataProvider.User.check(postData);
},
changePassword: function changePassword(postData) {
return dataProvider.User.changePassword(postData);
}
};
// # Notifications
notifications = {
destroy: function destroy(i) {
ghost.notifications = _.reject(ghost.notifications, function (element) {
return element.id === i.id;
});
return when(ghost.notifications);
},
add: function add(notification) {
return when(ghost.notifications.push(notification));
}
};
// # Settings
// Turn a settings collection into a single object/hashmap
settingsObject = function (settings) {
return (settings.toJSON ? settings.toJSON() : settings).reduce(function (res, item) {
if (item.toJSON) { item = item.toJSON(); }
if (item.key) { res[item.key] = item.value; }
return res;
}, {});
};
// Turn an object into a collection
settingsCollection = function (settings) {
return _.map(settings, function (value, key) {
return { key: key, value: value };
});
};
settings = {
browse: function browse(options) {
return dataProvider.Settings.browse(options).then(settingsObject, errors.logAndThrowError);
},
read: function read(options) {
if (_.isString(options)) {
options = { key: options };
}
return dataProvider.Settings.read(options.key).then(function (setting) {
if (!setting) {
return when.reject("Unable to find setting: " + options.key);
}
return _.pick(setting.toJSON(), 'key', 'value');
}, errors.logAndThrowError);
},
edit: function edit(key, value) {
// Check for passing a collection of settings first
if (_.isObject(key)) {
key = settingsCollection(key);
return dataProvider.Settings.edit(key).then(settingsObject, errors.logAndThrowError);
}
return dataProvider.Settings.read(key).then(function (setting) {
if (!setting) {
return when.reject("Unable to find setting: " + key);
}
if (!_.isString(value)) {
value = JSON.stringify(value);
}
setting.set('value', value);
return dataProvider.Settings.edit(setting);
}, errors.logAndThrowError);
}
};
// categories: {};
// post_categories: {};
// requestHandler
// decorator for api functions which are called via an HTTP request
// takes the API method and wraps it so that it gets data from the request and returns a sensible JSON response
requestHandler = function (apiMethod) {
return function (req, res) {
var options = _.extend(req.body, req.query, req.params);
return apiMethod(options).then(function (result) {
res.json(result || {});
}, function (error) {
res.json(400, {error: error});
});
};
};
cachedSettingsRequestHandler = function (apiMethod) {
if (!ghost.settings()) {
return requestHandler(apiMethod);
}
return function (req, res) {
var options = _.extend(req.body, req.query, req.params),
promise;
switch (apiMethod.name) {
case 'browse':
promise = when(ghost.settings());
break;
case 'read':
promise = when(ghost.settings()[options.key]);
break;
case 'edit':
promise = apiMethod(options).then(function (result) {
ghost.updateSettingsCache(result);
return result;
});
break;
default:
errors.logAndThrowError(new Error('Unknown method name for settings API: ' + apiMethod.name));
}
return promise.then(function (result) {
res.json(result || {});
}, function (error) {
res.json(400, {error: error});
});
};
};
module.exports.posts = posts;
module.exports.users = users;
module.exports.notifications = notifications;
module.exports.settings = settings;
module.exports.requestHandler = requestHandler;
module.exports.cachedSettingsRequestHandler = cachedSettingsRequestHandler;