2019-04-03 13:40:35 +03:00
|
|
|
const _ = require('lodash');
|
|
|
|
const hbs = require('./engine');
|
2019-06-19 12:30:28 +03:00
|
|
|
const urlUtils = require('../../../server/lib/url-utils');
|
2020-05-27 20:47:53 +03:00
|
|
|
const config = require('../../../shared/config');
|
2020-05-22 21:22:20 +03:00
|
|
|
const {i18n} = require('../../../server/lib/common');
|
|
|
|
const errors = require('@tryghost/errors');
|
2019-06-19 12:30:28 +03:00
|
|
|
const settingsCache = require('../../../server/services/settings/cache');
|
2019-11-06 10:42:39 +03:00
|
|
|
const labs = require('../../../server/services/labs');
|
2019-04-03 13:40:35 +03:00
|
|
|
const activeTheme = require('./active');
|
2017-03-21 12:03:09 +03:00
|
|
|
|
|
|
|
// ### Ensure Active Theme
|
2019-09-10 12:37:04 +03:00
|
|
|
// Ensure there's a properly set & mounted active theme before attempting to serve a site request
|
2017-03-21 12:03:09 +03:00
|
|
|
// If there is no active theme, throw an error
|
|
|
|
// Else, ensure the active theme is mounted
|
2019-04-03 13:40:35 +03:00
|
|
|
function ensureActiveTheme(req, res, next) {
|
2017-05-31 19:42:42 +03:00
|
|
|
// CASE: this means that the theme hasn't been loaded yet i.e. there is no active theme
|
2017-03-21 12:03:09 +03:00
|
|
|
if (!activeTheme.get()) {
|
|
|
|
// This is the one place we ACTUALLY throw an error for a missing theme as it's a request we cannot serve
|
2020-05-22 21:22:20 +03:00
|
|
|
return next(new errors.InternalServerError({
|
2017-03-21 12:03:09 +03:00
|
|
|
// We use the settingsCache here, because the setting will be set,
|
|
|
|
// even if the theme itself is not usable because it is invalid or missing.
|
2020-05-22 21:22:20 +03:00
|
|
|
message: i18n.t('errors.middleware.themehandler.missingTheme', {theme: settingsCache.get('active_theme')})
|
2017-03-21 12:03:09 +03:00
|
|
|
}));
|
|
|
|
}
|
|
|
|
|
2019-09-10 12:37:04 +03:00
|
|
|
// CASE: bootstrap theme validation failed, we would like to show the errors on the site [only production]
|
2017-05-31 19:42:42 +03:00
|
|
|
if (activeTheme.get().error && config.get('env') === 'production') {
|
2020-05-22 21:22:20 +03:00
|
|
|
return next(new errors.InternalServerError({
|
2017-05-31 19:42:42 +03:00
|
|
|
// We use the settingsCache here, because the setting will be set,
|
|
|
|
// even if the theme itself is not usable because it is invalid or missing.
|
2020-05-22 21:22:20 +03:00
|
|
|
message: i18n.t('errors.middleware.themehandler.invalidTheme', {theme: settingsCache.get('active_theme')}),
|
2017-05-31 19:42:42 +03:00
|
|
|
errorDetails: activeTheme.get().error.errorDetails
|
|
|
|
}));
|
|
|
|
}
|
|
|
|
|
2017-03-21 12:03:09 +03:00
|
|
|
// If the active theme has not yet been mounted, mount it into express
|
|
|
|
if (!activeTheme.get().mounted) {
|
|
|
|
activeTheme.get().mount(req.app);
|
|
|
|
}
|
|
|
|
|
|
|
|
next();
|
2019-04-03 13:40:35 +03:00
|
|
|
}
|
2017-03-21 12:03:09 +03:00
|
|
|
|
2019-10-21 13:50:54 +03:00
|
|
|
/*
|
|
|
|
* @TODO
|
|
|
|
* This should be definitely refactored and we need to consider _some_
|
|
|
|
* members settings as publicly readable
|
|
|
|
*/
|
|
|
|
function haxGetMembersPriceData() {
|
2020-03-04 08:15:21 +03:00
|
|
|
const CURRENCY_SYMBOLS = {
|
|
|
|
USD: '$',
|
|
|
|
AUD: '$',
|
|
|
|
CAD: '$',
|
|
|
|
GBP: '£',
|
|
|
|
EUR: '€'
|
|
|
|
};
|
|
|
|
const defaultPriceData = {
|
|
|
|
monthly: 0,
|
|
|
|
yearly: 0
|
|
|
|
};
|
|
|
|
|
2019-10-21 13:50:54 +03:00
|
|
|
try {
|
|
|
|
const membersSettings = settingsCache.get('members_subscription_settings');
|
|
|
|
const stripeProcessor = membersSettings.paymentProcessors.find(
|
|
|
|
processor => processor.adapter === 'stripe'
|
|
|
|
);
|
|
|
|
|
|
|
|
const priceData = stripeProcessor.config.plans.reduce((prices, plan) => {
|
|
|
|
const numberAmount = 0 + plan.amount;
|
|
|
|
const dollarAmount = numberAmount ? Math.round(numberAmount / 100) : 0;
|
|
|
|
return Object.assign(prices, {
|
|
|
|
[plan.name.toLowerCase()]: dollarAmount
|
|
|
|
});
|
|
|
|
}, {});
|
|
|
|
|
2020-03-04 08:15:21 +03:00
|
|
|
priceData.currency = String.prototype.toUpperCase.call(stripeProcessor.config.currency || 'usd');
|
|
|
|
priceData.currency_symbol = CURRENCY_SYMBOLS[priceData.currency];
|
|
|
|
|
2019-10-21 13:50:54 +03:00
|
|
|
if (Number.isInteger(priceData.monthly) && Number.isInteger(priceData.yearly)) {
|
|
|
|
return priceData;
|
|
|
|
}
|
|
|
|
|
|
|
|
return defaultPriceData;
|
|
|
|
} catch (err) {
|
|
|
|
return defaultPriceData;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-03 14:01:23 +03:00
|
|
|
function updateGlobalTemplateOptions(req, res, next) {
|
2017-03-21 12:03:09 +03:00
|
|
|
// Static information, same for every request unless the settings change
|
|
|
|
// @TODO: bind this once and then update based on events?
|
2019-01-15 15:03:17 +03:00
|
|
|
// @TODO: decouple theme layer from settings cache using the Content API
|
2019-04-03 13:40:35 +03:00
|
|
|
const siteData = settingsCache.getPublic();
|
2019-11-06 10:42:39 +03:00
|
|
|
const labsData = labs.getAll();
|
|
|
|
|
2019-04-03 14:01:23 +03:00
|
|
|
const themeData = {
|
|
|
|
posts_per_page: activeTheme.get().config('posts_per_page'),
|
|
|
|
image_sizes: activeTheme.get().config('image_sizes')
|
|
|
|
};
|
2019-10-21 13:50:54 +03:00
|
|
|
const priceData = haxGetMembersPriceData();
|
2017-03-21 12:03:09 +03:00
|
|
|
|
|
|
|
// @TODO: only do this if something changed?
|
2019-09-10 12:37:04 +03:00
|
|
|
// @TODO: remove blog if we drop v2 (Ghost 4.0)
|
2017-03-21 12:03:09 +03:00
|
|
|
hbs.updateTemplateOptions({
|
|
|
|
data: {
|
2019-01-03 20:52:37 +03:00
|
|
|
blog: siteData,
|
|
|
|
site: siteData,
|
2017-03-21 12:03:09 +03:00
|
|
|
labs: labsData,
|
2019-10-21 13:50:54 +03:00
|
|
|
config: themeData,
|
|
|
|
price: priceData
|
2017-03-21 12:03:09 +03:00
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
next();
|
2019-04-03 13:40:35 +03:00
|
|
|
}
|
2017-03-21 12:03:09 +03:00
|
|
|
|
2019-04-03 14:01:23 +03:00
|
|
|
function updateLocalTemplateData(req, res, next) {
|
|
|
|
// Pass 'secure' flag to the view engine
|
|
|
|
// so that templates can choose to render https or http 'url', see url utility
|
|
|
|
res.locals.secure = req.secure;
|
|
|
|
|
|
|
|
next();
|
|
|
|
}
|
|
|
|
|
|
|
|
function updateLocalTemplateOptions(req, res, next) {
|
|
|
|
const localTemplateOptions = hbs.getLocalTemplateOptions(res.locals);
|
|
|
|
const siteData = {
|
2019-06-18 16:13:55 +03:00
|
|
|
url: urlUtils.urlFor('home', {secure: req.secure, trailingSlash: false}, true)
|
2019-04-03 14:01:23 +03:00
|
|
|
};
|
|
|
|
|
2019-09-10 12:22:38 +03:00
|
|
|
const member = req.member ? {
|
2020-03-02 14:14:03 +03:00
|
|
|
uuid: req.member.uuid,
|
2019-09-10 12:22:38 +03:00
|
|
|
email: req.member.email,
|
2019-10-01 08:44:42 +03:00
|
|
|
name: req.member.name,
|
2019-10-09 07:47:01 +03:00
|
|
|
firstname: req.member.name && req.member.name.split(' ')[0],
|
2020-02-19 13:08:12 +03:00
|
|
|
avatar_image: req.member.avatar_image,
|
2019-10-01 08:44:42 +03:00
|
|
|
subscriptions: req.member.stripe.subscriptions,
|
2019-10-01 08:51:21 +03:00
|
|
|
paid: req.member.stripe.subscriptions.length !== 0
|
2019-09-10 12:22:38 +03:00
|
|
|
} : null;
|
|
|
|
|
2019-04-03 14:01:23 +03:00
|
|
|
hbs.updateLocalTemplateOptions(res.locals, _.merge({}, localTemplateOptions, {
|
2019-09-10 12:37:04 +03:00
|
|
|
// @TODO: remove blog if we drop v2 (Ghost 4.0)
|
2019-04-03 14:01:23 +03:00
|
|
|
data: {
|
2019-09-10 12:22:38 +03:00
|
|
|
member: member,
|
2019-04-03 14:01:23 +03:00
|
|
|
site: siteData,
|
|
|
|
blog: siteData
|
|
|
|
}
|
|
|
|
}));
|
|
|
|
|
|
|
|
next();
|
|
|
|
}
|
|
|
|
|
2017-03-21 12:03:09 +03:00
|
|
|
module.exports = [
|
2019-04-03 13:40:35 +03:00
|
|
|
ensureActiveTheme,
|
2019-04-03 14:01:23 +03:00
|
|
|
updateGlobalTemplateOptions,
|
|
|
|
updateLocalTemplateData,
|
|
|
|
updateLocalTemplateOptions
|
2017-03-21 12:03:09 +03:00
|
|
|
];
|