mirror of https://github.com/TryGhost/Ghost.git
Highlighted routes, controllers & renderers
refs #5091, refs #9192 - There are several theme template "renderers" all over the codebase - Some are in apps, and were called "controllers" - One is in error handling - All of them now have comments marking out how they share logic/steps - Other comments describe routes & controllers where they live
This commit is contained in:
parent
474e9234a6
commit
abaf0461cf
|
@ -7,14 +7,16 @@ var router = require('./lib/router'),
|
|||
|
||||
module.exports = {
|
||||
activate: function activate(ghost) {
|
||||
registerHelpers(ghost);
|
||||
var ampRoute = '*/' + config.get('routeKeywords').amp + '/';
|
||||
|
||||
ghost.routeService.registerRouter('*/' + config.get('routeKeywords').amp + '/', function settingsEnabledRouter(req, res, next) {
|
||||
ghost.routeService.registerRouter(ampRoute, function settingsEnabledRouter(req, res, next) {
|
||||
if (settingsCache.get('amp') === true) {
|
||||
return router.apply(this, arguments);
|
||||
}
|
||||
|
||||
next();
|
||||
});
|
||||
|
||||
registerHelpers(ghost);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -7,29 +7,38 @@ var path = require('path'),
|
|||
errors = require('../../../errors'),
|
||||
templates = require('../../../controllers/frontend/templates'),
|
||||
postLookup = require('../../../controllers/frontend/post-lookup'),
|
||||
setResponseContext = require('../../../controllers/frontend/context');
|
||||
setResponseContext = require('../../../controllers/frontend/context'),
|
||||
|
||||
function controller(req, res, next) {
|
||||
var templateName = 'amp',
|
||||
defaultTemplate = path.resolve(__dirname, 'views', templateName + '.hbs'),
|
||||
view = templates.pickTemplate(templateName, defaultTemplate),
|
||||
data = req.body || {};
|
||||
templateName = 'amp',
|
||||
defaultTemplate = path.resolve(__dirname, 'views', templateName + '.hbs');
|
||||
|
||||
function _renderer(req, res, next) {
|
||||
// Renderer begin
|
||||
// Format data
|
||||
var data = req.body || {};
|
||||
|
||||
// CASE: we only support amp pages for posts that are not static pages
|
||||
if (!data.post || data.post.page) {
|
||||
return next(new errors.NotFoundError({message: i18n.t('errors.errors.pageNotFound')}));
|
||||
}
|
||||
|
||||
// Context
|
||||
setResponseContext(req, res, data);
|
||||
|
||||
return res.render(view, data);
|
||||
// Template
|
||||
res.template = templates.pickTemplate(templateName, defaultTemplate);
|
||||
|
||||
// Render Call
|
||||
return res.render(res.template, data);
|
||||
}
|
||||
|
||||
// This here is a controller.
|
||||
// In fact, this whole file is nothing more than a controller + renderer & doesn't need to be a router
|
||||
function getPostData(req, res, next) {
|
||||
req.body = req.body || {};
|
||||
|
||||
postLookup(res.locals.relativeUrl)
|
||||
.then(function (result) {
|
||||
.then(function handleResult(result) {
|
||||
if (result && result.post) {
|
||||
req.body.post = result.post;
|
||||
}
|
||||
|
@ -43,9 +52,9 @@ function getPostData(req, res, next) {
|
|||
ampRouter.route('/')
|
||||
.get(
|
||||
getPostData,
|
||||
controller
|
||||
_renderer
|
||||
);
|
||||
|
||||
module.exports = ampRouter;
|
||||
module.exports.controller = controller;
|
||||
module.exports.renderer = _renderer;
|
||||
module.exports.getPostData = getPostData;
|
||||
|
|
|
@ -5,28 +5,35 @@ var config = require('../../config'),
|
|||
i18n = require('../../i18n'),
|
||||
middleware = require('./lib/middleware'),
|
||||
router = require('./lib/router'),
|
||||
registerHelpers = require('./lib/helpers');
|
||||
registerHelpers = require('./lib/helpers'),
|
||||
checkSubdir;
|
||||
|
||||
checkSubdir = function checkSubdir() {
|
||||
var paths;
|
||||
|
||||
if (utils.url.getSubdir()) {
|
||||
paths = utils.url.getSubdir().split('/');
|
||||
|
||||
if (paths.pop() === config.get('routeKeywords').private) {
|
||||
logging.error(new errors.GhostError({
|
||||
message: i18n.t('errors.config.urlCannotContainPrivateSubdir.error'),
|
||||
context: i18n.t('errors.config.urlCannotContainPrivateSubdir.description'),
|
||||
help: i18n.t('errors.config.urlCannotContainPrivateSubdir.help')
|
||||
}));
|
||||
|
||||
// @TODO: why
|
||||
process.exit(0);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
activate: function activate(ghost) {
|
||||
var paths;
|
||||
var privateRoute = '/' + config.get('routeKeywords').private + '/';
|
||||
|
||||
if (utils.url.getSubdir()) {
|
||||
paths = utils.url.getSubdir().split('/');
|
||||
checkSubdir();
|
||||
|
||||
if (paths.pop() === config.get('routeKeywords').private) {
|
||||
logging.error(new errors.GhostError({
|
||||
message: i18n.t('errors.config.urlCannotContainPrivateSubdir.error'),
|
||||
context: i18n.t('errors.config.urlCannotContainPrivateSubdir.description'),
|
||||
help: i18n.t('errors.config.urlCannotContainPrivateSubdir.help')
|
||||
}));
|
||||
|
||||
// @TODO: why
|
||||
process.exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
ghost.routeService.registerRouter('/' + config.get('routeKeywords').private + '/', router);
|
||||
ghost.routeService.registerRouter(privateRoute, router);
|
||||
|
||||
registerHelpers(ghost);
|
||||
},
|
||||
|
|
|
@ -6,36 +6,43 @@ var path = require('path'),
|
|||
setResponseContext = require('../../../controllers/frontend/context'),
|
||||
brute = require('../../../middleware/brute'),
|
||||
|
||||
templateName = 'private',
|
||||
defaultTemplate = path.resolve(__dirname, 'views', templateName + '.hbs'),
|
||||
|
||||
privateRouter = express.Router();
|
||||
|
||||
function controller(req, res) {
|
||||
var templateName = 'private',
|
||||
defaultTemplate = path.resolve(__dirname, 'views', templateName + '.hbs'),
|
||||
view = templates.pickTemplate(templateName, defaultTemplate),
|
||||
data = {};
|
||||
function _renderer(req, res) {
|
||||
// Renderer begin
|
||||
// Format data
|
||||
var data = {};
|
||||
|
||||
if (res.error) {
|
||||
data.error = res.error;
|
||||
}
|
||||
|
||||
// Context
|
||||
setResponseContext(req, res);
|
||||
|
||||
return res.render(view, data);
|
||||
// Template
|
||||
res.template = templates.pickTemplate(templateName, defaultTemplate);
|
||||
|
||||
// Render Call
|
||||
return res.render(res.template, data);
|
||||
}
|
||||
|
||||
// password-protected frontend route
|
||||
privateRouter.route('/')
|
||||
.get(
|
||||
middleware.isPrivateSessionAuth,
|
||||
controller
|
||||
_renderer
|
||||
)
|
||||
.post(
|
||||
bodyParser.urlencoded({extended: true}),
|
||||
middleware.isPrivateSessionAuth,
|
||||
brute.privateBlog,
|
||||
middleware.authenticateProtection,
|
||||
controller
|
||||
_renderer
|
||||
);
|
||||
|
||||
module.exports = privateRouter;
|
||||
module.exports.controller = controller;
|
||||
module.exports.renderer = _renderer;
|
||||
|
|
|
@ -7,10 +7,11 @@ var router = require('./lib/router'),
|
|||
|
||||
module.exports = {
|
||||
activate: function activate(ghost) {
|
||||
var subscribeRoute = '/' + config.get('routeKeywords').subscribe + '/';
|
||||
// TODO, how to do all this only if the Subscribers flag is set?!
|
||||
registerHelpers(ghost);
|
||||
|
||||
ghost.routeService.registerRouter('/' + config.get('routeKeywords').subscribe + '/', function labsEnabledRouter(req, res, next) {
|
||||
ghost.routeService.registerRouter(subscribeRoute, function labsEnabledRouter(req, res, next) {
|
||||
if (labs.isSet('subscribers') === true) {
|
||||
return router.apply(this, arguments);
|
||||
}
|
||||
|
|
|
@ -10,17 +10,25 @@ var path = require('path'),
|
|||
validator = require('../../../data/validation').validator,
|
||||
templates = require('../../../controllers/frontend/templates'),
|
||||
postLookup = require('../../../controllers/frontend/post-lookup'),
|
||||
setResponseContext = require('../../../controllers/frontend/context');
|
||||
setResponseContext = require('../../../controllers/frontend/context'),
|
||||
|
||||
function controller(req, res) {
|
||||
var templateName = 'subscribe',
|
||||
defaultTemplate = path.resolve(__dirname, 'views', templateName + '.hbs'),
|
||||
view = templates.pickTemplate(templateName, defaultTemplate),
|
||||
data = req.body;
|
||||
templateName = 'subscribe',
|
||||
defaultTemplate = path.resolve(__dirname, 'views', templateName + '.hbs');
|
||||
|
||||
// In future we'd have a more complex controller here - showing if someone already subscribed?!
|
||||
function _renderer(req, res) {
|
||||
// Renderer begin
|
||||
// Format data
|
||||
var data = req.body;
|
||||
|
||||
// Context
|
||||
setResponseContext(req, res);
|
||||
|
||||
return res.render(view, data);
|
||||
// Template
|
||||
res.template = templates.pickTemplate(templateName, defaultTemplate);
|
||||
|
||||
// Render Call
|
||||
return res.render(res.template, data);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -33,7 +41,7 @@ function errorHandler(error, req, res, next) {
|
|||
|
||||
if (error.statusCode !== 404) {
|
||||
res.locals.error = error;
|
||||
return controller(req, res);
|
||||
return _renderer(req, res);
|
||||
}
|
||||
|
||||
next(error);
|
||||
|
@ -100,19 +108,18 @@ function storeSubscriber(req, res, next) {
|
|||
// subscribe frontend route
|
||||
subscribeRouter.route('/')
|
||||
.get(
|
||||
controller
|
||||
_renderer
|
||||
)
|
||||
.post(
|
||||
bodyParser.urlencoded({extended: true}),
|
||||
honeyPot,
|
||||
handleSource,
|
||||
storeSubscriber,
|
||||
controller
|
||||
_renderer
|
||||
);
|
||||
|
||||
// configure an error handler just for subscribe problems
|
||||
subscribeRouter.use(errorHandler);
|
||||
|
||||
module.exports = subscribeRouter;
|
||||
module.exports.controller = controller;
|
||||
module.exports.storeSubscriber = storeSubscriber;
|
||||
|
|
|
@ -8,6 +8,9 @@ var _ = require('lodash'),
|
|||
setRequestIsSecure = require('./frontend/secure'),
|
||||
renderChannel = require('./frontend/render-channel');
|
||||
|
||||
// This here is a controller.
|
||||
// The "route" is handled in controllers/channels/router.js
|
||||
// There's both a top-level channelS router, and an individual channel one
|
||||
module.exports = function channelController(req, res, next) {
|
||||
// Parse the parameters we need from the URL
|
||||
var pageParam = req.params.page !== undefined ? req.params.page : 1,
|
||||
|
|
|
@ -6,12 +6,19 @@ var debug = require('ghost-ignition').debug('channels:render'),
|
|||
module.exports = function renderChannel(req, res) {
|
||||
debug('renderChannel called');
|
||||
return function renderChannel(result) {
|
||||
var view = templates.channel(res.locals.channel);
|
||||
|
||||
// Renderer begin
|
||||
// Format data 2
|
||||
// Do final data formatting and then render
|
||||
result = formatResponse.channel(result);
|
||||
|
||||
// Context
|
||||
setResponseContext(req, res);
|
||||
debug('Rendering view: ' + view);
|
||||
res.render(view, result);
|
||||
|
||||
// Template
|
||||
res.template = templates.channel(res.locals.channel);
|
||||
|
||||
// Render Call
|
||||
debug('Rendering view: ' + res.template);
|
||||
res.render(res.template, result);
|
||||
};
|
||||
};
|
||||
|
|
|
@ -12,11 +12,18 @@ var debug = require('ghost-ignition').debug('channels:render-post'),
|
|||
module.exports = function renderPost(req, res) {
|
||||
debug('renderPost called');
|
||||
return function renderPost(post) {
|
||||
var view = templates.single(post),
|
||||
response = formatResponse.single(post);
|
||||
// Renderer begin
|
||||
// Format data 2 - 1 is in preview/single
|
||||
var response = formatResponse.single(post);
|
||||
|
||||
// Context
|
||||
setResponseContext(req, res, response);
|
||||
debug('Rendering view: ' + view);
|
||||
res.render(view, response);
|
||||
|
||||
// Template
|
||||
res.template = templates.single(post);
|
||||
|
||||
// Render Call
|
||||
debug('Rendering view: ' + res.template);
|
||||
res.render(res.template, response);
|
||||
};
|
||||
};
|
||||
|
|
|
@ -5,6 +5,8 @@ var api = require('../api'),
|
|||
renderPost = require('./frontend/render-post'),
|
||||
setRequestIsSecure = require('./frontend/secure');
|
||||
|
||||
// This here is a controller.
|
||||
// The "route" is handled in site/routes.js
|
||||
module.exports = function previewController(req, res, next) {
|
||||
var params = {
|
||||
uuid: req.params.uuid,
|
||||
|
@ -13,6 +15,7 @@ module.exports = function previewController(req, res, next) {
|
|||
};
|
||||
|
||||
api.posts.read(params).then(function then(result) {
|
||||
// Format data 1
|
||||
var post = result.posts[0];
|
||||
|
||||
if (!post) {
|
||||
|
|
|
@ -46,6 +46,9 @@ function getData(channelOpts) {
|
|||
});
|
||||
}
|
||||
|
||||
// This here is a controller.
|
||||
// The "route" is handled in controllers/channels/router.js
|
||||
// We can only generate RSS for channels, so that sorta makes sense, but the location is rubbish
|
||||
// @TODO finish refactoring this - it's now a controller
|
||||
generate = function generate(req, res, next) {
|
||||
// Parse the parameters we need from the URL
|
||||
|
@ -67,11 +70,17 @@ generate = function generate(req, res, next) {
|
|||
return next(new errors.NotFoundError({message: i18n.t('errors.errors.pageNotFound')}));
|
||||
}
|
||||
|
||||
// Renderer begin
|
||||
// Format data
|
||||
data.version = res.locals.safeVersion;
|
||||
data.siteUrl = utils.url.urlFor('home', {secure: req.secure}, true);
|
||||
data.feedUrl = utils.url.urlFor({relativeUrl: baseUrl, secure: req.secure}, true);
|
||||
data.secure = req.secure;
|
||||
|
||||
// No context, no template
|
||||
// @TODO: should we have context? The context file expects it!
|
||||
|
||||
// Render call - to a different renderer
|
||||
// @TODO this is effectively a renderer
|
||||
return rssCache.getXML(baseUrl, data).then(function then(feedXml) {
|
||||
res.set('Content-Type', 'text/xml; charset=UTF-8');
|
||||
|
|
|
@ -5,9 +5,12 @@ var utils = require('../utils'),
|
|||
renderPost = require('./frontend/render-post'),
|
||||
setRequestIsSecure = require('./frontend/secure');
|
||||
|
||||
// This here is a controller.
|
||||
// The "route" is handled in site/routes.js
|
||||
module.exports = function singleController(req, res, next) {
|
||||
// Query database to find post
|
||||
return postLookup(req.path).then(function then(lookup) {
|
||||
// Format data 1
|
||||
var post = lookup ? lookup.post : false;
|
||||
|
||||
if (!post) {
|
||||
|
|
|
@ -71,6 +71,7 @@ _private.JSONErrorRenderer = function JSONErrorRenderer(err, req, res, next) { /
|
|||
});
|
||||
};
|
||||
|
||||
// @TODO: differenciate properly between rendering errors for theme templates, and other situations
|
||||
_private.HTMLErrorRenderer = function HTMLErrorRender(err, req, res, next) {
|
||||
// If the error code is explicitly set to STATIC_FILE_NOT_FOUND,
|
||||
// Skip trying to render an HTML error, and move on to the basic error renderer
|
||||
|
@ -80,25 +81,34 @@ _private.HTMLErrorRenderer = function HTMLErrorRender(err, req, res, next) {
|
|||
return next(err);
|
||||
}
|
||||
|
||||
// Renderer begin
|
||||
// Format Data
|
||||
var templateData = {
|
||||
message: err.message,
|
||||
// @deprecated
|
||||
code: err.statusCode,
|
||||
statusCode: err.statusCode,
|
||||
errorDetails: err.errorDetails || []
|
||||
},
|
||||
template = templates.error(err.statusCode);
|
||||
message: err.message,
|
||||
// @deprecated
|
||||
code: err.statusCode,
|
||||
statusCode: err.statusCode,
|
||||
errorDetails: err.errorDetails || []
|
||||
};
|
||||
|
||||
// Context
|
||||
// We don't do context for errors?!
|
||||
|
||||
// Template
|
||||
res.template = templates.error(err.statusCode);
|
||||
|
||||
// It can be that something went wrong with the theme or otherwise loading handlebars
|
||||
// This ensures that no matter what res.render will work here
|
||||
// @TODO: split the error handler for assets, admin & theme to refactor this away
|
||||
if (_.isEmpty(req.app.engines)) {
|
||||
template = 'error';
|
||||
res.template = 'error';
|
||||
req.app.engine('hbs', _private.createHbsEngine());
|
||||
req.app.set('view engine', 'hbs');
|
||||
req.app.set('views', config.get('paths').defaultViews);
|
||||
}
|
||||
|
||||
res.render(template, templateData, function renderResponse(err, html) {
|
||||
// Render Call - featuring an error handler for what happens if rendering fails
|
||||
res.render(res.template, templateData, function renderResponse(err, html) {
|
||||
if (!err) {
|
||||
return res.send(html);
|
||||
}
|
||||
|
|
|
@ -9,22 +9,23 @@ module.exports = function siteRouter() {
|
|||
var router = express.Router(),
|
||||
routeKeywords = config.get('routeKeywords');
|
||||
|
||||
// ### Admin routes
|
||||
// Admin redirects - register redirect as route
|
||||
// TODO: this should be middleware!
|
||||
router.get(/^\/(logout|signout)\/$/, function (req, res) { return utils.url.redirectToAdmin(301, res, '#/signout/'); });
|
||||
router.get(/^\/signup\/$/, function (req, res) { return utils.url.redirectToAdmin(301, res, '#/signup/'); });
|
||||
// redirect to /ghost and let that do the authentication to prevent redirects to /ghost//admin etc.
|
||||
router.get(/^\/((ghost-admin|admin|wp-admin|dashboard|signin|login)\/?)$/, function (req, res) { return utils.url.redirectToAdmin(301, res, '/'); });
|
||||
|
||||
// Post Live Preview
|
||||
// Preview - register controller as route
|
||||
router.get(utils.url.urlJoin('/', routeKeywords.preview, ':uuid', ':options?'), controllers.preview);
|
||||
|
||||
// Channels
|
||||
// Channels - register sub-router
|
||||
router.use(channels.router());
|
||||
|
||||
// setup routes for apps
|
||||
// Apps - register sub-router
|
||||
router.use(apps.router);
|
||||
|
||||
// Default
|
||||
// Default - register single controller as route
|
||||
router.get('*', controllers.single);
|
||||
|
||||
return router;
|
||||
|
|
|
@ -75,7 +75,7 @@ describe('AMP Controller', function () {
|
|||
done();
|
||||
};
|
||||
|
||||
ampController.controller(req, res, failTest(done));
|
||||
ampController.renderer(req, res, failTest(done));
|
||||
});
|
||||
|
||||
it('should render theme amp page when theme has amp template', function (done) {
|
||||
|
@ -87,13 +87,13 @@ describe('AMP Controller', function () {
|
|||
done();
|
||||
};
|
||||
|
||||
ampController.controller(req, res, failTest(done));
|
||||
ampController.renderer(req, res, failTest(done));
|
||||
});
|
||||
|
||||
it('throws 404 when req.body has no post', function (done) {
|
||||
req.body = {};
|
||||
|
||||
ampController.controller(req, res, function (err) {
|
||||
ampController.renderer(req, res, function (err) {
|
||||
should.exist(err);
|
||||
should.exist(err.message);
|
||||
should.exist(err.statusCode);
|
||||
|
@ -112,7 +112,7 @@ describe('AMP Controller', function () {
|
|||
}
|
||||
};
|
||||
|
||||
ampController.controller(req, res, function (err) {
|
||||
ampController.renderer(req, res, function (err) {
|
||||
should.exist(err);
|
||||
should.exist(err.message);
|
||||
should.exist(err.statusCode);
|
||||
|
|
|
@ -4,7 +4,7 @@ var should = require('should'),
|
|||
path = require('path'),
|
||||
configUtils = require('../../../utils/configUtils'),
|
||||
themes = require('../../../../server/themes'),
|
||||
privateController = require('../../../../server/apps/private-blogging/lib/router').controller,
|
||||
privateController = require('../../../../server/apps/private-blogging/lib/router'),
|
||||
|
||||
sandbox = sinon.sandbox.create();
|
||||
|
||||
|
@ -60,7 +60,7 @@ describe('Private Controller', function () {
|
|||
done();
|
||||
};
|
||||
|
||||
privateController(req, res, failTest(done));
|
||||
privateController.renderer(req, res, failTest(done));
|
||||
});
|
||||
|
||||
it('Should render theme password page when it exists', function (done) {
|
||||
|
@ -72,7 +72,7 @@ describe('Private Controller', function () {
|
|||
done();
|
||||
};
|
||||
|
||||
privateController(req, res, failTest(done));
|
||||
privateController.renderer(req, res, failTest(done));
|
||||
});
|
||||
|
||||
it('Should render with error when error is passed in', function (done) {
|
||||
|
@ -84,6 +84,6 @@ describe('Private Controller', function () {
|
|||
done();
|
||||
};
|
||||
|
||||
privateController(req, res, failTest(done));
|
||||
privateController.renderer(req, res, failTest(done));
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue