ghost 4.22.4 → 4.25.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.
Files changed (170) hide show
  1. package/.eslintrc.js +39 -0
  2. package/content/themes/casper/assets/built/casper.js +1 -1
  3. package/content/themes/casper/assets/built/casper.js.map +1 -1
  4. package/content/themes/casper/assets/built/global.css +1 -1
  5. package/content/themes/casper/assets/built/global.css.map +1 -1
  6. package/content/themes/casper/assets/built/screen.css +1 -1
  7. package/content/themes/casper/assets/built/screen.css.map +1 -1
  8. package/content/themes/casper/assets/css/global.css +6 -1
  9. package/content/themes/casper/assets/css/screen.css +32 -216
  10. package/content/themes/casper/default.hbs +2 -2
  11. package/content/themes/casper/package.json +3 -2
  12. package/content/themes/casper/post.hbs +1 -1
  13. package/content/themes/casper/yarn.lock +173 -123
  14. package/core/app.js +12 -1
  15. package/core/boot.js +33 -19
  16. package/core/bridge.js +10 -10
  17. package/core/built/assets/ghost-dark-f67240a9636407594be38571c615629c.css +1 -0
  18. package/core/built/assets/{ghost.min-2e3e64eb258cf424c59c3e308b4bc6e6.js → ghost.min-3441c3282e390002626a2dc1d7586185.js} +544 -619
  19. package/core/built/assets/ghost.min-ee5bd95a831378b4c8ccefb37d26eac0.css +1 -0
  20. package/core/built/assets/icons/audio-upload.svg +8 -0
  21. package/core/built/assets/{vendor.min-c9002845b6c30ac978abdadde9f33d7c.js → vendor.min-6fc912d1248c906f95efad2cb3eebb7d.js} +2656 -2118
  22. package/core/frontend/apps/amp/lib/helpers/amp_content.js +2 -2
  23. package/core/frontend/apps/amp/lib/views/amp.hbs +70 -0
  24. package/core/frontend/apps/private-blogging/index.js +1 -1
  25. package/core/frontend/helpers/url.js +18 -1
  26. package/core/frontend/services/apps/index.js +1 -1
  27. package/core/frontend/services/apps/loader.js +3 -3
  28. package/core/frontend/services/card-assets/index.js +0 -12
  29. package/core/frontend/services/card-assets/service.js +22 -21
  30. package/core/frontend/services/helpers/handlebars.js +1 -1
  31. package/core/frontend/services/theme-engine/middleware/ensure-active-theme.js +34 -0
  32. package/core/frontend/services/theme-engine/middleware/index.js +6 -0
  33. package/core/frontend/services/theme-engine/middleware/update-global-template-options.js +116 -0
  34. package/core/frontend/services/theme-engine/middleware/update-local-template-data.js +9 -0
  35. package/core/frontend/services/theme-engine/middleware/update-local-template-options.js +57 -0
  36. package/core/frontend/src/cards/css/blockquote.css +29 -0
  37. package/core/frontend/src/cards/css/bookmark.css +7 -0
  38. package/core/frontend/src/cards/css/button.css +4 -0
  39. package/core/frontend/src/cards/css/callout.css +23 -15
  40. package/core/frontend/src/cards/css/gallery.css +13 -3
  41. package/core/frontend/src/cards/css/toggle.css +36 -16
  42. package/core/frontend/web/middleware/error-handler.js +93 -0
  43. package/core/frontend/web/middleware/handle-image-sizes.js +3 -6
  44. package/core/frontend/web/middleware/index.js +1 -0
  45. package/core/frontend/web/middleware/serve-public-file.js +25 -8
  46. package/core/frontend/web/site.js +2 -5
  47. package/core/server/adapters/scheduling/SchedulingDefault.js +2 -2
  48. package/core/server/adapters/storage/LocalStorageBase.js +2 -2
  49. package/core/server/api/canary/db.js +2 -2
  50. package/core/server/api/canary/media.js +3 -2
  51. package/core/server/api/canary/oembed.js +16 -1
  52. package/core/server/api/canary/session.js +1 -1
  53. package/core/server/api/canary/slugs.js +1 -1
  54. package/core/server/api/canary/utils/permissions.js +2 -2
  55. package/core/server/api/canary/utils/serializers/output/config.js +2 -6
  56. package/core/server/api/v2/db.js +2 -2
  57. package/core/server/api/v2/session.js +1 -1
  58. package/core/server/api/v2/slugs.js +1 -1
  59. package/core/server/api/v2/utils/permissions.js +2 -2
  60. package/core/server/api/v3/db.js +2 -2
  61. package/core/server/api/v3/session.js +1 -1
  62. package/core/server/api/v3/slugs.js +1 -1
  63. package/core/server/api/v3/utils/permissions.js +2 -2
  64. package/core/server/data/db/state-manager.js +4 -4
  65. package/core/server/data/exporter/export-filename.js +1 -1
  66. package/core/server/data/importer/handlers/json.js +1 -1
  67. package/core/server/data/importer/import-manager.js +1 -1
  68. package/core/server/data/importer/importers/data/base.js +1 -1
  69. package/core/server/data/migrations/utils.js +2 -2
  70. package/core/server/data/migrations/versions/1.25/1-update-koenig-beta-html.js +1 -0
  71. package/core/server/data/migrations/versions/3.1/08-add-uuid-values-to-members.js +1 -0
  72. package/core/server/data/migrations/versions/3.22/02-settings-key-renames.js +2 -0
  73. package/core/server/data/migrations/versions/3.22/05-migrate-members-subscription-settings.js +3 -0
  74. package/core/server/data/migrations/versions/3.22/06-migrate-stripe-connect-settings.js +2 -0
  75. package/core/server/data/migrations/versions/3.23/01-migrate-bulk-email-settings.js +1 -0
  76. package/core/server/data/migrations/versions/3.29/01-remove-duplicate-subscriptions.js +2 -0
  77. package/core/server/data/migrations/versions/3.29/02-remove-duplicate-customers.js +2 -0
  78. package/core/server/data/migrations/versions/3.38/04-populate-recipient-filter-column.js +2 -0
  79. package/core/server/data/migrations/versions/4.0/01-update-mobiledoc.js +2 -0
  80. package/core/server/data/migrations/versions/4.0/03-populate-status-column-for-members.js +4 -0
  81. package/core/server/data/migrations/versions/4.0/06-populate-members-subscribe-events-table.js +1 -0
  82. package/core/server/data/migrations/versions/4.0/17-populate-members-status-events-table.js +1 -0
  83. package/core/server/data/migrations/versions/4.0/18-transform-urls-absolute-to-transform-ready.js +5 -0
  84. package/core/server/data/migrations/versions/4.0/22-solve-orphaned-webhooks.js +1 -0
  85. package/core/server/data/migrations/versions/4.0/23-regenerate-posts-html.js +1 -0
  86. package/core/server/data/migrations/versions/4.0/25-populate-members-paid-subscription-events-table.js +2 -1
  87. package/core/server/data/migrations/versions/4.12/02-fix-member-statuses.js +1 -0
  88. package/core/server/data/migrations/versions/4.14/01-fix-comped-member-statuses.js +3 -0
  89. package/core/server/data/migrations/versions/4.14/02-fix-free-members-status-events.js +1 -0
  90. package/core/server/data/migrations/versions/4.20/05-remove-not-null-constraint-from-portal-title.js +2 -0
  91. package/core/server/data/migrations/versions/4.23/01-truncate-offer-names.js +59 -0
  92. package/core/server/data/migrations/versions/4.3/04-attach-members-to-product.js +1 -0
  93. package/core/server/data/migrations/versions/4.4/01-restore-free-members-signup-setting-from-backup.js +1 -0
  94. package/core/server/data/migrations/versions/4.6/01-remove-comped-status.js +1 -0
  95. package/core/server/data/migrations/versions/4.8/04-migrate-show-newsletter-header-setting.js +1 -0
  96. package/core/server/data/migrations/versions/4.9/05-fix-missed-mobiledoc-url-transforms.js +1 -0
  97. package/core/server/data/migrations/versions/4.9/06-add-comped-status.js +1 -0
  98. package/core/server/data/migrations/versions/4.9/07-update-comped-members-status-events.js +1 -0
  99. package/core/server/data/schema/commands.js +2 -2
  100. package/core/server/ghost-server.js +2 -2
  101. package/core/server/lib/image/image-size.js +2 -2
  102. package/core/server/models/base/listeners.js +2 -2
  103. package/core/server/models/member-email-change-event.js +2 -2
  104. package/core/server/models/member-login-event.js +2 -2
  105. package/core/server/models/member-paid-subscription-event.js +3 -3
  106. package/core/server/models/member-payment-event.js +3 -3
  107. package/core/server/models/member-product-event.js +6 -6
  108. package/core/server/models/member-status-event.js +5 -3
  109. package/core/server/models/member-subscribe-event.js +9 -3
  110. package/core/server/models/relations/authors.js +1 -1
  111. package/core/server/models/settings.js +1 -1
  112. package/core/server/services/auth/passwordreset.js +1 -1
  113. package/core/server/services/auth/setup.js +1 -1
  114. package/core/server/services/email-analytics/jobs/index.js +1 -1
  115. package/core/server/services/mega/mega.js +6 -4
  116. package/core/server/services/mega/template.js +31 -12
  117. package/core/server/services/members/api.js +22 -0
  118. package/core/server/services/members/config.js +1 -1
  119. package/core/server/services/members/emails/signup-paid.js +168 -0
  120. package/core/server/services/members/service.js +6 -2
  121. package/core/server/services/members/stripe-connect.js +4 -2
  122. package/core/server/services/nft-oembed.js +6 -1
  123. package/core/server/services/oembed.js +36 -28
  124. package/core/server/services/permissions/can-this.js +1 -1
  125. package/core/server/services/redirects/api.js +20 -25
  126. package/core/server/services/redirects/index.js +18 -10
  127. package/core/server/services/redirects/utils.js +14 -0
  128. package/core/server/services/redirects/validation.js +10 -0
  129. package/core/server/services/route-settings/default-settings-manager.js +1 -1
  130. package/core/server/services/route-settings/index.js +40 -17
  131. package/core/server/services/route-settings/route-settings.js +120 -115
  132. package/core/server/services/route-settings/settings-loader.js +18 -36
  133. package/core/server/services/route-settings/yaml-parser.js +1 -1
  134. package/core/server/services/slack.js +1 -1
  135. package/core/server/services/themes/activation-bridge.js +3 -3
  136. package/core/server/services/themes/storage.js +2 -2
  137. package/core/server/services/twitter-embed.js +80 -0
  138. package/core/server/services/url/LocalFileCache.js +75 -0
  139. package/core/server/services/url/UrlService.js +15 -47
  140. package/core/server/services/url/index.js +17 -4
  141. package/core/server/services/xmlrpc.js +2 -2
  142. package/core/server/web/admin/app.js +2 -5
  143. package/core/server/web/admin/controller.js +35 -12
  144. package/core/server/web/admin/middleware/redirect-admin-urls.js +15 -0
  145. package/core/server/web/admin/views/default-prod.html +4 -4
  146. package/core/server/web/admin/views/default.html +4 -4
  147. package/core/server/web/api/canary/admin/app.js +0 -3
  148. package/core/server/web/api/canary/admin/middleware.js +1 -1
  149. package/core/server/web/api/canary/content/app.js +0 -3
  150. package/core/server/web/api/v2/admin/app.js +0 -3
  151. package/core/server/web/api/v2/admin/middleware.js +1 -1
  152. package/core/server/web/api/v2/content/app.js +0 -3
  153. package/core/server/web/api/v3/admin/app.js +0 -3
  154. package/core/server/web/api/v3/admin/middleware.js +1 -1
  155. package/core/server/web/api/v3/content/app.js +0 -3
  156. package/core/server/web/members/app.js +0 -3
  157. package/core/server/web/oauth/app.js +0 -4
  158. package/core/server/web/parent/app.js +17 -8
  159. package/core/server/web/shared/middleware/error-handler.js +57 -162
  160. package/core/server/web/shared/middleware/index.js +0 -4
  161. package/core/shared/config/defaults.json +7 -1
  162. package/core/shared/labs.js +10 -5
  163. package/core/shared/sentry.js +1 -1
  164. package/package.json +43 -42
  165. package/yarn.lock +802 -923
  166. package/content/themes/casper/assets/js/gallery-card.js +0 -24
  167. package/core/built/assets/ghost-dark-42cf6e0c730578940ec069bda45aea41.css +0 -1
  168. package/core/built/assets/ghost.min-fcf6a0738421f86c47c55f20d00c5ba9.css +0 -1
  169. package/core/frontend/services/theme-engine/middleware.js +0 -209
  170. package/core/server/web/shared/middleware/maintenance.js +0 -25
@@ -12,6 +12,7 @@ module.exports = {
12
12
 
13
13
  logging.info(`Adding uuid field value to ${membersWithoutUUID.length} members.`);
14
14
 
15
+ // eslint-disable-next-line no-restricted-syntax
15
16
  for (const member of membersWithoutUUID) {
16
17
  await conn('members').update('uuid', uuid.v4()).where('id', member.id);
17
18
  }
@@ -35,6 +35,7 @@ module.exports = {
35
35
  },
36
36
 
37
37
  async up(options) {
38
+ // eslint-disable-next-line no-restricted-syntax
38
39
  for (const renameMapping of renameMappings) {
39
40
  const oldSetting = await options.transacting('settings')
40
41
  .where('key', renameMapping.from)
@@ -61,6 +62,7 @@ module.exports = {
61
62
  },
62
63
 
63
64
  async down(options) {
65
+ // eslint-disable-next-line no-restricted-syntax
64
66
  for (const renameMapping of renameMappings) {
65
67
  const newSetting = await options.transacting('settings')
66
68
  .where('key', renameMapping.to)
@@ -24,6 +24,7 @@ module.exports = {
24
24
  key: 'stripe_plans'
25
25
  }];
26
26
 
27
+ // eslint-disable-next-line no-restricted-syntax
27
28
  for (const operation of defaultOperations) {
28
29
  logging.info(`Updating ${operation.key} setting group,type,flags`);
29
30
  await knex('settings')
@@ -86,6 +87,7 @@ module.exports = {
86
87
  value: JSON.stringify(stripePlans)
87
88
  }];
88
89
 
90
+ // eslint-disable-next-line no-restricted-syntax
89
91
  for (const operation of valueOperations) {
90
92
  logging.info(`Updating ${operation.key} setting value`);
91
93
  await knex('settings')
@@ -170,6 +172,7 @@ module.exports = {
170
172
  'stripe_secret_key'
171
173
  ];
172
174
 
175
+ // eslint-disable-next-line no-restricted-syntax
173
176
  for (const setting of settingsToDelete) {
174
177
  logging.info(`Deleting ${setting} setting`);
175
178
  }
@@ -20,6 +20,7 @@ module.exports = {
20
20
  key: 'stripe_connect_account_id'
21
21
  }];
22
22
 
23
+ // eslint-disable-next-line no-restricted-syntax
23
24
  for (const operation of defaultOperations) {
24
25
  logging.info(`Updating ${operation.key} setting group,type,flags`);
25
26
  await knex('settings')
@@ -62,6 +63,7 @@ module.exports = {
62
63
  value: stripeConnectIntegration.account_id || ''
63
64
  }];
64
65
 
66
+ // eslint-disable-next-line no-restricted-syntax
65
67
  for (const operation of valueOperations) {
66
68
  logging.info(`Updating ${operation.key} setting value`);
67
69
  await knex('settings')
@@ -35,6 +35,7 @@ module.exports = {
35
35
  value: bulkEmailSettings.baseUrl
36
36
  }];
37
37
 
38
+ // eslint-disable-next-line no-restricted-syntax
38
39
  for (const operation of operations) {
39
40
  logging.info(`Updating ${operation.key} setting's value, group, type & flags.`);
40
41
  await knex('settings')
@@ -23,6 +23,7 @@ module.exports = {
23
23
  }
24
24
 
25
25
  logging.info(`Found ${duplicates.length} duplicate stripe subscriptions`);
26
+ // eslint-disable-next-line no-restricted-syntax
26
27
  for (const duplicate of duplicates) {
27
28
  const subscriptions = await knex('members_stripe_customers_subscriptions')
28
29
  .select()
@@ -36,6 +37,7 @@ module.exports = {
36
37
 
37
38
  logging.info(`Keeping newest subscription ${newestSubscription.id} - ${newestSubscription.subscription_id}, last updated at ${newestSubscription.updated_at}`);
38
39
 
40
+ // eslint-disable-next-line no-restricted-syntax
39
41
  for (const subscriptionToDelete of olderSubscriptions) {
40
42
  logging.info(`Deleting duplicate subscription ${subscriptionToDelete.id} - ${subscriptionToDelete.subscription_id}, last updated at ${subscriptionToDelete.updated_at}`);
41
43
  await knex('members_stripe_customers_subscriptions')
@@ -23,6 +23,7 @@ module.exports = {
23
23
  }
24
24
 
25
25
  logging.info(`Found ${duplicates.length} duplicate stripe customers`);
26
+ // eslint-disable-next-line no-restricted-syntax
26
27
  for (const duplicate of duplicates) {
27
28
  const customers = await knex('members_stripe_customers')
28
29
  .select()
@@ -36,6 +37,7 @@ module.exports = {
36
37
 
37
38
  logging.info(`Keeping newest customer ${newestCustomer.id} - ${newestCustomer.customer_id}, last updated at ${newestCustomer.updated_at}`);
38
39
 
40
+ // eslint-disable-next-line no-restricted-syntax
39
41
  for (const customerToDelete of olderCustomers) {
40
42
  logging.info(`Deleting duplicate customer ${customerToDelete.id} - ${customerToDelete.customer_id}, last updated at ${customerToDelete.updated_at}`);
41
43
  await knex('members_stripe_customers')
@@ -25,12 +25,14 @@ module.exports = createTransactionalMigration(
25
25
  const paidPostIdChunks = chunk(paidPostIds, chunkSize);
26
26
  const membersAndPublicPostIdChunks = chunk(membersPostIds.concat(publicPostIds), chunkSize);
27
27
 
28
+ // eslint-disable-next-line no-restricted-syntax
28
29
  for (const paidPostIdsChunk of paidPostIdChunks) {
29
30
  await connection('emails')
30
31
  .update('recipient_filter', 'paid')
31
32
  .whereIn('post_id', paidPostIdsChunk);
32
33
  }
33
34
 
35
+ // eslint-disable-next-line no-restricted-syntax
34
36
  for (const membersAndPublicPostIdsChunk of membersAndPublicPostIdChunks) {
35
37
  await connection('emails')
36
38
  .update('recipient_filter', 'all')
@@ -15,6 +15,7 @@ module.exports = createIrreversibleMigration(async (knex) => {
15
15
  // pushing all queries into the query builder buffer in parallel
16
16
  // https://stackoverflow.com/questions/54105280/how-to-loop-through-multi-line-sql-query-and-use-them-in-knex-transactions
17
17
 
18
+ // eslint-disable-next-line no-restricted-syntax
18
19
  for (const postIdRow of postIdRows) {
19
20
  const {id} = postIdRow;
20
21
  const [{mobiledoc: mobiledocJson}] = await knex('posts')
@@ -31,6 +32,7 @@ module.exports = createIrreversibleMigration(async (knex) => {
31
32
  }
32
33
 
33
34
  if (mobiledoc.cards) {
35
+ // eslint-disable-next-line no-restricted-syntax
34
36
  mobiledoc.cards.forEach((card) => {
35
37
  // card-markdown card was used in 1.0 and aliased to markdown in 2.0 onwards
36
38
  // clean it up here whilst we're already modifying mobiledoc
@@ -5,6 +5,7 @@ const logging = require('@tryghost/logging');
5
5
  module.exports = createTransactionalMigration(
6
6
  async function up(knex) {
7
7
  logging.info('Updating members.status based on members_stripe_customers_subscriptions.status');
8
+ // eslint-disable-next-line no-restricted-syntax
8
9
  const paidMemberIds = (await knex('members')
9
10
  .select('members.id')
10
11
  .innerJoin(
@@ -24,6 +25,7 @@ module.exports = createTransactionalMigration(
24
25
  }
25
26
  )).map(({id}) => id);
26
27
 
28
+ // eslint-disable-next-line no-restricted-syntax
27
29
  const compedMemberIds = (await knex('members')
28
30
  .select('members.id')
29
31
  .innerJoin(
@@ -54,6 +56,7 @@ module.exports = createTransactionalMigration(
54
56
 
55
57
  const paidMemberIdChunks = chunk(paidMemberIds, chunkSize);
56
58
 
59
+ // eslint-disable-next-line no-restricted-syntax
57
60
  for (const paidMemberIdsChunk of paidMemberIdChunks) {
58
61
  await knex('members')
59
62
  .update('status', 'paid')
@@ -62,6 +65,7 @@ module.exports = createTransactionalMigration(
62
65
 
63
66
  const compedMemberIdChunks = chunk(compedMemberIds, chunkSize);
64
67
 
68
+ // eslint-disable-next-line no-restricted-syntax
65
69
  for (const compedMemberIdsChunk of compedMemberIdChunks) {
66
70
  await knex('members')
67
71
  .update('status', 'comped')
@@ -42,6 +42,7 @@ module.exports = createTransactionalMigration(
42
42
 
43
43
  const eventChunks = chunk(allEvents, chunkSize);
44
44
 
45
+ // eslint-disable-next-line no-restricted-syntax
45
46
  for (const events of eventChunks) {
46
47
  await knex.insert(events).into('members_subscribe_events');
47
48
  }
@@ -28,6 +28,7 @@ module.exports = createTransactionalMigration(
28
28
 
29
29
  const eventChunks = chunk(membersStatusEvents, chunkSize);
30
30
 
31
+ // eslint-disable-next-line no-restricted-syntax
31
32
  for (const events of eventChunks) {
32
33
  await knex.insert(events).into('members_status_events');
33
34
  }
@@ -18,6 +18,7 @@ module.exports = createIrreversibleMigration(async (knex) => {
18
18
  // pushing all queries into the query builder buffer in parallel
19
19
  // https://stackoverflow.com/questions/54105280/how-to-loop-through-multi-line-sql-query-and-use-them-in-knex-transactions
20
20
 
21
+ // eslint-disable-next-line no-restricted-syntax
21
22
  for (const postIdRow of postIdRows) {
22
23
  const {id} = postIdRow;
23
24
  const [post] = await knex('posts')
@@ -80,6 +81,7 @@ module.exports = createIrreversibleMigration(async (knex) => {
80
81
  .forUpdate()
81
82
  .select('id');
82
83
 
84
+ // eslint-disable-next-line no-restricted-syntax
83
85
  for (const userIdRow of userIdRows) {
84
86
  const {id} = userIdRow;
85
87
  const [user] = await knex('users')
@@ -108,6 +110,7 @@ module.exports = createIrreversibleMigration(async (knex) => {
108
110
  .forUpdate()
109
111
  .select('id');
110
112
 
113
+ // eslint-disable-next-line no-restricted-syntax
111
114
  for (const tagIdRow of tagIdRows) {
112
115
  const {id} = tagIdRow;
113
116
  const [tag] = await knex('tags')
@@ -148,6 +151,7 @@ module.exports = createIrreversibleMigration(async (knex) => {
148
151
  .forUpdate()
149
152
  .select('id');
150
153
 
154
+ // eslint-disable-next-line no-restricted-syntax
151
155
  for (const snippetIdRow of snippetIdRows) {
152
156
  const {id} = snippetIdRow;
153
157
  const [snippet] = await knex('snippets')
@@ -180,6 +184,7 @@ module.exports = createIrreversibleMigration(async (knex) => {
180
184
  'twitter_image'
181
185
  ]);
182
186
 
187
+ // eslint-disable-next-line no-restricted-syntax
183
188
  for (const settingRow of settingsRows) {
184
189
  let {key, value} = settingRow;
185
190
 
@@ -77,6 +77,7 @@ module.exports = createIrreversibleMigration(
77
77
  };
78
78
  await knex('api_keys').insert(adminKey);
79
79
 
80
+ // eslint-disable-next-line no-restricted-syntax
80
81
  for (let i = 0; i < orphanedWebhooks.length; i++) {
81
82
  const webhook = orphanedWebhooks[i];
82
83
 
@@ -17,6 +17,7 @@ module.exports = createIrreversibleMigration(async (knex) => {
17
17
  // pushing all queries into the query builder buffer in parallel
18
18
  // https://stackoverflow.com/questions/54105280/how-to-loop-through-multi-line-sql-query-and-use-them-in-knex-transactions
19
19
 
20
+ // eslint-disable-next-line no-restricted-syntax
20
21
  for (const postIdRow of postIdRows) {
21
22
  const {id} = postIdRow;
22
23
  const [post] = await knex('posts')
@@ -44,7 +44,7 @@ module.exports = createTransactionalMigration(
44
44
  return amount * 30;
45
45
  }
46
46
 
47
- throw new errors.GhostError({
47
+ throw new errors.InternalServerError({
48
48
  message: tpl(messages.unknownSubscriptionIntervalError , {
49
49
  interval
50
50
  })
@@ -116,6 +116,7 @@ module.exports = createTransactionalMigration(
116
116
 
117
117
  const eventChunks = chunk(allEvents, chunkSize);
118
118
 
119
+ // eslint-disable-next-line no-restricted-syntax
119
120
  for (const events of eventChunks) {
120
121
  await knex.insert(events).into('members_paid_subscription_events');
121
122
  }
@@ -26,6 +26,7 @@ module.exports = createTransactionalMigration(
26
26
 
27
27
  const chunks = chunkArray(freeMembersIds, chunkSize);
28
28
 
29
+ // eslint-disable-next-line no-restricted-syntax
29
30
  for (const chunk of chunks) {
30
31
  await knex('members')
31
32
  .update('status', 'free')
@@ -3,6 +3,7 @@ const {createTransactionalMigration} = require('../../utils');
3
3
  const logging = require('@tryghost/logging');
4
4
 
5
5
  module.exports = createTransactionalMigration(async function up(knex) {
6
+ // eslint-disable-next-line no-restricted-syntax
6
7
  const compedMemberIds = (await knex('members')
7
8
  .select('members.id')
8
9
  .innerJoin(
@@ -44,12 +45,14 @@ module.exports = createTransactionalMigration(async function up(knex) {
44
45
 
45
46
  const compedMemberIdChunks = chunk(compedMemberIds, chunkSize);
46
47
 
48
+ // eslint-disable-next-line no-restricted-syntax
47
49
  for (const compedMemberIdsChunk of compedMemberIdChunks) {
48
50
  await knex('members')
49
51
  .update('status', 'comped')
50
52
  .whereIn('id', compedMemberIdsChunk);
51
53
  }
52
54
 
55
+ // eslint-disable-next-line no-restricted-syntax
53
56
  for (const memberId of compedMemberIds) {
54
57
  const mostRecentStatusEvent = await knex('members_status_events')
55
58
  .select('*')
@@ -49,6 +49,7 @@ module.exports = createTransactionalMigration(
49
49
  // and so we're left with 998 for our WHERE IN clause values
50
50
  const chunkedEventsToUpdate = _.chunk(eventsToUpdate, 998);
51
51
 
52
+ // eslint-disable-next-line no-restricted-syntax
52
53
  for (const chunk of chunkedEventsToUpdate) {
53
54
  logging.info(`Updating a chunk of ${chunk.length} member status events`);
54
55
  await knex('members_status_events')
@@ -15,6 +15,7 @@ module.exports = createNonTransactionalMigration(
15
15
  });
16
16
 
17
17
  if (knex.client.config.client === 'sqlite3') {
18
+ // eslint-disable-next-line no-restricted-syntax
18
19
  for (const column of ['name', 'code', 'stripe_coupon_id']) {
19
20
  await addUnique('offers', column, knex);
20
21
  }
@@ -32,6 +33,7 @@ module.exports = createNonTransactionalMigration(
32
33
  });
33
34
 
34
35
  if (knex.client.config.client === 'sqlite3') {
36
+ // eslint-disable-next-line no-restricted-syntax
35
37
  for (const column of ['name', 'code', 'stripe_coupon_id']) {
36
38
  await addUnique('offers', column, knex);
37
39
  }
@@ -0,0 +1,59 @@
1
+ const logging = require('@tryghost/logging');
2
+ const {createTransactionalMigration} = require('../../utils');
3
+
4
+ /**
5
+ * @param {(val: string) => boolean} exists
6
+ * @param {string} requested
7
+ * @param {string} attempt
8
+ * @param {number} n
9
+ *
10
+ * @returns {string}
11
+ */
12
+ function getUnique(exists, requested, attempt = requested, n = 1) {
13
+ if (!exists(attempt)) {
14
+ return attempt;
15
+ }
16
+ const newAttempt = requested.slice(0, -n.toString().length) + n;
17
+ return getUnique(exists, requested, newAttempt, n + 1);
18
+ }
19
+
20
+ module.exports = createTransactionalMigration(
21
+ async function up(knex) {
22
+ const allOffers = await knex
23
+ .select('id', 'name')
24
+ .from('offers');
25
+
26
+ const offersNeedingTrunctation = allOffers.filter((row) => {
27
+ return row.name.length >= 40;
28
+ });
29
+
30
+ if (offersNeedingTrunctation.length === 0) {
31
+ logging.warn('No Offers found needing truncation');
32
+ return;
33
+ } else {
34
+ logging.info(`Found ${offersNeedingTrunctation.length} Offers needing truncation`);
35
+ }
36
+
37
+ const truncatedOffers = offersNeedingTrunctation.reduce((offers, row) => {
38
+ function exists(name) {
39
+ return offers.find(offer => offer.name === name) !== undefined;
40
+ }
41
+
42
+ const updatedRow = {
43
+ id: row.id,
44
+ name: getUnique(exists, row.name.slice(0, 40))
45
+ };
46
+
47
+ return offers.concat(updatedRow);
48
+ }, []);
49
+
50
+ // eslint-disable-next-line no-restricted-syntax
51
+ for (const truncatedOffer of truncatedOffers) {
52
+ await knex('offers')
53
+ .update('name', truncatedOffer.name)
54
+ .where('id', truncatedOffer.id);
55
+ }
56
+ },
57
+ // no-op we've lost the data required to roll this back
58
+ async function down() {}
59
+ );
@@ -38,6 +38,7 @@ module.exports = createTransactionalMigration(
38
38
  const chunkSize = 333;
39
39
  const memberProductRelationsChunks = chunk(memberProductRelations, chunkSize);
40
40
 
41
+ // eslint-disable-next-line no-restricted-syntax
41
42
  for (const relations of memberProductRelationsChunks) {
42
43
  await knex.insert(relations).into('members_products');
43
44
  }
@@ -63,6 +63,7 @@ module.exports = createTransactionalMigration(
63
63
 
64
64
  let hasRestored = false;
65
65
 
66
+ // eslint-disable-next-line no-restricted-syntax
66
67
  for (const backupFile of backupFiles) {
67
68
  try {
68
69
  const backup = require(path.join(dataPath, backupFile));
@@ -9,6 +9,7 @@ module.exports = createTransactionalMigration(
9
9
  .where('status', 'comped');
10
10
  },
11
11
  async function down(knex) {
12
+ // eslint-disable-next-line no-restricted-syntax
12
13
  const compedMemberIds = (await knex('members')
13
14
  .select('members.id')
14
15
  .innerJoin(
@@ -27,6 +27,7 @@ module.exports = createTransactionalMigration(
27
27
  const newSettingKeys = ['newsletter_show_header_title', 'newsletter_show_header_icon'];
28
28
  const now = connection.raw('CURRENT_TIMESTAMP');
29
29
 
30
+ // eslint-disable-next-line no-restricted-syntax
30
31
  for (const settingKey of newSettingKeys) {
31
32
  const existingSetting = await connection('settings').where('key', settingKey).first();
32
33
 
@@ -33,6 +33,7 @@ module.exports = createTransactionalMigration(
33
33
  .forUpdate()
34
34
  .select('id');
35
35
 
36
+ // eslint-disable-next-line no-restricted-syntax
36
37
  for (const postIdRow of postIdRows) {
37
38
  const {id} = postIdRow;
38
39
  const [post] = await knex('posts')
@@ -3,6 +3,7 @@ const {createTransactionalMigration} = require('../../utils.js');
3
3
 
4
4
  module.exports = createTransactionalMigration(
5
5
  async function up(knex) {
6
+ // eslint-disable-next-line no-restricted-syntax
6
7
  const compedMemberIds = (await knex('members')
7
8
  .select('members.id')
8
9
  .innerJoin(
@@ -15,6 +15,7 @@ module.exports = createTransactionalMigration(
15
15
  logging.info(`Found ${compedMembers.length} comped members - checking members_status_events`);
16
16
  }
17
17
 
18
+ // eslint-disable-next-line no-restricted-syntax
18
19
  for (const member of compedMembers) {
19
20
  const mostRecentStatusEvent = await knex('members_status_events')
20
21
  .select('*')
@@ -139,7 +139,7 @@ async function hasForeignSQLite({fromTable, fromColumn, toTable, toColumn, trans
139
139
  const client = knex.client.config.client;
140
140
 
141
141
  if (client !== 'sqlite3') {
142
- throw new errors.GhostError({
142
+ throw new errors.InternalServerError({
143
143
  message: tpl(messages.hasForeignSQLite3)
144
144
  });
145
145
  }
@@ -265,7 +265,7 @@ async function hasPrimaryKeySQLite(tableName, transaction) {
265
265
  const client = knex.client.config.client;
266
266
 
267
267
  if (client !== 'sqlite3') {
268
- throw new errors.GhostError({
268
+ throw new errors.InternalServerError({
269
269
  message: tpl(messages.hasPrimaryKeySQLiteError)
270
270
  });
271
271
  }
@@ -107,13 +107,13 @@ class GhostServer {
107
107
  let ghostError;
108
108
 
109
109
  if (error.code === 'EADDRINUSE') {
110
- ghostError = new errors.GhostError({
110
+ ghostError = new errors.InternalServerError({
111
111
  message: tpl(messages.addressInUse.error),
112
112
  context: tpl(messages.addressInUse.context, {port: config.get('server').port}),
113
113
  help: tpl(messages.addressInUse.help)
114
114
  });
115
115
  } else {
116
- ghostError = new errors.GhostError({
116
+ ghostError = new errors.InternalServerError({
117
117
  message: tpl(messages.otherError.error, {errorNumber: error.errno}),
118
118
  context: tpl(messages.otherError.context),
119
119
  help: tpl(messages.otherError.help)
@@ -177,7 +177,7 @@ class ImageSize {
177
177
  context: err.url || imagePath
178
178
  }));
179
179
  }).catch(function (err) {
180
- if (errors.utils.isIgnitionError(err)) {
180
+ if (errors.utils.isGhostError(err)) {
181
181
  return Promise.reject(err);
182
182
  }
183
183
 
@@ -241,7 +241,7 @@ class ImageSize {
241
241
  }
242
242
  }));
243
243
  }).catch((err) => {
244
- if (errors.utils.isIgnitionError(err)) {
244
+ if (errors.utils.isGhostError(err)) {
245
245
  return Promise.reject(err);
246
246
  }
247
247
 
@@ -69,13 +69,13 @@ events.on('settings.timezone.edited', function (settingModel, options) {
69
69
  try {
70
70
  await models.Post.edit(post.toJSON(), _.merge({id: post.id}, options));
71
71
  } catch (err) {
72
- logging.error(new errors.GhostError({
72
+ logging.error(new errors.InternalServerError({
73
73
  err
74
74
  }));
75
75
  }
76
76
  });
77
77
  } catch (err) {
78
- logging.error(new errors.GhostError({
78
+ logging.error(new errors.InternalServerError({
79
79
  err: err,
80
80
  level: 'critical'
81
81
  }));
@@ -9,11 +9,11 @@ const MemberEmailChangeEvent = ghostBookshelf.Model.extend({
9
9
  }
10
10
  }, {
11
11
  async edit() {
12
- throw new errors.IncorrectUsageError('Cannot edit MemberEmailChangeEvent');
12
+ throw new errors.IncorrectUsageError({message: 'Cannot edit MemberEmailChangeEvent'});
13
13
  },
14
14
 
15
15
  async destroy() {
16
- throw new errors.IncorrectUsageError('Cannot destroy MemberEmailChangeEvent');
16
+ throw new errors.IncorrectUsageError({message: 'Cannot destroy MemberEmailChangeEvent'});
17
17
  }
18
18
  });
19
19
 
@@ -9,11 +9,11 @@ const MemberLoginEvent = ghostBookshelf.Model.extend({
9
9
  }
10
10
  }, {
11
11
  async edit() {
12
- throw new errors.IncorrectUsageError('Cannot edit MemberLoginEvent');
12
+ throw new errors.IncorrectUsageError({message: 'Cannot edit MemberLoginEvent'});
13
13
  },
14
14
 
15
15
  async destroy() {
16
- throw new errors.IncorrectUsageError('Cannot destroy MemberLoginEvent');
16
+ throw new errors.IncorrectUsageError({message: 'Cannot destroy MemberLoginEvent'});
17
17
  }
18
18
  });
19
19
 
@@ -11,7 +11,7 @@ const MemberPaidSubscriptionEvent = ghostBookshelf.Model.extend({
11
11
  customQuery(qb, options) {
12
12
  if (options.aggregateMRRDeltas) {
13
13
  if (options.limit || options.filter) {
14
- throw new errors.IncorrectUsageError('aggregateMRRDeltas does not work when passed a filter or limit');
14
+ throw new errors.IncorrectUsageError({message: 'aggregateMRRDeltas does not work when passed a filter or limit'});
15
15
  }
16
16
  const knex = ghostBookshelf.knex;
17
17
  return qb.clear('select')
@@ -33,11 +33,11 @@ const MemberPaidSubscriptionEvent = ghostBookshelf.Model.extend({
33
33
  return options;
34
34
  },
35
35
  async edit() {
36
- throw new errors.IncorrectUsageError('Cannot edit MemberPaidSubscriptionEvent');
36
+ throw new errors.IncorrectUsageError({message: 'Cannot edit MemberPaidSubscriptionEvent'});
37
37
  },
38
38
 
39
39
  async destroy() {
40
- throw new errors.IncorrectUsageError('Cannot destroy MemberPaidSubscriptionEvent');
40
+ throw new errors.IncorrectUsageError({message: 'Cannot destroy MemberPaidSubscriptionEvent'});
41
41
  }
42
42
  });
43
43
 
@@ -11,7 +11,7 @@ const MemberPaymentEvent = ghostBookshelf.Model.extend({
11
11
  customQuery(qb, options) {
12
12
  if (options.aggregatePaymentVolume) {
13
13
  if (options.limit || options.filter) {
14
- throw new errors.IncorrectUsageError('aggregatePaymentVolume does not work when passed a filter or limit');
14
+ throw new errors.IncorrectUsageError({message: 'aggregatePaymentVolume does not work when passed a filter or limit'});
15
15
  }
16
16
  const knex = ghostBookshelf.knex;
17
17
  return qb.clear('select')
@@ -33,11 +33,11 @@ const MemberPaymentEvent = ghostBookshelf.Model.extend({
33
33
  return options;
34
34
  },
35
35
  async edit() {
36
- throw new errors.IncorrectUsageError('Cannot edit MemberPaymentEvent');
36
+ throw new errors.IncorrectUsageError({message: 'Cannot edit MemberPaymentEvent'});
37
37
  },
38
38
 
39
39
  async destroy() {
40
- throw new errors.IncorrectUsageError('Cannot destroy MemberPaymentEvent');
40
+ throw new errors.IncorrectUsageError({message: 'Cannot destroy MemberPaymentEvent'});
41
41
  }
42
42
  });
43
43
 
@@ -19,15 +19,15 @@ const MemberProductEvent = ghostBookshelf.Model.extend({
19
19
 
20
20
  }, {
21
21
  async edit() {
22
- throw new errors.IncorrectUsageError(
23
- tpl(messages.cannotPerformAction, 'edit')
24
- );
22
+ throw new errors.IncorrectUsageError({
23
+ message: tpl(messages.cannotPerformAction, 'edit')
24
+ });
25
25
  },
26
26
 
27
27
  async destroy() {
28
- throw new errors.IncorrectUsageError(
29
- tpl(messages.cannotPerformAction, 'destroy')
30
- );
28
+ throw new errors.IncorrectUsageError({
29
+ message: tpl(messages.cannotPerformAction, 'destroy')
30
+ });
31
31
  }
32
32
  });
33
33