0
Fork 0
mirror of https://github.com/TryGhost/Ghost.git synced 2025-02-17 23:44:39 -05:00

Merge pull request #166 from ErisDS/settings-cache

Settings cache & clean up "ghostGlobals"
This commit is contained in:
Hannah Wolfe 2013-06-17 15:33:18 -07:00
commit d0eace2d36
5 changed files with 86 additions and 56 deletions

48
app.js
View file

@ -18,20 +18,19 @@
filters = require('./core/frontend/filters'), filters = require('./core/frontend/filters'),
helpers = require('./core/frontend/helpers'), helpers = require('./core/frontend/helpers'),
// ## Variables // ## Custom Middleware
auth, auth,
authAPI, authAPI,
ghostLocals, ghostLocals,
// ## Variables
loading = when.defer(), loading = when.defer(),
/** /**
* Create new Ghost object * Create new Ghost object
* @type {Ghost} * @type {Ghost}
*/ */
ghost = new Ghost(), ghost = new Ghost();
// This is assigned after the call to ghost.init() below
ghostGlobals;
ghost.app().configure('development', function () { ghost.app().configure('development', function () {
@ -44,8 +43,6 @@
ghost.app().use(express.cookieSession({ cookie: { maxAge: 60000000 }})); ghost.app().use(express.cookieSession({ cookie: { maxAge: 60000000 }}));
ghost.app().use(ghost.initTheme(ghost.app())); ghost.app().use(ghost.initTheme(ghost.app()));
ghost.app().use(flash()); ghost.app().use(flash());
// bind locals - options which appear in every view - perhaps this should be admin only
}); });
/** /**
@ -75,18 +72,19 @@
/** /**
* Expose the standard locals that every external page should have available; * Expose the standard locals that every external page should have available;
* path, navItems and ghostGlobals * path, navItems and settingsCache
*/ */
ghostLocals = function (req, res, next) { ghostLocals = function (req, res, next) {
ghost.doFilter('ghostNavItems', {path: req.path, navItems: []}, function (navData) { ghost.doFilter('ghostNavItems', {path: req.path, navItems: []}, function (navData) {
// Make sure we have a locals value. // Make sure we have a locals value.
res.locals = res.locals || {}; res.locals = res.locals || {};
// Extend it with nav data and settings
// Extend it with nav data and ghostGlobals
_.extend(res.locals, navData, { _.extend(res.locals, navData, {
ghostGlobals: ghost.globals() messages: req.flash(),
settings: ghost.settings(),
availableThemes: ghost.paths().availableThemes,
availablePlugins: ghost.paths().availablePlugins
}); });
next(); next();
@ -97,21 +95,9 @@
ghost.loaded = loading.promise; ghost.loaded = loading.promise;
when.all([ghost.init(), filters.loadCoreFilters(ghost), helpers.loadCoreHelpers(ghost)]).then(function () { when.all([ghost.init(), filters.loadCoreFilters(ghost), helpers.loadCoreHelpers(ghost)]).then(function () {
// Assign the globals we have loaded
ghostGlobals = ghost.globals();
ghost.app().use(function (req, res, next) { // post init config
res.locals.messages = req.flash(); ghost.app().use(ghostLocals);
res.locals.siteTitle = ghostGlobals.title;
res.locals.siteDescription = ghostGlobals.description;
res.locals.siteUrl = ghostGlobals.url;
res.locals.activeTheme = ghostGlobals.activeTheme;
res.locals.activePlugin = ghostGlobals.activePlugin;
res.locals.availableThemes = ghost.paths().availableThemes;
res.locals.availablePlugins = ghost.paths().availablePlugins;
next();
});
/** /**
* API routes.. * API routes..
@ -122,9 +108,9 @@
ghost.app().get('/api/v0.1/posts/:id', authAPI, api.requestHandler(api.posts.read)); ghost.app().get('/api/v0.1/posts/:id', authAPI, api.requestHandler(api.posts.read));
ghost.app().put('/api/v0.1/posts/:id', authAPI, api.requestHandler(api.posts.edit)); ghost.app().put('/api/v0.1/posts/:id', authAPI, api.requestHandler(api.posts.edit));
ghost.app().del('/api/v0.1/posts/:id', authAPI, api.requestHandler(api.posts.destroy)); ghost.app().del('/api/v0.1/posts/:id', authAPI, api.requestHandler(api.posts.destroy));
ghost.app().get('/api/v0.1/settings', authAPI, api.requestHandler(api.settings.browse)); ghost.app().get('/api/v0.1/settings', authAPI, api.cachedSettingsRequestHandler(api.settings.browse));
ghost.app().get('/api/v0.1/settings/:key', authAPI, api.requestHandler(api.settings.read)); ghost.app().get('/api/v0.1/settings/:key', authAPI, api.cachedSettingsRequestHandler(api.settings.read));
ghost.app().put('/api/v0.1/settings', authAPI, api.requestHandler(api.settings.edit)); ghost.app().put('/api/v0.1/settings', authAPI, api.cachedSettingsRequestHandler(api.settings.edit));
/** /**
* Admin routes.. * Admin routes..
@ -151,8 +137,8 @@
* Frontend routes.. * Frontend routes..
* @todo dynamic routing, homepage generator, filters ETC ETC * @todo dynamic routing, homepage generator, filters ETC ETC
*/ */
ghost.app().get('/:slug', ghostLocals, frontend.single); ghost.app().get('/:slug', frontend.single);
ghost.app().get('/', ghostLocals, frontend.homepage); ghost.app().get('/', frontend.homepage);
ghost.app().listen(3333, function () { ghost.app().listen(3333, function () {
console.log("Express server listening on port " + 3333); console.log("Express server listening on port " + 3333);

View file

@ -16,14 +16,14 @@
'homepage': function (req, res) { 'homepage': function (req, res) {
api.posts.browse().then(function (page) { api.posts.browse().then(function (page) {
ghost.doFilter('prePostsRender', page.posts, function (posts) { ghost.doFilter('prePostsRender', page.posts, function (posts) {
res.render('index', {posts: posts, ghostGlobals: res.locals.ghostGlobals, navItems: res.locals.navItems}); res.render('index', {posts: posts});
}); });
}); });
}, },
'single': function (req, res) { 'single': function (req, res) {
api.posts.read({'slug': req.params.slug}).then(function (post) { api.posts.read({'slug': req.params.slug}).then(function (post) {
ghost.doFilter('prePostsRender', post.toJSON(), function (post) { ghost.doFilter('prePostsRender', post.toJSON(), function (post) {
res.render('single', {post: post, ghostGlobals: res.locals.ghostGlobals, navItems: res.locals.navItems}); res.render('single', {post: post});
}); });
}); });
} }

View file

@ -87,14 +87,12 @@
// load Plugins... // load Plugins...
// var f = new FancyFirstChar(ghost).init(); // var f = new FancyFirstChar(ghost).init();
_.extend(instance, { _.extend(instance, {
app: function () { return app; }, app: function () { return app; },
config: function () { return config; }, config: function () { return config; },
// there's no management here to be sure this has loaded // there's no management here to be sure this has loaded
globals: function () { return instance.globalConfig; }, settings: function () { return instance.settingsCache; },
dataProvider: models, dataProvider: models,
statuses: function () { return statuses; }, statuses: function () { return statuses; },
polyglot: function () { return polyglot; }, polyglot: function () { return polyglot; },
@ -125,6 +123,19 @@
var self = this; var self = this;
return when.join(instance.dataProvider.init(), instance.getPaths()).then(function () { return when.join(instance.dataProvider.init(), instance.getPaths()).then(function () {
return self.updateSettingsCache();
}, errors.logAndThrowError);
};
Ghost.prototype.updateSettingsCache = function (settings) {
var self = this;
settings = settings || {};
if (!_.isEmpty(settings)) {
self.settingsCache = settings;
} else {
// TODO: this should use api.browse // TODO: this should use api.browse
return models.Settings.findAll().then(function (result) { return models.Settings.findAll().then(function (result) {
var settings = {}; var settings = {};
@ -134,9 +145,9 @@
} }
}); });
self.globalConfig = settings; self.settingsCache = settings;
}, errors.logAndThrowError);
}, errors.logAndThrowError); }, errors.logAndThrowError);
}
}; };
/** /**

View file

@ -11,6 +11,8 @@
var Ghost = require('../ghost'), var Ghost = require('../ghost'),
_ = require('underscore'), _ = require('underscore'),
when = require('when'),
errors = require('./errorHandling'),
ghost = new Ghost(), ghost = new Ghost(),
dataProvider = ghost.dataProvider, dataProvider = ghost.dataProvider,
@ -18,6 +20,7 @@
users, users,
settings, settings,
requestHandler, requestHandler,
cachedSettingsRequestHandler,
settingsObject, settingsObject,
settingsCollection; settingsCollection;
@ -25,37 +28,37 @@
posts = { posts = {
// takes filter / pagination parameters // takes filter / pagination parameters
// returns a page of posts in a json response // returns a page of posts in a json response
browse: function (options) { browse: function browse(options) {
return dataProvider.Post.findPage(options); return dataProvider.Post.findPage(options);
}, },
// takes an identifier (id or slug?) // takes an identifier (id or slug?)
// returns a single post in a json response // returns a single post in a json response
read: function (args) { read: function read(args) {
return dataProvider.Post.findOne(args); return dataProvider.Post.findOne(args);
}, },
// takes a json object with all the properties which should be updated // takes a json object with all the properties which should be updated
// returns the resulting post in a json response // returns the resulting post in a json response
edit: function (postData) { edit: function edit(postData) {
return dataProvider.Post.edit(postData); return dataProvider.Post.edit(postData);
}, },
// takes a json object representing a post, // takes a json object representing a post,
// returns the resulting post in a json response // returns the resulting post in a json response
add: function (postData) { add: function add(postData) {
return dataProvider.Post.add(postData); return dataProvider.Post.add(postData);
}, },
// takes an identifier (id or slug?) // takes an identifier (id or slug?)
// returns a json response with the id of the deleted post // returns a json response with the id of the deleted post
destroy: function (args) { destroy: function destroy(args) {
return dataProvider.Post.destroy(args.id); return dataProvider.Post.destroy(args.id);
} }
}; };
// # Users // # Users
users = { users = {
add: function (postData) { add: function add(postData) {
return dataProvider.User.add(postData); return dataProvider.User.add(postData);
}, },
check: function (postData) { check: function check(postData) {
return dataProvider.User.check(postData); return dataProvider.User.check(postData);
} }
}; };
@ -78,21 +81,17 @@
}; };
settings = { settings = {
browse: function (options) { browse: function browse(options) {
return dataProvider.Settings.browse(options).then(settingsObject); return dataProvider.Settings.browse(options).then(settingsObject);
}, },
read: function (options) { read: function read(options) {
return dataProvider.Settings.read(options.key).then(function (setting) { return dataProvider.Settings.read(options.key).then(function (setting) {
return _.pick(setting.toJSON(), 'key', 'value'); return _.pick(setting.toJSON(), 'key', 'value');
}); });
}, },
edit: function (settings) { edit: function edit(settings) {
settings = settingsCollection(settings); settings = settingsCollection(settings);
return dataProvider.Settings.edit(settings).then(settingsObject); return dataProvider.Settings.edit(settings).then(settingsObject);
},
add: function (settings) {
settings = settingsCollection(settings);
return dataProvider.Settings.add(settings).then(settingsObject);
} }
}; };
@ -114,8 +113,42 @@
}; };
}; };
cachedSettingsRequestHandler = function (apiMethod) {
if (!ghost.settings()) {
return requestHandler(apiMethod);
}
return function (req, res) {
var options = _.extend(req.body, req.query, req.params),
promise;
switch (apiMethod.name) {
case 'browse':
promise = when(ghost.settings());
break;
case 'read':
promise = when(ghost.settings()[options.key]);
break;
case 'edit':
promise = apiMethod(options).then(function (result) {
ghost.updateSettingsCache(result);
return result;
});
break;
default:
errors.logAndThrowError(new Error('Unknown method name for settings API: ' + apiMethod.name));
}
return promise.then(function (result) {
res.json(result || {});
}, function (error) {
res.json(400, {error: error});
});
};
};
module.exports.posts = posts; module.exports.posts = posts;
module.exports.users = users; module.exports.users = users;
module.exports.settings = settings; module.exports.settings = settings;
module.exports.requestHandler = requestHandler; module.exports.requestHandler = requestHandler;
module.exports.cachedSettingsRequestHandler = cachedSettingsRequestHandler;
}()); }());

View file

@ -27,19 +27,19 @@
} }
}, },
dataProviderInitSpy = sinon.spy(fakeDataProvider, "init"), dataProviderInitSpy = sinon.spy(fakeDataProvider, "init"),
oldDataProvder = ghost.dataProvider; oldDataProvider = ghost.dataProvider;
ghost.dataProvider = fakeDataProvider; ghost.dataProvider = fakeDataProvider;
should.not.exist(ghost.globals()); should.not.exist(ghost.settings());
ghost.init().then(function () { ghost.init().then(function () {
should.exist(ghost.globals()); should.exist(ghost.settings());
dataProviderInitSpy.called.should.equal(true); dataProviderInitSpy.called.should.equal(true);
ghost.dataProvider = oldDataProvder; ghost.dataProvider = oldDataProvider;
done(); done();
}).then(null, done); }).then(null, done);