ghost 5.24.2 → 5.25.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/components/{tryghost-adapter-manager-5.24.2.tgz → tryghost-adapter-manager-5.25.0.tgz} +0 -0
- package/components/{tryghost-api-framework-5.24.2.tgz → tryghost-api-framework-5.25.0.tgz} +0 -0
- package/components/{tryghost-api-version-compatibility-service-5.24.2.tgz → tryghost-api-version-compatibility-service-5.25.0.tgz} +0 -0
- package/components/{tryghost-audience-feedback-5.24.2.tgz → tryghost-audience-feedback-5.25.0.tgz} +0 -0
- package/components/tryghost-bootstrap-socket-5.25.0.tgz +0 -0
- package/components/tryghost-constants-5.25.0.tgz +0 -0
- package/components/{tryghost-custom-theme-settings-service-5.24.2.tgz → tryghost-custom-theme-settings-service-5.25.0.tgz} +0 -0
- package/components/{tryghost-data-generator-5.24.2.tgz → tryghost-data-generator-5.25.0.tgz} +0 -0
- package/components/tryghost-domain-events-5.25.0.tgz +0 -0
- package/components/tryghost-email-analytics-provider-mailgun-5.25.0.tgz +0 -0
- package/components/tryghost-email-analytics-service-5.25.0.tgz +0 -0
- package/components/tryghost-email-content-generator-5.25.0.tgz +0 -0
- package/components/tryghost-email-events-5.25.0.tgz +0 -0
- package/components/tryghost-email-service-5.25.0.tgz +0 -0
- package/components/tryghost-email-suppression-list-5.25.0.tgz +0 -0
- package/components/{tryghost-express-dynamic-redirects-5.24.2.tgz → tryghost-express-dynamic-redirects-5.25.0.tgz} +0 -0
- package/components/tryghost-extract-api-key-5.25.0.tgz +0 -0
- package/components/tryghost-html-to-plaintext-5.25.0.tgz +0 -0
- package/components/tryghost-job-manager-5.25.0.tgz +0 -0
- package/components/{tryghost-link-redirects-5.24.2.tgz → tryghost-link-redirects-5.25.0.tgz} +0 -0
- package/components/tryghost-link-replacer-5.25.0.tgz +0 -0
- package/components/{tryghost-link-tracking-5.24.2.tgz → tryghost-link-tracking-5.25.0.tgz} +0 -0
- package/components/tryghost-magic-link-5.25.0.tgz +0 -0
- package/components/tryghost-mailgun-client-5.25.0.tgz +0 -0
- package/components/{tryghost-member-attribution-5.24.2.tgz → tryghost-member-attribution-5.25.0.tgz} +0 -0
- package/components/tryghost-member-events-5.25.0.tgz +0 -0
- package/components/tryghost-members-api-5.25.0.tgz +0 -0
- package/components/{tryghost-members-csv-5.24.2.tgz → tryghost-members-csv-5.25.0.tgz} +0 -0
- package/components/tryghost-members-events-service-5.25.0.tgz +0 -0
- package/components/{tryghost-members-importer-5.24.2.tgz → tryghost-members-importer-5.25.0.tgz} +0 -0
- package/components/tryghost-members-offers-5.25.0.tgz +0 -0
- package/components/tryghost-members-payments-5.25.0.tgz +0 -0
- package/components/tryghost-members-ssr-5.25.0.tgz +0 -0
- package/components/{tryghost-members-stripe-service-5.24.2.tgz → tryghost-members-stripe-service-5.25.0.tgz} +0 -0
- package/components/tryghost-minifier-5.25.0.tgz +0 -0
- package/components/tryghost-mw-api-version-mismatch-5.25.0.tgz +0 -0
- package/components/tryghost-mw-cache-control-5.25.0.tgz +0 -0
- package/components/{tryghost-mw-error-handler-5.24.2.tgz → tryghost-mw-error-handler-5.25.0.tgz} +0 -0
- package/components/tryghost-mw-session-from-token-5.25.0.tgz +0 -0
- package/components/tryghost-mw-update-user-last-seen-5.25.0.tgz +0 -0
- package/components/tryghost-mw-vhost-5.25.0.tgz +0 -0
- package/components/tryghost-oembed-service-5.25.0.tgz +0 -0
- package/components/{tryghost-package-json-5.24.2.tgz → tryghost-package-json-5.25.0.tgz} +0 -0
- package/components/tryghost-referrers-5.25.0.tgz +0 -0
- package/components/tryghost-security-5.25.0.tgz +0 -0
- package/components/{tryghost-session-service-5.24.2.tgz → tryghost-session-service-5.25.0.tgz} +0 -0
- package/components/tryghost-settings-path-manager-5.25.0.tgz +0 -0
- package/components/tryghost-staff-service-5.25.0.tgz +0 -0
- package/components/tryghost-stats-service-5.25.0.tgz +0 -0
- package/components/{tryghost-tiers-5.24.2.tgz → tryghost-tiers-5.25.0.tgz} +0 -0
- package/components/{tryghost-update-check-service-5.24.2.tgz → tryghost-update-check-service-5.25.0.tgz} +0 -0
- package/components/tryghost-verification-trigger-5.25.0.tgz +0 -0
- package/components/tryghost-version-notifications-data-service-5.25.0.tgz +0 -0
- package/core/boot.js +1 -1
- package/core/built/admin/assets/{chunk.143.ec6fc400326aebf73801.js → chunk.143.e2bde11e02e8a15d322f.js} +23 -23
- package/core/built/admin/assets/{chunk.178.1c3441f4acec543cf937.js → chunk.178.ce7c2b3c8b02f8374ec8.js} +4 -4
- package/core/built/admin/assets/{chunk.507.71dd4bfc4ccb354cc629.js → chunk.507.37279ad3a2f6aeb82302.js} +13 -13
- package/core/built/admin/assets/{chunk.613.6bbcc18224567657fc2e.js → chunk.613.a29fe5699dd5f7fb05f1.js} +162 -160
- package/core/built/admin/assets/{chunk.613.6bbcc18224567657fc2e.js.LICENSE.txt → chunk.613.a29fe5699dd5f7fb05f1.js.LICENSE.txt} +0 -0
- package/core/built/admin/assets/ghost-16dd31e7747e2dce6313f4362842b7b7.css +1 -0
- package/core/built/admin/assets/{ghost-34bc21923675def87aa2516f72ca15d7.js → ghost-a66ff073d219101414fa7b344095c1ca.js} +1084 -1051
- package/core/built/admin/assets/ghost-dark-1117e1c672c39d594cdd1dfdf3d1c1ac.css +1 -0
- package/core/built/admin/assets/{vendor-04415b2b8a59aa9567dfa5d819ada71c.js → vendor-a767da2d0322ba6e801e0d719ccf5a26.js} +40 -38
- package/core/built/admin/index.html +6 -6
- package/core/server/api/endpoints/emails.js +59 -0
- package/core/server/api/endpoints/utils/serializers/input/emails.js +15 -0
- package/core/server/api/endpoints/utils/serializers/input/index.js +4 -0
- package/core/server/api/endpoints/utils/serializers/output/emails.js +32 -0
- package/core/server/api/endpoints/utils/serializers/output/index.js +4 -0
- package/core/server/api/endpoints/utils/serializers/output/mappers/email-batches.js +31 -0
- package/core/server/api/endpoints/utils/serializers/output/mappers/email-failures.js +53 -0
- package/core/server/data/exporter/table-lists.js +4 -1
- package/core/server/data/importer/import-manager.js +1 -3
- package/core/server/data/migrations/versions/5.25/2022-11-24-10-36-add-suppressions-table.js +9 -0
- package/core/server/data/migrations/versions/5.25/2022-11-24-10-37-add-email-spam-complaint-events-table.js +12 -0
- package/core/server/data/migrations/versions/5.25/2022-11-29-08-30-add-error-recipient-failures-table.js +20 -0
- package/core/server/data/schema/schema.js +45 -0
- package/core/server/lib/lexical.js +37 -0
- package/core/server/models/email-batch.js +13 -0
- package/core/server/models/email-recipient-failure.js +29 -0
- package/core/server/models/email-spam-complaint-event.js +44 -0
- package/core/server/models/post.js +7 -1
- package/core/server/models/suppression.js +9 -0
- package/core/server/services/email-analytics/index.js +8 -2
- package/core/server/services/email-analytics/jobs/fetch-latest/index.js +50 -0
- package/core/server/services/email-analytics/jobs/{fetch-latest.js → fetch-latest/run.js} +16 -41
- package/core/server/services/email-analytics/jobs/index.js +1 -1
- package/core/server/services/email-service/wrapper.js +73 -12
- package/core/server/services/email-suppression-list/InMemoryEmailSuppressionList.js +36 -0
- package/core/server/services/email-suppression-list/MailgunEmailSuppressionList.js +117 -0
- package/core/server/services/email-suppression-list/service.js +15 -38
- package/core/server/services/jobs/job-service.js +5 -2
- package/core/server/services/mail/GhostMailer.js +1 -0
- package/core/server/services/mega/feedback-buttons.js +6 -0
- package/core/server/services/mega/mega.js +11 -7
- package/core/server/services/mega/template.js +12 -0
- package/core/server/services/members/api.js +2 -1
- package/core/server/services/members/config.js +11 -2
- package/core/server/services/members/service.js +1 -10
- package/core/server/services/members-events/index.js +2 -2
- package/core/server/services/settings-helpers/settings-helpers.js +4 -0
- package/core/server/web/api/endpoints/admin/routes.js +2 -0
- package/package.json +109 -107
- package/yarn.lock +185 -163
- package/.c8rc.e2e.json +0 -21
- package/components/tryghost-bootstrap-socket-5.24.2.tgz +0 -0
- package/components/tryghost-constants-5.24.2.tgz +0 -0
- package/components/tryghost-domain-events-5.24.2.tgz +0 -0
- package/components/tryghost-email-analytics-provider-mailgun-5.24.2.tgz +0 -0
- package/components/tryghost-email-analytics-service-5.24.2.tgz +0 -0
- package/components/tryghost-email-content-generator-5.24.2.tgz +0 -0
- package/components/tryghost-email-events-5.24.2.tgz +0 -0
- package/components/tryghost-email-service-5.24.2.tgz +0 -0
- package/components/tryghost-email-suppression-list-5.24.2.tgz +0 -0
- package/components/tryghost-extract-api-key-5.24.2.tgz +0 -0
- package/components/tryghost-html-to-plaintext-5.24.2.tgz +0 -0
- package/components/tryghost-job-manager-5.24.2.tgz +0 -0
- package/components/tryghost-link-replacer-5.24.2.tgz +0 -0
- package/components/tryghost-magic-link-5.24.2.tgz +0 -0
- package/components/tryghost-mailgun-client-5.24.2.tgz +0 -0
- package/components/tryghost-member-events-5.24.2.tgz +0 -0
- package/components/tryghost-members-api-5.24.2.tgz +0 -0
- package/components/tryghost-members-events-service-5.24.2.tgz +0 -0
- package/components/tryghost-members-offers-5.24.2.tgz +0 -0
- package/components/tryghost-members-payments-5.24.2.tgz +0 -0
- package/components/tryghost-members-ssr-5.24.2.tgz +0 -0
- package/components/tryghost-minifier-5.24.2.tgz +0 -0
- package/components/tryghost-mw-api-version-mismatch-5.24.2.tgz +0 -0
- package/components/tryghost-mw-cache-control-5.24.2.tgz +0 -0
- package/components/tryghost-mw-session-from-token-5.24.2.tgz +0 -0
- package/components/tryghost-mw-update-user-last-seen-5.24.2.tgz +0 -0
- package/components/tryghost-mw-vhost-5.24.2.tgz +0 -0
- package/components/tryghost-oembed-service-5.24.2.tgz +0 -0
- package/components/tryghost-referrers-5.24.2.tgz +0 -0
- package/components/tryghost-security-5.24.2.tgz +0 -0
- package/components/tryghost-settings-path-manager-5.24.2.tgz +0 -0
- package/components/tryghost-staff-service-5.24.2.tgz +0 -0
- package/components/tryghost-stats-service-5.24.2.tgz +0 -0
- package/components/tryghost-verification-trigger-5.24.2.tgz +0 -0
- package/components/tryghost-version-notifications-data-service-5.24.2.tgz +0 -0
- package/core/built/admin/assets/ghost-dark-a2076b08f23a9e6340072bc7b06ec9e7.css +0 -1
- package/core/built/admin/assets/ghost-f428683b68c0eea9042acc7c021641e0.css +0 -1
- package/core/server/services/email-analytics/lib/event-processor.js +0 -178
- package/core/server/services/members/settings.js +0 -30
- package/playwright.config.js +0 -26
|
@@ -1,178 +0,0 @@
|
|
|
1
|
-
const {EventProcessor} = require('@tryghost/email-analytics-service');
|
|
2
|
-
const {default: ObjectID} = require('bson-objectid');
|
|
3
|
-
const moment = require('moment-timezone');
|
|
4
|
-
|
|
5
|
-
class GhostEventProcessor extends EventProcessor {
|
|
6
|
-
constructor({db}) {
|
|
7
|
-
super(...arguments);
|
|
8
|
-
|
|
9
|
-
this.db = db;
|
|
10
|
-
|
|
11
|
-
// avoid having to query email_batch by provider_id for every event
|
|
12
|
-
this.providerIdEmailIdMap = {};
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
async getEmailId(event) {
|
|
16
|
-
if (event.emailId) {
|
|
17
|
-
return event.emailId;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
if (event.providerId) {
|
|
21
|
-
if (this.providerIdEmailIdMap[event.providerId]) {
|
|
22
|
-
return this.providerIdEmailIdMap[event.providerId];
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
const {emailId} = await this.db.knex('email_batches')
|
|
26
|
-
.select('email_id as emailId')
|
|
27
|
-
.where('provider_id', event.providerId)
|
|
28
|
-
.first() || {};
|
|
29
|
-
|
|
30
|
-
if (!emailId) {
|
|
31
|
-
return;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
this.providerIdEmailIdMap[event.providerId] = emailId;
|
|
35
|
-
return emailId;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
return undefined;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
async getMemberId(event) {
|
|
42
|
-
const emailId = await this.getEmailId(event);
|
|
43
|
-
|
|
44
|
-
if (!emailId) {
|
|
45
|
-
return false;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
if (emailId && event.recipientEmail) {
|
|
49
|
-
const {memberId} = await this.db.knex('email_recipients')
|
|
50
|
-
.select('member_id as memberId')
|
|
51
|
-
.where('member_email', event.recipientEmail)
|
|
52
|
-
.where('email_id', emailId)
|
|
53
|
-
.first() || {};
|
|
54
|
-
|
|
55
|
-
return memberId;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
return undefined;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
async handleDelivered(event) {
|
|
62
|
-
const emailId = await this.getEmailId(event);
|
|
63
|
-
|
|
64
|
-
if (!emailId) {
|
|
65
|
-
return false;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
const updateResult = await this.db.knex('email_recipients')
|
|
69
|
-
.where('email_id', '=', emailId)
|
|
70
|
-
.where('member_email', '=', event.recipientEmail)
|
|
71
|
-
.update({
|
|
72
|
-
delivered_at: this.db.knex.raw('COALESCE(delivered_at, ?)', [moment.utc(event.timestamp).format('YYYY-MM-DD HH:mm:ss')])
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
return updateResult > 0;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
async handleOpened(event) {
|
|
79
|
-
const emailId = await this.getEmailId(event);
|
|
80
|
-
|
|
81
|
-
if (!emailId) {
|
|
82
|
-
return false;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
const updateResult = await this.db.knex('email_recipients')
|
|
86
|
-
.where('email_id', '=', emailId)
|
|
87
|
-
.where('member_email', '=', event.recipientEmail)
|
|
88
|
-
.update({
|
|
89
|
-
opened_at: this.db.knex.raw('COALESCE(opened_at, ?)', [moment.utc(event.timestamp).format('YYYY-MM-DD HH:mm:ss')])
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
// Using the default timezone set in https://github.com/TryGhost/Ghost/blob/2c5643623db0fc4db390f6997c81a73dca7ccacd/core/server/data/schema/default-settings/default-settings.json#L105
|
|
93
|
-
let timezone = 'Etc/UTC';
|
|
94
|
-
const timezoneData = await this.db.knex('settings').first('value').where('key', 'timezone');
|
|
95
|
-
if (timezoneData && timezoneData.value) {
|
|
96
|
-
timezone = timezoneData.value;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
await this.db.knex('members')
|
|
100
|
-
.where('email', '=', event.recipientEmail)
|
|
101
|
-
.andWhere(builder => builder
|
|
102
|
-
.where('last_seen_at', '<', moment.utc(event.timestamp).tz(timezone).startOf('day').utc().format('YYYY-MM-DD HH:mm:ss'))
|
|
103
|
-
.orWhereNull('last_seen_at')
|
|
104
|
-
)
|
|
105
|
-
.update({
|
|
106
|
-
last_seen_at: moment.utc(event.timestamp).format('YYYY-MM-DD HH:mm:ss')
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
return updateResult > 0;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
async handleTemporaryFailed(/*event*/) {
|
|
113
|
-
// noop - we don't do anything with temporary failures for now
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
async handlePermanentFailed(event) {
|
|
117
|
-
const emailId = await this.getEmailId(event);
|
|
118
|
-
|
|
119
|
-
if (!emailId) {
|
|
120
|
-
return false;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
const updateResult = await this.db.knex('email_recipients')
|
|
124
|
-
.where('email_id', '=', emailId)
|
|
125
|
-
.where('member_email', '=', event.recipientEmail)
|
|
126
|
-
.update({
|
|
127
|
-
failed_at: this.db.knex.raw('COALESCE(failed_at, ?)', [moment.utc(event.timestamp).format('YYYY-MM-DD HH:mm:ss')])
|
|
128
|
-
});
|
|
129
|
-
|
|
130
|
-
return updateResult > 0;
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
async handleUnsubscribed(event) {
|
|
134
|
-
return this._unsubscribeFromNewsletters(event);
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
async handleComplained(event) {
|
|
138
|
-
return this._unsubscribeFromNewsletters(event);
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
async _unsubscribeFromNewsletters(event) {
|
|
142
|
-
const memberId = await this.getMemberId(event);
|
|
143
|
-
|
|
144
|
-
if (!memberId) {
|
|
145
|
-
return false;
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
const subscribedNewsletterIds = await this.db.knex('members_newsletters')
|
|
149
|
-
.where('member_id', '=', memberId)
|
|
150
|
-
.pluck('newsletter_id');
|
|
151
|
-
|
|
152
|
-
await this.db.knex('members_newsletters')
|
|
153
|
-
.where('member_id', '=', memberId)
|
|
154
|
-
.del();
|
|
155
|
-
|
|
156
|
-
const nowUTC = moment.utc().toDate();
|
|
157
|
-
for (const newsletterId of subscribedNewsletterIds) {
|
|
158
|
-
await this.db.knex('members_subscribe_events').insert({
|
|
159
|
-
id: ObjectID().toHexString(),
|
|
160
|
-
member_id: memberId,
|
|
161
|
-
newsletter_id: newsletterId,
|
|
162
|
-
subscribed: false,
|
|
163
|
-
created_at: nowUTC,
|
|
164
|
-
source: 'member'
|
|
165
|
-
});
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
const updateResult = await this.db.knex('members')
|
|
169
|
-
.where('id', '=', memberId)
|
|
170
|
-
.update({
|
|
171
|
-
updated_at: moment.utc().toDate()
|
|
172
|
-
});
|
|
173
|
-
|
|
174
|
-
return updateResult > 0;
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
module.exports = GhostEventProcessor;
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
const urlUtils = require('../../../shared/url-utils');
|
|
2
|
-
const SingleUseTokenProvider = require('./SingleUseTokenProvider');
|
|
3
|
-
const models = require('../../models');
|
|
4
|
-
const MAGIC_LINK_TOKEN_VALIDITY = 24 * 60 * 60 * 1000;
|
|
5
|
-
|
|
6
|
-
// @todo: can get removed, since this is moved to the settings bread service
|
|
7
|
-
function createSettingsInstance() {
|
|
8
|
-
const oldTokenProvider = new SingleUseTokenProvider(models.SingleUseToken, MAGIC_LINK_TOKEN_VALIDITY);
|
|
9
|
-
|
|
10
|
-
const getEmailFromToken = async ({token}) => {
|
|
11
|
-
const data = await oldTokenProvider.validate(token);
|
|
12
|
-
return data.email;
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
const getAdminRedirectLink = ({type}) => {
|
|
16
|
-
const adminUrl = urlUtils.urlFor('admin', true);
|
|
17
|
-
if (type === 'supportAddressUpdate') {
|
|
18
|
-
return urlUtils.urlJoin(adminUrl, `#/settings/members/?${type}=success`);
|
|
19
|
-
} else {
|
|
20
|
-
return urlUtils.urlJoin(adminUrl, `#/site/`);
|
|
21
|
-
}
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
return {
|
|
25
|
-
getEmailFromToken,
|
|
26
|
-
getAdminRedirectLink
|
|
27
|
-
};
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
module.exports = createSettingsInstance;
|
package/playwright.config.js
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
/** @type {import('@playwright/test').PlaywrightTestConfig} */
|
|
2
|
-
|
|
3
|
-
const config = {
|
|
4
|
-
timeout: 60 * 1000,
|
|
5
|
-
workers: 1,
|
|
6
|
-
use: {
|
|
7
|
-
// Use a single browser since we can't simultaneously test multiple browsers
|
|
8
|
-
browserName: 'chromium',
|
|
9
|
-
baseURL: process.env.TEST_URL ?? 'http://localhost:2368',
|
|
10
|
-
headless: false
|
|
11
|
-
}
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
if (!process.env.TEST_URL) {
|
|
15
|
-
config.webServer = {
|
|
16
|
-
command: 'yarn start',
|
|
17
|
-
env: {
|
|
18
|
-
// TODO: Use `testing` when starting a server
|
|
19
|
-
NODE_ENV: 'development'
|
|
20
|
-
},
|
|
21
|
-
reuseExistingServer: !process.env.CI,
|
|
22
|
-
url: 'http://localhost:2368'
|
|
23
|
-
};
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
module.exports = config;
|