ghost 6.0.10 → 6.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/components/tryghost-i18n-6.2.0.tgz +0 -0
  2. package/core/built/admin/assets/admin-x-activitypub/admin-x-activitypub.js +1 -1
  3. package/core/built/admin/assets/admin-x-activitypub/{index-wBqnq7A5.mjs → index-DmCoswaX.mjs} +2 -2
  4. package/core/built/admin/assets/admin-x-activitypub/{index-XhNX0QuF.mjs → index-lT95Q15h.mjs} +8212 -8183
  5. package/core/built/admin/assets/admin-x-settings/{CodeEditorView-BDBDWpWl.mjs → CodeEditorView-UxqLGRTu.mjs} +3 -3
  6. package/core/built/admin/assets/admin-x-settings/admin-x-settings.js +1 -1
  7. package/core/built/admin/assets/admin-x-settings/{index-o4Q9MNrB.mjs → index-8WxO2QXI.mjs} +3017 -2827
  8. package/core/built/admin/assets/admin-x-settings/{index-DsbJfrQ7.mjs → index-B5r0jdJS.mjs} +95 -95
  9. package/core/built/admin/assets/admin-x-settings/{index-BB7hgOf0.mjs → index-Co907MFn.mjs} +2 -2
  10. package/core/built/admin/assets/admin-x-settings/{index-BgCSf8S1.mjs → index-DD3HKlR3.mjs} +306 -315
  11. package/core/built/admin/assets/admin-x-settings/{modals-CCpr5VWU.mjs → modals-B7j9sxR4.mjs} +8799 -8807
  12. package/core/built/admin/assets/{chunk.397.e5d027e53a68dff31d76.js → chunk.397.d5e25bb9baf088f52499.js} +2 -2
  13. package/core/built/admin/assets/{chunk.524.695215c994f8cbf547d3.js → chunk.524.70595796c7b8c6003a2d.js} +7 -7
  14. package/core/built/admin/assets/{chunk.582.a949b80543caba37906c.js → chunk.582.d9b970b71da671ac1b7b.js} +8 -8
  15. package/core/built/admin/assets/{ghost-9c608430440a10746540adb7d2cd0f31.js → ghost-2066304fd0b166e1c16d397dd73ef7b2.js} +39 -35
  16. package/core/built/admin/assets/ghost-49475952d56ffe89bd47ab9d9c64ada8.css +1 -0
  17. package/core/built/admin/assets/ghost-dark-27877727751b91f03261d449d74e33b9.css +1 -0
  18. package/core/built/admin/assets/posts/posts.js +27400 -27361
  19. package/core/built/admin/assets/stats/stats.js +28701 -28674
  20. package/core/built/admin/index.html +5 -5
  21. package/core/frontend/public/member-attribution.min.js +1 -1
  22. package/core/server/api/endpoints/search-index.js +2 -2
  23. package/core/server/api/endpoints/stats.js +10 -4
  24. package/core/server/data/migrations/utils/schema.js +11 -6
  25. package/core/server/data/migrations/versions/6.1/2025-09-11-00-38-13-add-uuid-column-to-tokens.js +8 -0
  26. package/core/server/data/migrations/versions/6.1/2025-09-11-00-39-08-backfill-tokens-uuid.js +19 -0
  27. package/core/server/data/migrations/versions/6.1/2025-09-11-00-39-36-tokens-drop-nullable-uuid.js +4 -0
  28. package/core/server/data/migrations/versions/6.2/2025-09-30-14-28-09-add-utm-fields.js +24 -0
  29. package/core/server/data/schema/commands.js +21 -6
  30. package/core/server/data/schema/schema.js +25 -0
  31. package/core/server/data/tinybird/datasources/_mv_hits.datasource +7 -4
  32. package/core/server/data/tinybird/endpoints/api_top_utm_campaigns.pipe +2 -8
  33. package/core/server/data/tinybird/endpoints/api_top_utm_contents.pipe +2 -8
  34. package/core/server/data/tinybird/endpoints/api_top_utm_mediums.pipe +2 -8
  35. package/core/server/data/tinybird/endpoints/api_top_utm_sources.pipe +2 -8
  36. package/core/server/data/tinybird/endpoints/api_top_utm_terms.pipe +2 -8
  37. package/core/server/data/tinybird/fixtures/analytics_events.ndjson +11 -11
  38. package/core/server/data/tinybird/pipes/mv_hits.pipe +12 -2
  39. package/core/server/data/tinybird/pipes/mv_session_data.pipe +16 -6
  40. package/core/server/data/tinybird/tests/api_top_utm_campaigns.yaml +35 -34
  41. package/core/server/data/tinybird/tests/api_top_utm_contents.yaml +57 -48
  42. package/core/server/data/tinybird/tests/api_top_utm_mediums.yaml +40 -38
  43. package/core/server/data/tinybird/tests/api_top_utm_sources.yaml +59 -39
  44. package/core/server/data/tinybird/tests/api_top_utm_terms.yaml +55 -48
  45. package/core/server/models/single-use-token.js +1 -0
  46. package/core/server/services/email-service/EmailRenderer.js +1 -0
  47. package/core/server/services/email-service/email-templates/template.hbs +6 -0
  48. package/core/server/services/lib/MailgunClient.js +4 -3
  49. package/core/server/services/lib/magic-link/MagicLink.js +9 -9
  50. package/core/server/services/mail/GhostMailer.js +4 -1
  51. package/core/server/services/members/MembersConfigProvider.js +0 -15
  52. package/core/server/services/members/SingleUseTokenProvider.js +8 -8
  53. package/core/server/services/members/emails/signin.js +4 -4
  54. package/core/server/services/stats/MrrStatsService.js +10 -5
  55. package/core/server/services/stats/StatsService.js +2 -2
  56. package/core/shared/config/defaults.json +1 -1
  57. package/package.json +9 -9
  58. package/tsconfig.tsbuildinfo +1 -1
  59. package/yarn.lock +1076 -495
  60. package/components/tryghost-i18n-6.0.10.tgz +0 -0
  61. package/core/built/admin/assets/ghost-a7a53bf80dc45c37ae9c174a0d02a882.css +0 -1
  62. package/core/built/admin/assets/ghost-dark-6e0062029f988d8676e87f22d8e7f4a3.css +0 -1
  63. /package/core/built/admin/assets/{chunk.397.e5d027e53a68dff31d76.js.LICENSE.txt → chunk.397.d5e25bb9baf088f52499.js.LICENSE.txt} +0 -0
@@ -1,108 +1,110 @@
1
1
 
2
2
  - name: Date range
3
- description: All fixture data
3
+ description: All fixture data - real UTM mediums from mv_session_data
4
4
  parameters: site_uuid=mock_site_uuid&date_from=2100-01-01&date_to=2100-01-07&timezone=Etc/UTC
5
5
  expected_result: |
6
- {"utm_medium":"email","visits":6}
7
- {"utm_medium":"cpc","visits":3}
8
- {"utm_medium":"organic","visits":3}
9
- {"utm_medium":"referral","visits":3}
6
+ {"utm_medium":"social","visits":5}
7
+ {"utm_medium":"cpc","visits":2}
8
+ {"utm_medium":"organic","visits":1}
9
+ {"utm_medium":"referral","visits":1}
10
10
  {"utm_medium":"display","visits":1}
11
+ {"utm_medium":"email","visits":1}
11
12
 
12
13
  - name: Filtered by browser - Chrome
13
14
  description: Filtered by browser - Chrome
14
15
  parameters: site_uuid=mock_site_uuid&date_from=2100-01-01&date_to=2100-01-07&timezone=Etc/UTC&browser=chrome
15
16
  expected_result: |
16
- {"utm_medium":"email","visits":4}
17
- {"utm_medium":"cpc","visits":1}
17
+ {"utm_medium":"social","visits":2}
18
18
  {"utm_medium":"organic","visits":1}
19
19
  {"utm_medium":"referral","visits":1}
20
+ {"utm_medium":"display","visits":1}
20
21
 
21
22
  - name: Filtered by device - desktop
22
23
  description: Filtered by device - desktop
23
24
  parameters: site_uuid=mock_site_uuid&date_from=2100-01-01&date_to=2100-01-07&timezone=Etc/UTC&device=desktop
24
25
  expected_result: |
25
- {"utm_medium":"email","visits":6}
26
- {"utm_medium":"cpc","visits":3}
27
- {"utm_medium":"referral","visits":3}
28
- {"utm_medium":"organic","visits":2}
26
+ {"utm_medium":"social","visits":5}
27
+ {"utm_medium":"cpc","visits":1}
28
+ {"utm_medium":"organic","visits":1}
29
+ {"utm_medium":"referral","visits":1}
29
30
  {"utm_medium":"display","visits":1}
31
+ {"utm_medium":"email","visits":1}
30
32
 
31
33
  - name: Filtered by location - UK
32
34
  description: Filtered by location - UK
33
35
  parameters: site_uuid=mock_site_uuid&date_from=2100-01-01&date_to=2100-01-07&timezone=Etc/UTC&location=GB
34
36
  expected_result: |
35
- {"utm_medium":"email","visits":3}
36
- {"utm_medium":"organic","visits":2}
37
- {"utm_medium":"referral","visits":2}
38
37
  {"utm_medium":"cpc","visits":1}
38
+ {"utm_medium":"organic","visits":1}
39
+ {"utm_medium":"referral","visits":1}
40
+ {"utm_medium":"social","visits":1}
41
+ {"utm_medium":"display","visits":1}
42
+ {"utm_medium":"email","visits":1}
39
43
 
40
44
  - name: Filtered by OS - Windows
41
45
  description: Filtered by OS - Windows
42
46
  parameters: site_uuid=mock_site_uuid&date_from=2100-01-01&date_to=2100-01-07&timezone=Etc/UTC&os=windows
43
47
  expected_result: |
44
- {"utm_medium":"email","visits":5}
45
- {"utm_medium":"cpc","visits":3}
46
- {"utm_medium":"referral","visits":3}
47
- {"utm_medium":"organic","visits":2}
48
+ {"utm_medium":"social","visits":5}
49
+ {"utm_medium":"cpc","visits":1}
50
+ {"utm_medium":"organic","visits":1}
51
+ {"utm_medium":"referral","visits":1}
48
52
  {"utm_medium":"display","visits":1}
53
+ {"utm_medium":"email","visits":1}
49
54
 
50
55
  - name: Filtered by pathname - /about/
51
56
  description: Filtered by pathname - /about/
52
57
  parameters: site_uuid=mock_site_uuid&date_from=2100-01-01&date_to=2100-01-07&timezone=Etc/UTC&pathname=%2Fabout%2F
53
58
  expected_result: |
54
- {"utm_medium":"email","visits":4}
55
- {"utm_medium":"cpc","visits":2}
56
- {"utm_medium":"organic","visits":1}
59
+ {"utm_medium":"social","visits":3}
57
60
  {"utm_medium":"referral","visits":1}
61
+ {"utm_medium":"display","visits":1}
62
+ {"utm_medium":"email","visits":1}
58
63
 
59
64
  - name: Filtered by post_uuid - 06b1b0c9-fb53-4a15-a060-3db3fde7b1fc (/about/)
60
65
  description: Filtered by post_uuid - 06b1b0c9-fb53-4a15-a060-3db3fde7b1fc (/about/)
61
66
  parameters: site_uuid=mock_site_uuid&date_from=2100-01-01&date_to=2100-01-07&timezone=Etc/UTC&post_uuid=06b1b0c9-fb53-4a15-a060-3db3fde7b1fc
62
67
  expected_result: |
63
- {"utm_medium":"email","visits":4}
64
- {"utm_medium":"cpc","visits":2}
65
- {"utm_medium":"organic","visits":1}
68
+ {"utm_medium":"social","visits":3}
66
69
  {"utm_medium":"referral","visits":1}
70
+ {"utm_medium":"display","visits":1}
71
+ {"utm_medium":"email","visits":1}
67
72
 
68
73
  - name: Filtered by source - bing.com
69
74
  description: Filtered by source - bing.com
70
75
  parameters: site_uuid=mock_site_uuid&date_from=2100-01-01&date_to=2100-01-07&timezone=Etc/UTC&source=bing.com
71
76
  expected_result: |
72
- {"utm_medium":"cpc","visits":2}
77
+ {"utm_medium":"social","visits":1}
78
+ {"utm_medium":"email","visits":1}
73
79
 
74
80
  - name: Filtered by member status - paid
75
81
  description: Filtered by member status - paid
76
82
  parameters: site_uuid=mock_site_uuid&date_from=2100-01-01&date_to=2100-01-07&timezone=Etc/UTC&member_status=paid
77
83
  expected_result: |
78
- {"utm_medium":"referral","visits":2}
79
- {"utm_medium":"email","visits":2}
80
- {"utm_medium":"cpc","visits":1}
84
+ {"utm_medium":"social","visits":2}
85
+ {"utm_medium":"organic","visits":1}
81
86
 
82
87
  - name: Filtered by member status - undefined
83
88
  description: Filtered by member status - undefined
84
89
  parameters: site_uuid=mock_site_uuid&date_from=2100-01-01&date_to=2100-01-07&timezone=Etc/UTC&member_status=undefined
85
90
  expected_result: |
86
- {"utm_medium":"organic","visits":3}
91
+ {"utm_medium":"cpc","visits":2}
87
92
  {"utm_medium":"referral","visits":1}
88
- {"utm_medium":"display","visits":1}
89
- {"utm_medium":"email","visits":1}
93
+ {"utm_medium":"social","visits":1}
90
94
 
91
95
  - name: Filtered by timezone - America/Los_Angeles
92
96
  description: Filtered by timezone - America/Los_Angeles
93
97
  parameters: site_uuid=mock_site_uuid&date_from=2100-01-01&date_to=2100-01-07&timezone=America/Los_Angeles
94
98
  expected_result: |
95
- {"utm_medium":"email","visits":5}
96
- {"utm_medium":"referral","visits":3}
97
- {"utm_medium":"cpc","visits":2}
98
- {"utm_medium":"organic","visits":2}
99
+ {"utm_medium":"social","visits":4}
100
+ {"utm_medium":"cpc","visits":1}
101
+ {"utm_medium":"organic","visits":1}
102
+ {"utm_medium":"referral","visits":1}
99
103
  {"utm_medium":"display","visits":1}
100
104
 
101
105
  - name: Test with multiple filters combined
102
106
  description: Test with multiple filters combined
103
107
  parameters: site_uuid=mock_site_uuid&date_from=2100-01-01&date_to=2100-01-07&timezone=Etc/UTC&device=desktop&browser=firefox
104
108
  expected_result: |
105
- {"utm_medium":"referral","visits":2}
109
+ {"utm_medium":"social","visits":3}
106
110
  {"utm_medium":"cpc","visits":1}
107
- {"utm_medium":"organic","visits":1}
108
- {"utm_medium":"display","visits":1}
@@ -1,108 +1,128 @@
1
1
 
2
2
  - name: Date range
3
- description: All fixture data
3
+ description: All fixture data - real UTM sources from mv_session_data
4
4
  parameters: site_uuid=mock_site_uuid&date_from=2100-01-01&date_to=2100-01-07&timezone=Etc/UTC
5
5
  expected_result: |
6
- {"utm_source":"google","visits":6}
7
- {"utm_source":"linkedin","visits":3}
8
- {"utm_source":"twitter","visits":3}
9
- {"utm_source":"newsletter","visits":3}
6
+ {"utm_source":"google","visits":3}
7
+ {"utm_source":"linkedin","visits":1}
8
+ {"utm_source":"twitter","visits":1}
9
+ {"utm_source":"facebook","visits":1}
10
+ {"utm_source":"bing","visits":1}
11
+ {"utm_source":"reddit","visits":1}
10
12
  {"utm_source":"instagram","visits":1}
13
+ {"utm_source":"partner_site","visits":1}
14
+ {"utm_source":"newsletter","visits":1}
11
15
 
12
16
  - name: Filtered by browser - Chrome
13
17
  description: Filtered by browser - Chrome
14
18
  parameters: site_uuid=mock_site_uuid&date_from=2100-01-01&date_to=2100-01-07&timezone=Etc/UTC&browser=chrome
15
19
  expected_result: |
16
- {"utm_source":"google","visits":4}
17
- {"utm_source":"linkedin","visits":1}
18
- {"utm_source":"twitter","visits":1}
19
- {"utm_source":"newsletter","visits":1}
20
+ {"utm_source":"google","visits":1}
21
+ {"utm_source":"facebook","visits":1}
22
+ {"utm_source":"bing","visits":1}
23
+ {"utm_source":"instagram","visits":1}
24
+ {"utm_source":"partner_site","visits":1}
20
25
 
21
26
  - name: Filtered by device - desktop
22
27
  description: Filtered by device - desktop
23
28
  parameters: site_uuid=mock_site_uuid&date_from=2100-01-01&date_to=2100-01-07&timezone=Etc/UTC&device=desktop
24
29
  expected_result: |
25
- {"utm_source":"google","visits":6}
26
- {"utm_source":"twitter","visits":3}
27
- {"utm_source":"newsletter","visits":3}
28
- {"utm_source":"linkedin","visits":2}
30
+ {"utm_source":"google","visits":2}
31
+ {"utm_source":"linkedin","visits":1}
32
+ {"utm_source":"twitter","visits":1}
33
+ {"utm_source":"facebook","visits":1}
34
+ {"utm_source":"bing","visits":1}
35
+ {"utm_source":"reddit","visits":1}
29
36
  {"utm_source":"instagram","visits":1}
37
+ {"utm_source":"partner_site","visits":1}
38
+ {"utm_source":"newsletter","visits":1}
30
39
 
31
40
  - name: Filtered by location - UK
32
41
  description: Filtered by location - UK
33
42
  parameters: site_uuid=mock_site_uuid&date_from=2100-01-01&date_to=2100-01-07&timezone=Etc/UTC&location=GB
34
43
  expected_result: |
35
- {"utm_source":"google","visits":3}
36
- {"utm_source":"linkedin","visits":2}
37
- {"utm_source":"newsletter","visits":2}
44
+ {"utm_source":"google","visits":2}
38
45
  {"utm_source":"twitter","visits":1}
46
+ {"utm_source":"bing","visits":1}
47
+ {"utm_source":"partner_site","visits":1}
48
+ {"utm_source":"newsletter","visits":1}
39
49
 
40
50
  - name: Filtered by OS - Windows
41
51
  description: Filtered by OS - Windows
42
52
  parameters: site_uuid=mock_site_uuid&date_from=2100-01-01&date_to=2100-01-07&timezone=Etc/UTC&os=windows
43
53
  expected_result: |
44
- {"utm_source":"google","visits":5}
45
- {"utm_source":"twitter","visits":3}
46
- {"utm_source":"newsletter","visits":3}
47
- {"utm_source":"linkedin","visits":2}
54
+ {"utm_source":"google","visits":2}
55
+ {"utm_source":"linkedin","visits":1}
56
+ {"utm_source":"twitter","visits":1}
57
+ {"utm_source":"facebook","visits":1}
58
+ {"utm_source":"bing","visits":1}
59
+ {"utm_source":"reddit","visits":1}
48
60
  {"utm_source":"instagram","visits":1}
61
+ {"utm_source":"partner_site","visits":1}
62
+ {"utm_source":"newsletter","visits":1}
49
63
 
50
64
  - name: Filtered by pathname - /about/
51
65
  description: Filtered by pathname - /about/
52
66
  parameters: site_uuid=mock_site_uuid&date_from=2100-01-01&date_to=2100-01-07&timezone=Etc/UTC&pathname=%2Fabout%2F
53
67
  expected_result: |
54
- {"utm_source":"google","visits":4}
55
- {"utm_source":"twitter","visits":2}
56
- {"utm_source":"linkedin","visits":1}
68
+ {"utm_source":"twitter","visits":1}
69
+ {"utm_source":"bing","visits":1}
70
+ {"utm_source":"reddit","visits":1}
71
+ {"utm_source":"instagram","visits":1}
72
+ {"utm_source":"partner_site","visits":1}
57
73
  {"utm_source":"newsletter","visits":1}
58
74
 
59
75
  - name: Filtered by post_uuid - 06b1b0c9-fb53-4a15-a060-3db3fde7b1fc (/about/)
60
76
  description: Filtered by post_uuid - 06b1b0c9-fb53-4a15-a060-3db3fde7b1fc (/about/)
61
77
  parameters: site_uuid=mock_site_uuid&date_from=2100-01-01&date_to=2100-01-07&timezone=Etc/UTC&post_uuid=06b1b0c9-fb53-4a15-a060-3db3fde7b1fc
62
78
  expected_result: |
63
- {"utm_source":"google","visits":4}
64
- {"utm_source":"twitter","visits":2}
65
- {"utm_source":"linkedin","visits":1}
79
+ {"utm_source":"twitter","visits":1}
80
+ {"utm_source":"bing","visits":1}
81
+ {"utm_source":"reddit","visits":1}
82
+ {"utm_source":"instagram","visits":1}
83
+ {"utm_source":"partner_site","visits":1}
66
84
  {"utm_source":"newsletter","visits":1}
67
85
 
68
86
  - name: Filtered by source - bing.com
69
87
  description: Filtered by source - bing.com
70
88
  parameters: site_uuid=mock_site_uuid&date_from=2100-01-01&date_to=2100-01-07&timezone=Etc/UTC&source=bing.com
71
89
  expected_result: |
72
- {"utm_source":"twitter","visits":2}
90
+ {"utm_source":"instagram","visits":1}
91
+ {"utm_source":"newsletter","visits":1}
73
92
 
74
93
  - name: Filtered by member status - paid
75
94
  description: Filtered by member status - paid
76
95
  parameters: site_uuid=mock_site_uuid&date_from=2100-01-01&date_to=2100-01-07&timezone=Etc/UTC&member_status=paid
77
96
  expected_result: |
78
- {"utm_source":"google","visits":2}
79
- {"utm_source":"newsletter","visits":2}
80
97
  {"utm_source":"twitter","visits":1}
98
+ {"utm_source":"google","visits":1}
99
+ {"utm_source":"instagram","visits":1}
81
100
 
82
101
  - name: Filtered by member status - undefined
83
102
  description: Filtered by member status - undefined
84
103
  parameters: site_uuid=mock_site_uuid&date_from=2100-01-01&date_to=2100-01-07&timezone=Etc/UTC&member_status=undefined
85
104
  expected_result: |
86
- {"utm_source":"linkedin","visits":3}
87
- {"utm_source":"google","visits":1}
88
- {"utm_source":"instagram","visits":1}
89
- {"utm_source":"newsletter","visits":1}
105
+ {"utm_source":"google","visits":2}
106
+ {"utm_source":"reddit","visits":1}
107
+ {"utm_source":"partner_site","visits":1}
90
108
 
91
109
  - name: Filtered by timezone - America/Los_Angeles
92
110
  description: Filtered by timezone - America/Los_Angeles
93
111
  parameters: site_uuid=mock_site_uuid&date_from=2100-01-01&date_to=2100-01-07&timezone=America/Los_Angeles
94
112
  expected_result: |
95
- {"utm_source":"google","visits":5}
96
- {"utm_source":"newsletter","visits":3}
97
- {"utm_source":"linkedin","visits":2}
98
- {"utm_source":"twitter","visits":2}
113
+ {"utm_source":"google","visits":2}
114
+ {"utm_source":"linkedin","visits":1}
115
+ {"utm_source":"twitter","visits":1}
116
+ {"utm_source":"bing","visits":1}
117
+ {"utm_source":"reddit","visits":1}
99
118
  {"utm_source":"instagram","visits":1}
119
+ {"utm_source":"partner_site","visits":1}
100
120
 
101
121
  - name: Test with multiple filters combined
102
122
  description: Test with multiple filters combined
103
123
  parameters: site_uuid=mock_site_uuid&date_from=2100-01-01&date_to=2100-01-07&timezone=Etc/UTC&device=desktop&browser=firefox
104
124
  expected_result: |
105
- {"utm_source":"newsletter","visits":2}
106
125
  {"utm_source":"linkedin","visits":1}
107
126
  {"utm_source":"twitter","visits":1}
108
- {"utm_source":"instagram","visits":1}
127
+ {"utm_source":"google","visits":1}
128
+ {"utm_source":"reddit","visits":1}
@@ -3,106 +3,113 @@
3
3
  description: All fixture data
4
4
  parameters: site_uuid=mock_site_uuid&date_from=2100-01-01&date_to=2100-01-07&timezone=Etc/UTC
5
5
  expected_result: |
6
- {"utm_term":"ghost cms","visits":6}
7
- {"utm_term":"blog software","visits":3}
8
- {"utm_term":"content management","visits":3}
9
- {"utm_term":"newsletter platform","visits":3}
10
- {"utm_term":"membership site","visits":1}
6
+ {"utm_term":"discount","visits":1}
7
+ {"utm_term":"ghost_blog","visits":1}
8
+ {"utm_term":"subscribers","visits":1}
9
+ {"utm_term":"loyal_customers","visits":1}
10
+ {"utm_term":"black_friday","visits":1}
11
+ {"utm_term":"new_feature","visits":1}
12
+ {"utm_term":"announcement","visits":1}
11
13
 
12
14
  - name: Filtered by browser - Chrome
13
15
  description: Filtered by browser - Chrome
14
16
  parameters: site_uuid=mock_site_uuid&date_from=2100-01-01&date_to=2100-01-07&timezone=Etc/UTC&browser=chrome
15
17
  expected_result: |
16
- {"utm_term":"ghost cms","visits":4}
17
- {"utm_term":"blog software","visits":1}
18
- {"utm_term":"content management","visits":1}
19
- {"utm_term":"newsletter platform","visits":1}
18
+ {"utm_term":"discount","visits":1}
19
+ {"utm_term":"ghost_blog","visits":1}
20
+ {"utm_term":"loyal_customers","visits":1}
20
21
 
21
22
  - name: Filtered by device - desktop
22
23
  description: Filtered by device - desktop
23
24
  parameters: site_uuid=mock_site_uuid&date_from=2100-01-01&date_to=2100-01-07&timezone=Etc/UTC&device=desktop
24
25
  expected_result: |
25
- {"utm_term":"ghost cms","visits":6}
26
- {"utm_term":"blog software","visits":3}
27
- {"utm_term":"content management","visits":3}
28
- {"utm_term":"newsletter platform","visits":2}
29
- {"utm_term":"membership site","visits":1}
26
+ {"utm_term":"discount","visits":1}
27
+ {"utm_term":"ghost_blog","visits":1}
28
+ {"utm_term":"subscribers","visits":1}
29
+ {"utm_term":"loyal_customers","visits":1}
30
+ {"utm_term":"black_friday","visits":1}
31
+ {"utm_term":"new_feature","visits":1}
32
+ {"utm_term":"announcement","visits":1}
30
33
 
31
34
  - name: Filtered by location - UK
32
35
  description: Filtered by location - UK
33
36
  parameters: site_uuid=mock_site_uuid&date_from=2100-01-01&date_to=2100-01-07&timezone=Etc/UTC&location=GB
34
37
  expected_result: |
35
- {"utm_term":"ghost cms","visits":3}
36
- {"utm_term":"blog software","visits":2}
37
- {"utm_term":"newsletter platform","visits":2}
38
- {"utm_term":"content management","visits":1}
38
+ {"utm_term":"discount","visits":1}
39
+ {"utm_term":"ghost_blog","visits":1}
40
+ {"utm_term":"subscribers","visits":1}
41
+ {"utm_term":"new_feature","visits":1}
39
42
 
40
43
  - name: Filtered by OS - Windows
41
44
  description: Filtered by OS - Windows
42
45
  parameters: site_uuid=mock_site_uuid&date_from=2100-01-01&date_to=2100-01-07&timezone=Etc/UTC&os=windows
43
46
  expected_result: |
44
- {"utm_term":"ghost cms","visits":5}
45
- {"utm_term":"blog software","visits":3}
46
- {"utm_term":"content management","visits":3}
47
- {"utm_term":"newsletter platform","visits":2}
48
- {"utm_term":"membership site","visits":1}
47
+ {"utm_term":"discount","visits":1}
48
+ {"utm_term":"ghost_blog","visits":1}
49
+ {"utm_term":"subscribers","visits":1}
50
+ {"utm_term":"loyal_customers","visits":1}
51
+ {"utm_term":"black_friday","visits":1}
52
+ {"utm_term":"new_feature","visits":1}
53
+ {"utm_term":"announcement","visits":1}
49
54
 
50
55
  - name: Filtered by pathname - /about/
51
56
  description: Filtered by pathname - /about/
52
57
  parameters: site_uuid=mock_site_uuid&date_from=2100-01-01&date_to=2100-01-07&timezone=Etc/UTC&pathname=%2Fabout%2F
53
58
  expected_result: |
54
- {"utm_term":"ghost cms","visits":4}
55
- {"utm_term":"content management","visits":2}
56
- {"utm_term":"blog software","visits":1}
57
- {"utm_term":"newsletter platform","visits":1}
59
+ {"utm_term":"discount","visits":1}
60
+ {"utm_term":"subscribers","visits":1}
61
+ {"utm_term":"loyal_customers","visits":1}
62
+ {"utm_term":"new_feature","visits":1}
63
+ {"utm_term":"announcement","visits":1}
58
64
 
59
65
  - name: Filtered by post_uuid - 06b1b0c9-fb53-4a15-a060-3db3fde7b1fc (/about/)
60
66
  description: Filtered by post_uuid - 06b1b0c9-fb53-4a15-a060-3db3fde7b1fc (/about/)
61
67
  parameters: site_uuid=mock_site_uuid&date_from=2100-01-01&date_to=2100-01-07&timezone=Etc/UTC&post_uuid=06b1b0c9-fb53-4a15-a060-3db3fde7b1fc
62
68
  expected_result: |
63
- {"utm_term":"ghost cms","visits":4}
64
- {"utm_term":"content management","visits":2}
65
- {"utm_term":"blog software","visits":1}
66
- {"utm_term":"newsletter platform","visits":1}
69
+ {"utm_term":"discount","visits":1}
70
+ {"utm_term":"subscribers","visits":1}
71
+ {"utm_term":"loyal_customers","visits":1}
72
+ {"utm_term":"new_feature","visits":1}
73
+ {"utm_term":"announcement","visits":1}
67
74
 
68
75
  - name: Filtered by source - bing.com
69
76
  description: Filtered by source - bing.com
70
77
  parameters: site_uuid=mock_site_uuid&date_from=2100-01-01&date_to=2100-01-07&timezone=Etc/UTC&source=bing.com
71
78
  expected_result: |
72
- {"utm_term":"content management","visits":2}
79
+ {"utm_term":"subscribers","visits":1}
80
+ {"utm_term":"loyal_customers","visits":1}
73
81
 
74
82
  - name: Filtered by member status - paid
75
83
  description: Filtered by member status - paid
76
84
  parameters: site_uuid=mock_site_uuid&date_from=2100-01-01&date_to=2100-01-07&timezone=Etc/UTC&member_status=paid
77
85
  expected_result: |
78
- {"utm_term":"blog software","visits":2}
79
- {"utm_term":"ghost cms","visits":2}
80
- {"utm_term":"content management","visits":1}
86
+ {"utm_term":"ghost_blog","visits":1}
87
+ {"utm_term":"loyal_customers","visits":1}
88
+ {"utm_term":"new_feature","visits":1}
81
89
 
82
90
  - name: Filtered by member status - undefined
83
91
  description: Filtered by member status - undefined
84
92
  parameters: site_uuid=mock_site_uuid&date_from=2100-01-01&date_to=2100-01-07&timezone=Etc/UTC&member_status=undefined
85
93
  expected_result: |
86
- {"utm_term":"newsletter platform","visits":3}
87
- {"utm_term":"blog software","visits":1}
88
- {"utm_term":"membership site","visits":1}
89
- {"utm_term":"ghost cms","visits":1}
94
+ {"utm_term":"discount","visits":1}
95
+ {"utm_term":"black_friday","visits":1}
96
+ {"utm_term":"announcement","visits":1}
90
97
 
91
98
  - name: Filtered by timezone - America/Los_Angeles
92
99
  description: Filtered by timezone - America/Los_Angeles
93
100
  parameters: site_uuid=mock_site_uuid&date_from=2100-01-01&date_to=2100-01-07&timezone=America/Los_Angeles
94
101
  expected_result: |
95
- {"utm_term":"ghost cms","visits":5}
96
- {"utm_term":"blog software","visits":3}
97
- {"utm_term":"content management","visits":2}
98
- {"utm_term":"newsletter platform","visits":2}
99
- {"utm_term":"membership site","visits":1}
102
+ {"utm_term":"discount","visits":1}
103
+ {"utm_term":"ghost_blog","visits":1}
104
+ {"utm_term":"loyal_customers","visits":1}
105
+ {"utm_term":"black_friday","visits":1}
106
+ {"utm_term":"new_feature","visits":1}
107
+ {"utm_term":"announcement","visits":1}
100
108
 
101
109
  - name: Test with multiple filters combined
102
110
  description: Test with multiple filters combined
103
111
  parameters: site_uuid=mock_site_uuid&date_from=2100-01-01&date_to=2100-01-07&timezone=Etc/UTC&device=desktop&browser=firefox
104
112
  expected_result: |
105
- {"utm_term":"blog software","visits":2}
106
- {"utm_term":"membership site","visits":1}
107
- {"utm_term":"content management","visits":1}
108
- {"utm_term":"newsletter platform","visits":1}
113
+ {"utm_term":"black_friday","visits":1}
114
+ {"utm_term":"new_feature","visits":1}
115
+ {"utm_term":"announcement","visits":1}
@@ -7,6 +7,7 @@ const SingleUseToken = ghostBookshelf.Model.extend({
7
7
  defaults() {
8
8
  return {
9
9
  used_count: 0,
10
+ uuid: crypto.randomUUID(),
10
11
  token: crypto
11
12
  .randomBytes(192 / 8)
12
13
  .toString('base64')
@@ -1241,6 +1241,7 @@ class EmailRenderer {
1241
1241
  }, true) : null
1242
1242
  },
1243
1243
  preheader: this.#getEmailPreheader(post, segment, html),
1244
+ preheaderSpacing: `${' ͏ '.repeat(150)}${'­ '.repeat(200)}  `,
1244
1245
  html,
1245
1246
 
1246
1247
  post: {
@@ -9,6 +9,12 @@
9
9
  </head>
10
10
  <body>
11
11
  <span class="preheader">{{preheader}}</span>
12
+ {{#hasFeature 'emailCustomization'}}
13
+ <!-- SPACING TO AVOID BODY TEXT BEING DUPLICATED IN PREVIEW TEXT -->
14
+ <div style="display:none; max-height:0; overflow:hidden; mso-hide: all;" aria-hidden="true" role="presentation">
15
+ {{{preheaderSpacing}}}
16
+ </div>
17
+ {{/hasFeature}}
12
18
 
13
19
  <!-- HEADER WITH FULL-WIDTH BACKGROUND -->
14
20
  {{#if hasHeaderContent}}
@@ -67,7 +67,8 @@ module.exports = class MailgunClient {
67
67
  subject: messageContent.subject,
68
68
  html: messageContent.html,
69
69
  text: messageContent.plaintext,
70
- 'recipient-variables': JSON.stringify(recipientData)
70
+ 'recipient-variables': JSON.stringify(recipientData),
71
+ 'h:Sender': message.from
71
72
  };
72
73
 
73
74
  // Do we have a custom List-Unsubscribe header set?
@@ -348,9 +349,9 @@ module.exports = class MailgunClient {
348
349
  /**
349
350
  * Returns the configured target delivery window in seconds
350
351
  * Ghost will attempt to deliver emails evenly distributed over this window
351
- *
352
+ *
352
353
  * Defaults to 0 (no delay) if not set
353
- *
354
+ *
354
355
  * @returns {number}
355
356
  */
356
357
  getTargetDeliveryWindow() {
@@ -23,7 +23,7 @@ const messages = {
23
23
  * @typedef {Object} TokenProvider<T, D>
24
24
  * @prop {(data: D) => Promise<T>} create
25
25
  * @prop {(token: T, options?: TokenValidateOptions) => Promise<D>} validate
26
- * @prop {(token: T) => Promise<string | null>} [getIdByToken]
26
+ * @prop {(token: T) => Promise<string | null>} [getRefByToken]
27
27
  * @prop {(otcRef: string, tokenValue: T) => string} [deriveOTC]
28
28
  */
29
29
 
@@ -108,7 +108,7 @@ class MagicLink {
108
108
  let otcRef = null;
109
109
  if (this.labsService?.isSet('membersSigninOTC') && otc) {
110
110
  try {
111
- otcRef = await this.getIdFromToken(token);
111
+ otcRef = await this.getRefFromToken(token);
112
112
  } catch (err) {
113
113
  this.sentry?.captureException?.(err);
114
114
  otcRef = null;
@@ -135,17 +135,17 @@ class MagicLink {
135
135
  }
136
136
 
137
137
  /**
138
- * getIdFromToken
138
+ * getRefFromToken
139
139
  *
140
- * @param {Token} token - The token to get the id from
141
- * @returns {Promise<string|null>} id - The id of the token
140
+ * @param {Token} token - The token to get the ref from
141
+ * @returns {Promise<string|null>} ref - The ref of the token
142
142
  */
143
- async getIdFromToken(token) {
144
- if (typeof this.tokenProvider.getIdByToken !== 'function') {
143
+ async getRefFromToken(token) {
144
+ if (typeof this.tokenProvider.getRefByToken !== 'function') {
145
145
  return null;
146
146
  }
147
147
 
148
- const id = await this.tokenProvider.getIdByToken(token);
148
+ const id = await this.tokenProvider.getRefByToken(token);
149
149
  return id;
150
150
  }
151
151
 
@@ -156,7 +156,7 @@ class MagicLink {
156
156
  * @returns {Promise<string|null>} otc - The otc of the token
157
157
  */
158
158
  async getOTCFromToken(token) {
159
- const tokenId = await this.getIdFromToken(token);
159
+ const tokenId = await this.getRefFromToken(token);
160
160
 
161
161
  if (!tokenId || typeof this.tokenProvider.deriveOTC !== 'function') {
162
162
  return null;
@@ -68,7 +68,10 @@ function createMessage(message) {
68
68
  ...message,
69
69
  ...addresses,
70
70
  generateTextFromHTML,
71
- encoding
71
+ encoding,
72
+ headers: {
73
+ Sender: addresses.from
74
+ }
72
75
  };
73
76
  }
74
77
 
@@ -1,6 +1,5 @@
1
1
  const logging = require('@tryghost/logging');
2
2
  const {URL} = require('url');
3
- const crypto = require('crypto');
4
3
  const createKeypair = require('keypair');
5
4
 
6
5
  class MembersConfigProvider {
@@ -42,20 +41,6 @@ class MembersConfigProvider {
42
41
  return this._settingsHelpers.isStripeConnected();
43
42
  }
44
43
 
45
- getAuthSecret() {
46
- const hexSecret = this._settingsCache.get('members_email_auth_secret');
47
- if (!hexSecret) {
48
- logging.warn('Could not find members_email_auth_secret, using dynamically generated secret');
49
- return crypto.randomBytes(64);
50
- }
51
- const secret = Buffer.from(hexSecret, 'hex');
52
- if (secret.length < 64) {
53
- logging.warn('members_email_auth_secret not large enough (64 bytes), using dynamically generated secret');
54
- return crypto.randomBytes(64);
55
- }
56
- return secret;
57
- }
58
-
59
44
  getAllowSelfSignup() {
60
45
  // Free signups are allowed only if the site subscription is set to "Full-access"
61
46
  // It is blocked for "Invite-only", "Paid-members-only" and "None" accesses