ghost 4.37.0 → 4.38.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 (81) hide show
  1. package/content/themes/casper/LICENSE +1 -1
  2. package/content/themes/casper/README.md +1 -1
  3. package/content/themes/casper/assets/built/global.css +1 -1
  4. package/content/themes/casper/assets/built/global.css.map +1 -1
  5. package/content/themes/casper/assets/built/screen.css +1 -1
  6. package/content/themes/casper/assets/built/screen.css.map +1 -1
  7. package/content/themes/casper/assets/css/global.css +14 -6
  8. package/content/themes/casper/assets/css/screen.css +9 -1
  9. package/content/themes/casper/package.json +2 -2
  10. package/content/themes/casper/partials/post-card.hbs +1 -1
  11. package/content/themes/casper/post.hbs +18 -19
  12. package/content/themes/casper/yarn.lock +186 -217
  13. package/core/built/assets/ghost-dark-9f760f16230b8bc52e188d6ce28516b0.css +1 -0
  14. package/core/built/assets/{ghost.min-c1938f6ee696bf08bd6bf93cac341ea2.js → ghost.min-6386b02480494a69c3bfe66206754836.js} +339 -279
  15. package/core/built/assets/ghost.min-f4c59dd57a2136df8b0a34f87c099034.css +1 -0
  16. package/core/built/assets/icons/eye.svg +4 -1
  17. package/core/built/assets/icons/member-add.svg +3 -0
  18. package/core/built/assets/icons/pin.svg +4 -1
  19. package/core/built/assets/{vendor.min-6dc30be68238b5c55df0cdc1f2dc8b8d.js → vendor.min-c814d3c4b3f543c4cd5ef3aacd0fc645.js} +36 -34
  20. package/core/frontend/helpers/get.js +4 -0
  21. package/core/frontend/helpers/match.js +12 -0
  22. package/core/frontend/helpers/prev_post.js +11 -1
  23. package/core/frontend/helpers/tiers.js +59 -0
  24. package/core/frontend/helpers/tpl/content-cta.hbs +1 -1
  25. package/core/frontend/services/routing/router-manager.js +1 -1
  26. package/core/frontend/web/site.js +10 -0
  27. package/core/server/api/canary/index.js +4 -0
  28. package/core/server/api/canary/members.js +2 -1
  29. package/core/server/api/canary/products.js +3 -6
  30. package/core/server/api/canary/tiers-public.js +34 -0
  31. package/core/server/api/canary/tiers.js +3 -6
  32. package/core/server/api/canary/utils/serializers/output/email-posts.js +7 -1
  33. package/core/server/api/canary/utils/serializers/output/pages.js +9 -2
  34. package/core/server/api/canary/utils/serializers/output/posts.js +8 -2
  35. package/core/server/api/canary/utils/serializers/output/preview.js +7 -1
  36. package/core/server/api/canary/utils/serializers/output/products.js +3 -1
  37. package/core/server/api/canary/utils/serializers/output/tiers.js +4 -2
  38. package/core/server/api/canary/utils/serializers/output/utils/mapper.js +17 -7
  39. package/core/server/data/db/connection.js +3 -2
  40. package/core/server/data/migrations/versions/3.29/01-remove-duplicate-subscriptions.js +2 -1
  41. package/core/server/data/migrations/versions/3.29/02-remove-duplicate-customers.js +2 -1
  42. package/core/server/data/migrations/versions/3.29/03-remove-orphaned-customers.js +2 -1
  43. package/core/server/data/migrations/versions/3.29/04-remove-orphaned-subscriptions.js +2 -1
  44. package/core/server/data/migrations/versions/3.29/05-add-member-constraints.js +3 -2
  45. package/core/server/data/migrations/versions/3.39/06-add-email-recipient-index.js +4 -3
  46. package/core/server/data/migrations/versions/4.0/14-remove-orphaned-stripe-records.js +2 -1
  47. package/core/server/data/migrations/versions/4.0/26-add-cascade-on-delete.js +2 -1
  48. package/core/server/data/migrations/versions/4.0/29-fix-foreign-key-for-members-stripe-customers-subscriptions.js +2 -1
  49. package/core/server/data/migrations/versions/4.1/02-add-unique-constraint-for-member-stripe-tables.js +2 -1
  50. package/core/server/data/migrations/versions/4.20/05-remove-not-null-constraint-from-portal-title.js +3 -2
  51. package/core/server/data/migrations/versions/4.33/2022-01-18-09-07-remove-duplicate-offer-redemptions.js +2 -2
  52. package/core/server/data/migrations/versions/4.35/2022-02-01-11-48-update-email-recipient-filter-column-type.js +2 -1
  53. package/core/server/data/migrations/versions/4.35/2022-02-01-12-03-update-recipient-filter-column-type.js +2 -1
  54. package/core/server/data/migrations/versions/4.37/2022-02-21-09-53-backfill-members-last-seen-at-column.js +3 -2
  55. package/core/server/data/migrations/versions/4.38/2022-03-01-08-46-add-visibility-to-tiers.js +11 -0
  56. package/core/server/data/migrations/versions/4.38/2022-03-03-16-12-add-visibility-to-tiers.js +8 -0
  57. package/core/server/data/migrations/versions/4.38/2022-03-03-16-17-drop-tiers-visible-column.js +7 -0
  58. package/core/server/data/schema/clients/index.js +1 -1
  59. package/core/server/data/schema/clients/mysql.js +4 -4
  60. package/core/server/data/schema/commands.js +42 -50
  61. package/core/server/data/schema/fixtures/fixtures.json +4 -2
  62. package/core/server/data/schema/schema.js +7 -0
  63. package/core/server/models/product.js +2 -1
  64. package/core/server/services/auth/api-key/admin.js +15 -6
  65. package/core/server/services/auth/setup.js +5 -0
  66. package/core/server/services/email-analytics/lib/event-processor.js +18 -1
  67. package/core/server/services/members/middleware.js +3 -0
  68. package/core/server/services/members/service.js +13 -1
  69. package/core/server/web/admin/views/default-prod.html +4 -4
  70. package/core/server/web/admin/views/default.html +4 -4
  71. package/core/server/web/api/app.js +3 -0
  72. package/core/server/web/api/canary/admin/middleware.js +2 -0
  73. package/core/server/web/api/canary/content/routes.js +1 -0
  74. package/core/server/web/members/app.js +1 -1
  75. package/core/shared/config/defaults.json +2 -2
  76. package/core/shared/config/utils.js +5 -1
  77. package/core/shared/labs.js +1 -0
  78. package/package.json +47 -44
  79. package/yarn.lock +606 -574
  80. package/core/built/assets/ghost-dark-d54723f7267e66fa2595f897076e86c2.css +0 -1
  81. package/core/built/assets/ghost.min-02a5f8954bd85fe28817b8c8b111b8aa.css +0 -1
@@ -1,5 +1,6 @@
1
1
  const debug = require('@tryghost/debug')('api:canary:utils:serializers:output:pages');
2
2
  const mapper = require('./utils/mapper');
3
+ const membersService = require('../../../../../services/members');
3
4
 
4
5
  module.exports = {
5
6
  async all(models, apiConfig, frame) {
@@ -10,9 +11,15 @@ module.exports = {
10
11
  return;
11
12
  }
12
13
  let pages = [];
14
+
15
+ const tiersModels = await membersService.api.productRepository.list({
16
+ withRelated: ['monthlyPrice', 'yearlyPrice']
17
+ });
18
+ const tiers = tiersModels.data ? tiersModels.data.map(tierModel => tierModel.toJSON()) : [];
19
+
13
20
  if (models.meta) {
14
21
  for (let model of models.data) {
15
- let page = await mapper.mapPage(model, frame);
22
+ let page = await mapper.mapPage(model, frame, {tiers});
16
23
  pages.push(page);
17
24
  }
18
25
  frame.response = {
@@ -22,7 +29,7 @@ module.exports = {
22
29
 
23
30
  return;
24
31
  }
25
- let page = await mapper.mapPage(models, frame);
32
+ let page = await mapper.mapPage(models, frame, {tiers});
26
33
  frame.response = {
27
34
  pages: [page]
28
35
  };
@@ -1,5 +1,6 @@
1
1
  const debug = require('@tryghost/debug')('api:canary:utils:serializers:output:posts');
2
2
  const mapper = require('./utils/mapper');
3
+ const membersService = require('../../../../../services/members');
3
4
 
4
5
  module.exports = {
5
6
  async all(models, apiConfig, frame) {
@@ -10,9 +11,14 @@ module.exports = {
10
11
  return;
11
12
  }
12
13
  let posts = [];
14
+
15
+ const tiersModels = await membersService.api.productRepository.list({
16
+ withRelated: ['monthlyPrice', 'yearlyPrice']
17
+ });
18
+ const tiers = tiersModels.data ? tiersModels.data.map(tierModel => tierModel.toJSON()) : [];
13
19
  if (models.meta) {
14
20
  for (let model of models.data) {
15
- let post = await mapper.mapPost(model, frame);
21
+ let post = await mapper.mapPost(model, frame, {tiers});
16
22
  posts.push(post);
17
23
  }
18
24
  frame.response = {
@@ -22,7 +28,7 @@ module.exports = {
22
28
 
23
29
  return;
24
30
  }
25
- let post = await mapper.mapPost(models, frame);
31
+ let post = await mapper.mapPost(models, frame, {tiers});
26
32
  frame.response = {
27
33
  posts: [post]
28
34
  };
@@ -1,8 +1,14 @@
1
1
  const mapper = require('./utils/mapper');
2
+ const membersService = require('../../../../../services/members');
2
3
 
3
4
  module.exports = {
4
5
  async all(model, apiConfig, frame) {
5
- const data = await mapper.mapPost(model, frame);
6
+ const tiersModels = await membersService.api.productRepository.list({
7
+ withRelated: ['monthlyPrice', 'yearlyPrice']
8
+ });
9
+ const tiers = tiersModels.data ? tiersModels.data.map(tierModel => tierModel.toJSON()) : [];
10
+
11
+ const data = await mapper.mapPost(model, frame, {tiers});
6
12
  frame.response = {
7
13
  preview: [data]
8
14
  };
@@ -1,6 +1,7 @@
1
1
  //@ts-check
2
2
  const debug = require('@tryghost/debug')('api:canary:utils:serializers:output:products');
3
3
  const _ = require('lodash');
4
+ const utils = require('../../../../shared/utils');
4
5
 
5
6
  const allowedIncludes = ['stripe_prices', 'monthly_price', 'yearly_price'];
6
7
 
@@ -22,7 +23,7 @@ module.exports = {
22
23
  */
23
24
  function paginatedProducts(page, _apiConfig, frame) {
24
25
  const requestedQueryIncludes = frame.original && frame.original.query && frame.original.query.include && frame.original.query.include.split(',') || [];
25
- const requestedOptionsIncludes = frame.original && frame.original.options && frame.original.options.include || [];
26
+ const requestedOptionsIncludes = utils.options.trimAndLowerCase(frame.original && frame.original.options && frame.original.options.include || []);
26
27
  return {
27
28
  products: page.data.map((model) => {
28
29
  return cleanIncludes(
@@ -74,6 +75,7 @@ function serializeProduct(product, options, apiType) {
74
75
  description: json.description,
75
76
  slug: json.slug,
76
77
  active: json.active,
78
+ visibility: json.visibility,
77
79
  type: json.type,
78
80
  welcome_page_url: json.welcome_page_url,
79
81
  created_at: json.created_at,
@@ -3,6 +3,7 @@ const debug = require('@tryghost/debug')('api:canary:utils:serializers:output:ti
3
3
  const _ = require('lodash');
4
4
 
5
5
  const allowedIncludes = ['monthly_price', 'yearly_price'];
6
+ const utils = require('../../../../shared/utils');
6
7
 
7
8
  module.exports = {
8
9
  browse: createSerializer('browse', paginatedTiers),
@@ -22,7 +23,7 @@ module.exports = {
22
23
  */
23
24
  function paginatedTiers(page, _apiConfig, frame) {
24
25
  const requestedQueryIncludes = frame.original && frame.original.query && frame.original.query.include && frame.original.query.include.split(',') || [];
25
- const requestedOptionsIncludes = frame.original && frame.original.options && frame.original.options.include || [];
26
+ const requestedOptionsIncludes = utils.options.trimAndLowerCase(frame.original && frame.original.options && frame.original.options.include || []);
26
27
  return {
27
28
  tiers: page.data.map((model) => {
28
29
  return cleanIncludes(
@@ -81,7 +82,8 @@ function serializeTier(tier, options, apiType) {
81
82
  stripe_prices: json.stripePrices ? json.stripePrices.map(price => serializeStripePrice(price, hideStripeData)) : null,
82
83
  monthly_price: serializeStripePrice(json.monthlyPrice, hideStripeData),
83
84
  yearly_price: serializeStripePrice(json.yearlyPrice, hideStripeData),
84
- benefits: json.benefits || null
85
+ benefits: json.benefits || null,
86
+ visibility: json.visibility
85
87
  };
86
88
 
87
89
  return serialized;
@@ -31,7 +31,8 @@ const mapTag = (model, frame) => {
31
31
  return jsonModel;
32
32
  };
33
33
 
34
- const mapPost = async (model, frame) => {
34
+ const mapPost = async (model, frame, options = {}) => {
35
+ const {tiers: tiersData} = options || {};
35
36
  const extendedOptions = Object.assign(_.cloneDeep(frame.options), {
36
37
  extraProperties: ['canonical_url']
37
38
  });
@@ -45,12 +46,21 @@ const mapPost = async (model, frame) => {
45
46
  // Attach tiers to custom nql visibility filter
46
47
  if (labsService.isSet('multipleProducts')
47
48
  && jsonModel.visibility
48
- && !['members', 'public', 'paid', 'tiers'].includes(jsonModel.visibility)
49
49
  ) {
50
- const tiers = await postsService.getProductsFromVisibilityFilter(jsonModel.visibility);
50
+ if (['members', 'public'].includes(jsonModel.visibility) && jsonModel.tiers) {
51
+ jsonModel.tiers = tiersData || [];
52
+ }
53
+
54
+ if (jsonModel.visibility === 'paid' && jsonModel.tiers) {
55
+ jsonModel.tiers = tiersData ? tiersData.filter(t => t.type === 'paid') : [];
56
+ }
51
57
 
52
- jsonModel.visibility = 'tiers';
53
- jsonModel.tiers = tiers;
58
+ if (!['members', 'public', 'paid', 'tiers'].includes(jsonModel.visibility)) {
59
+ const tiers = await postsService.getProductsFromVisibilityFilter(jsonModel.visibility);
60
+
61
+ jsonModel.visibility = 'tiers';
62
+ jsonModel.tiers = tiers;
63
+ }
54
64
  }
55
65
 
56
66
  if (utils.isContentAPI(frame)) {
@@ -103,8 +113,8 @@ const mapPost = async (model, frame) => {
103
113
  return jsonModel;
104
114
  };
105
115
 
106
- const mapPage = async (model, frame) => {
107
- const jsonModel = await mapPost(model, frame);
116
+ const mapPage = async (model, frame, options) => {
117
+ const jsonModel = await mapPost(model, frame, options);
108
118
 
109
119
  delete jsonModel.email_subject;
110
120
  delete jsonModel.email_recipient_filter;
@@ -32,9 +32,10 @@ function configure(dbConfig) {
32
32
  process.env.BTHREADS_BACKEND = 'child_process';
33
33
  }
34
34
 
35
- if (client === 'mysql') {
36
- dbConfig.connection.timezone = 'UTC';
35
+ if (client === 'mysql2') {
36
+ dbConfig.connection.timezone = 'Z';
37
37
  dbConfig.connection.charset = 'utf8mb4';
38
+ dbConfig.connection.decimalNumbers = true;
38
39
 
39
40
  // NOTE: disabled so that worker processes can use the db without
40
41
  // requiring logging and causing file desriptor leaks.
@@ -1,4 +1,5 @@
1
1
  const logging = require('@tryghost/logging');
2
+ const DatabaseInfo = require('@tryghost/database-info');
2
3
 
3
4
  module.exports = {
4
5
  config: {
@@ -6,7 +7,7 @@ module.exports = {
6
7
  },
7
8
 
8
9
  async up({transacting: knex}) {
9
- if (knex.client.config.client !== 'mysql') {
10
+ if (!DatabaseInfo.isMySQL(knex)) {
10
11
  logging.warn('Skipping cleanup of duplicate subscriptions - database is not MySQL');
11
12
  return;
12
13
  }
@@ -1,4 +1,5 @@
1
1
  const logging = require('@tryghost/logging');
2
+ const DatabaseInfo = require('@tryghost/database-info');
2
3
 
3
4
  module.exports = {
4
5
  config: {
@@ -6,7 +7,7 @@ module.exports = {
6
7
  },
7
8
 
8
9
  async up({transacting: knex}) {
9
- if (knex.client.config.client !== 'mysql') {
10
+ if (!DatabaseInfo.isMySQL(knex)) {
10
11
  logging.warn('Skipping cleanup of duplicate customers - database is not MySQL');
11
12
  return;
12
13
  }
@@ -1,4 +1,5 @@
1
1
  const logging = require('@tryghost/logging');
2
+ const DatabaseInfo = require('@tryghost/database-info');
2
3
 
3
4
  module.exports = {
4
5
  config: {
@@ -6,7 +7,7 @@ module.exports = {
6
7
  },
7
8
 
8
9
  async up({transacting: knex}) {
9
- if (knex.client.config.client !== 'mysql') {
10
+ if (!DatabaseInfo.isMySQL(knex)) {
10
11
  logging.warn('Skipping cleanup of orphaned customers - database is not MySQL');
11
12
  return;
12
13
  }
@@ -1,4 +1,5 @@
1
1
  const logging = require('@tryghost/logging');
2
+ const DatabaseInfo = require('@tryghost/database-info');
2
3
 
3
4
  module.exports = {
4
5
  config: {
@@ -6,7 +7,7 @@ module.exports = {
6
7
  },
7
8
 
8
9
  async up({transacting: knex}) {
9
- if (knex.client.config.client !== 'mysql') {
10
+ if (!DatabaseInfo.isMySQL(knex)) {
10
11
  logging.warn('Skipping cleanup of orphaned subscriptions - database is not MySQL');
11
12
  return;
12
13
  }
@@ -1,4 +1,5 @@
1
1
  const logging = require('@tryghost/logging');
2
+ const DatabaseInfo = require('@tryghost/database-info');
2
3
 
3
4
  module.exports = {
4
5
  config: {
@@ -6,7 +7,7 @@ module.exports = {
6
7
  },
7
8
 
8
9
  async up({transacting: knex}) {
9
- if (knex.client.config.client !== 'mysql') {
10
+ if (!DatabaseInfo.isMySQL(knex)) {
10
11
  return logging.warn('Skipping member tables index creation - database is not MySQL');
11
12
  }
12
13
 
@@ -91,7 +92,7 @@ module.exports = {
91
92
  },
92
93
 
93
94
  async down({transacting: knex}) {
94
- if (knex.client.config.client !== 'mysql') {
95
+ if (!DatabaseInfo.isMySQL(knex)) {
95
96
  return logging.warn('Skipping member tables index removal - database is not MySQL');
96
97
  }
97
98
 
@@ -1,11 +1,12 @@
1
1
  const logging = require('@tryghost/logging');
2
2
  const {createNonTransactionalMigration} = require('../../utils');
3
+ const DatabaseInfo = require('@tryghost/database-info');
3
4
 
4
5
  module.exports = createNonTransactionalMigration(
5
6
  async function up(knex) {
6
7
  let hasIndex = false;
7
8
 
8
- if (knex.client.config.client === 'sqlite3') {
9
+ if (DatabaseInfo.isSQLite(knex)) {
9
10
  const result = await knex.raw(`select * from sqlite_master where type = 'index' and tbl_name = 'email_recipients' and name = 'email_recipients_email_id_member_email_index'`);
10
11
  hasIndex = result.length !== 0;
11
12
  } else {
@@ -27,7 +28,7 @@ module.exports = createNonTransactionalMigration(
27
28
  async function down(knex) {
28
29
  let missingIndex = false;
29
30
 
30
- if (knex.client.config.client === 'sqlite3') {
31
+ if (DatabaseInfo.isSQLite(knex)) {
31
32
  const result = await knex.raw(`select * from sqlite_master where type = 'index' and tbl_name = 'email_recipients' and name = 'email_recipients_email_id_member_email_index'`);
32
33
  missingIndex = result.length === 0;
33
34
  } else {
@@ -42,7 +43,7 @@ module.exports = createNonTransactionalMigration(
42
43
 
43
44
  logging.info('Dropping composite index on email_recipients for [email_id, member_email]');
44
45
 
45
- if (knex.client.config.client === 'mysql') {
46
+ if (DatabaseInfo.isMySQL(knex)) {
46
47
  await knex.schema.table('email_recipients', (table) => {
47
48
  table.dropForeign('email_id');
48
49
  table.dropIndex(['email_id', 'member_email']);
@@ -1,8 +1,9 @@
1
1
  const {createIrreversibleMigration} = require('../../utils');
2
2
  const logging = require('@tryghost/logging');
3
+ const DatabaseInfo = require('@tryghost/database-info');
3
4
 
4
5
  module.exports = createIrreversibleMigration(async function up(connection) {
5
- if (connection.client.config.client === 'mysql') {
6
+ if (DatabaseInfo.isMySQL(connection)) {
6
7
  logging.info('Skipping removal of orphaned stripe records for MySQL');
7
8
  return;
8
9
  }
@@ -1,9 +1,10 @@
1
1
  const logging = require('@tryghost/logging');
2
2
  const {createIrreversibleMigration} = require('../../utils');
3
3
  const {addForeign, dropForeign} = require('../../../schema/commands');
4
+ const DatabaseInfo = require('@tryghost/database-info');
4
5
 
5
6
  module.exports = createIrreversibleMigration(async (knex) => {
6
- if (knex.client.config.client !== 'sqlite3') {
7
+ if (!DatabaseInfo.isSQLite(knex)) {
7
8
  return logging.warn('Skipping adding "on delete cascade" - database is not SQLite3');
8
9
  }
9
10
 
@@ -1,9 +1,10 @@
1
1
  const logging = require('@tryghost/logging');
2
2
  const {createIrreversibleMigration} = require('../../utils');
3
3
  const {addForeign, dropForeign} = require('../../../schema/commands');
4
+ const DatabaseInfo = require('@tryghost/database-info');
4
5
 
5
6
  module.exports = createIrreversibleMigration(async (knex) => {
6
- if (knex.client.config.client !== 'sqlite3') {
7
+ if (!DatabaseInfo.isSQLite(knex)) {
7
8
  return logging.warn('Skipping fixing foreign key for members_stripe_customers_subscriptions - database is not SQLite3');
8
9
  }
9
10
 
@@ -1,10 +1,11 @@
1
1
  const logging = require('@tryghost/logging');
2
2
  const {createTransactionalMigration} = require('../../utils');
3
3
  const {addUnique} = require('../../../schema/commands');
4
+ const DatabaseInfo = require('@tryghost/database-info');
4
5
 
5
6
  module.exports = createTransactionalMigration(
6
7
  async function up(connection) {
7
- if (connection.client.config.client !== 'sqlite3') {
8
+ if (!DatabaseInfo.isSQLite(connection)) {
8
9
  return logging.warn('Skipping adding unique constraint for members_stripe_customers_subscriptions and members_stripe_customers - database is not SQLite3');
9
10
  }
10
11
 
@@ -1,6 +1,7 @@
1
1
  const logging = require('@tryghost/logging');
2
2
  const {createNonTransactionalMigration} = require('../../utils');
3
3
  const {addUnique} = require('../../../schema/commands');
4
+ const DatabaseInfo = require('@tryghost/database-info');
4
5
 
5
6
  module.exports = createNonTransactionalMigration(
6
7
  async function up(knex) {
@@ -14,7 +15,7 @@ module.exports = createNonTransactionalMigration(
14
15
  table.string('portal_title', 191).nullable();
15
16
  });
16
17
 
17
- if (knex.client.config.client === 'sqlite3') {
18
+ if (DatabaseInfo.isSQLite(knex)) {
18
19
  // eslint-disable-next-line no-restricted-syntax
19
20
  for (const column of ['name', 'code', 'stripe_coupon_id']) {
20
21
  await addUnique('offers', column, knex);
@@ -32,7 +33,7 @@ module.exports = createNonTransactionalMigration(
32
33
  table.string('portal_title', 191).notNullable();
33
34
  });
34
35
 
35
- if (knex.client.config.client === 'sqlite3') {
36
+ if (DatabaseInfo.isSQLite(knex)) {
36
37
  // eslint-disable-next-line no-restricted-syntax
37
38
  for (const column of ['name', 'code', 'stripe_coupon_id']) {
38
39
  await addUnique('offers', column, knex);
@@ -1,10 +1,10 @@
1
1
  const logging = require('@tryghost/logging');
2
-
3
2
  const {createTransactionalMigration} = require('../../utils');
3
+ const DatabaseInfo = require('@tryghost/database-info');
4
4
 
5
5
  module.exports = createTransactionalMigration(
6
6
  async function up(knex) {
7
- if (knex.client.config.client !== 'mysql') {
7
+ if (!DatabaseInfo.isMySQL(knex)) {
8
8
  logging.warn('Skipping cleanup of duplicate offer redemptions - database is not MySQL');
9
9
  return;
10
10
  }
@@ -1,9 +1,10 @@
1
1
  const logging = require('@tryghost/logging');
2
2
  const {createNonTransactionalMigration} = require('../../utils');
3
+ const DatabaseInfo = require('@tryghost/database-info');
3
4
 
4
5
  module.exports = createNonTransactionalMigration(
5
6
  async function up(knex) {
6
- if (knex.client.config.client === 'sqlite3') {
7
+ if (DatabaseInfo.isSQLite(knex)) {
7
8
  logging.warn('Skipping migration for SQLite3');
8
9
  return;
9
10
  }
@@ -1,9 +1,10 @@
1
1
  const logging = require('@tryghost/logging');
2
2
  const {createNonTransactionalMigration} = require('../../utils');
3
+ const DatabaseInfo = require('@tryghost/database-info');
3
4
 
4
5
  module.exports = createNonTransactionalMigration(
5
6
  async function up(knex) {
6
- if (knex.client.config.client === 'sqlite3') {
7
+ if (DatabaseInfo.isSQLite(knex)) {
7
8
  logging.warn('Skipping migration for SQLite3');
8
9
  return;
9
10
  }
@@ -1,9 +1,10 @@
1
1
  const logging = require('@tryghost/logging');
2
2
  const {createTransactionalMigration} = require('../../utils');
3
+ const DatabaseInfo = require('@tryghost/database-info');
3
4
 
4
5
  module.exports = createTransactionalMigration(
5
6
  async function up(knex) {
6
- if (knex.client.config.client === 'sqlite3') {
7
+ if (DatabaseInfo.isSQLite(knex)) {
7
8
  logging.warn('Skipping migration for SQLite3');
8
9
  return;
9
10
  }
@@ -21,7 +22,7 @@ module.exports = createTransactionalMigration(
21
22
  `);
22
23
  },
23
24
  async function down(knex) {
24
- if (knex.client.config.client === 'sqlite3') {
25
+ if (DatabaseInfo.isSQLite(knex)) {
25
26
  logging.warn('Skipping migration for SQLite3');
26
27
  return;
27
28
  }
@@ -0,0 +1,11 @@
1
+ const {createAddColumnMigration} = require('../../utils');
2
+
3
+ module.exports = createAddColumnMigration('products', 'visible', {
4
+ type: 'boolean',
5
+ nullable: false,
6
+ defaultTo: false
7
+ });
8
+
9
+ module.exports.up = async () => {
10
+ // noop - column will be replaced with `visibility` instead
11
+ };
@@ -0,0 +1,8 @@
1
+ const {createAddColumnMigration} = require('../../utils');
2
+
3
+ module.exports = createAddColumnMigration('products', 'visibility', {
4
+ type: 'string',
5
+ maxlength: 50,
6
+ nullable: false,
7
+ defaultTo: 'none'
8
+ });
@@ -0,0 +1,7 @@
1
+ const {createDropColumnMigration} = require('../../utils');
2
+
3
+ module.exports = createDropColumnMigration('products', 'visible', {});
4
+
5
+ module.exports.down = async () => {
6
+ // noop - column was replaced by `visibility` instead
7
+ };
@@ -3,5 +3,5 @@ const mysql = require('./mysql');
3
3
 
4
4
  module.exports = {
5
5
  sqlite3: sqlite3,
6
- mysql: mysql
6
+ mysql2: mysql
7
7
  };
@@ -1,8 +1,8 @@
1
1
  const _ = require('lodash');
2
2
  const db = require('../../../data/db');
3
3
 
4
- const doRawAndFlatten = function doRaw(query, transaction, flattenFn) {
5
- return (transaction || db.knex).raw(query).then(function (response) {
4
+ const doRawAndFlatten = function doRaw(query, transaction = db.knex, flattenFn) {
5
+ return transaction.raw(query).then(function (response) {
6
6
  return _.flatten(flattenFn(response));
7
7
  });
8
8
  };
@@ -31,8 +31,8 @@ const getColumns = function getColumns(table, transaction) {
31
31
  // a wrong datatype in schema.js some installations using mysql could have been created using the
32
32
  // data type text instead of mediumtext.
33
33
  // For details see: https://github.com/TryGhost/Ghost/issues/1947
34
- const checkPostTable = function checkPostTable(transaction) {
35
- return (transaction || db.knex).raw('SHOW FIELDS FROM posts where Field ="html" OR Field = "markdown"').then(function (response) {
34
+ const checkPostTable = function checkPostTable(transaction = db.knex) {
35
+ return transaction.raw('SHOW FIELDS FROM posts where Field ="html" OR Field = "markdown"').then(function (response) {
36
36
  return _.flatten(_.map(response[0], function (entry) {
37
37
  if (entry.Type.toLowerCase() !== 'mediumtext') {
38
38
  return (transaction || db.knex).raw('ALTER TABLE posts MODIFY ' + entry.Field + ' MEDIUMTEXT');