ghost 4.36.3 → 4.38.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/.c8rc.json +10 -0
- package/content/themes/casper/LICENSE +1 -1
- package/content/themes/casper/README.md +1 -1
- package/content/themes/casper/assets/built/global.css +1 -1
- package/content/themes/casper/assets/built/global.css.map +1 -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/global.css +14 -6
- package/content/themes/casper/assets/css/screen.css +9 -1
- package/content/themes/casper/package.json +2 -2
- package/content/themes/casper/partials/post-card.hbs +1 -1
- package/content/themes/casper/post.hbs +18 -19
- package/content/themes/casper/yarn.lock +186 -217
- package/core/built/assets/ghost-dark-9f760f16230b8bc52e188d6ce28516b0.css +1 -0
- package/core/built/assets/{ghost.min-801697772dc605c0dae0abfec54ec591.js → ghost.min-6386b02480494a69c3bfe66206754836.js} +375 -312
- package/core/built/assets/ghost.min-f4c59dd57a2136df8b0a34f87c099034.css +1 -0
- package/core/built/assets/icons/eye.svg +4 -1
- package/core/built/assets/icons/member-add.svg +3 -0
- package/core/built/assets/icons/pin.svg +4 -1
- package/core/built/assets/{vendor.min-2313642ee897688be83924a38d5e62f1.js → vendor.min-c814d3c4b3f543c4cd5ef3aacd0fc645.js} +40 -36
- package/core/frontend/helpers/excerpt.js +7 -4
- package/core/frontend/helpers/get.js +4 -0
- package/core/frontend/helpers/match.js +12 -0
- package/core/frontend/helpers/prev_post.js +11 -1
- package/core/frontend/helpers/tiers.js +59 -0
- package/core/frontend/helpers/tpl/content-cta.hbs +1 -1
- package/core/frontend/services/routing/router-manager.js +1 -1
- package/core/frontend/web/site.js +10 -0
- package/core/server/api/canary/authentication.js +2 -0
- package/core/server/api/canary/index.js +8 -0
- package/core/server/api/canary/members.js +2 -1
- package/core/server/api/canary/products.js +3 -6
- package/core/server/api/canary/tiers-public.js +34 -0
- package/core/server/api/canary/tiers.js +120 -0
- package/core/server/api/canary/utils/serializers/input/index.js +4 -0
- package/core/server/api/canary/utils/serializers/input/tiers.js +36 -0
- package/core/server/api/canary/utils/serializers/output/email-posts.js +7 -1
- package/core/server/api/canary/utils/serializers/output/index.js +4 -0
- package/core/server/api/canary/utils/serializers/output/members.js +5 -0
- package/core/server/api/canary/utils/serializers/output/pages.js +9 -2
- package/core/server/api/canary/utils/serializers/output/posts.js +8 -2
- package/core/server/api/canary/utils/serializers/output/preview.js +7 -1
- package/core/server/api/canary/utils/serializers/output/products.js +3 -1
- package/core/server/api/canary/utils/serializers/output/tiers.js +212 -0
- package/core/server/api/canary/utils/serializers/output/utils/mapper.js +17 -7
- package/core/server/api/canary/utils/validators/input/index.js +4 -0
- package/core/server/api/canary/utils/validators/input/tiers.js +6 -0
- package/core/server/api/v2/settings.js +2 -1
- package/core/server/data/db/connection.js +3 -2
- package/core/server/data/migrations/init/1-create-tables.js +4 -1
- package/core/server/data/migrations/versions/3.29/01-remove-duplicate-subscriptions.js +2 -1
- package/core/server/data/migrations/versions/3.29/02-remove-duplicate-customers.js +2 -1
- package/core/server/data/migrations/versions/3.29/03-remove-orphaned-customers.js +2 -1
- package/core/server/data/migrations/versions/3.29/04-remove-orphaned-subscriptions.js +2 -1
- package/core/server/data/migrations/versions/3.29/05-add-member-constraints.js +3 -2
- package/core/server/data/migrations/versions/3.39/06-add-email-recipient-index.js +4 -3
- package/core/server/data/migrations/versions/4.0/14-remove-orphaned-stripe-records.js +2 -1
- package/core/server/data/migrations/versions/4.0/26-add-cascade-on-delete.js +2 -1
- package/core/server/data/migrations/versions/4.0/29-fix-foreign-key-for-members-stripe-customers-subscriptions.js +2 -1
- package/core/server/data/migrations/versions/4.1/02-add-unique-constraint-for-member-stripe-tables.js +2 -1
- package/core/server/data/migrations/versions/4.20/05-remove-not-null-constraint-from-portal-title.js +3 -2
- package/core/server/data/migrations/versions/4.33/2022-01-18-09-07-remove-duplicate-offer-redemptions.js +2 -2
- package/core/server/data/migrations/versions/4.35/2022-02-01-11-48-update-email-recipient-filter-column-type.js +2 -1
- package/core/server/data/migrations/versions/4.35/2022-02-01-12-03-update-recipient-filter-column-type.js +2 -1
- package/core/server/data/migrations/versions/4.37/2022-02-21-09-53-backfill-members-last-seen-at-column.js +32 -0
- package/core/server/data/migrations/versions/4.38/2022-03-01-08-46-add-visibility-to-tiers.js +11 -0
- package/core/server/data/migrations/versions/4.38/2022-03-03-16-12-add-visibility-to-tiers.js +8 -0
- package/core/server/data/migrations/versions/4.38/2022-03-03-16-17-drop-tiers-visible-column.js +7 -0
- package/core/server/data/schema/clients/index.js +1 -1
- package/core/server/data/schema/clients/mysql.js +4 -4
- package/core/server/data/schema/commands.js +61 -70
- package/core/server/data/schema/{default-settings.json → default-settings/default-settings.json} +0 -0
- package/core/server/data/schema/default-settings/index.js +6 -0
- package/core/server/data/schema/fixtures/fixtures.json +4 -2
- package/core/server/data/schema/schema.js +7 -0
- package/core/server/models/product.js +2 -1
- package/core/server/services/auth/api-key/admin.js +15 -6
- package/core/server/services/auth/setup.js +13 -1
- package/core/server/services/email-analytics/lib/event-processor.js +18 -1
- package/core/server/services/members/middleware.js +4 -1
- package/core/server/services/members/service.js +21 -8
- package/core/server/services/route-settings/index.js +1 -1
- 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/app.js +3 -0
- package/core/server/web/api/canary/admin/middleware.js +2 -0
- package/core/server/web/api/canary/admin/routes.js +7 -0
- package/core/server/web/api/canary/content/routes.js +1 -0
- package/core/server/web/members/app.js +1 -1
- package/core/server/web/shared/middleware/uncapitalise.js +2 -2
- package/core/shared/config/defaults.json +3 -2
- package/core/shared/config/overrides.json +1 -1
- package/core/shared/config/utils.js +5 -1
- package/core/shared/labs.js +4 -1
- package/package.json +62 -61
- package/yarn.lock +729 -614
- package/core/built/assets/ghost-dark-25e568b14d76f6754fa8279cceb265ba.css +0 -1
- package/core/built/assets/ghost.min-75ed7451ca633bae1b345eb57e2c28e0.css +0 -1
|
@@ -7,13 +7,15 @@
|
|
|
7
7
|
"name": "Free",
|
|
8
8
|
"slug": "free",
|
|
9
9
|
"type": "free",
|
|
10
|
-
"active": true
|
|
10
|
+
"active": true,
|
|
11
|
+
"visibility": "public"
|
|
11
12
|
},
|
|
12
13
|
{
|
|
13
14
|
"name": "Default Product",
|
|
14
15
|
"slug": "default-product",
|
|
15
16
|
"type": "paid",
|
|
16
|
-
"active": true
|
|
17
|
+
"active": true,
|
|
18
|
+
"visibility": "public"
|
|
17
19
|
}
|
|
18
20
|
]
|
|
19
21
|
},
|
|
@@ -381,6 +381,13 @@ module.exports = {
|
|
|
381
381
|
slug: {type: 'string', maxlength: 191, nullable: false, unique: true},
|
|
382
382
|
active: {type: 'boolean', nullable: false, defaultTo: true},
|
|
383
383
|
welcome_page_url: {type: 'string', maxlength: 2000, nullable: true},
|
|
384
|
+
visibility: {
|
|
385
|
+
type: 'string',
|
|
386
|
+
maxlength: 50,
|
|
387
|
+
nullable: false,
|
|
388
|
+
defaultTo: 'none',
|
|
389
|
+
validations: {isIn: [['public', 'none']]}
|
|
390
|
+
},
|
|
384
391
|
monthly_price_id: {type: 'string', maxlength: 24, nullable: true},
|
|
385
392
|
yearly_price_id: {type: 'string', maxlength: 24, nullable: true},
|
|
386
393
|
description: {type: 'string', maxlength: 191, nullable: true},
|
|
@@ -3,6 +3,7 @@ const url = require('url');
|
|
|
3
3
|
const models = require('../../../models');
|
|
4
4
|
const errors = require('@tryghost/errors');
|
|
5
5
|
const limitService = require('../../../services/limits');
|
|
6
|
+
const config = require('../../../../shared/config');
|
|
6
7
|
const tpl = require('@tryghost/tpl');
|
|
7
8
|
const _ = require('lodash');
|
|
8
9
|
|
|
@@ -139,12 +140,20 @@ const authenticateWithToken = async (req, res, next, {token, JWT_OPTIONS}) => {
|
|
|
139
140
|
const secret = Buffer.from(apiKey.get('secret'), 'hex');
|
|
140
141
|
|
|
141
142
|
const {pathname} = url.parse(req.originalUrl);
|
|
142
|
-
const [hasMatch, version
|
|
143
|
-
|
|
144
|
-
// ensure the token was meant for this api
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
143
|
+
const [hasMatch, version, api] = pathname.match(/ghost\/api\/([^/]+)\/([^/]+)\/(.+)*/); // eslint-disable-line no-unused-vars
|
|
144
|
+
|
|
145
|
+
// ensure the token was meant for this api
|
|
146
|
+
let options;
|
|
147
|
+
if (!config.get('api:versions:all').includes(version)) {
|
|
148
|
+
// CASE: non-versioned api request
|
|
149
|
+
options = Object.assign({
|
|
150
|
+
audience: new RegExp(`\/?${version}\/?$`) // eslint-disable-line no-useless-escape
|
|
151
|
+
}, JWT_OPTIONS);
|
|
152
|
+
} else {
|
|
153
|
+
options = Object.assign({
|
|
154
|
+
audience: new RegExp(`\/?${version}\/${api}\/?$`) // eslint-disable-line no-useless-escape
|
|
155
|
+
}, JWT_OPTIONS);
|
|
156
|
+
}
|
|
148
157
|
|
|
149
158
|
try {
|
|
150
159
|
jwt.verify(token, secret, options);
|
|
@@ -77,6 +77,7 @@ async function doSettings(data, settingsAPI) {
|
|
|
77
77
|
const context = {context: {user: data.user.id}};
|
|
78
78
|
const user = data.user;
|
|
79
79
|
const blogTitle = data.userData.blogTitle;
|
|
80
|
+
const description = data.userData.description ? data.userData.description.trim() : null;
|
|
80
81
|
|
|
81
82
|
let userSettings;
|
|
82
83
|
|
|
@@ -86,9 +87,15 @@ async function doSettings(data, settingsAPI) {
|
|
|
86
87
|
|
|
87
88
|
userSettings = [
|
|
88
89
|
{key: 'title', value: blogTitle.trim()},
|
|
89
|
-
{key: 'description', value: tpl(messages.sampleBlogDescription)}
|
|
90
|
+
{key: 'description', value: description || tpl(messages.sampleBlogDescription)}
|
|
90
91
|
];
|
|
91
92
|
|
|
93
|
+
if (data.userData.accentColor) {
|
|
94
|
+
userSettings.push({
|
|
95
|
+
key: 'accent_color', value: data.userData.accentColor
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
|
|
92
99
|
await settingsAPI.edit({settings: userSettings}, context);
|
|
93
100
|
|
|
94
101
|
return user;
|
|
@@ -157,6 +164,11 @@ async function installTheme(data, api) {
|
|
|
157
164
|
return data;
|
|
158
165
|
}
|
|
159
166
|
|
|
167
|
+
if (themeName.toLowerCase() === 'tryghost/casper') {
|
|
168
|
+
logging.warn('Skipping theme install as Casper is the default theme.');
|
|
169
|
+
return data;
|
|
170
|
+
}
|
|
171
|
+
|
|
160
172
|
// Use the api instead of the services as the api performs extra logic
|
|
161
173
|
try {
|
|
162
174
|
const installResults = await api.themes.install({
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const {EventProcessor} = require('@tryghost/email-analytics-service');
|
|
2
|
-
const moment = require('moment');
|
|
2
|
+
const moment = require('moment-timezone');
|
|
3
3
|
|
|
4
4
|
class GhostEventProcessor extends EventProcessor {
|
|
5
5
|
constructor({db}) {
|
|
@@ -88,6 +88,23 @@ class GhostEventProcessor extends EventProcessor {
|
|
|
88
88
|
opened_at: this.db.knex.raw('COALESCE(opened_at, ?)', [moment.utc(event.timestamp).format('YYYY-MM-DD HH:mm:ss')])
|
|
89
89
|
});
|
|
90
90
|
|
|
91
|
+
// Using the default timezone set in https://github.com/TryGhost/Ghost/blob/2c5643623db0fc4db390f6997c81a73dca7ccacd/core/server/data/schema/default-settings/default-settings.json#L105
|
|
92
|
+
let timezone = 'Etc/UTC';
|
|
93
|
+
const timezoneData = await this.db.knex('settings').first('value').where('key', 'timezone');
|
|
94
|
+
if (timezoneData && timezoneData.value) {
|
|
95
|
+
timezone = timezoneData.value;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
await this.db.knex('members')
|
|
99
|
+
.where('email', '=', event.recipientEmail)
|
|
100
|
+
.andWhere(builder => builder
|
|
101
|
+
.where('last_seen_at', '<', moment.utc(event.timestamp).tz(timezone).startOf('day').utc().format('YYYY-MM-DD HH:mm:ss'))
|
|
102
|
+
.orWhereNull('last_seen_at')
|
|
103
|
+
)
|
|
104
|
+
.update({
|
|
105
|
+
last_seen_at: moment.utc(event.timestamp).format('YYYY-MM-DD HH:mm:ss')
|
|
106
|
+
});
|
|
107
|
+
|
|
91
108
|
return updateResult > 0;
|
|
92
109
|
}
|
|
93
110
|
|
|
@@ -110,9 +110,12 @@ const getPortalProductPrices = async function () {
|
|
|
110
110
|
monthlyPrice: product.monthlyPrice,
|
|
111
111
|
yearlyPrice: product.yearlyPrice,
|
|
112
112
|
benefits: product.benefits,
|
|
113
|
+
active: product.active,
|
|
113
114
|
type: product.type,
|
|
114
115
|
prices: productPrices
|
|
115
116
|
};
|
|
117
|
+
}).filter((product) => {
|
|
118
|
+
return !!product.active;
|
|
116
119
|
});
|
|
117
120
|
const defaultProduct = products.find((product) => {
|
|
118
121
|
return product.type === 'paid';
|
|
@@ -198,7 +201,7 @@ const createSessionFromMagicLink = async function (req, res, next) {
|
|
|
198
201
|
|
|
199
202
|
const action = req.query.action;
|
|
200
203
|
|
|
201
|
-
if (action === 'signup' || action === 'signup-paid') {
|
|
204
|
+
if (action === 'signup' || action === 'signup-paid' || action === 'subscribe') {
|
|
202
205
|
let customRedirect = '';
|
|
203
206
|
const mostRecentActiveSubscription = subscriptions
|
|
204
207
|
.sort((a, b) => {
|
|
@@ -16,6 +16,8 @@ const models = require('../../models');
|
|
|
16
16
|
const {GhostMailer} = require('../mail');
|
|
17
17
|
const jobsService = require('../jobs');
|
|
18
18
|
const VerificationTrigger = require('@tryghost/verification-trigger');
|
|
19
|
+
const DomainEvents = require('@tryghost/domain-events');
|
|
20
|
+
const {LastSeenAtUpdater} = require('@tryghost/members-events-service');
|
|
19
21
|
const events = require('../../lib/common/events');
|
|
20
22
|
|
|
21
23
|
const messages = {
|
|
@@ -125,6 +127,13 @@ module.exports = {
|
|
|
125
127
|
});
|
|
126
128
|
}
|
|
127
129
|
|
|
130
|
+
module.exports.ssr = MembersSSR({
|
|
131
|
+
cookieSecure: urlUtils.isSSL(urlUtils.getSiteUrl()),
|
|
132
|
+
cookieKeys: [settingsCache.get('theme_session_secret')],
|
|
133
|
+
cookieName: 'ghost-members-ssr',
|
|
134
|
+
getMembersApi: () => module.exports.api
|
|
135
|
+
});
|
|
136
|
+
|
|
128
137
|
verificationTrigger = new VerificationTrigger({
|
|
129
138
|
configThreshold: _.get(config.get('hostSettings'), 'emailVerification.importThreshold'),
|
|
130
139
|
isVerified: () => config.get('hostSettings:emailVerification:verified') === true,
|
|
@@ -132,7 +141,7 @@ module.exports = {
|
|
|
132
141
|
sendVerificationEmail: ({subject, message, amountImported}) => {
|
|
133
142
|
const escalationAddress = config.get('hostSettings:emailVerification:escalationAddress');
|
|
134
143
|
const fromAddress = config.get('user_email');
|
|
135
|
-
|
|
144
|
+
|
|
136
145
|
if (escalationAddress) {
|
|
137
146
|
ghostMailer.send({
|
|
138
147
|
subject,
|
|
@@ -151,6 +160,16 @@ module.exports = {
|
|
|
151
160
|
eventRepository: membersApi.events
|
|
152
161
|
});
|
|
153
162
|
|
|
163
|
+
new LastSeenAtUpdater({
|
|
164
|
+
models: {
|
|
165
|
+
Member: models.Member
|
|
166
|
+
},
|
|
167
|
+
services: {
|
|
168
|
+
domainEvents: DomainEvents,
|
|
169
|
+
settingsCache
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
|
|
154
173
|
(async () => {
|
|
155
174
|
try {
|
|
156
175
|
const collection = await models.SingleUseToken.fetchAll();
|
|
@@ -181,13 +200,7 @@ module.exports = {
|
|
|
181
200
|
return membersSettings;
|
|
182
201
|
},
|
|
183
202
|
|
|
184
|
-
ssr:
|
|
185
|
-
cookieSecure: urlUtils.isSSL(urlUtils.getSiteUrl()),
|
|
186
|
-
cookieKeys: [settingsCache.get('theme_session_secret')],
|
|
187
|
-
cookieName: 'ghost-members-ssr',
|
|
188
|
-
cookieCacheName: 'ghost-members-ssr-cache',
|
|
189
|
-
getMembersApi: () => module.exports.api
|
|
190
|
-
}),
|
|
203
|
+
ssr: null,
|
|
191
204
|
|
|
192
205
|
stripeConnect: require('./stripe-connect'),
|
|
193
206
|
|
|
@@ -22,7 +22,7 @@ module.exports = {
|
|
|
22
22
|
type: 'routes',
|
|
23
23
|
extension: '.yaml',
|
|
24
24
|
destinationFolderPath: config.getContentPath('settings'),
|
|
25
|
-
sourceFolderPath: config.get('paths').
|
|
25
|
+
sourceFolderPath: config.get('paths').defaultRouteSettings
|
|
26
26
|
});
|
|
27
27
|
|
|
28
28
|
return await defaultSettingsManager.ensureSettingsFileExists();
|
|
@@ -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.38%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%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" />
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
|
|
39
39
|
|
|
40
40
|
<link rel="stylesheet" href="assets/vendor.min-2c8ad32b7960bb605ebc20097fee5ebd.css">
|
|
41
|
-
<link rel="stylesheet" href="assets/ghost.min-
|
|
41
|
+
<link rel="stylesheet" href="assets/ghost.min-f4c59dd57a2136df8b0a34f87c099034.css" title="light">
|
|
42
42
|
|
|
43
43
|
|
|
44
44
|
|
|
@@ -56,8 +56,8 @@
|
|
|
56
56
|
<div id="ember-basic-dropdown-wormhole"></div>
|
|
57
57
|
|
|
58
58
|
|
|
59
|
-
<script src="assets/vendor.min-
|
|
60
|
-
<script src="assets/ghost.min-
|
|
59
|
+
<script src="assets/vendor.min-c814d3c4b3f543c4cd5ef3aacd0fc645.js"></script>
|
|
60
|
+
<script src="assets/ghost.min-6386b02480494a69c3bfe66206754836.js"></script>
|
|
61
61
|
|
|
62
62
|
</body>
|
|
63
63
|
</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.38%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%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" />
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
|
|
39
39
|
|
|
40
40
|
<link rel="stylesheet" href="assets/vendor.min-2c8ad32b7960bb605ebc20097fee5ebd.css">
|
|
41
|
-
<link rel="stylesheet" href="assets/ghost.min-
|
|
41
|
+
<link rel="stylesheet" href="assets/ghost.min-f4c59dd57a2136df8b0a34f87c099034.css" title="light">
|
|
42
42
|
|
|
43
43
|
|
|
44
44
|
|
|
@@ -56,8 +56,8 @@
|
|
|
56
56
|
<div id="ember-basic-dropdown-wormhole"></div>
|
|
57
57
|
|
|
58
58
|
|
|
59
|
-
<script src="assets/vendor.min-
|
|
60
|
-
<script src="assets/ghost.min-
|
|
59
|
+
<script src="assets/vendor.min-c814d3c4b3f543c4cd5ef3aacd0fc645.js"></script>
|
|
60
|
+
<script src="assets/ghost.min-6386b02480494a69c3bfe66206754836.js"></script>
|
|
61
61
|
|
|
62
62
|
</body>
|
|
63
63
|
</html>
|
|
@@ -25,6 +25,9 @@ module.exports = function setupApiApp() {
|
|
|
25
25
|
apiApp.lazyUse(urlUtils.getVersionPath({version: 'canary', type: 'content'}), require('./canary/content/app'));
|
|
26
26
|
apiApp.lazyUse(urlUtils.getVersionPath({version: 'canary', type: 'admin'}), require('./canary/admin/app'));
|
|
27
27
|
|
|
28
|
+
apiApp.lazyUse('/content/', require('./canary/content/app'));
|
|
29
|
+
apiApp.lazyUse('/admin/', require('./canary/admin/app'));
|
|
30
|
+
|
|
28
31
|
// Error handling for requests to non-existent API versions
|
|
29
32
|
apiApp.use(errorHandler.resourceNotFound);
|
|
30
33
|
apiApp.use(errorHandler.handleJSONResponse(sentry));
|
|
@@ -88,11 +88,18 @@ module.exports = function apiRoutes() {
|
|
|
88
88
|
router.del('/tags/:id', mw.authAdminApi, http(api.tags.destroy));
|
|
89
89
|
|
|
90
90
|
// Products
|
|
91
|
+
// TODO Remove
|
|
91
92
|
router.get('/products', mw.authAdminApi, http(api.products.browse));
|
|
92
93
|
router.post('/products', mw.authAdminApi, http(api.products.add));
|
|
93
94
|
router.get('/products/:id', mw.authAdminApi, http(api.products.read));
|
|
94
95
|
router.put('/products/:id', mw.authAdminApi, http(api.products.edit));
|
|
95
96
|
|
|
97
|
+
// Tiers
|
|
98
|
+
router.get('/tiers', mw.authAdminApi, http(api.tiers.browse));
|
|
99
|
+
router.post('/tiers', mw.authAdminApi, http(api.tiers.add));
|
|
100
|
+
router.get('/tiers/:id', mw.authAdminApi, http(api.tiers.read));
|
|
101
|
+
router.put('/tiers/:id', mw.authAdminApi, http(api.tiers.edit));
|
|
102
|
+
|
|
96
103
|
// ## Members
|
|
97
104
|
router.get('/members', mw.authAdminApi, http(api.members.browse));
|
|
98
105
|
router.post('/members', mw.authAdminApi, http(api.members.add));
|
|
@@ -34,6 +34,7 @@ module.exports = function apiRoutes() {
|
|
|
34
34
|
router.get('/settings', mw.authenticatePublic, http(api.publicSettings.browse));
|
|
35
35
|
|
|
36
36
|
router.get('/products', mw.authenticatePublic, http(api.productsPublic.browse));
|
|
37
|
+
router.get('/tiers', mw.authenticatePublic, http(api.tiersPublic.browse));
|
|
37
38
|
|
|
38
39
|
return router;
|
|
39
40
|
};
|
|
@@ -39,7 +39,7 @@ module.exports = function setupMembersApp() {
|
|
|
39
39
|
membersApp.get('/api/session', middleware.getIdentityToken);
|
|
40
40
|
membersApp.get('/api/offers/:id', middleware.getOfferData);
|
|
41
41
|
membersApp.delete('/api/session', middleware.deleteSession);
|
|
42
|
-
membersApp.get('/api/site',
|
|
42
|
+
membersApp.get('/api/site', middleware.getMemberSiteData);
|
|
43
43
|
|
|
44
44
|
// NOTE: this is wrapped in a function to ensure we always go via the getter
|
|
45
45
|
membersApp.post('/api/send-magic-link', bodyParser.json(), shared.middleware.brute.membersAuth, (req, res, next) => membersService.api.middleware.sendMagicLink(req, res, next));
|
|
@@ -27,13 +27,13 @@ const uncapitalise = (req, res, next) => {
|
|
|
27
27
|
let decodedURI;
|
|
28
28
|
|
|
29
29
|
const isSignupOrReset = pathToTest.match(/^(.*\/ghost\/(signup|reset)\/)/i);
|
|
30
|
-
const isAPI = pathToTest.match(/^(.*\/ghost\/api\/(v[\d.]+|canary)
|
|
30
|
+
const isAPI = pathToTest.match(/^(.*\/ghost\/api(\/(v[\d.]+|canary))?\/.*?\/)/i);
|
|
31
31
|
|
|
32
32
|
if (isSignupOrReset) {
|
|
33
33
|
pathToTest = isSignupOrReset[1];
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
// Do not lowercase anything after e.g. /api/v{X}
|
|
36
|
+
// Do not lowercase anything after e.g. /ghost/api(/v{X})?/ to protect :key/:slug
|
|
37
37
|
if (isAPI) {
|
|
38
38
|
pathToTest = isAPI[1];
|
|
39
39
|
}
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
"paths": {
|
|
18
18
|
"contentPath": "content/",
|
|
19
19
|
"fixtures": "core/server/data/schema/fixtures/fixtures",
|
|
20
|
+
"defaultSettings": "core/server/data/schema/default-settings/default-settings",
|
|
20
21
|
"assetSrc": "core/frontend/src"
|
|
21
22
|
},
|
|
22
23
|
"adapters": {
|
|
@@ -127,8 +128,8 @@
|
|
|
127
128
|
"emailAnalytics": true
|
|
128
129
|
},
|
|
129
130
|
"portal": {
|
|
130
|
-
"url": "https://unpkg.com/@tryghost/portal@~1.
|
|
131
|
-
"version": "1.
|
|
131
|
+
"url": "https://unpkg.com/@tryghost/portal@~1.15.0/umd/portal.min.js",
|
|
132
|
+
"version": "1.15"
|
|
132
133
|
},
|
|
133
134
|
"tenor": {
|
|
134
135
|
"publicReadOnlyApiKey": null,
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
"helperTemplates": "core/frontend/helpers/tpl/",
|
|
7
7
|
"adminViews": "core/server/web/admin/views/",
|
|
8
8
|
"defaultViews": "core/server/views/",
|
|
9
|
-
"
|
|
9
|
+
"defaultRouteSettings": "core/server/services/route-settings/",
|
|
10
10
|
"internalAppPath": "core/frontend/apps/",
|
|
11
11
|
"internalAdaptersPath": "core/server/adapters/",
|
|
12
12
|
"migrationPath": "core/server/data/migrations",
|
|
@@ -54,9 +54,13 @@ const checkUrlProtocol = function checkUrlProtocol(url) {
|
|
|
54
54
|
* https://github.com/indexzero/nconf/issues/235#issuecomment-257606507
|
|
55
55
|
*/
|
|
56
56
|
const sanitizeDatabaseProperties = function sanitizeDatabaseProperties(nconf) {
|
|
57
|
+
if (nconf.get('database:client') === 'mysql') {
|
|
58
|
+
nconf.set('database:client', 'mysql2');
|
|
59
|
+
}
|
|
60
|
+
|
|
57
61
|
const database = nconf.get('database');
|
|
58
62
|
|
|
59
|
-
if (nconf.get('database:client') === '
|
|
63
|
+
if (nconf.get('database:client') === 'mysql2') {
|
|
60
64
|
delete database.connection.filename;
|
|
61
65
|
} else {
|
|
62
66
|
delete database.connection.host;
|
package/core/shared/labs.js
CHANGED
|
@@ -34,7 +34,10 @@ const ALPHA_FEATURES = [
|
|
|
34
34
|
'improvedOnboarding',
|
|
35
35
|
'tierWelcomePages',
|
|
36
36
|
'tierName',
|
|
37
|
-
'membersTableStatus'
|
|
37
|
+
'membersTableStatus',
|
|
38
|
+
'membersLastSeenFilter',
|
|
39
|
+
'membersContainsFilters',
|
|
40
|
+
'selectablePortalLinks'
|
|
38
41
|
];
|
|
39
42
|
|
|
40
43
|
module.exports.GA_KEYS = [...GA_FEATURES];
|