ghost 4.22.3 → 4.25.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 (230) hide show
  1. package/.c8rc.json +24 -0
  2. package/.eslintrc.js +39 -0
  3. package/Gruntfile.js +0 -1
  4. package/content/public/README.md +3 -0
  5. package/content/themes/casper/assets/built/casper.js +1 -1
  6. package/content/themes/casper/assets/built/casper.js.map +1 -1
  7. package/content/themes/casper/assets/built/global.css +1 -1
  8. package/content/themes/casper/assets/built/global.css.map +1 -1
  9. package/content/themes/casper/assets/built/screen.css +1 -1
  10. package/content/themes/casper/assets/built/screen.css.map +1 -1
  11. package/content/themes/casper/assets/css/global.css +6 -1
  12. package/content/themes/casper/assets/css/screen.css +32 -216
  13. package/content/themes/casper/default.hbs +2 -2
  14. package/content/themes/casper/package.json +3 -2
  15. package/content/themes/casper/post.hbs +1 -1
  16. package/content/themes/casper/yarn.lock +173 -123
  17. package/core/app.js +12 -1
  18. package/core/boot.js +47 -28
  19. package/core/bridge.js +10 -10
  20. package/core/built/assets/{chunk.3.324fd0cc598c73650219.js → chunk.3.8f95b516d88ff4eec64c.js} +18 -18
  21. package/core/built/assets/ghost-dark-d690e732e17ffc794e2e59c1467ca282.css +1 -0
  22. package/core/built/assets/ghost.min-043bb7480a0810109b130f13b2a4235e.css +1 -0
  23. package/core/built/assets/{ghost.min-7da921f6c6cac3fe10da1ba104575440.js → ghost.min-bc72f685c1c9adc9885925c1412435a5.js} +563 -605
  24. package/core/built/assets/icons/audio-upload.svg +8 -0
  25. package/core/built/assets/icons/powered-by-tenor.svg +35 -0
  26. package/core/built/assets/icons/tenor.svg +7 -0
  27. package/core/built/assets/{vendor.min-413f887176a041e6dbf88214ca9a7481.js → vendor.min-d1234c632a54502777c34e50752fa3fc.js} +4622 -3631
  28. package/core/frontend/apps/amp/lib/helpers/amp_content.js +2 -2
  29. package/core/frontend/apps/amp/lib/views/amp.hbs +112 -0
  30. package/core/frontend/apps/private-blogging/index.js +1 -1
  31. package/core/frontend/apps/private-blogging/lib/router.js +1 -1
  32. package/core/frontend/services/apps/index.js +1 -1
  33. package/core/frontend/services/apps/loader.js +3 -3
  34. package/core/frontend/services/card-assets/index.js +0 -12
  35. package/core/frontend/services/card-assets/service.js +29 -28
  36. package/core/frontend/services/helpers/handlebars.js +1 -1
  37. package/core/frontend/services/routing/CollectionRouter.js +4 -5
  38. package/core/frontend/services/routing/EmailRouter.js +1 -1
  39. package/core/frontend/services/routing/ParentRouter.js +0 -8
  40. package/core/frontend/services/routing/PreviewRouter.js +1 -1
  41. package/core/frontend/services/routing/StaticPagesRouter.js +1 -1
  42. package/core/frontend/services/routing/StaticRoutesRouter.js +4 -4
  43. package/core/frontend/services/routing/TaxonomyRouter.js +3 -3
  44. package/core/frontend/services/routing/{middlewares → middleware}/index.js +0 -0
  45. package/core/frontend/services/routing/{middlewares → middleware}/page-param.js +0 -0
  46. package/core/frontend/services/routing/router-manager.js +7 -2
  47. package/core/frontend/services/rss/generate-feed.js +2 -1
  48. package/core/frontend/services/theme-engine/middleware/ensure-active-theme.js +34 -0
  49. package/core/frontend/services/theme-engine/middleware/index.js +6 -0
  50. package/core/frontend/services/theme-engine/middleware/update-global-template-options.js +116 -0
  51. package/core/frontend/services/theme-engine/middleware/update-local-template-data.js +9 -0
  52. package/core/frontend/services/theme-engine/middleware/update-local-template-options.js +57 -0
  53. package/core/frontend/src/cards/css/bookmark.css +72 -47
  54. package/core/frontend/src/cards/css/button.css +4 -0
  55. package/core/frontend/src/cards/css/callout.css +40 -3
  56. package/core/frontend/src/cards/css/gallery.css +15 -10
  57. package/core/frontend/src/cards/css/nft.css +20 -11
  58. package/core/frontend/src/cards/css/toggle.css +58 -0
  59. package/core/frontend/src/cards/js/toggle.js +16 -0
  60. package/core/frontend/web/middleware/error-handler.js +93 -0
  61. package/core/frontend/web/middleware/handle-image-sizes.js +3 -6
  62. package/core/frontend/web/middleware/index.js +1 -0
  63. package/core/frontend/web/middleware/serve-public-file.js +39 -16
  64. package/core/frontend/web/site.js +11 -14
  65. package/core/server/adapters/scheduling/SchedulingDefault.js +2 -2
  66. package/core/server/adapters/storage/LocalStorageBase.js +2 -2
  67. package/core/server/api/canary/authentication.js +1 -1
  68. package/core/server/api/canary/db.js +2 -2
  69. package/core/server/api/canary/media.js +3 -2
  70. package/core/server/api/canary/oembed.js +16 -1
  71. package/core/server/api/canary/session.js +1 -1
  72. package/core/server/api/canary/slugs.js +1 -1
  73. package/core/server/api/canary/utils/permissions.js +2 -2
  74. package/core/server/api/canary/utils/serializers/output/config.js +2 -6
  75. package/core/server/api/v2/authentication.js +1 -1
  76. package/core/server/api/v2/db.js +2 -2
  77. package/core/server/api/v2/session.js +1 -1
  78. package/core/server/api/v2/slugs.js +1 -1
  79. package/core/server/api/v2/utils/permissions.js +2 -2
  80. package/core/server/api/v3/authentication.js +1 -1
  81. package/core/server/api/v3/db.js +2 -2
  82. package/core/server/api/v3/session.js +1 -1
  83. package/core/server/api/v3/slugs.js +1 -1
  84. package/core/server/api/v3/utils/permissions.js +2 -2
  85. package/core/server/data/db/connection.js +7 -0
  86. package/core/server/data/db/state-manager.js +4 -4
  87. package/core/server/data/exporter/export-filename.js +1 -1
  88. package/core/server/data/importer/handlers/json.js +1 -1
  89. package/core/server/data/importer/import-manager.js +1 -1
  90. package/core/server/data/importer/importers/data/base.js +1 -1
  91. package/core/server/data/importer/importers/data/data-importer.js +3 -3
  92. package/core/server/data/migrations/init/2-create-fixtures.js +3 -20
  93. package/core/server/data/migrations/utils.js +2 -2
  94. package/core/server/data/migrations/versions/1.21/1-add-contributor-role.js +5 -5
  95. package/core/server/data/migrations/versions/1.25/1-update-koenig-beta-html.js +1 -0
  96. package/core/server/data/migrations/versions/2.15/2-insert-zapier-integration.js +3 -3
  97. package/core/server/data/migrations/versions/2.2/3-insert-admin-integration-role.js +5 -5
  98. package/core/server/data/migrations/versions/2.27/1-insert-ghost-db-backup-role.js +5 -6
  99. package/core/server/data/migrations/versions/2.27/2-insert-db-backup-integration.js +3 -4
  100. package/core/server/data/migrations/versions/2.28/3-insert-ghost-scheduler-role.js +7 -7
  101. package/core/server/data/migrations/versions/2.28/4-insert-scheduler-integration.js +3 -3
  102. package/core/server/data/migrations/versions/3.1/08-add-uuid-values-to-members.js +1 -0
  103. package/core/server/data/migrations/versions/3.22/02-settings-key-renames.js +2 -0
  104. package/core/server/data/migrations/versions/3.22/05-migrate-members-subscription-settings.js +3 -0
  105. package/core/server/data/migrations/versions/3.22/06-migrate-stripe-connect-settings.js +2 -0
  106. package/core/server/data/migrations/versions/3.23/01-migrate-bulk-email-settings.js +1 -0
  107. package/core/server/data/migrations/versions/3.29/01-remove-duplicate-subscriptions.js +2 -0
  108. package/core/server/data/migrations/versions/3.29/02-remove-duplicate-customers.js +2 -0
  109. package/core/server/data/migrations/versions/3.38/04-populate-recipient-filter-column.js +2 -0
  110. package/core/server/data/migrations/versions/4.0/01-update-mobiledoc.js +2 -0
  111. package/core/server/data/migrations/versions/4.0/03-populate-status-column-for-members.js +4 -0
  112. package/core/server/data/migrations/versions/4.0/06-populate-members-subscribe-events-table.js +1 -0
  113. package/core/server/data/migrations/versions/4.0/17-populate-members-status-events-table.js +1 -0
  114. package/core/server/data/migrations/versions/4.0/18-transform-urls-absolute-to-transform-ready.js +5 -0
  115. package/core/server/data/migrations/versions/4.0/22-solve-orphaned-webhooks.js +1 -0
  116. package/core/server/data/migrations/versions/4.0/23-regenerate-posts-html.js +1 -0
  117. package/core/server/data/migrations/versions/4.0/25-populate-members-paid-subscription-events-table.js +2 -1
  118. package/core/server/data/migrations/versions/4.12/02-fix-member-statuses.js +1 -0
  119. package/core/server/data/migrations/versions/4.14/01-fix-comped-member-statuses.js +3 -0
  120. package/core/server/data/migrations/versions/4.14/02-fix-free-members-status-events.js +1 -0
  121. package/core/server/data/migrations/versions/4.20/05-remove-not-null-constraint-from-portal-title.js +2 -0
  122. package/core/server/data/migrations/versions/4.23/01-truncate-offer-names.js +59 -0
  123. package/core/server/data/migrations/versions/4.3/04-attach-members-to-product.js +1 -0
  124. package/core/server/data/migrations/versions/4.4/01-restore-free-members-signup-setting-from-backup.js +1 -0
  125. package/core/server/data/migrations/versions/4.6/01-remove-comped-status.js +1 -0
  126. package/core/server/data/migrations/versions/4.8/04-migrate-show-newsletter-header-setting.js +1 -0
  127. package/core/server/data/migrations/versions/4.9/05-fix-missed-mobiledoc-url-transforms.js +1 -0
  128. package/core/server/data/migrations/versions/4.9/06-add-comped-status.js +1 -0
  129. package/core/server/data/migrations/versions/4.9/07-update-comped-members-status-events.js +1 -0
  130. package/core/server/data/schema/commands.js +2 -2
  131. package/core/server/data/schema/fixtures/fixture-manager.js +340 -0
  132. package/core/server/data/schema/fixtures/index.js +8 -2
  133. package/core/server/ghost-server.js +2 -2
  134. package/core/server/lib/image/image-size.js +2 -2
  135. package/core/server/models/base/listeners.js +2 -2
  136. package/core/server/models/member-email-change-event.js +2 -2
  137. package/core/server/models/member-login-event.js +2 -2
  138. package/core/server/models/member-paid-subscription-event.js +3 -3
  139. package/core/server/models/member-payment-event.js +3 -3
  140. package/core/server/models/member-product-event.js +6 -6
  141. package/core/server/models/member-status-event.js +5 -3
  142. package/core/server/models/member-subscribe-event.js +9 -3
  143. package/core/server/models/relations/authors.js +1 -1
  144. package/core/server/models/settings.js +1 -1
  145. package/core/server/services/auth/passwordreset.js +1 -1
  146. package/core/server/services/auth/setup.js +1 -1
  147. package/core/server/services/email-analytics/jobs/index.js +1 -1
  148. package/core/server/services/mega/mega.js +6 -4
  149. package/core/server/services/mega/post-email-serializer.js +5 -1
  150. package/core/server/services/mega/segment-parser.js +1 -2
  151. package/core/server/services/mega/template.js +52 -37
  152. package/core/server/services/members/api.js +22 -0
  153. package/core/server/services/members/config.js +1 -1
  154. package/core/server/services/members/emails/signup-paid.js +168 -0
  155. package/core/server/services/members/service.js +6 -2
  156. package/core/server/services/members/stripe-connect.js +4 -2
  157. package/core/server/services/nft-oembed.js +13 -22
  158. package/core/server/services/oembed.js +28 -24
  159. package/core/server/services/permissions/can-this.js +1 -1
  160. package/core/server/services/public-config/config.js +1 -1
  161. package/core/server/services/redirects/api.js +20 -25
  162. package/core/server/services/redirects/index.js +18 -10
  163. package/core/server/services/redirects/utils.js +14 -0
  164. package/core/server/services/redirects/validation.js +10 -0
  165. package/core/server/services/route-settings/default-settings-manager.js +1 -1
  166. package/core/server/services/route-settings/index.js +40 -17
  167. package/core/server/services/route-settings/route-settings.js +120 -115
  168. package/core/server/services/route-settings/settings-loader.js +18 -36
  169. package/core/server/services/route-settings/yaml-parser.js +1 -1
  170. package/core/server/services/slack.js +1 -1
  171. package/core/server/services/themes/activation-bridge.js +3 -3
  172. package/core/server/services/themes/storage.js +2 -2
  173. package/core/server/services/twitter-embed.js +80 -0
  174. package/core/server/services/url/LocalFileCache.js +75 -0
  175. package/core/server/services/url/Resources.js +8 -2
  176. package/core/server/services/url/UrlGenerator.js +23 -20
  177. package/core/server/services/url/UrlService.js +75 -63
  178. package/core/server/services/url/index.js +17 -3
  179. package/core/server/services/xmlrpc.js +2 -2
  180. package/core/server/web/admin/app.js +7 -10
  181. package/core/server/web/admin/controller.js +35 -12
  182. package/core/server/web/admin/middleware/redirect-admin-urls.js +15 -0
  183. package/core/server/web/admin/views/default-prod.html +4 -4
  184. package/core/server/web/admin/views/default.html +4 -4
  185. package/core/server/web/api/app.js +1 -1
  186. package/core/server/web/api/canary/admin/app.js +3 -6
  187. package/core/server/web/api/canary/admin/middleware.js +7 -7
  188. package/core/server/web/api/canary/admin/routes.js +5 -5
  189. package/core/server/web/api/canary/content/app.js +3 -6
  190. package/core/server/web/api/canary/content/middleware.js +3 -3
  191. package/core/server/web/api/v2/admin/app.js +3 -6
  192. package/core/server/web/api/v2/admin/middleware.js +7 -7
  193. package/core/server/web/api/v2/admin/routes.js +5 -5
  194. package/core/server/web/api/v2/content/app.js +3 -6
  195. package/core/server/web/api/v2/content/middleware.js +3 -3
  196. package/core/server/web/api/v3/admin/app.js +3 -6
  197. package/core/server/web/api/v3/admin/middleware.js +7 -7
  198. package/core/server/web/api/v3/admin/routes.js +5 -5
  199. package/core/server/web/api/v3/content/app.js +3 -6
  200. package/core/server/web/api/v3/content/middleware.js +3 -3
  201. package/core/server/web/members/app.js +6 -9
  202. package/core/server/web/oauth/app.js +0 -4
  203. package/core/server/web/parent/app.js +17 -9
  204. package/core/server/web/parent/frontend.js +1 -1
  205. package/core/server/web/shared/index.js +2 -2
  206. package/core/server/web/shared/{middlewares → middleware}/api/index.js +0 -0
  207. package/core/server/web/shared/{middlewares → middleware}/api/spam-prevention.js +0 -0
  208. package/core/server/web/shared/{middlewares → middleware}/brute.js +0 -0
  209. package/core/server/web/shared/{middlewares → middleware}/cache-control.js +0 -0
  210. package/core/server/web/shared/middleware/error-handler.js +224 -0
  211. package/core/server/web/shared/{middlewares → middleware}/index.js +0 -4
  212. package/core/server/web/shared/{middlewares → middleware}/pretty-urls.js +0 -0
  213. package/core/server/web/shared/{middlewares → middleware}/uncapitalise.js +0 -0
  214. package/core/server/web/shared/{middlewares → middleware}/url-redirects.js +0 -0
  215. package/core/shared/config/defaults.json +13 -1
  216. package/core/shared/config/helpers.js +42 -0
  217. package/core/shared/config/loader.js +1 -1
  218. package/core/shared/labs.js +9 -5
  219. package/core/shared/sentry.js +1 -1
  220. package/loggingrc.js +19 -20
  221. package/package.json +38 -37
  222. package/yarn.lock +1064 -892
  223. package/content/themes/casper/assets/js/gallery-card.js +0 -24
  224. package/core/built/assets/ghost-dark-39fb496d051565531062d7e047d1c0b1.css +0 -1
  225. package/core/built/assets/ghost.min-4207edfc1ae0a3f9f6505ca00d20b0c0.css +0 -1
  226. package/core/frontend/services/theme-engine/middleware.js +0 -209
  227. package/core/server/data/schema/fixtures/utils.js +0 -321
  228. package/core/server/web/parent/vhost-utils.js +0 -39
  229. package/core/server/web/shared/middlewares/error-handler.js +0 -329
  230. package/core/server/web/shared/middlewares/maintenance.js +0 -25
@@ -45,6 +45,7 @@ module.exports.up = function regenerateKoenigBetaHTML(options) {
45
45
  || (mobiledoc && !mobiledocIsCompatibleWithV1(mobiledoc))
46
46
  ) {
47
47
  // change imagecard.payload.imageStyle to imagecard.payload.cardWidth
48
+ // eslint-disable-next-line no-restricted-syntax
48
49
  mobiledoc.cards.forEach((card) => {
49
50
  if (card[0] === 'image') {
50
51
  card[1].cardWidth = card[1].imageStyle;
@@ -1,7 +1,7 @@
1
1
  const logging = require('@tryghost/logging');
2
2
  const merge = require('lodash/merge');
3
3
  const models = require('../../../../models');
4
- const utils = require('../../../schema/fixtures/utils');
4
+ const {fixtureManager} = require('../../../schema/fixtures');
5
5
 
6
6
  const _private = {};
7
7
 
@@ -15,12 +15,12 @@ _private.printResult = function printResult(result, message) {
15
15
 
16
16
  _private.addZapierIntegration = (options) => {
17
17
  const message = 'Adding "Zapier" integration';
18
- const fixtureIntegration = utils.findModelFixtureEntry('Integration', {slug: 'zapier'});
18
+ const fixtureIntegration = fixtureManager.findModelFixtureEntry('Integration', {slug: 'zapier'});
19
19
 
20
20
  return models.Integration.findOne({slug: fixtureIntegration.slug}, options)
21
21
  .then((integration) => {
22
22
  if (!integration) {
23
- return utils.addFixturesForModel({
23
+ return fixtureManager.addFixturesForModel({
24
24
  name: 'Integration',
25
25
  entries: [fixtureIntegration]
26
26
  }, options).then(result => _private.printResult(result, message));
@@ -1,7 +1,7 @@
1
1
  const logging = require('@tryghost/logging');
2
2
  const merge = require('lodash/merge');
3
3
  const models = require('../../../../models');
4
- const utils = require('../../../schema/fixtures/utils');
4
+ const {fixtureManager} = require('../../../schema/fixtures');
5
5
 
6
6
  const _private = {};
7
7
 
@@ -15,12 +15,12 @@ _private.printResult = function printResult(result, message) {
15
15
 
16
16
  _private.addApiKeyRole = (options) => {
17
17
  const message = 'Adding "Admin Integration" role to roles table';
18
- const apiKeyRole = utils.findModelFixtureEntry('Role', {name: 'Admin Integration'});
18
+ const apiKeyRole = fixtureManager.findModelFixtureEntry('Role', {name: 'Admin Integration'});
19
19
 
20
20
  return models.Role.findOne({name: apiKeyRole.name}, options)
21
21
  .then((role) => {
22
22
  if (!role) {
23
- return utils.addFixturesForModel({
23
+ return fixtureManager.addFixturesForModel({
24
24
  name: 'Role',
25
25
  entries: [apiKeyRole]
26
26
  }, options).then(result => _private.printResult(result, message));
@@ -32,9 +32,9 @@ _private.addApiKeyRole = (options) => {
32
32
 
33
33
  _private.addApiKeyPermissions = (options) => {
34
34
  const message = 'Adding permissions for the "Admin Integration" role';
35
- const relations = utils.findRelationFixture('Role', 'Permission');
35
+ const relations = fixtureManager.findRelationFixture('Role', 'Permission');
36
36
 
37
- return utils.addFixturesForRelation({
37
+ return fixtureManager.addFixturesForRelation({
38
38
  from: relations.from,
39
39
  to: relations.to,
40
40
  entries: {
@@ -1,7 +1,7 @@
1
1
  const logging = require('@tryghost/logging');
2
2
  const merge = require('lodash/merge');
3
3
  const models = require('../../../../models');
4
- const utils = require('../../../schema/fixtures/utils');
4
+ const {fixtureManager} = require('../../../schema/fixtures');
5
5
 
6
6
  const _private = {};
7
7
 
@@ -15,12 +15,12 @@ _private.printResult = function printResult(result, message) {
15
15
 
16
16
  _private.addApiKeyRole = (options) => {
17
17
  const message = 'Adding "DB Backup Integration" role to roles table';
18
- const apiKeyRole = utils.findModelFixtureEntry('Role', {name: 'DB Backup Integration'});
18
+ const apiKeyRole = fixtureManager.findModelFixtureEntry('Role', {name: 'DB Backup Integration'});
19
19
 
20
20
  return models.Role.findOne({name: apiKeyRole.name}, options)
21
21
  .then((role) => {
22
22
  if (!role) {
23
- return utils.addFixturesForModel({
23
+ return fixtureManager.addFixturesForModel({
24
24
  name: 'Role',
25
25
  entries: [apiKeyRole]
26
26
  }, options).then(result => _private.printResult(result, message));
@@ -32,9 +32,9 @@ _private.addApiKeyRole = (options) => {
32
32
 
33
33
  _private.addApiKeyPermissions = (options) => {
34
34
  const message = 'Adding permissions for the "DB Backup Integration" role';
35
- const relations = utils.findRelationFixture('Role', 'Permission');
35
+ const relations = fixtureManager.findRelationFixture('Role', 'Permission');
36
36
 
37
- return utils.addFixturesForRelation({
37
+ return fixtureManager.addFixturesForRelation({
38
38
  from: relations.from,
39
39
  to: relations.to,
40
40
  entries: {
@@ -81,4 +81,3 @@ module.exports.down = (options) => {
81
81
 
82
82
  return _private.removeApiKeyPermissionsAndRole(localOptions);
83
83
  };
84
-
@@ -1,7 +1,7 @@
1
1
  const logging = require('@tryghost/logging');
2
2
  const merge = require('lodash/merge');
3
3
  const models = require('../../../../models');
4
- const utils = require('../../../schema/fixtures/utils');
4
+ const {fixtureManager} = require('../../../schema/fixtures');
5
5
 
6
6
  const _private = {};
7
7
 
@@ -15,12 +15,12 @@ _private.printResult = function printResult(result, message) {
15
15
 
16
16
  _private.addGhostBackupIntegration = (options) => {
17
17
  const message = 'Adding "Ghost Backup DB" integration';
18
- const fixtureIntegration = utils.findModelFixtureEntry('Integration', {slug: 'ghost-backup'});
18
+ const fixtureIntegration = fixtureManager.findModelFixtureEntry('Integration', {slug: 'ghost-backup'});
19
19
 
20
20
  return models.Integration.findOne({slug: fixtureIntegration.slug}, options)
21
21
  .then((integration) => {
22
22
  if (!integration) {
23
- return utils.addFixturesForModel({
23
+ return fixtureManager.addFixturesForModel({
24
24
  name: 'Integration',
25
25
  entries: [fixtureIntegration]
26
26
  }, options).then(result => _private.printResult(result, message));
@@ -67,4 +67,3 @@ module.exports.down = (options) => {
67
67
 
68
68
  return _private.removeGhostBackupIntegration(localOptions);
69
69
  };
70
-
@@ -1,7 +1,7 @@
1
1
  const logging = require('@tryghost/logging');
2
2
  const merge = require('lodash/merge');
3
3
  const models = require('../../../../models');
4
- const utils = require('../../../schema/fixtures/utils');
4
+ const {fixtureManager} = require('../../../schema/fixtures');
5
5
 
6
6
  const resource = 'post';
7
7
  const _private = {};
@@ -16,12 +16,12 @@ _private.printResult = function printResult(result, message) {
16
16
 
17
17
  _private.addSchedulerRole = (options) => {
18
18
  const message = 'Adding "Scheduler Integration" role to roles table';
19
- const apiKeyRole = utils.findModelFixtureEntry('Role', {name: 'Scheduler Integration'});
19
+ const apiKeyRole = fixtureManager.findModelFixtureEntry('Role', {name: 'Scheduler Integration'});
20
20
 
21
21
  return models.Role.findOne({name: apiKeyRole.name}, options)
22
22
  .then((role) => {
23
23
  if (!role) {
24
- return utils.addFixturesForModel({
24
+ return fixtureManager.addFixturesForModel({
25
25
  name: 'Role',
26
26
  entries: [apiKeyRole]
27
27
  }, options).then(result => _private.printResult(result, message));
@@ -32,19 +32,19 @@ _private.addSchedulerRole = (options) => {
32
32
  };
33
33
 
34
34
  _private.addPublishPermission = (options) => {
35
- const modelToAdd = utils.findModelFixtures('Permission', {object_type: resource, action_type: 'publish'});
35
+ const modelToAdd = fixtureManager.findModelFixtures('Permission', {object_type: resource, action_type: 'publish'});
36
36
 
37
- return utils.addFixturesForModel(modelToAdd, options)
37
+ return fixtureManager.addFixturesForModel(modelToAdd, options)
38
38
  .then(result => _private.printResult(result, `Adding "publish" permissions fixtures for ${resource}s`));
39
39
  };
40
40
 
41
41
  _private.removeApiKeyPermissionsAndRole = (options) => {
42
42
  const message = 'Rollback: Removing "Scheduler Integration" role and permissions';
43
43
 
44
- const modelToRemove = utils.findModelFixtures('Permission', {object_type: resource, action_type: 'publish'});
44
+ const modelToRemove = fixtureManager.findModelFixtures('Permission', {object_type: resource, action_type: 'publish'});
45
45
 
46
46
  // permission model automatically cleans up permissions_roles on .destroy()
47
- return utils.removeFixturesForModel(modelToRemove, options)
47
+ return fixtureManager.removeFixturesForModel(modelToRemove, options)
48
48
  .then(result => _private.printResult(result, `Removing "publish" permissions fixtures for ${resource}s`))
49
49
  .then(() => models.Role.findOne({name: 'Scheduler Integration'}, options))
50
50
  .then((role) => {
@@ -1,7 +1,7 @@
1
1
  const logging = require('@tryghost/logging');
2
2
  const merge = require('lodash/merge');
3
3
  const models = require('../../../../models');
4
- const utils = require('../../../schema/fixtures/utils');
4
+ const {fixtureManager} = require('../../../schema/fixtures');
5
5
 
6
6
  const _private = {};
7
7
 
@@ -15,12 +15,12 @@ _private.printResult = function printResult(result, message) {
15
15
 
16
16
  _private.addGhostSchedulerIntegration = (options) => {
17
17
  const message = 'Adding "Ghost Scheduler" integration';
18
- const fixtureIntegration = utils.findModelFixtureEntry('Integration', {slug: 'ghost-scheduler'});
18
+ const fixtureIntegration = fixtureManager.findModelFixtureEntry('Integration', {slug: 'ghost-scheduler'});
19
19
 
20
20
  return models.Integration.findOne({slug: fixtureIntegration.slug}, options)
21
21
  .then((integration) => {
22
22
  if (!integration) {
23
- return utils.addFixturesForModel({
23
+ return fixtureManager.addFixturesForModel({
24
24
  name: 'Integration',
25
25
  entries: [fixtureIntegration]
26
26
  }, options).then(result => _private.printResult(result, message));
@@ -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')