ghost 5.58.0 → 5.59.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.
Files changed (190) hide show
  1. package/components/tryghost-adapter-cache-memory-ttl-5.59.1.tgz +0 -0
  2. package/components/tryghost-adapter-cache-redis-5.59.1.tgz +0 -0
  3. package/components/tryghost-adapter-manager-5.59.1.tgz +0 -0
  4. package/components/tryghost-announcement-bar-settings-5.59.1.tgz +0 -0
  5. package/components/{tryghost-api-framework-5.58.0.tgz → tryghost-api-framework-5.59.1.tgz} +0 -0
  6. package/components/tryghost-api-version-compatibility-service-5.59.1.tgz +0 -0
  7. package/components/tryghost-audience-feedback-5.59.1.tgz +0 -0
  8. package/components/tryghost-bootstrap-socket-5.59.1.tgz +0 -0
  9. package/components/tryghost-collections-5.59.1.tgz +0 -0
  10. package/components/tryghost-constants-5.59.1.tgz +0 -0
  11. package/components/tryghost-custom-theme-settings-service-5.59.1.tgz +0 -0
  12. package/components/tryghost-data-generator-5.59.1.tgz +0 -0
  13. package/components/tryghost-domain-events-5.59.1.tgz +0 -0
  14. package/components/tryghost-donations-5.59.1.tgz +0 -0
  15. package/components/tryghost-dynamic-routing-events-5.59.1.tgz +0 -0
  16. package/components/tryghost-email-analytics-provider-mailgun-5.59.1.tgz +0 -0
  17. package/components/tryghost-email-analytics-service-5.59.1.tgz +0 -0
  18. package/components/tryghost-email-content-generator-5.59.1.tgz +0 -0
  19. package/components/tryghost-email-events-5.59.1.tgz +0 -0
  20. package/components/tryghost-email-service-5.59.1.tgz +0 -0
  21. package/components/tryghost-email-suppression-list-5.59.1.tgz +0 -0
  22. package/components/tryghost-event-aware-cache-wrapper-5.59.1.tgz +0 -0
  23. package/components/tryghost-express-dynamic-redirects-5.59.1.tgz +0 -0
  24. package/components/tryghost-external-media-inliner-5.59.1.tgz +0 -0
  25. package/components/tryghost-extract-api-key-5.59.1.tgz +0 -0
  26. package/components/tryghost-html-to-plaintext-5.59.1.tgz +0 -0
  27. package/components/tryghost-i18n-5.59.1.tgz +0 -0
  28. package/components/tryghost-importer-handler-content-files-5.59.1.tgz +0 -0
  29. package/components/{tryghost-importer-revue-5.58.0.tgz → tryghost-importer-revue-5.59.1.tgz} +0 -0
  30. package/components/tryghost-in-memory-repository-5.59.1.tgz +0 -0
  31. package/components/tryghost-job-manager-5.59.1.tgz +0 -0
  32. package/components/tryghost-link-redirects-5.59.1.tgz +0 -0
  33. package/components/tryghost-link-replacer-5.59.1.tgz +0 -0
  34. package/components/tryghost-link-tracking-5.59.1.tgz +0 -0
  35. package/components/tryghost-magic-link-5.59.1.tgz +0 -0
  36. package/components/tryghost-mail-events-5.59.1.tgz +0 -0
  37. package/components/tryghost-mailgun-client-5.59.1.tgz +0 -0
  38. package/components/tryghost-member-attribution-5.59.1.tgz +0 -0
  39. package/components/tryghost-member-events-5.59.1.tgz +0 -0
  40. package/components/tryghost-members-api-5.59.1.tgz +0 -0
  41. package/components/tryghost-members-csv-5.59.1.tgz +0 -0
  42. package/components/tryghost-members-events-service-5.59.1.tgz +0 -0
  43. package/components/tryghost-members-importer-5.59.1.tgz +0 -0
  44. package/components/tryghost-members-offers-5.59.1.tgz +0 -0
  45. package/components/tryghost-members-payments-5.59.1.tgz +0 -0
  46. package/components/tryghost-members-ssr-5.59.1.tgz +0 -0
  47. package/components/tryghost-members-stripe-service-5.59.1.tgz +0 -0
  48. package/components/tryghost-mentions-email-report-5.59.1.tgz +0 -0
  49. package/components/tryghost-milestones-5.59.1.tgz +0 -0
  50. package/components/tryghost-minifier-5.59.1.tgz +0 -0
  51. package/components/tryghost-model-to-domain-event-interceptor-5.59.1.tgz +0 -0
  52. package/components/tryghost-mw-api-version-mismatch-5.59.1.tgz +0 -0
  53. package/components/tryghost-mw-cache-control-5.59.1.tgz +0 -0
  54. package/components/{tryghost-mw-error-handler-5.58.0.tgz → tryghost-mw-error-handler-5.59.1.tgz} +0 -0
  55. package/components/tryghost-mw-session-from-token-5.59.1.tgz +0 -0
  56. package/components/tryghost-mw-update-user-last-seen-5.59.1.tgz +0 -0
  57. package/components/tryghost-mw-version-match-5.59.1.tgz +0 -0
  58. package/components/tryghost-mw-vhost-5.59.1.tgz +0 -0
  59. package/components/tryghost-nql-filter-expansions-5.59.1.tgz +0 -0
  60. package/components/tryghost-oembed-service-5.59.1.tgz +0 -0
  61. package/components/tryghost-package-json-5.59.1.tgz +0 -0
  62. package/components/tryghost-post-events-5.59.1.tgz +0 -0
  63. package/components/tryghost-post-revisions-5.59.1.tgz +0 -0
  64. package/components/tryghost-posts-service-5.59.1.tgz +0 -0
  65. package/components/{tryghost-referrers-5.58.0.tgz → tryghost-referrers-5.59.1.tgz} +0 -0
  66. package/components/tryghost-security-5.59.1.tgz +0 -0
  67. package/components/tryghost-session-service-5.59.1.tgz +0 -0
  68. package/components/tryghost-settings-path-manager-5.59.1.tgz +0 -0
  69. package/components/tryghost-slack-notifications-5.59.1.tgz +0 -0
  70. package/components/tryghost-staff-service-5.59.1.tgz +0 -0
  71. package/components/tryghost-stats-service-5.59.1.tgz +0 -0
  72. package/components/{tryghost-tiers-5.58.0.tgz → tryghost-tiers-5.59.1.tgz} +0 -0
  73. package/components/tryghost-update-check-service-5.59.1.tgz +0 -0
  74. package/components/tryghost-verification-trigger-5.59.1.tgz +0 -0
  75. package/components/tryghost-version-notifications-data-service-5.59.1.tgz +0 -0
  76. package/components/tryghost-webmentions-5.59.1.tgz +0 -0
  77. package/content/themes/casper/LICENSE +1 -1
  78. package/content/themes/casper/README.md +1 -1
  79. package/core/built/admin/assets/{chunk.143.5173fd8491cb28bc6a86.js → chunk.143.361ded5611b0566d5e16.js} +5 -5
  80. package/core/built/admin/assets/{chunk.178.614c6ff2742bab9c6c84.js → chunk.178.a8572507a943599b5c65.js} +4 -4
  81. package/core/built/admin/assets/{chunk.757.ada6ed049fa8078cd416.js → chunk.757.ebdeaa01b967d376207e.js} +2832 -2816
  82. package/core/built/admin/assets/{ghost-1ab7ddfda5747da72ff210c8e4a68d6a.js → ghost-44831979758d416ac112014cc3606e48.js} +150 -113
  83. package/core/built/admin/assets/ghost-8b4c354fc3f7c2d3cf40ddae14796922.css +1 -0
  84. package/core/built/admin/assets/ghost-dark-3bed080c4d9acf9f36adaa804c7c7bbd.css +1 -0
  85. package/core/built/admin/assets/{vendor-16709e2a05d1300febb44b2e8f759976.js → vendor-fff5b0b3c122441beb3170947ae27b9d.js} +1894 -1889
  86. package/core/built/admin/index.html +6 -6
  87. package/core/frontend/apps/amp/lib/views/amp.hbs +2 -2
  88. package/core/frontend/helpers/ghost_head.js +3 -1
  89. package/core/frontend/services/data/checks.js +5 -0
  90. package/core/frontend/services/proxy.js +3 -3
  91. package/core/frontend/services/rendering/format-response.js +24 -1
  92. package/core/frontend/services/rendering/render-entries.js +1 -1
  93. package/core/frontend/services/routing/controllers/static.js +1 -1
  94. package/core/frontend/src/cards/css/bookmark.css +3 -3
  95. package/core/frontend/src/cards/css/header_v2.css +6 -2
  96. package/core/server/api/endpoints/pages.js +1 -0
  97. package/core/server/api/endpoints/posts.js +1 -0
  98. package/core/server/api/endpoints/utils/serializers/input/settings.js +3 -1
  99. package/core/server/api/endpoints/utils/serializers/output/utils/clean.js +1 -0
  100. package/core/server/data/migrations/versions/5.59/2023-08-07-10-42-add-donation-notifications-column.js +7 -0
  101. package/core/server/data/migrations/versions/5.59/2023-08-07-11-17-05-add-posts-published-at-index.js +51 -0
  102. package/core/server/data/schema/fixtures/fixtures.json +1 -0
  103. package/core/server/data/schema/schema.js +2 -1
  104. package/core/server/models/collection-post.js +9 -0
  105. package/core/server/models/collection.js +6 -0
  106. package/core/server/models/post.js +14 -1
  107. package/core/server/models/user.js +4 -1
  108. package/core/server/services/collections/BookshelfCollectionsRepository.js +4 -4
  109. package/core/server/services/members/api.js +1 -0
  110. package/core/server/services/settings/settings-service.js +1 -0
  111. package/core/server/services/settings-helpers/SettingsHelpers.js +4 -0
  112. package/core/server/services/stripe/service.js +3 -1
  113. package/core/shared/config/defaults.json +2 -2
  114. package/core/shared/labs.js +2 -2
  115. package/package.json +159 -158
  116. package/yarn.lock +1356 -837
  117. package/components/tryghost-adapter-cache-memory-ttl-5.58.0.tgz +0 -0
  118. package/components/tryghost-adapter-cache-redis-5.58.0.tgz +0 -0
  119. package/components/tryghost-adapter-manager-5.58.0.tgz +0 -0
  120. package/components/tryghost-announcement-bar-settings-5.58.0.tgz +0 -0
  121. package/components/tryghost-api-version-compatibility-service-5.58.0.tgz +0 -0
  122. package/components/tryghost-audience-feedback-5.58.0.tgz +0 -0
  123. package/components/tryghost-bootstrap-socket-5.58.0.tgz +0 -0
  124. package/components/tryghost-collections-5.58.0.tgz +0 -0
  125. package/components/tryghost-constants-5.58.0.tgz +0 -0
  126. package/components/tryghost-custom-theme-settings-service-5.58.0.tgz +0 -0
  127. package/components/tryghost-data-generator-5.58.0.tgz +0 -0
  128. package/components/tryghost-domain-events-5.58.0.tgz +0 -0
  129. package/components/tryghost-donations-5.58.0.tgz +0 -0
  130. package/components/tryghost-dynamic-routing-events-5.58.0.tgz +0 -0
  131. package/components/tryghost-email-analytics-provider-mailgun-5.58.0.tgz +0 -0
  132. package/components/tryghost-email-analytics-service-5.58.0.tgz +0 -0
  133. package/components/tryghost-email-content-generator-5.58.0.tgz +0 -0
  134. package/components/tryghost-email-events-5.58.0.tgz +0 -0
  135. package/components/tryghost-email-service-5.58.0.tgz +0 -0
  136. package/components/tryghost-email-suppression-list-5.58.0.tgz +0 -0
  137. package/components/tryghost-event-aware-cache-wrapper-5.58.0.tgz +0 -0
  138. package/components/tryghost-express-dynamic-redirects-5.58.0.tgz +0 -0
  139. package/components/tryghost-external-media-inliner-5.58.0.tgz +0 -0
  140. package/components/tryghost-extract-api-key-5.58.0.tgz +0 -0
  141. package/components/tryghost-html-to-plaintext-5.58.0.tgz +0 -0
  142. package/components/tryghost-i18n-5.58.0.tgz +0 -0
  143. package/components/tryghost-importer-handler-content-files-5.58.0.tgz +0 -0
  144. package/components/tryghost-in-memory-repository-5.58.0.tgz +0 -0
  145. package/components/tryghost-job-manager-5.58.0.tgz +0 -0
  146. package/components/tryghost-link-redirects-5.58.0.tgz +0 -0
  147. package/components/tryghost-link-replacer-5.58.0.tgz +0 -0
  148. package/components/tryghost-link-tracking-5.58.0.tgz +0 -0
  149. package/components/tryghost-magic-link-5.58.0.tgz +0 -0
  150. package/components/tryghost-mail-events-5.58.0.tgz +0 -0
  151. package/components/tryghost-mailgun-client-5.58.0.tgz +0 -0
  152. package/components/tryghost-member-attribution-5.58.0.tgz +0 -0
  153. package/components/tryghost-member-events-5.58.0.tgz +0 -0
  154. package/components/tryghost-members-api-5.58.0.tgz +0 -0
  155. package/components/tryghost-members-csv-5.58.0.tgz +0 -0
  156. package/components/tryghost-members-events-service-5.58.0.tgz +0 -0
  157. package/components/tryghost-members-importer-5.58.0.tgz +0 -0
  158. package/components/tryghost-members-offers-5.58.0.tgz +0 -0
  159. package/components/tryghost-members-payments-5.58.0.tgz +0 -0
  160. package/components/tryghost-members-ssr-5.58.0.tgz +0 -0
  161. package/components/tryghost-members-stripe-service-5.58.0.tgz +0 -0
  162. package/components/tryghost-mentions-email-report-5.58.0.tgz +0 -0
  163. package/components/tryghost-milestones-5.58.0.tgz +0 -0
  164. package/components/tryghost-minifier-5.58.0.tgz +0 -0
  165. package/components/tryghost-model-to-domain-event-interceptor-5.58.0.tgz +0 -0
  166. package/components/tryghost-mw-api-version-mismatch-5.58.0.tgz +0 -0
  167. package/components/tryghost-mw-cache-control-5.58.0.tgz +0 -0
  168. package/components/tryghost-mw-session-from-token-5.58.0.tgz +0 -0
  169. package/components/tryghost-mw-update-user-last-seen-5.58.0.tgz +0 -0
  170. package/components/tryghost-mw-version-match-5.58.0.tgz +0 -0
  171. package/components/tryghost-mw-vhost-5.58.0.tgz +0 -0
  172. package/components/tryghost-nql-filter-expansions-5.58.0.tgz +0 -0
  173. package/components/tryghost-oembed-service-5.58.0.tgz +0 -0
  174. package/components/tryghost-package-json-5.58.0.tgz +0 -0
  175. package/components/tryghost-post-events-5.58.0.tgz +0 -0
  176. package/components/tryghost-post-revisions-5.58.0.tgz +0 -0
  177. package/components/tryghost-posts-service-5.58.0.tgz +0 -0
  178. package/components/tryghost-security-5.58.0.tgz +0 -0
  179. package/components/tryghost-session-service-5.58.0.tgz +0 -0
  180. package/components/tryghost-settings-path-manager-5.58.0.tgz +0 -0
  181. package/components/tryghost-slack-notifications-5.58.0.tgz +0 -0
  182. package/components/tryghost-staff-service-5.58.0.tgz +0 -0
  183. package/components/tryghost-stats-service-5.58.0.tgz +0 -0
  184. package/components/tryghost-update-check-service-5.58.0.tgz +0 -0
  185. package/components/tryghost-verification-trigger-5.58.0.tgz +0 -0
  186. package/components/tryghost-version-notifications-data-service-5.58.0.tgz +0 -0
  187. package/components/tryghost-webmentions-5.58.0.tgz +0 -0
  188. package/core/built/admin/assets/ghost-683e596baef13faeef904df69817ee4c.css +0 -1
  189. package/core/built/admin/assets/ghost-dark-a16345be972fc4d64b44b2f371130681.css +0 -1
  190. /package/core/built/admin/assets/{chunk.757.ada6ed049fa8078cd416.js.LICENSE.txt → chunk.757.ebdeaa01b967d376207e.js.LICENSE.txt} +0 -0
@@ -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%22cdnUrl%22%3A%22%22%2C%22rootURL%22%3A%22%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%225.58%22%2C%22name%22%3A%22ghost-admin%22%7D%2C%22ember-simple-auth%22%3A%7B%7D%2C%22ember-websockets%22%3A%7B%22socketIO%22%3Atrue%7D%2C%22%40sentry%2Fember%22%3A%7B%22disablePerformance%22%3Atrue%2C%22sentry%22%3A%7B%7D%7D%2C%22ember-cli-mirage%22%3A%7B%22usingProxy%22%3Afalse%2C%22useDefaultPassthroughs%22%3Atrue%7D%2C%22exportApplicationGlobal%22%3Afalse%2C%22ember-load%22%3A%7B%22loadingIndicatorClass%22%3A%22ember-load-indicator%22%7D%7D" />
11
+ <meta name="ghost-admin/config/environment" content="%7B%22modulePrefix%22%3A%22ghost-admin%22%2C%22environment%22%3A%22production%22%2C%22cdnUrl%22%3A%22%22%2C%22rootURL%22%3A%22%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%225.59%22%2C%22name%22%3A%22ghost-admin%22%7D%2C%22ember-simple-auth%22%3A%7B%7D%2C%22ember-websockets%22%3A%7B%22socketIO%22%3Atrue%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" />
@@ -37,7 +37,7 @@
37
37
  </style>
38
38
 
39
39
  <link integrity="" rel="stylesheet" href="assets/vendor-3e6947aa681f0fb82b193090e520dc73.css">
40
- <link integrity="" rel="stylesheet" href="assets/ghost-683e596baef13faeef904df69817ee4c.css" title="light">
40
+ <link integrity="" rel="stylesheet" href="assets/ghost-8b4c354fc3f7c2d3cf40ddae14796922.css" title="light">
41
41
 
42
42
 
43
43
  </head>
@@ -56,9 +56,9 @@
56
56
 
57
57
  <div id="ember-basic-dropdown-wormhole"></div>
58
58
 
59
- <script src="assets/vendor-16709e2a05d1300febb44b2e8f759976.js"></script>
60
- <script src="assets/chunk.757.ada6ed049fa8078cd416.js"></script>
61
- <script src="assets/chunk.143.5173fd8491cb28bc6a86.js"></script>
62
- <script src="assets/ghost-1ab7ddfda5747da72ff210c8e4a68d6a.js"></script>
59
+ <script src="assets/vendor-fff5b0b3c122441beb3170947ae27b9d.js"></script>
60
+ <script src="assets/chunk.757.ebdeaa01b967d376207e.js"></script>
61
+ <script src="assets/chunk.143.361ded5611b0566d5e16.js"></script>
62
+ <script src="assets/ghost-44831979758d416ac112014cc3606e48.js"></script>
63
63
  </body>
64
64
  </html>
@@ -385,7 +385,7 @@
385
385
  }
386
386
 
387
387
  .kg-bookmark-card,
388
- .kg-bookmark-author {
388
+ .kg-bookmark-publisher {
389
389
  position: relative;
390
390
  }
391
391
 
@@ -475,7 +475,7 @@
475
475
  overflow: hidden;
476
476
  }
477
477
 
478
- .kg-bookmark-author::before {
478
+ .kg-bookmark-publisher::before {
479
479
  content: "•";
480
480
  margin: 0 .5em;
481
481
  }
@@ -45,9 +45,11 @@ function finaliseStructuredData(meta) {
45
45
  }
46
46
 
47
47
  function getMembersHelper(data, frontendKey) {
48
- if (!settingsCache.get('members_enabled')) {
48
+ // Do not load Portal if both Memberships and Tips & Donations are disabled
49
+ if (!settingsCache.get('members_enabled') && !settingsCache.get('donations_enabled')) {
49
50
  return '';
50
51
  }
52
+
51
53
  const {scriptUrl} = getFrontendAppConfig('portal');
52
54
 
53
55
  const colorString = (_.has(data, 'site._preview') && data.site.accent_color) ? data.site.accent_color : '';
@@ -3,6 +3,10 @@ function isPost(jsonData) {
3
3
  Object.prototype.hasOwnProperty.call(jsonData, 'title') && Object.prototype.hasOwnProperty.call(jsonData, 'slug');
4
4
  }
5
5
 
6
+ function isPage(jsonData = {}) {
7
+ return Object.prototype.hasOwnProperty.call(jsonData, 'show_title_and_feature_image');
8
+ }
9
+
6
10
  function isTag(jsonData) {
7
11
  return Object.prototype.hasOwnProperty.call(jsonData, 'name') && Object.prototype.hasOwnProperty.call(jsonData, 'slug') &&
8
12
  Object.prototype.hasOwnProperty.call(jsonData, 'description') && Object.prototype.hasOwnProperty.call(jsonData, 'feature_image');
@@ -20,6 +24,7 @@ function isNav(jsonData) {
20
24
 
21
25
  module.exports = {
22
26
  isPost,
27
+ isPage,
23
28
  isTag,
24
29
  isUser,
25
30
  isNav
@@ -26,10 +26,10 @@ module.exports = {
26
26
  if (resource.feature_image_caption) {
27
27
  resource.feature_image_caption = new SafeString(resource.feature_image_caption);
28
28
  }
29
- });
30
29
 
31
- // some properties are extracted to local template data to force one way of using it
32
- delete data.show_title_and_feature_image;
30
+ // some properties are extracted to local template data to force one way of using it
31
+ delete resource.show_title_and_feature_image;
32
+ });
33
33
  },
34
34
 
35
35
  /**
@@ -1,13 +1,14 @@
1
1
  const _ = require('lodash');
2
2
  const hbs = require('../theme-engine/engine');
3
3
  const {prepareContextResource} = require('../proxy');
4
+ const {isPage} = require('../data/checks');
4
5
 
5
6
  /**
6
7
  * @description Formats API response into handlebars/theme format.
7
8
  *
8
9
  * @return {Object} containing page variables
9
10
  */
10
- function formatPageResponse(result, pageAsPost = false) {
11
+ function formatPageResponse(result, pageAsPost = false, locals = {}) {
11
12
  const response = {};
12
13
 
13
14
  if (result.posts) {
@@ -19,6 +20,28 @@ function formatPageResponse(result, pageAsPost = false) {
19
20
  response.pagination = result.meta.pagination;
20
21
  }
21
22
 
23
+ // when a custom routed page is loaded it can have an associated page object,
24
+ // in that case we want to make sure @page is still available and matches the
25
+ // selected page properties
26
+ if (isPage(result.data?.page?.[0])) {
27
+ const page = result.data?.page?.[0];
28
+
29
+ // build up @page data for use in templates
30
+ // - done here rather than `update-local-template-options` middleware because
31
+ // we need access to the rendered entry's data which isn't available in middleware
32
+ const pageData = {
33
+ show_title_and_feature_image: page.show_title_and_feature_image
34
+ };
35
+
36
+ // merge @page into local template options
37
+ const localTemplateOptions = hbs.getLocalTemplateOptions(locals);
38
+ hbs.updateLocalTemplateOptions(locals, _.merge({}, localTemplateOptions, {
39
+ data: {
40
+ page: pageData
41
+ }
42
+ }));
43
+ }
44
+
22
45
  _.each(result.data, function (data, name) {
23
46
  prepareContextResource(data);
24
47
 
@@ -14,6 +14,6 @@ module.exports = function renderEntries(req, res) {
14
14
  return function renderEntriesClosure(result) {
15
15
  // Format data 2
16
16
  // Render
17
- return renderer(req, res, formatResponse.entries(result));
17
+ return renderer(req, res, formatResponse.entries(result, false, res.locals));
18
18
  };
19
19
  };
@@ -65,7 +65,7 @@ module.exports = function staticController(req, res, next) {
65
65
  // This flag solves the confusion about whether the output contains a post or page object by duplicating the objects
66
66
  // This is not ideal, but will solve some long standing pain points with dynamic routing until we can overhaul it
67
67
  const duplicatePagesAsPosts = true;
68
- renderer.renderer(req, res, renderer.formatResponse.entries(response, duplicatePagesAsPosts));
68
+ renderer.renderer(req, res, renderer.formatResponse.entries(response, duplicatePagesAsPosts, res.locals));
69
69
  })
70
70
  .catch(renderer.handleError(next));
71
71
  };
@@ -4,9 +4,9 @@
4
4
  }
5
5
 
6
6
  .kg-bookmark-card,
7
- .kg-bookmark-author {
7
+ .kg-bookmark-publisher {
8
8
  position: relative;
9
- width: 100%;
9
+ /* width: 100%; */
10
10
  }
11
11
 
12
12
  .kg-bookmark-card a.kg-bookmark-container,
@@ -74,7 +74,7 @@
74
74
  display: inline;
75
75
  }
76
76
 
77
- .kg-bookmark-author {
77
+ .kg-bookmark-publisher {
78
78
  text-overflow: ellipsis;
79
79
  overflow: hidden;
80
80
  max-width: 240px;
@@ -19,6 +19,10 @@
19
19
  background-color: var(--ghost-accent-color);
20
20
  }
21
21
 
22
+ .kg-header-card-content {
23
+ width: 100%;
24
+ }
25
+
22
26
  .kg-layout-split .kg-header-card-content {
23
27
  display: grid;
24
28
  grid-template-columns: 1fr 1fr;
@@ -31,14 +35,14 @@
31
35
  align-items: flex-start;
32
36
  justify-content: center;
33
37
  height: 100%;
34
- padding: 4vmax;
38
+ padding: 6.4vmax 4vmax;
35
39
  background-size: cover;
36
40
  background-position: center;
37
41
  text-align: left;
38
42
  }
39
43
 
40
44
  .kg-width-wide .kg-header-card-text {
41
- padding: 6.4vmax;
45
+ padding: 10vmax 6.4vmax;
42
46
  }
43
47
 
44
48
  .kg-width-full .kg-header-card-text {
@@ -141,6 +141,7 @@ module.exports = {
141
141
  'source',
142
142
  'force_rerender',
143
143
  'save_revision',
144
+ 'convert_to_lexical',
144
145
  // NOTE: only for internal context
145
146
  'forUpdate',
146
147
  'transacting'
@@ -192,6 +192,7 @@ module.exports = {
192
192
  'newsletter',
193
193
  'force_rerender',
194
194
  'save_revision',
195
+ 'convert_to_lexical',
195
196
  // NOTE: only for internal context
196
197
  'forUpdate',
197
198
  'transacting'
@@ -68,7 +68,9 @@ const EDITABLE_SETTINGS = [
68
68
  'announcement_visibility',
69
69
  'pintura',
70
70
  'pintura_js_url',
71
- 'pintura_css_url'
71
+ 'pintura_css_url',
72
+ 'donations_currency',
73
+ 'donations_suggested_amount'
72
74
  ];
73
75
 
74
76
  module.exports = {
@@ -37,6 +37,7 @@ const author = (attrs, frame) => {
37
37
  delete attrs.paid_subscription_canceled_notification;
38
38
  delete attrs.mention_notifications;
39
39
  delete attrs.milestone_notifications;
40
+ delete attrs.donation_notifications;
40
41
 
41
42
  // @NOTE: used for night shift
42
43
  delete attrs.accessibility;
@@ -0,0 +1,7 @@
1
+ const {createAddColumnMigration} = require('../../utils');
2
+
3
+ module.exports = createAddColumnMigration('users', 'donation_notifications', {
4
+ type: 'boolean',
5
+ nullable: false,
6
+ defaultTo: true
7
+ });
@@ -0,0 +1,51 @@
1
+ const logging = require('@tryghost/logging');
2
+ const DatabaseInfo = require('@tryghost/database-info');
3
+ const {createNonTransactionalMigration} = require('../../utils');
4
+
5
+ const INDEX_NAME = 'posts_published_at_index';
6
+
7
+ module.exports = createNonTransactionalMigration(
8
+ async function up(knex) {
9
+ let hasIndex = false;
10
+
11
+ if (DatabaseInfo.isSQLite(knex)) {
12
+ const result = await knex.raw(`select * from sqlite_master where type = 'index' and tbl_name = 'posts' and name = '${INDEX_NAME}'`);
13
+ hasIndex = (result.length !== 0);
14
+ } else {
15
+ const result = await knex.raw(`show index from posts where Key_name = '${INDEX_NAME}'`);
16
+ hasIndex = (result[0].length !== 0);
17
+ }
18
+
19
+ if (hasIndex) {
20
+ logging.info(`Skipping creation of index ${INDEX_NAME} on posts for published_at - already exists`);
21
+ return;
22
+ }
23
+
24
+ logging.info(`Creating index ${INDEX_NAME} on posts for published_at`);
25
+ await knex.schema.table('posts', (table) => {
26
+ table.index(['published_at']);
27
+ });
28
+ },
29
+
30
+ async function down(knex) {
31
+ let missingIndex = false;
32
+
33
+ if (DatabaseInfo.isSQLite(knex)) {
34
+ const result = await knex.raw(`select * from sqlite_master where type = 'index' and tbl_name = 'posts' and name = '${INDEX_NAME}'`);
35
+ missingIndex = (result.length === 0);
36
+ } else {
37
+ const result = await knex.raw(`show index from posts where Key_name = '${INDEX_NAME}'`);
38
+ missingIndex = (result[0].length === 0);
39
+ }
40
+
41
+ if (missingIndex) {
42
+ logging.info(`Skipping drop of index ${INDEX_NAME} on posts for published_at - does not exist`);
43
+ return;
44
+ }
45
+
46
+ logging.info(`Dropping index ${INDEX_NAME} on posts for published_at`);
47
+ await knex.schema.table('posts', (table) => {
48
+ table.dropIndex(['published_at']);
49
+ });
50
+ }
51
+ );
@@ -700,6 +700,7 @@
700
700
  "free_member_signup_notification": true,
701
701
  "paid_subscription_started_notification": true,
702
702
  "paid_subscription_canceled_notification": false,
703
+ "donation_notifications": true,
703
704
  "roles": []
704
705
  }
705
706
  ]
@@ -83,7 +83,7 @@ module.exports = {
83
83
  created_by: {type: 'string', maxlength: 24, nullable: false},
84
84
  updated_at: {type: 'dateTime', nullable: true},
85
85
  updated_by: {type: 'string', maxlength: 24, nullable: true},
86
- published_at: {type: 'dateTime', nullable: true},
86
+ published_at: {type: 'dateTime', nullable: true, index: true},
87
87
  published_by: {type: 'string', maxlength: 24, nullable: true},
88
88
  custom_excerpt: {type: 'string', maxlength: 2000, nullable: true, validations: {isLength: {max: 300}}},
89
89
  codeinjection_head: {type: 'text', maxlength: 65535, nullable: true},
@@ -164,6 +164,7 @@ module.exports = {
164
164
  paid_subscription_canceled_notification: {type: 'boolean', nullable: false, defaultTo: false},
165
165
  mention_notifications: {type: 'boolean', nullable: false, defaultTo: true},
166
166
  milestone_notifications: {type: 'boolean', nullable: false, defaultTo: true},
167
+ donation_notifications: {type: 'boolean', nullable: false, defaultTo: true},
167
168
  created_at: {type: 'dateTime', nullable: false},
168
169
  created_by: {type: 'string', maxlength: 24, nullable: false},
169
170
  updated_at: {type: 'dateTime', nullable: true},
@@ -0,0 +1,9 @@
1
+ const ghostBookshelf = require('./base');
2
+
3
+ const CollectionPost = ghostBookshelf.Model.extend({
4
+ tableName: 'collections_posts'
5
+ });
6
+
7
+ module.exports = {
8
+ CollectionPost: ghostBookshelf.model('CollectionPost', CollectionPost)
9
+ };
@@ -70,6 +70,12 @@ const Collection = ghostBookshelf.Model.extend({
70
70
  'id',
71
71
  'id'
72
72
  );
73
+ },
74
+
75
+ collectionPosts() {
76
+ return this.hasMany(
77
+ 'CollectionPost'
78
+ );
73
79
  }
74
80
  });
75
81
 
@@ -19,6 +19,8 @@ const {Tag} = require('./tag');
19
19
  const {Newsletter} = require('./newsletter');
20
20
  const {BadRequestError} = require('@tryghost/errors');
21
21
  const {PostRevisions} = require('@tryghost/post-revisions');
22
+ const {mobiledocToLexical} = require('@tryghost/kg-converters');
23
+ const labs = require('../../shared/labs');
22
24
 
23
25
  const messages = {
24
26
  isAlreadyPublished: 'Your post is already published, please reload your page.',
@@ -913,6 +915,16 @@ Post = ghostBookshelf.Model.extend({
913
915
  });
914
916
  }
915
917
 
918
+ // CASE: Convert post to lexical on the fly
919
+ if (labs.isSet('convertToLexical') && labs.isSet('lexicalEditor') && options.convert_to_lexical) {
920
+ ops.push(async function convertToLexical() {
921
+ const mobiledoc = model.get('mobiledoc');
922
+ const lexical = mobiledocToLexical(mobiledoc);
923
+ model.set('lexical', lexical);
924
+ model.set('mobiledoc', null);
925
+ });
926
+ }
927
+
916
928
  if (this.get('tiers')) {
917
929
  this.set('tiers', this.get('tiers').map(t => ({
918
930
  id: t.id
@@ -1154,9 +1166,10 @@ Post = ghostBookshelf.Model.extend({
1154
1166
  const validOptions = {
1155
1167
  findOne: ['columns', 'importing', 'withRelated', 'require', 'filter'],
1156
1168
  findPage: ['status'],
1169
+
1157
1170
  findAll: ['columns', 'filter'],
1158
1171
  destroy: ['destroyAll', 'destroyBy'],
1159
- edit: ['filter', 'email_segment', 'force_rerender', 'newsletter', 'save_revision']
1172
+ edit: ['filter', 'email_segment', 'force_rerender', 'newsletter', 'save_revision', 'convert_to_lexical']
1160
1173
  };
1161
1174
 
1162
1175
  // The post model additionally supports having a formats option
@@ -69,7 +69,8 @@ User = ghostBookshelf.Model.extend({
69
69
  paid_subscription_started_notification: true,
70
70
  paid_subscription_canceled_notification: false,
71
71
  mention_notifications: true,
72
- milestone_notifications: true
72
+ milestone_notifications: true,
73
+ donation_notifications: true
73
74
  };
74
75
  },
75
76
 
@@ -509,6 +510,8 @@ User = ghostBookshelf.Model.extend({
509
510
  filter += '+mention_notifications:true';
510
511
  } else if (type === 'milestone-received') {
511
512
  filter += '+milestone_notifications:true';
513
+ } else if (type === 'donation') {
514
+ filter += '+donation_notifications:true';
512
515
  }
513
516
  const updatedOptions = _.merge({}, options, {filter, withRelated: ['roles']});
514
517
  return this.findAll(updatedOptions).then((users) => {
@@ -23,7 +23,7 @@ module.exports = class BookshelfCollectionsRepository {
23
23
  async getById(id, options = {}) {
24
24
  const model = await this.#model.findOne({id}, {
25
25
  require: false,
26
- withRelated: ['posts'],
26
+ withRelated: ['collectionPosts'],
27
27
  transacting: options.transaction
28
28
  });
29
29
  if (!model) {
@@ -39,7 +39,7 @@ module.exports = class BookshelfCollectionsRepository {
39
39
  async getBySlug(slug, options = {}) {
40
40
  const model = await this.#model.findOne({slug}, {
41
41
  require: false,
42
- withRelated: ['posts'],
42
+ withRelated: ['collectionPosts'],
43
43
  transacting: options.transaction
44
44
  });
45
45
  if (!model) {
@@ -58,7 +58,7 @@ module.exports = class BookshelfCollectionsRepository {
58
58
  const models = await this.#model.findAll({
59
59
  ...options,
60
60
  transacting: options.transaction,
61
- withRelated: ['posts']
61
+ withRelated: ['collectionPosts']
62
62
  });
63
63
 
64
64
  return await Promise.all(models.map(model => this.#modelToCollection(model)));
@@ -75,7 +75,7 @@ module.exports = class BookshelfCollectionsRepository {
75
75
  filter: json.filter,
76
76
  type: json.type,
77
77
  featureImage: json.feature_image,
78
- posts: json.posts.map(post => post.id),
78
+ posts: json.collectionPosts.map(collectionPost => collectionPost.post_id),
79
79
  createdAt: json.created_at,
80
80
  updatedAt: json.updated_at
81
81
  });
@@ -182,6 +182,7 @@ function createApiInstance(config) {
182
182
  }
183
183
  },
184
184
  models: {
185
+ DonationPaymentEvent: models.DonationPaymentEvent,
185
186
  EmailRecipient: models.EmailRecipient,
186
187
  StripeCustomer: models.MemberStripeCustomer,
187
188
  StripeCustomerSubscription: models.StripeCustomerSubscription,
@@ -89,6 +89,7 @@ module.exports = {
89
89
  fields.push(new CalculatedField({key: 'members_invite_only', type: 'boolean', group: 'members', fn: settingsHelpers.isMembersInviteOnly.bind(settingsHelpers), dependents: ['members_signup_access']}));
90
90
  fields.push(new CalculatedField({key: 'paid_members_enabled', type: 'boolean', group: 'members', fn: settingsHelpers.arePaidMembersEnabled.bind(settingsHelpers), dependents: ['members_signup_access', 'stripe_secret_key', 'stripe_publishable_key', 'stripe_connect_secret_key', 'stripe_connect_publishable_key']}));
91
91
  fields.push(new CalculatedField({key: 'firstpromoter_account', type: 'string', group: 'firstpromoter', fn: settingsHelpers.getFirstpromoterId.bind(settingsHelpers), dependents: ['firstpromoter', 'firstpromoter_id']}));
92
+ fields.push(new CalculatedField({key: 'donations_enabled', type: 'boolean', group: 'donations', fn: settingsHelpers.areDonationsEnabled.bind(settingsHelpers), dependents: ['stripe_secret_key', 'stripe_publishable_key', 'stripe_connect_secret_key', 'stripe_connect_publishable_key']}));
92
93
 
93
94
  return fields;
94
95
  },
@@ -98,6 +98,10 @@ class SettingsHelpers {
98
98
  getNoReplyAddress() {
99
99
  return `noreply@${this.getDefaultEmailDomain()}`;
100
100
  }
101
+
102
+ areDonationsEnabled() {
103
+ return this.isStripeConnected();
104
+ }
101
105
  }
102
106
 
103
107
  module.exports = SettingsHelpers;
@@ -10,6 +10,7 @@ const models = require('../../models');
10
10
  const {getConfig} = require('./config');
11
11
  const settingsHelpers = require('../settings-helpers');
12
12
  const donationService = require('../donations');
13
+ const staffService = require('../staff');
13
14
 
14
15
  async function configureApi() {
15
16
  const cfg = getConfig({settingsHelpers, config, urlUtils});
@@ -56,7 +57,8 @@ module.exports = new StripeService({
56
57
  }]);
57
58
  }
58
59
  },
59
- donationService
60
+ donationService,
61
+ staffService
60
62
  });
61
63
 
62
64
  module.exports.init = async function init() {
@@ -182,7 +182,7 @@
182
182
  },
183
183
  "portal": {
184
184
  "url": "https://cdn.jsdelivr.net/ghost/portal@~{version}/umd/portal.min.js",
185
- "version": "2.33"
185
+ "version": "2.34"
186
186
  },
187
187
  "sodoSearch": {
188
188
  "url": "https://cdn.jsdelivr.net/ghost/sodo-search@~{version}/umd/sodo-search.min.js",
@@ -200,7 +200,7 @@
200
200
  },
201
201
  "editor": {
202
202
  "url": "https://cdn.jsdelivr.net/ghost/koenig-lexical@~{version}/dist/koenig-lexical.umd.js",
203
- "version": "0.3"
203
+ "version": "0.4"
204
204
  },
205
205
  "adminX": {
206
206
  "url": "https://cdn.jsdelivr.net/ghost/admin-x-settings@~{version}/dist/admin-x-settings.umd.js",
@@ -40,9 +40,9 @@ const ALPHA_FEATURES = [
40
40
  'adminXSettings',
41
41
  'mailEvents',
42
42
  'collectionsCard',
43
- 'headerUpgrade',
43
+ 'tipsAndDonations',
44
44
  'importMemberTier',
45
- 'tipsAndDonations'
45
+ 'convertToLexical'
46
46
  ];
47
47
 
48
48
  module.exports.GA_KEYS = [...GA_FEATURES];