ghost 5.20.0 → 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.20.0.tgz → tryghost-adapter-manager-5.21.0.tgz} +0 -0
- package/components/{tryghost-api-framework-5.20.0.tgz → tryghost-api-framework-5.21.0.tgz} +0 -0
- package/components/{tryghost-api-version-compatibility-service-5.20.0.tgz → 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.20.0.tgz → tryghost-bootstrap-socket-5.21.0.tgz} +0 -0
- package/components/{tryghost-constants-5.20.0.tgz → 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.20.0.tgz → 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.20.0.tgz → tryghost-email-content-generator-5.21.0.tgz} +0 -0
- package/components/{tryghost-express-dynamic-redirects-5.20.0.tgz → 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.20.0.tgz → tryghost-html-to-plaintext-5.21.0.tgz} +0 -0
- package/components/{tryghost-job-manager-5.20.0.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.20.0.tgz → 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.20.0.tgz → 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.20.0.tgz → 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.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.20.0.tgz → 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.20.0.tgz → tryghost-mw-session-from-token-5.21.0.tgz} +0 -0
- package/components/{tryghost-mw-update-user-last-seen-5.20.0.tgz → 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.20.0.tgz → tryghost-oembed-service-5.21.0.tgz} +0 -0
- package/components/tryghost-package-json-5.21.0.tgz +0 -0
- package/components/tryghost-referrers-5.21.0.tgz +0 -0
- package/components/{tryghost-security-5.20.0.tgz → tryghost-security-5.21.0.tgz} +0 -0
- package/components/{tryghost-session-service-5.20.0.tgz → 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.20.0.tgz → tryghost-staff-service-5.21.0.tgz} +0 -0
- package/components/{tryghost-stats-service-5.20.0.tgz → 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.21.0.tgz +0 -0
- package/components/{tryghost-verification-trigger-5.20.0.tgz → 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.d245b085ad1efed4ee76.js → chunk.143.9cddfa7bd1a8b9cf3d4b.js} +5 -5
- package/core/built/admin/assets/{chunk.178.c45f56ea31775e509497.js → chunk.178.6de14cfdb28df721b66e.js} +4 -4
- package/core/built/admin/assets/{chunk.613.c4d89dc2d28c1b20348f.js → chunk.613.695f31829550fb00d43c.js} +351 -420
- package/core/built/admin/assets/{chunk.613.c4d89dc2d28c1b20348f.js.LICENSE.txt → chunk.613.695f31829550fb00d43c.js.LICENSE.txt} +0 -0
- package/core/built/admin/assets/{ghost-07e4bbf5029630b3c8a8a50c4b9f2d9e.js → ghost-192fee3b46a193df1e65c49a67a7d694.js} +308 -237
- 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-518b03b02df9a55706d150627ef1004f.js → vendor-26cca1d4d56660dc6e915a12ccc3b330.js} +1038 -1003
- package/core/built/admin/index.html +6 -6
- package/core/cli/generate-data.js +51 -0
- package/core/frontend/helpers/ghost_head.js +1 -1
- package/core/server/api/endpoints/links.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 +1 -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/mappers/activity-feed-events.js +42 -0
- package/core/server/api/endpoints/utils/serializers/output/mappers/posts.js +5 -4
- 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/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/default-settings/default-settings.json +8 -0
- package/core/server/data/schema/fixtures/fixture-manager.js +16 -14
- package/core/server/data/schema/schema.js +5 -2
- package/core/server/models/base/plugins/crud.js +12 -0
- package/core/server/models/email.js +1 -0
- package/core/server/models/member-click-event.js +13 -0
- package/core/server/models/member-created-event.js +23 -0
- package/core/server/models/member-paid-subscription-event.js +4 -0
- package/core/server/models/member.js +6 -0
- package/core/server/models/post.js +1 -1
- package/core/server/models/subscription-created-event.js +7 -0
- 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 +2 -0
- 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/shared/config/defaults.json +1 -1
- package/core/shared/labs.js +6 -7
- package/ghost.js +1 -0
- package/package.json +115 -112
- package/yarn.lock +1170 -1097
- package/components/tryghost-audience-feedback-5.20.0.tgz +0 -0
- package/components/tryghost-custom-theme-settings-service-5.20.0.tgz +0 -0
- package/components/tryghost-email-analytics-provider-mailgun-5.20.0.tgz +0 -0
- package/components/tryghost-email-analytics-service-5.20.0.tgz +0 -0
- package/components/tryghost-extract-api-key-5.20.0.tgz +0 -0
- package/components/tryghost-link-redirects-5.20.0.tgz +0 -0
- package/components/tryghost-link-replacer-5.20.0.tgz +0 -0
- package/components/tryghost-link-tracking-5.20.0.tgz +0 -0
- package/components/tryghost-mailgun-client-5.20.0.tgz +0 -0
- package/components/tryghost-member-analytics-service-5.20.0.tgz +0 -0
- package/components/tryghost-member-attribution-5.20.0.tgz +0 -0
- package/components/tryghost-member-events-5.20.0.tgz +0 -0
- package/components/tryghost-members-api-5.20.0.tgz +0 -0
- package/components/tryghost-members-csv-5.20.0.tgz +0 -0
- package/components/tryghost-members-events-service-5.20.0.tgz +0 -0
- package/components/tryghost-members-importer-5.20.0.tgz +0 -0
- package/components/tryghost-members-payments-5.20.0.tgz +0 -0
- package/components/tryghost-members-ssr-5.20.0.tgz +0 -0
- package/components/tryghost-members-stripe-service-5.20.0.tgz +0 -0
- package/components/tryghost-minifier-5.20.0.tgz +0 -0
- package/components/tryghost-mw-cache-control-5.20.0.tgz +0 -0
- package/components/tryghost-mw-error-handler-5.20.0.tgz +0 -0
- package/components/tryghost-mw-vhost-5.20.0.tgz +0 -0
- package/components/tryghost-package-json-5.20.0.tgz +0 -0
- package/components/tryghost-referrers-5.20.0.tgz +0 -0
- package/components/tryghost-settings-path-manager-5.20.0.tgz +0 -0
- package/components/tryghost-tiers-5.20.0.tgz +0 -0
- package/components/tryghost-update-check-service-5.20.0.tgz +0 -0
- package/components/tryghost-version-notifications-data-service-5.20.0.tgz +0 -0
- package/core/built/admin/assets/ghost-dark-363185f15c782b4b8394c5db23984e7f.css +0 -1
- package/core/built/admin/assets/ghost-fd0480352bf27e013b2b00a1bf9ffe84.css +0 -1
|
@@ -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.21%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-9873519a8ad69b5b23284f0a9e050bc6.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-26cca1d4d56660dc6e915a12ccc3b330.js"></script>
|
|
60
|
+
<script src="assets/chunk.613.695f31829550fb00d43c.js"></script>
|
|
61
|
+
<script src="assets/chunk.143.9cddfa7bd1a8b9cf3d4b.js"></script>
|
|
62
|
+
<script src="assets/ghost-192fee3b46a193df1e65c49a67a7d694.js"></script>
|
|
63
63
|
</body>
|
|
64
64
|
</html>
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
const Command = require('./command');
|
|
2
|
+
const DataGenerator = require('@tryghost/data-generator');
|
|
3
|
+
|
|
4
|
+
module.exports = class REPL extends Command {
|
|
5
|
+
setup() {
|
|
6
|
+
this.help('Generates random data to populate the database for development & testing');
|
|
7
|
+
this.argument('--use-base-data', {type: 'boolean', defaultValue: false, desc: 'Only generate data outside of a defined base data set'});
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
initializeContext(context) {
|
|
11
|
+
const models = require('../server/models');
|
|
12
|
+
const knex = require('../server/data/db/connection');
|
|
13
|
+
|
|
14
|
+
models.init();
|
|
15
|
+
|
|
16
|
+
context.models = models;
|
|
17
|
+
context.m = models;
|
|
18
|
+
context.knex = knex;
|
|
19
|
+
context.k = knex;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
permittedEnvironments() {
|
|
23
|
+
return ['development', 'local', 'staging', 'production'];
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
async handle(argv = {}) {
|
|
27
|
+
const knex = require('../server/data/db/connection');
|
|
28
|
+
const {tables: schema} = require('../server/data/schema/index');
|
|
29
|
+
const dataGenerator = new DataGenerator({
|
|
30
|
+
useBaseData: argv['use-base-data'],
|
|
31
|
+
knex,
|
|
32
|
+
schema,
|
|
33
|
+
logger: {
|
|
34
|
+
log: this.log,
|
|
35
|
+
ok: this.ok,
|
|
36
|
+
info: this.info,
|
|
37
|
+
warn: this.warn,
|
|
38
|
+
error: this.error,
|
|
39
|
+
fatal: this.fatal,
|
|
40
|
+
debug: this.debug
|
|
41
|
+
},
|
|
42
|
+
modelQuantities: {}
|
|
43
|
+
});
|
|
44
|
+
try {
|
|
45
|
+
await dataGenerator.importData();
|
|
46
|
+
} catch (error) {
|
|
47
|
+
this.fatal('Failed while generating data: ', error);
|
|
48
|
+
}
|
|
49
|
+
knex.destroy();
|
|
50
|
+
}
|
|
51
|
+
};
|
|
@@ -234,7 +234,7 @@ module.exports = async function ghost_head(options) { // eslint-disable-line cam
|
|
|
234
234
|
head.push(`<script defer src="${getAssetUrl('public/comment-counts.min.js')}" data-ghost-comments-counts-api="${urlUtils.getSiteUrl(true)}members/api/comments/counts/"></script>`);
|
|
235
235
|
}
|
|
236
236
|
|
|
237
|
-
if (settingsCache.get('members_enabled')) {
|
|
237
|
+
if (settingsCache.get('members_enabled') && settingsCache.get('members_track_sources')) {
|
|
238
238
|
head.push(`<script defer src="${getAssetUrl('public/member-attribution.min.js')}"></script>`);
|
|
239
239
|
}
|
|
240
240
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
const linkTrackingService = require('../../services/link-tracking');
|
|
2
|
+
const INVALIDATE_ALL_REDIRECTS = '/r/*';
|
|
2
3
|
|
|
3
4
|
module.exports = {
|
|
4
5
|
docName: 'links',
|
|
@@ -25,7 +26,7 @@ module.exports = {
|
|
|
25
26
|
bulkEdit: {
|
|
26
27
|
statusCode: 200,
|
|
27
28
|
headers: {
|
|
28
|
-
cacheInvalidate:
|
|
29
|
+
cacheInvalidate: INVALIDATE_ALL_REDIRECTS
|
|
29
30
|
},
|
|
30
31
|
options: [
|
|
31
32
|
'filter'
|
|
@@ -1,8 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
// as it is a getter and may change during runtime.
|
|
3
|
-
const membersService = require('../../services/members');
|
|
4
|
-
|
|
5
|
-
const allowedIncludes = ['monthly_price', 'yearly_price', 'benefits'];
|
|
1
|
+
const tiersService = require('../../services/tiers');
|
|
6
2
|
|
|
7
3
|
module.exports = {
|
|
8
4
|
docName: 'tiers',
|
|
@@ -11,22 +7,14 @@ module.exports = {
|
|
|
11
7
|
options: [
|
|
12
8
|
'limit',
|
|
13
9
|
'fields',
|
|
14
|
-
'include',
|
|
15
10
|
'filter',
|
|
16
11
|
'order',
|
|
17
12
|
'debug',
|
|
18
13
|
'page'
|
|
19
14
|
],
|
|
20
15
|
permissions: true,
|
|
21
|
-
validation: {
|
|
22
|
-
options: {
|
|
23
|
-
include: {
|
|
24
|
-
values: allowedIncludes
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
},
|
|
28
16
|
async query(frame) {
|
|
29
|
-
const page = await
|
|
17
|
+
const page = await tiersService.api.browse(frame.options);
|
|
30
18
|
|
|
31
19
|
return page;
|
|
32
20
|
}
|
|
@@ -1,13 +1,4 @@
|
|
|
1
|
-
const
|
|
2
|
-
const membersService = require('../../services/members');
|
|
3
|
-
|
|
4
|
-
const tpl = require('@tryghost/tpl');
|
|
5
|
-
|
|
6
|
-
const allowedIncludes = ['monthly_price', 'yearly_price', 'benefits'];
|
|
7
|
-
|
|
8
|
-
const messages = {
|
|
9
|
-
productNotFound: 'Tier not found.'
|
|
10
|
-
};
|
|
1
|
+
const tiersService = require('../../services/tiers');
|
|
11
2
|
|
|
12
3
|
module.exports = {
|
|
13
4
|
docName: 'tiers',
|
|
@@ -16,7 +7,6 @@ module.exports = {
|
|
|
16
7
|
options: [
|
|
17
8
|
'limit',
|
|
18
9
|
'fields',
|
|
19
|
-
'include',
|
|
20
10
|
'filter',
|
|
21
11
|
'order',
|
|
22
12
|
'debug',
|
|
@@ -25,48 +15,21 @@ module.exports = {
|
|
|
25
15
|
permissions: {
|
|
26
16
|
docName: 'products'
|
|
27
17
|
},
|
|
28
|
-
validation: {
|
|
29
|
-
options: {
|
|
30
|
-
include: {
|
|
31
|
-
values: allowedIncludes
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
},
|
|
35
18
|
async query(frame) {
|
|
36
|
-
const page = await
|
|
37
|
-
|
|
19
|
+
const page = await tiersService.api.browse(frame.options);
|
|
38
20
|
return page;
|
|
39
21
|
}
|
|
40
22
|
},
|
|
41
23
|
|
|
42
24
|
read: {
|
|
43
|
-
options: [
|
|
44
|
-
'include'
|
|
45
|
-
],
|
|
46
|
-
headers: {},
|
|
47
25
|
data: [
|
|
48
26
|
'id'
|
|
49
27
|
],
|
|
50
|
-
validation: {
|
|
51
|
-
options: {
|
|
52
|
-
include: {
|
|
53
|
-
values: allowedIncludes
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
},
|
|
57
28
|
permissions: {
|
|
58
29
|
docName: 'products'
|
|
59
30
|
},
|
|
60
31
|
async query(frame) {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
if (!model) {
|
|
64
|
-
throw new errors.NotFoundError({
|
|
65
|
-
message: tpl(messages.productNotFound)
|
|
66
|
-
});
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
return model;
|
|
32
|
+
return await tiersService.api.read(frame.data.id);
|
|
70
33
|
}
|
|
71
34
|
},
|
|
72
35
|
|
|
@@ -84,11 +47,7 @@ module.exports = {
|
|
|
84
47
|
docName: 'products'
|
|
85
48
|
},
|
|
86
49
|
async query(frame) {
|
|
87
|
-
|
|
88
|
-
frame.data,
|
|
89
|
-
frame.options
|
|
90
|
-
);
|
|
91
|
-
return model;
|
|
50
|
+
return await tiersService.api.add(frame.data);
|
|
92
51
|
}
|
|
93
52
|
},
|
|
94
53
|
|
|
@@ -111,12 +70,7 @@ module.exports = {
|
|
|
111
70
|
docName: 'products'
|
|
112
71
|
},
|
|
113
72
|
async query(frame) {
|
|
114
|
-
|
|
115
|
-
frame.data,
|
|
116
|
-
frame.options
|
|
117
|
-
);
|
|
118
|
-
|
|
119
|
-
return model;
|
|
73
|
+
return await tiersService.api.edit(frame.options.id, frame.data);
|
|
120
74
|
}
|
|
121
75
|
}
|
|
122
76
|
};
|
|
@@ -45,7 +45,7 @@ function defaultRelations(frame) {
|
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
if (labs.isSet('audienceFeedback')) {
|
|
48
|
-
frame.options.withRelated = ['tags', 'authors', 'authors.roles', 'email', 'tiers', 'newsletter', 'count.conversions', 'count.clicks', 'count.sentiment', 'count.positive_feedback'];
|
|
48
|
+
frame.options.withRelated = ['tags', 'authors', 'authors.roles', 'email', 'tiers', 'newsletter', 'count.conversions', 'count.clicks', 'count.sentiment', 'count.positive_feedback', 'count.negative_feedback'];
|
|
49
49
|
} else {
|
|
50
50
|
frame.options.withRelated = ['tags', 'authors', 'authors.roles', 'email', 'tiers', 'newsletter', 'count.signups', 'count.paid_conversions', 'count.clicks'];
|
|
51
51
|
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
const localUtils = require('../../index');
|
|
2
|
-
const labs = require('../../../../../../shared/labs');
|
|
3
2
|
|
|
4
3
|
const forceActiveFilter = (frame) => {
|
|
5
4
|
if (frame.options.filter) {
|
|
@@ -10,39 +9,31 @@ const forceActiveFilter = (frame) => {
|
|
|
10
9
|
};
|
|
11
10
|
|
|
12
11
|
function convertTierInput(input) {
|
|
13
|
-
const converted = {
|
|
14
|
-
id: input.id,
|
|
15
|
-
name: input.name,
|
|
16
|
-
description: input.description,
|
|
17
|
-
slug: input.slug,
|
|
18
|
-
active: input.active,
|
|
19
|
-
type: input.type,
|
|
20
|
-
welcome_page_url: input.welcome_page_url,
|
|
21
|
-
created_at: input.created_at,
|
|
22
|
-
updated_at: input.updated_at,
|
|
23
|
-
visibility: input.visibility
|
|
24
|
-
};
|
|
12
|
+
const converted = Object.assign({}, input);
|
|
25
13
|
|
|
26
|
-
if (
|
|
27
|
-
converted.
|
|
14
|
+
if (Reflect.has(converted, 'active')) {
|
|
15
|
+
converted.status = converted.active ? 'active' : 'archived';
|
|
16
|
+
delete converted.active;
|
|
28
17
|
}
|
|
29
18
|
|
|
30
|
-
if (
|
|
31
|
-
converted.
|
|
32
|
-
|
|
33
|
-
currency: input.currency
|
|
34
|
-
};
|
|
19
|
+
if (Reflect.has(converted, 'welcome_page_url')) {
|
|
20
|
+
converted.welcomePageURL = converted.welcome_page_url;
|
|
21
|
+
delete converted.welcome_page_url;
|
|
35
22
|
}
|
|
36
23
|
|
|
37
|
-
if (
|
|
38
|
-
converted.
|
|
39
|
-
|
|
40
|
-
currency: input.currency
|
|
41
|
-
};
|
|
24
|
+
if (Reflect.has(converted, 'trial_days')) {
|
|
25
|
+
converted.trialDays = converted.trial_days;
|
|
26
|
+
delete converted.trial_days;
|
|
42
27
|
}
|
|
43
28
|
|
|
44
|
-
if (
|
|
45
|
-
converted.
|
|
29
|
+
if (Reflect.has(converted, 'monthly_price')) {
|
|
30
|
+
converted.monthlyPrice = converted.monthly_price;
|
|
31
|
+
delete converted.monthly_price;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (Reflect.has(converted, 'yearly_price')) {
|
|
35
|
+
converted.yearlyPrice = converted.yearly_price;
|
|
36
|
+
delete converted.yearly_price;
|
|
46
37
|
}
|
|
47
38
|
|
|
48
39
|
return converted;
|
|
@@ -53,6 +53,38 @@ const clickEventMapper = (json, frame) => {
|
|
|
53
53
|
response.created_at = data.created_at;
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
+
if (data.id) {
|
|
57
|
+
response.id = data.id;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return {
|
|
61
|
+
...json,
|
|
62
|
+
data: response
|
|
63
|
+
};
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
const aggregatedClickEventMapper = (json) => {
|
|
67
|
+
const data = json.data;
|
|
68
|
+
const response = {};
|
|
69
|
+
|
|
70
|
+
if (data.member) {
|
|
71
|
+
response.member = _.pick(data.member, memberFields);
|
|
72
|
+
} else {
|
|
73
|
+
response.member = null;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (data.created_at) {
|
|
77
|
+
response.created_at = data.created_at;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (data.id) {
|
|
81
|
+
response.id = data.id;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
response.count = {
|
|
85
|
+
clicks: data.count?.clicks ?? 0
|
|
86
|
+
};
|
|
87
|
+
|
|
56
88
|
return {
|
|
57
89
|
...json,
|
|
58
90
|
data: response
|
|
@@ -111,12 +143,22 @@ const activityFeedMapper = (event, frame) => {
|
|
|
111
143
|
if (event.type === 'click_event') {
|
|
112
144
|
return clickEventMapper(event, frame);
|
|
113
145
|
}
|
|
146
|
+
if (event.type === 'aggregated_click_event') {
|
|
147
|
+
return aggregatedClickEventMapper(event, frame);
|
|
148
|
+
}
|
|
114
149
|
if (event.type === 'feedback_event') {
|
|
115
150
|
return feedbackEventMapper(event, frame);
|
|
116
151
|
}
|
|
117
152
|
if (event.data?.attribution) {
|
|
118
153
|
event.data.attribution = serializeAttribution(event.data.attribution);
|
|
119
154
|
}
|
|
155
|
+
// TODO: add dedicated mappers for other event types
|
|
156
|
+
if (event.data?.batch_id) {
|
|
157
|
+
delete event.data.batch_id;
|
|
158
|
+
}
|
|
159
|
+
if (event.data?.subscriptionCreatedEvent) {
|
|
160
|
+
delete event.data.subscriptionCreatedEvent;
|
|
161
|
+
}
|
|
120
162
|
return event;
|
|
121
163
|
};
|
|
122
164
|
|
|
@@ -111,10 +111,7 @@ module.exports = async (model, frame, options = {}) => {
|
|
|
111
111
|
|
|
112
112
|
if (jsonModel.email && jsonModel.count) {
|
|
113
113
|
jsonModel.email.opened_count = Math.min(
|
|
114
|
-
|
|
115
|
-
jsonModel.email.opened_count || 0,
|
|
116
|
-
jsonModel.count.clicks || 0
|
|
117
|
-
),
|
|
114
|
+
jsonModel.email.opened_count || 0,
|
|
118
115
|
jsonModel.email.email_count
|
|
119
116
|
);
|
|
120
117
|
}
|
|
@@ -140,5 +137,9 @@ module.exports = async (model, frame, options = {}) => {
|
|
|
140
137
|
jsonModel.count.positive_feedback = 0;
|
|
141
138
|
}
|
|
142
139
|
|
|
140
|
+
if (jsonModel.count && !jsonModel.count.negative_feedback) {
|
|
141
|
+
jsonModel.count.negative_feedback = 0;
|
|
142
|
+
}
|
|
143
|
+
|
|
143
144
|
return jsonModel;
|
|
144
145
|
};
|
|
@@ -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 = {
|
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
|
+
);
|