ghost 5.19.3 → 5.20.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 +0 -0
- package/components/{tryghost-api-framework-5.19.3.tgz → tryghost-api-framework-5.20.0.tgz} +0 -0
- package/components/tryghost-api-version-compatibility-service-5.20.0.tgz +0 -0
- package/components/tryghost-audience-feedback-5.20.0.tgz +0 -0
- package/components/tryghost-bootstrap-socket-5.20.0.tgz +0 -0
- package/components/tryghost-constants-5.20.0.tgz +0 -0
- package/components/{tryghost-custom-theme-settings-service-5.19.3.tgz → tryghost-custom-theme-settings-service-5.20.0.tgz} +0 -0
- package/components/tryghost-domain-events-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-email-content-generator-5.20.0.tgz +0 -0
- package/components/tryghost-express-dynamic-redirects-5.20.0.tgz +0 -0
- package/components/tryghost-extract-api-key-5.20.0.tgz +0 -0
- package/components/tryghost-html-to-plaintext-5.20.0.tgz +0 -0
- package/components/{tryghost-job-manager-5.19.3.tgz → tryghost-job-manager-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-magic-link-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-analytics-ingress-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-offers-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-api-version-mismatch-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.19.3.tgz → tryghost-mw-error-handler-5.20.0.tgz} +0 -0
- package/components/tryghost-mw-session-from-token-5.20.0.tgz +0 -0
- package/components/tryghost-mw-update-user-last-seen-5.20.0.tgz +0 -0
- package/components/tryghost-mw-vhost-5.20.0.tgz +0 -0
- package/components/tryghost-oembed-service-5.20.0.tgz +0 -0
- package/components/tryghost-package-json-5.20.0.tgz +0 -0
- package/components/{tryghost-referrers-5.19.3.tgz → tryghost-referrers-5.20.0.tgz} +0 -0
- package/components/tryghost-security-5.20.0.tgz +0 -0
- package/components/tryghost-session-service-5.20.0.tgz +0 -0
- package/components/tryghost-settings-path-manager-5.20.0.tgz +0 -0
- package/components/tryghost-staff-service-5.20.0.tgz +0 -0
- package/components/tryghost-stats-service-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-verification-trigger-5.20.0.tgz +0 -0
- package/components/tryghost-version-notifications-data-service-5.20.0.tgz +0 -0
- package/core/built/admin/assets/{chunk.143.c035c61595ed02eee886.js → chunk.143.d245b085ad1efed4ee76.js} +7 -7
- package/core/built/admin/assets/{chunk.178.998dfbcebcec635146b1.js → chunk.178.c45f56ea31775e509497.js} +4 -4
- package/core/built/admin/assets/{chunk.613.f1d519ad47e7f9024263.js → chunk.613.c4d89dc2d28c1b20348f.js} +3 -3
- package/core/built/admin/assets/{chunk.613.f1d519ad47e7f9024263.js.LICENSE.txt → chunk.613.c4d89dc2d28c1b20348f.js.LICENSE.txt} +0 -0
- package/core/built/admin/assets/{ghost-5ce6f5a730c83c91fc258b12c537ea35.js → ghost-07e4bbf5029630b3c8a8a50c4b9f2d9e.js} +2746 -2658
- package/core/built/admin/assets/{ghost-dark-41929e4857de411a23597a9de49a4e4f.css → ghost-dark-363185f15c782b4b8394c5db23984e7f.css} +1 -1
- package/core/built/admin/assets/{ghost-982146a4ada3a5af1981d1919ae01d08.css → ghost-fd0480352bf27e013b2b00a1bf9ffe84.css} +1 -1
- package/core/built/admin/assets/{vendor-5c7d7063620bec13668c4370145cd4b4.js → vendor-518b03b02df9a55706d150627ef1004f.js} +84 -72
- package/core/built/admin/index.html +7 -7
- package/core/server/api/endpoints/links.js +33 -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/utils/serializers/input/posts.js +21 -1
- 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 +47 -15
- package/core/server/api/endpoints/utils/serializers/output/mappers/posts.js +15 -2
- 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/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/schema/commands.js +107 -48
- package/core/server/data/schema/fixtures/fixtures.json +14 -2
- package/core/server/data/schema/schema.js +2 -1
- package/core/server/models/base/plugins/actions.js +1 -1
- package/core/server/models/email-recipient.js +14 -0
- package/core/server/models/email.js +1 -5
- package/core/server/models/member-click-event.js +24 -0
- package/core/server/models/member-paid-subscription-event.js +15 -0
- package/core/server/models/post.js +32 -1
- package/core/server/models/redirect.js +1 -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/members/api.js +2 -1
- 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 +3 -3
- package/package.json +98 -97
- package/yarn.lock +28 -43
- 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-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-ssr-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-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-package-json-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-update-check-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
|
@@ -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.20%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-fd0480352bf27e013b2b00a1bf9ffe84.css" title="light">
|
|
41
41
|
|
|
42
42
|
|
|
43
43
|
</head>
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
|
|
46
46
|
<div class="ember-load-indicator">
|
|
47
47
|
<div class="gh-loading-content">
|
|
48
|
-
<video width="100" height="100" loop
|
|
48
|
+
<video width="100" height="100" loop autoplay muted playsinline preload="metadata" style="width: 100px; height: 100px;">
|
|
49
49
|
<source src="assets/videos/logo-loader.mp4" type="video/mp4" />
|
|
50
50
|
<div class="gh-loading-spinner"></div>
|
|
51
51
|
</video>
|
|
@@ -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-518b03b02df9a55706d150627ef1004f.js"></script>
|
|
60
|
+
<script src="assets/chunk.613.c4d89dc2d28c1b20348f.js"></script>
|
|
61
|
+
<script src="assets/chunk.143.d245b085ad1efed4ee76.js"></script>
|
|
62
|
+
<script src="assets/ghost-07e4bbf5029630b3c8a8a50c4b9f2d9e.js"></script>
|
|
63
63
|
</body>
|
|
64
64
|
</html>
|
|
@@ -6,7 +6,7 @@ module.exports = {
|
|
|
6
6
|
options: [
|
|
7
7
|
'filter'
|
|
8
8
|
],
|
|
9
|
-
permissions:
|
|
9
|
+
permissions: true,
|
|
10
10
|
async query(frame) {
|
|
11
11
|
const links = await linkTrackingService.service.getLinks(frame.options);
|
|
12
12
|
|
|
@@ -21,5 +21,37 @@ module.exports = {
|
|
|
21
21
|
}
|
|
22
22
|
};
|
|
23
23
|
}
|
|
24
|
+
},
|
|
25
|
+
bulkEdit: {
|
|
26
|
+
statusCode: 200,
|
|
27
|
+
headers: {
|
|
28
|
+
cacheInvalidate: true
|
|
29
|
+
},
|
|
30
|
+
options: [
|
|
31
|
+
'filter'
|
|
32
|
+
],
|
|
33
|
+
data: [
|
|
34
|
+
'action',
|
|
35
|
+
'meta'
|
|
36
|
+
],
|
|
37
|
+
validation: {
|
|
38
|
+
data: {
|
|
39
|
+
action: {
|
|
40
|
+
required: true,
|
|
41
|
+
values: ['updateLink']
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
options: {
|
|
45
|
+
filter: {
|
|
46
|
+
required: true
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
permissions: {
|
|
51
|
+
method: 'edit'
|
|
52
|
+
},
|
|
53
|
+
async query(frame) {
|
|
54
|
+
return await linkTrackingService.service.bulkEdit(frame.data.bulk, frame.options);
|
|
55
|
+
}
|
|
24
56
|
}
|
|
25
57
|
};
|
|
@@ -435,10 +435,7 @@ module.exports = {
|
|
|
435
435
|
method: 'browse'
|
|
436
436
|
},
|
|
437
437
|
async query(frame) {
|
|
438
|
-
|
|
439
|
-
return {
|
|
440
|
-
events
|
|
441
|
-
};
|
|
438
|
+
return await membersService.api.events.getEventTimeline(frame.options);
|
|
442
439
|
}
|
|
443
440
|
}
|
|
444
441
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
const models = require('../../models');
|
|
2
2
|
const tpl = require('@tryghost/tpl');
|
|
3
3
|
const errors = require('@tryghost/errors');
|
|
4
|
-
const allowedIncludes = ['tags', 'authors', 'tiers'];
|
|
4
|
+
const allowedIncludes = ['tags', 'authors', 'tiers', 'sentiment'];
|
|
5
5
|
|
|
6
6
|
const messages = {
|
|
7
7
|
postNotFound: 'Post not found.'
|
|
@@ -16,7 +16,26 @@ function removeSourceFormats(frame) {
|
|
|
16
16
|
}
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
+
/**
|
|
20
|
+
* Map names of relations to the internal names
|
|
21
|
+
*/
|
|
22
|
+
function mapWithRelated(frame) {
|
|
23
|
+
if (frame.options.withRelated) {
|
|
24
|
+
// Map sentiment to count.sentiment
|
|
25
|
+
if (labs.isSet('audienceFeedback')) {
|
|
26
|
+
frame.options.withRelated = frame.options.withRelated.map((relation) => {
|
|
27
|
+
return relation === 'sentiment' ? 'count.sentiment' : relation;
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
19
34
|
function defaultRelations(frame) {
|
|
35
|
+
// Apply same mapping as content API
|
|
36
|
+
mapWithRelated(frame);
|
|
37
|
+
|
|
38
|
+
// Addditional defaults for admin API
|
|
20
39
|
if (frame.options.withRelated) {
|
|
21
40
|
return;
|
|
22
41
|
}
|
|
@@ -26,7 +45,7 @@ function defaultRelations(frame) {
|
|
|
26
45
|
}
|
|
27
46
|
|
|
28
47
|
if (labs.isSet('audienceFeedback')) {
|
|
29
|
-
frame.options.withRelated = ['tags', 'authors', 'authors.roles', 'email', 'tiers', 'newsletter', 'count.
|
|
48
|
+
frame.options.withRelated = ['tags', 'authors', 'authors.roles', 'email', 'tiers', 'newsletter', 'count.conversions', 'count.clicks', 'count.sentiment', 'count.positive_feedback'];
|
|
30
49
|
} else {
|
|
31
50
|
frame.options.withRelated = ['tags', 'authors', 'authors.roles', 'email', 'tiers', 'newsletter', 'count.signups', 'count.paid_conversions', 'count.clicks'];
|
|
32
51
|
}
|
|
@@ -111,6 +130,7 @@ module.exports = {
|
|
|
111
130
|
|
|
112
131
|
setDefaultOrder(frame);
|
|
113
132
|
forceVisibilityColumn(frame);
|
|
133
|
+
mapWithRelated(frame);
|
|
114
134
|
}
|
|
115
135
|
|
|
116
136
|
if (!localUtils.isContentAPI(frame)) {
|
|
@@ -2,6 +2,21 @@ const mapComment = require('./comments');
|
|
|
2
2
|
const url = require('../utils/url');
|
|
3
3
|
const _ = require('lodash');
|
|
4
4
|
|
|
5
|
+
const memberFields = [
|
|
6
|
+
'id',
|
|
7
|
+
'uuid',
|
|
8
|
+
'name',
|
|
9
|
+
'email',
|
|
10
|
+
'avatar_image'
|
|
11
|
+
];
|
|
12
|
+
|
|
13
|
+
const postFields = [
|
|
14
|
+
'id',
|
|
15
|
+
'uuid',
|
|
16
|
+
'title',
|
|
17
|
+
'url'
|
|
18
|
+
];
|
|
19
|
+
|
|
5
20
|
const commentEventMapper = (json, frame) => {
|
|
6
21
|
return {
|
|
7
22
|
...json,
|
|
@@ -10,26 +25,11 @@ const commentEventMapper = (json, frame) => {
|
|
|
10
25
|
};
|
|
11
26
|
|
|
12
27
|
const clickEventMapper = (json, frame) => {
|
|
13
|
-
const memberFields = [
|
|
14
|
-
'id',
|
|
15
|
-
'uuid',
|
|
16
|
-
'name',
|
|
17
|
-
'email',
|
|
18
|
-
'avatar_image'
|
|
19
|
-
];
|
|
20
|
-
|
|
21
28
|
const linkFields = [
|
|
22
29
|
'from',
|
|
23
30
|
'to'
|
|
24
31
|
];
|
|
25
32
|
|
|
26
|
-
const postFields = [
|
|
27
|
-
'id',
|
|
28
|
-
'uuid',
|
|
29
|
-
'title',
|
|
30
|
-
'url'
|
|
31
|
-
];
|
|
32
|
-
|
|
33
33
|
const data = json.data;
|
|
34
34
|
const response = {};
|
|
35
35
|
|
|
@@ -59,6 +59,35 @@ const clickEventMapper = (json, frame) => {
|
|
|
59
59
|
};
|
|
60
60
|
};
|
|
61
61
|
|
|
62
|
+
const feedbackEventMapper = (json, frame) => {
|
|
63
|
+
const feedbackFields = [
|
|
64
|
+
'id',
|
|
65
|
+
'score',
|
|
66
|
+
'created_at'
|
|
67
|
+
];
|
|
68
|
+
|
|
69
|
+
const data = json.data;
|
|
70
|
+
const response = _.pick(data, feedbackFields);
|
|
71
|
+
|
|
72
|
+
if (data.post) {
|
|
73
|
+
url.forPost(data.post.id, data.post, frame);
|
|
74
|
+
response.post = _.pick(data.post, postFields);
|
|
75
|
+
} else {
|
|
76
|
+
response.post = null;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (data.member) {
|
|
80
|
+
response.member = _.pick(data.member, memberFields);
|
|
81
|
+
} else {
|
|
82
|
+
response.member = null;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return {
|
|
86
|
+
...json,
|
|
87
|
+
data: response
|
|
88
|
+
};
|
|
89
|
+
};
|
|
90
|
+
|
|
62
91
|
function serializeAttribution(attribution) {
|
|
63
92
|
if (!attribution) {
|
|
64
93
|
return attribution;
|
|
@@ -82,6 +111,9 @@ const activityFeedMapper = (event, frame) => {
|
|
|
82
111
|
if (event.type === 'click_event') {
|
|
83
112
|
return clickEventMapper(event, frame);
|
|
84
113
|
}
|
|
114
|
+
if (event.type === 'feedback_event') {
|
|
115
|
+
return feedbackEventMapper(event, frame);
|
|
116
|
+
}
|
|
85
117
|
if (event.data?.attribution) {
|
|
86
118
|
event.data.attribution = serializeAttribution(event.data.attribution);
|
|
87
119
|
}
|
|
@@ -119,8 +119,21 @@ module.exports = async (model, frame, options = {}) => {
|
|
|
119
119
|
);
|
|
120
120
|
}
|
|
121
121
|
|
|
122
|
-
|
|
123
|
-
|
|
122
|
+
// The sentiment has been loaded as a count relation in count.sentiment. But externally in the API we use just 'sentiment' instead of count.sentiment
|
|
123
|
+
// This part moves count.sentiment to just 'sentiment' when it has been loaded
|
|
124
|
+
if (frame.options.withRelated && frame.options.withRelated.includes('count.sentiment')) {
|
|
125
|
+
if (!jsonModel.count) {
|
|
126
|
+
jsonModel.sentiment = 0;
|
|
127
|
+
} else {
|
|
128
|
+
jsonModel.sentiment = jsonModel.count.sentiment ?? 0;
|
|
129
|
+
|
|
130
|
+
// Delete it from the original location
|
|
131
|
+
delete jsonModel.count.sentiment;
|
|
132
|
+
|
|
133
|
+
if (Object.keys(jsonModel.count).length === 0) {
|
|
134
|
+
delete jsonModel.count;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
124
137
|
}
|
|
125
138
|
|
|
126
139
|
if (jsonModel.count && !jsonModel.count.positive_feedback) {
|
|
@@ -22,8 +22,8 @@ module.exports = (snippet, frame) => {
|
|
|
22
22
|
/**
|
|
23
23
|
* @typedef {Object} SerializedSnippet
|
|
24
24
|
* @prop {string} id
|
|
25
|
-
* @prop {string
|
|
26
|
-
* @prop {string
|
|
25
|
+
* @prop {string} [name]
|
|
26
|
+
* @prop {string} [mobiledoc]
|
|
27
27
|
* @prop {string} created_at
|
|
28
28
|
* @prop {string} updated_at
|
|
29
29
|
* @prop {string} created_by
|
|
@@ -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
|
|
@@ -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
|
+
});
|