ghost 4.15.0 → 4.17.1
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/.eslintrc.js +7 -1
- package/content/themes/casper/assets/built/screen.css +1 -1
- package/content/themes/casper/assets/built/screen.css.map +1 -1
- package/content/themes/casper/assets/css/screen.css +1 -1
- package/content/themes/casper/default.hbs +2 -2
- package/content/themes/casper/package.json +1 -1
- package/content/themes/casper/page.hbs +28 -26
- package/content/themes/casper/partials/post-card.hbs +2 -2
- package/content/themes/casper/post.hbs +67 -65
- package/content/themes/casper/tag.hbs +2 -2
- package/core/boot.js +7 -7
- package/core/bridge.js +4 -3
- package/core/built/assets/{chunk.3.4b1d9e20e57164ac9c29.js → chunk.3.b80d3e1e6b8556aaff3c.js} +72 -71
- package/core/built/assets/ghost-dark-f7bf2dd8d8c702716f75bfa4ccd92df2.css +1 -0
- package/core/built/assets/{ghost.min-e35cfee26d942c364166f57f3dcc9e75.js → ghost.min-52a5420ffcea6bf17761b5c59cf020e2.js} +979 -908
- package/core/built/assets/ghost.min-741246f42f000c073999a5363434ea2c.css +1 -0
- package/core/built/assets/icons/discount-bubble.svg +1 -0
- package/core/built/assets/{vendor.min-ca33abc718f21a51327841d58f8875d0.js → vendor.min-1bfc9d56d27508db88ef417deb55f16f.js} +454 -434
- package/core/frontend/apps/amp/lib/helpers/amp_analytics.js +2 -2
- package/core/frontend/apps/amp/lib/helpers/amp_components.js +2 -1
- package/core/frontend/apps/amp/lib/helpers/amp_content.js +5 -1
- package/core/frontend/apps/amp/lib/helpers/amp_style.js +1 -1
- package/core/frontend/apps/amp/lib/router.js +8 -4
- package/core/frontend/apps/private-blogging/index.js +13 -5
- package/core/frontend/apps/private-blogging/lib/helpers/input_password.js +1 -1
- package/core/frontend/apps/private-blogging/lib/middleware.js +8 -3
- package/core/frontend/helpers/asset.js +10 -2
- package/core/frontend/helpers/author.js +5 -3
- package/core/frontend/helpers/authors.js +4 -3
- package/core/frontend/helpers/body_class.js +1 -1
- package/core/frontend/helpers/cancel_link.js +9 -2
- package/core/frontend/helpers/concat.js +1 -1
- package/core/frontend/helpers/content.js +1 -1
- package/core/frontend/helpers/date.js +1 -1
- package/core/frontend/helpers/encode.js +1 -1
- package/core/frontend/helpers/excerpt.js +2 -1
- package/core/frontend/helpers/facebook_url.js +2 -1
- package/core/frontend/helpers/foreach.js +11 -2
- package/core/frontend/helpers/get.js +14 -3
- package/core/frontend/helpers/ghost_foot.js +2 -1
- package/core/frontend/helpers/ghost_head.js +10 -1
- package/core/frontend/helpers/has.js +8 -3
- package/core/frontend/helpers/img_url.js +9 -3
- package/core/frontend/helpers/is.js +7 -2
- package/core/frontend/helpers/lang.js +1 -1
- package/core/frontend/helpers/link.js +11 -2
- package/core/frontend/helpers/link_class.js +11 -2
- package/core/frontend/helpers/match.js +12 -3
- package/core/frontend/helpers/navigation.js +13 -4
- package/core/frontend/helpers/pagination.js +15 -5
- package/core/frontend/helpers/plural.js +8 -2
- package/core/frontend/helpers/post_class.js +1 -1
- package/core/frontend/helpers/prev_post.js +9 -2
- package/core/frontend/helpers/price.js +11 -6
- package/core/frontend/helpers/products.js +2 -1
- package/core/frontend/helpers/reading_time.js +4 -2
- package/core/frontend/helpers/t.js +1 -1
- package/core/frontend/helpers/tags.js +3 -1
- package/core/frontend/helpers/title.js +1 -1
- package/core/frontend/helpers/twitter_url.js +2 -1
- package/core/frontend/helpers/url.js +3 -1
- package/core/frontend/services/proxy.js +34 -57
- package/core/frontend/services/rendering.js +24 -0
- package/core/frontend/services/routing/controllers/channel.js +6 -2
- package/core/frontend/services/routing/controllers/collection.js +6 -2
- package/core/frontend/services/routing/middlewares/page-param.js +6 -2
- package/core/frontend/services/theme-engine/middleware.js +23 -6
- package/core/frontend/services/theme-engine/preview.js +31 -8
- package/core/server/adapters/scheduling/post-scheduling/scheduler-intergation.js +6 -4
- package/core/server/adapters/storage/LocalFileStorage.js +10 -4
- package/core/server/api/canary/custom-theme-settings.js +22 -0
- package/core/server/api/canary/index.js +4 -0
- package/core/server/api/canary/members.js +1 -1
- package/core/server/api/canary/redirects.js +5 -5
- package/core/server/api/canary/settings.js +16 -148
- package/core/server/api/canary/utils/serializers/output/custom-theme-settings.js +13 -0
- package/core/server/api/canary/utils/serializers/output/index.js +4 -0
- package/core/server/api/canary/utils/validators/input/settings.js +23 -1
- package/core/server/api/v2/redirects.js +3 -3
- package/core/server/api/v2/settings.js +3 -4
- package/core/server/api/v3/redirects.js +5 -5
- package/core/server/api/v3/settings.js +16 -136
- package/core/server/api/v3/utils/validators/input/settings.js +23 -1
- package/core/server/data/db/state-manager.js +1 -1
- package/core/server/data/exporter/table-lists.js +3 -1
- package/core/server/data/importer/import-manager.js +398 -0
- package/core/server/data/importer/importers/data/data-importer.js +162 -0
- package/core/server/data/importer/importers/data/index.js +1 -162
- package/core/server/data/importer/index.js +1 -379
- package/core/server/data/migrations/versions/4.16/01-add-custom-theme-settings-table.js +9 -0
- package/core/server/data/migrations/versions/4.17/01-add-custom-theme-settings-permissions.js +21 -0
- package/core/server/data/migrations/versions/4.17/02-add-offers-table.js +19 -0
- package/core/server/data/migrations/versions/4.17/03-add-offers-permissions.js +35 -0
- package/core/server/data/schema/fixtures/fixtures.json +32 -0
- package/core/server/data/schema/schema.js +33 -0
- package/core/server/models/custom-theme-setting.js +9 -0
- package/core/server/models/index.js +2 -0
- package/core/server/services/custom-theme-settings.js +8 -0
- package/core/server/services/members/api.js +4 -1
- package/core/server/services/redirects/index.js +15 -0
- package/core/{frontend → server}/services/redirects/settings.js +13 -6
- package/core/server/services/redirects/validation.js +44 -0
- package/core/{frontend/services/settings → server/services/route-settings}/default-routes.yaml +0 -0
- package/core/server/services/route-settings/default-settings-manager.js +62 -0
- package/core/server/services/route-settings/index.js +32 -1
- package/core/server/services/route-settings/route-settings.js +38 -12
- package/core/server/services/route-settings/settings-loader.js +102 -0
- package/core/{frontend/services/settings → server/services/route-settings}/validate.js +38 -28
- package/core/server/services/route-settings/yaml-parser.js +53 -0
- package/core/server/services/settings/index.js +13 -16
- package/core/server/services/settings/settings-bread-service.js +188 -0
- package/core/server/services/settings/settings-utils.js +32 -0
- package/core/server/services/themes/ThemeStorage.js +5 -4
- package/core/server/services/themes/activation-bridge.js +14 -0
- package/core/server/services/themes/validate.js +5 -2
- package/core/server/web/admin/views/default-prod.html +4 -4
- package/core/server/web/admin/views/default.html +4 -4
- package/core/server/web/api/canary/admin/routes.js +5 -1
- package/core/server/web/members/app.js +3 -0
- package/core/server/web/oauth/app.js +7 -8
- package/core/server/web/shared/middlewares/custom-redirects.js +82 -59
- package/core/server/web/site/routes.js +2 -2
- package/core/shared/config/defaults.json +2 -2
- package/core/shared/config/overrides.json +1 -1
- package/core/shared/custom-theme-settings-cache.js +3 -0
- package/core/shared/i18n/translations/en.json +2 -13
- package/core/shared/labs.js +2 -2
- package/package.json +42 -41
- package/yarn.lock +916 -901
- package/core/built/assets/ghost-dark-faf931d90e92535e6c03ca16793cbe7b.css +0 -1
- package/core/built/assets/ghost.min-7aa074ad556a8455155ac88ceaca03ab.css +0 -1
- package/core/frontend/services/redirects/index.js +0 -9
- package/core/frontend/services/redirects/validation.js +0 -28
- package/core/frontend/services/settings/ensure-settings.js +0 -47
- package/core/frontend/services/settings/index.js +0 -104
- package/core/frontend/services/settings/loader.js +0 -89
- package/core/frontend/services/settings/yaml-parser.js +0 -31
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
const models = require('../../../models');
|
|
2
|
-
const
|
|
2
|
+
const tpl = require('@tryghost/tpl');
|
|
3
3
|
const errors = require('@tryghost/errors');
|
|
4
4
|
|
|
5
|
+
const messages = {
|
|
6
|
+
resourceNotFound: '{resource} not found.'
|
|
7
|
+
};
|
|
8
|
+
|
|
5
9
|
/**
|
|
6
10
|
* @description Load the internal scheduler integration
|
|
7
11
|
*
|
|
@@ -12,9 +16,7 @@ const getSchedulerIntegration = function () {
|
|
|
12
16
|
.then((integration) => {
|
|
13
17
|
if (!integration) {
|
|
14
18
|
throw new errors.NotFoundError({
|
|
15
|
-
message:
|
|
16
|
-
resource: 'Integration'
|
|
17
|
-
})
|
|
19
|
+
message: tpl(messages.resourceNotFound, {resource: 'Integration'})
|
|
18
20
|
});
|
|
19
21
|
}
|
|
20
22
|
return integration.toJSON();
|
|
@@ -7,13 +7,19 @@ const path = require('path');
|
|
|
7
7
|
const Promise = require('bluebird');
|
|
8
8
|
const moment = require('moment');
|
|
9
9
|
const config = require('../../../shared/config');
|
|
10
|
-
const
|
|
10
|
+
const tpl = require('@tryghost/tpl');
|
|
11
11
|
const logging = require('@tryghost/logging');
|
|
12
12
|
const errors = require('@tryghost/errors');
|
|
13
13
|
const constants = require('@tryghost/constants');
|
|
14
14
|
const urlUtils = require('../../../shared/url-utils');
|
|
15
15
|
const StorageBase = require('ghost-storage-base');
|
|
16
16
|
|
|
17
|
+
const messages = {
|
|
18
|
+
imageNotFound: 'Image not found',
|
|
19
|
+
imageNotFoundWithRef: 'Image not found: {img}',
|
|
20
|
+
cannotReadImage: 'Could not read image: {img}'
|
|
21
|
+
};
|
|
22
|
+
|
|
17
23
|
class LocalFileStore extends StorageBase {
|
|
18
24
|
constructor() {
|
|
19
25
|
super();
|
|
@@ -119,7 +125,7 @@ class LocalFileStore extends StorageBase {
|
|
|
119
125
|
if (err) {
|
|
120
126
|
if (err.statusCode === 404) {
|
|
121
127
|
return next(new errors.NotFoundError({
|
|
122
|
-
message:
|
|
128
|
+
message: tpl(messages.imageNotFound),
|
|
123
129
|
code: 'STATIC_FILE_NOT_FOUND',
|
|
124
130
|
property: err.path
|
|
125
131
|
}));
|
|
@@ -169,7 +175,7 @@ class LocalFileStore extends StorageBase {
|
|
|
169
175
|
if (err.code === 'ENOENT' || err.code === 'ENOTDIR') {
|
|
170
176
|
return reject(new errors.NotFoundError({
|
|
171
177
|
err: err,
|
|
172
|
-
message:
|
|
178
|
+
message: tpl(messages.imageNotFoundWithRef, {img: options.path})
|
|
173
179
|
}));
|
|
174
180
|
}
|
|
175
181
|
|
|
@@ -183,7 +189,7 @@ class LocalFileStore extends StorageBase {
|
|
|
183
189
|
|
|
184
190
|
return reject(new errors.GhostError({
|
|
185
191
|
err: err,
|
|
186
|
-
message:
|
|
192
|
+
message: tpl(messages.cannotReadImage, {img: options.path})
|
|
187
193
|
}));
|
|
188
194
|
}
|
|
189
195
|
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
const customThemeSettingsService = require('../../services/custom-theme-settings');
|
|
2
|
+
|
|
3
|
+
module.exports = {
|
|
4
|
+
docName: 'custom_theme_settings',
|
|
5
|
+
|
|
6
|
+
browse: {
|
|
7
|
+
permissions: true,
|
|
8
|
+
query() {
|
|
9
|
+
return customThemeSettingsService.listSettings();
|
|
10
|
+
}
|
|
11
|
+
},
|
|
12
|
+
|
|
13
|
+
edit: {
|
|
14
|
+
headers: {
|
|
15
|
+
cacheInvalidate: true
|
|
16
|
+
},
|
|
17
|
+
permissions: true,
|
|
18
|
+
query(frame) {
|
|
19
|
+
return customThemeSettingsService.updateSettings(frame.data.custom_theme_settings);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
};
|
|
@@ -153,6 +153,10 @@ module.exports = {
|
|
|
153
153
|
return shared.pipeline(require('./snippets'), localUtils);
|
|
154
154
|
},
|
|
155
155
|
|
|
156
|
+
get customThemeSettings() {
|
|
157
|
+
return shared.pipeline(require('./custom-theme-settings'), localUtils);
|
|
158
|
+
},
|
|
159
|
+
|
|
156
160
|
get serializers() {
|
|
157
161
|
return require('./utils/serializers');
|
|
158
162
|
},
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
const path = require('path');
|
|
2
2
|
|
|
3
3
|
const web = require('../../web');
|
|
4
|
-
const redirects = require('
|
|
4
|
+
const redirects = require('../../services/redirects');
|
|
5
5
|
|
|
6
6
|
module.exports = {
|
|
7
7
|
docName: 'redirects',
|
|
@@ -11,7 +11,7 @@ module.exports = {
|
|
|
11
11
|
disposition: {
|
|
12
12
|
type: 'file',
|
|
13
13
|
value() {
|
|
14
|
-
return redirects.
|
|
14
|
+
return redirects.api.getRedirectsFilePath()
|
|
15
15
|
.then((filePath) => {
|
|
16
16
|
// TODO: Default file type is .json for backward compatibility.
|
|
17
17
|
// When .yaml becomes default or .json is removed at v4,
|
|
@@ -26,13 +26,13 @@ module.exports = {
|
|
|
26
26
|
permissions: true,
|
|
27
27
|
response: {
|
|
28
28
|
async format() {
|
|
29
|
-
const filePath = await redirects.
|
|
29
|
+
const filePath = await redirects.api.getRedirectsFilePath();
|
|
30
30
|
|
|
31
31
|
return filePath === null || path.extname(filePath) === '.json' ? 'json' : 'plain';
|
|
32
32
|
}
|
|
33
33
|
},
|
|
34
34
|
query() {
|
|
35
|
-
return redirects.
|
|
35
|
+
return redirects.api.get();
|
|
36
36
|
}
|
|
37
37
|
},
|
|
38
38
|
|
|
@@ -42,7 +42,7 @@ module.exports = {
|
|
|
42
42
|
cacheInvalidate: true
|
|
43
43
|
},
|
|
44
44
|
query(frame) {
|
|
45
|
-
return redirects.
|
|
45
|
+
return redirects.api.setFromFilePath(frame.file.path, frame.file.ext)
|
|
46
46
|
.then(() => {
|
|
47
47
|
// CASE: trigger that redirects are getting re-registered
|
|
48
48
|
web.shared.middlewares.customRedirects.reload();
|
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
const Promise = require('bluebird');
|
|
2
2
|
const _ = require('lodash');
|
|
3
|
-
const validator = require('@tryghost/validator');
|
|
4
3
|
const models = require('../../models');
|
|
5
4
|
const routeSettings = require('../../services/route-settings');
|
|
6
|
-
const frontendSettings = require('../../../frontend/services/settings');
|
|
7
5
|
const i18n = require('../../../shared/i18n');
|
|
8
|
-
const {BadRequestError
|
|
6
|
+
const {BadRequestError} = require('@tryghost/errors');
|
|
9
7
|
const settingsService = require('../../services/settings');
|
|
10
|
-
const settingsCache = require('../../../shared/settings-cache');
|
|
11
8
|
const membersService = require('../../services/members');
|
|
12
9
|
|
|
10
|
+
const settingsBREADService = settingsService.getSettingsBREADServiceInstance();
|
|
11
|
+
|
|
13
12
|
module.exports = {
|
|
14
13
|
docName: 'settings',
|
|
15
14
|
|
|
@@ -17,26 +16,7 @@ module.exports = {
|
|
|
17
16
|
options: ['group'],
|
|
18
17
|
permissions: true,
|
|
19
18
|
query(frame) {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
// CASE: no context passed (functional call)
|
|
23
|
-
if (!frame.options.context) {
|
|
24
|
-
return Promise.resolve(settings.filter((setting) => {
|
|
25
|
-
return setting.group === 'site';
|
|
26
|
-
}));
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
if (!frame.options.context.internal) {
|
|
30
|
-
// CASE: omit core settings unless internal request
|
|
31
|
-
settings = _.filter(settings, (setting) => {
|
|
32
|
-
const isCore = setting.group === 'core';
|
|
33
|
-
return !isCore;
|
|
34
|
-
});
|
|
35
|
-
// CASE: omit secret settings unless internal request
|
|
36
|
-
settings = settings.map(settingsService.hideValueIfSecret);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
return settings;
|
|
19
|
+
return settingsBREADService.browse(frame.options.context);
|
|
40
20
|
}
|
|
41
21
|
},
|
|
42
22
|
|
|
@@ -55,41 +35,7 @@ module.exports = {
|
|
|
55
35
|
}
|
|
56
36
|
},
|
|
57
37
|
query(frame) {
|
|
58
|
-
|
|
59
|
-
if (frame.options.key === 'slack') {
|
|
60
|
-
const slackURL = settingsCache.get('slack_url', {resolve: false});
|
|
61
|
-
const slackUsername = settingsCache.get('slack_username', {resolve: false});
|
|
62
|
-
|
|
63
|
-
setting = slackURL || slackUsername;
|
|
64
|
-
setting.key = 'slack';
|
|
65
|
-
setting.value = [{
|
|
66
|
-
url: slackURL && slackURL.value,
|
|
67
|
-
username: slackUsername && slackUsername.value
|
|
68
|
-
}];
|
|
69
|
-
} else {
|
|
70
|
-
setting = settingsCache.get(frame.options.key, {resolve: false});
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
if (!setting) {
|
|
74
|
-
return Promise.reject(new NotFoundError({
|
|
75
|
-
message: i18n.t('errors.api.settings.problemFindingSetting', {
|
|
76
|
-
key: frame.options.key
|
|
77
|
-
})
|
|
78
|
-
}));
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
// @TODO: handle in settings model permissible fn
|
|
82
|
-
if (setting.group === 'core' && !(frame.options.context && frame.options.context.internal)) {
|
|
83
|
-
return Promise.reject(new NoPermissionError({
|
|
84
|
-
message: i18n.t('errors.api.settings.accessCoreSettingFromExtReq')
|
|
85
|
-
}));
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
setting = settingsService.hideValueIfSecret(setting);
|
|
89
|
-
|
|
90
|
-
return {
|
|
91
|
-
[frame.options.key]: setting
|
|
92
|
-
};
|
|
38
|
+
return settingsBREADService.read(frame.options.key, frame.options.context);
|
|
93
39
|
}
|
|
94
40
|
},
|
|
95
41
|
|
|
@@ -153,17 +99,7 @@ module.exports = {
|
|
|
153
99
|
],
|
|
154
100
|
async query(frame) {
|
|
155
101
|
const {email, type} = frame.data;
|
|
156
|
-
if (typeof email !== 'string' || !validator.isEmail(email)) {
|
|
157
|
-
throw new BadRequestError({
|
|
158
|
-
message: i18n.t('errors.api.settings.invalidEmailReceived')
|
|
159
|
-
});
|
|
160
|
-
}
|
|
161
102
|
|
|
162
|
-
if (!type || !['fromAddressUpdate', 'supportAddressUpdate'].includes(type)) {
|
|
163
|
-
throw new BadRequestError({
|
|
164
|
-
message: 'Invalid email type recieved'
|
|
165
|
-
});
|
|
166
|
-
}
|
|
167
103
|
try {
|
|
168
104
|
// Send magic link to update fromAddress
|
|
169
105
|
await membersService.settings.sendEmailAddressUpdateMagicLink({
|
|
@@ -225,91 +161,23 @@ module.exports = {
|
|
|
225
161
|
permissions: {
|
|
226
162
|
unsafeAttrsObject(frame) {
|
|
227
163
|
return _.find(frame.data.settings, {key: 'labs'});
|
|
228
|
-
},
|
|
229
|
-
async before(frame) {
|
|
230
|
-
if (frame.options.context && frame.options.context.internal) {
|
|
231
|
-
return;
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
const firstCoreSetting = frame.data.settings.find(setting => setting.group === 'core');
|
|
235
|
-
if (firstCoreSetting) {
|
|
236
|
-
throw new NoPermissionError({
|
|
237
|
-
message: i18n.t('errors.api.settings.accessCoreSettingFromExtReq')
|
|
238
|
-
});
|
|
239
|
-
}
|
|
240
164
|
}
|
|
241
165
|
},
|
|
242
166
|
async query(frame) {
|
|
167
|
+
let stripeConnectData;
|
|
243
168
|
const stripeConnectIntegrationToken = frame.data.settings.find(setting => setting.key === 'stripe_connect_integration_token');
|
|
244
169
|
|
|
245
|
-
const settings = frame.data.settings.filter((setting) => {
|
|
246
|
-
// The `stripe_connect_integration_token` "setting" is only used to set the `stripe_connect_*` settings.
|
|
247
|
-
return ![
|
|
248
|
-
'stripe_connect_integration_token',
|
|
249
|
-
'stripe_connect_publishable_key',
|
|
250
|
-
'stripe_connect_secret_key',
|
|
251
|
-
'stripe_connect_livemode',
|
|
252
|
-
'stripe_connect_account_id',
|
|
253
|
-
'stripe_connect_display_name'
|
|
254
|
-
].includes(setting.key)
|
|
255
|
-
// Remove obfuscated settings
|
|
256
|
-
&& !(setting.value === settingsService.obfuscatedSetting && settingsService.isSecretSetting(setting));
|
|
257
|
-
});
|
|
258
|
-
|
|
259
|
-
const getSetting = setting => settingsCache.get(setting.key, {resolve: false});
|
|
260
|
-
|
|
261
|
-
const firstUnknownSetting = settings.find(setting => !getSetting(setting));
|
|
262
|
-
|
|
263
|
-
if (firstUnknownSetting) {
|
|
264
|
-
throw new NotFoundError({
|
|
265
|
-
message: i18n.t('errors.api.settings.problemFindingSetting', {
|
|
266
|
-
key: firstUnknownSetting.key
|
|
267
|
-
})
|
|
268
|
-
});
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
if (!(frame.options.context && frame.options.context.internal)) {
|
|
272
|
-
const firstCoreSetting = settings.find(setting => getSetting(setting).group === 'core');
|
|
273
|
-
if (firstCoreSetting) {
|
|
274
|
-
throw new NoPermissionError({
|
|
275
|
-
message: i18n.t('errors.api.settings.accessCoreSettingFromExtReq')
|
|
276
|
-
});
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
|
|
280
170
|
if (stripeConnectIntegrationToken && stripeConnectIntegrationToken.value) {
|
|
281
171
|
const getSessionProp = prop => frame.original.session[prop];
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
settings.push({
|
|
289
|
-
key: 'stripe_connect_secret_key',
|
|
290
|
-
value: data.secret_key
|
|
291
|
-
});
|
|
292
|
-
settings.push({
|
|
293
|
-
key: 'stripe_connect_livemode',
|
|
294
|
-
value: data.livemode
|
|
295
|
-
});
|
|
296
|
-
settings.push({
|
|
297
|
-
key: 'stripe_connect_display_name',
|
|
298
|
-
value: data.display_name
|
|
299
|
-
});
|
|
300
|
-
settings.push({
|
|
301
|
-
key: 'stripe_connect_account_id',
|
|
302
|
-
value: data.account_id
|
|
303
|
-
});
|
|
304
|
-
} catch (err) {
|
|
305
|
-
throw new BadRequestError({
|
|
306
|
-
err,
|
|
307
|
-
message: 'The Stripe Connect token could not be parsed.'
|
|
308
|
-
});
|
|
309
|
-
}
|
|
172
|
+
|
|
173
|
+
stripeConnectData = await settingsBREADService.getStripeConnectData(
|
|
174
|
+
stripeConnectIntegrationToken,
|
|
175
|
+
getSessionProp,
|
|
176
|
+
membersService.stripeConnect.getStripeConnectTokenData
|
|
177
|
+
);
|
|
310
178
|
}
|
|
311
179
|
|
|
312
|
-
return
|
|
180
|
+
return await settingsBREADService.edit(frame.data.settings, frame.options, stripeConnectData);
|
|
313
181
|
}
|
|
314
182
|
},
|
|
315
183
|
|
|
@@ -321,8 +189,8 @@ module.exports = {
|
|
|
321
189
|
method: 'edit'
|
|
322
190
|
},
|
|
323
191
|
async query(frame) {
|
|
324
|
-
await routeSettings.setFromFilePath(frame.file.path);
|
|
325
|
-
const getRoutesHash = () =>
|
|
192
|
+
await routeSettings.api.setFromFilePath(frame.file.path);
|
|
193
|
+
const getRoutesHash = () => routeSettings.api.getCurrentHash();
|
|
326
194
|
await settingsService.syncRoutesHash(getRoutesHash);
|
|
327
195
|
}
|
|
328
196
|
},
|
|
@@ -341,7 +209,7 @@ module.exports = {
|
|
|
341
209
|
method: 'browse'
|
|
342
210
|
},
|
|
343
211
|
query() {
|
|
344
|
-
return routeSettings.get();
|
|
212
|
+
return routeSettings.api.get();
|
|
345
213
|
}
|
|
346
214
|
}
|
|
347
215
|
};
|
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
const Promise = require('bluebird');
|
|
2
2
|
const _ = require('lodash');
|
|
3
3
|
const i18n = require('../../../../../../shared/i18n');
|
|
4
|
-
const {NotFoundError, ValidationError} = require('@tryghost/errors');
|
|
4
|
+
const {NotFoundError, ValidationError, BadRequestError} = require('@tryghost/errors');
|
|
5
|
+
const validator = require('@tryghost/validator');
|
|
6
|
+
|
|
7
|
+
const messages = {
|
|
8
|
+
invalidEmailReceived: 'Please send a valid email',
|
|
9
|
+
invalidEmailTypeReceived: 'Invalid email type received'
|
|
10
|
+
};
|
|
5
11
|
|
|
6
12
|
module.exports = {
|
|
7
13
|
read(apiConfig, frame) {
|
|
@@ -62,5 +68,21 @@ module.exports = {
|
|
|
62
68
|
if (errors.length) {
|
|
63
69
|
return Promise.reject(errors[0]);
|
|
64
70
|
}
|
|
71
|
+
},
|
|
72
|
+
|
|
73
|
+
updateMembersEmail(apiConfig, frame) {
|
|
74
|
+
const {email, type} = frame.data;
|
|
75
|
+
|
|
76
|
+
if (typeof email !== 'string' || !validator.isEmail(email)) {
|
|
77
|
+
throw new BadRequestError({
|
|
78
|
+
message: messages.invalidEmailReceived
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (!type || !['fromAddressUpdate', 'supportAddressUpdate'].includes(type)) {
|
|
83
|
+
throw new BadRequestError({
|
|
84
|
+
message: messages.invalidEmailTypeReceived
|
|
85
|
+
});
|
|
86
|
+
}
|
|
65
87
|
}
|
|
66
88
|
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const web = require('../../web');
|
|
2
|
-
const redirects = require('
|
|
2
|
+
const redirects = require('../../services/redirects');
|
|
3
3
|
|
|
4
4
|
module.exports = {
|
|
5
5
|
docName: 'redirects',
|
|
@@ -13,7 +13,7 @@ module.exports = {
|
|
|
13
13
|
},
|
|
14
14
|
permissions: true,
|
|
15
15
|
query() {
|
|
16
|
-
return redirects.
|
|
16
|
+
return redirects.api.get();
|
|
17
17
|
}
|
|
18
18
|
},
|
|
19
19
|
|
|
@@ -23,7 +23,7 @@ module.exports = {
|
|
|
23
23
|
cacheInvalidate: true
|
|
24
24
|
},
|
|
25
25
|
query(frame) {
|
|
26
|
-
return redirects.
|
|
26
|
+
return redirects.api.setFromFilePath(frame.file.path)
|
|
27
27
|
.then(() => {
|
|
28
28
|
// CASE: trigger that redirects are getting re-registered
|
|
29
29
|
web.shared.middlewares.customRedirects.reload();
|
|
@@ -2,7 +2,6 @@ const Promise = require('bluebird');
|
|
|
2
2
|
const _ = require('lodash');
|
|
3
3
|
const models = require('../../models');
|
|
4
4
|
const routeSettings = require('../../services/route-settings');
|
|
5
|
-
const frontendSettings = require('../../../frontend/services/settings');
|
|
6
5
|
const i18n = require('../../../shared/i18n');
|
|
7
6
|
const {NoPermissionError, NotFoundError} = require('@tryghost/errors');
|
|
8
7
|
const settingsService = require('../../services/settings');
|
|
@@ -168,8 +167,8 @@ module.exports = {
|
|
|
168
167
|
method: 'edit'
|
|
169
168
|
},
|
|
170
169
|
async query(frame) {
|
|
171
|
-
await routeSettings.setFromFilePath(frame.file.path);
|
|
172
|
-
const getRoutesHash = () =>
|
|
170
|
+
await routeSettings.api.setFromFilePath(frame.file.path);
|
|
171
|
+
const getRoutesHash = () => routeSettings.api.getCurrentHash();
|
|
173
172
|
await settingsService.syncRoutesHash(getRoutesHash);
|
|
174
173
|
}
|
|
175
174
|
},
|
|
@@ -188,7 +187,7 @@ module.exports = {
|
|
|
188
187
|
method: 'browse'
|
|
189
188
|
},
|
|
190
189
|
query() {
|
|
191
|
-
return routeSettings.get();
|
|
190
|
+
return routeSettings.api.get();
|
|
192
191
|
}
|
|
193
192
|
}
|
|
194
193
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
const path = require('path');
|
|
2
2
|
|
|
3
3
|
const web = require('../../web');
|
|
4
|
-
const redirects = require('
|
|
4
|
+
const redirects = require('../../services/redirects');
|
|
5
5
|
|
|
6
6
|
module.exports = {
|
|
7
7
|
docName: 'redirects',
|
|
@@ -11,7 +11,7 @@ module.exports = {
|
|
|
11
11
|
disposition: {
|
|
12
12
|
type: 'file',
|
|
13
13
|
value() {
|
|
14
|
-
return redirects.
|
|
14
|
+
return redirects.api.getRedirectsFilePath()
|
|
15
15
|
.then((filePath) => {
|
|
16
16
|
// TODO: Default file type is .json for backward compatibility.
|
|
17
17
|
// When .yaml becomes default or .json is removed at v4,
|
|
@@ -26,13 +26,13 @@ module.exports = {
|
|
|
26
26
|
permissions: true,
|
|
27
27
|
response: {
|
|
28
28
|
async format() {
|
|
29
|
-
const filePath = await redirects.
|
|
29
|
+
const filePath = await redirects.api.getRedirectsFilePath();
|
|
30
30
|
|
|
31
31
|
return filePath === null || path.extname(filePath) === '.json' ? 'json' : 'plain';
|
|
32
32
|
}
|
|
33
33
|
},
|
|
34
34
|
query() {
|
|
35
|
-
return redirects.
|
|
35
|
+
return redirects.api.get();
|
|
36
36
|
}
|
|
37
37
|
},
|
|
38
38
|
|
|
@@ -42,7 +42,7 @@ module.exports = {
|
|
|
42
42
|
cacheInvalidate: true
|
|
43
43
|
},
|
|
44
44
|
query(frame) {
|
|
45
|
-
return redirects.
|
|
45
|
+
return redirects.api.setFromFilePath(frame.file.path, frame.file.ext)
|
|
46
46
|
.then(() => {
|
|
47
47
|
// CASE: trigger that redirects are getting re-registered
|
|
48
48
|
web.shared.middlewares.customRedirects.reload();
|