mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-02-03 23:00:14 -05:00
✨ Added additional newsletter customisation settings (#13074)
refs https://github.com/TryGhost/Team/issues/793 New settings added for newsletter customisation options: - `newsletter_header_image` - `null/"$url"` - `newsletter_show_header_icon` - `"true/false"` - `newsletter_show_header_title` - `"true/false"` - `newsletter_title_alignment` - `"center/left"` - `newsletter_title_font_category` - `"serif/sans_serif"` - `newsletter_show_feature_image` - `"true/false"` `newsletter_show_header` has been dropped because the same functionality can be achieved by setting both `newsletter_show_header_icon` and `newsletter_show_header_title` to `false` --- - migration to convert and delete `newsletter_show_header` setting - removed `newsletter_show_header` from default settings to ensure it doesn't get re-created - replaced main labs template and template settings generation with the labs template - deleted labs template
This commit is contained in:
parent
acb0bd47af
commit
446993a905
10 changed files with 178 additions and 1057 deletions
|
@ -0,0 +1,123 @@
|
|||
const logging = require('@tryghost/logging');
|
||||
const {createTransactionalMigration} = require('../../utils');
|
||||
const ObjectId = require('bson-objectid');
|
||||
|
||||
// newsletter_show_header = false ->
|
||||
// newsletter_show_header_title = false
|
||||
// newsletter_show_header_icon = false
|
||||
//
|
||||
// the default for both of the new settings is true so there's no need to migrate
|
||||
// anything if previously showing the header
|
||||
|
||||
module.exports = createTransactionalMigration(
|
||||
async function up(connection) {
|
||||
const oldSetting = await connection('settings')
|
||||
.where('key', 'newsletter_show_header')
|
||||
.select(['value', 'created_by'])
|
||||
.first();
|
||||
|
||||
if (!oldSetting) {
|
||||
logging.info('Skipping migration of newsletter_show_header setting. Does not exist');
|
||||
return;
|
||||
}
|
||||
|
||||
if (oldSetting.value === 'false') {
|
||||
logging.info('Migrating newsletter_show_header setting. Disabling title and logo');
|
||||
|
||||
const newSettingKeys = ['newsletter_show_header_title', 'newsletter_show_header_icon'];
|
||||
const now = connection.raw('CURRENT_TIMESTAMP');
|
||||
|
||||
for (const settingKey of newSettingKeys) {
|
||||
const existingSetting = await connection('settings').where('key', settingKey).first();
|
||||
|
||||
if (!existingSetting) {
|
||||
// insert default setting - migrations are run before default settings are created
|
||||
await connection('settings')
|
||||
.insert({
|
||||
id: ObjectId().toHexString(),
|
||||
key: settingKey,
|
||||
group: 'newsletter',
|
||||
type: 'boolean',
|
||||
value: 'true',
|
||||
created_at: now,
|
||||
updated_at: now,
|
||||
created_by: oldSetting.created_by,
|
||||
updated_by: oldSetting.created_by
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
await connection('settings')
|
||||
.whereIn('key', ['newsletter_show_header_title', 'newsletter_show_header_icon'])
|
||||
.update({value: 'false'});
|
||||
} else {
|
||||
logging.info('Skipping migration of newsletter_show_header setting. Matches new defaults');
|
||||
}
|
||||
|
||||
logging.info('Deleting newsletter_show_header setting');
|
||||
await connection('settings')
|
||||
.where('key', 'newsletter_show_header')
|
||||
.del();
|
||||
},
|
||||
|
||||
async function down(connection) {
|
||||
logging.info('Adding newsletter_show_header setting');
|
||||
|
||||
const oldSetting = await connection('settings')
|
||||
.where('key', '=', 'newsletter_show_header')
|
||||
.select('value')
|
||||
.first();
|
||||
|
||||
const showTitle = await connection('settings')
|
||||
.where('key', '=', 'newsletter_show_header_title')
|
||||
.select(['value', 'created_by'])
|
||||
.first();
|
||||
|
||||
const showIcon = await connection('settings')
|
||||
.where('key', '=', 'newsletter_show_header_icon')
|
||||
.select(['value', 'created_by'])
|
||||
.first();
|
||||
|
||||
if (oldSetting) {
|
||||
logging.warn('Skipping rollback of newsletter_show_header setting. Already exists');
|
||||
} else {
|
||||
const [{id: ownerId} = {id: 1}] = await connection('users')
|
||||
.select('users.id')
|
||||
.innerJoin(
|
||||
'roles_users',
|
||||
'users.id',
|
||||
'roles_users.user_id'
|
||||
)
|
||||
.where(
|
||||
'roles_users.role_id',
|
||||
connection('roles').select('id').where('name', 'Owner')
|
||||
);
|
||||
|
||||
let showHeader = 'true'; // default
|
||||
|
||||
if (showTitle && showIcon) {
|
||||
showHeader = showTitle.value === 'false' && showIcon.value === 'false' ? 'false' : 'true';
|
||||
}
|
||||
|
||||
const now = connection.raw('CURRENT_TIMESTAMP');
|
||||
|
||||
await connection('settings')
|
||||
.insert({
|
||||
id: ObjectId().toHexString(),
|
||||
key: 'newsletter_show_header',
|
||||
group: 'newsletter',
|
||||
type: 'boolean',
|
||||
value: showHeader,
|
||||
created_at: now,
|
||||
updated_at: now,
|
||||
created_by: ownerId,
|
||||
updated_by: ownerId
|
||||
});
|
||||
}
|
||||
|
||||
logging.info('Deleting newsletter_show_header_{title,icon} settings');
|
||||
await connection('settings')
|
||||
.whereIn('key', ['newsletter_show_header_title', 'newsletter_show_header_icon'])
|
||||
.del();
|
||||
}
|
||||
);
|
|
@ -463,19 +463,6 @@
|
|||
},
|
||||
"type": "boolean"
|
||||
},
|
||||
"newsletter_show_header": {
|
||||
"defaultValue": "true",
|
||||
"validations": {
|
||||
"isEmpty": false,
|
||||
"isIn": [
|
||||
[
|
||||
"true",
|
||||
"false"
|
||||
]
|
||||
]
|
||||
},
|
||||
"type": "boolean"
|
||||
},
|
||||
"newsletter_header_image": {
|
||||
"defaultValue": null,
|
||||
"validations": {
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
const _ = require('lodash');
|
||||
const juice = require('juice');
|
||||
const template = require('./template');
|
||||
const labsTemplate = require('./template-labs');
|
||||
const config = require('../../../shared/config');
|
||||
const settingsCache = require('../../services/settings/cache');
|
||||
const labs = require('../../services/labs');
|
||||
const urlUtils = require('../../../shared/url-utils');
|
||||
|
@ -125,16 +123,6 @@ const parseReplacements = (email) => {
|
|||
};
|
||||
|
||||
const getTemplateSettings = async () => {
|
||||
return {
|
||||
showSiteHeader: settingsCache.get('newsletter_show_header'),
|
||||
bodyFontCategory: settingsCache.get('newsletter_body_font_category'),
|
||||
showBadge: settingsCache.get('newsletter_show_badge'),
|
||||
footerContent: settingsCache.get('newsletter_footer_content'),
|
||||
accentColor: settingsCache.get('accent_color')
|
||||
};
|
||||
};
|
||||
|
||||
const getLabsTemplateSettings = async () => {
|
||||
const templateSettings = {
|
||||
headerImage: settingsCache.get('newsletter_header_image'),
|
||||
showHeaderIcon: settingsCache.get('newsletter_show_header_icon') && settingsCache.get('icon'),
|
||||
|
@ -244,11 +232,9 @@ const serialize = async (postModel, options = {isBrowserPreview: false, apiVersi
|
|||
}
|
||||
}
|
||||
|
||||
const useLabsTemplate = config.get('enableDeveloperExperiments');
|
||||
const templateSettings = await (useLabsTemplate ? getLabsTemplateSettings() : getTemplateSettings());
|
||||
const templateRenderer = useLabsTemplate ? labsTemplate : template;
|
||||
const templateSettings = await getTemplateSettings();
|
||||
|
||||
let htmlTemplate = templateRenderer({post, site: getSite(), templateSettings});
|
||||
let htmlTemplate = template({post, site: getSite(), templateSettings});
|
||||
|
||||
if (options.isBrowserPreview) {
|
||||
const previewUnsubscribeUrl = createUnsubscribeUrl(null);
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -2,6 +2,7 @@
|
|||
const iff = (cond, yes, no) => (cond ? yes : no);
|
||||
module.exports = ({post, site, templateSettings}) => {
|
||||
const date = new Date();
|
||||
const hasFeatureImageCaption = templateSettings.labsFeatureImageMeta && templateSettings.showFeatureImage && post.feature_image && post.feature_image_caption;
|
||||
return `<!doctype html>
|
||||
<html>
|
||||
|
||||
|
@ -267,6 +268,10 @@ figure blockquote p {
|
|||
font-size: 1em;
|
||||
}
|
||||
|
||||
.header-image {
|
||||
padding-top: 16px;
|
||||
}
|
||||
|
||||
.site-icon {
|
||||
padding-bottom: 10px;
|
||||
padding-top: 20px;
|
||||
|
@ -302,6 +307,12 @@ figure blockquote p {
|
|||
font-weight: 600;
|
||||
text-align: center;
|
||||
}
|
||||
.post-title-serif {
|
||||
font-family: Georgia, serif;
|
||||
}
|
||||
.post-title-left {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.post-title-link {
|
||||
color: #15212A;
|
||||
|
@ -309,6 +320,9 @@ figure blockquote p {
|
|||
text-align: center;
|
||||
margin-top: 50px;
|
||||
}
|
||||
.post-title-link-left {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.post-meta,
|
||||
.view-online {
|
||||
|
@ -320,6 +334,9 @@ figure blockquote p {
|
|||
text-transform: uppercase;
|
||||
text-align: center;
|
||||
}
|
||||
.post-meta-left {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.view-online {
|
||||
text-align: right;
|
||||
|
@ -336,6 +353,18 @@ figure blockquote p {
|
|||
width: 100%;
|
||||
}
|
||||
|
||||
.feature-image-with-caption {
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
.feature-image-caption {
|
||||
width: 100%;
|
||||
padding-bottom: 30px;
|
||||
text-align: center;
|
||||
font-size: 13px;
|
||||
color: #738a94;
|
||||
}
|
||||
|
||||
.post-content {
|
||||
max-width: 600px !important;
|
||||
font-family: Georgia, serif;
|
||||
|
@ -877,19 +906,27 @@ ${ templateSettings.showBadge ? `
|
|||
<td class="wrapper">
|
||||
<table role="presentation" border="0" cellpadding="0" cellspacing="0" width="100%">
|
||||
|
||||
${ templateSettings.headerImage ? `
|
||||
<tr>
|
||||
<td class="header-image" width="100%" align="center"><img src="${templateSettings.headerImage}"${templateSettings.headerImageWidth ? ` width="${templateSettings.headerImageWidth}"` : ''}></td>
|
||||
</tr>
|
||||
` : ''}
|
||||
|
||||
${ templateSettings.showSiteHeader ? `
|
||||
|
||||
${ templateSettings.showHeaderIcon || templateSettings.showHeaderTitle ? `
|
||||
<tr>
|
||||
<td class="site-info" width="100%" align="center">
|
||||
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
|
||||
${ site.iconUrl ? `
|
||||
${ templateSettings.showHeaderIcon && site.iconUrl ? `
|
||||
<tr>
|
||||
<td class="site-icon"><a href="${site.url}"><img src="${site.iconUrl}" border="0"></a></td>
|
||||
</tr>
|
||||
` : ``}
|
||||
${ templateSettings.showHeaderTitle ? `
|
||||
<tr>
|
||||
<td class="site-url"><div style="width: 100% !important;"><a href="${site.url}">${site.title}</a></div></td>
|
||||
</tr>
|
||||
` : ``}
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
|
@ -897,13 +934,15 @@ ${ templateSettings.showBadge ? `
|
|||
|
||||
|
||||
<tr>
|
||||
<td class="post-title"><a href="${post.url}" class="post-title-link">${post.title}</a></td>
|
||||
<td class="post-title ${templateSettings.titleFontCategory === 'serif' ? `post-title-serif` : `` } ${templateSettings.titleAlignment === 'left' ? `post-title-left` : ``}">
|
||||
<a href="${post.url}" class="post-title-link ${templateSettings.titleAlignment === 'left' ? `post-title-link-left` : ``}">${post.title}</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center">
|
||||
<td>
|
||||
<table role="presentation" border="0" cellpadding="0" cellspacing="0" width="100%">
|
||||
<tr>
|
||||
<td class="post-meta">
|
||||
<td class="post-meta ${templateSettings.titleAlignment === 'left' ? `post-meta-left` : ``}">
|
||||
By ${post.authors} –
|
||||
${post.published_at} –
|
||||
<a href="${post.url}" class="view-online-link">View online →</a>
|
||||
|
@ -912,9 +951,14 @@ ${ templateSettings.showBadge ? `
|
|||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
${post.feature_image ? `
|
||||
${ templateSettings.showFeatureImage && post.feature_image ? `
|
||||
<tr>
|
||||
<td class="feature-image"><img src="${post.feature_image}"${post.feature_image_width ? ` width="${post.feature_image_width}"` : ''}></td>
|
||||
<td class="feature-image ${hasFeatureImageCaption ? 'feature-image-with-caption' : ''}"><img src="${post.feature_image}"${post.feature_image_width ? ` width="${post.feature_image_width}"` : ''} alt="${post.feature_image_alt}"></td>
|
||||
</tr>
|
||||
` : ``}
|
||||
${ hasFeatureImageCaption ? `
|
||||
<tr>
|
||||
<td class="feature-image-caption" align="center">${post.feature_image_caption}</td>
|
||||
</tr>
|
||||
` : ``}
|
||||
<tr>
|
||||
|
|
|
@ -350,11 +350,6 @@ const defaultSettingsKeyTypes = [
|
|||
type: 'boolean',
|
||||
group: 'newsletter'
|
||||
},
|
||||
{
|
||||
key: 'newsletter_show_header',
|
||||
type: 'boolean',
|
||||
group: 'newsletter'
|
||||
},
|
||||
{
|
||||
key: 'newsletter_header_image',
|
||||
type: 'string',
|
||||
|
|
|
@ -72,7 +72,6 @@ const defaultSettingsKeyTypes = [
|
|||
{key: 'active_timezone', type: 'blog'},
|
||||
{key: 'default_locale', type: 'blog'},
|
||||
{key: 'newsletter_show_badge', type: 'newsletter'},
|
||||
{key: 'newsletter_show_header', type: 'newsletter'},
|
||||
{key: 'newsletter_header_image', type: 'newsletter'},
|
||||
{key: 'newsletter_show_header_icon', type: 'newsletter'},
|
||||
{key: 'newsletter_show_header_title', type: 'newsletter'},
|
||||
|
|
|
@ -76,7 +76,6 @@ const defaultSettingsKeyTypes = [
|
|||
{key: 'default_locale', type: 'blog'},
|
||||
{key: 'accent_color', type: 'blog'},
|
||||
{key: 'newsletter_show_badge', type: 'newsletter'},
|
||||
{key: 'newsletter_show_header', type: 'newsletter'},
|
||||
{key: 'newsletter_header_image', type: 'newsletter'},
|
||||
{key: 'newsletter_show_header_icon', type: 'newsletter'},
|
||||
{key: 'newsletter_show_header_title', type: 'newsletter'},
|
||||
|
|
|
@ -191,7 +191,7 @@ describe('Exporter', function () {
|
|||
|
||||
// NOTE: if default settings changed either modify the settings keys blocklist or increase allowedKeysLength
|
||||
// This is a reminder to think about the importer/exporter scenarios ;)
|
||||
const allowedKeysLength = 84;
|
||||
const allowedKeysLength = 83;
|
||||
totalKeysLength.should.eql(SETTING_KEYS_BLOCKLIST.length + allowedKeysLength);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -34,7 +34,7 @@ describe('DB version integrity', function () {
|
|||
// Only these variables should need updating
|
||||
const currentSchemaHash = 'ef13a18aee78222086ca864c16bde696';
|
||||
const currentFixturesHash = '8671672598d2a62e53418c4b91aa79a3';
|
||||
const currentSettingsHash = '9986400eb68ccb55173b181c2be4f94a';
|
||||
const currentSettingsHash = 'dd0a0a08e66b252e7704bb7e346a8c20';
|
||||
const currentRoutesHash = '3d180d52c663d173a6be791ef411ed01';
|
||||
|
||||
// If this test is failing, then it is likely a change has been made that requires a DB version bump,
|
||||
|
|
Loading…
Add table
Reference in a new issue