Ghost/core/server/controllers/admin.js
Hannah Wolfe 41e36cca7e Validation consistency
- introduced validation method in the post and user model
- moved signup validation onto model
- consistent use of validation & error messaging in the admin UI
- helper methods in base view moved to a utils object
2013-08-25 18:10:12 +01:00

362 lines
13 KiB
JavaScript

var Ghost = require('../../ghost'),
dataExport = require('../data/export'),
dataImport = require('../data/import'),
_ = require('underscore'),
fs = require('fs-extra'),
path = require('path'),
when = require('when'),
nodefn = require('when/node/function'),
api = require('../api'),
moment = require('moment'),
errors = require('../errorHandling'),
ghost = new Ghost(),
dataProvider = ghost.dataProvider,
adminNavbar,
adminControllers,
loginSecurity = [];
// TODO: combine path/navClass to single "slug(?)" variable with no prefix
adminNavbar = {
dashboard: {
name: 'Dashboard',
navClass: 'dashboard',
key: 'admin.navbar.dashboard',
path: '/'
},
content: {
name: 'Content',
navClass: 'content',
key: 'admin.navbar.content',
path: '/content/'
},
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 currentDate = moment(),
month = currentDate.format("MMM"),
year = currentDate.format("YYYY"),
tmp_path = req.files.uploadimage.path,
dir = path.join('content/images', year, month),
target_path = path.join(dir, req.files.uploadimage.name),
ext = path.extname(req.files.uploadimage.name).toLowerCase(),
src = path.join('/', target_path);
function renameFile() {
// adds directories recursively
fs.mkdirs(dir, function (err) {
if (err) {
errors.logError(err);
} else {
fs.copy(tmp_path, target_path, function (err) {
if (err) {
errors.logError(err);
} else {
res.send(src);
}
});
}
});
}
if (ext === ".jpg" || ext === ".png" || ext === ".gif") {
renameFile();
} else {
res.send("Invalid filetype");
}
},
'login': function (req, res) {
res.render('login', {
bodyClass: 'ghost-login',
hideNavbar: true,
adminNav: setSelected(adminNavbar, 'login')
});
},
'auth': function (req, res) {
var 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.user = user.id;
res.json(200, {redirect: req.body.redirect ? '/ghost/'
+ decodeURIComponent(req.body.redirect) : '/ghost/'});
}, 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) {
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) {
res.render('signup', {
bodyClass: 'ghost-login',
hideNavbar: true,
adminNav: setSelected(adminNavbar, 'login')
});
},
'doRegister': function (req, res) {
var email = req.body.email,
password = req.body.password;
api.users.add({
email_address: email,
password: password
}).then(function (user) {
if (req.session.user === undefined) {
req.session.user = user.id;
}
res.json(200, {redirect: '/ghost/'});
}, function (error) {
res.json(401, {error: error.message});
});
},
'logout': function (req, res) {
delete req.session.user;
var msg = {
type: 'success',
message: 'You were successfully signed out',
status: 'passive',
id: 'successlogout'
};
// let's only add the notification once
if (!_.contains(_.pluck(ghost.notifications, 'id'), 'successlogout')) {
ghost.notifications.push(msg);
}
res.redirect('/ghost/signin/');
},
'index': function (req, res) {
res.render('dashboard', {
bodyClass: 'dashboard',
adminNav: setSelected(adminNavbar, 'dashboard')
});
},
'editor': function (req, res) {
if (req.params.id !== undefined) {
api.posts.read({id: parseInt(req.params.id, 10)})
.then(function (post) {
res.render('editor', {
bodyClass: 'editor',
adminNav: setSelected(adminNavbar, 'content'),
title: post.get('title'),
content: post.get('content')
});
});
} else {
res.render('editor', {
bodyClass: 'editor',
adminNav: setSelected(adminNavbar, 'add')
});
}
},
'content': function (req, res) {
api.posts.browse({status: req.params.status || 'all'})
.then(function (page) {
res.render('content', {
bodyClass: 'manage',
adminNav: setSelected(adminNavbar, 'content'),
posts: page.posts
});
});
},
'settings': function (req, res) {
api.settings.browse()
.then(function (settings) {
res.render('settings', {
bodyClass: 'settings',
adminNav: setSelected(adminNavbar, 'settings'),
settings: settings
});
});
},
'debug': { /* ugly temporary stuff for managing the app before it's properly finished */
index: function (req, res) {
res.render('debug', {
bodyClass: 'settings',
adminNav: setSelected(adminNavbar, 'settings')
});
},
'export': function (req, res) {
// Get current version from settings
api.settings.read({ key: "currentVersion" })
.then(function (setting) {
// Export the current versions data
return dataExport(setting.value);
}, function () {
// If no setting, assume 001
return dataExport("001");
})
.then(function (exportedData) {
// Save the exported data to the file system for download
var fileName = path.resolve(__dirname + '/../../server/data/export/exported-' + (new Date().getTime()) + '.json');
return nodefn.call(fs.writeFile, fileName, JSON.stringify(exportedData)).then(function () {
return when(fileName);
});
})
.then(function (exportedFilePath) {
// Send the exported data file
res.download(exportedFilePath, 'GhostData.json');
})
.otherwise(function (error) {
// Notify of an error if it occurs
var notification = {
type: 'error',
message: error.message || error,
status: 'persistent',
id: 'per-' + (ghost.notifications.length + 1)
};
return api.notifications.add(notification).then(function () {
res.redirect("/ghost/debug/");
});
});
},
'import': function (req, res) {
if (!req.files.importfile) {
// Notify of an error if it occurs
var notification = {
type: 'error',
message: "Must select a file to import",
status: 'persistent',
id: 'per-' + (ghost.notifications.length + 1)
};
return api.notifications.add(notification).then(function () {
res.redirect("/ghost/debug/");
});
}
// Get the current version for importing
api.settings.read({ key: "currentVersion" })
.then(function (setting) {
return when(setting.value);
}, function () {
return when("001");
})
.then(function (currentVersion) {
// Read the file contents
return nodefn.call(fs.readFile, req.files.importfile.path)
.then(function (fileContents) {
var importData;
// Parse the json data
try {
importData = JSON.parse(fileContents);
} catch (e) {
return when.reject(new Error("Failed to parse the import file"));
}
if (!importData.meta || !importData.meta.version) {
return when.reject(new Error("Import data does not specify version"));
}
// Import for the current version
return dataImport(currentVersion, importData);
});
})
.then(function importSuccess() {
var notification = {
type: 'success',
message: "Data imported. Log in with the user details you imported",
status: 'persistent',
id: 'per-' + (ghost.notifications.length + 1)
};
return api.notifications.add(notification).then(function () {
delete req.session.user;
res.redirect('/ghost/signin/');
});
}, function importFailure(error) {
// Notify of an error if it occurs
var notification = {
type: 'error',
message: error.message || error,
status: 'persistent',
id: 'per-' + (ghost.notifications.length + 1)
};
return api.notifications.add(notification).then(function () {
res.redirect('/ghost/debug/');
});
});
},
'reset': function (req, res) {
// Grab the current version so we can get the migration
dataProvider.reset()
.then(function resetSuccess() {
var notification = {
type: 'success',
message: "Database reset. Create a new user",
status: 'persistent',
id: 'per-' + (ghost.notifications.length + 1)
};
return api.notifications.add(notification).then(function () {
delete req.session.user;
res.redirect('/ghost/signup/');
});
}, function resetFailure(error) {
var notification = {
type: 'error',
message: error.message || error,
status: 'persistent',
id: 'per-' + (ghost.notifications.length + 1)
};
return api.notifications.add(notification).then(function () {
res.redirect('/ghost/debug/');
});
});
}
}
};
module.exports = adminControllers;