0
Fork 0
mirror of https://github.com/TryGhost/Ghost.git synced 2025-02-24 23:48:13 -05:00
ghost/core/server/controllers/admin.js
Harry Wolff 37b2fd93d8 This commit removes a lot of code from ghost.js, including:
Move helper functions registerThemeHelper and registerAsyncThemeHelper
to the helpers module.
Also update the app proxy object to reflect this new code location,
and the tests to reflect that as well

Create ./sore/server/filters which houses all filter related behavior.
Was previously on the ghost singleton.
Also create the filters_spec file for testing
and update all code and tests to use new code location.

Create ./sore/server/helpers/template which houses all template related behavior.
Was previously on the ghost singleton.
Also create the helpers_template_spec file for testing
and update all code and tests to use new code location.

Move ghost.mail instance onto the mail module directly
and update related code and tests to use new location

Move Polyglot instance onto require module directly

Move ghost.availablePlugins to plugins module directly
2013-11-28 09:21:53 -05:00

320 lines
11 KiB
JavaScript

var Ghost = require('../../ghost'),
config = require('../config'),
_ = require('underscore'),
path = require('path'),
when = require('when'),
api = require('../api'),
mailer = require('../mail'),
errors = require('../errorHandling'),
storage = require('../storage'),
ghost = new Ghost(),
dataProvider = ghost.dataProvider,
adminNavbar,
adminControllers,
loginSecurity = [];
// TODO: combine path/navClass to single "slug(?)" variable with no prefix
adminNavbar = {
content: {
name: 'Content',
navClass: 'content',
key: 'admin.navbar.content',
path: '/'
},
add: {
name: 'New Post',
navClass: 'editor',
key: 'admin.navbar.editor',
path: '/editor/'
},
settings: {
name: 'Settings',
navClass: 'settings',
key: 'admin.navbar.settings',
path: '/settings/'
}
};
// TODO: make this a util or helper
function setSelected(list, name) {
_.each(list, function (item, key) {
item.selected = key === name;
});
return list;
}
adminControllers = {
'uploader': function (req, res) {
var type = req.files.uploadimage.type,
ext = path.extname(req.files.uploadimage.name).toLowerCase(),
store = storage.get_storage();
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')) {
return res.send(415, 'Unsupported Media Type');
}
store
.save(req.files.uploadimage)
.then(function (url) {
return res.send(url);
})
.otherwise(function (e) {
return errors.logError(e);
});
},
'login': function (req, res) {
/*jslint unparam:true*/
res.render('login', {
bodyClass: 'ghost-login',
hideNavbar: true,
adminNav: setSelected(adminNavbar, 'login')
});
},
'auth': function (req, res) {
var root = ghost.blogGlobals().path === '/' ? '' : ghost.blogGlobals().path,
currentTime = process.hrtime()[0],
denied = '';
loginSecurity = _.filter(loginSecurity, function (ipTime) {
return (ipTime.time + 2 > currentTime);
});
denied = _.find(loginSecurity, function (ipTime) {
return (ipTime.ip === req.connection.remoteAddress);
});
if (!denied) {
loginSecurity.push({ip: req.connection.remoteAddress, time: process.hrtime()[0]});
api.users.check({email: req.body.email, pw: req.body.password}).then(function (user) {
req.session.regenerate(function (err) {
if (!err) {
req.session.user = user.id;
var redirect = root + '/ghost/';
if (req.body.redirect) {
redirect += decodeURIComponent(req.body.redirect);
}
res.json(200, {redirect: redirect});
}
});
}, function (error) {
res.json(401, {error: error.message});
});
} else {
res.json(401, {error: 'Slow down, there are way too many login attempts!'});
}
},
'changepw': function (req, res) {
return api.users.changePassword({
currentUser: req.session.user,
oldpw: req.body.password,
newpw: req.body.newpassword,
ne2pw: req.body.ne2password
}).then(function () {
res.json(200, {msg: 'Password changed successfully'});
}, function (error) {
res.send(401, {error: error.message});
});
},
'signup': function (req, res) {
/*jslint unparam:true*/
res.render('signup', {
bodyClass: 'ghost-signup',
hideNavbar: true,
adminNav: setSelected(adminNavbar, 'login')
});
},
'doRegister': function (req, res) {
var root = ghost.blogGlobals().path === '/' ? '' : ghost.blogGlobals().path,
name = req.body.name,
email = req.body.email,
password = req.body.password;
api.users.add({
name: name,
email: email,
password: password
}).then(function (user) {
api.settings.edit('email', email).then(function () {
req.session.regenerate(function (err) {
if (!err) {
if (req.session.user === undefined) {
req.session.user = user.id;
}
res.json(200, {redirect: root + '/ghost/'});
}
});
});
}).otherwise(function (error) {
res.json(401, {error: error.message});
});
},
'forgotten': function (req, res) {
/*jslint unparam:true*/
res.render('forgotten', {
bodyClass: 'ghost-forgotten',
hideNavbar: true,
adminNav: setSelected(adminNavbar, 'login')
});
},
'generateResetToken': function (req, res) {
var root = ghost.blogGlobals().path === '/' ? '' : ghost.blogGlobals().path,
email = req.body.email;
api.users.generateResetToken(email).then(function (token) {
var siteLink = '<a href="' + config().url + '">' + config().url + '</a>',
resetUrl = config().url + '/ghost/reset/' + token + '/',
resetLink = '<a href="' + resetUrl + '">' + resetUrl + '</a>',
message = {
to: email,
subject: 'Reset Password',
html: '<p><strong>Hello!</strong></p>' +
'<p>A request has been made to reset the password on the site ' + siteLink + '.</p>' +
'<p>Please follow the link below to reset your password:<br><br>' + resetLink + '</p>' +
'<p>Ghost</p>'
};
return mailer.send(message);
}).then(function success() {
var notification = {
type: 'success',
message: 'Check your email for further instructions',
status: 'passive',
id: 'successresetpw'
};
return api.notifications.add(notification).then(function () {
res.json(200, {redirect: root + '/ghost/signin/'});
});
}, function failure(error) {
// TODO: This is kind of sketchy, depends on magic string error.message from Bookshelf.
// TODO: It's debatable whether we want to just tell the user we sent the email in this case or not, we are giving away sensitive info here.
if (error && error.message === 'EmptyResponse') {
error.message = "Invalid email address";
}
res.json(401, {error: error.message});
});
},
'reset': function (req, res) {
var root = ghost.blogGlobals().path === '/' ? '' : ghost.blogGlobals().path,
// Validate the request token
token = req.params.token;
api.users.validateToken(token).then(function () {
// Render the reset form
res.render('reset', {
bodyClass: 'ghost-reset',
hideNavbar: true,
adminNav: setSelected(adminNavbar, 'reset')
});
}).otherwise(function (err) {
// Redirect to forgotten if invalid token
var notification = {
type: 'error',
message: 'Invalid or expired token',
status: 'persistent',
id: 'errorinvalidtoken'
};
errors.logError(err, 'admin.js', "Please check the provided token for validity and expiration.");
return api.notifications.add(notification).then(function () {
res.redirect(root + '/ghost/forgotten');
});
});
},
'resetPassword': function (req, res) {
var root = ghost.blogGlobals().path === '/' ? '' : ghost.blogGlobals().path,
token = req.params.token,
newPassword = req.param('newpassword'),
ne2Password = req.param('ne2password');
api.users.resetPassword(token, newPassword, ne2Password).then(function () {
var notification = {
type: 'success',
message: 'Password changed successfully.',
status: 'passive',
id: 'successresetpw'
};
return api.notifications.add(notification).then(function () {
res.json(200, {redirect: root + '/ghost/signin/'});
});
}).otherwise(function (err) {
// TODO: Better error message if we can tell whether the passwords didn't match or something
res.json(401, {error: err.message});
});
},
'logout': function (req, res) {
req.session.destroy();
var root = ghost.blogGlobals().path === '/' ? '' : ghost.blogGlobals().path,
notification = {
type: 'success',
message: 'You were successfully signed out',
status: 'passive',
id: 'successlogout'
};
return api.notifications.add(notification).then(function () {
res.redirect(root + '/ghost/signin/');
});
},
'index': function (req, res) {
/*jslint unparam:true*/
res.render('content', {
bodyClass: 'manage',
adminNav: setSelected(adminNavbar, 'content')
});
},
'editor': function (req, res) {
if (req.params.id !== undefined) {
res.render('editor', {
bodyClass: 'editor',
adminNav: setSelected(adminNavbar, 'content')
});
} else {
res.render('editor', {
bodyClass: 'editor',
adminNav: setSelected(adminNavbar, 'add')
});
}
},
'content': function (req, res) {
/*jslint unparam:true*/
res.render('content', {
bodyClass: 'manage',
adminNav: setSelected(adminNavbar, 'content')
});
},
'settings': function (req, res, next) {
// TODO: Centralise list/enumeration of settings panes, so we don't
// run into trouble in future.
var allowedSections = ['', 'general', 'user'],
section = req.url.replace(/(^\/ghost\/settings[\/]*|\/$)/ig, '');
if (allowedSections.indexOf(section) < 0) {
return next();
}
res.render('settings', {
bodyClass: 'settings',
adminNav: setSelected(adminNavbar, 'settings')
});
},
'debug': { /* ugly temporary stuff for managing the app before it's properly finished */
index: function (req, res) {
/*jslint unparam:true*/
res.render('debug', {
bodyClass: 'settings',
adminNav: setSelected(adminNavbar, 'settings')
});
}
}
};
module.exports = adminControllers;