ghost 4.34.3 → 4.35.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 (56) hide show
  1. package/README.md +1 -1
  2. package/core/built/assets/ghost-dark-cf32b34face01b83c9f3f30d650ba9a8.css +1 -0
  3. package/core/built/assets/ghost.min-73194305644461704a99cd2eb522637a.css +1 -0
  4. package/core/built/assets/{ghost.min-4886fb099a526cb6ca5b733bbfbb5d3a.js → ghost.min-f3a45466144e8273938175e32f788438.js} +1520 -1307
  5. package/core/built/assets/icons/get-started-members.svg +6 -0
  6. package/core/built/assets/icons/get-started-migrations.svg +6 -0
  7. package/core/built/assets/icons/get-started.svg +3 -0
  8. package/core/built/assets/{vendor.min-079fa61c64e24f0984f2cd7d2ebbf3c3.js → vendor.min-b36a93f4fb64127af926ceefa488b00e.js} +1304 -1260
  9. package/core/frontend/helpers/prev_post.js +1 -1
  10. package/core/frontend/helpers/products.js +2 -6
  11. package/core/frontend/helpers/tpl/content-cta.hbs +1 -1
  12. package/core/frontend/services/routing/controllers/email-post.js +1 -1
  13. package/core/frontend/services/routing/controllers/preview.js +1 -1
  14. package/core/frontend/services/routing/controllers/static.js +1 -1
  15. package/core/frontend/services/routing/helpers/entry-lookup.js +1 -1
  16. package/core/frontend/services/routing/helpers/fetch-data.js +1 -1
  17. package/core/frontend/views/unsubscribe.hbs +4 -2
  18. package/core/server/api/canary/email-post.js +1 -1
  19. package/core/server/api/canary/pages-public.js +1 -1
  20. package/core/server/api/canary/pages.js +1 -1
  21. package/core/server/api/canary/posts-public.js +1 -1
  22. package/core/server/api/canary/posts.js +1 -1
  23. package/core/server/api/canary/utils/serializers/input/pages.js +1 -9
  24. package/core/server/api/canary/utils/serializers/input/posts.js +1 -9
  25. package/core/server/api/canary/utils/serializers/output/email-posts.js +2 -2
  26. package/core/server/api/canary/utils/serializers/output/pages.js +9 -5
  27. package/core/server/api/canary/utils/serializers/output/posts.js +9 -5
  28. package/core/server/api/canary/utils/serializers/output/preview.js +3 -2
  29. package/core/server/api/canary/utils/serializers/output/products.js +2 -0
  30. package/core/server/api/canary/utils/serializers/output/utils/clean.js +0 -9
  31. package/core/server/api/canary/utils/serializers/output/utils/mapper.js +18 -3
  32. package/core/server/api/canary/utils/validators/input/pages.js +1 -1
  33. package/core/server/api/canary/utils/validators/input/posts.js +1 -1
  34. package/core/server/data/exporter/table-lists.js +1 -0
  35. package/core/server/data/migrations/versions/4.35/2022-01-20-05-55-add-post-products-table.js +8 -0
  36. package/core/server/data/migrations/versions/4.35/2022-01-30-15-17-set-welcome-page-url-from-settings.js +45 -0
  37. package/core/server/data/migrations/versions/4.35/2022-02-01-11-48-update-email-recipient-filter-column-type.js +18 -0
  38. package/core/server/data/migrations/versions/4.35/2022-02-01-12-03-update-recipient-filter-column-type.js +18 -0
  39. package/core/server/data/migrations/versions/4.35/2022-02-02-10-38-add-default-content-visibility-tiers-setting.js +8 -0
  40. package/core/server/data/migrations/versions/4.35/2022-02-02-13-10-transform-specific-tiers-default-content-visibility.js +147 -0
  41. package/core/server/data/migrations/versions/4.35/2022-02-04-04-34-populate-empty-portal-products.js +60 -0
  42. package/core/server/data/schema/default-settings.json +4 -0
  43. package/core/server/data/schema/schema.js +10 -4
  44. package/core/server/models/post.js +29 -5
  45. package/core/server/services/mega/template.js +1 -1
  46. package/core/server/services/members/content-gating.js +6 -1
  47. package/core/server/services/members/middleware.js +20 -3
  48. package/core/server/services/members/service.js +30 -4
  49. package/core/server/services/posts/posts-service.js +25 -1
  50. package/core/server/web/admin/views/default-prod.html +4 -4
  51. package/core/server/web/admin/views/default.html +4 -4
  52. package/core/shared/labs.js +1 -1
  53. package/package.json +33 -33
  54. package/yarn.lock +811 -799
  55. package/core/built/assets/ghost-dark-2de4c728f3d2deae25e45092ea0e811f.css +0 -1
  56. package/core/built/assets/ghost.min-b1d3e45166f2023dd56b35f720636979.css +0 -1
@@ -27,7 +27,7 @@ const buildApiOptions = function buildApiOptions(options, post) {
27
27
  /**
28
28
  * @deprecated: single authors was superceded by multiple authors in Ghost 1.22.0
29
29
  */
30
- include: 'author,authors,tags',
30
+ include: 'author,authors,tags,tiers',
31
31
  order: 'published_at ' + order,
32
32
  limit: 1,
33
33
  // This line deliberately uses double quotes because GQL cannot handle either double quotes
@@ -6,7 +6,6 @@
6
6
  const {labs} = require('../services/proxy');
7
7
  const {SafeString} = require('../services/rendering');
8
8
 
9
- const nql = require('@nexes/nql');
10
9
  const isString = require('lodash/isString');
11
10
 
12
11
  function products(options = {}) {
@@ -29,11 +28,8 @@ function products(options = {}) {
29
28
  accessProductsList = productsList;
30
29
  }
31
30
 
32
- if (this.visibility === 'filter') {
33
- const nqlFilter = nql(this.visibility_filter);
34
- accessProductsList = productsList.filter((product) => {
35
- return nqlFilter.queryJSON({product: product.slug});
36
- });
31
+ if (this.visibility === 'tiers') {
32
+ accessProductsList = this.tiers;
37
33
  }
38
34
 
39
35
  if (accessProductsList.length > 0) {
@@ -7,7 +7,7 @@
7
7
  {{#has visibility="members"}}
8
8
  <h2>This post is for subscribers only</h2>
9
9
  {{/has}}
10
- {{#has visibility="filter"}}
10
+ {{#has visibility="tiers"}}
11
11
  <h2>This post is for subscribers on the {{products}} only </h2>
12
12
  {{/has}}
13
13
  {{#if @member}}
@@ -18,7 +18,7 @@ module.exports = function emailPostController(req, res, next) {
18
18
 
19
19
  const params = {
20
20
  uuid: req.params.uuid,
21
- include: 'authors,tags',
21
+ include: 'authors,tags,tiers',
22
22
  context: {
23
23
  member: res.locals.member
24
24
  }
@@ -19,7 +19,7 @@ module.exports = function previewController(req, res, next) {
19
19
  const params = {
20
20
  uuid: req.params.uuid,
21
21
  status: 'all',
22
- include: 'authors,tags'
22
+ include: 'authors,tags,tiers'
23
23
  };
24
24
 
25
25
  return api[res.routerOptions.query.controller]
@@ -13,7 +13,7 @@ function processQuery(query, locals) {
13
13
  // We override the `include` property for now, because the full data set is required anyway.
14
14
  if (_.get(query, 'resource') === 'posts' || _.get(query, 'resource') === 'pages') {
15
15
  _.extend(query.options, {
16
- include: 'authors,tags'
16
+ include: 'authors,tags,tiers'
17
17
  });
18
18
  }
19
19
 
@@ -39,7 +39,7 @@ function entryLookup(postUrl, routerOptions, locals) {
39
39
  }
40
40
 
41
41
  let options = {
42
- include: 'authors,tags'
42
+ include: 'authors,tags,tiers'
43
43
  };
44
44
 
45
45
  options.context = {member: locals.member};
@@ -19,7 +19,7 @@ const queryDefaults = {
19
19
  */
20
20
  const defaultQueryOptions = {
21
21
  options: {
22
- include: 'authors,tags'
22
+ include: 'authors,tags,tiers'
23
23
  }
24
24
  };
25
25
 
@@ -42,8 +42,10 @@
42
42
  {{#if member}}
43
43
  <p>
44
44
  <span class="gh-flow-em">{{member.email}}</span> has been successfully unsubscribed from emails.
45
- <br>
46
- Don't worry, this will not cancel your paid subscription to {{@site.title}}.
45
+ {{#match member.status "!=" "free"}}
46
+ <br>
47
+ Don't worry, this will not cancel your paid subscription to {{@site.title}}.
48
+ {{/match}}
47
49
  </p>
48
50
  <p>Didn't mean to do this? Manage your account <a href="{{@site.url}}/#/portal/account">here</a>.</p>
49
51
  {{/if}}
@@ -1,7 +1,7 @@
1
1
  const tpl = require('@tryghost/tpl');
2
2
  const errors = require('@tryghost/errors');
3
3
  const models = require('../../models');
4
- const ALLOWED_INCLUDES = ['authors', 'tags'];
4
+ const ALLOWED_INCLUDES = ['authors', 'tags', 'tiers'];
5
5
 
6
6
  const messages = {
7
7
  postNotFound: 'Post not found.'
@@ -1,7 +1,7 @@
1
1
  const tpl = require('@tryghost/tpl');
2
2
  const errors = require('@tryghost/errors');
3
3
  const models = require('../../models');
4
- const ALLOWED_INCLUDES = ['tags', 'authors'];
4
+ const ALLOWED_INCLUDES = ['tags', 'authors', 'tiers'];
5
5
 
6
6
  const messages = {
7
7
  pageNotFound: 'Page not found.'
@@ -2,7 +2,7 @@ const models = require('../../models');
2
2
  const tpl = require('@tryghost/tpl');
3
3
  const errors = require('@tryghost/errors');
4
4
  const getPostServiceInstance = require('../../services/posts/posts-service');
5
- const ALLOWED_INCLUDES = ['tags', 'authors', 'authors.roles'];
5
+ const ALLOWED_INCLUDES = ['tags', 'authors', 'authors.roles', 'tiers'];
6
6
  const UNSAFE_ATTRS = ['status', 'authors', 'visibility'];
7
7
 
8
8
  const messages = {
@@ -1,7 +1,7 @@
1
1
  const models = require('../../models');
2
2
  const tpl = require('@tryghost/tpl');
3
3
  const errors = require('@tryghost/errors');
4
- const allowedIncludes = ['tags', 'authors'];
4
+ const allowedIncludes = ['tags', 'authors', 'tiers'];
5
5
 
6
6
  const messages = {
7
7
  postNotFound: 'Post not found.'
@@ -2,7 +2,7 @@ const models = require('../../models');
2
2
  const tpl = require('@tryghost/tpl');
3
3
  const errors = require('@tryghost/errors');
4
4
  const getPostServiceInstance = require('../../services/posts/posts-service');
5
- const allowedIncludes = ['tags', 'authors', 'authors.roles', 'email'];
5
+ const allowedIncludes = ['tags', 'authors', 'authors.roles', 'email', 'tiers'];
6
6
  const unsafeAttrs = ['status', 'authors', 'visibility'];
7
7
 
8
8
  const messages = {
@@ -38,7 +38,7 @@ function defaultRelations(frame) {
38
38
  return false;
39
39
  }
40
40
 
41
- frame.options.withRelated = ['tags', 'authors', 'authors.roles'];
41
+ frame.options.withRelated = ['tags', 'authors', 'authors.roles', 'tiers'];
42
42
  }
43
43
 
44
44
  function setDefaultOrder(frame) {
@@ -102,13 +102,6 @@ const forceStatusFilter = (frame) => {
102
102
  }
103
103
  };
104
104
 
105
- const transformPageVisibilityFilters = (frame) => {
106
- if (frame.data.pages[0].visibility === 'filter' && frame.data.pages[0].visibility_filter) {
107
- frame.data.pages[0].visibility = frame.data.pages[0].visibility_filter;
108
- }
109
- delete frame.data.pages[0].visibility_filter;
110
- };
111
-
112
105
  module.exports = {
113
106
  browse(apiConfig, frame) {
114
107
  debug('browse');
@@ -187,7 +180,6 @@ module.exports = {
187
180
  });
188
181
  }
189
182
 
190
- transformPageVisibilityFilters(frame);
191
183
  handlePostsMeta(frame);
192
184
  defaultFormat(frame);
193
185
  defaultRelations(frame);
@@ -38,7 +38,7 @@ function defaultRelations(frame) {
38
38
  return false;
39
39
  }
40
40
 
41
- frame.options.withRelated = ['tags', 'authors', 'authors.roles', 'email'];
41
+ frame.options.withRelated = ['tags', 'authors', 'authors.roles', 'email', 'tiers'];
42
42
  }
43
43
 
44
44
  function setDefaultOrder(frame) {
@@ -111,13 +111,6 @@ const transformLegacyEmailRecipientFilters = (frame) => {
111
111
  }
112
112
  };
113
113
 
114
- const transformPostVisibilityFilters = (frame) => {
115
- if (frame.data.posts[0].visibility === 'filter' && frame.data.posts[0].visibility_filter) {
116
- frame.data.posts[0].visibility = frame.data.posts[0].visibility_filter;
117
- }
118
- delete frame.data.posts[0].visibility_filter;
119
- };
120
-
121
114
  module.exports = {
122
115
  browse(apiConfig, frame) {
123
116
  debug('browse');
@@ -212,7 +205,6 @@ module.exports = {
212
205
  });
213
206
  }
214
207
 
215
- transformPostVisibilityFilters(frame);
216
208
  transformLegacyEmailRecipientFilters(frame);
217
209
  handlePostsMeta(frame);
218
210
  defaultFormat(frame);
@@ -2,8 +2,8 @@ const mapper = require('./utils/mapper');
2
2
  const gating = require('./utils/post-gating');
3
3
 
4
4
  module.exports = {
5
- read(model, apiConfig, frame) {
6
- const emailPost = mapper.mapPost(model, frame);
5
+ async read(model, apiConfig, frame) {
6
+ const emailPost = await mapper.mapPost(model, frame);
7
7
  gating.forPost(emailPost, frame);
8
8
 
9
9
  frame.response = {
@@ -2,25 +2,29 @@ const debug = require('@tryghost/debug')('api:canary:utils:serializers:output:pa
2
2
  const mapper = require('./utils/mapper');
3
3
 
4
4
  module.exports = {
5
- all(models, apiConfig, frame) {
5
+ async all(models, apiConfig, frame) {
6
6
  debug('all');
7
7
 
8
8
  // CASE: e.g. destroy returns null
9
9
  if (!models) {
10
10
  return;
11
11
  }
12
-
12
+ let pages = [];
13
13
  if (models.meta) {
14
+ for (let model of models.data) {
15
+ let page = await mapper.mapPage(model, frame);
16
+ pages.push(page);
17
+ }
14
18
  frame.response = {
15
- pages: models.data.map(model => mapper.mapPage(model, frame)),
19
+ pages,
16
20
  meta: models.meta
17
21
  };
18
22
 
19
23
  return;
20
24
  }
21
-
25
+ let page = await mapper.mapPage(models, frame);
22
26
  frame.response = {
23
- pages: [mapper.mapPage(models, frame)]
27
+ pages: [page]
24
28
  };
25
29
  }
26
30
  };
@@ -2,25 +2,29 @@ const debug = require('@tryghost/debug')('api:canary:utils:serializers:output:po
2
2
  const mapper = require('./utils/mapper');
3
3
 
4
4
  module.exports = {
5
- all(models, apiConfig, frame) {
5
+ async all(models, apiConfig, frame) {
6
6
  debug('all');
7
7
 
8
8
  // CASE: e.g. destroy returns null
9
9
  if (!models) {
10
10
  return;
11
11
  }
12
-
12
+ let posts = [];
13
13
  if (models.meta) {
14
+ for (let model of models.data) {
15
+ let post = await mapper.mapPost(model, frame);
16
+ posts.push(post);
17
+ }
14
18
  frame.response = {
15
- posts: models.data.map(model => mapper.mapPost(model, frame)),
19
+ posts,
16
20
  meta: models.meta
17
21
  };
18
22
 
19
23
  return;
20
24
  }
21
-
25
+ let post = await mapper.mapPost(models, frame);
22
26
  frame.response = {
23
- posts: [mapper.mapPost(models, frame)]
27
+ posts: [post]
24
28
  };
25
29
  }
26
30
  };
@@ -1,9 +1,10 @@
1
1
  const mapper = require('./utils/mapper');
2
2
 
3
3
  module.exports = {
4
- all(model, apiConfig, frame) {
4
+ async all(model, apiConfig, frame) {
5
+ const data = await mapper.mapPost(model, frame);
5
6
  frame.response = {
6
- preview: [mapper.mapPost(model, frame)]
7
+ preview: [data]
7
8
  };
8
9
  frame.response.preview[0].page = model.get('type') === 'page';
9
10
  }
@@ -75,6 +75,7 @@ function serializeProduct(product, options, apiType) {
75
75
  slug: json.slug,
76
76
  active: json.active,
77
77
  type: json.type,
78
+ welcome_page_url: json.welcome_page_url,
78
79
  created_at: json.created_at,
79
80
  updated_at: json.updated_at,
80
81
  stripe_prices: json.stripePrices ? json.stripePrices.map(price => serializeStripePrice(price, hideStripeData)) : null,
@@ -164,6 +165,7 @@ function createSerializer(debugString, serialize) {
164
165
  * @prop {string} description
165
166
  * @prop {boolean} active
166
167
  * @prop {string} type
168
+ * @prop {string} welcome_page_url
167
169
  * @prop {Date} created_at
168
170
  * @prop {Date} updated_at
169
171
  * @prop {StripePrice[]} [stripe_prices]
@@ -1,6 +1,5 @@
1
1
  const _ = require('lodash');
2
2
  const localUtils = require('../../../index');
3
- const labsService = require('../../../../../../../shared/labs');
4
3
 
5
4
  const tag = (attrs, frame) => {
6
5
  if (localUtils.isContentAPI(frame)) {
@@ -122,14 +121,6 @@ const post = (attrs, frame) => {
122
121
  delete attrs.primary_author;
123
122
  }
124
123
 
125
- // Handles visibility filter for multiple products
126
- if (attrs.visibility && labsService.isSet('multipleProducts')) {
127
- if (!['members', 'public', 'paid'].includes(attrs.visibility)) {
128
- attrs.visibility_filter = attrs.visibility;
129
- attrs.visibility = 'filter';
130
- }
131
- }
132
-
133
124
  delete attrs.locale;
134
125
  delete attrs.author;
135
126
  delete attrs.type;
@@ -7,6 +7,10 @@ const clean = require('./clean');
7
7
  const extraAttrs = require('./extra-attrs');
8
8
  const postsMetaSchema = require('../../../../../../data/schema').tables.posts_meta;
9
9
  const mega = require('../../../../../../services/mega');
10
+ const labsService = require('../../../../../../../shared/labs');
11
+
12
+ const getPostServiceInstance = require('../../../../../../services/posts/posts-service');
13
+ const postsService = getPostServiceInstance('canary');
10
14
 
11
15
  const mapUser = (model, frame) => {
12
16
  const jsonModel = model.toJSON ? model.toJSON(frame.options) : model;
@@ -27,7 +31,7 @@ const mapTag = (model, frame) => {
27
31
  return jsonModel;
28
32
  };
29
33
 
30
- const mapPost = (model, frame) => {
34
+ const mapPost = async (model, frame) => {
31
35
  const extendedOptions = Object.assign(_.cloneDeep(frame.options), {
32
36
  extraProperties: ['canonical_url']
33
37
  });
@@ -38,6 +42,17 @@ const mapPost = (model, frame) => {
38
42
 
39
43
  extraAttrs.forPost(frame, model, jsonModel);
40
44
 
45
+ // Attach tiers to custom nql visibility filter
46
+ if (labsService.isSet('multipleProducts')
47
+ && jsonModel.visibility
48
+ && !['members', 'public', 'paid', 'tiers'].includes(jsonModel.visibility)
49
+ ) {
50
+ const tiers = await postsService.getProductsFromVisibilityFilter(jsonModel.visibility);
51
+
52
+ jsonModel.visibility = 'tiers';
53
+ jsonModel.tiers = tiers;
54
+ }
55
+
41
56
  if (utils.isContentAPI(frame)) {
42
57
  // Content api v2 still expects page prop
43
58
  if (jsonModel.type === 'page') {
@@ -88,8 +103,8 @@ const mapPost = (model, frame) => {
88
103
  return jsonModel;
89
104
  };
90
105
 
91
- const mapPage = (model, frame) => {
92
- const jsonModel = mapPost(model, frame);
106
+ const mapPage = async (model, frame) => {
107
+ const jsonModel = await mapPost(model, frame);
93
108
 
94
109
  delete jsonModel.email_subject;
95
110
  delete jsonModel.email_recipient_filter;
@@ -16,7 +16,7 @@ const validateVisibility = async function (frame) {
16
16
  const visibility = frame.data.pages[0].visibility;
17
17
  const visibilityFilter = frame.data.pages[0].visibility_filter;
18
18
  if (visibility) {
19
- if (!['public', 'members', 'paid'].includes(visibility)) {
19
+ if (!['public', 'members', 'paid', 'tiers'].includes(visibility)) {
20
20
  // check filter is valid
21
21
  try {
22
22
  await models.Member.findPage({filter: visibilityFilter, limit: 1});
@@ -16,7 +16,7 @@ const validateVisibility = async function (frame) {
16
16
  const visibility = frame.data.posts[0].visibility;
17
17
  const visibilityFilter = frame.data.posts[0].visibility_filter;
18
18
  if (visibility) {
19
- if (!['public', 'members', 'paid'].includes(visibility)) {
19
+ if (!['public', 'members', 'paid', 'tiers'].includes(visibility)) {
20
20
  // check filter is valid
21
21
  try {
22
22
  await models.Member.findPage({filter: visibilityFilter, limit: 1});
@@ -10,6 +10,7 @@ const BACKUP_TABLES = [
10
10
  'members',
11
11
  'members_labels',
12
12
  'members_products',
13
+ 'posts_products',
13
14
  'members_stripe_customers',
14
15
  'members_stripe_customers_subscriptions',
15
16
  'migrations',
@@ -0,0 +1,8 @@
1
+ const {addTable} = require('../../utils');
2
+
3
+ module.exports = addTable('posts_products', {
4
+ id: {type: 'string', maxlength: 24, nullable: false, primary: true},
5
+ post_id: {type: 'string', maxlength: 24, nullable: false, references: 'posts.id', cascadeDelete: true},
6
+ product_id: {type: 'string', maxlength: 24, nullable: false, references: 'products.id', cascadeDelete: true},
7
+ sort_order: {type: 'integer', nullable: false, unsigned: true, defaultTo: 0}
8
+ });
@@ -0,0 +1,45 @@
1
+ const logging = require('@tryghost/logging');
2
+
3
+ // For DML - data changes
4
+ const {createTransactionalMigration} = require('../../utils');
5
+
6
+ module.exports = createTransactionalMigration(
7
+ async function up(knex) {
8
+ logging.info('Setting welcome_page_url from settings');
9
+
10
+ const paidSignupRedirect = await knex('settings')
11
+ .select('value')
12
+ .where('key', 'members_paid_signup_redirect')
13
+ .first();
14
+
15
+ const freeSignupRedirect = await knex('settings')
16
+ .select('value')
17
+ .where('key', 'members_free_signup_redirect')
18
+ .first();
19
+
20
+ if (paidSignupRedirect) {
21
+ logging.info(`Setting paid Tiers welcome_page_url to ${paidSignupRedirect.value}`);
22
+
23
+ await knex('products')
24
+ .update('welcome_page_url', paidSignupRedirect.value)
25
+ .where('type', 'paid');
26
+ } else {
27
+ logging.info(`No members_paid_signup_redirect setting found`);
28
+ }
29
+
30
+ if (freeSignupRedirect) {
31
+ logging.info(`Setting free Tiers welcome_page_url to ${freeSignupRedirect.value}`);
32
+
33
+ await knex('products')
34
+ .update('welcome_page_url', freeSignupRedirect.value)
35
+ .where('type', 'free');
36
+ } else {
37
+ logging.info(`No members_free_signup_redirect setting found`);
38
+ }
39
+ },
40
+ async function down(knex) {
41
+ logging.info('Setting welcome_page_url to NULL');
42
+ await knex('products')
43
+ .update('welcome_page_url', null);
44
+ }
45
+ );
@@ -0,0 +1,18 @@
1
+ const logging = require('@tryghost/logging');
2
+ const {createNonTransactionalMigration} = require('../../utils');
3
+
4
+ module.exports = createNonTransactionalMigration(
5
+ async function up(knex) {
6
+ if (knex.client.config.client === 'sqlite3') {
7
+ logging.warn('Skipping migration for SQLite3');
8
+ return;
9
+ }
10
+ logging.info('Changing posts.email_recipient_filter column from VARCHAR(50) to TEXT');
11
+ await knex.schema.alterTable('posts', function (table) {
12
+ table.text('email_recipient_filter').alter();
13
+ });
14
+ },
15
+ async function down() {
16
+ logging.warn('Not changing posts.email_recipient_filter column');
17
+ }
18
+ );
@@ -0,0 +1,18 @@
1
+ const logging = require('@tryghost/logging');
2
+ const {createNonTransactionalMigration} = require('../../utils');
3
+
4
+ module.exports = createNonTransactionalMigration(
5
+ async function up(knex) {
6
+ if (knex.client.config.client === 'sqlite3') {
7
+ logging.warn('Skipping migration for SQLite3');
8
+ return;
9
+ }
10
+ logging.info('Changing emails.recipient_filter column from VARCHAR(50) to TEXT');
11
+ await knex.schema.alterTable('emails', function (table) {
12
+ table.text('recipient_filter').alter();
13
+ });
14
+ },
15
+ async function down() {
16
+ logging.warn('Not changing emails.recipient_filter column');
17
+ }
18
+ );
@@ -0,0 +1,8 @@
1
+ const {addSetting} = require('../../utils.js');
2
+
3
+ module.exports = addSetting({
4
+ key: 'default_content_visibility_tiers',
5
+ value: '[]',
6
+ type: 'array',
7
+ group: 'members'
8
+ });