ghost 5.5.0 → 5.7.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 (447) hide show
  1. package/PRIVACY.md +3 -2
  2. package/components/tryghost-adapter-manager-0.0.0.tgz +0 -0
  3. package/components/tryghost-api-version-compatibility-service-0.0.0.tgz +0 -0
  4. package/components/tryghost-bootstrap-socket-0.0.0.tgz +0 -0
  5. package/components/tryghost-constants-0.0.0.tgz +0 -0
  6. package/components/tryghost-email-analytics-provider-mailgun-0.0.0.tgz +0 -0
  7. package/components/tryghost-email-content-generator-0.0.0.tgz +0 -0
  8. package/components/tryghost-extract-api-key-0.0.0.tgz +0 -0
  9. package/components/tryghost-job-manager-0.0.0.tgz +0 -0
  10. package/components/tryghost-members-api-0.0.0.tgz +0 -0
  11. package/components/tryghost-members-events-service-0.0.0.tgz +0 -0
  12. package/components/tryghost-members-importer-0.0.0.tgz +0 -0
  13. package/components/tryghost-members-stripe-service-0.0.0.tgz +0 -0
  14. package/components/tryghost-minifier-0.0.0.tgz +0 -0
  15. package/components/tryghost-mw-api-version-mismatch-0.0.0.tgz +0 -0
  16. package/components/tryghost-mw-error-handler-0.0.0.tgz +0 -0
  17. package/components/tryghost-mw-session-from-token-0.0.0.tgz +0 -0
  18. package/components/tryghost-mw-update-user-last-seen-0.0.0.tgz +0 -0
  19. package/components/tryghost-mw-vhost-0.0.0.tgz +0 -0
  20. package/components/tryghost-package-json-0.0.0.tgz +0 -0
  21. package/components/tryghost-security-0.0.0.tgz +0 -0
  22. package/components/tryghost-session-service-0.0.0.tgz +0 -0
  23. package/components/tryghost-settings-path-manager-0.0.0.tgz +0 -0
  24. package/components/tryghost-update-check-service-0.0.0.tgz +0 -0
  25. package/components/tryghost-verification-trigger-0.0.0.tgz +0 -0
  26. package/components/tryghost-version-notifications-data-service-0.0.0.tgz +0 -0
  27. package/content/themes/casper/assets/built/screen.css +1 -1
  28. package/content/themes/casper/assets/built/screen.css.map +1 -1
  29. package/content/themes/casper/assets/css/screen.css +21 -0
  30. package/content/themes/casper/package.json +1 -1
  31. package/core/boot.js +1 -1
  32. package/core/built/admin/production/assets/chunk.143.8ada616796634b355196.js +41 -0
  33. package/core/built/admin/production/assets/chunk.178.707d6d4d6204a049b9f2.js +11 -0
  34. package/core/built/admin/production/assets/chunk.599.628afe8bdebf6628418c.js +9315 -0
  35. package/core/built/admin/production/assets/chunk.599.628afe8bdebf6628418c.js.LICENSE.txt +142 -0
  36. package/core/built/admin/production/assets/chunk.846.2cf7666babb53987e514.js +239 -0
  37. package/core/built/{assets/codemirror/codemirror-30201ab2cff61db847193fc9f5ed922d.js → admin/production/assets/codemirror/codemirror-1b460af155bb0ecaab9591678ac8c942.js} +1 -1
  38. package/core/built/{assets → admin/production/assets}/fonts/Inter.ttf +0 -0
  39. package/core/built/{assets/ghost.min-a89d10b3b58c1a5ebaca68cef93a404c.css → admin/production/assets/ghost-5f1b1d81fa8b9b6bfb0fb2b92ca60409.css} +1 -1
  40. package/core/built/{assets/ghost.min-c75f224decd20f9538179d7564cd2ab4.js → admin/production/assets/ghost-9d8eda43a01eb17ac57c0edaeeb04c2f.js} +364 -345
  41. package/core/built/{assets/ghost-dark-5c2a961b35311d7298136e02289d98b2.css → admin/production/assets/ghost-dark-4f2fd083685ad82226386053fccb3497.css} +1 -1
  42. package/core/built/{assets → admin/production/assets}/icons/account-group.svg +0 -0
  43. package/core/built/{assets → admin/production/assets}/icons/activity-placeholder.svg +0 -0
  44. package/core/built/{assets → admin/production/assets}/icons/add-stroke.svg +0 -0
  45. package/core/built/{assets → admin/production/assets}/icons/add-view.svg +0 -0
  46. package/core/built/{assets → admin/production/assets}/icons/add.svg +0 -0
  47. package/core/built/{assets → admin/production/assets}/icons/align-center.svg +0 -0
  48. package/core/built/{assets → admin/production/assets}/icons/align-left.svg +0 -0
  49. package/core/built/{assets → admin/production/assets}/icons/ambulance.svg +0 -0
  50. package/core/built/{assets → admin/production/assets}/icons/analytics.svg +0 -0
  51. package/core/built/{assets → admin/production/assets}/icons/arrow-down-small.svg +0 -0
  52. package/core/built/{assets → admin/production/assets}/icons/arrow-down-stroke.svg +0 -0
  53. package/core/built/{assets → admin/production/assets}/icons/arrow-down.svg +0 -0
  54. package/core/built/{assets → admin/production/assets}/icons/arrow-left-small.svg +0 -0
  55. package/core/built/{assets → admin/production/assets}/icons/arrow-left-stroke.svg +0 -0
  56. package/core/built/{assets → admin/production/assets}/icons/arrow-left-tail.svg +0 -0
  57. package/core/built/{assets → admin/production/assets}/icons/arrow-left.svg +0 -0
  58. package/core/built/{assets → admin/production/assets}/icons/arrow-right-small.svg +0 -0
  59. package/core/built/{assets → admin/production/assets}/icons/arrow-right-stroke.svg +0 -0
  60. package/core/built/{assets → admin/production/assets}/icons/arrow-right-tail.svg +0 -0
  61. package/core/built/{assets → admin/production/assets}/icons/arrow-right.svg +0 -0
  62. package/core/built/{assets → admin/production/assets}/icons/arrow-up-small.svg +0 -0
  63. package/core/built/{assets → admin/production/assets}/icons/arrow-up-stroke.svg +0 -0
  64. package/core/built/{assets → admin/production/assets}/icons/arrow-up.svg +0 -0
  65. package/core/built/{assets → admin/production/assets}/icons/arrow2-down.svg +0 -0
  66. package/core/built/{assets → admin/production/assets}/icons/arrow2-right.svg +0 -0
  67. package/core/built/{assets → admin/production/assets}/icons/audio-file.svg +0 -0
  68. package/core/built/{assets → admin/production/assets}/icons/audio-upload.svg +0 -0
  69. package/core/built/{assets → admin/production/assets}/icons/book-open.svg +0 -0
  70. package/core/built/{assets → admin/production/assets}/icons/bookmark-article.svg +0 -0
  71. package/core/built/{assets → admin/production/assets}/icons/box-hands.svg +0 -0
  72. package/core/built/{assets → admin/production/assets}/icons/box.svg +0 -0
  73. package/core/built/{assets → admin/production/assets}/icons/boxes.svg +0 -0
  74. package/core/built/{assets → admin/production/assets}/icons/brackets.svg +0 -0
  75. package/core/built/{assets → admin/production/assets}/icons/button.svg +0 -0
  76. package/core/built/{assets → admin/production/assets}/icons/calendar.svg +0 -0
  77. package/core/built/{assets → admin/production/assets}/icons/cash.svg +0 -0
  78. package/core/built/{assets → admin/production/assets}/icons/chat-double-bubble.svg +0 -0
  79. package/core/built/{assets → admin/production/assets}/icons/check-2.svg +0 -0
  80. package/core/built/{assets → admin/production/assets}/icons/check-circle-stroke.svg +0 -0
  81. package/core/built/{assets → admin/production/assets}/icons/check-circle.svg +0 -0
  82. package/core/built/{assets → admin/production/assets}/icons/check.svg +0 -0
  83. package/core/built/{assets → admin/production/assets}/icons/cheeseburger.svg +0 -0
  84. package/core/built/{assets → admin/production/assets}/icons/circle-ellipsis.svg +0 -0
  85. package/core/built/{assets → admin/production/assets}/icons/clock.svg +0 -0
  86. package/core/built/{assets → admin/production/assets}/icons/clockface.svg +0 -0
  87. package/core/built/{assets → admin/production/assets}/icons/close-stroke.svg +0 -0
  88. package/core/built/{assets → admin/production/assets}/icons/close.svg +0 -0
  89. package/core/built/{assets → admin/production/assets}/icons/cloud.svg +0 -0
  90. package/core/built/{assets → admin/production/assets}/icons/compass-2.svg +0 -0
  91. package/core/built/{assets → admin/production/assets}/icons/compass.svg +0 -0
  92. package/core/built/{assets → admin/production/assets}/icons/computer.svg +0 -0
  93. package/core/built/{assets → admin/production/assets}/icons/confetti.svg +0 -0
  94. package/core/built/{assets → admin/production/assets}/icons/content-bold.svg +0 -0
  95. package/core/built/{assets → admin/production/assets}/icons/content.svg +0 -0
  96. package/core/built/{assets → admin/production/assets}/icons/copy.svg +0 -0
  97. package/core/built/{assets → admin/production/assets}/icons/credit-card.svg +0 -0
  98. package/core/built/{assets → admin/production/assets}/icons/cross-circle.svg +0 -0
  99. package/core/built/{assets → admin/production/assets}/icons/cycle.svg +0 -0
  100. package/core/built/{assets → admin/production/assets}/icons/default-favicon.svg +0 -0
  101. package/core/built/{assets → admin/production/assets}/icons/desert.svg +0 -0
  102. package/core/built/{assets → admin/production/assets}/icons/desktop.svg +0 -0
  103. package/core/built/{assets → admin/production/assets}/icons/diamond.svg +0 -0
  104. package/core/built/{assets → admin/production/assets}/icons/discount-bubble.svg +0 -0
  105. package/core/built/{assets → admin/production/assets}/icons/dividers.svg +0 -0
  106. package/core/built/{assets → admin/production/assets}/icons/dotdotdot.svg +0 -0
  107. package/core/built/{assets → admin/production/assets}/icons/download-circle.svg +0 -0
  108. package/core/built/{assets → admin/production/assets}/icons/download.svg +0 -0
  109. package/core/built/{assets → admin/production/assets}/icons/eco-globe.svg +0 -0
  110. package/core/built/{assets → admin/production/assets}/icons/eco-lightbulb.svg +0 -0
  111. package/core/built/{assets → admin/production/assets}/icons/edit-view.svg +0 -0
  112. package/core/built/{assets → admin/production/assets}/icons/ellipsis.svg +0 -0
  113. package/core/built/{assets → admin/production/assets}/icons/email-at.svg +0 -0
  114. package/core/built/{assets → admin/production/assets}/icons/email-body.svg +0 -0
  115. package/core/built/{assets → admin/production/assets}/icons/email-footer.svg +0 -0
  116. package/core/built/{assets → admin/production/assets}/icons/email-header.svg +0 -0
  117. package/core/built/{assets → admin/production/assets}/icons/email-love-letter.svg +0 -0
  118. package/core/built/{assets → admin/production/assets}/icons/email-member.svg +0 -0
  119. package/core/built/{assets → admin/production/assets}/icons/email-name.svg +0 -0
  120. package/core/built/{assets → admin/production/assets}/icons/email-send.svg +0 -0
  121. package/core/built/{assets → admin/production/assets}/icons/email-stroke.svg +0 -0
  122. package/core/built/{assets → admin/production/assets}/icons/email-unread.svg +0 -0
  123. package/core/built/{assets → admin/production/assets}/icons/email.svg +0 -0
  124. package/core/built/{assets → admin/production/assets}/icons/event-canceled-subscription.svg +0 -0
  125. package/core/built/{assets → admin/production/assets}/icons/event-comment.svg +0 -0
  126. package/core/built/{assets → admin/production/assets}/icons/event-email-delivery-failed.svg +0 -0
  127. package/core/built/{assets → admin/production/assets}/icons/event-logged-in.svg +0 -0
  128. package/core/built/{assets → admin/production/assets}/icons/event-made-a-payment.svg +0 -0
  129. package/core/built/{assets → admin/production/assets}/icons/event-opened-email.svg +0 -0
  130. package/core/built/{assets → admin/production/assets}/icons/event-received-email.svg +0 -0
  131. package/core/built/{assets → admin/production/assets}/icons/event-signed-up.svg +0 -0
  132. package/core/built/{assets → admin/production/assets}/icons/event-subscribed-to-email.svg +0 -0
  133. package/core/built/{assets → admin/production/assets}/icons/event-subscriptions.svg +0 -0
  134. package/core/built/{assets → admin/production/assets}/icons/event-unsubscribed-from-email.svg +0 -0
  135. package/core/built/{assets → admin/production/assets}/icons/expand.svg +0 -0
  136. package/core/built/{assets → admin/production/assets}/icons/external.svg +0 -0
  137. package/core/built/{assets → admin/production/assets}/icons/eye.svg +0 -0
  138. package/core/built/{assets → admin/production/assets}/icons/facebook-heart.svg +0 -0
  139. package/core/built/{assets → admin/production/assets}/icons/facebook-like.svg +0 -0
  140. package/core/built/{assets → admin/production/assets}/icons/facebook.svg +0 -0
  141. package/core/built/{assets → admin/production/assets}/icons/feature-image.svg +0 -0
  142. package/core/built/{assets → admin/production/assets}/icons/file-download.svg +0 -0
  143. package/core/built/{assets → admin/production/assets}/icons/file-tabular-data.svg +0 -0
  144. package/core/built/{assets → admin/production/assets}/icons/file-text-document.svg +0 -0
  145. package/core/built/{assets → admin/production/assets}/icons/file-upload.svg +0 -0
  146. package/core/built/{assets → admin/production/assets}/icons/film-camera.svg +0 -0
  147. package/core/built/{assets → admin/production/assets}/icons/filter.svg +0 -0
  148. package/core/built/{assets → admin/production/assets}/icons/firstpromoter-ce8b5219e5b5ebda463bd60396c6ab81.png +0 -0
  149. package/core/built/{assets → admin/production/assets}/icons/folder.svg +0 -0
  150. package/core/built/{assets → admin/production/assets}/icons/gallery-placeholder.svg +0 -0
  151. package/core/built/{assets → admin/production/assets}/icons/get-started-import.svg +0 -0
  152. package/core/built/{assets → admin/production/assets}/icons/get-started-members.svg +0 -0
  153. package/core/built/{assets → admin/production/assets}/icons/get-started-migrations.svg +0 -0
  154. package/core/built/{assets → admin/production/assets}/icons/get-started.svg +0 -0
  155. package/core/built/{assets → admin/production/assets}/icons/ghost-logo-orb.svg +0 -0
  156. package/core/built/{assets → admin/production/assets}/icons/ghost-logo.svg +0 -0
  157. package/core/built/{assets → admin/production/assets}/icons/ghost-orb.svg +0 -0
  158. package/core/built/{assets → admin/production/assets}/icons/ghost-squircle.svg +0 -0
  159. package/core/built/{assets → admin/production/assets}/icons/gift.svg +0 -0
  160. package/core/built/{assets → admin/production/assets}/icons/github-outline.svg +0 -0
  161. package/core/built/{assets → admin/production/assets}/icons/github-star.svg +0 -0
  162. package/core/built/{assets → admin/production/assets}/icons/github.svg +0 -0
  163. package/core/built/{assets → admin/production/assets}/icons/globe.svg +0 -0
  164. package/core/built/{assets → admin/production/assets}/icons/google-favicon.svg +0 -0
  165. package/core/built/{assets → admin/production/assets}/icons/google-search.svg +0 -0
  166. package/core/built/{assets → admin/production/assets}/icons/google.svg +0 -0
  167. package/core/built/{assets → admin/production/assets}/icons/grab.svg +0 -0
  168. package/core/built/{assets → admin/production/assets}/icons/graph-line.svg +0 -0
  169. package/core/built/{assets → admin/production/assets}/icons/heart-beat.svg +0 -0
  170. package/core/built/{assets → admin/production/assets}/icons/heart-circle.svg +0 -0
  171. package/core/built/{assets → admin/production/assets}/icons/heart.svg +0 -0
  172. package/core/built/{assets → admin/production/assets}/icons/help.svg +0 -0
  173. package/core/built/{assets → admin/production/assets}/icons/hotspot.svg +0 -0
  174. package/core/built/{assets → admin/production/assets}/icons/house-bold.svg +0 -0
  175. package/core/built/{assets → admin/production/assets}/icons/house.svg +0 -0
  176. package/core/built/{assets → admin/production/assets}/icons/icon.svg +0 -0
  177. package/core/built/{assets → admin/production/assets}/icons/id-card.svg +0 -0
  178. package/core/built/{assets → admin/production/assets}/icons/idea.svg +0 -0
  179. package/core/built/{assets → admin/production/assets}/icons/info.svg +0 -0
  180. package/core/built/{assets → admin/production/assets}/icons/instagram.svg +0 -0
  181. package/core/built/{assets → admin/production/assets}/icons/integration.svg +0 -0
  182. package/core/built/{assets → admin/production/assets}/icons/labs.svg +0 -0
  183. package/core/built/{assets → admin/production/assets}/icons/laptop.svg +0 -0
  184. package/core/built/{assets → admin/production/assets}/icons/line.svg +0 -0
  185. package/core/built/{assets → admin/production/assets}/icons/link.svg +0 -0
  186. package/core/built/{assets → admin/production/assets}/icons/list-bullet.svg +0 -0
  187. package/core/built/{assets → admin/production/assets}/icons/list-number.svg +0 -0
  188. package/core/built/{assets → admin/production/assets}/icons/lock.svg +0 -0
  189. package/core/built/{assets → admin/production/assets}/icons/lock2.svg +0 -0
  190. package/core/built/{assets → admin/production/assets}/icons/loop-infinite.svg +0 -0
  191. package/core/built/{assets → admin/production/assets}/icons/lotus.svg +0 -0
  192. package/core/built/{assets → admin/production/assets}/icons/markdown.svg +0 -0
  193. package/core/built/{assets → admin/production/assets}/icons/member-add.svg +0 -0
  194. package/core/built/{assets → admin/production/assets}/icons/member.svg +0 -0
  195. package/core/built/{assets → admin/production/assets}/icons/members-all.svg +0 -0
  196. package/core/built/{assets → admin/production/assets}/icons/members-bold.svg +0 -0
  197. package/core/built/{assets → admin/production/assets}/icons/members-outline.svg +0 -0
  198. package/core/built/{assets → admin/production/assets}/icons/members-paid.svg +0 -0
  199. package/core/built/{assets → admin/production/assets}/icons/members-placeholder.svg +0 -0
  200. package/core/built/{assets → admin/production/assets}/icons/members-post.svg +0 -0
  201. package/core/built/{assets → admin/production/assets}/icons/members-segment.svg +0 -0
  202. package/core/built/{assets → admin/production/assets}/icons/members.svg +0 -0
  203. package/core/built/{assets → admin/production/assets}/icons/mobile-phone-heart.svg +0 -0
  204. package/core/built/{assets → admin/production/assets}/icons/mobile-phone.svg +0 -0
  205. package/core/built/{assets → admin/production/assets}/icons/module.svg +0 -0
  206. package/core/built/{assets → admin/production/assets}/icons/modules.svg +0 -0
  207. package/core/built/{assets → admin/production/assets}/icons/monitor-labs.svg +0 -0
  208. package/core/built/{assets → admin/production/assets}/icons/moon.svg +0 -0
  209. package/core/built/{assets → admin/production/assets}/icons/mountains.svg +0 -0
  210. package/core/built/{assets → admin/production/assets}/icons/mute.svg +0 -0
  211. package/core/built/{assets → admin/production/assets}/icons/navigation.svg +0 -0
  212. package/core/built/{assets → admin/production/assets}/icons/network.svg +0 -0
  213. package/core/built/{assets → admin/production/assets}/icons/news-article.svg +0 -0
  214. package/core/built/{assets → admin/production/assets}/icons/nightshift.svg +0 -0
  215. package/core/built/{assets → admin/production/assets}/icons/no-data-line-chart.svg +0 -0
  216. package/core/built/{assets → admin/production/assets}/icons/no-data-list.svg +0 -0
  217. package/core/built/{assets → admin/production/assets}/icons/no-data-subscription.svg +0 -0
  218. package/core/built/{assets → admin/production/assets}/icons/no-email.svg +0 -0
  219. package/core/built/{assets → admin/production/assets}/icons/no-members.svg +0 -0
  220. package/core/built/{assets → admin/production/assets}/icons/offer.svg +0 -0
  221. package/core/built/{assets → admin/production/assets}/icons/page-bold.svg +0 -0
  222. package/core/built/{assets → admin/production/assets}/icons/page.svg +0 -0
  223. package/core/built/{assets → admin/production/assets}/icons/pages-placeholder.svg +0 -0
  224. package/core/built/{assets → admin/production/assets}/icons/paint-palette.svg +0 -0
  225. package/core/built/{assets → admin/production/assets}/icons/paintbrush.svg +0 -0
  226. package/core/built/{assets → admin/production/assets}/icons/pause.svg +0 -0
  227. package/core/built/{assets → admin/production/assets}/icons/pen.svg +0 -0
  228. package/core/built/{assets → admin/production/assets}/icons/pencil-circle.svg +0 -0
  229. package/core/built/{assets → admin/production/assets}/icons/pencil.svg +0 -0
  230. package/core/built/{assets → admin/production/assets}/icons/percentage.svg +0 -0
  231. package/core/built/{assets → admin/production/assets}/icons/photos-people.svg +0 -0
  232. package/core/built/{assets → admin/production/assets}/icons/photos.svg +0 -0
  233. package/core/built/{assets → admin/production/assets}/icons/piggy-bank.svg +0 -0
  234. package/core/built/{assets → admin/production/assets}/icons/pin.svg +0 -0
  235. package/core/built/{assets → admin/production/assets}/icons/plane.svg +0 -0
  236. package/core/built/{assets → admin/production/assets}/icons/play.svg +0 -0
  237. package/core/built/{assets → admin/production/assets}/icons/plus.svg +0 -0
  238. package/core/built/{assets → admin/production/assets}/icons/portal-icon-1.svg +0 -0
  239. package/core/built/{assets → admin/production/assets}/icons/portal-icon-2.svg +0 -0
  240. package/core/built/{assets → admin/production/assets}/icons/portal-icon-3.svg +0 -0
  241. package/core/built/{assets → admin/production/assets}/icons/portal-icon-4.svg +0 -0
  242. package/core/built/{assets → admin/production/assets}/icons/portal-icon-5.svg +0 -0
  243. package/core/built/{assets → admin/production/assets}/icons/portal-logo-stroke.svg +0 -0
  244. package/core/built/{assets → admin/production/assets}/icons/portal-logo.svg +0 -0
  245. package/core/built/{assets → admin/production/assets}/icons/post.svg +0 -0
  246. package/core/built/{assets → admin/production/assets}/icons/posts-placeholder.svg +0 -0
  247. package/core/built/{assets → admin/production/assets}/icons/posts.svg +0 -0
  248. package/core/built/{assets → admin/production/assets}/icons/powered-by-stripe.svg +0 -0
  249. package/core/built/{assets → admin/production/assets}/icons/powered-by-tenor.svg +0 -0
  250. package/core/built/{assets → admin/production/assets}/icons/presentation-code.svg +0 -0
  251. package/core/built/{assets → admin/production/assets}/icons/published-post.svg +0 -0
  252. package/core/built/{assets → admin/production/assets}/icons/recycle.svg +0 -0
  253. package/core/built/{assets → admin/production/assets}/icons/reload.svg +0 -0
  254. package/core/built/{assets → admin/production/assets}/icons/repo.svg +0 -0
  255. package/core/built/{assets → admin/production/assets}/icons/retry.svg +0 -0
  256. package/core/built/{assets → admin/production/assets}/icons/satellite.svg +0 -0
  257. package/core/built/{assets → admin/production/assets}/icons/search.svg +0 -0
  258. package/core/built/{assets → admin/production/assets}/icons/send-email.svg +0 -0
  259. package/core/built/{assets → admin/production/assets}/icons/server.svg +0 -0
  260. package/core/built/{assets → admin/production/assets}/icons/settings.svg +0 -0
  261. package/core/built/{assets → admin/production/assets}/icons/shield-lock.svg +0 -0
  262. package/core/built/{assets → admin/production/assets}/icons/shield.svg +0 -0
  263. package/core/built/{assets → admin/production/assets}/icons/sidemenu-open.svg +0 -0
  264. package/core/built/{assets → admin/production/assets}/icons/sidemenu.svg +0 -0
  265. package/core/built/{assets → admin/production/assets}/icons/signal-tower.svg +0 -0
  266. package/core/built/{assets → admin/production/assets}/icons/signout.svg +0 -0
  267. package/core/built/{assets → admin/production/assets}/icons/smiley.svg +0 -0
  268. package/core/built/{assets → admin/production/assets}/icons/social-facebook.svg +0 -0
  269. package/core/built/{assets → admin/production/assets}/icons/social-share.svg +0 -0
  270. package/core/built/{assets → admin/production/assets}/icons/social-twitter.svg +0 -0
  271. package/core/built/{assets → admin/production/assets}/icons/spinner.svg +0 -0
  272. package/core/built/{assets → admin/production/assets}/icons/staff.svg +0 -0
  273. package/core/built/{assets → admin/production/assets}/icons/star-filled.svg +0 -0
  274. package/core/built/{assets → admin/production/assets}/icons/store.svg +0 -0
  275. package/core/built/{assets → admin/production/assets}/icons/stripe-verified-partner-badge.svg +0 -0
  276. package/core/built/{assets → admin/production/assets}/icons/summer.svg +0 -0
  277. package/core/built/{assets → admin/production/assets}/icons/sun.svg +0 -0
  278. package/core/built/{assets → admin/production/assets}/icons/support.svg +0 -0
  279. package/core/built/{assets → admin/production/assets}/icons/sync.svg +0 -0
  280. package/core/built/{assets → admin/production/assets}/icons/tag.svg +0 -0
  281. package/core/built/{assets → admin/production/assets}/icons/tags-placeholder.svg +0 -0
  282. package/core/built/{assets → admin/production/assets}/icons/tenor.svg +0 -0
  283. package/core/built/{assets → admin/production/assets}/icons/terminal.svg +0 -0
  284. package/core/built/{assets → admin/production/assets}/icons/text-vector.svg +0 -0
  285. package/core/built/{assets → admin/production/assets}/icons/text.svg +0 -0
  286. package/core/built/{assets → admin/production/assets}/icons/theme.svg +0 -0
  287. package/core/built/{assets → admin/production/assets}/icons/ticket.svg +0 -0
  288. package/core/built/{assets → admin/production/assets}/icons/trash.svg +0 -0
  289. package/core/built/{assets → admin/production/assets}/icons/trophy.svg +0 -0
  290. package/core/built/{assets → admin/production/assets}/icons/tumbleweed.svg +0 -0
  291. package/core/built/{assets → admin/production/assets}/icons/twitter-comment.svg +0 -0
  292. package/core/built/{assets → admin/production/assets}/icons/twitter-like.svg +0 -0
  293. package/core/built/{assets → admin/production/assets}/icons/twitter-link.svg +0 -0
  294. package/core/built/{assets → admin/production/assets}/icons/twitter-logo.svg +0 -0
  295. package/core/built/{assets → admin/production/assets}/icons/twitter-retweet.svg +0 -0
  296. package/core/built/{assets → admin/production/assets}/icons/twitter-share.svg +0 -0
  297. package/core/built/{assets → admin/production/assets}/icons/twitter.svg +0 -0
  298. package/core/built/{assets → admin/production/assets}/icons/ufo-attack.svg +0 -0
  299. package/core/built/{assets → admin/production/assets}/icons/unmute.svg +0 -0
  300. package/core/built/{assets → admin/production/assets}/icons/unsplash-heart.svg +0 -0
  301. package/core/built/{assets → admin/production/assets}/icons/unsplash.svg +0 -0
  302. package/core/built/{assets → admin/production/assets}/icons/unsubscribed.svg +0 -0
  303. package/core/built/{assets → admin/production/assets}/icons/upload-fill.svg +0 -0
  304. package/core/built/{assets → admin/production/assets}/icons/upload.svg +0 -0
  305. package/core/built/{assets → admin/production/assets}/icons/user-circle.svg +0 -0
  306. package/core/built/{assets → admin/production/assets}/icons/user-group.svg +0 -0
  307. package/core/built/{assets → admin/production/assets}/icons/user-group2.svg +0 -0
  308. package/core/built/{assets → admin/production/assets}/icons/v-ellipsis.svg +0 -0
  309. package/core/built/{assets → admin/production/assets}/icons/view-site.svg +0 -0
  310. package/core/built/{assets → admin/production/assets}/icons/warning-stroke.svg +0 -0
  311. package/core/built/{assets → admin/production/assets}/icons/warning.svg +0 -0
  312. package/core/built/{assets → admin/production/assets}/icons/window-app.svg +0 -0
  313. package/core/built/{assets → admin/production/assets}/icons/window-pulse.svg +0 -0
  314. package/core/built/{assets → admin/production/assets}/icons/wrench-double.svg +0 -0
  315. package/core/built/{assets → admin/production/assets}/icons/zap.svg +0 -0
  316. package/core/built/{assets → admin/production/assets}/img/404-ghost-e112dbfadde79cf30dbca8e8cfe7a21a.png +0 -0
  317. package/core/built/{assets → admin/production/assets}/img/404-ghost@2x-34c1119ed15cc3ea71e4406f80c8e810.png +0 -0
  318. package/core/built/{assets → admin/production/assets}/img/abstract-2-2937e2902b64360d0cbe4cec8bd8479b.jpg +0 -0
  319. package/core/built/{assets → admin/production/assets}/img/abstract-c52b2f4208e7fd2e7b8abd8b1eec4f7b.jpg +0 -0
  320. package/core/built/{assets → admin/production/assets}/img/amp.svg +0 -0
  321. package/core/built/{assets → admin/production/assets}/img/apple-touch-icon-74680e326a7e87b159d366c7d4fb3d4b.png +0 -0
  322. package/core/built/{assets → admin/production/assets}/img/buffer-db31f6b5dc27a298050e16312619c586.png +0 -0
  323. package/core/built/{assets → admin/production/assets}/img/community-background-3f501ff1d764d0cb81f7c2cbacfc6503.jpg +0 -0
  324. package/core/built/{assets → admin/production/assets}/img/community-be8c1dcecfb157f2bfba5cababc8e686.jpg +0 -0
  325. package/core/built/{assets → admin/production/assets}/img/dashboard/bp1-03a13253453b372d0bbd5e6a19b20fca.jpg +0 -0
  326. package/core/built/{assets → admin/production/assets}/img/dashboard/bp2-ed14f9f48c56d5d6fe997dc637a8b1ad.jpg +0 -0
  327. package/core/built/{assets → admin/production/assets}/img/dashboard/join-community-bb5478f7dca6c04a2d0baf2b02f880fb.jpg +0 -0
  328. package/core/built/{assets → admin/production/assets}/img/dashboard-feature-image-8949197550decb94a8f1dea57ad47819.jpeg +0 -0
  329. package/core/built/{assets → admin/production/assets}/img/disqus.svg +0 -0
  330. package/core/built/{assets → admin/production/assets}/img/favicon.ico +0 -0
  331. package/core/built/{assets → admin/production/assets}/img/firstpromoter-ce8b5219e5b5ebda463bd60396c6ab81.png +0 -0
  332. package/core/built/{assets → admin/production/assets}/img/footer-marketplace-bg-572b6c6486a7e26316954d599eaa9f30.png +0 -0
  333. package/core/built/{assets → admin/production/assets}/img/get-started-995c36b9ede90bb3777c83751e798ef7.jpg +0 -0
  334. package/core/built/{assets → admin/production/assets}/img/github.svg +0 -0
  335. package/core/built/{assets → admin/production/assets}/img/google-analytics-e05fc1327377939663407200d4978eba.png +0 -0
  336. package/core/built/{assets → admin/production/assets}/img/google-docs.svg +0 -0
  337. package/core/built/{assets → admin/production/assets}/img/install-welcome-ff3912d18bf8949df89c83b1c3b8bb66.png +0 -0
  338. package/core/built/{assets → admin/production/assets}/img/invite-placeholder-4b3731d47c6c8f6cb3aaa6bc4d870c9f.png +0 -0
  339. package/core/built/{assets → admin/production/assets}/img/large-ac90af7c93a4b47e8d956fa9fef31d9d.png +0 -0
  340. package/core/built/{assets → admin/production/assets}/img/launch-wizard-bg-13b995b1f02bce34b269db3190897384.png +0 -0
  341. package/core/built/{assets → admin/production/assets}/img/loadingcat-5f501b7a8c7bd54b253463e261c99634.gif +0 -0
  342. package/core/built/{assets → admin/production/assets}/img/logos/ghost-logo-black-1-fb561a374422b405ec90fa586b05ebdf.png +0 -0
  343. package/core/built/{assets → admin/production/assets}/img/logos/orb-black-1-32b72766be2164fdea6ab2565fb1c137.png +0 -0
  344. package/core/built/{assets → admin/production/assets}/img/logos/orb-black-2-4b0baef1ec34816af6f3fbede7ab191d.png +0 -0
  345. package/core/built/{assets → admin/production/assets}/img/logos/orb-black-3-9780c5e9991b69ed2303b526aa3e3252.png +0 -0
  346. package/core/built/{assets → admin/production/assets}/img/logos/orb-black-4-d9c3caacb8d2ba98a52517ff2971433c.png +0 -0
  347. package/core/built/{assets → admin/production/assets}/img/logos/orb-black-5-063a200f749e09c587b9443ffd2c4cfa.png +0 -0
  348. package/core/built/{assets → admin/production/assets}/img/mailchimp.svg +0 -0
  349. package/core/built/{assets → admin/production/assets}/img/marketing/members-1-8b89a1f48fe7b336754e91a429531f65.jpg +0 -0
  350. package/core/built/{assets → admin/production/assets}/img/marketing/members-2-791205c82d5cf221f8c99a74f9ee1739.jpg +0 -0
  351. package/core/built/{assets → admin/production/assets}/img/marketing/offers-1-f2e1b653c4d5bb90eea9d7a2862530f9.jpg +0 -0
  352. package/core/built/{assets → admin/production/assets}/img/marketing/offers-2-28a225d34cc39d133748431536961d00.jpg +0 -0
  353. package/core/built/{assets → admin/production/assets}/img/marketing/offers-3-2094c91ab21a16c37fbe6ec16c140160.jpg +0 -0
  354. package/core/built/{assets → admin/production/assets}/img/medium-fef07013cffd5c45a655a250912a0ad7.png +0 -0
  355. package/core/built/{assets → admin/production/assets}/img/more-fe5480ab76c7be7aec28bcfe844f41c1.png +0 -0
  356. package/core/built/{assets → admin/production/assets}/img/newsletter-1-197ae8063dfb2e22278d355198029c9e.jpg +0 -0
  357. package/core/built/{assets → admin/production/assets}/img/newsletter-2-5a2c7693ea9380d4282061302c01267a.jpg +0 -0
  358. package/core/built/{assets → admin/production/assets}/img/orb-squircle-645fd62e92a80557905c0cb60874b699.png +0 -0
  359. package/core/built/{assets → admin/production/assets}/img/patreon.svg +0 -0
  360. package/core/built/{assets → admin/production/assets}/img/paypal.svg +0 -0
  361. package/core/built/{assets → admin/production/assets}/img/plausible-1b754a95e19a6d935e0bc8bf6790ba56.png +0 -0
  362. package/core/built/{assets → admin/production/assets}/img/resource-1-722f202795856e4a5596c8a3b7bedc43.jpg +0 -0
  363. package/core/built/{assets → admin/production/assets}/img/slackicon-406aadea8994ca2ddee9c1d7157208db.png +0 -0
  364. package/core/built/{assets → admin/production/assets}/img/small-b90396925485f17b2ca82c31be42de5f.png +0 -0
  365. package/core/built/{assets → admin/production/assets}/img/themes/Alto-a5172a42994782321d8c9f268928d987.jpg +0 -0
  366. package/core/built/{assets → admin/production/assets}/img/themes/Alto-cut-c667d9d6457c5e981aa7bdc8946b215a.jpg +0 -0
  367. package/core/built/{assets → admin/production/assets}/img/themes/Alto-f4db5af43ca9771c7ac1f754de3ddf2f.png +0 -0
  368. package/core/built/{assets → admin/production/assets}/img/themes/Bulletin-57d45b992ff0e26e0acdce7ed4cccd67.png +0 -0
  369. package/core/built/{assets → admin/production/assets}/img/themes/Casper-19b7267aac5acc6abfaaed7e41eddae8.jpg +0 -0
  370. package/core/built/{assets → admin/production/assets}/img/themes/Dawn-be81aa8c8caae8fcfb5d5fbec823fdcc.png +0 -0
  371. package/core/built/{assets → admin/production/assets}/img/themes/Digest-d3467ac22a290e1ad3a543014758286e.png +0 -0
  372. package/core/built/{assets → admin/production/assets}/img/themes/Dope-6f8e0bbc199ce4af9a60859e9e6a74ad.png +0 -0
  373. package/core/built/{assets → admin/production/assets}/img/themes/Ease-7cfb8f06f9b66b1aa04b92493a471fef.jpg +0 -0
  374. package/core/built/{assets → admin/production/assets}/img/themes/Ease-9c279ea6cec3c0f1823f81c9dd24b116.png +0 -0
  375. package/core/built/{assets → admin/production/assets}/img/themes/Ease-cut-78d5aa00682bee6a4cf22155f09e49e8.jpg +0 -0
  376. package/core/built/{assets → admin/production/assets}/img/themes/Edge-0258906309e11fd075a1d9880aa09b20.png +0 -0
  377. package/core/built/{assets → admin/production/assets}/img/themes/Edition-b94372eb5c88fce0f4befba39148ff28.jpg +0 -0
  378. package/core/built/{assets → admin/production/assets}/img/themes/Edition-cut-e6545bab2768aafa1996100774f310ff.jpg +0 -0
  379. package/core/built/{assets → admin/production/assets}/img/themes/Edition-d8f508e93bc24bdf2716ae6f8b3d44f8.png +0 -0
  380. package/core/built/{assets → admin/production/assets}/img/themes/Headline-c5070cf549e797a6a72b87237caa1617.jpg +0 -0
  381. package/core/built/{assets → admin/production/assets}/img/themes/Journal-accf0031bbae0919900a049061e65a04.png +0 -0
  382. package/core/built/{assets → admin/production/assets}/img/themes/London-3f07efcee9e5bfb9a33827064eb77e70.jpg +0 -0
  383. package/core/built/{assets → admin/production/assets}/img/themes/London-cut-599cba221f81a15ad37fe395cf4e572c.jpg +0 -0
  384. package/core/built/{assets → admin/production/assets}/img/themes/Ruby-11a53c62015612f4b3aca8f503121225.png +0 -0
  385. package/core/built/{assets → admin/production/assets}/img/themes/Wave-86e8044c2d76cb57a9030e4c24ac9520.png +0 -0
  386. package/core/built/{assets → admin/production/assets}/img/touch-icon-ipad-2e78629d62ad05746f980f14623dfadb.png +0 -0
  387. package/core/built/{assets → admin/production/assets}/img/touch-icon-iphone-93ed4382d391be9180093fd77ce8f410.png +0 -0
  388. package/core/built/{assets → admin/production/assets}/img/twitter.svg +0 -0
  389. package/core/built/{assets → admin/production/assets}/img/typeform.svg +0 -0
  390. package/core/built/{assets → admin/production/assets}/img/ulysses-3c66b59fb45c285bf336b4b613dc86e4.png +0 -0
  391. package/core/built/{assets → admin/production/assets}/img/unsplash-404-71ab3705c9920a9706bb822c3d7e34d1.png +0 -0
  392. package/core/built/{assets → admin/production/assets}/img/user-cover-e8f42b12b5fcba292a8b5dfa81e13dd2.png +0 -0
  393. package/core/built/{assets → admin/production/assets}/img/user-image-639a88b784fb5f10964be8b975ca9fdf.png +0 -0
  394. package/core/built/{assets → admin/production/assets}/img/users-33427addfe0f11c78b42cccaf83be073.png +0 -0
  395. package/core/built/{assets → admin/production/assets}/img/whats-new-header-bg.svg +0 -0
  396. package/core/built/{assets → admin/production/assets}/img/zapier-logo.svg +0 -0
  397. package/core/built/{assets → admin/production/assets}/img/zapier.svg +0 -0
  398. package/core/built/{assets → admin/production/assets}/img/zero-bounce-ee799eddb1f88e33ab8c462858cbfed9.png +0 -0
  399. package/core/built/{assets/simplemde/simplemde-fb4527da6e489b34dc24b28ea870b286.js → admin/production/assets/simplemde/simplemde-0cd04dbb388ed0cf571a6808464ea57e.js} +1 -1
  400. package/core/built/admin/production/assets/vendor-39e3abc175134f5c42eaa7c4a2d6f479.js +13800 -0
  401. package/core/built/{assets/vendor.min-4a6661c574707ceca220aa2e76558995.css → admin/production/assets/vendor-bc9d2c9e5c8a33f0c92e81189d48e04c.css} +17 -9
  402. package/core/{server/web/admin/views/default.html → built/admin/production/index.html} +13 -15
  403. package/core/frontend/helpers/comment_count.js +15 -9
  404. package/core/frontend/helpers/comments.js +17 -4
  405. package/core/frontend/helpers/img_url.js +67 -6
  406. package/core/frontend/src/comment-counts/js/comment-counts.js +17 -2
  407. package/core/frontend/web/middleware/handle-image-sizes.js +7 -11
  408. package/core/server/api/endpoints/{comments-comments.js → comments-members.js} +9 -63
  409. package/core/server/api/endpoints/index.js +2 -6
  410. package/core/server/api/endpoints/utils/serializers/output/mappers/posts.js +11 -0
  411. package/core/server/api/endpoints/utils/serializers/output/utils/clean.js +4 -0
  412. package/core/server/data/migrations/versions/5.3/2022-07-06-09-17-add-ghost-explore-integration.js +0 -1
  413. package/core/server/data/migrations/versions/5.3/2022-07-06-09-26-add-ghost-explore-integration-api-key.js +0 -1
  414. package/core/server/data/migrations/versions/5.6/2022-07-27-13-40-change-explore-type.js +24 -0
  415. package/core/server/data/schema/fixtures/fixtures.json +1 -1
  416. package/core/server/models/comment.js +34 -14
  417. package/core/server/services/bulk-email/bulk-email-processor.js +6 -0
  418. package/core/server/services/comments/controller.js +92 -0
  419. package/core/server/services/comments/email-templates/new-comment-reply.hbs +4 -4
  420. package/core/server/services/comments/email-templates/new-comment-reply.txt.js +1 -1
  421. package/core/server/services/comments/email-templates/new-comment.hbs +3 -3
  422. package/core/server/services/comments/email-templates/new-comment.txt.js +1 -1
  423. package/core/server/services/comments/email-templates/report.hbs +2 -2
  424. package/core/server/services/comments/email-templates/report.txt.js +1 -1
  425. package/core/server/services/comments/emails.js +3 -3
  426. package/core/server/services/comments/index.js +10 -1
  427. package/core/server/services/comments/service.js +101 -11
  428. package/core/server/services/comments/stats.js +44 -0
  429. package/core/server/services/mega/email-preview.js +5 -1
  430. package/core/server/services/mega/mega.js +2 -4
  431. package/core/server/services/mega/post-email-serializer.js +97 -2
  432. package/core/server/services/mega/segment-parser.js +10 -1
  433. package/core/server/services/members/service.js +9 -4
  434. package/core/server/web/admin/app.js +3 -1
  435. package/core/server/web/admin/controller.js +2 -2
  436. package/core/server/web/comments/routes.js +9 -9
  437. package/core/shared/config/defaults.json +1 -1
  438. package/core/shared/config/overrides.json +1 -2
  439. package/core/shared/html-to-plaintext.js +18 -0
  440. package/core/shared/labs.js +6 -2
  441. package/core/shared/settings-cache/cache.js +103 -84
  442. package/core/shared/settings-cache/index.js +7 -9
  443. package/package.json +53 -32
  444. package/yarn.lock +381 -552
  445. package/core/built/assets/chunk.3.550552fbc71864fb9738.js +0 -197
  446. package/core/built/assets/vendor.min-cf3af99dca0c71937669305afb3686a1.js +0 -23793
  447. package/core/server/web/admin/views/default-prod.html +0 -63
@@ -2,15 +2,18 @@ const _ = require('lodash');
2
2
  const template = require('./template');
3
3
  const settingsCache = require('../../../shared/settings-cache');
4
4
  const urlUtils = require('../../../shared/url-utils');
5
+ const labs = require('../../../shared/labs');
5
6
  const moment = require('moment-timezone');
6
7
  const api = require('../../api').endpoints;
7
8
  const apiShared = require('../../api').shared;
8
9
  const {URL} = require('url');
9
10
  const mobiledocLib = require('../../lib/mobiledoc');
10
11
  const htmlToPlaintext = require('../../../shared/html-to-plaintext');
12
+ const membersService = require('../members');
11
13
  const {isUnsplashImage, isLocalContentImage} = require('@tryghost/kg-default-cards/lib/utils');
12
14
  const {textColorForBackgroundColor, darkenToContrastThreshold} = require('@tryghost/color-utils');
13
15
  const logging = require('@tryghost/logging');
16
+ const urlService = require('../../services/url');
14
17
 
15
18
  const ALLOWED_REPLACEMENTS = ['first_name'];
16
19
 
@@ -74,6 +77,27 @@ const createUnsubscribeUrl = (uuid, newsletterUuid) => {
74
77
  return unsubscribeUrl.href;
75
78
  };
76
79
 
80
+ /**
81
+ * createPostSignupUrl
82
+ *
83
+ * Takes a post object. Returns the url that should be used to signup from newsletter
84
+ *
85
+ * @param {Object} post post object
86
+ */
87
+ const createPostSignupUrl = (post) => {
88
+ let url = urlService.getUrlByResourceId(post.id, {absolute: true});
89
+
90
+ // For email-only posts, use site url as base
91
+ if (post.status !== 'published' && url.match(/\/404\//)) {
92
+ url = urlUtils.getSiteUrl();
93
+ }
94
+
95
+ const signupUrl = new URL(url);
96
+ signupUrl.hash = `/portal/signup`;
97
+
98
+ return signupUrl.href;
99
+ };
100
+
77
101
  // NOTE: serialization is needed to make sure we do post transformations such as image URL transformation from relative to absolute
78
102
  const serializePostModel = async (model) => {
79
103
  // fetch mobiledoc rather than html and plaintext so we can render email-specific contents
@@ -297,18 +321,87 @@ const serialize = async (postModel, newsletter, options = {isBrowserPreview: fal
297
321
  html: formatHtmlForEmail(htmlTemplate),
298
322
  plaintext: post.plaintext
299
323
  });
300
-
301
- return {
324
+ const data = {
302
325
  subject: post.email_subject || post.title,
303
326
  html,
304
327
  plaintext
305
328
  };
329
+ if (labs.isSet('newsletterPaywall')) {
330
+ data.post = post;
331
+ }
332
+ return data;
306
333
  };
307
334
 
335
+ /**
336
+ * renderPaywallCTA
337
+ *
338
+ * outputs html for rendering paywall CTA in newsletter
339
+ *
340
+ * @param {Object} post Post Object
341
+ */
342
+
343
+ function renderPaywallCTA(post) {
344
+ const accentColor = settingsCache.get('accent_color');
345
+ const siteTitle = settingsCache.get('title') || 'Ghost';
346
+ const signupUrl = createPostSignupUrl(post);
347
+
348
+ return `<div class="align-center" style="text-align: center;">
349
+ <hr
350
+ style="position: relative; display: block; width: 100%; margin: 3em 0; padding: 0; height: 1px; border: 0; border-top: 1px solid #e5eff5;">
351
+ <h2
352
+ style="margin-top: 0; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; line-height: 1.11em; font-weight: 700; text-rendering: optimizeLegibility; margin: 1.5em 0 0.5em 0; font-size: 26px;">
353
+ Subscribe to <span style="white-space: nowrap; font-size: 26px !important;">continue reading.</span></h2>
354
+ <p style="margin: 0 auto 1.5em auto; line-height: 1.6em; max-width: 440px;">Become a paid member of ${siteTitle} to get access to all
355
+ <span style="white-space: nowrap;">subscriber-only content.</span></p>
356
+ <div class="btn btn-accent" style="box-sizing: border-box; width: 100%; display: table;">
357
+ <table border="0" cellspacing="0" cellpadding="0" align="center"
358
+ style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: auto;">
359
+ <tbody>
360
+ <tr>
361
+ <td align="center"
362
+ style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; vertical-align: top; text-align: center; border-radius: 5px;"
363
+ valign="top" bgcolor="${accentColor}">
364
+ <a href="${signupUrl}"
365
+ style="overflow-wrap: anywhere; border: solid 1px #3498db; border-radius: 5px; box-sizing: border-box; cursor: pointer; display: inline-block; font-size: 14px; font-weight: bold; margin: 0; padding: 12px 25px; text-decoration: none; background-color: ${accentColor}; border-color: ${accentColor}; color: #FFFFFF;"
366
+ target="_blank">Subscribe
367
+ </a>
368
+ </td>
369
+ </tr>
370
+ </tbody>
371
+ </table>
372
+ </div>
373
+ <p style="margin: 0 0 1.5em 0; line-height: 1.6em;"></p>
374
+ </div>`;
375
+ }
376
+
308
377
  function renderEmailForSegment(email, memberSegment) {
309
378
  const cheerio = require('cheerio');
310
379
 
311
380
  const result = {...email};
381
+
382
+ /** Checks and hides content for newsletter behind paywall card
383
+ * based on member's status and post access
384
+ * Adds CTA in case content is hidden.
385
+ */
386
+ if (labs.isSet('newsletterPaywall')) {
387
+ const paywallIndex = (result.html || '').indexOf('<!--members-only-->');
388
+ if (paywallIndex !== -1 && memberSegment && result.post) {
389
+ let statusFilter = memberSegment === 'status:free' ? {status: 'free'} : {status: 'paid'};
390
+ const postVisiblity = result.post.visibility;
391
+
392
+ // For newsletter paywall, specific tiers visibility is considered on par to paid tiers
393
+ result.post.visibility = postVisiblity === 'tiers' ? 'paid' : postVisiblity;
394
+
395
+ const memberHasAccess = membersService.contentGating.checkPostAccess(result.post, statusFilter);
396
+
397
+ if (!memberHasAccess) {
398
+ const postContentEndIdx = result.html.search(/[\s\n\r]+?<!-- POST CONTENT END -->/);
399
+ result.html = result.html.slice(0, paywallIndex) + renderPaywallCTA(result.post) + result.html.slice(postContentEndIdx);
400
+ result.plaintext = htmlToPlaintext.excerpt(result.html);
401
+ }
402
+ }
403
+ }
404
+
312
405
  const $ = cheerio.load(result.html);
313
406
 
314
407
  $('[data-gh-segment]').get().forEach((node) => {
@@ -322,6 +415,7 @@ function renderEmailForSegment(email, memberSegment) {
322
415
 
323
416
  result.html = formatHtmlForEmail($.html());
324
417
  result.plaintext = htmlToPlaintext.email(result.html);
418
+ delete result.post;
325
419
 
326
420
  return result;
327
421
  }
@@ -329,6 +423,7 @@ function renderEmailForSegment(email, memberSegment) {
329
423
  module.exports = {
330
424
  serialize,
331
425
  createUnsubscribeUrl,
426
+ createPostSignupUrl,
332
427
  renderEmailForSegment,
333
428
  parseReplacements,
334
429
  // Export for tests
@@ -1,11 +1,20 @@
1
+ const labs = require('../../../shared/labs');
2
+
1
3
  const getSegmentsFromHtml = (html) => {
2
4
  const cheerio = require('cheerio');
3
5
  const $ = cheerio.load(html);
4
6
 
5
- const allSegments = $('[data-gh-segment]')
7
+ let allSegments = $('[data-gh-segment]')
6
8
  .get()
7
9
  .map(el => el.attribs['data-gh-segment']);
8
10
 
11
+ /**
12
+ * Always add free and paid segments if email has paywall card
13
+ */
14
+ if (labs.isSet('newsletterPaywall') && html.indexOf('<!--members-only-->') !== -1) {
15
+ allSegments = allSegments.concat(['status:free', 'status:-free']);
16
+ }
17
+
9
18
  // only return unique elements
10
19
  return [...new Set(allSegments)];
11
20
  };
@@ -148,10 +148,15 @@ module.exports = {
148
148
  }
149
149
  })();
150
150
 
151
- try {
152
- await stripeService.migrations.execute();
153
- } catch (err) {
154
- logging.error(err);
151
+ const membersMigrationJobName = 'members-migrations';
152
+ if (!(await jobsService.hasExecutedSuccessfully(membersMigrationJobName))) {
153
+ jobsService.addOneOffJob({
154
+ name: membersMigrationJobName,
155
+ offloaded: false,
156
+ job: stripeService.migrations.execute.bind(stripeService.migrations)
157
+ });
158
+
159
+ await jobsService.awaitCompletion(membersMigrationJobName);
155
160
  }
156
161
  },
157
162
  contentGating: require('./content-gating'),
@@ -1,4 +1,5 @@
1
1
  const debug = require('@tryghost/debug')('web:admin:app');
2
+ const path = require('path');
2
3
  const express = require('../../../shared/express');
3
4
  const serveStatic = express.static;
4
5
  const config = require('../../../shared/config');
@@ -16,8 +17,9 @@ module.exports = function setupAdminApp() {
16
17
  // Admin assets
17
18
  // @TODO ensure this gets a local 404 error handler
18
19
  const configMaxAge = config.get('caching:admin:maxAge');
20
+ const envDir = config.get('env') === 'production' ? 'production' : 'development';
19
21
  adminApp.use('/assets', serveStatic(
20
- config.get('paths').adminAssets,
22
+ path.join(config.get('paths').adminAssets, envDir, 'assets'),
21
23
  {maxAge: (configMaxAge || configMaxAge === 0) ? configMaxAge : constants.ONE_YEAR_MS, fallthrough: false}
22
24
  ));
23
25
 
@@ -29,8 +29,8 @@ module.exports = function adminController(req, res) {
29
29
  // CASE: trigger update check unit and let it run in background, don't block the admin rendering
30
30
  updateCheck();
31
31
 
32
- const defaultTemplate = config.get('env') === 'production' ? 'default-prod.html' : 'default.html';
33
- const templatePath = path.resolve(config.get('paths').adminViews, defaultTemplate);
32
+ const envDir = config.get('env') === 'production' ? 'production' : 'development';
33
+ const templatePath = path.resolve(config.get('paths').adminAssets, envDir, 'index.html');
34
34
  const headers = {};
35
35
 
36
36
  try {
@@ -13,18 +13,18 @@ module.exports = function apiRoutes() {
13
13
  // Global handling for member session, ensures a member is logged in to the frontend
14
14
  router.use(membersService.middleware.loadMemberSession);
15
15
 
16
- router.post('/counts', http(api.commentsComments.counts));
16
+ router.post('/counts', http(api.commentsMembers.counts));
17
17
 
18
- router.get('/', http(api.commentsComments.browse));
19
- router.get('/:id', http(api.commentsComments.read));
20
- router.post('/', http(api.commentsComments.add));
21
- router.put('/:id', http(api.commentsComments.edit));
22
- router.delete('/:id', http(api.commentsComments.destroy));
18
+ router.get('/', http(api.commentsMembers.browse));
19
+ router.get('/:id', http(api.commentsMembers.read));
20
+ router.post('/', http(api.commentsMembers.add));
21
+ router.put('/:id', http(api.commentsMembers.edit));
22
+ router.delete('/:id', http(api.commentsMembers.destroy));
23
23
 
24
- router.post('/:id/like', http(api.commentsComments.like));
25
- router.delete('/:id/like', http(api.commentsComments.unlike));
24
+ router.post('/:id/like', http(api.commentsMembers.like));
25
+ router.delete('/:id/like', http(api.commentsMembers.unlike));
26
26
 
27
- router.post('/:id/report', http(api.commentsComments.report));
27
+ router.post('/:id/report', http(api.commentsMembers.report));
28
28
 
29
29
  return router;
30
30
  };
@@ -147,7 +147,7 @@
147
147
  "version": "0.2"
148
148
  },
149
149
  "editor": {
150
- "url": ""
150
+ "url": "https://cdn.jsdelivr.net/npm/@tryghost/koenig-react/dist/umd/koenig-react.min.js"
151
151
  },
152
152
  "tenor": {
153
153
  "publicReadOnlyApiKey": null,
@@ -2,10 +2,9 @@
2
2
  "paths": {
3
3
  "appRoot": ".",
4
4
  "corePath": "core/",
5
- "adminAssets": "core/built/assets",
5
+ "adminAssets": "core/built/admin",
6
6
  "adminAuthAssets": "content/public/admin-auth",
7
7
  "helperTemplates": "core/frontend/helpers/tpl/",
8
- "adminViews": "core/server/web/admin/views/",
9
8
  "defaultViews": "core/server/views/",
10
9
  "defaultRouteSettings": "core/server/services/route-settings/",
11
10
  "internalAppPath": "core/frontend/apps/",
@@ -34,6 +34,7 @@ const baseSettings = {
34
34
 
35
35
  let excerptConverter;
36
36
  let emailConverter;
37
+ let commentConverter;
37
38
 
38
39
  const loadConverters = () => {
39
40
  if (excerptConverter && emailConverter) {
@@ -63,8 +64,19 @@ const loadConverters = () => {
63
64
  ]
64
65
  });
65
66
 
67
+ const commentSettings = mergeSettings({
68
+ preserveNewlines: false,
69
+ selectors: [
70
+ // equiv hideLinkHrefIfSameAsText: true
71
+ {selector: 'a', options: {hideLinkHrefIfSameAsText: true}},
72
+ // No space between <p> tags. An empty <p> is needed
73
+ {selector: 'p', options: {leadingLineBreaks: 1, trailingLineBreaks: 1}}
74
+ ]
75
+ });
76
+
66
77
  excerptConverter = compile(excerptSettings);
67
78
  emailConverter = compile(emailSettings);
79
+ commentConverter = compile(commentSettings);
68
80
  };
69
81
 
70
82
  module.exports.excerpt = (html) => {
@@ -78,3 +90,9 @@ module.exports.email = (html) => {
78
90
 
79
91
  return emailConverter(html);
80
92
  };
93
+
94
+ module.exports.comment = (html) => {
95
+ loadConverters();
96
+
97
+ return commentConverter(html);
98
+ };
@@ -14,7 +14,9 @@ const messages = {
14
14
  };
15
15
 
16
16
  // flags in this list always return `true`, allows quick global enable prior to full flag removal
17
- const GA_FEATURES = [];
17
+ const GA_FEATURES = [
18
+ 'newsletterPaywall'
19
+ ];
18
20
 
19
21
  // NOTE: this allowlist is meant to be used to filter out any unexpected
20
22
  // input for the "labs" setting value
@@ -25,7 +27,9 @@ const BETA_FEATURES = [
25
27
  const ALPHA_FEATURES = [
26
28
  'urlCache',
27
29
  'beforeAfterCard',
28
- 'comments'
30
+ 'comments',
31
+ 'explore',
32
+ 'freeTrial'
29
33
  ];
30
34
 
31
35
  module.exports.GA_KEYS = [...GA_FEATURES];
@@ -4,77 +4,91 @@
4
4
  const debug = require('@tryghost/debug')('settings:cache');
5
5
  const _ = require('lodash');
6
6
 
7
- const publicSettings = require('./public');
8
-
9
- // Local function, only ever used for initializing
10
- // We deliberately call "set" on each model so that set is a consistent interface
11
- const updateSettingFromModel = function updateSettingFromModel(settingModel) {
12
- debug('Auto updating', settingModel.get('key'));
13
- module.exports.set(settingModel.get('key'), settingModel.toJSON());
14
- };
15
-
16
- const updateCalculatedField = function updateCalculatedField(field) {
17
- return () => {
18
- debug('Auto updating', field.key);
19
- module.exports.set(field.key, field.getSetting());
20
- };
21
- };
22
-
23
7
  /**
24
- * ## Cache
25
- * Holds cached settings
26
- * Keyed by setting.key
27
- * Contains the JSON version of the model
28
- * @type {{}} - object of objects
8
+ * Why hasn't this been moved to @tryghost/settings-cache yet?
9
+ *
10
+ * - It currently still couples the frontend and server together in a weird way via the event system
11
+ * - See the notes in core/server/lib/common/events
12
+ * - There's also a plan to introduce a proper caching layer, and rewrite this on top of that
29
13
  */
30
- let settingsCache = {};
31
- let _calculatedFields = [];
14
+ class CacheManager {
15
+ /**
16
+ * @prop {Object} options
17
+ * @prop {{}} options.cache - object of objects. Holds cached settings, keyed by setting.key, contains the JSON version of the model
18
+ * @prop {Object} options.publicSettings - key/value pairs of settings which are publicly accessible
19
+ */
20
+ constructor({cache, publicSettings}) {
21
+ this.settingsCache = cache;
22
+ this.publicSettings = publicSettings;
23
+ this.calculatedFields = [];
24
+
25
+ this.get = this.get.bind(this);
26
+ this.set = this.set.bind(this);
27
+ this.getAll = this.getAll.bind(this);
28
+ this.getPublic = this.getPublic.bind(this);
29
+ this.reset = this.reset.bind(this);
30
+ this._doGet = this._doGet.bind(this);
31
+ this._updateSettingFromModel = this._updateSettingFromModel.bind(this);
32
+ this._updateCalculatedField = this._updateCalculatedField.bind(this);
33
+ }
32
34
 
33
- const doGet = (key, options) => {
34
- if (!settingsCache[key]) {
35
- return;
35
+ // Local function, only ever used for initializing
36
+ // We deliberately call "set" on each model so that set is a consistent interface
37
+ _updateSettingFromModel(settingModel) {
38
+ debug('Auto updating', settingModel.get('key'));
39
+ this.set(settingModel.get('key'), settingModel.toJSON());
36
40
  }
37
41
 
38
- // Don't try to resolve to the value of the setting
39
- if (options && options.resolve === false) {
40
- return settingsCache[key];
42
+ _updateCalculatedField(field) {
43
+ return () => {
44
+ debug('Auto updating', field.key);
45
+ this.set(field.key, field.getSetting());
46
+ };
41
47
  }
42
48
 
43
- // Default behaviour is to try to resolve the value and return that
44
- try {
45
- // CASE: handle literal false
46
- if (settingsCache[key].value === false || settingsCache[key].value === 'false') {
47
- return false;
49
+ _doGet(key, options) {
50
+ if (!this.settingsCache[key]) {
51
+ return;
48
52
  }
49
53
 
50
- // CASE: if a string contains a number e.g. "1", JSON.parse will auto convert into integer
51
- if (!isNaN(Number(settingsCache[key].value))) {
52
- return settingsCache[key].value || null;
54
+ // Don't try to resolve to the value of the setting
55
+ if (options && options.resolve === false) {
56
+ return this.settingsCache[key];
53
57
  }
54
58
 
55
- return JSON.parse(settingsCache[key].value) || null;
56
- } catch (err) {
57
- return settingsCache[key].value || null;
59
+ // Default behaviour is to try to resolve the value and return that
60
+ try {
61
+ // CASE: handle literal false
62
+ if (this.settingsCache[key].value === false || this.settingsCache[key].value === 'false') {
63
+ return false;
64
+ }
65
+
66
+ // CASE: if a string contains a number e.g. "1", JSON.parse will auto convert into integer
67
+ if (!isNaN(Number(this.settingsCache[key].value))) {
68
+ return this.settingsCache[key].value || null;
69
+ }
70
+
71
+ return JSON.parse(this.settingsCache[key].value) || null;
72
+ } catch (err) {
73
+ return this.settingsCache[key].value || null;
74
+ }
58
75
  }
59
- };
60
76
 
61
- /**
62
- *
63
- * IMPORTANT:
64
- * We store settings with a type and a key in the database.
65
- *
66
- * {
67
- * type: core
68
- * key: db_hash
69
- * value: ...
70
- * }
71
- *
72
- * But the settings cache does not allow requesting a value by type, only by key.
73
- * e.g. settingsCache.get('db_hash')
74
- */
75
- module.exports = {
76
77
  /**
77
- * Get a key from the settingsCache
78
+ *
79
+ * IMPORTANT:
80
+ * We store settings with a type and a key in the database.
81
+ *
82
+ * {
83
+ * type: core
84
+ * key: db_hash
85
+ * value: ...
86
+ * }
87
+ *
88
+ * But the settings cache does not allow requesting a value by type, only by key.
89
+ * e.g. settingsCache.get('db_hash')
90
+ *
91
+ * Get a key from the this.settingsCache
78
92
  * Will resolve to the value, including parsing JSON, unless {resolve: false} is passed in as an option
79
93
  * In which case the full JSON version of the model will be resolved
80
94
  *
@@ -83,8 +97,9 @@ module.exports = {
83
97
  * @return {*}
84
98
  */
85
99
  get(key, options) {
86
- return doGet(key, options);
87
- },
100
+ return this._doGet(key, options);
101
+ }
102
+
88
103
  /**
89
104
  * Set a key on the cache
90
105
  * The only way to get an object into the cache
@@ -93,16 +108,17 @@ module.exports = {
93
108
  * @param {object} value json version of settings model
94
109
  */
95
110
  set(key, value) {
96
- settingsCache[key] = _.cloneDeep(value);
97
- },
111
+ this.settingsCache[key] = _.cloneDeep(value);
112
+ }
113
+
98
114
  /**
99
115
  * Get the entire cache object
100
116
  * Uses clone to prevent modifications from being reflected
101
117
  * @return {object} cache
102
118
  */
103
119
  getAll() {
104
- return _.cloneDeep(settingsCache);
105
- },
120
+ return _.cloneDeep(this.settingsCache);
121
+ }
106
122
 
107
123
  /**
108
124
  * Get all the publically accessible cache entries with their correct names
@@ -112,12 +128,13 @@ module.exports = {
112
128
  getPublic() {
113
129
  let settings = {};
114
130
 
115
- _.each(publicSettings, (key, newKey) => {
116
- settings[newKey] = doGet(key) ?? null;
131
+ _.each(this.publicSettings, (key, newKey) => {
132
+ settings[newKey] = this._doGet(key) ?? null;
117
133
  });
118
134
 
119
135
  return settings;
120
- },
136
+ }
137
+
121
138
  /**
122
139
  * Initialise the cache
123
140
  *
@@ -134,45 +151,47 @@ module.exports = {
134
151
 
135
152
  // // if we have been passed a collection of settings, use this to populate the cache
136
153
  if (settingsCollection && settingsCollection.models) {
137
- _.each(settingsCollection.models, updateSettingFromModel);
154
+ _.each(settingsCollection.models, this._updateSettingFromModel);
138
155
  }
139
156
 
140
- _calculatedFields = Array.isArray(calculatedFields) ? calculatedFields : [];
157
+ this.calculatedFields = Array.isArray(calculatedFields) ? calculatedFields : [];
141
158
 
142
159
  // Bind to events to automatically keep up-to-date
143
- events.on('settings.edited', updateSettingFromModel);
144
- events.on('settings.added', updateSettingFromModel);
145
- events.on('settings.deleted', updateSettingFromModel);
160
+ events.on('settings.edited', this._updateSettingFromModel);
161
+ events.on('settings.added', this._updateSettingFromModel);
162
+ events.on('settings.deleted', this._updateSettingFromModel);
146
163
 
147
164
  // set and bind calculated fields
148
- _calculatedFields.forEach((field) => {
149
- updateCalculatedField(field)();
165
+ this.calculatedFields.forEach((field) => {
166
+ this._updateCalculatedField(field)();
150
167
  field.dependents.forEach((dependent) => {
151
- events.on(`settings.${dependent}.edited`, updateCalculatedField(field));
168
+ events.on(`settings.${dependent}.edited`, this._updateCalculatedField(field));
152
169
  });
153
170
  });
154
171
 
155
- return settingsCache;
156
- },
172
+ return this.settingsCache;
173
+ }
157
174
 
158
175
  /**
159
176
  * Reset both the cache and the listeners, must be called during init
160
177
  * @param {EventEmitter} events
161
178
  */
162
179
  reset(events) {
163
- settingsCache = {};
180
+ this.settingsCache = {};
164
181
 
165
- events.removeListener('settings.edited', updateSettingFromModel);
166
- events.removeListener('settings.added', updateSettingFromModel);
167
- events.removeListener('settings.deleted', updateSettingFromModel);
182
+ events.removeListener('settings.edited', this._updateSettingFromModel);
183
+ events.removeListener('settings.added', this._updateSettingFromModel);
184
+ events.removeListener('settings.deleted', this._updateSettingFromModel);
168
185
 
169
186
  //unbind calculated fields
170
- _calculatedFields.forEach((field) => {
187
+ this.calculatedFields.forEach((field) => {
171
188
  field.dependents.forEach((dependent) => {
172
- events.removeListener(`settings.${dependent}.edited`, updateCalculatedField(field));
189
+ events.removeListener(`settings.${dependent}.edited`, this._updateCalculatedField(field));
173
190
  });
174
191
  });
175
192
 
176
- _calculatedFields = [];
193
+ this.calculatedFields = [];
177
194
  }
178
- };
195
+ }
196
+
197
+ module.exports = CacheManager;
@@ -1,9 +1,7 @@
1
- /**
2
- * Why hasn't this been moved to @tryghost/settings-cache yet?
3
- *
4
- * - It currently still couples the frontend and server together in a weird way via the event system
5
- * - See the notes in core/server/lib/common/events
6
- * - There's also a plan to introduce a proper caching layer, and rewrite this on top of that
7
- * - Finally, I'm not sure if this shouldn't be two things - a cache, and a cache manager (the update system)
8
- */
9
- module.exports = require('./cache');
1
+ const CacheManager = require('./cache');
2
+ const publicSettings = require('./public');
3
+ const cache = {};
4
+
5
+ const cacheManager = new CacheManager({cache, publicSettings});
6
+
7
+ module.exports = cacheManager;