ghost 5.61.3 → 5.62.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.62.0.tgz +0 -0
- package/components/tryghost-adapter-cache-redis-5.62.0.tgz +0 -0
- package/components/{tryghost-adapter-manager-5.61.3.tgz → tryghost-adapter-manager-5.62.0.tgz} +0 -0
- package/components/tryghost-announcement-bar-settings-5.62.0.tgz +0 -0
- package/components/tryghost-api-framework-5.62.0.tgz +0 -0
- package/components/{tryghost-api-version-compatibility-service-5.61.3.tgz → tryghost-api-version-compatibility-service-5.62.0.tgz} +0 -0
- package/components/{tryghost-audience-feedback-5.61.3.tgz → tryghost-audience-feedback-5.62.0.tgz} +0 -0
- package/components/tryghost-bookshelf-repository-5.62.0.tgz +0 -0
- package/components/tryghost-bootstrap-socket-5.62.0.tgz +0 -0
- package/components/tryghost-collections-5.62.0.tgz +0 -0
- package/components/{tryghost-constants-5.61.3.tgz → tryghost-constants-5.62.0.tgz} +0 -0
- package/components/tryghost-custom-theme-settings-service-5.62.0.tgz +0 -0
- package/components/tryghost-data-generator-5.62.0.tgz +0 -0
- package/components/tryghost-domain-events-5.62.0.tgz +0 -0
- package/components/tryghost-donations-5.62.0.tgz +0 -0
- package/components/tryghost-dynamic-routing-events-5.62.0.tgz +0 -0
- package/components/tryghost-email-analytics-provider-mailgun-5.62.0.tgz +0 -0
- package/components/{tryghost-email-analytics-service-5.61.3.tgz → tryghost-email-analytics-service-5.62.0.tgz} +0 -0
- package/components/tryghost-email-content-generator-5.62.0.tgz +0 -0
- package/components/{tryghost-email-events-5.61.3.tgz → tryghost-email-events-5.62.0.tgz} +0 -0
- package/components/{tryghost-email-service-5.61.3.tgz → tryghost-email-service-5.62.0.tgz} +0 -0
- package/components/tryghost-email-suppression-list-5.62.0.tgz +0 -0
- package/components/tryghost-event-aware-cache-wrapper-5.62.0.tgz +0 -0
- package/components/{tryghost-express-dynamic-redirects-5.61.3.tgz → tryghost-express-dynamic-redirects-5.62.0.tgz} +0 -0
- package/components/{tryghost-external-media-inliner-5.61.3.tgz → tryghost-external-media-inliner-5.62.0.tgz} +0 -0
- package/components/{tryghost-extract-api-key-5.61.3.tgz → tryghost-extract-api-key-5.62.0.tgz} +0 -0
- package/components/{tryghost-html-to-plaintext-5.61.3.tgz → tryghost-html-to-plaintext-5.62.0.tgz} +0 -0
- package/components/tryghost-i18n-5.62.0.tgz +0 -0
- package/components/tryghost-importer-handler-content-files-5.62.0.tgz +0 -0
- package/components/{tryghost-importer-revue-5.61.3.tgz → tryghost-importer-revue-5.62.0.tgz} +0 -0
- package/components/tryghost-in-memory-repository-5.62.0.tgz +0 -0
- package/components/{tryghost-job-manager-5.61.3.tgz → tryghost-job-manager-5.62.0.tgz} +0 -0
- package/components/tryghost-link-redirects-5.62.0.tgz +0 -0
- package/components/tryghost-link-replacer-5.62.0.tgz +0 -0
- package/components/{tryghost-link-tracking-5.61.3.tgz → tryghost-link-tracking-5.62.0.tgz} +0 -0
- package/components/{tryghost-magic-link-5.61.3.tgz → tryghost-magic-link-5.62.0.tgz} +0 -0
- package/components/tryghost-mail-events-5.62.0.tgz +0 -0
- package/components/tryghost-mailgun-client-5.62.0.tgz +0 -0
- package/components/{tryghost-member-attribution-5.61.3.tgz → tryghost-member-attribution-5.62.0.tgz} +0 -0
- package/components/tryghost-member-events-5.62.0.tgz +0 -0
- package/components/tryghost-members-api-5.62.0.tgz +0 -0
- package/components/{tryghost-members-csv-5.61.3.tgz → tryghost-members-csv-5.62.0.tgz} +0 -0
- package/components/{tryghost-members-events-service-5.61.3.tgz → tryghost-members-events-service-5.62.0.tgz} +0 -0
- package/components/{tryghost-members-importer-5.61.3.tgz → tryghost-members-importer-5.62.0.tgz} +0 -0
- package/components/tryghost-members-offers-5.62.0.tgz +0 -0
- package/components/tryghost-members-payments-5.62.0.tgz +0 -0
- package/components/tryghost-members-ssr-5.62.0.tgz +0 -0
- package/components/{tryghost-members-stripe-service-5.61.3.tgz → tryghost-members-stripe-service-5.62.0.tgz} +0 -0
- package/components/tryghost-mentions-email-report-5.62.0.tgz +0 -0
- package/components/tryghost-milestones-5.62.0.tgz +0 -0
- package/components/{tryghost-minifier-5.61.3.tgz → tryghost-minifier-5.62.0.tgz} +0 -0
- package/components/tryghost-model-to-domain-event-interceptor-5.62.0.tgz +0 -0
- package/components/tryghost-mw-api-version-mismatch-5.62.0.tgz +0 -0
- package/components/tryghost-mw-cache-control-5.62.0.tgz +0 -0
- package/components/{tryghost-mw-error-handler-5.61.3.tgz → tryghost-mw-error-handler-5.62.0.tgz} +0 -0
- package/components/tryghost-mw-session-from-token-5.62.0.tgz +0 -0
- package/components/tryghost-mw-update-user-last-seen-5.62.0.tgz +0 -0
- package/components/tryghost-mw-version-match-5.62.0.tgz +0 -0
- package/components/{tryghost-mw-vhost-5.61.3.tgz → tryghost-mw-vhost-5.62.0.tgz} +0 -0
- package/components/tryghost-nql-filter-expansions-5.62.0.tgz +0 -0
- package/components/{tryghost-oembed-service-5.61.3.tgz → tryghost-oembed-service-5.62.0.tgz} +0 -0
- package/components/{tryghost-package-json-5.61.3.tgz → tryghost-package-json-5.62.0.tgz} +0 -0
- package/components/tryghost-post-events-5.62.0.tgz +0 -0
- package/components/{tryghost-post-revisions-5.61.3.tgz → tryghost-post-revisions-5.62.0.tgz} +0 -0
- package/components/tryghost-posts-service-5.62.0.tgz +0 -0
- package/components/tryghost-recommendations-5.62.0.tgz +0 -0
- package/components/tryghost-referrers-5.62.0.tgz +0 -0
- package/components/{tryghost-security-5.61.3.tgz → tryghost-security-5.62.0.tgz} +0 -0
- package/components/{tryghost-session-service-5.61.3.tgz → tryghost-session-service-5.62.0.tgz} +0 -0
- package/components/tryghost-settings-path-manager-5.62.0.tgz +0 -0
- package/components/tryghost-slack-notifications-5.62.0.tgz +0 -0
- package/components/{tryghost-staff-service-5.61.3.tgz → tryghost-staff-service-5.62.0.tgz} +0 -0
- package/components/{tryghost-stats-service-5.61.3.tgz → tryghost-stats-service-5.62.0.tgz} +0 -0
- package/components/{tryghost-tiers-5.61.3.tgz → tryghost-tiers-5.62.0.tgz} +0 -0
- package/components/{tryghost-update-check-service-5.61.3.tgz → tryghost-update-check-service-5.62.0.tgz} +0 -0
- package/components/tryghost-verification-trigger-5.62.0.tgz +0 -0
- package/components/tryghost-version-notifications-data-service-5.62.0.tgz +0 -0
- package/components/tryghost-webmentions-5.62.0.tgz +0 -0
- package/core/built/admin/assets/{chunk.143.da84b3b434141aff0f01.js → chunk.143.5b5502a550ce35005d0f.js} +6 -5
- package/core/built/admin/assets/{chunk.178.659d369f286d4162b294.js → chunk.178.546664edca0b1b0f2ab2.js} +4 -4
- package/core/built/admin/assets/{chunk.208.dbf172ad32f72f21a5dc.js → chunk.853.f743ed975e8838475532.js} +91 -27
- package/core/built/admin/assets/{ghost-54f84395df6a6fb47b37008ded8eba22.js → ghost-d804aba7bca07fa75d308ab892c508fc.js} +13 -13
- package/core/built/admin/assets/{vendor-3631184082d609038638c1e169a002e7.js → vendor-b50a3e5c2079b8a35d9122a1a4c34ef6.js} +248 -321
- package/core/built/admin/index.html +5 -5
- package/core/server/adapters/storage/LocalStorageBase.js +1 -8
- package/core/server/api/endpoints/recommendations-public.js +2 -5
- package/core/server/api/endpoints/recommendations.js +6 -3
- package/core/server/api/endpoints/utils/serializers/input/pages.js +8 -0
- package/core/server/api/endpoints/utils/serializers/input/posts.js +9 -1
- package/core/server/api/endpoints/utils/serializers/output/site.js +2 -0
- package/core/server/lib/lexical.js +15 -0
- package/core/server/models/base/plugins/crud.js +6 -0
- package/core/server/models/base/plugins/sanitize.js +1 -1
- package/core/server/models/post.js +11 -1
- package/core/server/services/mentions/WebmentionMetadata.js +38 -1
- package/core/server/services/mentions/service.js +2 -1
- package/core/server/services/offers/OfferBookshelfRepository.js +230 -0
- package/core/server/services/offers/service.js +7 -3
- package/core/server/services/public-config/site.js +3 -1
- package/core/server/services/recommendations/RecommendationEnablerService.js +28 -0
- package/core/server/services/recommendations/RecommendationServiceWrapper.js +23 -1
- package/core/server/services/settings/SettingsBREADService.js +1 -1
- package/core/server/services/settings/settings-service.js +1 -0
- package/core/server/services/settings-helpers/SettingsHelpers.js +7 -0
- package/core/server/web/members/app.js +7 -0
- package/core/shared/config/defaults.json +2 -2
- package/core/shared/settings-cache/public.js +1 -0
- package/package.json +150 -149
- package/yarn.lock +197 -229
- package/components/tryghost-adapter-cache-memory-ttl-5.61.3.tgz +0 -0
- package/components/tryghost-adapter-cache-redis-5.61.3.tgz +0 -0
- package/components/tryghost-announcement-bar-settings-5.61.3.tgz +0 -0
- package/components/tryghost-api-framework-5.61.3.tgz +0 -0
- package/components/tryghost-bookshelf-repository-5.61.3.tgz +0 -0
- package/components/tryghost-bootstrap-socket-5.61.3.tgz +0 -0
- package/components/tryghost-collections-5.61.3.tgz +0 -0
- package/components/tryghost-custom-theme-settings-service-5.61.3.tgz +0 -0
- package/components/tryghost-data-generator-5.61.3.tgz +0 -0
- package/components/tryghost-domain-events-5.61.3.tgz +0 -0
- package/components/tryghost-donations-5.61.3.tgz +0 -0
- package/components/tryghost-dynamic-routing-events-5.61.3.tgz +0 -0
- package/components/tryghost-email-analytics-provider-mailgun-5.61.3.tgz +0 -0
- package/components/tryghost-email-content-generator-5.61.3.tgz +0 -0
- package/components/tryghost-email-suppression-list-5.61.3.tgz +0 -0
- package/components/tryghost-event-aware-cache-wrapper-5.61.3.tgz +0 -0
- package/components/tryghost-i18n-5.61.3.tgz +0 -0
- package/components/tryghost-importer-handler-content-files-5.61.3.tgz +0 -0
- package/components/tryghost-in-memory-repository-5.61.3.tgz +0 -0
- package/components/tryghost-link-redirects-5.61.3.tgz +0 -0
- package/components/tryghost-link-replacer-5.61.3.tgz +0 -0
- package/components/tryghost-mail-events-5.61.3.tgz +0 -0
- package/components/tryghost-mailgun-client-5.61.3.tgz +0 -0
- package/components/tryghost-member-events-5.61.3.tgz +0 -0
- package/components/tryghost-members-api-5.61.3.tgz +0 -0
- package/components/tryghost-members-offers-5.61.3.tgz +0 -0
- package/components/tryghost-members-payments-5.61.3.tgz +0 -0
- package/components/tryghost-members-ssr-5.61.3.tgz +0 -0
- package/components/tryghost-mentions-email-report-5.61.3.tgz +0 -0
- package/components/tryghost-milestones-5.61.3.tgz +0 -0
- package/components/tryghost-model-to-domain-event-interceptor-5.61.3.tgz +0 -0
- package/components/tryghost-mw-api-version-mismatch-5.61.3.tgz +0 -0
- package/components/tryghost-mw-cache-control-5.61.3.tgz +0 -0
- package/components/tryghost-mw-session-from-token-5.61.3.tgz +0 -0
- package/components/tryghost-mw-update-user-last-seen-5.61.3.tgz +0 -0
- package/components/tryghost-mw-version-match-5.61.3.tgz +0 -0
- package/components/tryghost-nql-filter-expansions-5.61.3.tgz +0 -0
- package/components/tryghost-post-events-5.61.3.tgz +0 -0
- package/components/tryghost-posts-service-5.61.3.tgz +0 -0
- package/components/tryghost-recommendations-5.61.3.tgz +0 -0
- package/components/tryghost-referrers-5.61.3.tgz +0 -0
- package/components/tryghost-settings-path-manager-5.61.3.tgz +0 -0
- package/components/tryghost-slack-notifications-5.61.3.tgz +0 -0
- package/components/tryghost-verification-trigger-5.61.3.tgz +0 -0
- package/components/tryghost-version-notifications-data-service-5.61.3.tgz +0 -0
- package/components/tryghost-webmentions-5.61.3.tgz +0 -0
- /package/core/built/admin/assets/{chunk.208.dbf172ad32f72f21a5dc.js.LICENSE.txt → chunk.853.f743ed975e8838475532.js.LICENSE.txt} +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%22cdnUrl%22%3A%22%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%22cdnUrl%22%3A%22%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.62%22%2C%22name%22%3A%22ghost-admin%22%7D%2C%22ember-simple-auth%22%3A%7B%7D%2C%22ember-websockets%22%3A%7B%22socketIO%22%3Atrue%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" />
|
|
@@ -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.
|
|
61
|
-
<script src="assets/chunk.143.
|
|
62
|
-
<script src="assets/ghost-
|
|
59
|
+
<script src="assets/vendor-b50a3e5c2079b8a35d9122a1a4c34ef6.js"></script>
|
|
60
|
+
<script src="assets/chunk.853.f743ed975e8838475532.js"></script>
|
|
61
|
+
<script src="assets/chunk.143.5b5502a550ce35005d0f.js"></script>
|
|
62
|
+
<script src="assets/ghost-d804aba7bca07fa75d308ab892c508fc.js"></script>
|
|
63
63
|
</body>
|
|
64
64
|
</html>
|
|
@@ -4,9 +4,7 @@ const serveStatic = require('../../../shared/express').static;
|
|
|
4
4
|
|
|
5
5
|
const fs = require('fs-extra');
|
|
6
6
|
const path = require('path');
|
|
7
|
-
const moment = require('moment');
|
|
8
7
|
const tpl = require('@tryghost/tpl');
|
|
9
|
-
const logging = require('@tryghost/logging');
|
|
10
8
|
const errors = require('@tryghost/errors');
|
|
11
9
|
const constants = require('@tryghost/constants');
|
|
12
10
|
const urlUtils = require('../../../shared/url-utils');
|
|
@@ -127,16 +125,11 @@ class LocalStorageBase extends StorageBase {
|
|
|
127
125
|
const {storagePath, errorMessages} = this;
|
|
128
126
|
|
|
129
127
|
return function serveStaticContent(req, res, next) {
|
|
130
|
-
const startedAtMoment = moment();
|
|
131
|
-
|
|
132
128
|
return serveStatic(
|
|
133
129
|
storagePath,
|
|
134
130
|
{
|
|
135
131
|
maxAge: constants.ONE_YEAR_MS,
|
|
136
|
-
fallthrough: false
|
|
137
|
-
onEnd: () => {
|
|
138
|
-
logging.info('LocalStorageBase.serve', req.path, moment().diff(startedAtMoment, 'ms') + 'ms');
|
|
139
|
-
}
|
|
132
|
+
fallthrough: false
|
|
140
133
|
}
|
|
141
134
|
)(req, res, (err) => {
|
|
142
135
|
if (err) {
|
|
@@ -9,16 +9,13 @@ module.exports = {
|
|
|
9
9
|
},
|
|
10
10
|
options: [
|
|
11
11
|
'limit',
|
|
12
|
-
'fields',
|
|
13
|
-
'filter',
|
|
14
12
|
'order',
|
|
15
|
-
'debug',
|
|
16
13
|
'page'
|
|
17
14
|
],
|
|
18
15
|
permissions: true,
|
|
19
16
|
validation: {},
|
|
20
|
-
async query() {
|
|
21
|
-
return await recommendations.controller.listRecommendations();
|
|
17
|
+
async query(frame) {
|
|
18
|
+
return await recommendations.controller.listRecommendations(frame);
|
|
22
19
|
}
|
|
23
20
|
}
|
|
24
21
|
};
|
|
@@ -7,11 +7,14 @@ module.exports = {
|
|
|
7
7
|
headers: {
|
|
8
8
|
cacheInvalidate: false
|
|
9
9
|
},
|
|
10
|
-
options: [
|
|
10
|
+
options: [
|
|
11
|
+
'limit',
|
|
12
|
+
'page'
|
|
13
|
+
],
|
|
11
14
|
permissions: true,
|
|
12
15
|
validation: {},
|
|
13
|
-
async query() {
|
|
14
|
-
return await recommendations.controller.listRecommendations();
|
|
16
|
+
async query(frame) {
|
|
17
|
+
return await recommendations.controller.listRecommendations(frame);
|
|
15
18
|
}
|
|
16
19
|
},
|
|
17
20
|
|
|
@@ -6,6 +6,8 @@ const slugFilterOrder = require('./utils/slug-filter-order');
|
|
|
6
6
|
const localUtils = require('../../index');
|
|
7
7
|
const postsMetaSchema = require('../../../../../data/schema').tables.posts_meta;
|
|
8
8
|
const clean = require('./utils/clean');
|
|
9
|
+
const labs = require('../../../../../../shared/labs');
|
|
10
|
+
const lexical = require('../../../../../lib/lexical');
|
|
9
11
|
|
|
10
12
|
function removeSourceFormats(frame) {
|
|
11
13
|
if (frame.options.formats?.includes('mobiledoc') || frame.options.formats?.includes('lexical')) {
|
|
@@ -133,6 +135,12 @@ module.exports = {
|
|
|
133
135
|
|
|
134
136
|
if (frame.options.source === 'html' && !_.isEmpty(html)) {
|
|
135
137
|
frame.data.pages[0].mobiledoc = JSON.stringify(mobiledoc.htmlToMobiledocConverter(html));
|
|
138
|
+
|
|
139
|
+
// normally we don't allow both mobiledoc+lexical but the model layer will remove lexical
|
|
140
|
+
// if mobiledoc is already present to avoid migrating formats outside of an explicit conversion
|
|
141
|
+
if (labs.isSet('lexicalEditor')) {
|
|
142
|
+
frame.data.pages[0].lexical = JSON.stringify(lexical.htmlToLexicalConverter(html));
|
|
143
|
+
}
|
|
136
144
|
}
|
|
137
145
|
}
|
|
138
146
|
|
|
@@ -6,6 +6,8 @@ const localUtils = require('../../index');
|
|
|
6
6
|
const mobiledoc = require('../../../../../lib/mobiledoc');
|
|
7
7
|
const postsMetaSchema = require('../../../../../data/schema').tables.posts_meta;
|
|
8
8
|
const clean = require('./utils/clean');
|
|
9
|
+
const labs = require('../../../../../../shared/labs');
|
|
10
|
+
const lexical = require('../../../../../lib/lexical');
|
|
9
11
|
|
|
10
12
|
function removeSourceFormats(frame) {
|
|
11
13
|
if (frame.options.formats?.includes('mobiledoc') || frame.options.formats?.includes('lexical')) {
|
|
@@ -32,7 +34,7 @@ function defaultRelations(frame) {
|
|
|
32
34
|
// Apply same mapping as content API
|
|
33
35
|
mapWithRelated(frame);
|
|
34
36
|
|
|
35
|
-
//
|
|
37
|
+
// Additional defaults for admin API
|
|
36
38
|
if (frame.options.withRelated) {
|
|
37
39
|
return;
|
|
38
40
|
}
|
|
@@ -167,6 +169,12 @@ module.exports = {
|
|
|
167
169
|
|
|
168
170
|
if (frame.options.source === 'html' && !_.isEmpty(html)) {
|
|
169
171
|
frame.data.posts[0].mobiledoc = JSON.stringify(mobiledoc.htmlToMobiledocConverter(html));
|
|
172
|
+
|
|
173
|
+
// normally we don't allow both mobiledoc+lexical but the model layer will remove lexical
|
|
174
|
+
// if mobiledoc is already present to avoid migrating formats outside of an explicit conversion
|
|
175
|
+
if (labs.isSet('lexicalEditor')) {
|
|
176
|
+
frame.data.posts[0].lexical = JSON.stringify(lexical.htmlToLexicalConverter(html));
|
|
177
|
+
}
|
|
170
178
|
}
|
|
171
179
|
}
|
|
172
180
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
const path = require('path');
|
|
2
|
+
const errors = require('@tryghost/errors');
|
|
2
3
|
const urlUtils = require('../../shared/url-utils');
|
|
3
4
|
const config = require('../../shared/config');
|
|
4
5
|
const storage = require('../adapters/storage');
|
|
@@ -78,5 +79,19 @@ module.exports = {
|
|
|
78
79
|
}
|
|
79
80
|
|
|
80
81
|
return urlTransformMap;
|
|
82
|
+
},
|
|
83
|
+
|
|
84
|
+
get htmlToLexicalConverter() {
|
|
85
|
+
try {
|
|
86
|
+
return require('@tryghost/kg-html-to-lexical').htmlToLexical;
|
|
87
|
+
} catch (err) {
|
|
88
|
+
throw new errors.InternalServerError({
|
|
89
|
+
message: 'Unable to convert from source HTML to Lexical',
|
|
90
|
+
context: 'The html-to-lexical package was not installed',
|
|
91
|
+
help: 'Please review any errors from the install process by checking the Ghost logs',
|
|
92
|
+
code: 'HTML_TO_LEXICAL_INSTALLATION',
|
|
93
|
+
err: err
|
|
94
|
+
});
|
|
95
|
+
}
|
|
81
96
|
}
|
|
82
97
|
};
|
|
@@ -44,6 +44,12 @@ module.exports = function (Bookshelf) {
|
|
|
44
44
|
});
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
+
if (options.page && options.limit) {
|
|
48
|
+
itemCollection
|
|
49
|
+
.query('limit', options.limit)
|
|
50
|
+
.query('offset', options.limit * (options.page - 1));
|
|
51
|
+
}
|
|
52
|
+
|
|
47
53
|
const result = await itemCollection.fetchAll(options);
|
|
48
54
|
if (options.withRelated) {
|
|
49
55
|
_.each(result.models, function each(item) {
|
|
@@ -45,7 +45,7 @@ module.exports = function (Bookshelf) {
|
|
|
45
45
|
case 'findOne':
|
|
46
46
|
return baseOptions.concat(extraOptions, ['columns', 'require', 'mongoTransformer']);
|
|
47
47
|
case 'findAll':
|
|
48
|
-
return baseOptions.concat(extraOptions, ['filter', 'columns', 'mongoTransformer']);
|
|
48
|
+
return baseOptions.concat(extraOptions, ['filter', 'columns', 'mongoTransformer', 'page', 'limit']);
|
|
49
49
|
case 'findPage':
|
|
50
50
|
return baseOptions.concat(extraOptions, ['filter', 'order', 'autoOrder', 'page', 'limit', 'columns', 'mongoTransformer']);
|
|
51
51
|
default:
|
|
@@ -552,6 +552,16 @@ Post = ghostBookshelf.Model.extend({
|
|
|
552
552
|
let tagsToSave;
|
|
553
553
|
const ops = [];
|
|
554
554
|
|
|
555
|
+
// normally we don't allow both mobiledoc & lexical through at the API level but there's
|
|
556
|
+
// an exception for ?source=html which always sets both when the lexical editor is enabled.
|
|
557
|
+
// That's necessary because at the input serializer layer we don't have access to the
|
|
558
|
+
// actual model to check if this would result in a change of format
|
|
559
|
+
if (this.previous('mobiledoc') && this.get('lexical')) {
|
|
560
|
+
this.set('lexical', null);
|
|
561
|
+
} else if (this.get('mobiledoc') && this.get('lexical')) {
|
|
562
|
+
this.set('mobiledoc', null);
|
|
563
|
+
}
|
|
564
|
+
|
|
555
565
|
// CASE: disallow published -> scheduled
|
|
556
566
|
// @TODO: remove when we have versioning based on updated_at
|
|
557
567
|
if (newStatus !== olderStatus && newStatus === 'scheduled' && olderStatus === 'published') {
|
|
@@ -653,7 +663,7 @@ Post = ghostBookshelf.Model.extend({
|
|
|
653
663
|
|
|
654
664
|
// If we're force re-rendering we want to make sure that all image cards
|
|
655
665
|
// have original dimensions stored in the payload for use by card renderers
|
|
656
|
-
if (options.force_rerender) {
|
|
666
|
+
if (options.force_rerender && this.get('mobiledoc')) {
|
|
657
667
|
this.set('mobiledoc', await mobiledocLib.populateImageSizes(this.get('mobiledoc')));
|
|
658
668
|
}
|
|
659
669
|
|
|
@@ -1,12 +1,41 @@
|
|
|
1
1
|
const oembedService = require('../oembed');
|
|
2
2
|
|
|
3
3
|
module.exports = class WebmentionMetadata {
|
|
4
|
+
/**
|
|
5
|
+
* Helpers that change the URL for which metadata for a given external resource is fetched. Return undefined to now handle the URL.
|
|
6
|
+
* @type {((url: URL) => URL|undefined)[]}
|
|
7
|
+
*/
|
|
8
|
+
#mappers = [];
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* @param {(url: URL) => URL|undefined} mapper
|
|
12
|
+
*/
|
|
13
|
+
addMapper(mapper) {
|
|
14
|
+
this.#mappers.push(mapper);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
*
|
|
19
|
+
* @param {URL} url
|
|
20
|
+
*/
|
|
21
|
+
#getMappedUrl(url) {
|
|
22
|
+
for (const mapper of this.#mappers) {
|
|
23
|
+
const mappedUrl = mapper(url);
|
|
24
|
+
if (mappedUrl) {
|
|
25
|
+
return this.#getMappedUrl(mappedUrl);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return url;
|
|
29
|
+
}
|
|
30
|
+
|
|
4
31
|
/**
|
|
5
32
|
* @param {URL} url
|
|
6
33
|
* @returns {Promise<import('@tryghost/webmentions/lib/MentionsAPI').WebmentionMetadata>}
|
|
7
34
|
*/
|
|
8
35
|
async fetch(url) {
|
|
9
|
-
const
|
|
36
|
+
const mappedUrl = this.#getMappedUrl(url);
|
|
37
|
+
const data = await oembedService.fetchOembedDataFromUrl(mappedUrl.href, 'mention');
|
|
38
|
+
|
|
10
39
|
const result = {
|
|
11
40
|
siteTitle: data.metadata.publisher,
|
|
12
41
|
title: data.metadata.title,
|
|
@@ -17,6 +46,14 @@ module.exports = class WebmentionMetadata {
|
|
|
17
46
|
body: data.body,
|
|
18
47
|
contentType: data.contentType
|
|
19
48
|
};
|
|
49
|
+
|
|
50
|
+
if (mappedUrl.href !== url.href) {
|
|
51
|
+
// Still need to fetch body and contentType separately now
|
|
52
|
+
// For verification
|
|
53
|
+
const {body, contentType} = await oembedService.fetchPageHtml(url);
|
|
54
|
+
result.body = body;
|
|
55
|
+
result.contentType = contentType;
|
|
56
|
+
}
|
|
20
57
|
return result;
|
|
21
58
|
}
|
|
22
59
|
};
|
|
@@ -28,6 +28,7 @@ module.exports = {
|
|
|
28
28
|
/** @type {import('@tryghost/webmentions/lib/MentionsAPI')} */
|
|
29
29
|
api: null,
|
|
30
30
|
controller: new MentionController(),
|
|
31
|
+
metadata: new WebmentionMetadata(),
|
|
31
32
|
/** @type {import('@tryghost/webmentions/lib/MentionSendingService')} */
|
|
32
33
|
sendingService: null,
|
|
33
34
|
didInit: false,
|
|
@@ -40,7 +41,7 @@ module.exports = {
|
|
|
40
41
|
MentionModel: models.Mention,
|
|
41
42
|
DomainEvents
|
|
42
43
|
});
|
|
43
|
-
const webmentionMetadata =
|
|
44
|
+
const webmentionMetadata = this.metadata;
|
|
44
45
|
const discoveryService = new MentionDiscoveryService({externalRequest});
|
|
45
46
|
const resourceService = new ResourceService({
|
|
46
47
|
urlUtils,
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
const {flowRight} = require('lodash');
|
|
2
|
+
const {mapKeyValues, mapQuery} = require('@tryghost/mongo-utils');
|
|
3
|
+
const DomainEvents = require('@tryghost/domain-events');
|
|
4
|
+
const {Offer} = require('@tryghost/members-offers');
|
|
5
|
+
const sentry = require('../../../shared/sentry');
|
|
6
|
+
const logger = require('@tryghost/logging');
|
|
7
|
+
|
|
8
|
+
const statusTransformer = mapKeyValues({
|
|
9
|
+
key: {
|
|
10
|
+
from: 'status',
|
|
11
|
+
to: 'active'
|
|
12
|
+
},
|
|
13
|
+
values: [{
|
|
14
|
+
from: 'active',
|
|
15
|
+
to: true
|
|
16
|
+
}, {
|
|
17
|
+
from: 'archived',
|
|
18
|
+
to: false
|
|
19
|
+
}]
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
const rejectNonStatusTransformer = input => mapQuery(input, function (value, key) {
|
|
23
|
+
if (key !== 'status') {
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return {
|
|
28
|
+
[key]: value
|
|
29
|
+
};
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
const mongoTransformer = flowRight(statusTransformer, rejectNonStatusTransformer);
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* @typedef {object} BaseOptions
|
|
36
|
+
* @prop {import('knex').Transaction} transacting
|
|
37
|
+
*/
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* @typedef {object} ListOptions
|
|
41
|
+
* @prop {import('knex').Transaction} transacting
|
|
42
|
+
* @prop {string} filter
|
|
43
|
+
*/
|
|
44
|
+
|
|
45
|
+
class OfferBookshelfRepository {
|
|
46
|
+
/**
|
|
47
|
+
* @param {{forge: (data: object) => import('bookshelf').Model<Offer.OfferProps>}} OfferModel
|
|
48
|
+
* @param {{forge: (data: object) => import('bookshelf').Model<any>}} OfferRedemptionModel
|
|
49
|
+
*/
|
|
50
|
+
constructor(OfferModel, OfferRedemptionModel) {
|
|
51
|
+
/** @private */
|
|
52
|
+
this.OfferModel = OfferModel;
|
|
53
|
+
/** @private */
|
|
54
|
+
this.OfferRedemptionModel = OfferRedemptionModel;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* @template T
|
|
59
|
+
* @param {(t: import('knex').Transaction) => Promise<T>} cb
|
|
60
|
+
* @returns {Promise<T>}
|
|
61
|
+
*/
|
|
62
|
+
async createTransaction(cb) {
|
|
63
|
+
return this.OfferModel.transaction(cb);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* @param {string} name
|
|
68
|
+
* @param {BaseOptions} [options]
|
|
69
|
+
* @returns {Promise<boolean>}
|
|
70
|
+
*/
|
|
71
|
+
async existsByName(name, options) {
|
|
72
|
+
const model = await this.OfferModel.findOne({name}, options);
|
|
73
|
+
if (!model) {
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
return true;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* @param {string} code
|
|
81
|
+
* @param {BaseOptions} [options]
|
|
82
|
+
* @returns {Promise<boolean>}
|
|
83
|
+
*/
|
|
84
|
+
async existsByCode(code, options) {
|
|
85
|
+
const model = await this.OfferModel.findOne({code}, options);
|
|
86
|
+
if (!model) {
|
|
87
|
+
return false;
|
|
88
|
+
}
|
|
89
|
+
return true;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* @private
|
|
94
|
+
* @param {import('bookshelf').Model<any>} model
|
|
95
|
+
* @param {BaseOptions} options
|
|
96
|
+
* @returns {Promise<import('@tryghost/members-offers').Offer>}
|
|
97
|
+
*/
|
|
98
|
+
async mapToOffer(model, options) {
|
|
99
|
+
const json = model.toJSON();
|
|
100
|
+
|
|
101
|
+
const count = await this.OfferRedemptionModel.where({offer_id: json.id}).count('id', {
|
|
102
|
+
transacting: options.transacting
|
|
103
|
+
});
|
|
104
|
+
try {
|
|
105
|
+
return await Offer.create({
|
|
106
|
+
id: json.id,
|
|
107
|
+
name: json.name,
|
|
108
|
+
code: json.code,
|
|
109
|
+
display_title: json.portal_title,
|
|
110
|
+
display_description: json.portal_description,
|
|
111
|
+
type: json.discount_type === 'amount' ? 'fixed' : json.discount_type,
|
|
112
|
+
amount: json.discount_amount,
|
|
113
|
+
cadence: json.interval,
|
|
114
|
+
currency: json.currency,
|
|
115
|
+
duration: json.duration,
|
|
116
|
+
duration_in_months: json.duration_in_months,
|
|
117
|
+
redemptionCount: count,
|
|
118
|
+
status: json.active ? 'active' : 'archived',
|
|
119
|
+
tier: {
|
|
120
|
+
id: json.product.id,
|
|
121
|
+
name: json.product.name
|
|
122
|
+
}
|
|
123
|
+
}, null);
|
|
124
|
+
} catch (err) {
|
|
125
|
+
logger.error(err);
|
|
126
|
+
sentry.captureException(err);
|
|
127
|
+
return null;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* @param {string} id
|
|
133
|
+
* @param {BaseOptions} [options]
|
|
134
|
+
* @returns {Promise<import('@tryghost/members-offers').Offer>}
|
|
135
|
+
*/
|
|
136
|
+
async getById(id, options) {
|
|
137
|
+
const model = await this.OfferModel.findOne({id}, {
|
|
138
|
+
...options,
|
|
139
|
+
withRelated: ['product']
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
if (!model) {
|
|
143
|
+
return null;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
return this.mapToOffer(model, options);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* @param {string} id stripe_coupon_id
|
|
151
|
+
* @param {BaseOptions} [options]
|
|
152
|
+
* @returns {Promise<import('@tryghost/members-offers').Offer>}
|
|
153
|
+
*/
|
|
154
|
+
async getByStripeCouponId(id, options) {
|
|
155
|
+
const model = await this.OfferModel.findOne({stripe_coupon_id: id}, {
|
|
156
|
+
...options,
|
|
157
|
+
withRelated: ['product']
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
if (!model) {
|
|
161
|
+
return null;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
return this.mapToOffer(model, options);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* @param {ListOptions} options
|
|
169
|
+
* @returns {Promise<import('@tryghost/members-offers').Offer[]>}
|
|
170
|
+
*/
|
|
171
|
+
async getAll(options) {
|
|
172
|
+
const models = await this.OfferModel.findAll({
|
|
173
|
+
...options,
|
|
174
|
+
mongoTransformer,
|
|
175
|
+
withRelated: ['product']
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
const mapOptions = {
|
|
179
|
+
transacting: options && options.transacting
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
const offers = models.map(model => this.mapToOffer(model, mapOptions));
|
|
183
|
+
|
|
184
|
+
return (await Promise.all(offers)).filter(offer => offer !== null);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* @param {import('@tryghost/members-offers').Offer} offer
|
|
189
|
+
* @param {BaseOptions} [options]
|
|
190
|
+
* @returns {Promise<void>}
|
|
191
|
+
*/
|
|
192
|
+
async save(offer, options) {
|
|
193
|
+
/** @type any */
|
|
194
|
+
const data = {
|
|
195
|
+
id: offer.id,
|
|
196
|
+
name: offer.name.value,
|
|
197
|
+
code: offer.code.value,
|
|
198
|
+
portal_title: offer.displayTitle.value || null,
|
|
199
|
+
portal_description: offer.displayDescription.value || null,
|
|
200
|
+
discount_type: offer.type.value === 'fixed' ? 'amount' : offer.type.value,
|
|
201
|
+
discount_amount: offer.amount.value,
|
|
202
|
+
interval: offer.cadence.value,
|
|
203
|
+
product_id: offer.tier.id,
|
|
204
|
+
duration: offer.duration.value.type,
|
|
205
|
+
duration_in_months: offer.duration.value.type === 'repeating' ? offer.duration.value.months : null,
|
|
206
|
+
currency: offer.currency ? offer.currency.value : null,
|
|
207
|
+
active: offer.status.value === 'active'
|
|
208
|
+
};
|
|
209
|
+
|
|
210
|
+
if (offer.isNew) {
|
|
211
|
+
await this.OfferModel.add(data, options);
|
|
212
|
+
} else {
|
|
213
|
+
await this.OfferModel.edit(data, {...options, id: data.id});
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
for (const event of offer.events) {
|
|
217
|
+
if (options.transacting) {
|
|
218
|
+
// Only dispatch the event after the transaction has finished
|
|
219
|
+
// Because else the offer won't be committed to the database yet
|
|
220
|
+
options.transacting.executionPromise.then(() => {
|
|
221
|
+
DomainEvents.dispatch(event);
|
|
222
|
+
});
|
|
223
|
+
} else {
|
|
224
|
+
DomainEvents.dispatch(event);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
module.exports = OfferBookshelfRepository;
|
|
@@ -4,6 +4,7 @@ const OffersModule = require('@tryghost/members-offers');
|
|
|
4
4
|
const config = require('../../../shared/config');
|
|
5
5
|
const urlUtils = require('../../../shared/url-utils');
|
|
6
6
|
const models = require('../../models');
|
|
7
|
+
const OfferBookshelfRepository = require('./OfferBookshelfRepository');
|
|
7
8
|
|
|
8
9
|
let redirectManager;
|
|
9
10
|
|
|
@@ -15,10 +16,13 @@ module.exports = {
|
|
|
15
16
|
return urlUtils.urlJoin(urlUtils.getSubdir(), pathname);
|
|
16
17
|
}
|
|
17
18
|
});
|
|
19
|
+
const repository = new OfferBookshelfRepository(
|
|
20
|
+
models.Offer,
|
|
21
|
+
models.OfferRedemption
|
|
22
|
+
);
|
|
18
23
|
const offersModule = OffersModule.create({
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
redirectManager
|
|
24
|
+
redirectManager,
|
|
25
|
+
repository
|
|
22
26
|
});
|
|
23
27
|
|
|
24
28
|
this.api = offersModule.api;
|
|
@@ -9,10 +9,12 @@ module.exports = function getSiteProperties() {
|
|
|
9
9
|
description: settingsCache.get('description'),
|
|
10
10
|
logo: settingsCache.get('logo'),
|
|
11
11
|
icon: settingsCache.get('icon'),
|
|
12
|
+
cover_image: settingsCache.get('cover_image'),
|
|
12
13
|
accent_color: settingsCache.get('accent_color'),
|
|
13
14
|
locale: settingsCache.get('locale'),
|
|
14
15
|
url: urlUtils.urlFor('home', true),
|
|
15
|
-
version: ghostVersion.safe
|
|
16
|
+
version: ghostVersion.safe,
|
|
17
|
+
allow_self_signup: settingsCache.get('allow_self_signup')
|
|
16
18
|
};
|
|
17
19
|
|
|
18
20
|
if (config.get('client_sentry') && !config.get('client_sentry').disabled) {
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
module.exports = class RecommendationEnablerService {
|
|
2
|
+
/** @type {import('../settings/SettingsBREADService')} */
|
|
3
|
+
#settingsService;
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @param {object} deps
|
|
7
|
+
* @param {import('../settings/SettingsBREADService')} deps.settingsService
|
|
8
|
+
*/
|
|
9
|
+
constructor(deps) {
|
|
10
|
+
this.#settingsService = deps.settingsService;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* @returns {string}
|
|
15
|
+
*/
|
|
16
|
+
getSetting() {
|
|
17
|
+
this.#settingsService.read('recommendations_enabled');
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
*
|
|
22
|
+
* @param {string} value
|
|
23
|
+
* @returns Promise<void>
|
|
24
|
+
*/
|
|
25
|
+
async setSetting(value) {
|
|
26
|
+
this.#settingsService.edit([{key: 'recommendations_enabled', value}], {context: {internal: true}});
|
|
27
|
+
}
|
|
28
|
+
};
|
|
@@ -23,7 +23,14 @@ class RecommendationServiceWrapper {
|
|
|
23
23
|
const urlUtils = require('../../../shared/url-utils');
|
|
24
24
|
const models = require('../../models');
|
|
25
25
|
const sentry = require('../../../shared/sentry');
|
|
26
|
-
const
|
|
26
|
+
const settings = require('../settings');
|
|
27
|
+
const RecommendationEnablerService = require('./RecommendationEnablerService');
|
|
28
|
+
const {
|
|
29
|
+
BookshelfRecommendationRepository,
|
|
30
|
+
RecommendationService,
|
|
31
|
+
RecommendationController,
|
|
32
|
+
WellknownService
|
|
33
|
+
} = require('@tryghost/recommendations');
|
|
27
34
|
|
|
28
35
|
const mentions = require('../mentions');
|
|
29
36
|
|
|
@@ -37,11 +44,15 @@ class RecommendationServiceWrapper {
|
|
|
37
44
|
urlUtils
|
|
38
45
|
});
|
|
39
46
|
|
|
47
|
+
const settingsService = settings.getSettingsBREADServiceInstance();
|
|
48
|
+
const recommendationEnablerService = new RecommendationEnablerService({settingsService});
|
|
49
|
+
|
|
40
50
|
this.repository = new BookshelfRecommendationRepository(models.Recommendation, {
|
|
41
51
|
sentry
|
|
42
52
|
});
|
|
43
53
|
this.service = new RecommendationService({
|
|
44
54
|
repository: this.repository,
|
|
55
|
+
recommendationEnablerService,
|
|
45
56
|
wellknownService,
|
|
46
57
|
mentionSendingService: mentions.sendingService
|
|
47
58
|
});
|
|
@@ -51,6 +62,17 @@ class RecommendationServiceWrapper {
|
|
|
51
62
|
|
|
52
63
|
// eslint-disable-next-line no-console
|
|
53
64
|
this.service.init().catch(console.error);
|
|
65
|
+
|
|
66
|
+
// Add mapper to WebmentionMetadata
|
|
67
|
+
mentions.metadata.addMapper((url) => {
|
|
68
|
+
const p = '/.well-known/recommendations.json';
|
|
69
|
+
if (url.pathname.endsWith(p)) {
|
|
70
|
+
// Strip p
|
|
71
|
+
const newUrl = new URL(url.toString());
|
|
72
|
+
newUrl.pathname = newUrl.pathname.slice(0, -p.length);
|
|
73
|
+
return newUrl;
|
|
74
|
+
}
|
|
75
|
+
});
|
|
54
76
|
}
|
|
55
77
|
}
|
|
56
78
|
|
|
@@ -147,7 +147,7 @@ class SettingsBREADService {
|
|
|
147
147
|
* @param {Object[]} settings
|
|
148
148
|
* @param {Object} options
|
|
149
149
|
* @param {Object} [options.context]
|
|
150
|
-
* @param {Object} [stripeConnectData]
|
|
150
|
+
* @param {Object|null} [stripeConnectData]
|
|
151
151
|
* @returns
|
|
152
152
|
*/
|
|
153
153
|
async edit(settings, options, stripeConnectData) {
|