ghost 5.38.0 → 5.40.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-cache-memory-ttl-5.38.0.tgz → tryghost-adapter-cache-memory-ttl-5.40.0.tgz} +0 -0
- package/components/tryghost-adapter-cache-redis-5.40.0.tgz +0 -0
- package/components/tryghost-adapter-manager-5.40.0.tgz +0 -0
- package/components/{tryghost-api-framework-5.38.0.tgz → tryghost-api-framework-5.40.0.tgz} +0 -0
- package/components/tryghost-api-version-compatibility-service-5.40.0.tgz +0 -0
- package/components/tryghost-audience-feedback-5.40.0.tgz +0 -0
- package/components/tryghost-bootstrap-socket-5.40.0.tgz +0 -0
- package/components/tryghost-constants-5.40.0.tgz +0 -0
- package/components/{tryghost-custom-theme-settings-service-5.38.0.tgz → tryghost-custom-theme-settings-service-5.40.0.tgz} +0 -0
- package/components/tryghost-data-generator-5.40.0.tgz +0 -0
- package/components/{tryghost-domain-events-5.38.0.tgz → tryghost-domain-events-5.40.0.tgz} +0 -0
- package/components/tryghost-dynamic-routing-events-5.40.0.tgz +0 -0
- package/components/tryghost-email-analytics-provider-mailgun-5.40.0.tgz +0 -0
- package/components/tryghost-email-analytics-service-5.40.0.tgz +0 -0
- package/components/tryghost-email-content-generator-5.40.0.tgz +0 -0
- package/components/tryghost-email-events-5.40.0.tgz +0 -0
- package/components/tryghost-email-service-5.40.0.tgz +0 -0
- package/components/{tryghost-email-suppression-list-5.38.0.tgz → tryghost-email-suppression-list-5.40.0.tgz} +0 -0
- package/components/tryghost-event-aware-cache-wrapper-5.40.0.tgz +0 -0
- package/components/{tryghost-express-dynamic-redirects-5.38.0.tgz → tryghost-express-dynamic-redirects-5.40.0.tgz} +0 -0
- package/components/tryghost-external-media-inliner-5.40.0.tgz +0 -0
- package/components/tryghost-extract-api-key-5.40.0.tgz +0 -0
- package/components/tryghost-html-to-plaintext-5.40.0.tgz +0 -0
- package/components/tryghost-i18n-5.40.0.tgz +0 -0
- package/components/tryghost-importer-handler-content-files-5.40.0.tgz +0 -0
- package/components/tryghost-importer-revue-5.40.0.tgz +0 -0
- package/components/tryghost-job-manager-5.40.0.tgz +0 -0
- package/components/tryghost-link-redirects-5.40.0.tgz +0 -0
- package/components/tryghost-link-replacer-5.40.0.tgz +0 -0
- package/components/{tryghost-link-tracking-5.38.0.tgz → tryghost-link-tracking-5.40.0.tgz} +0 -0
- package/components/tryghost-magic-link-5.40.0.tgz +0 -0
- package/components/tryghost-mailgun-client-5.40.0.tgz +0 -0
- package/components/tryghost-member-attribution-5.40.0.tgz +0 -0
- package/components/tryghost-member-events-5.40.0.tgz +0 -0
- package/components/tryghost-members-api-5.40.0.tgz +0 -0
- package/components/tryghost-members-csv-5.40.0.tgz +0 -0
- package/components/{tryghost-members-events-service-5.38.0.tgz → tryghost-members-events-service-5.40.0.tgz} +0 -0
- package/components/tryghost-members-importer-5.40.0.tgz +0 -0
- package/components/tryghost-members-offers-5.40.0.tgz +0 -0
- package/components/tryghost-members-payments-5.40.0.tgz +0 -0
- package/components/tryghost-members-ssr-5.40.0.tgz +0 -0
- package/components/tryghost-members-stripe-service-5.40.0.tgz +0 -0
- package/components/tryghost-mentions-email-report-5.40.0.tgz +0 -0
- package/components/tryghost-milestones-5.40.0.tgz +0 -0
- package/components/{tryghost-minifier-5.38.0.tgz → tryghost-minifier-5.40.0.tgz} +0 -0
- package/components/tryghost-mw-api-version-mismatch-5.40.0.tgz +0 -0
- package/components/{tryghost-mw-cache-control-5.38.0.tgz → tryghost-mw-cache-control-5.40.0.tgz} +0 -0
- package/components/tryghost-mw-error-handler-5.40.0.tgz +0 -0
- package/components/tryghost-mw-session-from-token-5.40.0.tgz +0 -0
- package/components/tryghost-mw-update-user-last-seen-5.40.0.tgz +0 -0
- package/components/{tryghost-mw-version-match-5.38.0.tgz → tryghost-mw-version-match-5.40.0.tgz} +0 -0
- package/components/tryghost-mw-vhost-5.40.0.tgz +0 -0
- package/components/tryghost-oembed-service-5.40.0.tgz +0 -0
- package/components/tryghost-package-json-5.40.0.tgz +0 -0
- package/components/tryghost-posts-service-5.40.0.tgz +0 -0
- package/components/tryghost-referrers-5.40.0.tgz +0 -0
- package/components/tryghost-security-5.40.0.tgz +0 -0
- package/components/tryghost-session-service-5.40.0.tgz +0 -0
- package/components/tryghost-settings-path-manager-5.40.0.tgz +0 -0
- package/components/tryghost-slack-notifications-5.40.0.tgz +0 -0
- package/components/tryghost-staff-service-5.40.0.tgz +0 -0
- package/components/tryghost-stats-service-5.40.0.tgz +0 -0
- package/components/tryghost-tiers-5.40.0.tgz +0 -0
- package/components/{tryghost-update-check-service-5.38.0.tgz → tryghost-update-check-service-5.40.0.tgz} +0 -0
- package/components/tryghost-verification-trigger-5.40.0.tgz +0 -0
- package/components/tryghost-version-notifications-data-service-5.40.0.tgz +0 -0
- package/components/tryghost-webmentions-5.40.0.tgz +0 -0
- package/core/boot.js +7 -0
- package/core/built/admin/assets/{chunk.143.c6802c882a911797ce4f.js → chunk.143.9e105aa0a9236484523a.js} +8 -8
- package/core/built/admin/assets/{chunk.178.09faefd4027fcba4113d.js → chunk.178.9b53f20952b9ae4763a2.js} +4 -4
- package/core/built/admin/assets/{chunk.220.9ca2950240aba3fced21.js → chunk.462.b66cfed1f66c8d2678b2.js} +9407 -9041
- package/core/built/admin/assets/chunk.808.2e76eb12fa4d7be8cb23.js +5 -0
- package/core/built/admin/assets/{ghost-35103ff053c43f1dfa7f35821c3c2412.js → ghost-467b96c17c6bc0d06fa88e85074fbecf.js} +299 -275
- package/core/built/admin/assets/ghost-68ea49029c6d45b4aa090f4e218917aa.css +1 -0
- package/core/built/admin/assets/ghost-dark-c9b38252afc29364507e8c92e4ba9933.css +1 -0
- package/core/built/admin/assets/img/latest-posts-1-ea1e669b275f2c7dfa23abd4be8d7ad5.png +0 -0
- package/core/built/admin/assets/img/latest-posts-2-e6b0809353ac31642839a6f3bab0d4e8.png +0 -0
- package/core/built/admin/assets/img/latest-posts-3-ac8c2e95dd9adecb9029a7b037ed7f15.png +0 -0
- package/core/built/admin/assets/{vendor-b982e3bf1020bff77b2a3c44d5f59e55.js → vendor-d08b4de6f990b9cd7b5a92d61952a5bb.js} +54 -49
- package/core/built/admin/index.html +6 -6
- package/core/frontend/meta/schema.js +4 -16
- package/core/server/api/endpoints/db.js +10 -2
- package/core/server/api/endpoints/members.js +8 -1
- package/core/server/api/endpoints/posts.js +30 -1
- package/core/server/api/endpoints/utils/serializers/output/mappers/emails.js +2 -1
- package/core/server/api/endpoints/utils/serializers/output/posts.js +5 -0
- package/core/server/data/importer/import-manager.js +3 -8
- package/core/server/data/migrations/versions/5.39/2023-03-13-09-29-add-newsletter-show-post-title-section.js +7 -0
- package/core/server/data/migrations/versions/5.39/2023-03-13-13-11-add-newsletter-show-comment-cta.js +7 -0
- package/core/server/data/migrations/versions/5.39/2023-03-13-14-30-add-newsletter-show-subscription-details.js +7 -0
- package/core/server/data/migrations/versions/5.39/2023-03-14-12-26-add-last-mentions-email-report-timestamp-setting.js +8 -0
- package/core/server/data/migrations/versions/5.40/2023-03-13-14-05-add-newsletter-show-latest-posts.js +7 -0
- package/core/server/data/migrations/versions/5.40/2023-03-21-18-42-add-self-serve-integration-role.js +31 -0
- package/core/server/data/migrations/versions/5.40/2023-03-21-18-43-add-self-serve-migration-and-permissions.js +25 -0
- package/core/server/data/migrations/versions/5.40/2023-03-21-18-52-add-self-serve-integration.js +37 -0
- package/core/server/data/migrations/versions/5.40/2023-03-21-19-02-add-self-serve-integration-api-key.js +72 -0
- package/core/server/data/schema/default-settings/default-settings.json +4 -0
- package/core/server/data/schema/fixtures/fixtures.json +21 -0
- package/core/server/data/schema/schema.js +4 -0
- package/core/server/lib/request-external.js +8 -4
- package/core/server/models/base/plugins/relations.js +22 -0
- package/core/server/models/base/plugins/sanitize.js +1 -1
- package/core/server/models/newsletter.js +4 -0
- package/core/server/services/email-service/wrapper.js +4 -1
- package/core/server/services/i18n.js +14 -0
- package/core/server/services/member-attribution/index.js +2 -1
- package/core/server/services/members/api.js +43 -42
- package/core/server/services/members/emails/signin.js +9 -9
- package/core/server/services/mentions/BookshelfMentionRepository.js +11 -0
- package/core/server/services/mentions/service.js +4 -0
- package/core/server/services/mentions-email-report/StartMentionEmailReportJob.js +16 -0
- package/core/server/services/mentions-email-report/index.js +1 -0
- package/core/server/services/mentions-email-report/job.js +11 -0
- package/core/server/services/mentions-email-report/service.js +162 -0
- package/core/server/services/milestones/BookshelfMilestoneRepository.js +18 -6
- package/core/server/services/milestones/service.js +17 -15
- package/core/server/services/posts/posts-service.js +22 -119
- package/core/server/services/public-config/config.js +1 -1
- package/core/server/services/slack-notifications/service.js +1 -2
- package/core/server/services/webhooks/trigger.js +2 -2
- package/core/server/web/api/endpoints/admin/routes.js +2 -1
- package/core/shared/config/defaults.json +3 -4
- package/core/shared/config/overrides.json +3 -1
- package/core/shared/labs.js +3 -4
- package/package.json +149 -142
- package/yarn.lock +3544 -1240
- package/components/tryghost-adapter-cache-redis-5.38.0.tgz +0 -0
- package/components/tryghost-adapter-manager-5.38.0.tgz +0 -0
- package/components/tryghost-api-version-compatibility-service-5.38.0.tgz +0 -0
- package/components/tryghost-audience-feedback-5.38.0.tgz +0 -0
- package/components/tryghost-bootstrap-socket-5.38.0.tgz +0 -0
- package/components/tryghost-constants-5.38.0.tgz +0 -0
- package/components/tryghost-data-generator-5.38.0.tgz +0 -0
- package/components/tryghost-dynamic-routing-events-5.38.0.tgz +0 -0
- package/components/tryghost-email-analytics-provider-mailgun-5.38.0.tgz +0 -0
- package/components/tryghost-email-analytics-service-5.38.0.tgz +0 -0
- package/components/tryghost-email-content-generator-5.38.0.tgz +0 -0
- package/components/tryghost-email-events-5.38.0.tgz +0 -0
- package/components/tryghost-email-service-5.38.0.tgz +0 -0
- package/components/tryghost-event-aware-cache-wrapper-5.38.0.tgz +0 -0
- package/components/tryghost-external-media-inliner-5.38.0.tgz +0 -0
- package/components/tryghost-extract-api-key-5.38.0.tgz +0 -0
- package/components/tryghost-html-to-plaintext-5.38.0.tgz +0 -0
- package/components/tryghost-i18n-5.38.0.tgz +0 -0
- package/components/tryghost-importer-handler-content-files-5.38.0.tgz +0 -0
- package/components/tryghost-importer-revue-5.38.0.tgz +0 -0
- package/components/tryghost-job-manager-5.38.0.tgz +0 -0
- package/components/tryghost-link-redirects-5.38.0.tgz +0 -0
- package/components/tryghost-link-replacer-5.38.0.tgz +0 -0
- package/components/tryghost-magic-link-5.38.0.tgz +0 -0
- package/components/tryghost-mailgun-client-5.38.0.tgz +0 -0
- package/components/tryghost-member-attribution-5.38.0.tgz +0 -0
- package/components/tryghost-member-events-5.38.0.tgz +0 -0
- package/components/tryghost-members-api-5.38.0.tgz +0 -0
- package/components/tryghost-members-csv-5.38.0.tgz +0 -0
- package/components/tryghost-members-importer-5.38.0.tgz +0 -0
- package/components/tryghost-members-offers-5.38.0.tgz +0 -0
- package/components/tryghost-members-payments-5.38.0.tgz +0 -0
- package/components/tryghost-members-ssr-5.38.0.tgz +0 -0
- package/components/tryghost-members-stripe-service-5.38.0.tgz +0 -0
- package/components/tryghost-milestones-5.38.0.tgz +0 -0
- package/components/tryghost-mw-api-version-mismatch-5.38.0.tgz +0 -0
- package/components/tryghost-mw-error-handler-5.38.0.tgz +0 -0
- package/components/tryghost-mw-session-from-token-5.38.0.tgz +0 -0
- package/components/tryghost-mw-update-user-last-seen-5.38.0.tgz +0 -0
- package/components/tryghost-mw-vhost-5.38.0.tgz +0 -0
- package/components/tryghost-oembed-service-5.38.0.tgz +0 -0
- package/components/tryghost-package-json-5.38.0.tgz +0 -0
- package/components/tryghost-referrers-5.38.0.tgz +0 -0
- package/components/tryghost-security-5.38.0.tgz +0 -0
- package/components/tryghost-session-service-5.38.0.tgz +0 -0
- package/components/tryghost-settings-path-manager-5.38.0.tgz +0 -0
- package/components/tryghost-slack-notifications-5.38.0.tgz +0 -0
- package/components/tryghost-staff-service-5.38.0.tgz +0 -0
- package/components/tryghost-stats-service-5.38.0.tgz +0 -0
- package/components/tryghost-tiers-5.38.0.tgz +0 -0
- package/components/tryghost-verification-trigger-5.38.0.tgz +0 -0
- package/components/tryghost-version-notifications-data-service-5.38.0.tgz +0 -0
- package/components/tryghost-webmentions-5.38.0.tgz +0 -0
- package/core/built/admin/assets/chunk.79.acb7dd01e1c785f4920c.js +0 -287
- package/core/built/admin/assets/ghost-a9307c9cfe26a4bc621e02cd3bae421a.css +0 -1
- package/core/built/admin/assets/ghost-dark-f309cf445255344e4861a95ecb8f1920.css +0 -1
- /package/core/built/admin/assets/{chunk.220.9ca2950240aba3fced21.js.LICENSE.txt → chunk.462.b66cfed1f66c8d2678b2.js.LICENSE.txt} +0 -0
|
@@ -9,7 +9,7 @@ const allowedIncludes = [
|
|
|
9
9
|
'email',
|
|
10
10
|
'tiers',
|
|
11
11
|
'newsletter',
|
|
12
|
-
'count.conversions',
|
|
12
|
+
'count.conversions',
|
|
13
13
|
'count.signups',
|
|
14
14
|
'count.paid_conversions',
|
|
15
15
|
'count.clicks',
|
|
@@ -57,6 +57,35 @@ module.exports = {
|
|
|
57
57
|
}
|
|
58
58
|
},
|
|
59
59
|
|
|
60
|
+
exportCSV: {
|
|
61
|
+
options: [
|
|
62
|
+
'limit',
|
|
63
|
+
'filter',
|
|
64
|
+
'order'
|
|
65
|
+
],
|
|
66
|
+
headers: {
|
|
67
|
+
disposition: {
|
|
68
|
+
type: 'csv',
|
|
69
|
+
value() {
|
|
70
|
+
const datetime = (new Date()).toJSON().substring(0, 10);
|
|
71
|
+
return `posts.${datetime}.csv`;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
response: {
|
|
76
|
+
format: 'plain'
|
|
77
|
+
},
|
|
78
|
+
permissions: {
|
|
79
|
+
method: 'browse'
|
|
80
|
+
},
|
|
81
|
+
validation: {},
|
|
82
|
+
async query(frame) {
|
|
83
|
+
return {
|
|
84
|
+
data: await postsService.export(frame)
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
|
|
60
89
|
read: {
|
|
61
90
|
options: [
|
|
62
91
|
'include',
|
|
@@ -7,7 +7,8 @@ module.exports = (model, frame) => {
|
|
|
7
7
|
|
|
8
8
|
// Ensure we're not outputting unwanted replacement strings when viewing email contents
|
|
9
9
|
// TODO: extract this to a utility, it's duplicated in the email-preview API controller
|
|
10
|
-
if (jsonModel.html) {
|
|
10
|
+
if (jsonModel.html && emailService.renderer && emailService.service) {
|
|
11
|
+
// In worker threads the renderer and servie service are not available, but we don't need to do this, so okay to skip.
|
|
11
12
|
const replacements = emailService.renderer.buildReplacementDefinitions({html: jsonModel.html, newsletterUuid: 'preview'});
|
|
12
13
|
const exampleMember = emailService.service.getDefaultExampleMember();
|
|
13
14
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
const debug = require('@tryghost/debug')('api:endpoints:utils:serializers:output:posts');
|
|
2
2
|
const mappers = require('./mappers');
|
|
3
3
|
const membersService = require('../../../../../services/members');
|
|
4
|
+
const papaparse = require('papaparse');
|
|
4
5
|
|
|
5
6
|
module.exports = {
|
|
6
7
|
async all(models, apiConfig, frame) {
|
|
@@ -32,5 +33,9 @@ module.exports = {
|
|
|
32
33
|
frame.response = {
|
|
33
34
|
posts: [post]
|
|
34
35
|
};
|
|
36
|
+
},
|
|
37
|
+
|
|
38
|
+
exportCSV(models, apiConfig, frame) {
|
|
39
|
+
frame.response = papaparse.unparse(models.data);
|
|
35
40
|
}
|
|
36
41
|
};
|
|
@@ -61,6 +61,7 @@ class ImportManager {
|
|
|
61
61
|
// in the importer, so we need to keep it as general "content" unless
|
|
62
62
|
// it becomes a strict requirement
|
|
63
63
|
directories: ['media', 'content'],
|
|
64
|
+
ignoreRootFolderFiles: true,
|
|
64
65
|
extensions: config.get('uploads').media.extensions,
|
|
65
66
|
contentTypes: config.get('uploads').media.contentTypes,
|
|
66
67
|
contentPath: config.getContentPath('media'),
|
|
@@ -74,6 +75,7 @@ class ImportManager {
|
|
|
74
75
|
// in the importer, so we need to keep it as general "content" unless
|
|
75
76
|
// it becomes a strict requirement
|
|
76
77
|
directories: ['files', 'content'],
|
|
78
|
+
ignoreRootFolderFiles: true,
|
|
77
79
|
extensions: config.get('uploads').files.extensions,
|
|
78
80
|
contentTypes: config.get('uploads').files.contentTypes,
|
|
79
81
|
contentPath: config.getContentPath('files'),
|
|
@@ -301,14 +303,7 @@ class ImportManager {
|
|
|
301
303
|
const baseDir = this.getBaseDirectory(zipDirectory);
|
|
302
304
|
|
|
303
305
|
for (const handler of this.handlers) {
|
|
304
|
-
|
|
305
|
-
if (handler.directories?.length > 0) {
|
|
306
|
-
for (const dir of handler.directories) {
|
|
307
|
-
files.push(...this.getFilesFromZip(handler, path.join(zipDirectory, (baseDir || ''), dir)));
|
|
308
|
-
}
|
|
309
|
-
} else {
|
|
310
|
-
files.push(...this.getFilesFromZip(handler, zipDirectory));
|
|
311
|
-
}
|
|
306
|
+
const files = this.getFilesFromZip(handler, zipDirectory);
|
|
312
307
|
|
|
313
308
|
debug('handler', handler.type, files);
|
|
314
309
|
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
const logging = require('@tryghost/logging');
|
|
2
|
+
const {default: ObjectID} = require('bson-objectid');
|
|
3
|
+
const {createTransactionalMigration, meta} = require('../../utils');
|
|
4
|
+
|
|
5
|
+
module.exports = createTransactionalMigration(
|
|
6
|
+
async function up(knex) {
|
|
7
|
+
logging.info('Creating "Self-Serve Migration Integration" role');
|
|
8
|
+
const existingRole = await knex('roles').where({
|
|
9
|
+
name: 'Self-Serve Migration Integration'
|
|
10
|
+
}).first();
|
|
11
|
+
|
|
12
|
+
if (existingRole) {
|
|
13
|
+
logging.warn('"Self-Serve Migration Integration" role already exists, skipping');
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
await knex('roles').insert({
|
|
18
|
+
id: (new ObjectID()).toHexString(),
|
|
19
|
+
name: 'Self-Serve Migration Integration',
|
|
20
|
+
description: 'Core Integration for the Ghost Explore directory',
|
|
21
|
+
created_by: meta.MIGRATION_USER,
|
|
22
|
+
created_at: knex.raw('current_timestamp')
|
|
23
|
+
});
|
|
24
|
+
},
|
|
25
|
+
async function down(knex) {
|
|
26
|
+
logging.info('Deleting role "Self-Serve Migration Integration"');
|
|
27
|
+
await knex('roles').where({
|
|
28
|
+
name: 'Self-Serve Migration Integration'
|
|
29
|
+
}).del();
|
|
30
|
+
}
|
|
31
|
+
);
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
const {combineTransactionalMigrations, addPermissionWithRoles} = require('../../utils');
|
|
2
|
+
|
|
3
|
+
module.exports = combineTransactionalMigrations(
|
|
4
|
+
addPermissionWithRoles({
|
|
5
|
+
name: 'Import database',
|
|
6
|
+
action: 'importContent',
|
|
7
|
+
object: 'db'
|
|
8
|
+
}, [
|
|
9
|
+
'Self-Serve Migration Integration'
|
|
10
|
+
]),
|
|
11
|
+
addPermissionWithRoles({
|
|
12
|
+
name: 'Add Members',
|
|
13
|
+
action: 'add',
|
|
14
|
+
object: 'member'
|
|
15
|
+
}, [
|
|
16
|
+
'Self-Serve Migration Integration'
|
|
17
|
+
]),
|
|
18
|
+
addPermissionWithRoles({
|
|
19
|
+
name: 'Read tags',
|
|
20
|
+
action: 'read',
|
|
21
|
+
object: 'tag'
|
|
22
|
+
}, [
|
|
23
|
+
'Self-Serve Migration Integration'
|
|
24
|
+
])
|
|
25
|
+
);
|
package/core/server/data/migrations/versions/5.40/2023-03-21-18-52-add-self-serve-integration.js
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
const logging = require('@tryghost/logging');
|
|
2
|
+
const {default: ObjectID} = require('bson-objectid');
|
|
3
|
+
const {createTransactionalMigration, meta} = require('../../utils');
|
|
4
|
+
|
|
5
|
+
module.exports = createTransactionalMigration(
|
|
6
|
+
async function up(knex) {
|
|
7
|
+
logging.info('Creating "Self-Serve Migration Integration"');
|
|
8
|
+
const existingIntegration = await knex('integrations').where({
|
|
9
|
+
name: 'Self-Serve Migration Integration',
|
|
10
|
+
slug: 'self-serve-migration'
|
|
11
|
+
}).first();
|
|
12
|
+
|
|
13
|
+
if (existingIntegration) {
|
|
14
|
+
logging.warn('Integration already exists, skipping');
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
await knex('integrations').insert({
|
|
19
|
+
id: (new ObjectID()).toHexString(),
|
|
20
|
+
type: 'core',
|
|
21
|
+
name: 'Self-Serve Migration Integration',
|
|
22
|
+
description: 'Core Integration for the Self-Serve migration tool',
|
|
23
|
+
slug: 'self-serve-migration',
|
|
24
|
+
created_at: knex.raw('current_timestamp'),
|
|
25
|
+
created_by: meta.MIGRATION_USER
|
|
26
|
+
});
|
|
27
|
+
},
|
|
28
|
+
async function down(knex) {
|
|
29
|
+
logging.info('Deleting "Self-Serve Migration Integration"');
|
|
30
|
+
|
|
31
|
+
await knex('integrations').where({
|
|
32
|
+
type: 'core',
|
|
33
|
+
name: 'Self-Serve Migration Integration',
|
|
34
|
+
slug: 'self-serve-migration'
|
|
35
|
+
}).del();
|
|
36
|
+
}
|
|
37
|
+
);
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
const {InternalServerError} = require('@tryghost/errors');
|
|
2
|
+
const logging = require('@tryghost/logging');
|
|
3
|
+
const security = require('@tryghost/security');
|
|
4
|
+
const {default: ObjectID} = require('bson-objectid');
|
|
5
|
+
const {createTransactionalMigration, meta} = require('../../utils');
|
|
6
|
+
|
|
7
|
+
module.exports = createTransactionalMigration(
|
|
8
|
+
async function up(knex) {
|
|
9
|
+
logging.info('Adding Admin API key for "Self-Serve Migration Integration"');
|
|
10
|
+
|
|
11
|
+
const integration = await knex('integrations').where({
|
|
12
|
+
slug: 'self-serve-migration',
|
|
13
|
+
name: 'Self-Serve Migration Integration'
|
|
14
|
+
}).first();
|
|
15
|
+
|
|
16
|
+
if (!integration) {
|
|
17
|
+
throw new InternalServerError('Could not find "Self-Serve Migration Integration"');
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const role = await knex('roles').where({
|
|
21
|
+
name: 'Self-Serve Migration Integration'
|
|
22
|
+
}).first();
|
|
23
|
+
|
|
24
|
+
if (!role) {
|
|
25
|
+
throw new InternalServerError('Could not find "Self-Serve Migration Integration" Role');
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const existingKey = await knex('api_keys').where({
|
|
29
|
+
integration_id: integration.id,
|
|
30
|
+
role_id: role.id
|
|
31
|
+
}).first();
|
|
32
|
+
|
|
33
|
+
if (existingKey) {
|
|
34
|
+
logging.warn('Admin API key for "Self-Serve Migration Integration" already exists');
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
await knex('api_keys').insert({
|
|
39
|
+
id: (new ObjectID()).toHexString(),
|
|
40
|
+
type: 'core',
|
|
41
|
+
secret: security.secret.create('admin'),
|
|
42
|
+
role_id: role.id,
|
|
43
|
+
integration_id: integration.id,
|
|
44
|
+
created_at: knex.raw('current_timestamp'),
|
|
45
|
+
created_by: meta.MIGRATION_USER
|
|
46
|
+
});
|
|
47
|
+
},
|
|
48
|
+
async function down(knex) {
|
|
49
|
+
logging.info('Removing "Self-Serve Migration Integration" API key');
|
|
50
|
+
|
|
51
|
+
const integration = await knex('integrations').where({
|
|
52
|
+
slug: 'self-serve-migration',
|
|
53
|
+
type: 'core',
|
|
54
|
+
name: 'Self-Serve Migration Integration'
|
|
55
|
+
}).first();
|
|
56
|
+
|
|
57
|
+
const role = await knex('roles').where({
|
|
58
|
+
name: 'Self-Serve Migration Integration'
|
|
59
|
+
}).first();
|
|
60
|
+
|
|
61
|
+
if (!role || !integration) {
|
|
62
|
+
logging.warn('Could not delete "Self-Serve Migration Integration" API key');
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
logging.info('Deleting "Self-Serve Migration Integration" API Key');
|
|
67
|
+
await knex('api_keys').where({
|
|
68
|
+
integration_id: integration.id,
|
|
69
|
+
role_id: role.id
|
|
70
|
+
}).del();
|
|
71
|
+
}
|
|
72
|
+
);
|
|
@@ -76,6 +76,10 @@
|
|
|
76
76
|
"name": "Ghost Explore Integration",
|
|
77
77
|
"description": "Internal Integration for the Ghost Explore directory"
|
|
78
78
|
},
|
|
79
|
+
{
|
|
80
|
+
"name": "Self-Serve Migration Integration",
|
|
81
|
+
"description": "Internal Integration for the Self-Serve migration tool"
|
|
82
|
+
},
|
|
79
83
|
{
|
|
80
84
|
"name": "DB Backup Integration",
|
|
81
85
|
"description": "Internal DB Backup Client"
|
|
@@ -701,6 +705,18 @@
|
|
|
701
705
|
"type": "core",
|
|
702
706
|
"api_keys": [{"type": "admin", "role": "Ghost Explore Integration"}]
|
|
703
707
|
},
|
|
708
|
+
{
|
|
709
|
+
"slug": "self-serve-migration",
|
|
710
|
+
"name": "Self-Serve Migration Integration",
|
|
711
|
+
"description": "Core Self-Serve Migration integration",
|
|
712
|
+
"type": "core",
|
|
713
|
+
"api_keys": [
|
|
714
|
+
{
|
|
715
|
+
"type": "admin",
|
|
716
|
+
"role": "Self-Serve Migration Integration"
|
|
717
|
+
}
|
|
718
|
+
]
|
|
719
|
+
},
|
|
704
720
|
{
|
|
705
721
|
"slug": "ghost-backup",
|
|
706
722
|
"name": "Ghost Backup",
|
|
@@ -780,6 +796,11 @@
|
|
|
780
796
|
"Ghost Explore Integration": {
|
|
781
797
|
"explore": "read"
|
|
782
798
|
},
|
|
799
|
+
"Self-Serve Migration Integration": {
|
|
800
|
+
"db": "importContent",
|
|
801
|
+
"member": "add",
|
|
802
|
+
"tag": "read"
|
|
803
|
+
},
|
|
783
804
|
"Admin Integration": {
|
|
784
805
|
"mail": "all",
|
|
785
806
|
"notification": "all",
|
|
@@ -37,6 +37,10 @@ module.exports = {
|
|
|
37
37
|
footer_content: {type: 'text', maxlength: 1000000000, nullable: true},
|
|
38
38
|
show_badge: {type: 'boolean', nullable: false, defaultTo: true},
|
|
39
39
|
show_header_name: {type: 'boolean', nullable: false, defaultTo: true},
|
|
40
|
+
show_post_title_section: {type: 'boolean', nullable: false, defaultTo: true},
|
|
41
|
+
show_comment_cta: {type: 'boolean', nullable: false, defaultTo: true},
|
|
42
|
+
show_subscription_details: {type: 'boolean', nullable: false, defaultTo: false},
|
|
43
|
+
show_latest_posts: {type: 'boolean', nullable: false, defaultTo: false},
|
|
40
44
|
created_at: {type: 'dateTime', nullable: false},
|
|
41
45
|
updated_at: {type: 'dateTime', nullable: true}
|
|
42
46
|
},
|
|
@@ -48,15 +48,19 @@ async function errorIfInvalidUrl(options) {
|
|
|
48
48
|
|
|
49
49
|
// same as our normal request lib but if any request in a redirect chain resolves
|
|
50
50
|
// to a private IP address it will be blocked before the request is made.
|
|
51
|
-
const
|
|
51
|
+
const gotOpts = {
|
|
52
52
|
headers: {
|
|
53
53
|
'user-agent': 'Ghost(https://github.com/TryGhost/Ghost)'
|
|
54
54
|
},
|
|
55
55
|
timeout: 10000, // default is no timeout
|
|
56
56
|
hooks: {
|
|
57
|
-
beforeRequest: [errorIfInvalidUrl,errorIfHostnameResolvesToPrivateIp],
|
|
57
|
+
beforeRequest: [errorIfInvalidUrl, errorIfHostnameResolvesToPrivateIp],
|
|
58
58
|
beforeRedirect: [errorIfHostnameResolvesToPrivateIp]
|
|
59
59
|
}
|
|
60
|
-
}
|
|
60
|
+
};
|
|
61
61
|
|
|
62
|
-
|
|
62
|
+
if (process.env.NODE_ENV?.startsWith('test')) {
|
|
63
|
+
gotOpts.retry = 0;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
module.exports = got.extend(gotOpts);
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
const errors = require('@tryghost/errors');
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* @param {import('bookshelf')} Bookshelf
|
|
3
5
|
*/
|
|
@@ -9,6 +11,7 @@ module.exports = function (Bookshelf) {
|
|
|
9
11
|
* @param {string} name Name of the relation to load
|
|
10
12
|
* @param {Object} [options] Options to pass to the fetch when not yet loaded (or when force refreshing)
|
|
11
13
|
* @param {boolean} [options.forceRefresh] If true, the relation will be fetched again even if it has already been loaded.
|
|
14
|
+
* @param {boolean} [options.require] Off by default. Throws an error if relation is not found.
|
|
12
15
|
* @returns {Promise<import('bookshelf').Model|import('bookshelf').Collection|null>}
|
|
13
16
|
*/
|
|
14
17
|
getLazyRelation: async function (name, options = {}) {
|
|
@@ -18,13 +21,32 @@ module.exports = function (Bookshelf) {
|
|
|
18
21
|
}
|
|
19
22
|
|
|
20
23
|
if (!this[name]) {
|
|
24
|
+
if (options.require) {
|
|
25
|
+
throw new errors.NotFoundError();
|
|
26
|
+
}
|
|
21
27
|
return undefined;
|
|
22
28
|
}
|
|
29
|
+
|
|
30
|
+
// Explicitly set require to false if it's not set, because default for .fetch is true (not false)
|
|
31
|
+
if (options.require) {
|
|
32
|
+
options.require = true;
|
|
33
|
+
} else {
|
|
34
|
+
options.require = false;
|
|
35
|
+
}
|
|
36
|
+
|
|
23
37
|
// Not yet loaded, or force refresh
|
|
24
38
|
// Note that we don't use .refresh on the relation on options.forceRefresh
|
|
25
39
|
// Because the relation can also be a collection, which doesn't have a refresh method
|
|
26
40
|
const instance = this[name]();
|
|
27
41
|
await instance.fetch(options);
|
|
42
|
+
|
|
43
|
+
if (!instance.id && !(instance instanceof Bookshelf.Collection)) {
|
|
44
|
+
// Some weird behaviour in Bookshelf allows to just return a newly created model instance instead of throwing an error
|
|
45
|
+
if (options.require) {
|
|
46
|
+
throw new errors.NotFoundError();
|
|
47
|
+
}
|
|
48
|
+
return undefined;
|
|
49
|
+
}
|
|
28
50
|
this.relations[name] = instance;
|
|
29
51
|
return instance;
|
|
30
52
|
}
|
|
@@ -41,7 +41,7 @@ module.exports = function (Bookshelf) {
|
|
|
41
41
|
case 'add':
|
|
42
42
|
return baseOptions.concat(extraOptions, ['autoRefresh']);
|
|
43
43
|
case 'edit':
|
|
44
|
-
return baseOptions.concat(extraOptions, ['id', 'require']);
|
|
44
|
+
return baseOptions.concat(extraOptions, ['id', 'require', 'autoRefresh']);
|
|
45
45
|
case 'findOne':
|
|
46
46
|
return baseOptions.concat(extraOptions, ['columns', 'require', 'mongoTransformer']);
|
|
47
47
|
case 'findAll':
|
|
@@ -22,6 +22,10 @@ const Newsletter = ghostBookshelf.Model.extend({
|
|
|
22
22
|
show_header_icon: true,
|
|
23
23
|
show_header_title: true,
|
|
24
24
|
show_header_name: true,
|
|
25
|
+
show_post_title_section: true,
|
|
26
|
+
show_comment_cta: true,
|
|
27
|
+
show_subscription_details: false,
|
|
28
|
+
show_latest_posts: false,
|
|
25
29
|
feedback_enabled: false
|
|
26
30
|
};
|
|
27
31
|
},
|
|
@@ -25,6 +25,7 @@ class EmailServiceWrapper {
|
|
|
25
25
|
const sentry = require('../../../shared/sentry');
|
|
26
26
|
const membersRepository = membersService.api.members;
|
|
27
27
|
const limitService = require('../limits');
|
|
28
|
+
const labs = require('../../../shared/labs');
|
|
28
29
|
|
|
29
30
|
const mobiledocLib = require('../../lib/mobiledoc');
|
|
30
31
|
const lexicalLib = require('../../lib/lexical');
|
|
@@ -68,7 +69,9 @@ class EmailServiceWrapper {
|
|
|
68
69
|
linkTracking,
|
|
69
70
|
memberAttributionService: memberAttribution.service,
|
|
70
71
|
audienceFeedbackService: audienceFeedback.service,
|
|
71
|
-
outboundLinkTagger: memberAttribution.outboundLinkTagger
|
|
72
|
+
outboundLinkTagger: memberAttribution.outboundLinkTagger,
|
|
73
|
+
labs,
|
|
74
|
+
models: {Post}
|
|
72
75
|
});
|
|
73
76
|
|
|
74
77
|
const sendingService = new SendingService({
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
//const debug = require('@tryghost/debug')('i18n');
|
|
2
|
+
const i18n = require('@tryghost/i18n');
|
|
3
|
+
|
|
4
|
+
module.exports.init = function () {
|
|
5
|
+
//const events = require('../lib/common/events');
|
|
6
|
+
//const settingsCache = require('../../shared/settings-cache');
|
|
7
|
+
|
|
8
|
+
module.exports = i18n(/* settingsCache.get('locale') */ 'en', 'ghost');
|
|
9
|
+
|
|
10
|
+
/*events.on('settings.locale.edited', (model) => {
|
|
11
|
+
debug('locale changed, updating i18n to', model.get('value'));
|
|
12
|
+
i18nInstance.changeLanguage(model.get('value'));
|
|
13
|
+
});*/
|
|
14
|
+
};
|
|
@@ -2,6 +2,7 @@ const urlService = require('../url');
|
|
|
2
2
|
const urlUtils = require('../../../shared/url-utils');
|
|
3
3
|
const settingsCache = require('../../../shared/settings-cache');
|
|
4
4
|
const labs = require('../../../shared/labs');
|
|
5
|
+
const config = require('../../../shared/config');
|
|
5
6
|
|
|
6
7
|
class MemberAttributionServiceWrapper {
|
|
7
8
|
init() {
|
|
@@ -35,7 +36,7 @@ class MemberAttributionServiceWrapper {
|
|
|
35
36
|
|
|
36
37
|
this.outboundLinkTagger = new OutboundLinkTagger({
|
|
37
38
|
isEnabled: () => !labs.isSet('outboundLinkTagging') || !!settingsCache.get('outbound_link_tagging'),
|
|
38
|
-
|
|
39
|
+
getSiteUrl: () => config.getSiteUrl(),
|
|
39
40
|
urlUtils
|
|
40
41
|
});
|
|
41
42
|
|