ghost 4.15.1 → 4.16.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/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/built/assets/ghost-dark-bb2831fc27fcb02893ed0a761207dc63.css +1 -0
- package/core/built/assets/{ghost.min-e35cfee26d942c364166f57f3dcc9e75.js → ghost.min-d1d99f3ed6e0f427874b2a11e7078475.js} +228 -187
- package/core/built/assets/ghost.min-e7612edfa72b0fe2c201b387923e6fc7.css +1 -0
- package/core/built/assets/icons/discount-bubble.svg +1 -0
- package/core/built/assets/{vendor.min-ca33abc718f21a51327841d58f8875d0.js → vendor.min-3660ec7864887f1496fe7a27fd23ab76.js} +44 -42
- package/core/frontend/helpers/ghost_head.js +7 -1
- package/core/frontend/services/settings/loader.js +2 -2
- package/core/frontend/services/theme-engine/middleware.js +4 -1
- package/core/server/api/canary/settings.js +13 -144
- package/core/server/api/canary/utils/validators/input/settings.js +23 -1
- package/core/server/api/v3/settings.js +13 -132
- package/core/server/api/v3/utils/validators/input/settings.js +23 -1
- package/core/server/data/exporter/table-lists.js +1 -0
- 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/schema/schema.js +16 -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 +1 -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/members/app.js +2 -0
- package/core/shared/custom-theme-settings-cache.js +3 -0
- package/core/shared/labs.js +2 -1
- package/package.json +28 -27
- package/yarn.lock +806 -795
- package/core/built/assets/ghost-dark-faf931d90e92535e6c03ca16793cbe7b.css +0 -1
- package/core/built/assets/ghost.min-7aa074ad556a8455155ac88ceaca03ab.css +0 -1
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
const _ = require('lodash');
|
|
2
|
+
const tpl = require('@tryghost/tpl');
|
|
3
|
+
const {NotFoundError, NoPermissionError, BadRequestError} = require('@tryghost/errors');
|
|
4
|
+
const {obfuscatedSetting, isSecretSetting, hideValueIfSecret} = require('./settings-utils');
|
|
5
|
+
|
|
6
|
+
const messages = {
|
|
7
|
+
problemFindingSetting: 'Problem finding setting: {key}',
|
|
8
|
+
accessCoreSettingFromExtReq: 'Attempted to access core setting from external request'
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
class SettingsBREADService {
|
|
12
|
+
/**
|
|
13
|
+
*
|
|
14
|
+
* @param {Object} options
|
|
15
|
+
* @param {Object} options.SettingsModel
|
|
16
|
+
* @param {Object} options.settingsCache - SettingsCache instance
|
|
17
|
+
*/
|
|
18
|
+
constructor({SettingsModel, settingsCache}) {
|
|
19
|
+
this.SettingsModel = SettingsModel;
|
|
20
|
+
this.settingsCache = settingsCache;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
*
|
|
25
|
+
* @param {Object} context ghost API context instance
|
|
26
|
+
* @returns
|
|
27
|
+
*/
|
|
28
|
+
browse(context) {
|
|
29
|
+
let settings = this.settingsCache.getAll();
|
|
30
|
+
|
|
31
|
+
// CASE: no context passed (functional call)
|
|
32
|
+
if (!context) {
|
|
33
|
+
return Promise.resolve(settings.filter((setting) => {
|
|
34
|
+
return setting.group === 'site';
|
|
35
|
+
}));
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (!context.internal) {
|
|
39
|
+
// CASE: omit core settings unless internal request
|
|
40
|
+
settings = _.filter(settings, (setting) => {
|
|
41
|
+
const isCore = setting.group === 'core';
|
|
42
|
+
return !isCore;
|
|
43
|
+
});
|
|
44
|
+
// CASE: omit secret settings unless internal request
|
|
45
|
+
settings = settings.map(hideValueIfSecret);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return settings;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
*
|
|
53
|
+
* @param {String} key setting key
|
|
54
|
+
* @param {Object} [context] API context instance
|
|
55
|
+
* @returns {Object} an object with a filled out key that comes in a parameter
|
|
56
|
+
*/
|
|
57
|
+
read(key, context) {
|
|
58
|
+
let setting;
|
|
59
|
+
|
|
60
|
+
if (key === 'slack') {
|
|
61
|
+
const slackURL = this.settingsCache.get('slack_url', {resolve: false});
|
|
62
|
+
const slackUsername = this.settingsCache.get('slack_username', {resolve: false});
|
|
63
|
+
|
|
64
|
+
setting = slackURL || slackUsername;
|
|
65
|
+
setting.key = 'slack';
|
|
66
|
+
setting.value = [{
|
|
67
|
+
url: slackURL && slackURL.value,
|
|
68
|
+
username: slackUsername && slackUsername.value
|
|
69
|
+
}];
|
|
70
|
+
} else {
|
|
71
|
+
setting = this.settingsCache.get(key, {resolve: false});
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (!setting) {
|
|
75
|
+
return Promise.reject(new NotFoundError({
|
|
76
|
+
message: tpl(messages.problemFindingSetting, {
|
|
77
|
+
key: key
|
|
78
|
+
})
|
|
79
|
+
}));
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// @TODO: handle in settings model permissible fn
|
|
83
|
+
if (setting.group === 'core' && !(context && context.internal)) {
|
|
84
|
+
return Promise.reject(new NoPermissionError({
|
|
85
|
+
message: tpl(messages.accessCoreSettingFromExtReq)
|
|
86
|
+
}));
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
setting = hideValueIfSecret(setting);
|
|
90
|
+
|
|
91
|
+
return {
|
|
92
|
+
[key]: setting
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
*
|
|
98
|
+
* @param {Object[]} settings
|
|
99
|
+
* @param {Object} options
|
|
100
|
+
* @param {Object} [options.context]
|
|
101
|
+
* @param {Object} [stripeConnectData]
|
|
102
|
+
* @returns
|
|
103
|
+
*/
|
|
104
|
+
async edit(settings, options, stripeConnectData) {
|
|
105
|
+
const filteredSettings = settings.filter((setting) => {
|
|
106
|
+
// The `stripe_connect_integration_token` "setting" is only used to set the `stripe_connect_*` settings.
|
|
107
|
+
return ![
|
|
108
|
+
'stripe_connect_integration_token',
|
|
109
|
+
'stripe_connect_publishable_key',
|
|
110
|
+
'stripe_connect_secret_key',
|
|
111
|
+
'stripe_connect_livemode',
|
|
112
|
+
'stripe_connect_account_id',
|
|
113
|
+
'stripe_connect_display_name'
|
|
114
|
+
].includes(setting.key)
|
|
115
|
+
// Remove obfuscated settings
|
|
116
|
+
&& !(setting.value === obfuscatedSetting && isSecretSetting(setting));
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
const getSetting = setting => this.settingsCache.get(setting.key, {resolve: false});
|
|
120
|
+
|
|
121
|
+
const firstUnknownSetting = filteredSettings.find(setting => !getSetting(setting));
|
|
122
|
+
|
|
123
|
+
if (firstUnknownSetting) {
|
|
124
|
+
throw new NotFoundError({
|
|
125
|
+
message: tpl(messages.problemFindingSetting, {
|
|
126
|
+
key: firstUnknownSetting.key
|
|
127
|
+
})
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
if (!(options.context && options.context.internal)) {
|
|
132
|
+
const firstCoreSetting = filteredSettings.find(setting => getSetting(setting).group === 'core');
|
|
133
|
+
|
|
134
|
+
if (firstCoreSetting) {
|
|
135
|
+
throw new NoPermissionError({
|
|
136
|
+
message: tpl(messages.accessCoreSettingFromExtReq)
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
if (stripeConnectData) {
|
|
142
|
+
filteredSettings.push({
|
|
143
|
+
key: 'stripe_connect_publishable_key',
|
|
144
|
+
value: stripeConnectData.public_key
|
|
145
|
+
});
|
|
146
|
+
filteredSettings.push({
|
|
147
|
+
key: 'stripe_connect_secret_key',
|
|
148
|
+
value: stripeConnectData.secret_key
|
|
149
|
+
});
|
|
150
|
+
filteredSettings.push({
|
|
151
|
+
key: 'stripe_connect_livemode',
|
|
152
|
+
value: stripeConnectData.livemode
|
|
153
|
+
});
|
|
154
|
+
filteredSettings.push({
|
|
155
|
+
key: 'stripe_connect_display_name',
|
|
156
|
+
value: stripeConnectData.display_name
|
|
157
|
+
});
|
|
158
|
+
filteredSettings.push({
|
|
159
|
+
key: 'stripe_connect_account_id',
|
|
160
|
+
value: stripeConnectData.account_id
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
return this.SettingsModel.edit(filteredSettings, options);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
*
|
|
169
|
+
* @param {Object} stripeConnectIntegrationToken
|
|
170
|
+
* @param {Function} getSessionProp sync function fetching property from session store
|
|
171
|
+
* @param {Function} getStripeConnectTokenData async function retreiving Stripe Connect data for settings
|
|
172
|
+
* @returns {Promise<Object>} resolves with an object with following keys: public_key, secret_key, livemode, display_name, account_id
|
|
173
|
+
*/
|
|
174
|
+
async getStripeConnectData(stripeConnectIntegrationToken, getSessionProp, getStripeConnectTokenData) {
|
|
175
|
+
if (stripeConnectIntegrationToken && stripeConnectIntegrationToken.value) {
|
|
176
|
+
try {
|
|
177
|
+
return await getStripeConnectTokenData(stripeConnectIntegrationToken.value, getSessionProp);
|
|
178
|
+
} catch (err) {
|
|
179
|
+
throw new BadRequestError({
|
|
180
|
+
err,
|
|
181
|
+
message: 'The Stripe Connect token could not be parsed.'
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
module.exports = SettingsBREADService;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
// The string returned when a setting is set as write-only
|
|
2
|
+
const obfuscatedSetting = '••••••••';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @description // The function used to decide whether a setting is write-only
|
|
6
|
+
* @param {Object} setting setting record
|
|
7
|
+
* @param {String} setting.key
|
|
8
|
+
* @returns {Boolean}
|
|
9
|
+
*/
|
|
10
|
+
function isSecretSetting(setting) {
|
|
11
|
+
return /secret/.test(setting.key);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* @description The function that obfuscates a write-only setting
|
|
16
|
+
* @param {Object} setting setting record
|
|
17
|
+
* @param {String} setting.value
|
|
18
|
+
* @param {String} setting.key
|
|
19
|
+
* @returns {Object} settings record with obfuscated value if it's a secret
|
|
20
|
+
*/
|
|
21
|
+
function hideValueIfSecret(setting) {
|
|
22
|
+
if (setting.value && isSecretSetting(setting)) {
|
|
23
|
+
return {...setting, value: obfuscatedSetting};
|
|
24
|
+
}
|
|
25
|
+
return setting;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
module.exports = {
|
|
29
|
+
obfuscatedSetting,
|
|
30
|
+
isSecretSetting,
|
|
31
|
+
hideValueIfSecret
|
|
32
|
+
};
|
|
@@ -60,8 +60,8 @@ class ThemeStorage extends LocalFileStorage {
|
|
|
60
60
|
/**
|
|
61
61
|
* Rename a file / folder
|
|
62
62
|
*
|
|
63
|
-
*
|
|
64
|
-
* @param String
|
|
63
|
+
* @param {String} srcName
|
|
64
|
+
* @param {String} destName
|
|
65
65
|
*/
|
|
66
66
|
rename(srcName, destName) {
|
|
67
67
|
let src = path.join(this.getTargetDir(), srcName);
|
|
@@ -71,9 +71,10 @@ class ThemeStorage extends LocalFileStorage {
|
|
|
71
71
|
}
|
|
72
72
|
|
|
73
73
|
/**
|
|
74
|
-
*
|
|
74
|
+
* Remove a file / folder
|
|
75
75
|
*
|
|
76
|
-
* @param String
|
|
76
|
+
* @param {String} fileName
|
|
77
|
+
* @returns {Promise<void>}
|
|
77
78
|
*/
|
|
78
79
|
delete(fileName) {
|
|
79
80
|
return fs.remove(path.join(this.getTargetDir(), fileName));
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
const debug = require('@tryghost/debug')('themes');
|
|
2
2
|
const bridge = require('../../../bridge');
|
|
3
|
+
const labs = require('../../../shared/labs');
|
|
4
|
+
const customThemeSettings = require('../custom-theme-settings');
|
|
3
5
|
|
|
4
6
|
/**
|
|
5
7
|
* These helper methods mean that the bridge is only required in one place
|
|
@@ -8,14 +10,26 @@ const bridge = require('../../../bridge');
|
|
|
8
10
|
module.exports = {
|
|
9
11
|
activateFromBoot: (themeName, theme, checkedTheme) => {
|
|
10
12
|
debug('Activating theme (method A on boot)', themeName);
|
|
13
|
+
// TODO: probably a better place for this to happen - after successful activation / when reloading site?
|
|
14
|
+
if (labs.isSet('customThemeSettings')) {
|
|
15
|
+
customThemeSettings.activateTheme(checkedTheme);
|
|
16
|
+
}
|
|
11
17
|
bridge.activateTheme(theme, checkedTheme);
|
|
12
18
|
},
|
|
13
19
|
activateFromAPI: (themeName, theme, checkedTheme) => {
|
|
14
20
|
debug('Activating theme (method B on API "activate")', themeName);
|
|
21
|
+
// TODO: probably a better place for this to happen - after successful activation / when reloading site?
|
|
22
|
+
if (labs.isSet('customThemeSettings')) {
|
|
23
|
+
customThemeSettings.activateTheme(checkedTheme);
|
|
24
|
+
}
|
|
15
25
|
bridge.activateTheme(theme, checkedTheme);
|
|
16
26
|
},
|
|
17
27
|
activateFromAPIOverride: (themeName, theme, checkedTheme) => {
|
|
18
28
|
debug('Activating theme (method C on API "override")', themeName);
|
|
29
|
+
// TODO: probably a better place for this to happen - after successful activation / when reloading site?
|
|
30
|
+
if (labs.isSet('customThemeSettings')) {
|
|
31
|
+
customThemeSettings.activateTheme(checkedTheme);
|
|
32
|
+
}
|
|
19
33
|
bridge.activateTheme(theme, checkedTheme);
|
|
20
34
|
}
|
|
21
35
|
};
|
|
@@ -2,6 +2,7 @@ const debug = require('@tryghost/debug')('themes');
|
|
|
2
2
|
const _ = require('lodash');
|
|
3
3
|
const fs = require('fs-extra');
|
|
4
4
|
const config = require('../../../shared/config');
|
|
5
|
+
const labs = require('../../../shared/labs');
|
|
5
6
|
const tpl = require('@tryghost/tpl');
|
|
6
7
|
const errors = require('@tryghost/errors');
|
|
7
8
|
|
|
@@ -27,12 +28,14 @@ const check = async function check(theme, isZip) {
|
|
|
27
28
|
debug('zip mode');
|
|
28
29
|
checkedTheme = await gscan.checkZip(theme, {
|
|
29
30
|
keepExtractedDir: true,
|
|
30
|
-
checkVersion: 'canary'
|
|
31
|
+
checkVersion: 'canary',
|
|
32
|
+
labs: labs.getAll()
|
|
31
33
|
});
|
|
32
34
|
} else {
|
|
33
35
|
debug('non-zip mode');
|
|
34
36
|
checkedTheme = await gscan.check(theme.path, {
|
|
35
|
-
checkVersion: 'canary'
|
|
37
|
+
checkVersion: 'canary',
|
|
38
|
+
labs: labs.getAll()
|
|
36
39
|
});
|
|
37
40
|
}
|
|
38
41
|
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
<title>Ghost Admin</title>
|
|
9
9
|
|
|
10
10
|
|
|
11
|
-
<meta name="ghost-admin/config/environment" content="%7B%22modulePrefix%22%3A%22ghost-admin%22%2C%22environment%22%3A%22production%22%2C%22rootURL%22%3A%22%2F%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%224.
|
|
11
|
+
<meta name="ghost-admin/config/environment" content="%7B%22modulePrefix%22%3A%22ghost-admin%22%2C%22environment%22%3A%22production%22%2C%22rootURL%22%3A%22%2F%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%224.16%22%2C%22name%22%3A%22ghost-admin%22%7D%2C%22ember-simple-auth%22%3A%7B%7D%2C%22moment%22%3A%7B%22includeTimezone%22%3A%22all%22%7D%2C%22emberKeyboard%22%3A%7B%22disableInputsInitializer%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" />
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
|
|
42
42
|
|
|
43
43
|
<link rel="stylesheet" href="assets/vendor.min-987af30228885bce50f05c4723fe6f53.css">
|
|
44
|
-
<link rel="stylesheet" href="assets/ghost.min-
|
|
44
|
+
<link rel="stylesheet" href="assets/ghost.min-e7612edfa72b0fe2c201b387923e6fc7.css" title="light">
|
|
45
45
|
|
|
46
46
|
|
|
47
47
|
|
|
@@ -59,8 +59,8 @@
|
|
|
59
59
|
<div id="ember-basic-dropdown-wormhole"></div>
|
|
60
60
|
|
|
61
61
|
|
|
62
|
-
<script src="assets/vendor.min-
|
|
63
|
-
<script src="assets/ghost.min-
|
|
62
|
+
<script src="assets/vendor.min-3660ec7864887f1496fe7a27fd23ab76.js"></script>
|
|
63
|
+
<script src="assets/ghost.min-d1d99f3ed6e0f427874b2a11e7078475.js"></script>
|
|
64
64
|
|
|
65
65
|
</body>
|
|
66
66
|
</html>
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
<title>Ghost Admin</title>
|
|
9
9
|
|
|
10
10
|
|
|
11
|
-
<meta name="ghost-admin/config/environment" content="%7B%22modulePrefix%22%3A%22ghost-admin%22%2C%22environment%22%3A%22production%22%2C%22rootURL%22%3A%22%2F%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%224.
|
|
11
|
+
<meta name="ghost-admin/config/environment" content="%7B%22modulePrefix%22%3A%22ghost-admin%22%2C%22environment%22%3A%22production%22%2C%22rootURL%22%3A%22%2F%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%224.16%22%2C%22name%22%3A%22ghost-admin%22%7D%2C%22ember-simple-auth%22%3A%7B%7D%2C%22moment%22%3A%7B%22includeTimezone%22%3A%22all%22%7D%2C%22emberKeyboard%22%3A%7B%22disableInputsInitializer%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" />
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
|
|
42
42
|
|
|
43
43
|
<link rel="stylesheet" href="assets/vendor.min-987af30228885bce50f05c4723fe6f53.css">
|
|
44
|
-
<link rel="stylesheet" href="assets/ghost.min-
|
|
44
|
+
<link rel="stylesheet" href="assets/ghost.min-e7612edfa72b0fe2c201b387923e6fc7.css" title="light">
|
|
45
45
|
|
|
46
46
|
|
|
47
47
|
|
|
@@ -59,8 +59,8 @@
|
|
|
59
59
|
<div id="ember-basic-dropdown-wormhole"></div>
|
|
60
60
|
|
|
61
61
|
|
|
62
|
-
<script src="assets/vendor.min-
|
|
63
|
-
<script src="assets/ghost.min-
|
|
62
|
+
<script src="assets/vendor.min-3660ec7864887f1496fe7a27fd23ab76.js"></script>
|
|
63
|
+
<script src="assets/ghost.min-d1d99f3ed6e0f427874b2a11e7078475.js"></script>
|
|
64
64
|
|
|
65
65
|
</body>
|
|
66
66
|
</html>
|
|
@@ -7,6 +7,7 @@ const urlUtils = require('../../../shared/url-utils');
|
|
|
7
7
|
const membersService = require('../../services/members');
|
|
8
8
|
const middleware = membersService.middleware;
|
|
9
9
|
const shared = require('../shared');
|
|
10
|
+
const labs = require('../../../shared/labs');
|
|
10
11
|
|
|
11
12
|
module.exports = function setupMembersApp() {
|
|
12
13
|
debug('Members App setup start');
|
|
@@ -44,6 +45,7 @@ module.exports = function setupMembersApp() {
|
|
|
44
45
|
membersApp.post('/api/create-stripe-checkout-session', (req, res, next) => membersService.api.middleware.createCheckoutSession(req, res, next));
|
|
45
46
|
membersApp.post('/api/create-stripe-update-session', (req, res, next) => membersService.api.middleware.createCheckoutSetupSession(req, res, next));
|
|
46
47
|
membersApp.put('/api/subscriptions/:id', (req, res, next) => membersService.api.middleware.updateSubscription(req, res, next));
|
|
48
|
+
membersApp.post('/api/events', labs.enabledMiddleware('membersActivity'), middleware.loadMemberSession, (req, res, next) => membersService.api.middleware.createEvents(req, res, next));
|
|
47
49
|
|
|
48
50
|
// API error handling
|
|
49
51
|
membersApp.use('/api', shared.middlewares.errorHandler.resourceNotFound);
|
package/core/shared/labs.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ghost",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.16.0",
|
|
4
4
|
"description": "The professional publishing platform",
|
|
5
5
|
"author": "Ghost Foundation",
|
|
6
6
|
"homepage": "https://ghost.org",
|
|
@@ -51,50 +51,51 @@
|
|
|
51
51
|
},
|
|
52
52
|
"dependencies": {
|
|
53
53
|
"@nexes/nql": "0.6.0",
|
|
54
|
-
"@sentry/node": "6.
|
|
55
|
-
"@tryghost/adapter-manager": "0.2.
|
|
54
|
+
"@sentry/node": "6.13.2",
|
|
55
|
+
"@tryghost/adapter-manager": "0.2.15",
|
|
56
56
|
"@tryghost/admin-api-schema": "2.6.0",
|
|
57
57
|
"@tryghost/bookshelf-plugins": "0.3.1",
|
|
58
|
-
"@tryghost/bootstrap-socket": "0.2.
|
|
58
|
+
"@tryghost/bootstrap-socket": "0.2.10",
|
|
59
59
|
"@tryghost/color-utils": "0.1.2",
|
|
60
|
-
"@tryghost/config-url-helpers": "0.1.
|
|
61
|
-
"@tryghost/constants": "0.1.
|
|
60
|
+
"@tryghost/config-url-helpers": "0.1.1",
|
|
61
|
+
"@tryghost/constants": "0.1.9",
|
|
62
|
+
"@tryghost/custom-theme-settings-service": "0.0.2",
|
|
62
63
|
"@tryghost/debug": "0.1.5",
|
|
63
|
-
"@tryghost/email-analytics-provider-mailgun": "1.0.
|
|
64
|
-
"@tryghost/email-analytics-service": "1.0.
|
|
65
|
-
"@tryghost/errors": "0.2.
|
|
64
|
+
"@tryghost/email-analytics-provider-mailgun": "1.0.1",
|
|
65
|
+
"@tryghost/email-analytics-service": "1.0.1",
|
|
66
|
+
"@tryghost/errors": "0.2.14",
|
|
66
67
|
"@tryghost/helpers": "1.1.52",
|
|
67
|
-
"@tryghost/image-transform": "1.0.
|
|
68
|
-
"@tryghost/job-manager": "0.8.
|
|
68
|
+
"@tryghost/image-transform": "1.0.14",
|
|
69
|
+
"@tryghost/job-manager": "0.8.8",
|
|
69
70
|
"@tryghost/kg-card-factory": "3.0.4",
|
|
70
71
|
"@tryghost/kg-default-atoms": "3.0.0",
|
|
71
72
|
"@tryghost/kg-default-cards": "5.0.7",
|
|
72
73
|
"@tryghost/kg-markdown-html-renderer": "5.0.5",
|
|
73
74
|
"@tryghost/kg-mobiledoc-html-renderer": "5.1.1",
|
|
74
|
-
"@tryghost/limit-service": "0.6.
|
|
75
|
+
"@tryghost/limit-service": "0.6.2",
|
|
75
76
|
"@tryghost/logging": "0.1.7",
|
|
76
|
-
"@tryghost/magic-link": "1.0.
|
|
77
|
-
"@tryghost/members-api": "1.
|
|
77
|
+
"@tryghost/magic-link": "1.0.12",
|
|
78
|
+
"@tryghost/members-api": "1.38.1",
|
|
78
79
|
"@tryghost/members-csv": "1.1.6",
|
|
79
80
|
"@tryghost/members-importer": "0.3.2",
|
|
80
|
-
"@tryghost/members-ssr": "1.0.
|
|
81
|
-
"@tryghost/mw-session-from-token": "0.1.
|
|
81
|
+
"@tryghost/members-ssr": "1.0.13",
|
|
82
|
+
"@tryghost/mw-session-from-token": "0.1.23",
|
|
82
83
|
"@tryghost/nodemailer": "0.3.2",
|
|
83
|
-
"@tryghost/package-json": "1.0.
|
|
84
|
-
"@tryghost/promise": "0.1.
|
|
84
|
+
"@tryghost/package-json": "1.0.3",
|
|
85
|
+
"@tryghost/promise": "0.1.10",
|
|
85
86
|
"@tryghost/request": "0.1.5",
|
|
86
87
|
"@tryghost/root-utils": "0.3.4",
|
|
87
|
-
"@tryghost/security": "0.2.
|
|
88
|
-
"@tryghost/session-service": "0.1.
|
|
88
|
+
"@tryghost/security": "0.2.10",
|
|
89
|
+
"@tryghost/session-service": "0.1.25",
|
|
89
90
|
"@tryghost/social-urls": "0.1.26",
|
|
90
91
|
"@tryghost/string": "0.1.20",
|
|
91
|
-
"@tryghost/tpl": "0.1.
|
|
92
|
+
"@tryghost/tpl": "0.1.4",
|
|
92
93
|
"@tryghost/update-check-service": "0.2.2",
|
|
93
94
|
"@tryghost/url-utils": "2.0.2",
|
|
94
95
|
"@tryghost/validator": "0.1.5",
|
|
95
96
|
"@tryghost/version": "0.1.4",
|
|
96
|
-
"@tryghost/vhost-middleware": "1.0.
|
|
97
|
-
"@tryghost/zip": "1.1.
|
|
97
|
+
"@tryghost/vhost-middleware": "1.0.16",
|
|
98
|
+
"@tryghost/zip": "1.1.15",
|
|
98
99
|
"amperize": "0.6.1",
|
|
99
100
|
"analytics-node": "5.1.0",
|
|
100
101
|
"bluebird": "3.7.2",
|
|
@@ -118,9 +119,9 @@
|
|
|
118
119
|
"express-session": "1.17.2",
|
|
119
120
|
"fs-extra": "10.0.0",
|
|
120
121
|
"ghost-storage-base": "0.0.6",
|
|
121
|
-
"glob": "7.
|
|
122
|
+
"glob": "7.2.0",
|
|
122
123
|
"got": "9.6.0",
|
|
123
|
-
"gscan": "4.
|
|
124
|
+
"gscan": "4.3.1",
|
|
124
125
|
"html-to-text": "5.1.1",
|
|
125
126
|
"image-size": "1.0.0",
|
|
126
127
|
"intl": "1.2.5",
|
|
@@ -169,7 +170,7 @@
|
|
|
169
170
|
"devDependencies": {
|
|
170
171
|
"@lodder/grunt-postcss": "3.0.1",
|
|
171
172
|
"c8": "7.9.0",
|
|
172
|
-
"coffeescript": "2.
|
|
173
|
+
"coffeescript": "2.6.0",
|
|
173
174
|
"cssnano": "5.0.8",
|
|
174
175
|
"eslint": "7.32.0",
|
|
175
176
|
"eslint-plugin-ghost": "2.6.0",
|
|
@@ -190,7 +191,7 @@
|
|
|
190
191
|
"mock-knex": "0.4.10",
|
|
191
192
|
"nock": "13.1.3",
|
|
192
193
|
"papaparse": "5.3.1",
|
|
193
|
-
"postcss": "8.3.
|
|
194
|
+
"postcss": "8.3.7",
|
|
194
195
|
"rewire": "5.0.0",
|
|
195
196
|
"should": "13.2.3",
|
|
196
197
|
"sinon": "11.1.2",
|