ghost 5.119.3 → 5.120.1
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-i18n-5.120.1.tgz +0 -0
- package/core/boot.js +0 -2
- package/core/built/admin/assets/admin-x-activitypub/admin-x-activitypub.js +7555 -7216
- package/core/built/admin/assets/admin-x-settings/{CodeEditorView-60ce658c.mjs → CodeEditorView-1c5b0683.mjs} +2 -2
- package/core/built/admin/assets/admin-x-settings/admin-x-settings.js +2 -2
- package/core/built/admin/assets/admin-x-settings/{index-8480baa8.mjs → index-14e518a7.mjs} +3 -3
- package/core/built/admin/assets/admin-x-settings/{index-a2648c61.mjs → index-fc9f985b.mjs} +2 -2
- package/core/built/admin/assets/admin-x-settings/{modals-6900c1d5.mjs → modals-15bc6a0f.mjs} +7192 -6656
- package/core/built/admin/assets/{chunk.137.c9bf40f01afeeadb4660.js → chunk.383.25fca2f09b4896656125.js} +76 -59
- package/core/built/admin/assets/chunk.524.24ab802c6c20f2da3449.js +28 -0
- package/core/built/admin/assets/{chunk.582.2697b46a5652693fc674.js → chunk.582.ebfc460cd2d6864d2cc9.js} +20 -27
- package/core/built/admin/assets/{ghost-843572e9507d099162ae744d791daba1.js → ghost-b3b44421acca3b3eec76bfbb6ba0e81b.js} +3 -3
- package/core/built/admin/assets/koenig-lexical/koenig-lexical.js +12578 -12352
- package/core/built/admin/assets/koenig-lexical/koenig-lexical.umd.js +423 -211
- package/core/built/admin/assets/posts/posts.js +13680 -13671
- package/core/built/admin/assets/stats/stats.js +16457 -16635
- package/core/built/admin/assets/{vendor-8f805740fee4db959a5b2119001a56b1.js → vendor-4ce6d282a2a00fe486a0951e0591da19.js} +11 -9
- package/core/built/admin/index.html +5 -5
- package/core/frontend/helpers/match.js +6 -0
- package/core/frontend/services/routing/ParentRouter.js +1 -1
- package/core/frontend/services/routing/controllers/email-post.js +0 -2
- package/core/frontend/services/routing/controllers/previews.js +0 -3
- package/core/frontend/web/middleware/frontend-caching.js +2 -2
- package/core/server/api/endpoints/authentication.js +37 -73
- package/core/server/api/endpoints/authors-public.js +8 -9
- package/core/server/api/endpoints/db.js +34 -35
- package/core/server/api/endpoints/emails.js +8 -10
- package/core/server/api/endpoints/integrations.js +20 -18
- package/core/server/api/endpoints/invites.js +8 -10
- package/core/server/api/endpoints/labels.js +19 -23
- package/core/server/api/endpoints/notifications.js +3 -4
- package/core/server/api/endpoints/pages-public.js +8 -10
- package/core/server/api/endpoints/pages.js +14 -18
- package/core/server/api/endpoints/posts-public.js +8 -10
- package/core/server/api/endpoints/posts.js +6 -8
- package/core/server/api/endpoints/previews.js +8 -10
- package/core/server/api/endpoints/redirects.js +7 -8
- package/core/server/api/endpoints/schedules.js +5 -7
- package/core/server/api/endpoints/slugs.js +7 -9
- package/core/server/api/endpoints/snippets.js +16 -20
- package/core/server/api/endpoints/tags-public.js +8 -10
- package/core/server/api/endpoints/tags.js +19 -23
- package/core/server/api/endpoints/themes.js +6 -8
- package/core/server/api/endpoints/users.js +31 -36
- package/core/server/api/endpoints/utils/permissions.js +10 -10
- package/core/server/api/endpoints/utils/serializers/output/roles.js +9 -10
- package/core/server/api/endpoints/utils/validators/input/images.js +43 -52
- package/core/server/api/endpoints/utils/validators/input/invites.js +6 -8
- package/core/server/api/endpoints/webhooks.js +38 -42
- package/core/server/data/migrations/versions/5.120/2025-05-07-14-57-38-add-newsletters-button-corners-column.js +8 -0
- package/core/server/data/migrations/versions/5.120/2025-05-13-17-36-56-add-newsletters-button-style-column.js +8 -0
- package/core/server/data/migrations/versions/5.120/2025-05-14-20-00-15-add-newsletters-setting-columns.js +22 -0
- package/core/server/data/schema/schema.js +6 -1
- package/core/server/lib/image/Gravatar.js +12 -13
- package/core/server/lib/lexical.js +3 -1
- package/core/server/models/newsletter.js +6 -1
- package/core/server/services/api-version-compatibility/index.js +1 -33
- package/core/server/services/auth/session/emails/signin.js +3 -3
- package/core/server/services/email-address/EmailAddressParser.js +70 -0
- package/core/server/services/email-address/EmailAddressParser.js.d.ts +13 -0
- package/core/server/services/email-address/EmailAddressService.js +142 -0
- package/core/server/services/email-address/EmailAddressService.ts +183 -0
- package/core/server/services/email-address/EmailAddressServiceWrapper.js +2 -4
- package/core/server/services/email-analytics/EmailAnalyticsService.js +1 -1
- package/core/server/services/email-analytics/EmailAnalyticsServiceWrapper.js +2 -1
- package/core/server/services/email-service/BatchSendingService.js +703 -0
- package/core/server/services/email-service/EmailBodyCache.js +20 -0
- package/core/server/services/email-service/EmailController.js +94 -0
- package/core/server/services/email-service/EmailEventProcessor.js +267 -0
- package/core/server/services/email-service/EmailEventStorage.js +187 -0
- package/core/server/services/email-service/EmailRenderer.js +1263 -0
- package/core/server/services/email-service/EmailSegmenter.js +74 -0
- package/core/server/services/email-service/EmailService.js +310 -0
- package/core/server/services/email-service/EmailServiceWrapper.js +9 -2
- package/core/server/services/email-service/MailgunEmailProvider.js +191 -0
- package/core/server/services/email-service/SendingService.js +173 -0
- package/core/server/services/email-service/email-templates/partials/feedback-button.hbs +7 -0
- package/core/server/services/email-service/email-templates/partials/latest-posts.hbs +39 -0
- package/core/server/services/email-service/email-templates/partials/paywall.hbs +20 -0
- package/core/server/services/email-service/email-templates/partials/styles.hbs +2348 -0
- package/core/server/services/email-service/email-templates/template.hbs +238 -0
- package/core/server/services/email-service/events/EmailBouncedEvent.js +63 -0
- package/core/server/services/email-service/events/EmailDeliveredEvent.js +49 -0
- package/core/server/services/email-service/events/EmailOpenedEvent.js +49 -0
- package/core/server/services/email-service/events/EmailTemporaryBouncedEvent.js +63 -0
- package/core/server/services/email-service/events/EmailUnsubscribedEvent.js +42 -0
- package/core/server/services/email-service/events/SpamComplaintEvent.js +42 -0
- package/core/server/services/email-service/helpers/register-helpers.js +59 -0
- package/core/server/services/email-suppression-list/MailgunEmailSuppressionList.js +2 -1
- package/core/server/services/explore-ping/index.js +2 -1
- package/core/server/services/mail/GhostMailer.js +1 -1
- package/core/server/services/media-inliner/ExternalMediaInliner.js +2 -1
- package/core/server/services/members/api.js +15 -15
- package/core/server/services/members/emails/signin.js +4 -4
- package/core/server/services/members/emails/signup-paid.js +3 -4
- package/core/server/services/members/emails/signup.js +3 -3
- package/core/server/services/members/emails/subscribe.js +3 -3
- package/core/server/services/members/members-api/repositories/MemberRepository.js +92 -92
- package/core/server/services/members-events/LastSeenAtUpdater.js +1 -1
- package/core/server/services/settings-helpers/SettingsHelpers.js +1 -1
- package/core/server/services/staff/StaffServiceEmails.js +1 -1
- package/core/server/services/stats/PostsStatsService.js +28 -7
- package/core/server/web/api/app.js +0 -1
- package/core/server/web/api/endpoints/admin/app.js +0 -2
- package/core/server/web/api/endpoints/content/app.js +0 -2
- package/core/server/web/api/middleware/upload.js +2 -2
- package/core/shared/custom-theme-settings-cache/CustomThemeSettingsService.js +2 -1
- package/package.json +39 -97
- package/tsconfig.tsbuildinfo +1 -1
- package/yarn.lock +385 -517
- package/components/tryghost-api-framework-5.119.3.tgz +0 -0
- package/components/tryghost-custom-fonts-5.119.3.tgz +0 -0
- package/components/tryghost-domain-events-5.119.3.tgz +0 -0
- package/components/tryghost-email-addresses-5.119.3.tgz +0 -0
- package/components/tryghost-email-service-5.119.3.tgz +0 -0
- package/components/tryghost-html-to-plaintext-5.119.3.tgz +0 -0
- package/components/tryghost-i18n-5.119.3.tgz +0 -0
- package/components/tryghost-job-manager-5.119.3.tgz +0 -0
- package/components/tryghost-members-csv-5.119.3.tgz +0 -0
- package/components/tryghost-mw-error-handler-5.119.3.tgz +0 -0
- package/components/tryghost-mw-vhost-5.119.3.tgz +0 -0
- package/components/tryghost-prometheus-metrics-5.119.3.tgz +0 -0
- package/components/tryghost-security-5.119.3.tgz +0 -0
- package/core/built/admin/assets/chunk.524.c86e2e1b3e94d7cb1e4c.js +0 -35
- package/core/server/services/api-version-compatibility/APIVersionCompatibilityService.js +0 -99
- package/core/server/services/api-version-compatibility/VersionNotificationsDataService.js +0 -80
- package/core/server/services/api-version-compatibility/extract-api-key.js +0 -57
- package/core/server/services/api-version-compatibility/mw-api-version-mismatch.js +0 -31
- /package/core/built/admin/assets/{chunk.137.c9bf40f01afeeadb4660.js.LICENSE.txt → chunk.383.25fca2f09b4896656125.js.LICENSE.txt} +0 -0
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html>
|
|
3
|
+
<head>
|
|
4
|
+
<meta name="viewport" content="width=device-width" />
|
|
5
|
+
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
|
6
|
+
<!--[if mso]><xml><o:OfficeDocumentSettings><o:PixelsPerInch>96</o:PixelsPerInch><o:AllowPNG/></o:OfficeDocumentSettings></xml><![endif]-->
|
|
7
|
+
<title>{{post.title}}</title>
|
|
8
|
+
{{>styles}}
|
|
9
|
+
</head>
|
|
10
|
+
<body>
|
|
11
|
+
<span class="preheader">{{preheader}}</span>
|
|
12
|
+
<table role="presentation" border="0" cellpadding="0" cellspacing="0" class="body" width="100%">
|
|
13
|
+
<!-- Outlook doesn't respect max-width so we need an extra centered table -->
|
|
14
|
+
<!--[if mso]>
|
|
15
|
+
<tr>
|
|
16
|
+
<td>
|
|
17
|
+
<center>
|
|
18
|
+
<table border="0" cellpadding="0" cellspacing="0" width="600">
|
|
19
|
+
<![endif]-->
|
|
20
|
+
<tr>
|
|
21
|
+
<td> </td>
|
|
22
|
+
<td class="container">
|
|
23
|
+
<div class="content">
|
|
24
|
+
<!-- START CENTERED WHITE CONTAINER -->
|
|
25
|
+
<table role="presentation" border="0" cellpadding="0" cellspacing="0" class="main" width="100%">
|
|
26
|
+
|
|
27
|
+
<!-- START MAIN CONTENT AREA -->
|
|
28
|
+
<tr>
|
|
29
|
+
<td class="wrapper">
|
|
30
|
+
<table role="presentation" border="0" cellpadding="0" cellspacing="0" width="100%">
|
|
31
|
+
{{#if headerImage}}
|
|
32
|
+
<tr class="header-image-row">
|
|
33
|
+
<td class="header-image" width="100%" align="center">
|
|
34
|
+
<a href="{{site.url}}">
|
|
35
|
+
<img
|
|
36
|
+
src="{{headerImage}}"
|
|
37
|
+
{{#if headerImageWidth}}
|
|
38
|
+
width="{{headerImageWidth}}"
|
|
39
|
+
{{/if}}
|
|
40
|
+
>
|
|
41
|
+
</a>
|
|
42
|
+
</td>
|
|
43
|
+
</tr>
|
|
44
|
+
{{/if}}
|
|
45
|
+
|
|
46
|
+
{{#if (or showHeaderIcon showHeaderTitle showHeaderName) }}
|
|
47
|
+
<tr class="site-info-row">
|
|
48
|
+
<td class="site-info" width="100%" align="center">
|
|
49
|
+
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
|
|
50
|
+
{{#if (and showHeaderIcon site.iconUrl) }}
|
|
51
|
+
<tr>
|
|
52
|
+
<td class="site-icon"><a href="{{site.url}}"><img src="{{site.iconUrl}}" alt="{{site.title}}" border="0" width="48" height="48"></a></td>
|
|
53
|
+
</tr>
|
|
54
|
+
{{/if}}
|
|
55
|
+
{{#if showHeaderTitle }}
|
|
56
|
+
<tr>
|
|
57
|
+
<td class="site-url {{#unless showHeaderName}}site-url-bottom-padding{{/unless}}"><div style="width: 100% !important;"><a href="{{site.url}}" class="site-title">{{site.title}}</a></div></td>
|
|
58
|
+
</tr>
|
|
59
|
+
{{/if}}
|
|
60
|
+
{{#if (and showHeaderName showHeaderTitle) }}
|
|
61
|
+
<tr>
|
|
62
|
+
<td class="site-url site-url-bottom-padding"><div style="width: 100% !important;"><a href="{{site.url}}" class="site-subtitle">{{newsletter.name}}</a></div></td>
|
|
63
|
+
</tr>
|
|
64
|
+
{{/if}}
|
|
65
|
+
{{#if (and showHeaderName (not showHeaderTitle)) }}
|
|
66
|
+
<tr>
|
|
67
|
+
<td class="site-url site-url-bottom-padding"><div style="width: 100% !important;"><a href="{{site.url}}" class="site-title">{{newsletter.name}}</a></div></td>
|
|
68
|
+
</tr>
|
|
69
|
+
{{/if}}
|
|
70
|
+
|
|
71
|
+
</table>
|
|
72
|
+
</td>
|
|
73
|
+
</tr>
|
|
74
|
+
{{/if}}
|
|
75
|
+
|
|
76
|
+
{{#if newsletter.showPostTitleSection}}
|
|
77
|
+
<tr>
|
|
78
|
+
<td class="{{classes.title}}">
|
|
79
|
+
<a href="{{post.url}}" class="{{classes.titleLink}}">{{post.title}}</a>
|
|
80
|
+
</td>
|
|
81
|
+
</tr>
|
|
82
|
+
{{#if (and newsletter.showExcerpt post.customExcerpt)}}
|
|
83
|
+
<tr>
|
|
84
|
+
<td class="post-excerpt-wrapper" style="width: 100%">
|
|
85
|
+
<p class="{{classes.excerpt}}">{{post.customExcerpt}}</p>
|
|
86
|
+
</td>
|
|
87
|
+
</tr>
|
|
88
|
+
{{/if}}
|
|
89
|
+
<tr>
|
|
90
|
+
<td style="width: 100%">
|
|
91
|
+
<table class="post-meta-wrapper" role="presentation" border="0" cellpadding="0" cellspacing="0" width="100%" style="padding-bottom: 32px;">
|
|
92
|
+
<tr>
|
|
93
|
+
<td height="20" class="{{classes.meta}}" style="padding: 0;">
|
|
94
|
+
{{{t 'By {authors}' authors=post.authors }}} • <span class="post-meta-date">{{t '{date}' date=post.publishedAt}} </span>
|
|
95
|
+
</td>
|
|
96
|
+
<td class="{{classes.meta}} view-online desktop">
|
|
97
|
+
<a href="{{post.url}}" class="view-online-link">{{t 'View in browser'}}</a>
|
|
98
|
+
</td>
|
|
99
|
+
</tr>
|
|
100
|
+
<tr class="{{classes.meta}} view-online-mobile">
|
|
101
|
+
<td height="20" class="view-online">
|
|
102
|
+
<a href="{{post.url}}" class="view-online-link">{{t 'View in browser'}}</a>
|
|
103
|
+
</td>
|
|
104
|
+
</tr>
|
|
105
|
+
</table>
|
|
106
|
+
</td>
|
|
107
|
+
</tr>
|
|
108
|
+
{{/if}}
|
|
109
|
+
|
|
110
|
+
{{#if showFeatureImage }}
|
|
111
|
+
<tr class="feature-image-row">
|
|
112
|
+
<td class="feature-image
|
|
113
|
+
{{#if post.feature_image_caption }}
|
|
114
|
+
feature-image-with-caption
|
|
115
|
+
{{/if}}
|
|
116
|
+
" align="center"><img
|
|
117
|
+
src="{{post.feature_image}}"
|
|
118
|
+
{{#if post.feature_image_width }}
|
|
119
|
+
width="{{post.feature_image_width}}"
|
|
120
|
+
{{/if}}
|
|
121
|
+
{{#if post.feature_image_alt }}
|
|
122
|
+
alt="{{post.feature_image_alt}}"
|
|
123
|
+
{{/if}}
|
|
124
|
+
></td>
|
|
125
|
+
</tr>
|
|
126
|
+
|
|
127
|
+
{{#if post.feature_image_caption }}
|
|
128
|
+
<tr>
|
|
129
|
+
<td align="center">
|
|
130
|
+
<div class="feature-image-caption">
|
|
131
|
+
{{{post.feature_image_caption}}}
|
|
132
|
+
</div>
|
|
133
|
+
</td>
|
|
134
|
+
</tr>
|
|
135
|
+
{{/if}}
|
|
136
|
+
{{/if}}
|
|
137
|
+
<tr class="post-content-row">
|
|
138
|
+
<td class="{{classes.body}}">
|
|
139
|
+
<!-- POST CONTENT START -->
|
|
140
|
+
{{{html}}}
|
|
141
|
+
<!-- POST CONTENT END -->
|
|
142
|
+
|
|
143
|
+
{{#if paywall}}
|
|
144
|
+
{{>paywall}}
|
|
145
|
+
{{/if}}
|
|
146
|
+
</td>
|
|
147
|
+
</tr>
|
|
148
|
+
</table>
|
|
149
|
+
</td>
|
|
150
|
+
</tr>
|
|
151
|
+
|
|
152
|
+
<!-- END MAIN CONTENT AREA -->
|
|
153
|
+
|
|
154
|
+
{{#if (or feedbackButtons newsletter.showCommentCta) }}
|
|
155
|
+
<tr>
|
|
156
|
+
<td dir="ltr" width="100%" style="background-color: #ffffff; text-align: center; padding: 32px 0 24px; border-bottom: 1px solid #e0e7eb;" align="center">
|
|
157
|
+
<table class="feedback-buttons" role="presentation" border="0" cellpadding="0" cellspacing="0">
|
|
158
|
+
<tr>
|
|
159
|
+
{{#if feedbackButtons }}
|
|
160
|
+
{{> feedbackButton feedbackButtons href=feedbackButtons.likeHref buttonText='More like this' iconUrl="https://static.ghost.org/v5.0.0/images/more-like-this-mobile.png" width="42" height="42" }}
|
|
161
|
+
{{> feedbackButton feedbackButtons href=feedbackButtons.dislikeHref buttonText='Less like this' iconUrl="https://static.ghost.org/v5.0.0/images/less-like-this-mobile.png" width="42" height="42" }}
|
|
162
|
+
{{/if}}
|
|
163
|
+
{{#if newsletter.showCommentCta}}
|
|
164
|
+
{{> feedbackButton href=post.commentUrl buttonText='Comment' iconUrl="https://static.ghost.org/v5.0.0/images/comment-mobile.png" width="42" height="42"}}
|
|
165
|
+
{{/if}}
|
|
166
|
+
</tr>
|
|
167
|
+
</table>
|
|
168
|
+
</td>
|
|
169
|
+
</tr>
|
|
170
|
+
{{/if}}
|
|
171
|
+
|
|
172
|
+
{{#if latestPosts.length}}
|
|
173
|
+
<tr>
|
|
174
|
+
<td style="padding: 24px 0; border-bottom: 1px solid #e0e7eb;">
|
|
175
|
+
<h3 class="latest-posts-header">{{t 'Keep reading'}}</h3>
|
|
176
|
+
{{> latestPosts}}
|
|
177
|
+
</td>
|
|
178
|
+
</tr>
|
|
179
|
+
{{/if}}
|
|
180
|
+
|
|
181
|
+
{{#if newsletter.showSubscriptionDetails}}
|
|
182
|
+
<tr>
|
|
183
|
+
<td class="subscription-box">
|
|
184
|
+
<h3>{{t 'Subscription details'}}</h3>
|
|
185
|
+
<p style="margin-bottom: 16px;">
|
|
186
|
+
<span>{{{t "You are receiving this because you are a <strong>%%{status}%% subscriber</strong> to {site}." site=site.title }}}</span> %%{status_text}%%
|
|
187
|
+
</p>
|
|
188
|
+
<table role="presentation" border="0" cellpadding="0" cellspacing="0" width="100%">
|
|
189
|
+
<tr>
|
|
190
|
+
<td class="subscription-details">
|
|
191
|
+
<p class="%%{name_class}%%">{{t 'Name'}}: %%{name, "not provided"}%%</p>
|
|
192
|
+
<p>{{t 'Email'}}: <a href="#">%%{email}%%</a></p>
|
|
193
|
+
<p>{{t 'Member since'}}: %%{created_at}%%</p>
|
|
194
|
+
</td>
|
|
195
|
+
<td align="right" valign="bottom" class="manage-subscription">
|
|
196
|
+
<a href="%%{manage_account_url}%%"> {{t 'Manage subscription'}} →</a>
|
|
197
|
+
</td>
|
|
198
|
+
</tr>
|
|
199
|
+
</table>
|
|
200
|
+
</td>
|
|
201
|
+
</tr>
|
|
202
|
+
{{/if}}
|
|
203
|
+
|
|
204
|
+
<tr>
|
|
205
|
+
<td class="wrapper" align="center">
|
|
206
|
+
<table role="presentation" border="0" cellpadding="0" cellspacing="0" width="100%" style="padding-top: 40px; padding-bottom: 30px;">
|
|
207
|
+
{{#if footerContent }}
|
|
208
|
+
<tr><td class="footer">{{{footerContent}}}</td></tr>
|
|
209
|
+
{{/if}}
|
|
210
|
+
<tr>
|
|
211
|
+
<td class="footer">{{site.title}} © {{year}} – <a href="%%{unsubscribe_url}%%">{{t 'Unsubscribe'}}</a></td>
|
|
212
|
+
</tr>
|
|
213
|
+
|
|
214
|
+
{{#if showBadge }}
|
|
215
|
+
<tr>
|
|
216
|
+
<td class="footer-powered"><a href="https://ghost.org/?via=pbg-newsletter"><img src="https://static.ghost.org/v4.0.0/images/powered.png" border="0" width="142" height="30" class="gh-powered" alt="Powered by Ghost"></a></td>
|
|
217
|
+
</tr>
|
|
218
|
+
{{/if}}
|
|
219
|
+
</table>
|
|
220
|
+
</td>
|
|
221
|
+
</tr>
|
|
222
|
+
|
|
223
|
+
</table>
|
|
224
|
+
<!-- END CENTERED WHITE CONTAINER -->
|
|
225
|
+
</div>
|
|
226
|
+
</td>
|
|
227
|
+
<td> </td>
|
|
228
|
+
</tr>
|
|
229
|
+
|
|
230
|
+
<!--[if mso]>
|
|
231
|
+
</table>
|
|
232
|
+
</center>
|
|
233
|
+
</td>
|
|
234
|
+
</tr>
|
|
235
|
+
<![endif]-->
|
|
236
|
+
</table>
|
|
237
|
+
</body>
|
|
238
|
+
</html>
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
module.exports = class EmailBouncedEvent {
|
|
2
|
+
/**
|
|
3
|
+
* @readonly
|
|
4
|
+
* @type {string}
|
|
5
|
+
*/
|
|
6
|
+
id;
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @readonly
|
|
10
|
+
* @type {string}
|
|
11
|
+
*/
|
|
12
|
+
email;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* @readonly
|
|
16
|
+
* @type {string}
|
|
17
|
+
*/
|
|
18
|
+
memberId;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* @readonly
|
|
22
|
+
* @type {string}
|
|
23
|
+
*/
|
|
24
|
+
emailId;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* @readonly
|
|
28
|
+
* @type {{message: string, code: number, enhancedCode: string | null}|null}
|
|
29
|
+
*/
|
|
30
|
+
error;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* @readonly
|
|
34
|
+
* @type {string}
|
|
35
|
+
*/
|
|
36
|
+
emailRecipientId;
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* @readonly
|
|
40
|
+
* @type {Date}
|
|
41
|
+
*/
|
|
42
|
+
timestamp;
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* @private
|
|
46
|
+
*/
|
|
47
|
+
constructor({id, email, memberId, emailId, error, emailRecipientId, timestamp}) {
|
|
48
|
+
this.id = id;
|
|
49
|
+
this.memberId = memberId;
|
|
50
|
+
this.emailId = emailId;
|
|
51
|
+
this.email = email;
|
|
52
|
+
this.error = error;
|
|
53
|
+
this.emailRecipientId = emailRecipientId;
|
|
54
|
+
this.timestamp = timestamp;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
static create(data) {
|
|
58
|
+
return new EmailBouncedEvent({
|
|
59
|
+
...data,
|
|
60
|
+
timestamp: data.timestamp || new Date
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
module.exports = class EmailDeliveredEvent {
|
|
2
|
+
/**
|
|
3
|
+
* @readonly
|
|
4
|
+
* @type {string}
|
|
5
|
+
*/
|
|
6
|
+
email;
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @readonly
|
|
10
|
+
* @type {string}
|
|
11
|
+
*/
|
|
12
|
+
memberId;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* @readonly
|
|
16
|
+
* @type {string}
|
|
17
|
+
*/
|
|
18
|
+
emailId;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* @readonly
|
|
22
|
+
* @type {string}
|
|
23
|
+
*/
|
|
24
|
+
emailRecipientId;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* @readonly
|
|
28
|
+
* @type {Date}
|
|
29
|
+
*/
|
|
30
|
+
timestamp;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* @private
|
|
34
|
+
*/
|
|
35
|
+
constructor({email, memberId, emailId, emailRecipientId, timestamp}) {
|
|
36
|
+
this.email = email;
|
|
37
|
+
this.memberId = memberId;
|
|
38
|
+
this.emailId = emailId;
|
|
39
|
+
this.emailRecipientId = emailRecipientId;
|
|
40
|
+
this.timestamp = timestamp;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
static create(data) {
|
|
44
|
+
return new EmailDeliveredEvent({
|
|
45
|
+
...data,
|
|
46
|
+
timestamp: data.timestamp || new Date
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
module.exports = class EmailOpenedEvent {
|
|
2
|
+
/**
|
|
3
|
+
* @readonly
|
|
4
|
+
* @type {string}
|
|
5
|
+
*/
|
|
6
|
+
email;
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @readonly
|
|
10
|
+
* @type {string}
|
|
11
|
+
*/
|
|
12
|
+
memberId;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* @readonly
|
|
16
|
+
* @type {string}
|
|
17
|
+
*/
|
|
18
|
+
emailId;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* @readonly
|
|
22
|
+
* @type {string}
|
|
23
|
+
*/
|
|
24
|
+
emailRecipientId;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* @readonly
|
|
28
|
+
* @type {Date}
|
|
29
|
+
*/
|
|
30
|
+
timestamp;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* @private
|
|
34
|
+
*/
|
|
35
|
+
constructor({email, memberId, emailId, emailRecipientId, timestamp}) {
|
|
36
|
+
this.memberId = memberId;
|
|
37
|
+
this.emailId = emailId;
|
|
38
|
+
this.emailRecipientId = emailRecipientId;
|
|
39
|
+
this.email = email;
|
|
40
|
+
this.timestamp = timestamp;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
static create(data) {
|
|
44
|
+
return new EmailOpenedEvent({
|
|
45
|
+
...data,
|
|
46
|
+
timestamp: data.timestamp || new Date
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
};
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
module.exports = class EmailTemporaryBouncedEvent {
|
|
2
|
+
/**
|
|
3
|
+
* @readonly
|
|
4
|
+
* @type {string}
|
|
5
|
+
*/
|
|
6
|
+
id;
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @readonly
|
|
10
|
+
* @type {string}
|
|
11
|
+
*/
|
|
12
|
+
email;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* @readonly
|
|
16
|
+
* @type {string}
|
|
17
|
+
*/
|
|
18
|
+
memberId;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* @readonly
|
|
22
|
+
* @type {string}
|
|
23
|
+
*/
|
|
24
|
+
emailId;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* @readonly
|
|
28
|
+
* @type {{message: string, code: number, enhancedCode: string | null}|null}
|
|
29
|
+
*/
|
|
30
|
+
error;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* @readonly
|
|
34
|
+
* @type {string}
|
|
35
|
+
*/
|
|
36
|
+
emailRecipientId;
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* @readonly
|
|
40
|
+
* @type {Date}
|
|
41
|
+
*/
|
|
42
|
+
timestamp;
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* @private
|
|
46
|
+
*/
|
|
47
|
+
constructor({id, email, memberId, emailId, emailRecipientId, error, timestamp}) {
|
|
48
|
+
this.id = id;
|
|
49
|
+
this.memberId = memberId;
|
|
50
|
+
this.emailId = emailId;
|
|
51
|
+
this.email = email;
|
|
52
|
+
this.error = error;
|
|
53
|
+
this.emailRecipientId = emailRecipientId;
|
|
54
|
+
this.timestamp = timestamp;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
static create(data) {
|
|
58
|
+
return new EmailTemporaryBouncedEvent({
|
|
59
|
+
...data,
|
|
60
|
+
timestamp: data.timestamp || new Date
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
module.exports = class EmailUnsubscribedEvent {
|
|
2
|
+
/**
|
|
3
|
+
* @readonly
|
|
4
|
+
* @type {string}
|
|
5
|
+
*/
|
|
6
|
+
email;
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @readonly
|
|
10
|
+
* @type {string}
|
|
11
|
+
*/
|
|
12
|
+
memberId;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* @readonly
|
|
16
|
+
* @type {string}
|
|
17
|
+
*/
|
|
18
|
+
emailId;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* @readonly
|
|
22
|
+
* @type {Date}
|
|
23
|
+
*/
|
|
24
|
+
timestamp;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* @private
|
|
28
|
+
*/
|
|
29
|
+
constructor({email, memberId, emailId, timestamp}) {
|
|
30
|
+
this.memberId = memberId;
|
|
31
|
+
this.emailId = emailId;
|
|
32
|
+
this.email = email;
|
|
33
|
+
this.timestamp = timestamp;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
static create(data) {
|
|
37
|
+
return new EmailUnsubscribedEvent({
|
|
38
|
+
...data,
|
|
39
|
+
timestamp: data.timestamp || new Date
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
module.exports = class SpamComplaintEvent {
|
|
2
|
+
/**
|
|
3
|
+
* @readonly
|
|
4
|
+
* @type {string}
|
|
5
|
+
*/
|
|
6
|
+
email;
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @readonly
|
|
10
|
+
* @type {string}
|
|
11
|
+
*/
|
|
12
|
+
memberId;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* @readonly
|
|
16
|
+
* @type {string}
|
|
17
|
+
*/
|
|
18
|
+
emailId;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* @readonly
|
|
22
|
+
* @type {Date}
|
|
23
|
+
*/
|
|
24
|
+
timestamp;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* @private
|
|
28
|
+
*/
|
|
29
|
+
constructor({email, memberId, emailId, timestamp}) {
|
|
30
|
+
this.memberId = memberId;
|
|
31
|
+
this.emailId = emailId;
|
|
32
|
+
this.email = email;
|
|
33
|
+
this.timestamp = timestamp;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
static create(data) {
|
|
37
|
+
return new SpamComplaintEvent({
|
|
38
|
+
...data,
|
|
39
|
+
timestamp: data.timestamp || new Date
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
};
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
registerHelpers(handlebars, labs, thist) {
|
|
3
|
+
handlebars.registerHelper('if', function (conditional, options) {
|
|
4
|
+
if (conditional) {
|
|
5
|
+
return options.fn(this);
|
|
6
|
+
} else {
|
|
7
|
+
return options.inverse(this);
|
|
8
|
+
}
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
handlebars.registerHelper('and', function () {
|
|
12
|
+
const len = arguments.length - 1;
|
|
13
|
+
|
|
14
|
+
for (let i = 0; i < len; i++) {
|
|
15
|
+
if (!arguments[i]) {
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return true;
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
handlebars.registerHelper('not', function () {
|
|
24
|
+
const len = arguments.length - 1;
|
|
25
|
+
|
|
26
|
+
for (let i = 0; i < len; i++) {
|
|
27
|
+
if (!arguments[i]) {
|
|
28
|
+
return true;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return false;
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
handlebars.registerHelper('or', function () {
|
|
36
|
+
const len = arguments.length - 1;
|
|
37
|
+
|
|
38
|
+
for (let i = 0; i < len; i++) {
|
|
39
|
+
if (arguments[i]) {
|
|
40
|
+
return true;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return false;
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
handlebars.registerHelper('hasFeature', function (flag, options) {
|
|
48
|
+
if (labs.isSet(flag)) {
|
|
49
|
+
return options.fn(this);
|
|
50
|
+
} else {
|
|
51
|
+
return options.inverse(this);
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
handlebars.registerHelper('t', function (key, options) {
|
|
55
|
+
let hash = options?.hash;
|
|
56
|
+
return thist(key, hash || options || {});
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
const {AbstractEmailSuppressionList, EmailSuppressionData, EmailSuppressedEvent} = require('./EmailSuppressionList');
|
|
2
|
-
const
|
|
2
|
+
const SpamComplaintEvent = require('../email-service/events/SpamComplaintEvent');
|
|
3
|
+
const EmailBouncedEvent = require('../email-service/events/EmailBouncedEvent');
|
|
3
4
|
const DomainEvents = require('@tryghost/domain-events');
|
|
4
5
|
const logging = require('@tryghost/logging');
|
|
5
6
|
const models = require('../../models');
|
|
@@ -27,5 +27,6 @@ module.exports.init = async function init() {
|
|
|
27
27
|
|
|
28
28
|
// The final intention is to have this run on a schedule
|
|
29
29
|
// For the initial version, we'll just ping when the server starts
|
|
30
|
-
|
|
30
|
+
// Without waiting for the response
|
|
31
|
+
explorePingService.ping();
|
|
31
32
|
};
|
|
@@ -16,7 +16,7 @@ const messages = {
|
|
|
16
16
|
reason: ' Reason: {reason}.',
|
|
17
17
|
messageSent: 'Message sent. Double check inbox and spam folder!'
|
|
18
18
|
};
|
|
19
|
-
const
|
|
19
|
+
const EmailAddressParser = require('../email-address/EmailAddressParser');
|
|
20
20
|
|
|
21
21
|
function getDomain() {
|
|
22
22
|
const domain = urlUtils.urlFor('home', true).match(new RegExp('^https?://([^/:?#]+)(?:[/:?#]|$)', 'i'));
|
|
@@ -70,8 +70,9 @@ class ExternalMediaInliner {
|
|
|
70
70
|
|
|
71
71
|
/**
|
|
72
72
|
*
|
|
73
|
+
* @param {string} requestURL - url of remote media
|
|
73
74
|
* @param {Object} response - response from request
|
|
74
|
-
* @returns {Object}
|
|
75
|
+
* @returns {Promise<Object>}
|
|
75
76
|
*/
|
|
76
77
|
async extractFileDataFromResponse(requestURL, response) {
|
|
77
78
|
let extension;
|