ghost 4.38.1 → 4.40.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. package/.c8rc.json +1 -1
  2. package/Gruntfile.js +1 -1
  3. package/README.md +26 -18
  4. package/core/built/assets/{chunk.3.4906cf0b01d6d8e33374.js → chunk.3.6e2ed2d00856e12bd81a.js} +19 -19
  5. package/core/built/assets/ghost-dark-498ff8339a89bb68c3f78f59bee4146e.css +1 -0
  6. package/core/built/assets/ghost.min-77b93478f83b0def6ddc5a4f23ce963e.css +1 -0
  7. package/core/built/assets/{ghost.min-6386b02480494a69c3bfe66206754836.js → ghost.min-88c665c3ba304b4f220d08b8bcf9d246.js} +525 -538
  8. package/core/built/assets/icons/{event-changed-subscription.svg → event-subscriptions.svg} +0 -1
  9. package/core/built/assets/icons/member.svg +3 -0
  10. package/core/built/assets/{vendor.min-c814d3c4b3f543c4cd5ef3aacd0fc645.js → vendor.min-ed945ad80ea22f1d3ffeec6d5ae63aee.js} +2355 -1419
  11. package/core/frontend/apps/private-blogging/lib/middleware.js +1 -1
  12. package/core/frontend/apps/private-blogging/lib/views/private.hbs +9 -10
  13. package/core/frontend/public/ghost.css +205 -143
  14. package/core/frontend/public/ghost.min.css +1 -1
  15. package/core/frontend/services/theme-engine/middleware/update-local-template-options.js +3 -1
  16. package/core/frontend/views/unsubscribe.hbs +28 -33
  17. package/core/frontend/web/middleware/error-handler.js +2 -2
  18. package/core/server/api/canary/authentication.js +7 -0
  19. package/core/server/api/canary/identities.js +0 -1
  20. package/core/server/api/canary/members.js +7 -1
  21. package/core/server/api/canary/tiers.js +3 -1
  22. package/core/server/api/canary/utils/serializers/input/pages.js +1 -1
  23. package/core/server/api/canary/utils/serializers/input/posts.js +1 -1
  24. package/core/server/api/canary/utils/serializers/input/tiers.js +17 -0
  25. package/core/server/api/canary/utils/serializers/output/actions.js +2 -2
  26. package/core/server/api/canary/utils/serializers/output/authentication.js +3 -3
  27. package/core/server/api/canary/utils/serializers/output/authors.js +3 -3
  28. package/core/server/api/canary/utils/serializers/output/email-posts.js +2 -2
  29. package/core/server/api/canary/utils/serializers/output/emails.js +3 -3
  30. package/core/server/api/canary/utils/serializers/output/images.js +2 -2
  31. package/core/server/api/canary/utils/serializers/output/integrations.js +5 -6
  32. package/core/server/api/canary/utils/serializers/output/labels.js +3 -3
  33. package/core/server/api/canary/utils/serializers/output/mappers/actions.js +7 -0
  34. package/core/server/api/canary/utils/serializers/output/mappers/emails.js +17 -0
  35. package/core/server/api/canary/utils/serializers/output/mappers/images.js +5 -0
  36. package/core/server/api/canary/utils/serializers/output/mappers/index.js +12 -0
  37. package/core/server/api/canary/utils/serializers/output/mappers/integrations.js +13 -0
  38. package/core/server/api/canary/utils/serializers/output/mappers/labels.js +4 -0
  39. package/core/server/api/canary/utils/serializers/output/mappers/pages.js +11 -0
  40. package/core/server/api/canary/utils/serializers/output/mappers/posts.js +101 -0
  41. package/core/server/api/canary/utils/serializers/output/mappers/settings.js +37 -0
  42. package/core/server/api/canary/utils/serializers/output/mappers/tags.js +11 -0
  43. package/core/server/api/canary/utils/serializers/output/mappers/users.js +12 -0
  44. package/core/server/api/canary/utils/serializers/output/members.js +2 -7
  45. package/core/server/api/canary/utils/serializers/output/pages.js +3 -3
  46. package/core/server/api/canary/utils/serializers/output/posts.js +3 -3
  47. package/core/server/api/canary/utils/serializers/output/preview.js +2 -2
  48. package/core/server/api/canary/utils/serializers/output/settings.js +2 -2
  49. package/core/server/api/canary/utils/serializers/output/tags.js +3 -3
  50. package/core/server/api/canary/utils/serializers/output/users.js +3 -3
  51. package/core/server/api/shared/serializers/handle.js +2 -2
  52. package/core/server/api/v2/utils/serializers/input/pages.js +1 -1
  53. package/core/server/api/v2/utils/serializers/input/posts.js +1 -1
  54. package/core/server/api/v3/utils/serializers/input/pages.js +1 -1
  55. package/core/server/api/v3/utils/serializers/input/posts.js +1 -1
  56. package/core/server/data/exporter/table-lists.js +1 -0
  57. package/core/server/data/importer/import-manager.js +152 -113
  58. package/core/server/data/migrations/versions/4.33/2022-01-14-11-51-add-default-free-tier.js +3 -0
  59. package/core/server/data/migrations/versions/4.39/2022-03-07-10-57-update-free-products-visibility-column.js +66 -0
  60. package/core/server/data/migrations/versions/4.39/2022-03-07-10-57-update-products-visibility-column.js +36 -0
  61. package/core/server/data/migrations/versions/4.40/2022-03-07-14-37-add-members-cancel-events-table.js +8 -0
  62. package/core/server/data/migrations/versions/4.40/2022-03-15-06-40-add-offers-admin-integration-permission-roles.js +23 -0
  63. package/core/server/data/migrations/versions/4.40/2022-03-15-06-40-add-tiers-admin-integration-permission-roles.js +20 -0
  64. package/core/server/data/schema/default-settings/default-settings.json +2 -2
  65. package/core/server/data/schema/fixtures/fixtures.json +17 -160
  66. package/core/server/data/schema/schema.js +6 -0
  67. package/core/server/lib/image/image-size.js +12 -4
  68. package/core/server/models/base/plugins/generate-slug.js +13 -1
  69. package/core/server/models/base/plugins/raw-knex.js +1 -1
  70. package/core/server/models/member-cancel-event.js +28 -0
  71. package/core/server/models/post.js +16 -6
  72. package/core/server/models/user.js +1 -1
  73. package/core/server/services/auth/setup.js +29 -13
  74. package/core/server/services/mega/mega.js +4 -4
  75. package/core/server/services/mega/template.js +2 -1
  76. package/core/server/services/members/api.js +1 -0
  77. package/core/server/services/members/content-gating.js +1 -1
  78. package/core/server/services/members/middleware.js +1 -0
  79. package/core/server/services/posts/posts-service.js +1 -1
  80. package/core/server/services/themes/validate.js +3 -3
  81. package/core/server/services/url/UrlGenerator.js +1 -1
  82. package/core/server/services/webhooks/webhooks-service.js +2 -0
  83. package/core/server/views/maintenance.html +2 -2
  84. package/core/server/web/admin/views/default-prod.html +4 -4
  85. package/core/server/web/admin/views/default.html +4 -4
  86. package/core/server/web/api/app.js +0 -3
  87. package/core/server/web/api/canary/admin/middleware.js +2 -0
  88. package/core/server/web/parent/backend.js +2 -1
  89. package/core/server/web/shared/middleware/uncapitalise.js +2 -1
  90. package/core/shared/config/defaults.json +2 -2
  91. package/core/shared/config/overrides.json +7 -3
  92. package/core/shared/labs.js +8 -10
  93. package/core/shared/url-utils.js +4 -1
  94. package/package.json +37 -36
  95. package/yarn.lock +513 -329
  96. package/core/built/assets/ghost-dark-9f760f16230b8bc52e188d6ce28516b0.css +0 -1
  97. package/core/built/assets/ghost.min-f4c59dd57a2136df8b0a34f87c099034.css +0 -1
  98. package/core/built/assets/icons/event-started-subscription.svg +0 -6
  99. package/core/built/assets/icons/locked-email-back.svg +0 -1
  100. package/core/built/assets/icons/locked-email-front.svg +0 -1
  101. package/core/built/assets/icons/locked-email-lock.svg +0 -1
  102. package/core/built/assets/img/ghost-logo-de2acf283f53ba1fd1149928faeaaa74.png +0 -0
  103. package/core/server/api/canary/utils/serializers/output/utils/mapper.js +0 -213
  104. package/core/server/frontend/ghost.min.css +0 -1
@@ -3,6 +3,7 @@ const config = require('../../../shared/config');
3
3
  const errors = require('@tryghost/errors');
4
4
  const tpl = require('@tryghost/tpl');
5
5
  const logging = require('@tryghost/logging');
6
+ const moment = require('moment');
6
7
  const models = require('../../models');
7
8
  const mail = require('../mail');
8
9
 
@@ -16,6 +17,11 @@ const messages = {
16
17
  failedThemeInstall: 'Theme {themeName} didn\'t install because of the error: {error}'
17
18
  };
18
19
 
20
+ const postSetupFixtures = {
21
+ 'coming-soon': '{"version":"0.3.1","atoms":[],"cards":[],"markups":[["a",["href","#/portal/"]]],"sections":[[1,"p",[[0,[],0,"This is {{site.title}}, a brand new site by {{author.name}} that\'s just getting started. Things will be up and running here shortly, but you can "],[0,[0],1,"subscribe"],[0,[],0," in the meantime if you\'d like to stay up to date and receive emails when new content is published!"]]]],"ghostVersion":"4.0"}',
22
+ about: '{"version":"0.3.1","atoms":[],"cards":[["hr",{}]],"markups":[["a",["href","https://ghost.org"]]],"sections":[[1,"p",[[0,[],0,"{{site.title}} is an independent publication launched in {{date}} by {{author.name}}. If you subscribe today, you\'ll get full access to the website as well as email newsletters about new content when it\'s available. Your subscription makes this site possible, and allows {{site.title}} to continue to exist. Thank you!"]]],[1,"h3",[[0,[],0,"Access all areas"]]],[1,"p",[[0,[],0,"By signing up, you\'ll get access to the full archive of everything that\'s been published before and everything that\'s still to come. Your very own private library."]]],[1,"h3",[[0,[],0,"Fresh content, delivered"]]],[1,"p",[[0,[],0,"Stay up to date with new content sent straight to your inbox! No more worrying about whether you missed something because of a pesky algorithm or news feed."]]],[1,"h3",[[0,[],0,"Meet people like you"]]],[1,"p",[[0,[],0,"Join a community of other subscribers who share the same interests."]]],[10,0],[1,"h3",[[0,[],0,"Start your own thing"]]],[1,"p",[[0,[],0,"Enjoying the experience? Get started for free and set up your very own subscription business using "],[0,[0],1,"Ghost"],[0,[],0,", the same platform that powers this website."]]]],"ghostVersion":"4.0"}'
23
+ };
24
+
19
25
  /**
20
26
  * Returns setup status
21
27
  *
@@ -110,14 +116,15 @@ async function doProduct(data, productsAPI) {
110
116
  return user;
111
117
  }
112
118
  try {
113
- const page = await productsAPI.browse({limit: 1});
119
+ const page = await productsAPI.browse({limit: 'all'});
120
+
121
+ const product = page.products.find(p => p.slug === 'default-product');
114
122
 
115
- const [product] = page.products;
116
123
  if (!product) {
117
124
  return data;
118
125
  }
119
126
 
120
- productsAPI.edit({products: [{name: blogTitle.trim()}]}, {context: context.context, id: product.id});
127
+ await productsAPI.edit({products: [{name: blogTitle.trim()}]}, {context: context.context, id: product.id});
121
128
  } catch (e) {
122
129
  return data;
123
130
  }
@@ -125,6 +132,22 @@ async function doProduct(data, productsAPI) {
125
132
  return data;
126
133
  }
127
134
 
135
+ async function doFixtures(data) {
136
+ const date = moment().format('MMMM YYYY');
137
+
138
+ _.each(postSetupFixtures, async (mobiledoc, key) => {
139
+ // Using very simple find and replace because we control the fixtures
140
+ mobiledoc = mobiledoc.replace(/{{site.title}}/g, data.userData.blogTitle);
141
+ mobiledoc = mobiledoc.replace(/{{author.name}}/g, data.userData.name);
142
+ mobiledoc = mobiledoc.replace(/{{date}}/, date);
143
+
144
+ const post = await models.Post.findOne({slug: key});
145
+ await models.Post.edit({mobiledoc}, {id: post.id});
146
+ });
147
+
148
+ return data;
149
+ }
150
+
128
151
  function sendWelcomeEmail(email, mailAPI) {
129
152
  if (config.get('sendWelcomeEmail')) {
130
153
  const data = {
@@ -185,14 +208,6 @@ async function installTheme(data, api) {
185
208
  } catch (error) {
186
209
  //Fallback to Casper by doing nothing as the theme setting update is the last step
187
210
  logging.warn(tpl(messages.failedThemeInstall, {themeName, error: error.message}));
188
-
189
- await api.notifications.add({
190
- notifications: [{
191
- custom: true, //avoids update-check from deleting the notification
192
- type: 'warn',
193
- message: 'The installation of the theme you have selected wasn\'t successful.'
194
- }]
195
- }, {context: {internal: true}});
196
211
  }
197
212
 
198
213
  return data;
@@ -204,6 +219,7 @@ module.exports = {
204
219
  setupUser: setupUser,
205
220
  doSettings: doSettings,
206
221
  doProduct: doProduct,
207
- sendWelcomeEmail: sendWelcomeEmail,
208
- installTheme: installTheme
222
+ installTheme: installTheme,
223
+ doFixtures: doFixtures,
224
+ sendWelcomeEmail: sendWelcomeEmail
209
225
  };
@@ -249,14 +249,14 @@ const retryFailedEmail = async (emailModel) => {
249
249
  async function handleUnsubscribeRequest(req) {
250
250
  if (!req.url) {
251
251
  throw new errors.BadRequestError({
252
- message: 'Unsubscribe failed! Could not find member'
252
+ message: 'Email address not found.'
253
253
  });
254
254
  }
255
255
 
256
256
  const {query} = url.parse(req.url, true);
257
257
  if (!query || !query.uuid) {
258
258
  throw new errors.BadRequestError({
259
- message: (query.preview ? 'Unsubscribe preview' : 'Unsubscribe failed! Could not find member')
259
+ message: (query.preview ? 'Unsubscribe preview' : 'Email address not found.')
260
260
  });
261
261
  }
262
262
 
@@ -266,7 +266,7 @@ async function handleUnsubscribeRequest(req) {
266
266
 
267
267
  if (!member) {
268
268
  throw new errors.BadRequestError({
269
- message: 'Unsubscribe failed! Could not find member'
269
+ message: 'Email address not found.'
270
270
  });
271
271
  }
272
272
 
@@ -276,7 +276,7 @@ async function handleUnsubscribeRequest(req) {
276
276
  } catch (err) {
277
277
  throw new errors.InternalServerError({
278
278
  err,
279
- message: 'Failed to unsubscribe member'
279
+ message: 'Failed to unsubscribe this email address'
280
280
  });
281
281
  }
282
282
  }
@@ -263,6 +263,7 @@ code {
263
263
 
264
264
  pre {
265
265
  white-space: pre-wrap;
266
+ overflow: auto;
266
267
  background: #15212A;
267
268
  padding: 15px;
268
269
  border-radius: 3px;
@@ -1216,7 +1217,7 @@ ${ templateSettings.showBadge ? `
1216
1217
 
1217
1218
  ${ templateSettings.showBadge ? `
1218
1219
  <tr>
1219
- <td class="footer-powered"><a href="https://ghost.org/"><img src="https://static.ghost.org/v4.0.0/images/powered.png" border="0" width="142" height="30" class="gh-powered" alt="Publish with Ghost"></a></td>
1220
+ <td class="footer-powered"><a href="https://ghost.org/"><img src="https://static.ghost.org/v4.0.0/images/powered.png" border="0" width="142" height="30" class="gh-powered" alt="Powered by Ghost"></a></td>
1220
1221
  </tr>
1221
1222
  ` : '' }
1222
1223
  </table>
@@ -177,6 +177,7 @@ function createApiInstance(config) {
177
177
  StripeCustomer: models.MemberStripeCustomer,
178
178
  StripeCustomerSubscription: models.StripeCustomerSubscription,
179
179
  Member: models.Member,
180
+ MemberCancelEvent: models.MemberCancelEvent,
180
181
  MemberSubscribeEvent: models.MemberSubscribeEvent,
181
182
  MemberPaidSubscriptionEvent: models.MemberPaidSubscriptionEvent,
182
183
  MemberLoginEvent: models.MemberLoginEvent,
@@ -1,4 +1,4 @@
1
- const nql = require('@nexes/nql');
1
+ const nql = require('@tryghost/nql');
2
2
 
3
3
  // @ts-check
4
4
  /** @typedef { boolean } AccessFlag */
@@ -112,6 +112,7 @@ const getPortalProductPrices = async function () {
112
112
  benefits: product.benefits,
113
113
  active: product.active,
114
114
  type: product.type,
115
+ visibility: product.visibility,
115
116
  prices: productPrices
116
117
  };
117
118
  }).filter((product) => {
@@ -1,4 +1,4 @@
1
- const nql = require('@nexes/nql');
1
+ const nql = require('@tryghost/nql');
2
2
  const {BadRequestError} = require('@tryghost/errors');
3
3
  const tpl = require('@tryghost/tpl');
4
4
 
@@ -28,20 +28,20 @@ const check = async function check(theme, isZip) {
28
28
  debug('zip mode');
29
29
  checkedTheme = await gscan.checkZip(theme, {
30
30
  keepExtractedDir: true,
31
- checkVersion: 'canary',
31
+ checkVersion: 'v4',
32
32
  labs: labs.getAll()
33
33
  });
34
34
  } else {
35
35
  debug('non-zip mode');
36
36
  checkedTheme = await gscan.check(theme.path, {
37
- checkVersion: 'canary',
37
+ checkVersion: 'v4',
38
38
  labs: labs.getAll()
39
39
  });
40
40
  }
41
41
 
42
42
  checkedTheme = gscan.format(checkedTheme, {
43
43
  onlyFatalErrors: config.get('env') === 'production',
44
- checkVersion: 'canary'
44
+ checkVersion: 'v4'
45
45
  });
46
46
 
47
47
  debug('End: Check');
@@ -1,5 +1,5 @@
1
1
  const _ = require('lodash');
2
- const nql = require('@nexes/nql');
2
+ const nql = require('@tryghost/nql');
3
3
  const debug = require('@tryghost/debug')('services:url:generator');
4
4
  const localUtils = require('../../../shared/url-utils');
5
5
 
@@ -41,6 +41,8 @@ class WebhooksService {
41
41
  help: messages.nonExistingIntegrationIdProvided.help
42
42
  });
43
43
  }
44
+
45
+ throw error;
44
46
  }
45
47
  }
46
48
  }
@@ -44,7 +44,7 @@ body {
44
44
  flex-direction: column;
45
45
  justify-content: center;
46
46
  max-width: 500px;
47
- min-height: 500px;
47
+ min-height: 360px;
48
48
  margin: 0 0 4vmin;
49
49
  padding: 40px;
50
50
  text-align: center;
@@ -63,7 +63,7 @@ h1 {
63
63
  letter-spacing: -0.02em;
64
64
  }
65
65
  p {
66
- margin: 0 0 40px;
66
+ margin: 0;
67
67
  opacity: 0.7;
68
68
  font-weight: 400;
69
69
  }
@@ -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.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" />
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.40%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-f4c59dd57a2136df8b0a34f87c099034.css" title="light">
41
+ <link rel="stylesheet" href="assets/ghost.min-77b93478f83b0def6ddc5a4f23ce963e.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-c814d3c4b3f543c4cd5ef3aacd0fc645.js"></script>
60
- <script src="assets/ghost.min-6386b02480494a69c3bfe66206754836.js"></script>
59
+ <script src="assets/vendor.min-ed945ad80ea22f1d3ffeec6d5ae63aee.js"></script>
60
+ <script src="assets/ghost.min-88c665c3ba304b4f220d08b8bcf9d246.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.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" />
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.40%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-f4c59dd57a2136df8b0a34f87c099034.css" title="light">
41
+ <link rel="stylesheet" href="assets/ghost.min-77b93478f83b0def6ddc5a4f23ce963e.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-c814d3c4b3f543c4cd5ef3aacd0fc645.js"></script>
60
- <script src="assets/ghost.min-6386b02480494a69c3bfe66206754836.js"></script>
59
+ <script src="assets/vendor.min-ed945ad80ea22f1d3ffeec6d5ae63aee.js"></script>
60
+ <script src="assets/ghost.min-88c665c3ba304b4f220d08b8bcf9d246.js"></script>
61
61
 
62
62
  </body>
63
63
  </html>
@@ -25,9 +25,6 @@ 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
-
31
28
  // Error handling for requests to non-existent API versions
32
29
  apiApp.use(errorHandler.resourceNotFound);
33
30
  apiApp.use(errorHandler.handleJSONResponse(sentry));
@@ -29,6 +29,8 @@ const notImplemented = function (req, res, next) {
29
29
  users: ['GET'],
30
30
  themes: ['POST', 'PUT'],
31
31
  members: ['GET', 'PUT', 'DELETE', 'POST'],
32
+ tiers: ['GET', 'PUT', 'POST'],
33
+ offers: ['GET', 'PUT', 'POST'],
32
34
  config: ['GET'],
33
35
  schedules: ['PUT'],
34
36
  files: ['POST'],
@@ -1,5 +1,6 @@
1
1
  const debug = require('@tryghost/debug')('web:backend');
2
2
  const express = require('../../../shared/express');
3
+ const {BASE_API_PATH} = require('../../../shared/url-utils');
3
4
 
4
5
  /**
5
6
  *
@@ -11,7 +12,7 @@ module.exports = () => {
11
12
  // Wrap the admin and API apps into a single express app for use with vhost
12
13
  const backendApp = express('backend');
13
14
 
14
- backendApp.lazyUse('/ghost/api', require('../api'));
15
+ backendApp.lazyUse(BASE_API_PATH, require('../api'));
15
16
  backendApp.lazyUse('/ghost/oauth', require('../oauth'));
16
17
  backendApp.lazyUse('/ghost/.well-known', require('../well-known'));
17
18
 
@@ -27,7 +27,8 @@ 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))?\/.*?\/)/i);
30
+ const isAPIRegExp = new RegExp(`^(.*${urlUtils.BASE_API_PATH}(/(v[\\d.]+|canary))?/.*?/)`, 'i');
31
+ const isAPI = pathToTest.match(isAPIRegExp);
31
32
 
32
33
  if (isSignupOrReset) {
33
34
  pathToTest = isSignupOrReset[1];
@@ -128,8 +128,8 @@
128
128
  "emailAnalytics": true
129
129
  },
130
130
  "portal": {
131
- "url": "https://unpkg.com/@tryghost/portal@~1.15.0/umd/portal.min.js",
132
- "version": "1.15"
131
+ "url": "https://unpkg.com/@tryghost/portal@~1.17.0/umd/portal.min.js",
132
+ "version": "1.17"
133
133
  },
134
134
  "tenor": {
135
135
  "publicReadOnlyApiKey": null,
@@ -79,11 +79,15 @@
79
79
  },
80
80
  "api": {
81
81
  "versions": {
82
- "all": ["v2", "v3", "v4", "canary"],
82
+ "all": ["v2", "v3", "v4", "v5", "canary"],
83
83
  "default": "v4",
84
84
  "canary": {
85
- "admin": "canary/admin",
86
- "content": "canary/content"
85
+ "admin": "admin",
86
+ "content": "content"
87
+ },
88
+ "v5": {
89
+ "admin": "admin",
90
+ "content": "content"
87
91
  },
88
92
  "v4": {
89
93
  "admin": "v4/admin",
@@ -15,13 +15,18 @@ const messages = {
15
15
 
16
16
  // flags in this list always return `true`, allows quick global enable prior to full flag removal
17
17
  const GA_FEATURES = [
18
+ 'multipleProducts',
19
+ 'tierWelcomePages',
20
+ 'tierName',
21
+ 'selectablePortalLinks',
22
+ 'membersTableStatus',
23
+ 'improvedOnboarding'
18
24
  ];
19
25
 
20
26
  // NOTE: this allowlist is meant to be used to filter out any unexpected
21
27
  // input for the "labs" setting value
22
28
  const BETA_FEATURES = [
23
- 'activitypub',
24
- 'multipleProducts'
29
+ 'activitypub'
25
30
  ];
26
31
 
27
32
  const ALPHA_FEATURES = [
@@ -30,14 +35,7 @@ const ALPHA_FEATURES = [
30
35
  'urlCache',
31
36
  'beforeAfterCard',
32
37
  'tweetGridCard',
33
- 'membersActivityFeed',
34
- 'improvedOnboarding',
35
- 'tierWelcomePages',
36
- 'tierName',
37
- 'membersTableStatus',
38
- 'membersLastSeenFilter',
39
- 'membersContainsFilters',
40
- 'selectablePortalLinks'
38
+ 'membersActivityFeed'
41
39
  ];
42
40
 
43
41
  module.exports.GA_KEYS = [...GA_FEATURES];
@@ -1,6 +1,8 @@
1
1
  const UrlUtils = require('@tryghost/url-utils');
2
2
  const config = require('./config');
3
3
 
4
+ const BASE_API_PATH = '/ghost/api';
5
+
4
6
  const urlUtils = new UrlUtils({
5
7
  getSubdir: config.getSubdir,
6
8
  getSiteUrl: config.getSiteUrl,
@@ -9,7 +11,8 @@ const urlUtils = new UrlUtils({
9
11
  defaultApiVersion: config.get('api:versions:default'),
10
12
  slugs: config.get('slugs').protected,
11
13
  redirectCacheMaxAge: config.get('caching:301:maxAge'),
12
- baseApiPath: '/ghost/api'
14
+ baseApiPath: BASE_API_PATH
13
15
  });
14
16
 
15
17
  module.exports = urlUtils;
18
+ module.exports.BASE_API_PATH = BASE_API_PATH;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ghost",
3
- "version": "4.38.1",
3
+ "version": "4.40.0",
4
4
  "description": "The professional publishing platform",
5
5
  "author": "Ghost Foundation",
6
6
  "homepage": "https://ghost.org",
@@ -29,7 +29,8 @@
29
29
  "test": "mocha --require=./test/utils/overrides.js --exit --trace-warnings --recursive --extension=test.js --timeout=60000",
30
30
  "test:all": "yarn test:unit && yarn test:integration && yarn test:e2e && yarn lint",
31
31
  "test:debug": "DEBUG=ghost:test* yarn test",
32
- "test:unit": "c8 mocha --require=./test/utils/overrides.js --exit --trace-warnings --recursive --extension=test.js './test/unit' --timeout=2000",
32
+ "test:unit": "c8 yarn test:unit:base",
33
+ "test:unit:base": "mocha --require=./test/utils/overrides.js --exit --trace-warnings --recursive --extension=test.js './test/unit' --timeout=2000",
33
34
  "test:integration": "mocha --require=./test/utils/overrides.js --exit --trace-warnings --recursive --extension=test.js './test/integration' --timeout=5000",
34
35
  "test:e2e": "mocha --require=./test/utils/overrides.js --exit --trace-warnings --recursive --extension=test.js './test/e2e-api' './test/e2e-frontend' './test/e2e-server' --timeout=10000",
35
36
  "test:regression": "mocha --require=./test/utils/overrides.js --exit --trace-warnings --recursive --extension=test.js './test/regression' --timeout=60000",
@@ -54,13 +55,12 @@
54
55
  "cli": "^1.17.0"
55
56
  },
56
57
  "dependencies": {
57
- "@nexes/nql": "0.6.0",
58
- "@sentry/node": "6.18.1",
58
+ "@sentry/node": "6.18.2",
59
59
  "@tryghost/adapter-manager": "0.2.28",
60
- "@tryghost/admin-api-schema": "2.10.0",
61
- "@tryghost/bookshelf-plugins": "0.3.10",
60
+ "@tryghost/admin-api-schema": "2.12.0",
61
+ "@tryghost/bookshelf-plugins": "0.3.11",
62
62
  "@tryghost/bootstrap-socket": "0.2.17",
63
- "@tryghost/color-utils": "0.1.8",
63
+ "@tryghost/color-utils": "0.1.10",
64
64
  "@tryghost/config-url-helpers": "0.1.5",
65
65
  "@tryghost/constants": "1.0.2",
66
66
  "@tryghost/custom-theme-settings-service": "0.3.1",
@@ -69,9 +69,9 @@
69
69
  "@tryghost/domain-events": "0.1.8",
70
70
  "@tryghost/email-analytics-provider-mailgun": "1.0.7",
71
71
  "@tryghost/email-analytics-service": "1.0.5",
72
- "@tryghost/errors": "1.2.3",
72
+ "@tryghost/errors": "1.2.5",
73
73
  "@tryghost/express-dynamic-redirects": "0.2.6",
74
- "@tryghost/helpers": "1.1.57",
74
+ "@tryghost/helpers": "1.1.59",
75
75
  "@tryghost/image-transform": "1.0.28",
76
76
  "@tryghost/job-manager": "0.8.20",
77
77
  "@tryghost/kg-card-factory": "3.1.2",
@@ -81,22 +81,23 @@
81
81
  "@tryghost/kg-mobiledoc-html-renderer": "5.3.4",
82
82
  "@tryghost/limit-service": "1.0.10",
83
83
  "@tryghost/logging": "2.0.4",
84
- "@tryghost/magic-link": "1.0.20",
84
+ "@tryghost/magic-link": "1.0.21",
85
85
  "@tryghost/member-events": "0.4.0",
86
- "@tryghost/members-api": "5.0.4",
86
+ "@tryghost/members-api": "5.4.0",
87
87
  "@tryghost/members-events-service": "0.3.1",
88
88
  "@tryghost/members-importer": "0.5.3",
89
- "@tryghost/members-offers": "0.10.8",
89
+ "@tryghost/members-offers": "0.10.9",
90
90
  "@tryghost/members-ssr": "1.0.22",
91
- "@tryghost/members-stripe-service": "0.8.4",
91
+ "@tryghost/members-stripe-service": "0.9.1",
92
92
  "@tryghost/metrics": "1.0.6",
93
93
  "@tryghost/minifier": "0.1.11",
94
- "@tryghost/mw-error-handler": "0.1.3",
94
+ "@tryghost/mw-error-handler": "0.1.4",
95
95
  "@tryghost/mw-session-from-token": "0.1.28",
96
- "@tryghost/nodemailer": "0.3.13",
96
+ "@tryghost/nodemailer": "0.3.14",
97
+ "@tryghost/nql": "0.9.0",
97
98
  "@tryghost/package-json": "1.0.16",
98
99
  "@tryghost/promise": "0.1.15",
99
- "@tryghost/request": "0.1.16",
100
+ "@tryghost/request": "0.1.17",
100
101
  "@tryghost/root-utils": "0.3.11",
101
102
  "@tryghost/security": "0.2.15",
102
103
  "@tryghost/session-service": "0.1.38",
@@ -105,8 +106,8 @@
105
106
  "@tryghost/string": "0.1.23",
106
107
  "@tryghost/tpl": "0.1.12",
107
108
  "@tryghost/update-check-service": "0.3.1",
108
- "@tryghost/url-utils": "2.0.7",
109
- "@tryghost/validator": "0.1.14",
109
+ "@tryghost/url-utils": "2.0.8",
110
+ "@tryghost/validator": "0.1.15",
110
111
  "@tryghost/verification-trigger": "0.1.5",
111
112
  "@tryghost/version": "0.1.11",
112
113
  "@tryghost/vhost-middleware": "1.0.22",
@@ -116,9 +117,9 @@
116
117
  "bluebird": "3.7.2",
117
118
  "body-parser": "1.19.2",
118
119
  "bookshelf": "1.2.0",
119
- "bookshelf-relations": "2.3.0",
120
+ "bookshelf-relations": "2.4.0",
120
121
  "brute-knex": "4.0.1",
121
- "bson-objectid": "2.0.2",
122
+ "bson-objectid": "2.0.3",
122
123
  "bthreads": "0.5.1",
123
124
  "cheerio": "0.22.0",
124
125
  "compression": "1.7.4",
@@ -148,19 +149,19 @@
148
149
  "juice": "8.0.0",
149
150
  "keypair": "1.0.4",
150
151
  "knex": "0.21.21",
151
- "knex-migrator": "4.2.2",
152
+ "knex-migrator": "4.2.3",
152
153
  "lodash": "4.17.21",
153
154
  "luxon": "2.3.1",
154
155
  "mailgun-js": "0.22.0",
155
- "metascraper": "5.25.8",
156
- "metascraper-author": "5.25.8",
157
- "metascraper-description": "5.25.8",
158
- "metascraper-image": "5.25.8",
159
- "metascraper-logo": "5.25.8",
160
- "metascraper-logo-favicon": "5.25.8",
161
- "metascraper-publisher": "5.25.8",
162
- "metascraper-title": "5.25.8",
163
- "metascraper-url": "5.25.8",
156
+ "metascraper": "5.26.0",
157
+ "metascraper-author": "5.26.0",
158
+ "metascraper-description": "5.26.0",
159
+ "metascraper-image": "5.26.0",
160
+ "metascraper-logo": "5.26.0",
161
+ "metascraper-logo-favicon": "5.26.0",
162
+ "metascraper-publisher": "5.26.0",
163
+ "metascraper-title": "5.26.0",
164
+ "metascraper-url": "5.26.0",
164
165
  "moment": "2.24.0",
165
166
  "moment-timezone": "0.5.23",
166
167
  "multer": "1.4.4",
@@ -171,7 +172,7 @@
171
172
  "passport": "0.5.2",
172
173
  "passport-google-oauth": "2.0.0",
173
174
  "path-match": "1.2.4",
174
- "probe-image-size": "5.0.0",
175
+ "probe-image-size": "7.2.3",
175
176
  "rss": "1.2.2",
176
177
  "sanitize-html": "2.7.0",
177
178
  "semver": "7.3.5",
@@ -187,11 +188,11 @@
187
188
  "devDependencies": {
188
189
  "@lodder/grunt-postcss": "3.1.1",
189
190
  "@playwright/test": "1.19.2",
190
- "@tryghost/express-test": "0.6.0",
191
+ "@tryghost/express-test": "0.6.1",
191
192
  "c8": "7.11.0",
192
193
  "coffeescript": "2.6.1",
193
- "cssnano": "5.1.0",
194
- "eslint": "8.10.0",
194
+ "cssnano": "5.1.2",
195
+ "eslint": "8.11.0",
195
196
  "eslint-plugin-ghost": "2.13.0",
196
197
  "grunt": "1.4.1",
197
198
  "grunt-bg-shell": "2.3.3",
@@ -205,12 +206,12 @@
205
206
  "grunt-subgrunt": "1.3.0",
206
207
  "grunt-update-submodules": "0.4.1",
207
208
  "jwks-rsa": "2.0.5",
208
- "mocha": "9.2.1",
209
+ "mocha": "9.2.2",
209
210
  "mocha-slow-test-reporter": "0.1.2",
210
211
  "mock-knex": "0.4.10",
211
212
  "nock": "13.2.4",
212
213
  "papaparse": "5.3.1",
213
- "postcss": "8.4.7",
214
+ "postcss": "8.4.8",
214
215
  "rewire": "6.0.0",
215
216
  "should": "13.2.3",
216
217
  "sinon": "13.0.1",