ghost 5.19.3 → 5.21.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/components/tryghost-adapter-manager-5.21.0.tgz +0 -0
- package/components/{tryghost-api-framework-5.19.3.tgz → tryghost-api-framework-5.21.0.tgz} +0 -0
- package/components/tryghost-api-version-compatibility-service-5.21.0.tgz +0 -0
- package/components/tryghost-audience-feedback-5.21.0.tgz +0 -0
- package/components/tryghost-bootstrap-socket-5.21.0.tgz +0 -0
- package/components/tryghost-constants-5.21.0.tgz +0 -0
- package/components/tryghost-custom-theme-settings-service-5.21.0.tgz +0 -0
- package/components/tryghost-data-generator-5.21.0.tgz +0 -0
- package/components/tryghost-domain-events-5.21.0.tgz +0 -0
- package/components/tryghost-email-analytics-provider-mailgun-5.21.0.tgz +0 -0
- package/components/tryghost-email-analytics-service-5.21.0.tgz +0 -0
- package/components/tryghost-email-content-generator-5.21.0.tgz +0 -0
- package/components/tryghost-express-dynamic-redirects-5.21.0.tgz +0 -0
- package/components/tryghost-extract-api-key-5.21.0.tgz +0 -0
- package/components/tryghost-html-to-plaintext-5.21.0.tgz +0 -0
- package/components/{tryghost-job-manager-5.19.3.tgz → tryghost-job-manager-5.21.0.tgz} +0 -0
- package/components/tryghost-link-redirects-5.21.0.tgz +0 -0
- package/components/tryghost-link-replacer-5.21.0.tgz +0 -0
- package/components/tryghost-link-tracking-5.21.0.tgz +0 -0
- package/components/tryghost-magic-link-5.21.0.tgz +0 -0
- package/components/tryghost-mailgun-client-5.21.0.tgz +0 -0
- package/components/tryghost-member-analytics-service-5.21.0.tgz +0 -0
- package/components/tryghost-member-attribution-5.21.0.tgz +0 -0
- package/components/tryghost-member-events-5.21.0.tgz +0 -0
- package/components/tryghost-members-analytics-ingress-5.21.0.tgz +0 -0
- package/components/tryghost-members-api-5.21.0.tgz +0 -0
- package/components/tryghost-members-csv-5.21.0.tgz +0 -0
- package/components/tryghost-members-events-service-5.21.0.tgz +0 -0
- package/components/tryghost-members-importer-5.21.0.tgz +0 -0
- package/components/tryghost-members-offers-5.21.0.tgz +0 -0
- package/components/tryghost-members-payments-5.21.0.tgz +0 -0
- package/components/{tryghost-members-ssr-5.19.3.tgz → tryghost-members-ssr-5.21.0.tgz} +0 -0
- package/components/tryghost-members-stripe-service-5.21.0.tgz +0 -0
- package/components/tryghost-minifier-5.21.0.tgz +0 -0
- package/components/tryghost-mw-api-version-mismatch-5.21.0.tgz +0 -0
- package/components/tryghost-mw-cache-control-5.21.0.tgz +0 -0
- package/components/tryghost-mw-error-handler-5.21.0.tgz +0 -0
- package/components/tryghost-mw-session-from-token-5.21.0.tgz +0 -0
- package/components/tryghost-mw-update-user-last-seen-5.21.0.tgz +0 -0
- package/components/tryghost-mw-vhost-5.21.0.tgz +0 -0
- package/components/tryghost-oembed-service-5.21.0.tgz +0 -0
- package/components/{tryghost-package-json-5.19.3.tgz → tryghost-package-json-5.21.0.tgz} +0 -0
- package/components/tryghost-referrers-5.21.0.tgz +0 -0
- package/components/tryghost-security-5.21.0.tgz +0 -0
- package/components/tryghost-session-service-5.21.0.tgz +0 -0
- package/components/tryghost-settings-path-manager-5.21.0.tgz +0 -0
- package/components/tryghost-staff-service-5.21.0.tgz +0 -0
- package/components/tryghost-stats-service-5.21.0.tgz +0 -0
- package/components/tryghost-tiers-5.21.0.tgz +0 -0
- package/components/{tryghost-update-check-service-5.19.3.tgz → tryghost-update-check-service-5.21.0.tgz} +0 -0
- package/components/tryghost-verification-trigger-5.21.0.tgz +0 -0
- package/components/tryghost-version-notifications-data-service-5.21.0.tgz +0 -0
- package/core/boot.js +2 -0
- package/core/built/admin/assets/{chunk.143.c035c61595ed02eee886.js → chunk.143.9cddfa7bd1a8b9cf3d4b.js} +7 -7
- package/core/built/admin/assets/{chunk.178.998dfbcebcec635146b1.js → chunk.178.6de14cfdb28df721b66e.js} +4 -4
- package/core/built/admin/assets/{chunk.613.f1d519ad47e7f9024263.js → chunk.613.695f31829550fb00d43c.js} +352 -421
- package/core/built/admin/assets/{chunk.613.f1d519ad47e7f9024263.js.LICENSE.txt → chunk.613.695f31829550fb00d43c.js.LICENSE.txt} +0 -0
- package/core/built/admin/assets/{ghost-5ce6f5a730c83c91fc258b12c537ea35.js → ghost-192fee3b46a193df1e65c49a67a7d694.js} +2866 -2707
- package/core/built/admin/assets/ghost-9873519a8ad69b5b23284f0a9e050bc6.css +1 -0
- package/core/built/admin/assets/ghost-dark-190bdce42b125c3d4be930bd7599b442.css +1 -0
- package/core/built/admin/assets/{vendor-5c7d7063620bec13668c4370145cd4b4.js → vendor-26cca1d4d56660dc6e915a12ccc3b330.js} +1079 -1032
- package/core/built/admin/index.html +7 -7
- package/core/cli/generate-data.js +51 -0
- package/core/frontend/helpers/ghost_head.js +1 -1
- package/core/server/api/endpoints/links.js +34 -1
- package/core/server/api/endpoints/members.js +1 -4
- package/core/server/api/endpoints/posts-public.js +1 -1
- package/core/server/api/endpoints/posts.js +2 -1
- package/core/server/api/endpoints/tiers-public.js +2 -14
- package/core/server/api/endpoints/tiers.js +5 -51
- package/core/server/api/endpoints/utils/serializers/input/posts.js +21 -1
- package/core/server/api/endpoints/utils/serializers/input/settings.js +1 -0
- package/core/server/api/endpoints/utils/serializers/input/tiers.js +18 -27
- package/core/server/api/endpoints/utils/serializers/output/index.js +4 -0
- package/core/server/api/endpoints/utils/serializers/output/links.js +5 -0
- package/core/server/api/endpoints/utils/serializers/output/mappers/activity-feed-events.js +89 -15
- package/core/server/api/endpoints/utils/serializers/output/mappers/posts.js +20 -6
- package/core/server/api/endpoints/utils/serializers/output/mappers/snippets.js +2 -2
- package/core/server/api/endpoints/utils/serializers/output/members.js +6 -5
- package/core/server/api/endpoints/utils/serializers/output/tiers.js +15 -55
- package/core/server/data/db/backup.js +17 -10
- package/core/server/data/importer/importers/data/custom-theme-settings.js +81 -0
- package/core/server/data/importer/importers/data/data-importer.js +2 -0
- package/core/server/data/migrations/utils/permissions.js +35 -24
- package/core/server/data/migrations/versions/5.20/2022-10-18-05-39-drop-nullable-tier-id.js +3 -0
- package/core/server/data/migrations/versions/5.20/2022-10-18-10-13-add-ghost-subscription-id-column-to-mscs.js +10 -0
- package/core/server/data/migrations/versions/5.20/2022-10-19-11-17-add-link-browse-permissions.js +10 -0
- package/core/server/data/migrations/versions/5.20/2022-10-20-02-52-add-link-edit-permissions.js +10 -0
- package/core/server/data/migrations/versions/5.21/2022-10-24-07-23-disable-feedback-enabled.js +20 -0
- package/core/server/data/migrations/versions/5.21/2022-10-25-12-05-backfill-missed-products-columns.js +35 -0
- package/core/server/data/migrations/versions/5.21/2022-10-26-04-49-add-batch-id-members-created-events.js +7 -0
- package/core/server/data/migrations/versions/5.21/2022-10-26-04-49-add-batch-id-subscription-created-events.js +7 -0
- package/core/server/data/migrations/versions/5.21/2022-10-26-04-50-member-subscription-created-batch-id.js +72 -0
- package/core/server/data/migrations/versions/5.21/2022-10-26-09-32-add-feedback-enabled-column-to-emails.js +7 -0
- package/core/server/data/migrations/versions/5.21/2022-10-27-09-50-add-member-track-source-setting.js +8 -0
- package/core/server/data/schema/commands.js +107 -48
- package/core/server/data/schema/default-settings/default-settings.json +8 -0
- package/core/server/data/schema/fixtures/fixture-manager.js +16 -14
- package/core/server/data/schema/fixtures/fixtures.json +14 -2
- package/core/server/data/schema/schema.js +7 -3
- package/core/server/models/base/plugins/actions.js +1 -1
- package/core/server/models/base/plugins/crud.js +12 -0
- package/core/server/models/email-recipient.js +14 -0
- package/core/server/models/email.js +2 -5
- package/core/server/models/member-click-event.js +37 -0
- package/core/server/models/member-created-event.js +23 -0
- package/core/server/models/member-paid-subscription-event.js +19 -0
- package/core/server/models/member.js +6 -0
- package/core/server/models/post.js +33 -2
- package/core/server/models/redirect.js +1 -0
- package/core/server/models/subscription-created-event.js +7 -0
- package/core/server/services/audience-feedback/index.js +2 -0
- package/core/server/services/link-redirection/LinkRedirectRepository.js +16 -5
- package/core/server/services/link-tracking/PostLinkRepository.js +26 -2
- package/core/server/services/link-tracking/index.js +3 -1
- package/core/server/services/mega/feedback-buttons.js +87 -16
- package/core/server/services/mega/mega.js +1 -0
- package/core/server/services/mega/template.js +3 -0
- package/core/server/services/member-attribution/index.js +3 -1
- package/core/server/services/members/api.js +4 -1
- package/core/server/services/members/service.js +8 -1
- package/core/server/services/newsletters/index.js +3 -1
- package/core/server/services/newsletters/service.js +11 -1
- package/core/server/services/tiers/TierRepository.js +116 -0
- package/core/server/services/tiers/index.js +1 -0
- package/core/server/services/tiers/service.js +32 -0
- package/core/server/services/url/UrlGenerator.js +4 -2
- package/core/server/web/api/endpoints/admin/routes.js +1 -0
- package/core/shared/config/defaults.json +1 -1
- package/core/shared/labs.js +7 -8
- package/ghost.js +1 -0
- package/package.json +117 -113
- package/yarn.lock +1187 -1129
- package/components/tryghost-adapter-manager-5.19.3.tgz +0 -0
- package/components/tryghost-api-version-compatibility-service-5.19.3.tgz +0 -0
- package/components/tryghost-audience-feedback-5.19.3.tgz +0 -0
- package/components/tryghost-bootstrap-socket-5.19.3.tgz +0 -0
- package/components/tryghost-constants-5.19.3.tgz +0 -0
- package/components/tryghost-custom-theme-settings-service-5.19.3.tgz +0 -0
- package/components/tryghost-domain-events-5.19.3.tgz +0 -0
- package/components/tryghost-email-analytics-provider-mailgun-5.19.3.tgz +0 -0
- package/components/tryghost-email-analytics-service-5.19.3.tgz +0 -0
- package/components/tryghost-email-content-generator-5.19.3.tgz +0 -0
- package/components/tryghost-express-dynamic-redirects-5.19.3.tgz +0 -0
- package/components/tryghost-extract-api-key-5.19.3.tgz +0 -0
- package/components/tryghost-html-to-plaintext-5.19.3.tgz +0 -0
- package/components/tryghost-link-redirects-5.19.3.tgz +0 -0
- package/components/tryghost-link-replacer-5.19.3.tgz +0 -0
- package/components/tryghost-link-tracking-5.19.3.tgz +0 -0
- package/components/tryghost-magic-link-5.19.3.tgz +0 -0
- package/components/tryghost-mailgun-client-5.19.3.tgz +0 -0
- package/components/tryghost-member-analytics-service-5.19.3.tgz +0 -0
- package/components/tryghost-member-attribution-5.19.3.tgz +0 -0
- package/components/tryghost-member-events-5.19.3.tgz +0 -0
- package/components/tryghost-members-analytics-ingress-5.19.3.tgz +0 -0
- package/components/tryghost-members-api-5.19.3.tgz +0 -0
- package/components/tryghost-members-csv-5.19.3.tgz +0 -0
- package/components/tryghost-members-events-service-5.19.3.tgz +0 -0
- package/components/tryghost-members-importer-5.19.3.tgz +0 -0
- package/components/tryghost-members-offers-5.19.3.tgz +0 -0
- package/components/tryghost-members-payments-5.19.3.tgz +0 -0
- package/components/tryghost-members-stripe-service-5.19.3.tgz +0 -0
- package/components/tryghost-minifier-5.19.3.tgz +0 -0
- package/components/tryghost-mw-api-version-mismatch-5.19.3.tgz +0 -0
- package/components/tryghost-mw-cache-control-5.19.3.tgz +0 -0
- package/components/tryghost-mw-error-handler-5.19.3.tgz +0 -0
- package/components/tryghost-mw-session-from-token-5.19.3.tgz +0 -0
- package/components/tryghost-mw-update-user-last-seen-5.19.3.tgz +0 -0
- package/components/tryghost-mw-vhost-5.19.3.tgz +0 -0
- package/components/tryghost-oembed-service-5.19.3.tgz +0 -0
- package/components/tryghost-referrers-5.19.3.tgz +0 -0
- package/components/tryghost-security-5.19.3.tgz +0 -0
- package/components/tryghost-session-service-5.19.3.tgz +0 -0
- package/components/tryghost-settings-path-manager-5.19.3.tgz +0 -0
- package/components/tryghost-staff-service-5.19.3.tgz +0 -0
- package/components/tryghost-stats-service-5.19.3.tgz +0 -0
- package/components/tryghost-verification-trigger-5.19.3.tgz +0 -0
- package/components/tryghost-version-notifications-data-service-5.19.3.tgz +0 -0
- package/core/built/admin/assets/ghost-982146a4ada3a5af1981d1919ae01d08.css +0 -1
- package/core/built/admin/assets/ghost-dark-41929e4857de411a23597a9de49a4e4f.css +0 -1
|
@@ -76,11 +76,12 @@ function bulkAction(bulkActionResult, _apiConfig, frame) {
|
|
|
76
76
|
|
|
77
77
|
/**
|
|
78
78
|
*
|
|
79
|
-
* @returns {{events: any[]}}
|
|
79
|
+
* @returns {{events: any[], meta: any}}
|
|
80
80
|
*/
|
|
81
81
|
function activityFeed(data, _apiConfig, frame) {
|
|
82
82
|
return {
|
|
83
|
-
events: data.events.map(e => mappers.activityFeedEvents(e, frame))
|
|
83
|
+
events: data.events.map(e => mappers.activityFeedEvents(e, frame)),
|
|
84
|
+
meta: data.meta
|
|
84
85
|
};
|
|
85
86
|
}
|
|
86
87
|
|
|
@@ -216,15 +217,15 @@ function createSerializer(debugString, serialize) {
|
|
|
216
217
|
* @prop {string} id
|
|
217
218
|
* @prop {string} uuid
|
|
218
219
|
* @prop {string} email
|
|
219
|
-
* @prop {string
|
|
220
|
-
* @prop {string
|
|
220
|
+
* @prop {string} [name]
|
|
221
|
+
* @prop {string} [note]
|
|
221
222
|
* @prop {null|string} geolocation
|
|
222
223
|
* @prop {boolean} subscribed
|
|
223
224
|
* @prop {string} created_at
|
|
224
225
|
* @prop {string} updated_at
|
|
225
226
|
* @prop {string[]} labels
|
|
226
227
|
* @prop {SerializedMemberStripeSubscription[]} subscriptions
|
|
227
|
-
* @prop {SerializedMemberProduct[]
|
|
228
|
+
* @prop {SerializedMemberProduct[]} [products]
|
|
228
229
|
* @prop {string} avatar_image
|
|
229
230
|
* @prop {boolean} comped
|
|
230
231
|
* @prop {number} email_count
|
|
@@ -1,11 +1,6 @@
|
|
|
1
1
|
//@ts-check
|
|
2
2
|
const debug = require('@tryghost/debug')('api:endpoints:utils:serializers:output:tiers');
|
|
3
3
|
|
|
4
|
-
const allowedIncludes = ['monthly_price', 'yearly_price'];
|
|
5
|
-
const localUtils = require('../../index');
|
|
6
|
-
const {utils} = require('@tryghost/api-framework');
|
|
7
|
-
const labs = require('../../../../../../shared/labs');
|
|
8
|
-
|
|
9
4
|
module.exports = {
|
|
10
5
|
browse: createSerializer('browse', paginatedTiers),
|
|
11
6
|
read: createSerializer('read', singleTier),
|
|
@@ -49,11 +44,10 @@ function singleTier(model, _apiConfig, frame) {
|
|
|
49
44
|
/**
|
|
50
45
|
* @param {import('bookshelf').Model} tier
|
|
51
46
|
* @param {object} options
|
|
52
|
-
* @param {object} frame
|
|
53
47
|
*
|
|
54
48
|
* @returns {SerializedTier}
|
|
55
49
|
*/
|
|
56
|
-
function serializeTier(tier, options
|
|
50
|
+
function serializeTier(tier, options) {
|
|
57
51
|
const json = tier.toJSON(options);
|
|
58
52
|
|
|
59
53
|
const serialized = {
|
|
@@ -61,66 +55,32 @@ function serializeTier(tier, options, frame) {
|
|
|
61
55
|
name: json.name,
|
|
62
56
|
description: json.description,
|
|
63
57
|
slug: json.slug,
|
|
64
|
-
active: json.active,
|
|
58
|
+
active: json.status === 'active',
|
|
65
59
|
type: json.type,
|
|
66
|
-
welcome_page_url: json.
|
|
67
|
-
created_at: json.
|
|
68
|
-
updated_at: json.
|
|
60
|
+
welcome_page_url: json.welcomePageURL,
|
|
61
|
+
created_at: json.createdAt,
|
|
62
|
+
updated_at: json.updatedAt,
|
|
69
63
|
visibility: json.visibility,
|
|
70
|
-
benefits:
|
|
64
|
+
benefits: json.benefits,
|
|
65
|
+
currency: json.currency,
|
|
66
|
+
monthly_price: json.monthlyPrice,
|
|
67
|
+
yearly_price: json.yearlyPrice,
|
|
68
|
+
trial_days: json.trialDays
|
|
71
69
|
};
|
|
72
70
|
|
|
73
|
-
if (
|
|
74
|
-
serialized.trial_days = json.trial_days;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
if (Array.isArray(json.benefits)) {
|
|
78
|
-
serialized.benefits = json.benefits.map(benefit => benefit.name);
|
|
79
|
-
} else {
|
|
71
|
+
if (!Array.isArray(serialized.benefits)) {
|
|
80
72
|
serialized.benefits = null;
|
|
81
73
|
}
|
|
82
74
|
|
|
83
|
-
if (serialized.type === '
|
|
84
|
-
serialized.currency
|
|
85
|
-
serialized.monthly_price
|
|
86
|
-
serialized.yearly_price
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
if (!localUtils.isContentAPI(frame)) {
|
|
90
|
-
const requestedQueryIncludes = frame.original && frame.original.query && frame.original.query.include && frame.original.query.include.split(',') || [];
|
|
91
|
-
const requestedOptionsIncludes = utils.options.trimAndLowerCase(frame.original && frame.original.options && frame.original.options.include || []);
|
|
92
|
-
|
|
93
|
-
return cleanIncludes(
|
|
94
|
-
allowedIncludes,
|
|
95
|
-
requestedQueryIncludes.concat(requestedOptionsIncludes),
|
|
96
|
-
serialized
|
|
97
|
-
);
|
|
75
|
+
if (serialized.type === 'free') {
|
|
76
|
+
delete serialized.currency;
|
|
77
|
+
delete serialized.monthly_price;
|
|
78
|
+
delete serialized.yearly_price;
|
|
98
79
|
}
|
|
99
80
|
|
|
100
81
|
return serialized;
|
|
101
82
|
}
|
|
102
83
|
|
|
103
|
-
/**
|
|
104
|
-
* @template Data
|
|
105
|
-
*
|
|
106
|
-
* @param {string[]} allowed
|
|
107
|
-
* @param {string[]} requested
|
|
108
|
-
* @param {Data & Object<string, any>} data
|
|
109
|
-
*
|
|
110
|
-
* @returns {Data}
|
|
111
|
-
*/
|
|
112
|
-
function cleanIncludes(allowed, requested, data) {
|
|
113
|
-
const cleaned = {
|
|
114
|
-
...data
|
|
115
|
-
};
|
|
116
|
-
for (const include of allowed) {
|
|
117
|
-
if (!requested.includes(include)) {
|
|
118
|
-
delete cleaned[include];
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
return cleaned;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
84
|
/**
|
|
125
85
|
* @template Data
|
|
126
86
|
* @template Response
|
|
@@ -9,12 +9,21 @@ const logging = require('@tryghost/logging');
|
|
|
9
9
|
const urlUtils = require('../../../shared/url-utils');
|
|
10
10
|
const exporter = require('../exporter');
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
/**
|
|
13
|
+
* @param {object} exportResult
|
|
14
|
+
* @param {string} exportResult.filename
|
|
15
|
+
* @param {object} exportResult.data
|
|
16
|
+
*/
|
|
17
|
+
const writeExportFile = async (exportResult) => {
|
|
13
18
|
const filename = path.resolve(urlUtils.urlJoin(config.get('paths').contentPath, 'data', exportResult.filename));
|
|
14
19
|
|
|
15
|
-
|
|
20
|
+
await fs.writeFile(filename, JSON.stringify(exportResult.data));
|
|
21
|
+
return filename;
|
|
16
22
|
};
|
|
17
23
|
|
|
24
|
+
/**
|
|
25
|
+
* @param {string} filename
|
|
26
|
+
*/
|
|
18
27
|
const readBackup = async (filename) => {
|
|
19
28
|
const parsedFileName = path.parse(filename);
|
|
20
29
|
const sanitized = `${parsedFileName.name}${parsedFileName.ext}`;
|
|
@@ -35,21 +44,19 @@ const readBackup = async (filename) => {
|
|
|
35
44
|
* does an export, and stores this in a local file
|
|
36
45
|
* @returns {Promise<*>}
|
|
37
46
|
*/
|
|
38
|
-
const backup = function backup(options) {
|
|
47
|
+
const backup = async function backup(options = {}) {
|
|
39
48
|
logging.info('Creating database backup');
|
|
40
|
-
options = options || {};
|
|
41
49
|
|
|
42
50
|
const props = {
|
|
43
51
|
data: exporter.doExport(options),
|
|
44
52
|
filename: exporter.fileName(options)
|
|
45
53
|
};
|
|
46
54
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
});
|
|
55
|
+
const exportResult = await Promise.props(props);
|
|
56
|
+
const filename = await writeExportFile(exportResult);
|
|
57
|
+
|
|
58
|
+
logging.info('Database backup written to: ' + filename);
|
|
59
|
+
return filename;
|
|
53
60
|
};
|
|
54
61
|
|
|
55
62
|
module.exports = {
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
const _ = require('lodash');
|
|
2
|
+
const Promise = require('bluebird');
|
|
3
|
+
const debug = require('@tryghost/debug')('importer:roles');
|
|
4
|
+
const BaseImporter = require('./base');
|
|
5
|
+
const models = require('../../../../models');
|
|
6
|
+
const {activate} = require('../../../../services/themes/activate');
|
|
7
|
+
|
|
8
|
+
class CustomThemeSettingsImporter extends BaseImporter {
|
|
9
|
+
constructor(allDataFromFile) {
|
|
10
|
+
super(allDataFromFile, {
|
|
11
|
+
modelName: 'CustomThemeSetting',
|
|
12
|
+
dataKeyToImport: 'custom_theme_settings'
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
beforeImport() {
|
|
17
|
+
debug('beforeImport');
|
|
18
|
+
return super.beforeImport();
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
doImport(options, importOptions) {
|
|
22
|
+
debug('doImport', this.modelName, this.dataToImport.length);
|
|
23
|
+
|
|
24
|
+
let ops = [];
|
|
25
|
+
|
|
26
|
+
_.each(this.dataToImport, (item) => {
|
|
27
|
+
ops.push(models.CustomThemeSetting.findOne({theme: item.theme, key: item.key}, options)
|
|
28
|
+
.then((setting) => {
|
|
29
|
+
if (_.isObject(item.value)) {
|
|
30
|
+
item.value = JSON.stringify(item.value);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (setting) {
|
|
34
|
+
setting.set('value', item.value);
|
|
35
|
+
if (setting.hasChanged()) {
|
|
36
|
+
return setting.save(null, options)
|
|
37
|
+
.then((importedModel) => {
|
|
38
|
+
if (importOptions.returnImportedData) {
|
|
39
|
+
this.importedDataToReturn.push(importedModel.toJSON());
|
|
40
|
+
}
|
|
41
|
+
return importedModel;
|
|
42
|
+
})
|
|
43
|
+
.catch((err) => {
|
|
44
|
+
return this.handleError(err, item);
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return Promise.resolve();
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return models.CustomThemeSetting.add(item, options)
|
|
52
|
+
.then((importedModel) => {
|
|
53
|
+
if (importOptions.returnImportedData) {
|
|
54
|
+
this.importedDataToReturn.push(importedModel.toJSON());
|
|
55
|
+
}
|
|
56
|
+
return importedModel;
|
|
57
|
+
})
|
|
58
|
+
.catch((err) => {
|
|
59
|
+
return this.handleError(err, item);
|
|
60
|
+
});
|
|
61
|
+
})
|
|
62
|
+
.reflect());
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
const opsPromise = Promise.all(ops);
|
|
66
|
+
|
|
67
|
+
// activate function is called to refresh cache when importing custom theme settings for active theme
|
|
68
|
+
opsPromise.then(() => {
|
|
69
|
+
models.Settings.findOne({key: 'active_theme'})
|
|
70
|
+
.then((theme) => {
|
|
71
|
+
const currentTheme = theme.get('value');
|
|
72
|
+
if (this.dataToImport.some(themeSetting => themeSetting.theme === currentTheme)) {
|
|
73
|
+
activate(currentTheme);
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
return opsPromise;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
module.exports = CustomThemeSettingsImporter;
|
|
@@ -13,6 +13,7 @@ const NewslettersImporter = require('./newsletters');
|
|
|
13
13
|
const ProductsImporter = require('./products');
|
|
14
14
|
const StripeProductsImporter = require('./stripe-products');
|
|
15
15
|
const StripePricesImporter = require('./stripe-prices');
|
|
16
|
+
const CustomThemeSettingsImporter = require('./custom-theme-settings');
|
|
16
17
|
const RolesImporter = require('./roles');
|
|
17
18
|
let importers = {};
|
|
18
19
|
let DataImporter;
|
|
@@ -35,6 +36,7 @@ DataImporter = {
|
|
|
35
36
|
importers.stripe_products = new StripeProductsImporter(importData.data);
|
|
36
37
|
importers.stripe_prices = new StripePricesImporter(importData.data);
|
|
37
38
|
importers.posts = new PostsImporter(importData.data);
|
|
39
|
+
importers.custom_theme_settings = new CustomThemeSettingsImporter(importData.data);
|
|
38
40
|
|
|
39
41
|
return importData;
|
|
40
42
|
},
|
|
@@ -10,6 +10,10 @@ const messages = {
|
|
|
10
10
|
permissionRoleActionError: 'Cannot {action} permission({permission}) with role({role}) - {resource} does not exist'
|
|
11
11
|
};
|
|
12
12
|
|
|
13
|
+
/**
|
|
14
|
+
* @param {import('knex').Knex} connection
|
|
15
|
+
* @param {PermissionConfig} config
|
|
16
|
+
*/
|
|
13
17
|
async function addPermissionHelper(connection, config) {
|
|
14
18
|
const existingPermission = await connection('permissions').where({
|
|
15
19
|
name: config.name,
|
|
@@ -38,6 +42,10 @@ async function addPermissionHelper(connection, config) {
|
|
|
38
42
|
});
|
|
39
43
|
}
|
|
40
44
|
|
|
45
|
+
/**
|
|
46
|
+
* @param {import('knex').Knex} connection
|
|
47
|
+
* @param {PermissionConfig} config
|
|
48
|
+
*/
|
|
41
49
|
async function removePermissionHelper(connection, config) {
|
|
42
50
|
const existingPermission = await connection('permissions').where({
|
|
43
51
|
name: config.name,
|
|
@@ -61,10 +69,7 @@ async function removePermissionHelper(connection, config) {
|
|
|
61
69
|
/**
|
|
62
70
|
* Creates a migration which will add a permission to the database
|
|
63
71
|
*
|
|
64
|
-
* @param {
|
|
65
|
-
* @param {string} config.name - The name of the permission
|
|
66
|
-
* @param {string} config.action - The action_type of the permission
|
|
67
|
-
* @param {string} config.object - The object_type of the permission
|
|
72
|
+
* @param {PermissionConfig} config
|
|
68
73
|
*
|
|
69
74
|
* @returns {Migration}
|
|
70
75
|
*/
|
|
@@ -82,10 +87,7 @@ function addPermission(config) {
|
|
|
82
87
|
/**
|
|
83
88
|
* Creates a migration which will remove a permission from the database
|
|
84
89
|
*
|
|
85
|
-
* @param {
|
|
86
|
-
* @param {string} config.name - The name of the permission
|
|
87
|
-
* @param {string} config.action - The action_type of the permission
|
|
88
|
-
* @param {string} config.object - The object_type of the permission
|
|
90
|
+
* @param {PermissionConfig} config
|
|
89
91
|
*
|
|
90
92
|
* @returns {Migration}
|
|
91
93
|
*/
|
|
@@ -100,6 +102,10 @@ function removePermission(config) {
|
|
|
100
102
|
);
|
|
101
103
|
}
|
|
102
104
|
|
|
105
|
+
/**
|
|
106
|
+
* @param {import('knex').Knex} connection
|
|
107
|
+
* @param {PermissionRoleConfig} config
|
|
108
|
+
*/
|
|
103
109
|
async function addPermissionToRoleHelper(connection, config) {
|
|
104
110
|
const permission = await connection('permissions').where({
|
|
105
111
|
name: config.permission
|
|
@@ -149,6 +155,10 @@ async function addPermissionToRoleHelper(connection, config) {
|
|
|
149
155
|
});
|
|
150
156
|
}
|
|
151
157
|
|
|
158
|
+
/**
|
|
159
|
+
* @param {import('knex').Knex} connection
|
|
160
|
+
* @param {PermissionRoleConfig} config
|
|
161
|
+
*/
|
|
152
162
|
async function removePermissionFromRoleHelper(connection, config) {
|
|
153
163
|
const permission = await connection('permissions').where({
|
|
154
164
|
name: config.permission
|
|
@@ -188,9 +198,7 @@ async function removePermissionFromRoleHelper(connection, config) {
|
|
|
188
198
|
/**
|
|
189
199
|
* Creates a migration which will link a permission to a role in the database
|
|
190
200
|
*
|
|
191
|
-
* @param {
|
|
192
|
-
* @param {string} config.permission - The name of the permission
|
|
193
|
-
* @param {string} config.role - The name of the role
|
|
201
|
+
* @param {PermissionRoleConfig} config
|
|
194
202
|
*
|
|
195
203
|
* @returns {Migration}
|
|
196
204
|
*/
|
|
@@ -208,9 +216,7 @@ function addPermissionToRole(config) {
|
|
|
208
216
|
/**
|
|
209
217
|
* Creates a migration which will remove the permission from roles
|
|
210
218
|
*
|
|
211
|
-
* @param {
|
|
212
|
-
* @param {string} config.permission - The name of the permission
|
|
213
|
-
* @param {string} config.role - The name of the role
|
|
219
|
+
* @param {PermissionRoleConfig} config
|
|
214
220
|
*
|
|
215
221
|
* @returns {Migration}
|
|
216
222
|
*/
|
|
@@ -228,11 +234,7 @@ function removePermissionFromRole(config) {
|
|
|
228
234
|
/**
|
|
229
235
|
* Creates a migration which will add a permission to the database, and then link it to roles
|
|
230
236
|
*
|
|
231
|
-
* @param {
|
|
232
|
-
* @param {string} config.name - The name of the permission
|
|
233
|
-
* @param {string} config.action - The action_type of the permission
|
|
234
|
-
* @param {string} config.object - The object_type of the permission
|
|
235
|
-
*
|
|
237
|
+
* @param {PermissionConfig} config
|
|
236
238
|
* @param {string[]} roles - A list of role names
|
|
237
239
|
*
|
|
238
240
|
* @returns {Migration}
|
|
@@ -247,11 +249,7 @@ function addPermissionWithRoles(config, roles) {
|
|
|
247
249
|
/**
|
|
248
250
|
* Creates a migration which will remove permissions from roles, and then remove the permission
|
|
249
251
|
*
|
|
250
|
-
* @param {
|
|
251
|
-
* @param {string} config.name - The name of the permission
|
|
252
|
-
* @param {string} config.action - The action_type of the permission
|
|
253
|
-
* @param {string} config.object - The object_type of the permission
|
|
254
|
-
*
|
|
252
|
+
* @param {PermissionConfig} config
|
|
255
253
|
* @param {string[]} roles - A list of role names
|
|
256
254
|
*
|
|
257
255
|
* @returns {Migration}
|
|
@@ -270,6 +268,19 @@ module.exports = {
|
|
|
270
268
|
createRemovePermissionMigration
|
|
271
269
|
};
|
|
272
270
|
|
|
271
|
+
/**
|
|
272
|
+
* @typedef {Object} PermissionConfig
|
|
273
|
+
* @prop {string} config.name - The name of the permission
|
|
274
|
+
* @prop {string} config.action - The action_type of the permission
|
|
275
|
+
* @prop {string} config.object - The object_type of the permission
|
|
276
|
+
*/
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* @typedef {Object} PermissionRoleConfig
|
|
280
|
+
* @prop {string} config.permission - The name of the permission
|
|
281
|
+
* @prop {string} config.role - The role to assign the Permission to
|
|
282
|
+
*/
|
|
283
|
+
|
|
273
284
|
/**
|
|
274
285
|
* @typedef {Object} TransactionalMigrationFunctionOptions
|
|
275
286
|
*
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
const {createAddColumnMigration} = require('../../utils');
|
|
2
|
+
|
|
3
|
+
module.exports = createAddColumnMigration('members_stripe_customers_subscriptions', 'ghost_subscription_id', {
|
|
4
|
+
type: 'string',
|
|
5
|
+
maxlength: 24,
|
|
6
|
+
nullable: true,
|
|
7
|
+
references: 'subscriptions.id',
|
|
8
|
+
constraintName: 'mscs_ghost_subscription_id_foreign',
|
|
9
|
+
cascadeDelete: true
|
|
10
|
+
});
|
package/core/server/data/migrations/versions/5.21/2022-10-24-07-23-disable-feedback-enabled.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
const logging = require('@tryghost/logging');
|
|
2
|
+
const {createTransactionalMigration} = require('../../utils');
|
|
3
|
+
|
|
4
|
+
module.exports = createTransactionalMigration(
|
|
5
|
+
async function up(connection) {
|
|
6
|
+
const affectedRows = await connection('newsletters')
|
|
7
|
+
.update({
|
|
8
|
+
feedback_enabled: false
|
|
9
|
+
})
|
|
10
|
+
.where('feedback_enabled', true);
|
|
11
|
+
|
|
12
|
+
if (affectedRows > 0) {
|
|
13
|
+
// Only log if this site was affected by the issue.
|
|
14
|
+
logging.info(`Disabled feedback for ${affectedRows} newsletter(s)`);
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
async function down() {
|
|
18
|
+
// no-op: we don't need to change it back
|
|
19
|
+
}
|
|
20
|
+
);
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
const logging = require('@tryghost/logging');
|
|
2
|
+
const {createTransactionalMigration} = require('../../utils');
|
|
3
|
+
|
|
4
|
+
module.exports = createTransactionalMigration(
|
|
5
|
+
async function up(knex) {
|
|
6
|
+
logging.info(`Fixing currency/monthly_price/yearly_price values for default paid tiers`);
|
|
7
|
+
|
|
8
|
+
const currencyUpdated = await knex('products')
|
|
9
|
+
.update('currency', 'usd')
|
|
10
|
+
.where({
|
|
11
|
+
currency: null,
|
|
12
|
+
type: 'paid'
|
|
13
|
+
});
|
|
14
|
+
logging.info(`Updated ${currencyUpdated} tier(s) where currency=null, type=paid to currency=USD`);
|
|
15
|
+
|
|
16
|
+
const monthlyPriceUpdated = await knex('products')
|
|
17
|
+
.update('monthly_price', 500)
|
|
18
|
+
.where({
|
|
19
|
+
monthly_price: null,
|
|
20
|
+
type: 'paid'
|
|
21
|
+
});
|
|
22
|
+
logging.info(`Updated ${monthlyPriceUpdated} tier(s) where monthly_price=null, type=paid to monthly_price=500`);
|
|
23
|
+
|
|
24
|
+
const yearlyPriceUpdated = await knex('products')
|
|
25
|
+
.update('yearly_price', 5000)
|
|
26
|
+
.where({
|
|
27
|
+
yearly_price: null,
|
|
28
|
+
type: 'paid'
|
|
29
|
+
});
|
|
30
|
+
logging.info(`Updated ${yearlyPriceUpdated} tier(s) where yearly_price=null, type=paid to yearly_price=5000`);
|
|
31
|
+
},
|
|
32
|
+
async function down(/* knex */) {
|
|
33
|
+
// no-op: we don't want to revert to bad data
|
|
34
|
+
}
|
|
35
|
+
);
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
const _ = require('lodash');
|
|
2
|
+
const logging = require('@tryghost/logging');
|
|
3
|
+
const ObjectId = require('bson-objectid').default;
|
|
4
|
+
const {createTransactionalMigration} = require('../../utils');
|
|
5
|
+
const DatabaseInfo = require('@tryghost/database-info');
|
|
6
|
+
|
|
7
|
+
// This migration links together members_created_events and members_subscription_created_events
|
|
8
|
+
|
|
9
|
+
module.exports = createTransactionalMigration(
|
|
10
|
+
async function up(knex) {
|
|
11
|
+
if (DatabaseInfo.isSQLite(knex)) {
|
|
12
|
+
logging.info('Skipped linking members_created_events and members_subscription_created_events on SQLite');
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// All events that happened within 15 minutes of each other will be linked
|
|
17
|
+
const rows = await knex('members_created_events as m')
|
|
18
|
+
.select('m.id as m_id', 's.id as s_id', 'm.member_id as member_id', 's.subscription_id as subscription_id')
|
|
19
|
+
.join('members_subscription_created_events AS s', 's.member_id', 'm.member_id')
|
|
20
|
+
.whereRaw('TIMESTAMPDIFF(MINUTE, s.created_at, m.created_at) between -15 and 15');
|
|
21
|
+
|
|
22
|
+
if (!rows.length) {
|
|
23
|
+
logging.info('Did not find linkable members_created_events and members_subscription_created_events');
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Attach a unique id to each row
|
|
28
|
+
for (const row of rows) { // eslint-disable-line no-restricted-syntax
|
|
29
|
+
row.batch_id = ObjectId().toHexString();
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Create batches (insertBatch doesn't support the onConflict option)
|
|
33
|
+
const batches = _.chunk(rows, 1000);
|
|
34
|
+
|
|
35
|
+
for (const batch of batches) { // eslint-disable-line no-restricted-syntax
|
|
36
|
+
// Update the members_created_events table using INSERT ON DUPLICATE KEY UPDATE trick
|
|
37
|
+
const response1 = await knex('members_created_events').insert(batch.map((r) => {
|
|
38
|
+
return {
|
|
39
|
+
id: r.m_id,
|
|
40
|
+
batch_id: r.batch_id,
|
|
41
|
+
member_id: r.member_id, // added to make the insert work
|
|
42
|
+
source: '', // added to make the insert work
|
|
43
|
+
created_at: knex.raw('NOW()') // added to make the insert work
|
|
44
|
+
};
|
|
45
|
+
})).onConflict('id').merge(['batch_id']);
|
|
46
|
+
|
|
47
|
+
if (response1[0] !== 0) {
|
|
48
|
+
logging.error(`Inserted ${response1[0]} members_created_events, expected 0`);
|
|
49
|
+
throw new Error('Rolling back');
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const response2 = await knex('members_subscription_created_events').insert(batch.map((r) => {
|
|
53
|
+
return {
|
|
54
|
+
id: r.s_id,
|
|
55
|
+
batch_id: r.batch_id,
|
|
56
|
+
member_id: r.member_id, // added to make the insert work
|
|
57
|
+
subscription_id: r.subscription_id, // added to make the insert work
|
|
58
|
+
created_at: knex.raw('NOW()') // added to make the insert work
|
|
59
|
+
};
|
|
60
|
+
})).onConflict('id').merge(['batch_id']);
|
|
61
|
+
|
|
62
|
+
if (response2[0] !== 0) {
|
|
63
|
+
logging.error(`Inserted ${response1[0]} members_subscription_created_events, expected 0`);
|
|
64
|
+
throw new Error('Rolling back');
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
logging.info(`Linked ${rows.length} members_created_events and members_subscription_created_events`);
|
|
68
|
+
},
|
|
69
|
+
async function down() {
|
|
70
|
+
// noop
|
|
71
|
+
}
|
|
72
|
+
);
|