Ghost/core/server/themes/index.js
Hannah Wolfe b06f03b370 New fully-loaded & validated activeTheme concept (#8146)
📡 Add debug for the 3 theme activation methods
There are 3 different ways that a theme can be activated in Ghost:

A. On boot: we load the active theme from the file system, according to the `activeTheme` setting
B. On API "activate": when an /activate/ request is triggered for a theme, we validate & change the `activeTheme` setting
C. On API "override": if uploading a theme with the same name, we override. Using a dirty hack to make this work.

A: setting is done, should load & validate + next request does mounting
B: load is done, should validate & change setting + next request does mounting
C: load, validate & setting are all done + a hack is needed to ensure the next request does mounting

 Validate w/ gscan when theme activating on boot
- use the new gscan validation validate.check() method when activating on boot

 New concept of active theme
- add ActiveTheme class
- make it possible to set a theme to be active, and to get the active theme
- call the new themes.activate() method in all 3 cases where we activate a theme

🎨 Use new activeTheme to simplify theme code
- make use of the new concept where we can, to reduce & simplify code
- use new hasPartials() method so we don't have to do file lookups
- use path & name getters to reduce use of getContentPath etc
- remove requirement on req.app.get('activeTheme') from static-theme middleware (more on this soon)

🚨 Improve theme unit tests (TODO: fix inter-dep)
- The theme unit tests are borked! They all pass because they don't test the right things.
- This improves them, but they are still dependent on each-other
- configHbsForContext tests don't pass if the activateTheme tests aren't run first
- I will fix this in a later PR
2017-03-13 21:13:17 +01:00

68 lines
2.8 KiB
JavaScript

var debug = require('debug')('ghost:themes'),
_ = require('lodash'),
events = require('../events'),
errors = require('../errors'),
logging = require('../logging'),
i18n = require('../i18n'),
themeLoader = require('./loader'),
active = require('./active'),
validate = require('./validate'),
settingsCache = require('../settings/cache');
// @TODO: reduce the amount of things we expose to the outside world
// Make this a nice clean sensible API we can all understand!
module.exports = {
// Init themes module
// TODO: move this once we're clear what needs to happen here
init: function initThemes() {
var activeThemeName = settingsCache.get('activeTheme'),
self = this;
debug('init themes', activeThemeName);
// Register a listener for server-start to load all themes
events.on('server:start', function readAllThemesOnServerStart() {
themeLoader.loadAllThemes();
});
// Just read the active theme for now
return themeLoader
.loadOneTheme(activeThemeName)
.then(function activeThemeHasLoaded(theme) {
// Validate
return validate
.check(theme)
.then(function resultHandler(checkedTheme) {
// Activate! (sort of)
debug('Activating theme (method A on boot)', activeThemeName);
self.activate(theme, checkedTheme);
})
.catch(function () {
// Active theme is not valid, we don't want to exit because the admin panel will still work
logging.warn(i18n.t('errors.middleware.themehandler.invalidTheme', {theme: activeThemeName}));
});
})
.catch(function () {
// Active theme is missing, we don't want to exit because the admin panel will still work
logging.warn(i18n.t('errors.middleware.themehandler.missingTheme', {theme: activeThemeName}));
});
},
// Load themes, soon to be removed and exposed via specific function.
loadAll: themeLoader.loadAllThemes,
loadOne: themeLoader.loadOneTheme,
list: require('./list'),
validate: validate,
toJSON: require('./to-json'),
getActive: active.get,
activate: function activate(loadedTheme, checkedTheme) {
if (!_.has(checkedTheme, 'results.score.level') || checkedTheme.results.score.level !== 'passing') {
throw new errors.InternalServerError({
message: i18n.t('errors.middleware.themehandler.invalidTheme', {theme: loadedTheme.name})
});
}
// Use the two theme objects to set the current active theme
active.set(loadedTheme, checkedTheme);
}
};