ghost 4.42.1 → 4.43.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.
- package/content/themes/casper/package.json +2 -3
- package/content/themes/casper/partials/post-card.hbs +1 -1
- package/core/built/assets/{ghost-dark-a93afb20027060d760ac6d78f115a76f.css → ghost-dark-1933079797e24ccb8839657020830be5.css} +1 -1
- package/core/built/assets/{ghost.min-20096eef632760c3a2906e243adbd24b.js → ghost.min-2a278873d60d6a13a4c05a396e5bed5e.js} +336 -278
- package/core/built/assets/{ghost.min-ce35ef1b76d9a943ab912c076773b132.css → ghost.min-38f3c38c0c6a1864f57079b068a0b0ce.css} +1 -1
- package/core/frontend/apps/amp/lib/helpers/amp_analytics.js +1 -1
- package/core/frontend/apps/amp/lib/helpers/amp_components.js +1 -1
- package/core/frontend/apps/amp/lib/helpers/amp_content.js +1 -1
- package/core/frontend/apps/amp/lib/helpers/amp_style.js +1 -1
- package/core/frontend/apps/amp/lib/router.js +6 -5
- package/core/frontend/apps/private-blogging/lib/helpers/input_password.js +1 -1
- package/core/frontend/apps/private-blogging/lib/router.js +2 -2
- package/core/frontend/helpers/asset.js +1 -1
- package/core/frontend/helpers/author.js +1 -1
- package/core/frontend/helpers/authors.js +1 -1
- package/core/frontend/helpers/body_class.js +1 -1
- package/core/frontend/helpers/cancel_link.js +1 -1
- package/core/frontend/helpers/concat.js +1 -1
- package/core/frontend/helpers/content.js +1 -1
- package/core/frontend/helpers/date.js +1 -1
- package/core/frontend/helpers/encode.js +1 -1
- package/core/frontend/helpers/excerpt.js +1 -1
- package/core/frontend/helpers/facebook_url.js +1 -1
- package/core/frontend/helpers/foreach.js +2 -2
- package/core/frontend/helpers/get.js +1 -1
- package/core/frontend/helpers/ghost_foot.js +1 -1
- package/core/frontend/helpers/ghost_head.js +1 -1
- package/core/frontend/helpers/lang.js +1 -1
- package/core/frontend/helpers/link.js +1 -1
- package/core/frontend/helpers/link_class.js +1 -1
- package/core/frontend/helpers/match.js +1 -1
- package/core/frontend/helpers/navigation.js +1 -1
- package/core/frontend/helpers/pagination.js +1 -1
- package/core/frontend/helpers/plural.js +1 -1
- package/core/frontend/helpers/post_class.js +1 -1
- package/core/frontend/helpers/prev_post.js +6 -5
- package/core/frontend/helpers/products.js +1 -1
- package/core/frontend/helpers/reading_time.js +2 -2
- package/core/frontend/helpers/t.js +1 -1
- package/core/frontend/helpers/tags.js +1 -1
- package/core/frontend/helpers/tiers.js +1 -1
- package/core/frontend/helpers/title.js +1 -1
- package/core/frontend/helpers/twitter_url.js +1 -1
- package/core/frontend/helpers/url.js +1 -1
- package/core/frontend/meta/url.js +4 -4
- package/core/{server/data/schema → frontend/services/data}/checks.js +4 -4
- package/core/frontend/services/{routing/helpers → data}/entry-lookup.js +3 -3
- package/core/frontend/services/{routing/helpers → data}/fetch-data.js +3 -3
- package/core/frontend/services/data/index.js +5 -0
- package/core/frontend/services/{rendering.js → handlebars.js} +2 -1
- package/core/frontend/services/helpers/handlebars.js +1 -1
- package/core/frontend/services/proxy.js +2 -4
- package/core/frontend/services/{routing/helpers → rendering}/context.js +0 -0
- package/core/frontend/services/{routing/helpers → rendering}/error.js +0 -0
- package/core/frontend/services/{routing/helpers → rendering}/format-response.js +1 -1
- package/core/frontend/services/{routing/helpers → rendering}/index.js +0 -8
- package/core/frontend/services/{routing/helpers → rendering}/render-entries.js +1 -1
- package/core/frontend/services/{routing/helpers → rendering}/render-entry.js +1 -1
- package/core/frontend/services/{routing/helpers → rendering}/renderer.js +1 -1
- package/core/frontend/services/{routing/helpers → rendering}/secure.js +0 -0
- package/core/frontend/services/{routing/helpers → rendering}/templates.js +2 -2
- package/core/frontend/services/routing/CollectionRouter.js +1 -1
- package/core/frontend/services/routing/controllers/channel.js +9 -9
- package/core/frontend/services/routing/controllers/collection.js +9 -9
- package/core/frontend/services/routing/controllers/email-post.js +5 -6
- package/core/frontend/services/routing/controllers/entry.js +6 -6
- package/core/frontend/services/routing/controllers/preview.js +5 -6
- package/core/frontend/services/routing/controllers/rss.js +4 -3
- package/core/frontend/services/routing/controllers/static.js +5 -5
- package/core/frontend/services/routing/controllers/unsubscribe.js +2 -2
- package/core/frontend/services/routing/index.js +0 -4
- package/core/frontend/web/middleware/error-handler.js +2 -2
- package/core/server/api/canary/stats.js +9 -0
- package/core/server/api/canary/utils/serializers/output/members.js +5 -0
- package/core/server/api/canary/utils/validators/input/index.js +6 -0
- package/core/server/api/shared/http.js +52 -51
- package/core/server/data/exporter/table-lists.js +1 -0
- package/core/server/data/migrations/utils.js +33 -1
- package/core/server/data/migrations/versions/4.42/2022-03-21-17-17-add.js +5 -0
- package/core/server/data/migrations/versions/4.43/2022-03-28-19-26-recreate-newsletter-table.js +29 -0
- package/core/server/data/migrations/versions/4.43/2022-03-29-14-45-add-members-newsletters-table.js +7 -0
- package/core/server/data/migrations/versions/4.43/2022-04-01-10-13-add-post-newsletter-relation.js +108 -0
- package/core/server/data/migrations/versions/4.43/2022-04-06-09-47-add-type-column-to-paid-subscription-events.js +7 -0
- package/core/server/data/migrations/versions/4.43/2022-04-06-14-56-add-email-newsletter-relation.js +8 -0
- package/core/server/data/migrations/versions/4.43/2022-04-08-10-45-add-subscription-id-to-mrr-events.js +7 -0
- package/core/server/data/schema/commands.js +6 -1
- package/core/server/data/schema/index.js +0 -1
- package/core/server/data/schema/schema.js +34 -16
- package/core/server/models/base/bookshelf.js +1 -1
- package/core/server/models/base/plugins/crud.js +8 -0
- package/core/server/models/member.js +18 -1
- package/core/server/models/newsletter.js +35 -1
- package/core/server/models/post.js +4 -1
- package/core/server/services/auth/setup.js +4 -1
- package/core/server/services/members/api.js +3 -1
- package/core/server/services/members/middleware.js +13 -3
- package/core/server/services/members/utils.js +13 -1
- package/core/server/services/newsletters/index.js +10 -0
- package/core/server/services/newsletters/service.js +24 -0
- package/core/server/services/slack.js +11 -3
- package/core/server/services/stats/lib/members-stats-service.js +30 -34
- package/core/server/services/stats/lib/mrr-stats-service.js +154 -0
- package/core/server/services/stats/service.js +3 -1
- package/core/server/services/stripe/service.js +1 -0
- package/core/server/web/admin/views/default-prod.html +3 -3
- package/core/server/web/admin/views/default.html +3 -3
- package/core/server/web/api/canary/admin/routes.js +1 -0
- package/core/shared/config/defaults.json +2 -2
- package/package.json +33 -33
- package/yarn.lock +352 -277
- package/content/themes/casper/assets/css/csscomb.json +0 -240
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const
|
|
1
|
+
const moment = require('moment');
|
|
2
2
|
|
|
3
3
|
class MembersStatsService {
|
|
4
4
|
constructor({db}) {
|
|
@@ -28,8 +28,8 @@ class MembersStatsService {
|
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
/**
|
|
31
|
-
* Get the member deltas by status for all days
|
|
32
|
-
* @returns {Promise<MemberStatusDelta[]>} The deltas of paid, free and comped users per day, sorted
|
|
31
|
+
* Get the member deltas by status for all days, sorted ascending
|
|
32
|
+
* @returns {Promise<MemberStatusDelta[]>} The deltas of paid, free and comped users per day, sorted ascending
|
|
33
33
|
*/
|
|
34
34
|
async fetchAllStatusDeltas() {
|
|
35
35
|
const knex = this.db.knex;
|
|
@@ -54,7 +54,7 @@ class MembersStatsService {
|
|
|
54
54
|
ELSE 0 END
|
|
55
55
|
) as free_delta`))
|
|
56
56
|
.groupByRaw('DATE(created_at)')
|
|
57
|
-
.orderByRaw('DATE(created_at)
|
|
57
|
+
.orderByRaw('DATE(created_at)');
|
|
58
58
|
return rows;
|
|
59
59
|
}
|
|
60
60
|
|
|
@@ -69,22 +69,26 @@ class MembersStatsService {
|
|
|
69
69
|
const totals = await this.getCount();
|
|
70
70
|
let {paid, free, comped} = totals;
|
|
71
71
|
|
|
72
|
-
// Get today in UTC (default timezone
|
|
73
|
-
const today =
|
|
72
|
+
// Get today in UTC (default timezone)
|
|
73
|
+
const today = moment().format('YYYY-MM-DD');
|
|
74
74
|
|
|
75
75
|
const cumulativeResults = [];
|
|
76
|
-
|
|
76
|
+
|
|
77
|
+
// Loop in reverse order (needed to have correct sorted result)
|
|
78
|
+
for (let i = rows.length - 1; i >= 0; i -= 1) {
|
|
79
|
+
const row = rows[i];
|
|
80
|
+
|
|
77
81
|
// Convert JSDates to YYYY-MM-DD (in UTC)
|
|
78
|
-
const date =
|
|
82
|
+
const date = moment(row.date).format('YYYY-MM-DD');
|
|
79
83
|
if (date > today) {
|
|
80
84
|
// Skip results that are in the future (fix for invalid events)
|
|
81
85
|
continue;
|
|
82
86
|
}
|
|
83
87
|
cumulativeResults.unshift({
|
|
84
88
|
date,
|
|
85
|
-
paid,
|
|
86
|
-
free,
|
|
87
|
-
comped,
|
|
89
|
+
paid: Math.max(0, paid),
|
|
90
|
+
free: Math.max(0, free),
|
|
91
|
+
comped: Math.max(0, comped),
|
|
88
92
|
|
|
89
93
|
// Deltas
|
|
90
94
|
paid_subscribed: row.paid_subscribed,
|
|
@@ -92,36 +96,28 @@ class MembersStatsService {
|
|
|
92
96
|
});
|
|
93
97
|
|
|
94
98
|
// Update current counts
|
|
95
|
-
paid
|
|
96
|
-
free
|
|
97
|
-
comped
|
|
99
|
+
paid -= row.paid_subscribed - row.paid_canceled;
|
|
100
|
+
free -= row.free_delta;
|
|
101
|
+
comped -= row.comped_delta;
|
|
98
102
|
}
|
|
99
103
|
|
|
100
|
-
//
|
|
101
|
-
|
|
102
|
-
cumulativeResults.push({
|
|
103
|
-
date: today,
|
|
104
|
-
paid,
|
|
105
|
-
free,
|
|
106
|
-
comped,
|
|
104
|
+
// Now also add the oldest day we have left over (this one will be zero, which is also needed as a data point for graphs)
|
|
105
|
+
const oldestDate = rows.length > 0 ? moment(rows[0].date).add(-1, 'days').format('YYYY-MM-DD') : today;
|
|
107
106
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
107
|
+
cumulativeResults.unshift({
|
|
108
|
+
date: oldestDate,
|
|
109
|
+
paid: Math.max(0, paid),
|
|
110
|
+
free: Math.max(0, free),
|
|
111
|
+
comped: Math.max(0, comped),
|
|
112
|
+
|
|
113
|
+
// Deltas
|
|
114
|
+
paid_subscribed: 0,
|
|
115
|
+
paid_canceled: 0
|
|
116
|
+
});
|
|
113
117
|
|
|
114
118
|
return {
|
|
115
119
|
data: cumulativeResults,
|
|
116
120
|
meta: {
|
|
117
|
-
pagination: {
|
|
118
|
-
page: 1,
|
|
119
|
-
limit: 'all',
|
|
120
|
-
pages: 1,
|
|
121
|
-
total: cumulativeResults.length,
|
|
122
|
-
next: null,
|
|
123
|
-
prev: null
|
|
124
|
-
},
|
|
125
121
|
totals
|
|
126
122
|
}
|
|
127
123
|
};
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
const moment = require('moment');
|
|
2
|
+
|
|
3
|
+
class MrrStatsService {
|
|
4
|
+
constructor({db}) {
|
|
5
|
+
this.db = db;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Get the current total MRR, grouped by currency (ascending order)
|
|
10
|
+
* @returns {Promise<MrrByCurrency[]>}
|
|
11
|
+
*/
|
|
12
|
+
async getCurrentMrr() {
|
|
13
|
+
const knex = this.db.knex;
|
|
14
|
+
const rows = await knex('members_stripe_customers_subscriptions')
|
|
15
|
+
.select(knex.raw(`plan_currency as currency`))
|
|
16
|
+
.select(knex.raw(`SUM(
|
|
17
|
+
CASE WHEN plan_interval = 'year' THEN
|
|
18
|
+
FLOOR(plan_amount / 12)
|
|
19
|
+
ELSE
|
|
20
|
+
plan_amount
|
|
21
|
+
END
|
|
22
|
+
) AS mrr`))
|
|
23
|
+
.whereIn('status', ['active', 'unpaid', 'past_due'])
|
|
24
|
+
.where('cancel_at_period_end', 0)
|
|
25
|
+
.groupBy('plan_currency')
|
|
26
|
+
.orderBy('currency');
|
|
27
|
+
|
|
28
|
+
if (rows.length === 0) {
|
|
29
|
+
// Add a USD placeholder to always have at least one currency
|
|
30
|
+
rows.push({
|
|
31
|
+
currency: 'usd',
|
|
32
|
+
mrr: 0
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return rows;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Get the MRR deltas for all days (from old to new), grouped by currency (ascending alphabetically)
|
|
41
|
+
* @returns {Promise<MrrDelta[]>} The deltas sorted from new to old
|
|
42
|
+
*/
|
|
43
|
+
async fetchAllDeltas() {
|
|
44
|
+
const knex = this.db.knex;
|
|
45
|
+
const rows = await knex('members_paid_subscription_events')
|
|
46
|
+
.select('currency')
|
|
47
|
+
// In SQLite, DATE(created_at) would map to a string value, while DATE(created_at) would map to a JSDate object in MySQL
|
|
48
|
+
// That is why we need the cast here (to have some consistency)
|
|
49
|
+
.select(knex.raw('CAST(DATE(created_at) as CHAR) as date'))
|
|
50
|
+
.select(knex.raw(`SUM(mrr_delta) as delta`))
|
|
51
|
+
.groupByRaw('CAST(DATE(created_at) as CHAR), currency')
|
|
52
|
+
.orderByRaw('CAST(DATE(created_at) as CHAR), currency');
|
|
53
|
+
return rows;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Returns a list of the MRR history for each day and currency, including the current MRR per currency as meta data.
|
|
58
|
+
* The respons is in ascending date order, and currencies for the same date are always in ascending order.
|
|
59
|
+
* @returns {Promise<MrrHistory>}
|
|
60
|
+
*/
|
|
61
|
+
async getHistory() {
|
|
62
|
+
// Fetch current total amounts and start counting from there
|
|
63
|
+
const totals = await this.getCurrentMrr();
|
|
64
|
+
|
|
65
|
+
const rows = await this.fetchAllDeltas();
|
|
66
|
+
|
|
67
|
+
// Get today in UTC (default timezone)
|
|
68
|
+
const today = moment().format('YYYY-MM-DD');
|
|
69
|
+
|
|
70
|
+
const results = [];
|
|
71
|
+
|
|
72
|
+
// Create a map of the totals by currency for fast lookup and editing
|
|
73
|
+
const currentTotals = {};
|
|
74
|
+
for (const total of totals) {
|
|
75
|
+
currentTotals[total.currency] = total.mrr;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Loop in reverse order (needed to have correct sorted result)
|
|
79
|
+
for (let i = rows.length - 1; i >= 0; i -= 1) {
|
|
80
|
+
const row = rows[i];
|
|
81
|
+
|
|
82
|
+
if (currentTotals[row.currency] === undefined) {
|
|
83
|
+
// Skip unexpected currencies that are not in the totals
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Convert JSDates to YYYY-MM-DD (in UTC)
|
|
88
|
+
const date = moment(row.date).format('YYYY-MM-DD');
|
|
89
|
+
|
|
90
|
+
if (date > today) {
|
|
91
|
+
// Skip results that are in the future for some reason
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
results.unshift({
|
|
96
|
+
date,
|
|
97
|
+
mrr: Math.max(0, currentTotals[row.currency]),
|
|
98
|
+
currency: row.currency
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
currentTotals[row.currency] -= row.delta;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Now also add the oldest days we have left over and do not have deltas
|
|
105
|
+
const oldestDate = rows.length > 0 ? moment(rows[0].date).add(-1, 'days').format('YYYY-MM-DD') : today;
|
|
106
|
+
|
|
107
|
+
// Note that we also need to loop the totals in reverse order because we need to unshift
|
|
108
|
+
for (let i = totals.length - 1; i >= 0; i -= 1) {
|
|
109
|
+
const total = totals[i];
|
|
110
|
+
results.unshift({
|
|
111
|
+
date: oldestDate,
|
|
112
|
+
mrr: Math.max(0, currentTotals[total.currency]),
|
|
113
|
+
currency: total.currency
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return {
|
|
118
|
+
data: results,
|
|
119
|
+
meta: {
|
|
120
|
+
totals
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
module.exports = MrrStatsService;
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* @typedef MrrByCurrency
|
|
130
|
+
* @type {Object}
|
|
131
|
+
* @property {number} mrr
|
|
132
|
+
* @property {string} currency
|
|
133
|
+
*/
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* @typedef MrrDelta
|
|
137
|
+
* @type {Object}
|
|
138
|
+
* @property {Date} date
|
|
139
|
+
* @property {string} currency
|
|
140
|
+
* @property {number} delta MRR change on this day
|
|
141
|
+
*/
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* @typedef {Object} MrrRecord
|
|
145
|
+
* @property {string} date In YYYY-MM-DD format
|
|
146
|
+
* @property {string} currency
|
|
147
|
+
* @property {number} mrr MRR on this day
|
|
148
|
+
*/
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* @typedef {Object} MrrHistory
|
|
152
|
+
* @property {MrrRecord[]} data List of the total members by status for each day, including the paid deltas paid_subscribed and paid_canceled
|
|
153
|
+
* @property {Object} meta
|
|
154
|
+
*/
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
const db = require('../../data/db');
|
|
2
2
|
const MemberStatsService = require('./lib/members-stats-service');
|
|
3
|
+
const MrrStatsService = require('./lib/mrr-stats-service');
|
|
3
4
|
|
|
4
5
|
module.exports = {
|
|
5
|
-
members: new MemberStatsService({db})
|
|
6
|
+
members: new MemberStatsService({db}),
|
|
7
|
+
mrr: new MrrStatsService({db})
|
|
6
8
|
};
|
|
@@ -12,6 +12,7 @@ const {getConfig} = require('./config');
|
|
|
12
12
|
async function configureApi() {
|
|
13
13
|
const cfg = getConfig(settings, config, urlUtils);
|
|
14
14
|
if (cfg) {
|
|
15
|
+
cfg.testEnv = process.env.NODE_ENV.startsWith('test');
|
|
15
16
|
await module.exports.configure(cfg);
|
|
16
17
|
return true;
|
|
17
18
|
}
|
|
@@ -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.
|
|
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.43%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" />
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
|
|
39
39
|
|
|
40
40
|
<link rel="stylesheet" href="assets/vendor.min-ba66b98f7c24fa40e061c7ffc94f4e23.css">
|
|
41
|
-
<link rel="stylesheet" href="assets/ghost.min-
|
|
41
|
+
<link rel="stylesheet" href="assets/ghost.min-38f3c38c0c6a1864f57079b068a0b0ce.css" title="light">
|
|
42
42
|
|
|
43
43
|
|
|
44
44
|
|
|
@@ -57,7 +57,7 @@
|
|
|
57
57
|
|
|
58
58
|
|
|
59
59
|
<script src="assets/vendor.min-21f79c68a284acb1b70039f3f63e5507.js"></script>
|
|
60
|
-
<script src="assets/ghost.min-
|
|
60
|
+
<script src="assets/ghost.min-2a278873d60d6a13a4c05a396e5bed5e.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.
|
|
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.43%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" />
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
|
|
39
39
|
|
|
40
40
|
<link rel="stylesheet" href="assets/vendor.min-ba66b98f7c24fa40e061c7ffc94f4e23.css">
|
|
41
|
-
<link rel="stylesheet" href="assets/ghost.min-
|
|
41
|
+
<link rel="stylesheet" href="assets/ghost.min-38f3c38c0c6a1864f57079b068a0b0ce.css" title="light">
|
|
42
42
|
|
|
43
43
|
|
|
44
44
|
|
|
@@ -57,7 +57,7 @@
|
|
|
57
57
|
|
|
58
58
|
|
|
59
59
|
<script src="assets/vendor.min-21f79c68a284acb1b70039f3f63e5507.js"></script>
|
|
60
|
-
<script src="assets/ghost.min-
|
|
60
|
+
<script src="assets/ghost.min-2a278873d60d6a13a4c05a396e5bed5e.js"></script>
|
|
61
61
|
|
|
62
62
|
</body>
|
|
63
63
|
</html>
|
|
@@ -139,6 +139,7 @@ module.exports = function apiRoutes() {
|
|
|
139
139
|
|
|
140
140
|
// ## Stats
|
|
141
141
|
router.get('/stats/member_count', mw.authAdminApi, http(api.stats.memberCountHistory));
|
|
142
|
+
router.get('/stats/mrr', mw.authAdminApi, http(api.stats.mrr));
|
|
142
143
|
|
|
143
144
|
// ## Labels
|
|
144
145
|
router.get('/labels', mw.authAdminApi, http(api.labels.browse));
|
|
@@ -128,8 +128,8 @@
|
|
|
128
128
|
"emailAnalytics": true
|
|
129
129
|
},
|
|
130
130
|
"portal": {
|
|
131
|
-
"url": "https://unpkg.com/@tryghost/portal@~1.
|
|
132
|
-
"version": "1.
|
|
131
|
+
"url": "https://unpkg.com/@tryghost/portal@~1.19.0/umd/portal.min.js",
|
|
132
|
+
"version": "1.19"
|
|
133
133
|
},
|
|
134
134
|
"tenor": {
|
|
135
135
|
"publicReadOnlyApiKey": null,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ghost",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.43.0",
|
|
4
4
|
"description": "The professional publishing platform",
|
|
5
5
|
"author": "Ghost Foundation",
|
|
6
6
|
"homepage": "https://ghost.org",
|
|
@@ -55,22 +55,22 @@
|
|
|
55
55
|
"cli": "^1.17.0"
|
|
56
56
|
},
|
|
57
57
|
"dependencies": {
|
|
58
|
-
"@sentry/node": "6.19.
|
|
58
|
+
"@sentry/node": "6.19.6",
|
|
59
59
|
"@tryghost/adapter-manager": "0.2.28",
|
|
60
|
-
"@tryghost/admin-api-schema": "2.
|
|
61
|
-
"@tryghost/bookshelf-plugins": "0.3.
|
|
60
|
+
"@tryghost/admin-api-schema": "2.13.0",
|
|
61
|
+
"@tryghost/bookshelf-plugins": "0.3.18",
|
|
62
62
|
"@tryghost/bootstrap-socket": "0.2.17",
|
|
63
63
|
"@tryghost/color-utils": "0.1.12",
|
|
64
64
|
"@tryghost/config-url-helpers": "0.1.5",
|
|
65
65
|
"@tryghost/constants": "1.0.2",
|
|
66
66
|
"@tryghost/custom-theme-settings-service": "0.3.2",
|
|
67
|
-
"@tryghost/database-info": "0.3.
|
|
67
|
+
"@tryghost/database-info": "0.3.1",
|
|
68
68
|
"@tryghost/debug": "0.1.14",
|
|
69
69
|
"@tryghost/domain-events": "0.1.9",
|
|
70
70
|
"@tryghost/email-analytics-provider-mailgun": "1.0.8",
|
|
71
71
|
"@tryghost/email-analytics-service": "1.0.6",
|
|
72
|
-
"@tryghost/errors": "1.2.
|
|
73
|
-
"@tryghost/express-dynamic-redirects": "0.2.
|
|
72
|
+
"@tryghost/errors": "1.2.10",
|
|
73
|
+
"@tryghost/express-dynamic-redirects": "0.2.8",
|
|
74
74
|
"@tryghost/helpers": "1.1.62",
|
|
75
75
|
"@tryghost/image-transform": "1.0.29",
|
|
76
76
|
"@tryghost/job-manager": "0.8.21",
|
|
@@ -80,24 +80,24 @@
|
|
|
80
80
|
"@tryghost/kg-markdown-html-renderer": "5.1.5",
|
|
81
81
|
"@tryghost/kg-mobiledoc-html-renderer": "5.3.5",
|
|
82
82
|
"@tryghost/limit-service": "1.0.10",
|
|
83
|
-
"@tryghost/logging": "2.1.
|
|
83
|
+
"@tryghost/logging": "2.1.5",
|
|
84
84
|
"@tryghost/magic-link": "1.0.21",
|
|
85
85
|
"@tryghost/member-events": "0.4.1",
|
|
86
|
-
"@tryghost/members-api": "5.
|
|
87
|
-
"@tryghost/members-events-service": "0.3.
|
|
88
|
-
"@tryghost/members-importer": "0.5.
|
|
86
|
+
"@tryghost/members-api": "5.6.1",
|
|
87
|
+
"@tryghost/members-events-service": "0.3.3",
|
|
88
|
+
"@tryghost/members-importer": "0.5.7",
|
|
89
89
|
"@tryghost/members-offers": "0.10.9",
|
|
90
90
|
"@tryghost/members-ssr": "1.0.23",
|
|
91
|
-
"@tryghost/members-stripe-service": "0.9.
|
|
91
|
+
"@tryghost/members-stripe-service": "0.9.4",
|
|
92
92
|
"@tryghost/metrics": "1.0.8",
|
|
93
93
|
"@tryghost/minifier": "0.1.12",
|
|
94
|
-
"@tryghost/mw-error-handler": "0.
|
|
94
|
+
"@tryghost/mw-error-handler": "0.2.0",
|
|
95
95
|
"@tryghost/mw-session-from-token": "0.1.28",
|
|
96
|
-
"@tryghost/nodemailer": "0.3.
|
|
96
|
+
"@tryghost/nodemailer": "0.3.20",
|
|
97
97
|
"@tryghost/nql": "0.9.1",
|
|
98
98
|
"@tryghost/package-json": "1.0.18",
|
|
99
99
|
"@tryghost/promise": "0.1.15",
|
|
100
|
-
"@tryghost/request": "0.1.
|
|
100
|
+
"@tryghost/request": "0.1.24",
|
|
101
101
|
"@tryghost/root-utils": "0.3.12",
|
|
102
102
|
"@tryghost/security": "0.2.15",
|
|
103
103
|
"@tryghost/session-service": "0.1.38",
|
|
@@ -107,7 +107,7 @@
|
|
|
107
107
|
"@tryghost/tpl": "0.1.14",
|
|
108
108
|
"@tryghost/update-check-service": "0.3.2",
|
|
109
109
|
"@tryghost/url-utils": "2.1.0",
|
|
110
|
-
"@tryghost/validator": "0.1.
|
|
110
|
+
"@tryghost/validator": "0.1.22",
|
|
111
111
|
"@tryghost/verification-trigger": "0.1.6",
|
|
112
112
|
"@tryghost/version": "0.1.12",
|
|
113
113
|
"@tryghost/vhost-middleware": "1.0.22",
|
|
@@ -115,7 +115,7 @@
|
|
|
115
115
|
"amperize": "0.6.1",
|
|
116
116
|
"analytics-node": "6.0.0",
|
|
117
117
|
"bluebird": "3.7.2",
|
|
118
|
-
"body-parser": "1.
|
|
118
|
+
"body-parser": "1.20.0",
|
|
119
119
|
"bookshelf": "1.2.0",
|
|
120
120
|
"bookshelf-relations": "2.4.0",
|
|
121
121
|
"brute-knex": "4.0.1",
|
|
@@ -148,20 +148,20 @@
|
|
|
148
148
|
"jsonwebtoken": "8.5.1",
|
|
149
149
|
"juice": "8.0.0",
|
|
150
150
|
"keypair": "1.0.4",
|
|
151
|
-
"knex": "1.0.
|
|
152
|
-
"knex-migrator": "4.2.
|
|
151
|
+
"knex": "1.0.5",
|
|
152
|
+
"knex-migrator": "4.2.6",
|
|
153
153
|
"lodash": "4.17.21",
|
|
154
154
|
"luxon": "2.3.1",
|
|
155
155
|
"mailgun-js": "0.22.0",
|
|
156
|
-
"metascraper": "5.
|
|
157
|
-
"metascraper-author": "5.
|
|
158
|
-
"metascraper-description": "5.
|
|
159
|
-
"metascraper-image": "5.
|
|
160
|
-
"metascraper-logo": "5.
|
|
161
|
-
"metascraper-logo-favicon": "5.
|
|
162
|
-
"metascraper-publisher": "5.
|
|
163
|
-
"metascraper-title": "5.
|
|
164
|
-
"metascraper-url": "5.
|
|
156
|
+
"metascraper": "5.29.0",
|
|
157
|
+
"metascraper-author": "5.29.0",
|
|
158
|
+
"metascraper-description": "5.29.0",
|
|
159
|
+
"metascraper-image": "5.29.0",
|
|
160
|
+
"metascraper-logo": "5.29.0",
|
|
161
|
+
"metascraper-logo-favicon": "5.29.0",
|
|
162
|
+
"metascraper-publisher": "5.29.0",
|
|
163
|
+
"metascraper-title": "5.29.0",
|
|
164
|
+
"metascraper-url": "5.29.0",
|
|
165
165
|
"moment": "2.24.0",
|
|
166
166
|
"moment-timezone": "0.5.23",
|
|
167
167
|
"multer": "1.4.4",
|
|
@@ -175,7 +175,7 @@
|
|
|
175
175
|
"probe-image-size": "7.2.3",
|
|
176
176
|
"rss": "1.2.2",
|
|
177
177
|
"sanitize-html": "2.7.0",
|
|
178
|
-
"semver": "7.3.
|
|
178
|
+
"semver": "7.3.6",
|
|
179
179
|
"stoppable": "1.1.0",
|
|
180
180
|
"tough-cookie": "4.0.0",
|
|
181
181
|
"uuid": "8.3.2",
|
|
@@ -187,11 +187,11 @@
|
|
|
187
187
|
},
|
|
188
188
|
"devDependencies": {
|
|
189
189
|
"@lodder/grunt-postcss": "3.1.1",
|
|
190
|
-
"@playwright/test": "1.20.
|
|
191
|
-
"@tryghost/express-test": "0.8.
|
|
190
|
+
"@playwright/test": "1.20.2",
|
|
191
|
+
"@tryghost/express-test": "0.8.3",
|
|
192
192
|
"c8": "7.11.0",
|
|
193
193
|
"coffeescript": "2.6.1",
|
|
194
|
-
"cssnano": "5.1.
|
|
194
|
+
"cssnano": "5.1.7",
|
|
195
195
|
"eslint": "8.12.0",
|
|
196
196
|
"eslint-plugin-ghost": "2.13.0",
|
|
197
197
|
"grunt": "1.4.1",
|
|
@@ -219,7 +219,7 @@
|
|
|
219
219
|
"tmp": "0.2.1"
|
|
220
220
|
},
|
|
221
221
|
"resolutions": {
|
|
222
|
-
"@tryghost/logging": "2.1.
|
|
222
|
+
"@tryghost/logging": "2.1.5",
|
|
223
223
|
"moment": "2.24.0",
|
|
224
224
|
"moment-timezone": "0.5.23"
|
|
225
225
|
}
|