ghost 4.47.4 → 4.48.2

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.
@@ -4354,6 +4354,6 @@ var i=t.default.create({properties:["name","event","targetUrl"],name(e){Ember.is
4354
4354
  e.default=i})),define("ghost-admin/views/application",["exports"],(function(e){Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
4355
4355
  var t=Ember.Component.extend({})
4356
4356
  e.default=t})),define("ghost-admin/config/environment",[],(function(){try{var e="ghost-admin/config/environment",t=document.querySelector('meta[name="'+e+'"]').getAttribute("content"),n={default:JSON.parse(decodeURIComponent(t))}
4357
- return Object.defineProperty(n,"__esModule",{value:!0}),n}catch(i){throw new Error('Could not read config from meta tag with name "'+e+'".')}})),runningTests||require("ghost-admin/app").default.create({version:"4.47",name:"ghost-admin"})
4357
+ return Object.defineProperty(n,"__esModule",{value:!0}),n}catch(i){throw new Error('Could not read config from meta tag with name "'+e+'".')}})),runningTests||require("ghost-admin/app").default.create({version:"4.48",name:"ghost-admin"})
4358
4358
 
4359
- //# sourceMappingURL=ghost.min-a2a47979b0b61d15a3914042a7b1cd20.map
4359
+ //# sourceMappingURL=ghost.min-10ba0de3ecb93d63d62bb43ac11c740f.map
@@ -45,7 +45,9 @@ module.exports = function (...attrs) {
45
45
  // i18n: Making dates, including month names, translatable to any language.
46
46
  // Documentation: http://momentjs.com/docs/#/i18n/
47
47
  // Locales: https://github.com/moment/moment/tree/develop/locale
48
- dateMoment.locale(locale);
48
+ if (locale && locale.match('^[^/\\\\]*$') !== null) {
49
+ dateMoment.locale(locale);
50
+ }
49
51
 
50
52
  if (timeago) {
51
53
  date = dateMoment.tz(timezone).from(timeNow);
@@ -5,7 +5,6 @@ const moment = require('moment-timezone');
5
5
  const errors = require('@tryghost/errors');
6
6
  const models = require('../../models');
7
7
  const membersService = require('../../services/members');
8
- const labsService = require('../../../shared/labs');
9
8
 
10
9
  const settingsCache = require('../../../shared/settings-cache');
11
10
  const tpl = require('@tryghost/tpl');
@@ -362,16 +361,9 @@ module.exports = {
362
361
  },
363
362
  validation: {},
364
363
  async query(frame) {
365
- frame.options.withRelated = ['labels', 'stripeSubscriptions', 'stripeSubscriptions.customer'];
366
- if (labsService.isSet('multipleProducts')) {
367
- frame.options.withRelated.push('products');
368
- }
369
- if (labsService.isSet('multipleNewsletters')) {
370
- frame.options.withRelated.push('newsletters');
371
- }
372
- const page = await membersService.api.members.list(frame.options);
373
-
374
- return page;
364
+ return {
365
+ data: await membersService.export(frame.options)
366
+ };
375
367
  }
376
368
  },
377
369
 
@@ -79,18 +79,13 @@ function bulkAction(bulkActionResult, _apiConfig, frame) {
79
79
  /**
80
80
  * @template PageMeta
81
81
  *
82
- * @param {{data: import('bookshelf').Model[], meta: PageMeta}} page
83
- * @param {APIConfig} _apiConfig
84
- * @param {Frame} frame
82
+ * @param {{data: any[]}} data
85
83
  *
86
84
  * @returns {string} - A CSV string
87
85
  */
88
- function exportCSV(page, _apiConfig, frame) {
86
+ function exportCSV(data) {
89
87
  debug('exportCSV');
90
-
91
- const members = page.data.map(model => serializeMember(model, frame.options));
92
-
93
- return unparse(members);
88
+ return unparse(data.data);
94
89
  }
95
90
 
96
91
  /**
@@ -1,5 +1,8 @@
1
+ const {BACKUP_TABLES, TABLES_ALLOWLIST} = require('./table-lists');
2
+
1
3
  module.exports = {
2
4
  doExport: require('./exporter'),
3
5
  fileName: require('./export-filename'),
4
- BACKUP_TABLES: require('./table-lists').BACKUP_TABLES
6
+ BACKUP_TABLES,
7
+ TABLES_ALLOWLIST
5
8
  };
@@ -10,25 +10,17 @@ const BACKUP_TABLES = [
10
10
  'members',
11
11
  'members_labels',
12
12
  'members_products',
13
- 'posts_products',
14
13
  'members_stripe_customers',
15
14
  'members_stripe_customers_subscriptions',
16
15
  'migrations',
17
16
  'migrations_lock',
18
- 'newsletters',
19
17
  'oauth',
20
18
  'permissions',
21
19
  'permissions_roles',
22
20
  'permissions_users',
23
- 'products',
24
- 'benefits',
25
- 'products_benefits',
26
21
  'webhooks',
27
- 'snippets',
28
22
  'tokens',
29
23
  'sessions',
30
- 'stripe_products',
31
- 'stripe_prices',
32
24
  'mobiledoc_revisions',
33
25
  'email_batches',
34
26
  'email_recipients',
@@ -40,9 +32,8 @@ const BACKUP_TABLES = [
40
32
  'members_paid_subscription_events',
41
33
  'members_subscribe_events',
42
34
  'members_product_events',
43
- 'members_newsletters',
44
- 'offers',
45
- 'offer_redemptions'
35
+ 'members_newsletters'
36
+
46
37
  ];
47
38
 
48
39
  // NOTE: exposing only tables which are going to be included in a "default" export file
@@ -58,7 +49,17 @@ const TABLES_ALLOWLIST = [
58
49
  'settings',
59
50
  'custom_theme_settings',
60
51
  'tags',
61
- 'users'
52
+ 'users',
53
+ 'products',
54
+ 'stripe_products',
55
+ 'stripe_prices',
56
+ 'posts_products',
57
+ 'newsletters',
58
+ 'benefits',
59
+ 'products_benefits',
60
+ 'offers',
61
+ 'offer_redemptions',
62
+ 'snippets'
62
63
  ];
63
64
 
64
65
  // NOTE: these are settings keys which should never end up in the export file
@@ -0,0 +1,88 @@
1
+ const models = require('../../../models');
2
+ const {knex} = require('../../../data/db');
3
+ const moment = require('moment');
4
+
5
+ module.exports = async function (options) {
6
+ const hasFilter = options.limit !== 'all' || options.filter || options.search;
7
+
8
+ let ids = null;
9
+ if (hasFilter) {
10
+ // do a very minimal query, only to fetch the ids of the filtered values
11
+ // should be quite fast
12
+ options.withRelated = [];
13
+ options.columns = ['id'];
14
+
15
+ const page = await models.Member.findPage(options);
16
+ ids = page.data.map(d => d.id);
17
+
18
+ /*
19
+ const filterOptions = _.pick(options, ['transacting', 'context']);
20
+
21
+ if (all !== true) {
22
+ // Include mongoTransformer to apply subscribed:{true|false} => newsletter relation mapping
23
+ Object.assign(filterOptions, _.pick(options, ['filter', 'search', 'mongoTransformer']));
24
+ }
25
+
26
+ const memberRows = await models.Member.getFilteredCollectionQuery(filterOptions)
27
+ .select('members.id')
28
+ .distinct();
29
+
30
+ ids = memberRows.map(row => row.id);
31
+ */
32
+ }
33
+
34
+ const allProducts = await models.Product.fetchAll();
35
+ const allLabels = await models.Label.fetchAll();
36
+
37
+ let query = knex('members')
38
+ .select('id', 'email', 'name', 'note', 'status', 'created_at')
39
+ .select(knex.raw(`
40
+ (CASE WHEN EXISTS (SELECT 1 FROM members_newsletters n WHERE n.member_id = members.id)
41
+ THEN TRUE ELSE FALSE
42
+ END) as subscribed
43
+ `))
44
+ .select(knex.raw(`
45
+ (SELECT GROUP_CONCAT(product_id) FROM members_products f WHERE f.member_id = members.id) as products
46
+ `))
47
+ .select(knex.raw(`
48
+ (SELECT GROUP_CONCAT(label_id) FROM members_labels f WHERE f.member_id = members.id) as labels
49
+ `))
50
+ .select(knex.raw(`
51
+ (SELECT customer_id FROM members_stripe_customers f WHERE f.member_id = members.id limit 1) as stripe_customer_id
52
+ `));
53
+
54
+ if (hasFilter) {
55
+ query = query.whereIn('id', ids);
56
+ }
57
+
58
+ const rows = await query;
59
+ for (const row of rows) {
60
+ const productIds = row.products ? row.products.split(',') : [];
61
+ const products = productIds.map((id) => {
62
+ const product = allProducts.find(p => p.id === id);
63
+ return {
64
+ name: product.get('name')
65
+ };
66
+ });
67
+ row.products = products;
68
+
69
+ const labelIds = row.labels ? row.labels.split(',') : [];
70
+ const labels = labelIds.map((id) => {
71
+ const label = allLabels.find(l => l.id === id);
72
+ return {
73
+ name: label.get('name')
74
+ };
75
+ });
76
+ row.labels = labels;
77
+ }
78
+
79
+ for (const member of rows) {
80
+ // Note: we don't modify the array or change/duplicate objects
81
+ // to increase performance
82
+ member.subscribed = !!member.subscribed;
83
+ member.comped = member.status === 'comped';
84
+ member.created_at = moment(member.created_at).toISOString();
85
+ }
86
+
87
+ return rows;
88
+ };
@@ -202,7 +202,7 @@ module.exports = {
202
202
 
203
203
  processImport: processImport,
204
204
 
205
- stats: membersStats
206
-
205
+ stats: membersStats,
206
+ export: require('./exporter/query')
207
207
  };
208
208
  module.exports.middleware = require('./middleware');
@@ -8,7 +8,7 @@
8
8
  <title>Ghost Admin</title>
9
9
 
10
10
 
11
- <meta name="ghost-admin/config/environment" content="%7B%22modulePrefix%22%3A%22ghost-admin%22%2C%22environment%22%3A%22production%22%2C%22rootURL%22%3A%22%2F%22%2C%22locationType%22%3A%22trailing-hash%22%2C%22EmberENV%22%3A%7B%22FEATURES%22%3A%7B%7D%2C%22EXTEND_PROTOTYPES%22%3A%7B%22Date%22%3Afalse%2C%22Array%22%3Atrue%2C%22String%22%3Atrue%2C%22Function%22%3Afalse%7D%2C%22_APPLICATION_TEMPLATE_WRAPPER%22%3Afalse%2C%22_JQUERY_INTEGRATION%22%3Atrue%2C%22_TEMPLATE_ONLY_GLIMMER_COMPONENTS%22%3Atrue%7D%2C%22APP%22%3A%7B%22version%22%3A%224.47%22%2C%22name%22%3A%22ghost-admin%22%7D%2C%22ember-simple-auth%22%3A%7B%7D%2C%22moment%22%3A%7B%22includeTimezone%22%3A%22all%22%7D%2C%22%40sentry%2Fember%22%3A%7B%22disablePerformance%22%3Atrue%2C%22sentry%22%3A%7B%7D%7D%2C%22ember-cli-mirage%22%3A%7B%22usingProxy%22%3Afalse%2C%22useDefaultPassthroughs%22%3Atrue%7D%2C%22exportApplicationGlobal%22%3Afalse%2C%22ember-load%22%3A%7B%22loadingIndicatorClass%22%3A%22ember-load-indicator%22%7D%7D" />
11
+ <meta name="ghost-admin/config/environment" content="%7B%22modulePrefix%22%3A%22ghost-admin%22%2C%22environment%22%3A%22production%22%2C%22rootURL%22%3A%22%2F%22%2C%22locationType%22%3A%22trailing-hash%22%2C%22EmberENV%22%3A%7B%22FEATURES%22%3A%7B%7D%2C%22EXTEND_PROTOTYPES%22%3A%7B%22Date%22%3Afalse%2C%22Array%22%3Atrue%2C%22String%22%3Atrue%2C%22Function%22%3Afalse%7D%2C%22_APPLICATION_TEMPLATE_WRAPPER%22%3Afalse%2C%22_JQUERY_INTEGRATION%22%3Atrue%2C%22_TEMPLATE_ONLY_GLIMMER_COMPONENTS%22%3Atrue%7D%2C%22APP%22%3A%7B%22version%22%3A%224.48%22%2C%22name%22%3A%22ghost-admin%22%7D%2C%22ember-simple-auth%22%3A%7B%7D%2C%22moment%22%3A%7B%22includeTimezone%22%3A%22all%22%7D%2C%22%40sentry%2Fember%22%3A%7B%22disablePerformance%22%3Atrue%2C%22sentry%22%3A%7B%7D%7D%2C%22ember-cli-mirage%22%3A%7B%22usingProxy%22%3Afalse%2C%22useDefaultPassthroughs%22%3Atrue%7D%2C%22exportApplicationGlobal%22%3Afalse%2C%22ember-load%22%3A%7B%22loadingIndicatorClass%22%3A%22ember-load-indicator%22%7D%7D" />
12
12
 
13
13
  <meta name="HandheldFriendly" content="True" />
14
14
  <meta name="MobileOptimized" content="320" />
@@ -57,7 +57,7 @@
57
57
 
58
58
 
59
59
  <script src="assets/vendor.min-97fd438f4772c5ec6bb30ad779b8530e.js"></script>
60
- <script src="assets/ghost.min-a2a47979b0b61d15a3914042a7b1cd20.js"></script>
60
+ <script src="assets/ghost.min-10ba0de3ecb93d63d62bb43ac11c740f.js"></script>
61
61
 
62
62
  </body>
63
63
  </html>
@@ -8,7 +8,7 @@
8
8
  <title>Ghost Admin</title>
9
9
 
10
10
 
11
- <meta name="ghost-admin/config/environment" content="%7B%22modulePrefix%22%3A%22ghost-admin%22%2C%22environment%22%3A%22production%22%2C%22rootURL%22%3A%22%2F%22%2C%22locationType%22%3A%22trailing-hash%22%2C%22EmberENV%22%3A%7B%22FEATURES%22%3A%7B%7D%2C%22EXTEND_PROTOTYPES%22%3A%7B%22Date%22%3Afalse%2C%22Array%22%3Atrue%2C%22String%22%3Atrue%2C%22Function%22%3Afalse%7D%2C%22_APPLICATION_TEMPLATE_WRAPPER%22%3Afalse%2C%22_JQUERY_INTEGRATION%22%3Atrue%2C%22_TEMPLATE_ONLY_GLIMMER_COMPONENTS%22%3Atrue%7D%2C%22APP%22%3A%7B%22version%22%3A%224.47%22%2C%22name%22%3A%22ghost-admin%22%7D%2C%22ember-simple-auth%22%3A%7B%7D%2C%22moment%22%3A%7B%22includeTimezone%22%3A%22all%22%7D%2C%22%40sentry%2Fember%22%3A%7B%22disablePerformance%22%3Atrue%2C%22sentry%22%3A%7B%7D%7D%2C%22ember-cli-mirage%22%3A%7B%22usingProxy%22%3Afalse%2C%22useDefaultPassthroughs%22%3Atrue%7D%2C%22exportApplicationGlobal%22%3Afalse%2C%22ember-load%22%3A%7B%22loadingIndicatorClass%22%3A%22ember-load-indicator%22%7D%7D" />
11
+ <meta name="ghost-admin/config/environment" content="%7B%22modulePrefix%22%3A%22ghost-admin%22%2C%22environment%22%3A%22production%22%2C%22rootURL%22%3A%22%2F%22%2C%22locationType%22%3A%22trailing-hash%22%2C%22EmberENV%22%3A%7B%22FEATURES%22%3A%7B%7D%2C%22EXTEND_PROTOTYPES%22%3A%7B%22Date%22%3Afalse%2C%22Array%22%3Atrue%2C%22String%22%3Atrue%2C%22Function%22%3Afalse%7D%2C%22_APPLICATION_TEMPLATE_WRAPPER%22%3Afalse%2C%22_JQUERY_INTEGRATION%22%3Atrue%2C%22_TEMPLATE_ONLY_GLIMMER_COMPONENTS%22%3Atrue%7D%2C%22APP%22%3A%7B%22version%22%3A%224.48%22%2C%22name%22%3A%22ghost-admin%22%7D%2C%22ember-simple-auth%22%3A%7B%7D%2C%22moment%22%3A%7B%22includeTimezone%22%3A%22all%22%7D%2C%22%40sentry%2Fember%22%3A%7B%22disablePerformance%22%3Atrue%2C%22sentry%22%3A%7B%7D%7D%2C%22ember-cli-mirage%22%3A%7B%22usingProxy%22%3Afalse%2C%22useDefaultPassthroughs%22%3Atrue%7D%2C%22exportApplicationGlobal%22%3Afalse%2C%22ember-load%22%3A%7B%22loadingIndicatorClass%22%3A%22ember-load-indicator%22%7D%7D" />
12
12
 
13
13
  <meta name="HandheldFriendly" content="True" />
14
14
  <meta name="MobileOptimized" content="320" />
@@ -57,7 +57,7 @@
57
57
 
58
58
 
59
59
  <script src="assets/vendor.min-97fd438f4772c5ec6bb30ad779b8530e.js"></script>
60
- <script src="assets/ghost.min-a2a47979b0b61d15a3914042a7b1cd20.js"></script>
60
+ <script src="assets/ghost.min-10ba0de3ecb93d63d62bb43ac11c740f.js"></script>
61
61
 
62
62
  </body>
63
63
  </html>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ghost",
3
- "version": "4.47.4",
3
+ "version": "4.48.2",
4
4
  "description": "The professional publishing platform",
5
5
  "author": "Ghost Foundation",
6
6
  "homepage": "https://ghost.org",
@@ -152,8 +152,8 @@
152
152
  "jsonwebtoken": "8.5.1",
153
153
  "juice": "8.0.0",
154
154
  "keypair": "1.0.4",
155
- "knex": "2.0.0",
156
- "knex-migrator": "4.2.8",
155
+ "knex": "2.1.0",
156
+ "knex-migrator": "4.2.11",
157
157
  "lodash": "4.17.21",
158
158
  "luxon": "2.3.2",
159
159
  "mailgun-js": "0.22.0",
package/yarn.lock CHANGED
@@ -1876,6 +1876,11 @@
1876
1876
  resolved "https://registry.yarnpkg.com/@tryghost/database-info/-/database-info-0.3.3.tgz#dbe27b1fd8d97d5ac4a867eb0accd6d7229048b0"
1877
1877
  integrity sha512-nEJYo2RLS7FJoXIaWWpgT3h6N/4FsTtAz2Wm5wvMxk6dVx8LKbZ0D25H069IsrVqqEItJ9kBYcCLmv+6qoPSmw==
1878
1878
 
1879
+ "@tryghost/database-info@0.3.5":
1880
+ version "0.3.5"
1881
+ resolved "https://registry.yarnpkg.com/@tryghost/database-info/-/database-info-0.3.5.tgz#81b77dc976142a8bbbec81f58d56e89c05a1ecdc"
1882
+ integrity sha512-pRWpmQmdg/KOQdkEHDpOAwYvNNc4nrhQ5X8HEVmvqC5ALEKMS6ghKavQGXSnCfUn6Bu8+GXEZ789mE7YOk32jQ==
1883
+
1879
1884
  "@tryghost/debug@0.1.11":
1880
1885
  version "0.1.11"
1881
1886
  resolved "https://registry.yarnpkg.com/@tryghost/debug/-/debug-0.1.11.tgz#cc21e55ac610190426c366a7c69067c5d53117ad"
@@ -8061,31 +8066,31 @@ kind-of@^6.0.0, kind-of@^6.0.2:
8061
8066
  resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd"
8062
8067
  integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==
8063
8068
 
8064
- knex-migrator@4.2.8:
8065
- version "4.2.8"
8066
- resolved "https://registry.yarnpkg.com/knex-migrator/-/knex-migrator-4.2.8.tgz#ef797def311f265ca4bc873494d711ce75469da2"
8067
- integrity sha512-KUMS9DU95pE56w+8NOSZlQKYeSgW/7XqWQnzviyDhejGEbYqXw2IHWQWat8asqs4WWZLregWeqoL8L0KcYAljQ==
8069
+ knex-migrator@4.2.11:
8070
+ version "4.2.11"
8071
+ resolved "https://registry.yarnpkg.com/knex-migrator/-/knex-migrator-4.2.11.tgz#8e80098039f92210840f9932a024b13db7322bbb"
8072
+ integrity sha512-eQDFuiF645g3qL9UyA2kl8V4oOJfn0Kn6o7vNXj/YA/3Z64BHBzw1syparYKzNhxkb+Cl/VepOXt+1wtaQSv+A==
8068
8073
  dependencies:
8069
- "@tryghost/database-info" "0.3.3"
8074
+ "@tryghost/database-info" "0.3.5"
8070
8075
  "@tryghost/logging" "2.1.8"
8071
8076
  bluebird "3.7.2"
8072
8077
  commander "5.1.0"
8073
8078
  compare-ver "2.0.2"
8074
8079
  debug "4.3.4"
8075
8080
  ghost-ignition "4.6.3"
8076
- knex "2.0.0"
8081
+ knex "2.1.0"
8077
8082
  lodash "4.17.21"
8078
8083
  moment "2.24.0"
8079
8084
  mysql2 "2.3.3"
8080
8085
  nconf "0.12.0"
8081
8086
  resolve "1.22.0"
8082
8087
  optionalDependencies:
8083
- sqlite3 "5.0.6"
8088
+ sqlite3 "5.0.8"
8084
8089
 
8085
- knex@2.0.0:
8086
- version "2.0.0"
8087
- resolved "https://registry.yarnpkg.com/knex/-/knex-2.0.0.tgz#84296ced7ef27e0f3b954302ac7d9da67c28b5d3"
8088
- integrity sha512-LchC8/GLfreMz8d4kCwh/ymXttsoJG8zO1O0AJBjnxdyr2oT/k2ik77hP1PpZkZH9mDQrq6WsQcIu18Pnqppzg==
8090
+ knex@2.1.0:
8091
+ version "2.1.0"
8092
+ resolved "https://registry.yarnpkg.com/knex/-/knex-2.1.0.tgz#9348aace3a08ff5be26eb1c8e838416ddf1aa216"
8093
+ integrity sha512-vVsnD6UJdSJy55TvCXfFF9syfwyXNxfE9mvr2hJL/4Obciy2EPGoqjDpgRSlMruHuPWDOeYAG25nyrGvU+jJog==
8089
8094
  dependencies:
8090
8095
  colorette "2.0.16"
8091
8096
  commander "^9.1.0"
@@ -11599,6 +11604,17 @@ sqlite3@5.0.6:
11599
11604
  optionalDependencies:
11600
11605
  node-gyp "8.x"
11601
11606
 
11607
+ sqlite3@5.0.8:
11608
+ version "5.0.8"
11609
+ resolved "https://registry.yarnpkg.com/sqlite3/-/sqlite3-5.0.8.tgz#b4b7eab7156debec80866ef492e01165b4688272"
11610
+ integrity sha512-f2ACsbSyb2D1qFFcqIXPfFscLtPVOWJr5GmUzYxf4W+0qelu5MWrR+FAQE1d5IUArEltBrzSDxDORG8P/IkqyQ==
11611
+ dependencies:
11612
+ "@mapbox/node-pre-gyp" "^1.0.0"
11613
+ node-addon-api "^4.2.0"
11614
+ tar "^6.1.11"
11615
+ optionalDependencies:
11616
+ node-gyp "8.x"
11617
+
11602
11618
  sqlstring@^2.3.2:
11603
11619
  version "2.3.3"
11604
11620
  resolved "https://registry.yarnpkg.com/sqlstring/-/sqlstring-2.3.3.tgz#2ddc21f03bce2c387ed60680e739922c65751d0c"