Ghost/core/server/middleware/theme-handler.js
Hannah Wolfe 3e727d01f7 Refresh assetHash on theme activation (#7464)
closes #7423

- asset hashes have never been refreshed properly!
- Ghost(Pro)'s 1-theme-only limitation has been hiding this bug for 3 years 🙄
2016-09-30 13:13:16 +02:00

132 lines
5.1 KiB
JavaScript

var _ = require('lodash'),
fs = require('fs'),
path = require('path'),
hbs = require('express-hbs'),
api = require('../api'),
config = require('../config'),
errors = require('../errors'),
i18n = require('../i18n'),
themeHandler;
themeHandler = {
// ### GhostLocals Middleware
// Expose the standard locals that every external page should have available,
// separating between the theme and the admin
ghostLocals: function ghostLocals(req, res, next) {
// Make sure we have a locals value.
res.locals = res.locals || {};
res.locals.version = config.get('ghostVersion');
res.locals.safeVersion = config.get('ghostVersion').match(/^(\d+\.)?(\d+)/)[0];
// relative path from the URL
res.locals.relativeUrl = req.path;
next();
},
// ### configHbsForContext Middleware
// Setup handlebars for the current context (admin or theme)
configHbsForContext: function configHbsForContext(req, res, next) {
var themeData = _.cloneDeep(config.get('theme')),
labsData = _.cloneDeep(config.get('labs')),
blogApp = req.app;
if (req.secure && config.get('urlSSL')) {
// For secure requests override .url property with the SSL version
themeData.url = config.get('urlSSL').replace(/\/$/, '');
}
// Change camelCase to snake_case
themeData.posts_per_page = themeData.postsPerPage;
delete themeData.postsPerPage;
hbs.updateTemplateOptions({data: {blog: themeData, labs: labsData}});
if (config.getContentPath('themes') && blogApp.get('activeTheme')) {
blogApp.set('views', path.join(config.getContentPath('themes'), blogApp.get('activeTheme')));
}
// Pass 'secure' flag to the view engine
// so that templates can choose 'url' vs 'urlSSL'
res.locals.secure = req.secure;
next();
},
// ### Activate Theme
// Helper for updateActiveTheme
activateTheme: function activateTheme(blogApp, activeTheme) {
var hbsOptions,
themePartials = path.join(config.getContentPath('themes'), activeTheme, 'partials');
// clear the view cache
blogApp.cache = {};
// reset the asset hash
config.assetHash = null;
// set view engine
hbsOptions = {
partialsDir: [config.get('paths').helperTemplates],
onCompile: function onCompile(exhbs, source) {
return exhbs.handlebars.compile(source, {preventIndent: true});
}
};
fs.stat(themePartials, function stat(err, stats) {
// Check that the theme has a partials directory before trying to use it
if (!err && stats && stats.isDirectory()) {
hbsOptions.partialsDir.push(themePartials);
}
});
blogApp.engine('hbs', hbs.express3(hbsOptions));
// Update user error template
errors.updateActiveTheme(activeTheme);
// Set active theme variable on the express server
blogApp.set('activeTheme', activeTheme);
},
// ### updateActiveTheme
// Updates the blogApp's activeTheme variable and subsequently
// activates that theme's views with the hbs templating engine if it
// is not yet activated.
updateActiveTheme: function updateActiveTheme(req, res, next) {
var blogApp = req.app;
api.settings.read({context: {internal: true}, key: 'activeTheme'}).then(function then(response) {
var activeTheme = response.settings[0];
// Check if the theme changed
if (activeTheme.value !== blogApp.get('activeTheme')) {
// Change theme
if (!config.get('paths').availableThemes.hasOwnProperty(activeTheme.value)) {
if (!res.isAdmin) {
// Throw an error if the theme is not available, but not on the admin UI
return errors.throwError(i18n.t('errors.middleware.themehandler.missingTheme', {theme: activeTheme.value}));
} else {
// At this point the activated theme is not present and the current
// request is for the admin client. In order to allow the user access
// to the admin client we set an hbs instance on the app so that middleware
// processing can continue.
blogApp.engine('hbs', hbs.express3());
errors.logWarn(i18n.t('errors.middleware.themehandler.missingTheme', {theme: activeTheme.value}));
return next();
}
} else {
themeHandler.activateTheme(blogApp, activeTheme.value);
}
}
next();
}).catch(function handleError(err) {
// Trying to start up without the active theme present, setup a simple hbs instance
// and render an error page straight away.
blogApp.engine('hbs', hbs.express3());
next(err);
});
}
};
module.exports = themeHandler;