ghost 5.22.11 → 5.24.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.c8rc.e2e.json +21 -0
- package/README.md +0 -2
- package/components/tryghost-adapter-manager-5.24.0.tgz +0 -0
- package/components/tryghost-api-framework-5.24.0.tgz +0 -0
- package/components/tryghost-api-version-compatibility-service-5.24.0.tgz +0 -0
- package/components/tryghost-audience-feedback-5.24.0.tgz +0 -0
- package/components/tryghost-bootstrap-socket-5.24.0.tgz +0 -0
- package/components/tryghost-constants-5.24.0.tgz +0 -0
- package/components/tryghost-custom-theme-settings-service-5.24.0.tgz +0 -0
- package/components/tryghost-data-generator-5.24.0.tgz +0 -0
- package/components/tryghost-domain-events-5.24.0.tgz +0 -0
- package/components/tryghost-email-analytics-provider-mailgun-5.24.0.tgz +0 -0
- package/components/tryghost-email-analytics-service-5.24.0.tgz +0 -0
- package/components/tryghost-email-content-generator-5.24.0.tgz +0 -0
- package/components/tryghost-email-events-5.24.0.tgz +0 -0
- package/components/tryghost-email-service-5.24.0.tgz +0 -0
- package/components/tryghost-email-suppression-list-5.24.0.tgz +0 -0
- package/components/tryghost-express-dynamic-redirects-5.24.0.tgz +0 -0
- package/components/tryghost-extract-api-key-5.24.0.tgz +0 -0
- package/components/tryghost-html-to-plaintext-5.24.0.tgz +0 -0
- package/components/{tryghost-job-manager-5.22.11.tgz → tryghost-job-manager-5.24.0.tgz} +0 -0
- package/components/tryghost-link-redirects-5.24.0.tgz +0 -0
- package/components/tryghost-link-replacer-5.24.0.tgz +0 -0
- package/components/tryghost-link-tracking-5.24.0.tgz +0 -0
- package/components/{tryghost-magic-link-5.22.11.tgz → tryghost-magic-link-5.24.0.tgz} +0 -0
- package/components/tryghost-mailgun-client-5.24.0.tgz +0 -0
- package/components/{tryghost-member-attribution-5.22.11.tgz → tryghost-member-attribution-5.24.0.tgz} +0 -0
- package/components/{tryghost-member-events-5.22.11.tgz → tryghost-member-events-5.24.0.tgz} +0 -0
- package/components/tryghost-members-api-5.24.0.tgz +0 -0
- package/components/tryghost-members-csv-5.24.0.tgz +0 -0
- package/components/tryghost-members-events-service-5.24.0.tgz +0 -0
- package/components/tryghost-members-importer-5.24.0.tgz +0 -0
- package/components/{tryghost-members-offers-5.22.11.tgz → tryghost-members-offers-5.24.0.tgz} +0 -0
- package/components/tryghost-members-payments-5.24.0.tgz +0 -0
- package/components/tryghost-members-ssr-5.24.0.tgz +0 -0
- package/components/tryghost-members-stripe-service-5.24.0.tgz +0 -0
- package/components/tryghost-minifier-5.24.0.tgz +0 -0
- package/components/tryghost-mw-api-version-mismatch-5.24.0.tgz +0 -0
- package/components/tryghost-mw-cache-control-5.24.0.tgz +0 -0
- package/components/tryghost-mw-error-handler-5.24.0.tgz +0 -0
- package/components/tryghost-mw-session-from-token-5.24.0.tgz +0 -0
- package/components/tryghost-mw-update-user-last-seen-5.24.0.tgz +0 -0
- package/components/tryghost-mw-vhost-5.24.0.tgz +0 -0
- package/components/tryghost-oembed-service-5.24.0.tgz +0 -0
- package/components/tryghost-package-json-5.24.0.tgz +0 -0
- package/components/tryghost-referrers-5.24.0.tgz +0 -0
- package/components/tryghost-security-5.24.0.tgz +0 -0
- package/components/tryghost-session-service-5.24.0.tgz +0 -0
- package/components/{tryghost-settings-path-manager-5.22.11.tgz → tryghost-settings-path-manager-5.24.0.tgz} +0 -0
- package/components/tryghost-staff-service-5.24.0.tgz +0 -0
- package/components/{tryghost-stats-service-5.22.11.tgz → tryghost-stats-service-5.24.0.tgz} +0 -0
- package/components/{tryghost-tiers-5.22.11.tgz → tryghost-tiers-5.24.0.tgz} +0 -0
- package/components/tryghost-update-check-service-5.24.0.tgz +0 -0
- package/components/tryghost-verification-trigger-5.24.0.tgz +0 -0
- package/components/tryghost-version-notifications-data-service-5.24.0.tgz +0 -0
- package/content/themes/casper/assets/built/screen.css +1 -1
- package/content/themes/casper/assets/built/screen.css.map +1 -1
- package/content/themes/casper/assets/css/screen.css +3 -5
- package/content/themes/casper/default.hbs +2 -2
- package/content/themes/casper/package.json +1 -1
- package/core/boot.js +5 -1
- package/core/built/admin/assets/{chunk.143.8f4f86908026af3b9484.js → chunk.143.dd395a3e804fef2c3b21.js} +14 -14
- package/core/built/admin/assets/{chunk.178.0aff330fc5d8e74617b5.js → chunk.178.ec67ba4dc75bcec75c6f.js} +4 -4
- package/core/built/admin/assets/chunk.507.71dd4bfc4ccb354cc629.js +267 -0
- package/core/built/admin/assets/{chunk.613.695f31829550fb00d43c.js → chunk.613.6bbcc18224567657fc2e.js} +3089 -3074
- package/core/built/admin/assets/{chunk.613.695f31829550fb00d43c.js.LICENSE.txt → chunk.613.6bbcc18224567657fc2e.js.LICENSE.txt} +0 -0
- package/core/built/admin/assets/{ghost-b204dcc6ad523053868da9b2d8d65f80.js → ghost-34bc21923675def87aa2516f72ca15d7.js} +1287 -1248
- package/core/built/admin/assets/ghost-dark-a2076b08f23a9e6340072bc7b06ec9e7.css +1 -0
- package/core/built/admin/assets/ghost-f428683b68c0eea9042acc7c021641e0.css +1 -0
- package/core/built/admin/assets/{vendor-dc9f883b3468ff84794cf13741e6c4b4.js → vendor-04415b2b8a59aa9567dfa5d819ada71c.js} +315 -303
- package/core/built/admin/index.html +6 -6
- package/core/cli/record-test.js +47 -0
- package/core/frontend/apps/amp/lib/helpers/amp_content.js +5 -1
- package/core/frontend/apps/amp/lib/views/amp.hbs +10 -0
- package/core/frontend/helpers/ghost_head.js +1 -7
- package/core/server/api/endpoints/db.js +17 -11
- package/core/server/api/endpoints/email-previews.js +10 -2
- package/core/server/api/endpoints/emails.js +20 -14
- package/core/server/api/endpoints/posts.js +4 -1
- package/core/server/api/endpoints/utils/serializers/input/posts.js +4 -11
- package/core/server/api/endpoints/utils/serializers/output/db.js +3 -7
- package/core/server/api/endpoints/utils/serializers/output/members.js +5 -0
- package/core/server/data/importer/email-template.js +163 -0
- package/core/server/data/importer/import-manager.js +116 -35
- package/core/server/data/importer/importers/data/base.js +1 -0
- package/core/server/data/importer/importers/data/data-importer.js +27 -1
- package/core/server/data/migrations/versions/5.24/2022-11-21-09-32-add-source-columns-to-emails-table.js +17 -0
- package/core/server/data/migrations/versions/5.24/2022-11-21-15-03-populate-source-column-with-html-for-emails.js +19 -0
- package/core/server/data/migrations/versions/5.24/2022-11-21-15-57-add-error-columns-for-email-batches.js +22 -0
- package/core/server/data/schema/default-settings/default-settings.json +1 -1
- package/core/server/data/schema/schema.js +11 -0
- package/core/server/models/base/plugins/bulk-operations.js +0 -1
- package/core/server/models/comment.js +1 -1
- package/core/server/models/email.js +2 -1
- package/core/server/models/member-newsletter.js +9 -0
- package/core/server/models/member.js +1 -9
- package/core/server/models/stripe-customer-subscription.js +3 -7
- package/core/server/services/bulk-email/bulk-email-processor.js +14 -23
- package/core/server/services/email-service/index.js +3 -0
- package/core/server/services/email-service/wrapper.js +64 -0
- package/core/server/services/email-suppression-list/index.js +1 -0
- package/core/server/services/email-suppression-list/service.js +38 -0
- package/core/server/services/mega/mega.js +65 -6
- package/core/server/services/mega/segment-parser.js +1 -3
- package/core/server/services/members/api.js +4 -2
- package/core/server/services/members/middleware.js +19 -3
- package/core/server/services/members/service.js +36 -29
- package/core/server/services/members/utils.js +7 -0
- package/core/server/services/posts/posts-service.js +19 -6
- package/core/server/web/members/app.js +12 -10
- package/core/shared/config/defaults.json +1 -1
- package/core/shared/labs.js +3 -7
- package/core/shared/sentry.js +25 -3
- package/ghost.js +1 -0
- package/package.json +111 -106
- package/playwright.config.js +26 -0
- package/yarn.lock +263 -358
- package/components/tryghost-adapter-manager-5.22.11.tgz +0 -0
- package/components/tryghost-api-framework-5.22.11.tgz +0 -0
- package/components/tryghost-api-version-compatibility-service-5.22.11.tgz +0 -0
- package/components/tryghost-audience-feedback-5.22.11.tgz +0 -0
- package/components/tryghost-bootstrap-socket-5.22.11.tgz +0 -0
- package/components/tryghost-constants-5.22.11.tgz +0 -0
- package/components/tryghost-custom-theme-settings-service-5.22.11.tgz +0 -0
- package/components/tryghost-data-generator-5.22.11.tgz +0 -0
- package/components/tryghost-domain-events-5.22.11.tgz +0 -0
- package/components/tryghost-email-analytics-provider-mailgun-5.22.11.tgz +0 -0
- package/components/tryghost-email-analytics-service-5.22.11.tgz +0 -0
- package/components/tryghost-email-content-generator-5.22.11.tgz +0 -0
- package/components/tryghost-express-dynamic-redirects-5.22.11.tgz +0 -0
- package/components/tryghost-extract-api-key-5.22.11.tgz +0 -0
- package/components/tryghost-html-to-plaintext-5.22.11.tgz +0 -0
- package/components/tryghost-link-redirects-5.22.11.tgz +0 -0
- package/components/tryghost-link-replacer-5.22.11.tgz +0 -0
- package/components/tryghost-link-tracking-5.22.11.tgz +0 -0
- package/components/tryghost-mailgun-client-5.22.11.tgz +0 -0
- package/components/tryghost-member-analytics-service-5.22.11.tgz +0 -0
- package/components/tryghost-members-analytics-ingress-5.22.11.tgz +0 -0
- package/components/tryghost-members-api-5.22.11.tgz +0 -0
- package/components/tryghost-members-csv-5.22.11.tgz +0 -0
- package/components/tryghost-members-events-service-5.22.11.tgz +0 -0
- package/components/tryghost-members-importer-5.22.11.tgz +0 -0
- package/components/tryghost-members-payments-5.22.11.tgz +0 -0
- package/components/tryghost-members-ssr-5.22.11.tgz +0 -0
- package/components/tryghost-members-stripe-service-5.22.11.tgz +0 -0
- package/components/tryghost-minifier-5.22.11.tgz +0 -0
- package/components/tryghost-mw-api-version-mismatch-5.22.11.tgz +0 -0
- package/components/tryghost-mw-cache-control-5.22.11.tgz +0 -0
- package/components/tryghost-mw-error-handler-5.22.11.tgz +0 -0
- package/components/tryghost-mw-session-from-token-5.22.11.tgz +0 -0
- package/components/tryghost-mw-update-user-last-seen-5.22.11.tgz +0 -0
- package/components/tryghost-mw-vhost-5.22.11.tgz +0 -0
- package/components/tryghost-oembed-service-5.22.11.tgz +0 -0
- package/components/tryghost-package-json-5.22.11.tgz +0 -0
- package/components/tryghost-referrers-5.22.11.tgz +0 -0
- package/components/tryghost-security-5.22.11.tgz +0 -0
- package/components/tryghost-session-service-5.22.11.tgz +0 -0
- package/components/tryghost-staff-service-5.22.11.tgz +0 -0
- package/components/tryghost-update-check-service-5.22.11.tgz +0 -0
- package/components/tryghost-verification-trigger-5.22.11.tgz +0 -0
- package/components/tryghost-version-notifications-data-service-5.22.11.tgz +0 -0
- package/core/built/admin/assets/chunk.174.3a133d51d9b45097c101.js +0 -245
- package/core/built/admin/assets/ghost-03c7a25d23ad4d0725da171f8d7c7b2a.css +0 -1
- package/core/built/admin/assets/ghost-dark-8896a076fc06ec2b09343b1c9df7feca.css +0 -1
- package/core/server/models/member-analytic-event.js +0 -9
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
<title>Ghost Admin</title>
|
|
9
9
|
|
|
10
10
|
|
|
11
|
-
<meta name="ghost-admin/config/environment" content="%7B%22modulePrefix%22%3A%22ghost-admin%22%2C%22environment%22%3A%22production%22%2C%22rootURL%22%3A%22%22%2C%22locationType%22%3A%22trailing-hash%22%2C%22EmberENV%22%3A%7B%22FEATURES%22%3A%7B%7D%2C%22EXTEND_PROTOTYPES%22%3A%7B%22Date%22%3Afalse%2C%22Array%22%3Atrue%2C%22String%22%3Atrue%2C%22Function%22%3Afalse%7D%2C%22_APPLICATION_TEMPLATE_WRAPPER%22%3Afalse%2C%22_JQUERY_INTEGRATION%22%3Atrue%2C%22_TEMPLATE_ONLY_GLIMMER_COMPONENTS%22%3Atrue%7D%2C%22APP%22%3A%7B%22version%22%3A%225.
|
|
11
|
+
<meta name="ghost-admin/config/environment" content="%7B%22modulePrefix%22%3A%22ghost-admin%22%2C%22environment%22%3A%22production%22%2C%22rootURL%22%3A%22%22%2C%22locationType%22%3A%22trailing-hash%22%2C%22EmberENV%22%3A%7B%22FEATURES%22%3A%7B%7D%2C%22EXTEND_PROTOTYPES%22%3A%7B%22Date%22%3Afalse%2C%22Array%22%3Atrue%2C%22String%22%3Atrue%2C%22Function%22%3Afalse%7D%2C%22_APPLICATION_TEMPLATE_WRAPPER%22%3Afalse%2C%22_JQUERY_INTEGRATION%22%3Atrue%2C%22_TEMPLATE_ONLY_GLIMMER_COMPONENTS%22%3Atrue%7D%2C%22APP%22%3A%7B%22version%22%3A%225.24%22%2C%22name%22%3A%22ghost-admin%22%7D%2C%22ember-simple-auth%22%3A%7B%7D%2C%22%40sentry%2Fember%22%3A%7B%22disablePerformance%22%3Atrue%2C%22sentry%22%3A%7B%7D%7D%2C%22ember-cli-mirage%22%3A%7B%22usingProxy%22%3Afalse%2C%22useDefaultPassthroughs%22%3Atrue%7D%2C%22exportApplicationGlobal%22%3Afalse%2C%22ember-load%22%3A%7B%22loadingIndicatorClass%22%3A%22ember-load-indicator%22%7D%7D" />
|
|
12
12
|
|
|
13
13
|
<meta name="HandheldFriendly" content="True" />
|
|
14
14
|
<meta name="MobileOptimized" content="320" />
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
</style>
|
|
38
38
|
|
|
39
39
|
<link integrity="" rel="stylesheet" href="assets/vendor-3e6947aa681f0fb82b193090e520dc73.css">
|
|
40
|
-
<link integrity="" rel="stylesheet" href="assets/ghost-
|
|
40
|
+
<link integrity="" rel="stylesheet" href="assets/ghost-f428683b68c0eea9042acc7c021641e0.css" title="light">
|
|
41
41
|
|
|
42
42
|
|
|
43
43
|
</head>
|
|
@@ -56,9 +56,9 @@
|
|
|
56
56
|
|
|
57
57
|
<div id="ember-basic-dropdown-wormhole"></div>
|
|
58
58
|
|
|
59
|
-
<script src="assets/vendor-
|
|
60
|
-
<script src="assets/chunk.613.
|
|
61
|
-
<script src="assets/chunk.143.
|
|
62
|
-
<script src="assets/ghost-
|
|
59
|
+
<script src="assets/vendor-04415b2b8a59aa9567dfa5d819ada71c.js"></script>
|
|
60
|
+
<script src="assets/chunk.613.6bbcc18224567657fc2e.js"></script>
|
|
61
|
+
<script src="assets/chunk.143.dd395a3e804fef2c3b21.js"></script>
|
|
62
|
+
<script src="assets/ghost-34bc21923675def87aa2516f72ca15d7.js"></script>
|
|
63
63
|
</body>
|
|
64
64
|
</html>
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
const {chromium} = require('@playwright/test');
|
|
2
|
+
const Command = require('./command');
|
|
3
|
+
const testUtils = require('../../test/utils');
|
|
4
|
+
|
|
5
|
+
module.exports = class RecordTest extends Command {
|
|
6
|
+
setup() {
|
|
7
|
+
this.help('Use PlayWright to record a browser-based test');
|
|
8
|
+
this.argument('--admin', {type: 'boolean', defaultValue: false, desc: 'Start browser-based test in Ghost admin'});
|
|
9
|
+
this.argument('--no-setup', {type: 'boolean', defaultValue: false, desc: 'Disable the default setup, for testing Ghost admin setup'});
|
|
10
|
+
this.argument('--fixtures', {type: 'array', defaultValue: [], delimiter: ',', desc: 'A list of comma-separated fixtures to include'});
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
permittedEnvironments() {
|
|
14
|
+
return ['development', 'testing'];
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
async handle(argv) {
|
|
18
|
+
const app = await testUtils.startGhost();
|
|
19
|
+
|
|
20
|
+
if (argv.fixtures.length > 0) {
|
|
21
|
+
await testUtils.initFixtures(...argv.fixtures);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const browser = await chromium.launch({headless: false});
|
|
25
|
+
|
|
26
|
+
const baseURL = argv.admin ? `${app.url}ghost/` : app.url;
|
|
27
|
+
const context = await browser.newContext({
|
|
28
|
+
baseURL
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
// Pause the page, and start recording manually.
|
|
32
|
+
const page = await context.newPage();
|
|
33
|
+
await page.goto('');
|
|
34
|
+
|
|
35
|
+
if (argv.admin && !argv['no-setup']) {
|
|
36
|
+
await page.getByPlaceholder('The Daily Awesome').click();
|
|
37
|
+
await page.getByPlaceholder('The Daily Awesome').fill('The Local Test');
|
|
38
|
+
await page.getByPlaceholder('Jamie Larson').fill('Testy McTesterson');
|
|
39
|
+
await page.getByPlaceholder('jamie@example.com').fill('testy@example.com');
|
|
40
|
+
await page.getByPlaceholder('At least 10 characters').fill('Mc.T3ster$0n');
|
|
41
|
+
await page.getByPlaceholder('At least 10 characters').press('Enter');
|
|
42
|
+
await page.locator('.gh-done-pink').click();
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
await page.pause();
|
|
46
|
+
}
|
|
47
|
+
};
|
|
@@ -108,7 +108,7 @@ allowedAMPAttributes = {
|
|
|
108
108
|
'amp-audio': ['src', 'width', 'height', 'autoplay', 'loop', 'muted', 'controls'],
|
|
109
109
|
'amp-iframe': ['src', 'srcdoc', 'width', 'height', 'layout', 'frameborder', 'allowfullscreen', 'allowtransparency',
|
|
110
110
|
'sandbox', 'referrerpolicy'],
|
|
111
|
-
'amp-youtube': ['src', '
|
|
111
|
+
'amp-youtube': ['src', 'layout', 'frameborder', 'autoplay', 'loop', 'data-videoid', 'data-live-channelid', 'width', 'height']
|
|
112
112
|
};
|
|
113
113
|
|
|
114
114
|
function getAmperizeHTML(html, post) {
|
|
@@ -193,6 +193,10 @@ module.exports = async function amp_content() { // eslint-disable-line camelcase
|
|
|
193
193
|
$('audio').children('source').remove();
|
|
194
194
|
$('audio').children('track').remove();
|
|
195
195
|
|
|
196
|
+
$('amp-youtube').attr('layout', 'responsive');
|
|
197
|
+
$('amp-youtube').attr('height', '350');
|
|
198
|
+
$('amp-youtube').attr('width', '600');
|
|
199
|
+
|
|
196
200
|
ampHTML = $.html();
|
|
197
201
|
|
|
198
202
|
// @TODO: remove this, when Amperize supports HTML sanitizing
|
|
@@ -182,6 +182,16 @@
|
|
|
182
182
|
amp-img img {
|
|
183
183
|
object-fit: cover;
|
|
184
184
|
}
|
|
185
|
+
|
|
186
|
+
amp-youtube {
|
|
187
|
+
height: calc(100vw / 1.78);
|
|
188
|
+
width: 100vw;
|
|
189
|
+
position: relative;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
amp-youtube img {
|
|
193
|
+
position: absolute;
|
|
194
|
+
}
|
|
185
195
|
|
|
186
196
|
.page-header {
|
|
187
197
|
padding: 50px 5vmin 30px;
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// Usage: `{{ghost_head}}`
|
|
3
3
|
//
|
|
4
4
|
// Outputs scripts and other assets at the top of a Ghost theme
|
|
5
|
-
const {metaData, settingsCache, config, blogIcon, urlUtils,
|
|
5
|
+
const {metaData, settingsCache, config, blogIcon, urlUtils, getFrontendKey} = require('../services/proxy');
|
|
6
6
|
const {escapeExpression, SafeString} = require('../services/handlebars');
|
|
7
7
|
|
|
8
8
|
// BAD REQUIRE
|
|
@@ -207,12 +207,6 @@ module.exports = async function ghost_head(options) { // eslint-disable-line cam
|
|
|
207
207
|
head.push('<meta name="generator" content="Ghost ' +
|
|
208
208
|
escapeExpression(safeVersion) + '" />');
|
|
209
209
|
|
|
210
|
-
// Ghost analytics tag
|
|
211
|
-
if (labs.isSet('membersActivity')) {
|
|
212
|
-
const postId = (dataRoot && dataRoot.post) ? dataRoot.post.id : '';
|
|
213
|
-
head.push(writeMetaTag('ghost-analytics-id', postId, 'name'));
|
|
214
|
-
}
|
|
215
|
-
|
|
216
210
|
head.push('<link rel="alternate" type="application/rss+xml" title="' +
|
|
217
211
|
escapeExpression(meta.site.title) + '" href="' +
|
|
218
212
|
escapeExpression(meta.rssUrl) + '" />');
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
const Promise = require('bluebird');
|
|
2
|
+
const moment = require('moment-timezone');
|
|
2
3
|
const dbBackup = require('../../data/db/backup');
|
|
3
4
|
const exporter = require('../../data/exporter');
|
|
4
5
|
const importer = require('../../data/importer');
|
|
5
6
|
const errors = require('@tryghost/errors');
|
|
6
7
|
const models = require('../../models');
|
|
8
|
+
const settingsCache = require('../../../shared/settings-cache');
|
|
7
9
|
|
|
8
10
|
module.exports = {
|
|
9
11
|
docName: 'db',
|
|
@@ -68,22 +70,26 @@ module.exports = {
|
|
|
68
70
|
},
|
|
69
71
|
|
|
70
72
|
importContent: {
|
|
73
|
+
statusCode(result) {
|
|
74
|
+
if (result && (result.db || result.problems)) {
|
|
75
|
+
return 200;
|
|
76
|
+
} else {
|
|
77
|
+
return 202;
|
|
78
|
+
}
|
|
79
|
+
},
|
|
71
80
|
headers: {
|
|
72
81
|
cacheInvalidate: true
|
|
73
82
|
},
|
|
74
|
-
options: [
|
|
75
|
-
'include'
|
|
76
|
-
],
|
|
77
|
-
validation: {
|
|
78
|
-
options: {
|
|
79
|
-
include: {
|
|
80
|
-
values: exporter.BACKUP_TABLES
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
},
|
|
84
83
|
permissions: true,
|
|
85
84
|
query(frame) {
|
|
86
|
-
|
|
85
|
+
const siteTimezone = settingsCache.get('timezone');
|
|
86
|
+
const importTag = `Import ${moment().tz(siteTimezone).format('YYYY-MM-DD HH:mm')}`;
|
|
87
|
+
return importer.importFromFile(frame.file, {
|
|
88
|
+
user: {
|
|
89
|
+
email: frame.user.get('email')
|
|
90
|
+
},
|
|
91
|
+
importTag
|
|
92
|
+
});
|
|
87
93
|
}
|
|
88
94
|
},
|
|
89
95
|
|
|
@@ -2,7 +2,8 @@ const models = require('../../models');
|
|
|
2
2
|
const tpl = require('@tryghost/tpl');
|
|
3
3
|
const errors = require('@tryghost/errors');
|
|
4
4
|
const mega = require('../../services/mega');
|
|
5
|
-
|
|
5
|
+
const emailService = require('../../services/email-service');
|
|
6
|
+
const labs = require('../../../shared/labs');
|
|
6
7
|
const messages = {
|
|
7
8
|
postNotFound: 'Post not found.'
|
|
8
9
|
};
|
|
@@ -29,6 +30,10 @@ module.exports = {
|
|
|
29
30
|
],
|
|
30
31
|
permissions: true,
|
|
31
32
|
async query(frame) {
|
|
33
|
+
if (labs.isSet('emailStability')) {
|
|
34
|
+
return await emailService.controller.previewEmail(frame);
|
|
35
|
+
}
|
|
36
|
+
|
|
32
37
|
const options = Object.assign(frame.options, {formats: 'html,plaintext', withRelated: ['authors', 'posts_meta']});
|
|
33
38
|
const data = Object.assign(frame.data, {status: 'all'});
|
|
34
39
|
|
|
@@ -61,6 +66,10 @@ module.exports = {
|
|
|
61
66
|
},
|
|
62
67
|
permissions: true,
|
|
63
68
|
async query(frame) {
|
|
69
|
+
if (labs.isSet('emailStability')) {
|
|
70
|
+
return await emailService.controller.sendTestEmail(frame);
|
|
71
|
+
}
|
|
72
|
+
|
|
64
73
|
const options = Object.assign(frame.options, {status: 'all'});
|
|
65
74
|
let model = await models.Post.findOne(options, {withRelated: ['authors']});
|
|
66
75
|
|
|
@@ -69,7 +78,6 @@ module.exports = {
|
|
|
69
78
|
message: tpl(messages.postNotFound)
|
|
70
79
|
});
|
|
71
80
|
}
|
|
72
|
-
|
|
73
81
|
const {emails = [], memberSegment} = frame.data;
|
|
74
82
|
return await mega.mega.sendTestEmail(model, emails, memberSegment);
|
|
75
83
|
}
|
|
@@ -2,6 +2,8 @@ const models = require('../../models');
|
|
|
2
2
|
const tpl = require('@tryghost/tpl');
|
|
3
3
|
const errors = require('@tryghost/errors');
|
|
4
4
|
const megaService = require('../../services/mega');
|
|
5
|
+
const emailService = require('../../services/email-service');
|
|
6
|
+
const labs = require('../../../shared/labs');
|
|
5
7
|
|
|
6
8
|
const messages = {
|
|
7
9
|
emailNotFound: 'Email not found.',
|
|
@@ -57,23 +59,27 @@ module.exports = {
|
|
|
57
59
|
'id'
|
|
58
60
|
],
|
|
59
61
|
permissions: true,
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
});
|
|
67
|
-
}
|
|
62
|
+
// (complexity removed with new labs flag)
|
|
63
|
+
// eslint-disable-next-line ghost/ghost-custom/max-api-complexity
|
|
64
|
+
async query(frame) {
|
|
65
|
+
if (labs.isSet('emailStability')) {
|
|
66
|
+
return await emailService.controller.retryFailedEmail(frame);
|
|
67
|
+
}
|
|
68
68
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
69
|
+
const model = await models.Email.findOne(frame.data, frame.options);
|
|
70
|
+
if (!model) {
|
|
71
|
+
throw new errors.NotFoundError({
|
|
72
|
+
message: tpl(messages.emailNotFound)
|
|
73
|
+
});
|
|
74
|
+
}
|
|
74
75
|
|
|
75
|
-
|
|
76
|
+
if (model.get('status') !== 'failed') {
|
|
77
|
+
throw new errors.IncorrectUsageError({
|
|
78
|
+
message: tpl(messages.retryNotAllowed)
|
|
76
79
|
});
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return await megaService.mega.retryFailedEmail(model);
|
|
77
83
|
}
|
|
78
84
|
}
|
|
79
85
|
};
|
|
@@ -9,10 +9,13 @@ const allowedIncludes = [
|
|
|
9
9
|
'email',
|
|
10
10
|
'tiers',
|
|
11
11
|
'newsletter',
|
|
12
|
+
'count.conversions',
|
|
12
13
|
'count.signups',
|
|
13
14
|
'count.paid_conversions',
|
|
14
15
|
'count.clicks',
|
|
15
|
-
'sentiment'
|
|
16
|
+
'sentiment',
|
|
17
|
+
'count.positive_feedback',
|
|
18
|
+
'count.negative_feedback'
|
|
16
19
|
];
|
|
17
20
|
const unsafeAttrs = ['status', 'authors', 'visibility'];
|
|
18
21
|
|
|
@@ -6,7 +6,6 @@ const localUtils = require('../../index');
|
|
|
6
6
|
const mobiledoc = require('../../../../../lib/mobiledoc');
|
|
7
7
|
const postsMetaSchema = require('../../../../../data/schema').tables.posts_meta;
|
|
8
8
|
const clean = require('./utils/clean');
|
|
9
|
-
const labs = require('../../../../../../shared/labs');
|
|
10
9
|
|
|
11
10
|
function removeSourceFormats(frame) {
|
|
12
11
|
if (frame.options.formats?.includes('mobiledoc') || frame.options.formats?.includes('lexical')) {
|
|
@@ -22,11 +21,9 @@ function removeSourceFormats(frame) {
|
|
|
22
21
|
function mapWithRelated(frame) {
|
|
23
22
|
if (frame.options.withRelated) {
|
|
24
23
|
// Map sentiment to count.sentiment
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
});
|
|
29
|
-
}
|
|
24
|
+
frame.options.withRelated = frame.options.withRelated.map((relation) => {
|
|
25
|
+
return relation === 'sentiment' ? 'count.sentiment' : relation;
|
|
26
|
+
});
|
|
30
27
|
return;
|
|
31
28
|
}
|
|
32
29
|
}
|
|
@@ -44,11 +41,7 @@ function defaultRelations(frame) {
|
|
|
44
41
|
return false;
|
|
45
42
|
}
|
|
46
43
|
|
|
47
|
-
|
|
48
|
-
frame.options.withRelated = ['tags', 'authors', 'authors.roles', 'email', 'tiers', 'newsletter', 'count.conversions', 'count.clicks', 'count.sentiment', 'count.positive_feedback', 'count.negative_feedback'];
|
|
49
|
-
} else {
|
|
50
|
-
frame.options.withRelated = ['tags', 'authors', 'authors.roles', 'email', 'tiers', 'newsletter', 'count.signups', 'count.paid_conversions', 'count.clicks'];
|
|
51
|
-
}
|
|
44
|
+
frame.options.withRelated = ['tags', 'authors', 'authors.roles', 'email', 'tiers', 'newsletter', 'count.clicks'];
|
|
52
45
|
}
|
|
53
46
|
|
|
54
47
|
function setDefaultOrder(frame) {
|
|
@@ -20,15 +20,11 @@ module.exports = {
|
|
|
20
20
|
importContent(response, apiConfig, frame) {
|
|
21
21
|
debug('importContent');
|
|
22
22
|
|
|
23
|
-
// NOTE: response can contain 2 objects if images are imported
|
|
24
|
-
const problems = (response.length === 2)
|
|
25
|
-
? response[1].problems
|
|
26
|
-
: response[0].problems;
|
|
27
|
-
|
|
28
23
|
frame.response = {
|
|
29
|
-
db: []
|
|
30
|
-
problems: problems
|
|
24
|
+
db: []
|
|
31
25
|
};
|
|
26
|
+
|
|
27
|
+
frame.response.problems = response?.data?.problems ?? [];
|
|
32
28
|
},
|
|
33
29
|
|
|
34
30
|
deleteAllContent(response, apiConfig, frame) {
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
const debug = require('@tryghost/debug')('api:endpoints:utils:serializers:output:members');
|
|
3
3
|
const {unparse} = require('@tryghost/members-csv');
|
|
4
4
|
const mappers = require('./mappers');
|
|
5
|
+
const labs = require('../../../../../../shared/labs');
|
|
5
6
|
|
|
6
7
|
module.exports = {
|
|
7
8
|
browse: createSerializer('browse', paginatedMembers),
|
|
@@ -171,6 +172,10 @@ function serializeMember(member, options) {
|
|
|
171
172
|
delete subscription.price.product;
|
|
172
173
|
}
|
|
173
174
|
|
|
175
|
+
if (labs.isSet('suppressionList')) {
|
|
176
|
+
serialized.email_suppression = json.email_suppression;
|
|
177
|
+
}
|
|
178
|
+
|
|
174
179
|
if (json.newsletters) {
|
|
175
180
|
serialized.newsletters = json.newsletters
|
|
176
181
|
.filter(newsletter => newsletter.status === 'active')
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
module.exports = ({result, siteUrl, postsUrl, emailRecipient}) => `
|
|
2
|
+
<!doctype html>
|
|
3
|
+
<html>
|
|
4
|
+
<head>
|
|
5
|
+
<meta name="viewport" content="width=device-width">
|
|
6
|
+
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
|
7
|
+
<title>Your content import is complete</title>
|
|
8
|
+
<style>
|
|
9
|
+
/* -------------------------------------
|
|
10
|
+
RESPONSIVE AND MOBILE FRIENDLY STYLES
|
|
11
|
+
------------------------------------- */
|
|
12
|
+
@media only screen and (max-width: 620px) {
|
|
13
|
+
table[class=body] h1 {
|
|
14
|
+
font-size: 28px !important;
|
|
15
|
+
margin-bottom: 10px !important;
|
|
16
|
+
}
|
|
17
|
+
table[class=body] p,
|
|
18
|
+
table[class=body] ul,
|
|
19
|
+
table[class=body] ol,
|
|
20
|
+
table[class=body] td,
|
|
21
|
+
table[class=body] span,
|
|
22
|
+
table[class=body] a {
|
|
23
|
+
font-size: 16px !important;
|
|
24
|
+
}
|
|
25
|
+
table[class=body] .title {
|
|
26
|
+
font-size: 22px !important;
|
|
27
|
+
}
|
|
28
|
+
table[class=body] .wrapper,
|
|
29
|
+
table[class=body] .article {
|
|
30
|
+
padding: 10px !important;
|
|
31
|
+
}
|
|
32
|
+
table[class=body] .content {
|
|
33
|
+
padding: 0 !important;
|
|
34
|
+
}
|
|
35
|
+
table[class=body] .container {
|
|
36
|
+
padding: 0 !important;
|
|
37
|
+
width: 100% !important;
|
|
38
|
+
}
|
|
39
|
+
table[class=body] .main {
|
|
40
|
+
border-left-width: 0 !important;
|
|
41
|
+
border-radius: 0 !important;
|
|
42
|
+
border-right-width: 0 !important;
|
|
43
|
+
}
|
|
44
|
+
table[class=body] .btn table {
|
|
45
|
+
width: 100% !important;
|
|
46
|
+
}
|
|
47
|
+
table[class=body] .btn a {
|
|
48
|
+
width: 100% !important;
|
|
49
|
+
}
|
|
50
|
+
table[class=body] .img-responsive {
|
|
51
|
+
height: auto !important;
|
|
52
|
+
max-width: 100% !important;
|
|
53
|
+
width: auto !important;
|
|
54
|
+
}
|
|
55
|
+
table[class=body] p[class=small],
|
|
56
|
+
table[class=body] a[class=small] {
|
|
57
|
+
font-size: 12x !important;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
/* -------------------------------------
|
|
61
|
+
PRESERVE THESE STYLES IN THE HEAD
|
|
62
|
+
------------------------------------- */
|
|
63
|
+
@media all {
|
|
64
|
+
.ExternalClass {
|
|
65
|
+
width: 100%;
|
|
66
|
+
}
|
|
67
|
+
.ExternalClass,
|
|
68
|
+
.ExternalClass p,
|
|
69
|
+
.ExternalClass span,
|
|
70
|
+
.ExternalClass font,
|
|
71
|
+
.ExternalClass td,
|
|
72
|
+
.ExternalClass div {
|
|
73
|
+
line-height: 100%;
|
|
74
|
+
}
|
|
75
|
+
.recipient-link a {
|
|
76
|
+
color: inherit !important;
|
|
77
|
+
font-family: inherit !important;
|
|
78
|
+
font-size: inherit !important;
|
|
79
|
+
font-weight: inherit !important;
|
|
80
|
+
line-height: inherit !important;
|
|
81
|
+
text-decoration: none !important;
|
|
82
|
+
}
|
|
83
|
+
#MessageViewBody a {
|
|
84
|
+
color: inherit;
|
|
85
|
+
text-decoration: none;
|
|
86
|
+
font-size: inherit;
|
|
87
|
+
font-family: inherit;
|
|
88
|
+
font-weight: inherit;
|
|
89
|
+
line-height: inherit;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
hr {
|
|
93
|
+
border-width: 0;
|
|
94
|
+
height: 0;
|
|
95
|
+
margin-top: 34px;
|
|
96
|
+
margin-bottom: 34px;
|
|
97
|
+
border-bottom-width: 1px;
|
|
98
|
+
border-bottom-color: #EEF5F8;
|
|
99
|
+
}
|
|
100
|
+
a {
|
|
101
|
+
color: #3A464C;
|
|
102
|
+
}
|
|
103
|
+
</style>
|
|
104
|
+
</head>
|
|
105
|
+
<body class="" style="background-color: #ffffff; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; -webkit-font-smoothing: antialiased; font-size: 14px; line-height: 1.5em; margin: 0; padding: 0; -ms-text-size-adjust: 100%; -webkit-text-size-adjust: 100%;">
|
|
106
|
+
<table border="0" cellpadding="0" cellspacing="0" class="body" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%;">
|
|
107
|
+
<tr>
|
|
108
|
+
<td style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 14px; vertical-align: top;"> </td>
|
|
109
|
+
<td class="container" style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 14px; vertical-align: top; display: block; Margin: 0 auto; max-width: 540px; padding: 10px; width: 540px;">
|
|
110
|
+
<div class="content" style="box-sizing: border-box; display: block; Margin: 0 auto; max-width: 600px; padding: 30px 20px;">
|
|
111
|
+
|
|
112
|
+
<!-- START CENTERED CONTAINER -->
|
|
113
|
+
<span class="preheader" style="color: transparent; display: none; height: 0; max-height: 0; max-width: 0; opacity: 0; overflow: hidden; mso-hide: all; visibility: hidden; width: 0;">Your content import is complete</span>
|
|
114
|
+
<table class="main" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%; background: #ffffff; border-radius: 8px;">
|
|
115
|
+
|
|
116
|
+
<!-- START MAIN CONTENT AREA -->
|
|
117
|
+
<tr>
|
|
118
|
+
<td class="wrapper" style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 14px; vertical-align: top; box-sizing: border-box;">
|
|
119
|
+
<table border="0" cellpadding="0" cellspacing="0" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%;">
|
|
120
|
+
<tr>
|
|
121
|
+
<td align="center" style="padding-top: 20px; padding-bottom: 12px;"><img src="https://static.ghost.org/v4.0.0/images/ghost-orb-4.png" width="60" height="60" style="width: 60px; height: 60px;" /></td>
|
|
122
|
+
</tr>
|
|
123
|
+
<tr>
|
|
124
|
+
<td style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; vertical-align: top;">
|
|
125
|
+
<p class="title" style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 21px; color: #3A464C; font-weight: normal; line-height: 25px; margin-bottom: 30px; margin-top: 50px; font-weight: 600; color: #15212A;">${result?.data?.errors ? 'Import unsuccessful' : 'Your content import has finished successfully'}</p>
|
|
126
|
+
</td>
|
|
127
|
+
</tr>
|
|
128
|
+
${result?.data?.errors ? `
|
|
129
|
+
<tr>
|
|
130
|
+
<td style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 14px; vertical-align: top; padding-bottom: 16px;">One or more error occured while importing your content. Please contact support or report on the <a href="https://forum.ghost.org/">Ghost Community Forum</a>.</td>
|
|
131
|
+
</tr>
|
|
132
|
+
` : `
|
|
133
|
+
<tr>
|
|
134
|
+
<td style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 14px; vertical-align: top; padding-bottom: 12px; padding-top: 16px;">
|
|
135
|
+
<a href="${postsUrl.href}" target="_blank" style="display: inline-block; color: #ffffff; background-color: #15212A; border: solid 1px #15212A; border-radius: 5px; box-sizing: border-box; cursor: pointer; text-decoration: none; font-size: 16px; font-weight: normal; margin: 0; padding: 9px 22px 10px; border-color: #15212A;">View posts</a>
|
|
136
|
+
</td>
|
|
137
|
+
</tr>
|
|
138
|
+
`}
|
|
139
|
+
</table>
|
|
140
|
+
</td>
|
|
141
|
+
</tr>
|
|
142
|
+
<tr>
|
|
143
|
+
<td style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; vertical-align: top; padding-top: 80px; padding-bottom: 10px;">
|
|
144
|
+
<div class="footer">
|
|
145
|
+
<p class="small" style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; color: #738A94; font-weight: normal; margin: 0; line-height: 18px; margin-bottom: 0px; font-size: 11px;">This email was sent from <a href="${siteUrl.href}" style="color: #738A94;">${siteUrl.host}</a> to <a href="mailto:${emailRecipient}" style="color: #738A94;">${emailRecipient}</a></p>
|
|
146
|
+
</div>
|
|
147
|
+
</td>
|
|
148
|
+
</tr>
|
|
149
|
+
|
|
150
|
+
<!-- END MAIN CONTENT AREA -->
|
|
151
|
+
</table>
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
<!-- END CENTERED CONTAINER -->
|
|
155
|
+
</div>
|
|
156
|
+
</td>
|
|
157
|
+
<td style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 14px; vertical-align: top;"> </td>
|
|
158
|
+
</tr>
|
|
159
|
+
</table>
|
|
160
|
+
</body>
|
|
161
|
+
</html>
|
|
162
|
+
`;
|
|
163
|
+
|