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
@@ -7,6 +7,7 @@ const logging = require('@tryghost/logging');
7
7
  const models = require('../../models');
8
8
  const mailgunProvider = require('./mailgun');
9
9
  const sentry = require('../../../shared/sentry');
10
+ const labs = require('../../../shared/labs');
10
11
  const debug = require('@tryghost/debug')('mega');
11
12
  const postEmailSerializer = require('../mega/post-email-serializer');
12
13
 
@@ -170,6 +171,11 @@ module.exports = {
170
171
  // Load newsletter data on email
171
172
  await emailBatchModel.relations.email.getLazyRelation('newsletter', {require: false, ...knexOptions});
172
173
 
174
+ if (labs.isSet('newsletterPaywall')) {
175
+ // Load post data on email - for content gating on paywall
176
+ await emailBatchModel.relations.email.getLazyRelation('post', {require: false, ...knexOptions});
177
+ }
178
+
173
179
  // send the email
174
180
  const sendResponse = await this.send(emailBatchModel.relations.email.toJSON(), recipientRows, memberSegment);
175
181
 
@@ -0,0 +1,92 @@
1
+ /**
2
+ * @typedef {import('../../api/shared/frame')} Frame
3
+ */
4
+
5
+ const {MethodNotAllowedError} = require('@tryghost/errors');
6
+ const tpl = require('@tryghost/tpl');
7
+
8
+ const messages = {
9
+ cannotDestroyComments: 'You cannot destroy comments.'
10
+ };
11
+
12
+ module.exports = class CommentsController {
13
+ /**
14
+ * @param {import('./service')} service
15
+ * @param {import('./stats')} stats
16
+ */
17
+ constructor(service, stats) {
18
+ this.service = service;
19
+ this.stats = stats;
20
+ }
21
+
22
+ /**
23
+ * @param {Frame} frame
24
+ */
25
+ async browse(frame) {
26
+ return this.service.getComments(frame.options);
27
+ }
28
+
29
+ /**
30
+ * @param {Frame} frame
31
+ */
32
+ async read(frame) {
33
+ return await this.service.getCommentByID(frame.data.id, frame.options);
34
+ }
35
+
36
+ /**
37
+ * @param {Frame} frame
38
+ */
39
+ async edit(frame) {
40
+ if (frame.data.comments[0].status === 'deleted') {
41
+ return await this.service.deleteComment(
42
+ frame.options.id,
43
+ frame?.options?.context?.member?.id,
44
+ frame.options
45
+ );
46
+ }
47
+
48
+ return await this.service.editCommentContent(
49
+ frame.options.id,
50
+ frame?.options?.context?.member?.id,
51
+ frame.data.comments[0].html,
52
+ frame.options
53
+ );
54
+ }
55
+
56
+ /**
57
+ * @param {Frame} frame
58
+ */
59
+ async add(frame) {
60
+ const data = frame.data.comments[0];
61
+
62
+ if (data.parent_id) {
63
+ return await this.service.replyToComment(
64
+ data.parent_id,
65
+ frame.options.context.member.id,
66
+ data.html,
67
+ frame.options
68
+ );
69
+ }
70
+
71
+ return await this.service.commentOnPost(
72
+ data.post_id,
73
+ frame.options.context.member.id,
74
+ data.html,
75
+ frame.options
76
+ );
77
+ }
78
+
79
+ async destroy() {
80
+ throw new MethodNotAllowedError({
81
+ message: tpl(messages.cannotDestroyComments)
82
+ });
83
+ }
84
+
85
+ async count(frame) {
86
+ if (!frame?.data?.ids) {
87
+ return await this.stats.getAllCounts();
88
+ }
89
+
90
+ return await this.stats.getCountsByPost(frame.data.ids);
91
+ }
92
+ };
@@ -106,7 +106,7 @@
106
106
  <div class="content" style="box-sizing: border-box; display: block; Margin: 0 auto; max-width: 600px; padding: 30px 20px;">
107
107
 
108
108
  <!-- START CENTERED CONTAINER -->
109
- <span class="preheader" style="color: transparent; display: none; height: 0; max-height: 0; max-width: 0; opacity: 0; overflow: hidden; mso-hide: all; visibility: hidden; width: 0;">Someone left a comment on your post</span>
109
+ <span class="preheader" style="color: transparent; display: none; height: 0; max-height: 0; max-width: 0; opacity: 0; overflow: hidden; mso-hide: all; visibility: hidden; width: 0;">Someone just replied to your comment</span>
110
110
  <table class="main" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%; background: #ffffff; border-radius: 8px;">
111
111
 
112
112
  <!-- START MAIN CONTENT AREA -->
@@ -116,7 +116,7 @@
116
116
  <tr>
117
117
  <td style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 14px; vertical-align: top;">
118
118
  <p style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 20px; color: #15212A; font-weight: bold; line-height: 25px; margin: 0; margin-bottom: 15px;">Hey there,</p>
119
- <p style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; color: #3A464C; font-weight: normal; margin: 0; line-height: 25px; margin-bottom: 32px;">Someone just replied to your comment on <a href="{{postUrl}}" target="_blank">{{postTitle}}</a>.</p>
119
+ <p style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; color: #3A464C; font-weight: normal; margin: 0; line-height: 25px; margin-bottom: 32px;">Someone just replied to your comment on <a href="{{postUrl}}" target="_blank" style="font-weight: bold; text-decoration: underline;">{{postTitle}}</a>.</p>
120
120
 
121
121
  <table border="0" cellpadding="0" cellspacing="0" class="btn btn-primary" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%; box-sizing: border-box; background: #F9F9FA; border-radius: 7px;">
122
122
  <tbody>
@@ -154,7 +154,7 @@
154
154
  <table border="0" cellpadding="0" cellspacing="0" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: auto;">
155
155
  <tbody>
156
156
  <tr>
157
- <td style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; vertical-align: top; background-color: {{accentColor}}; border-radius: 5px; text-align: center;"> <a href="{{postUrl}}#ghost-comments-root" target="_blank" style="display: inline-block; color: #ffffff; background-color: {{accentColor}}; border: solid 1px {{accentColor}}; border-radius: 5px; box-sizing: border-box; cursor: pointer; text-decoration: none; font-size: 16px; font-weight: normal; margin: 0; padding: 9px 22px 10px; border-color: {{accentColor}};">View comments</a> </td>
157
+ <td style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; vertical-align: top; background-color: {{accentColor}}; border-radius: 5px; text-align: center;"> <a href="{{postUrl}}#ghost-comments" target="_blank" style="display: inline-block; color: #ffffff; background-color: {{accentColor}}; border: solid 1px {{accentColor}}; border-radius: 5px; box-sizing: border-box; cursor: pointer; text-decoration: none; font-size: 16px; font-weight: normal; margin: 0; padding: 9px 22px 10px; border-color: {{accentColor}};">View comments</a> </td>
158
158
  </tr>
159
159
  </tbody>
160
160
  </table>
@@ -164,7 +164,7 @@
164
164
  </table>
165
165
  <hr/>
166
166
  <p style="word-break: break-all; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 15px; color: #3A464C; font-weight: normal; margin: 0; line-height: 25px; margin-bottom: 5px;">You can also copy & paste this URL into your browser:</p>
167
- <p style="word-break: break-all; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 15px; line-height: 25px; margin-top:0; color: #3A464C;">{{postUrl}}#ghost-comments-root</p>
167
+ <p style="word-break: break-all; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 15px; line-height: 25px; margin-top:0; color: #3A464C;">{{postUrl}}#ghost-comments</p>
168
168
  </td>
169
169
  </tr>
170
170
 
@@ -4,7 +4,7 @@ module.exports = function (data) {
4
4
 
5
5
  Someone just replied to your comment on "${data.postTitle}"
6
6
 
7
- ${data.postUrl}#ghost-comments-root
7
+ ${data.postUrl}#ghost-comments
8
8
 
9
9
  ---
10
10
 
@@ -116,7 +116,7 @@
116
116
  <tr>
117
117
  <td style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 14px; vertical-align: top;">
118
118
  <p style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 20px; color: #15212A; font-weight: bold; line-height: 25px; margin: 0; margin-bottom: 15px;">Hey there,</p>
119
- <p style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; color: #3A464C; font-weight: normal; margin: 0; line-height: 25px; margin-bottom: 32px;">Someone just left a comment on your post <a href="{{postUrl}}" target="_blank">{{postTitle}}</a>.</p>
119
+ <p style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; color: #3A464C; font-weight: normal; margin: 0; line-height: 25px; margin-bottom: 32px;">Someone just left a comment on your post <a href="{{postUrl}}" target="_blank" style="font-weight: bold; text-decoration: underline;">{{postTitle}}</a>.</p>
120
120
 
121
121
  <table border="0" cellpadding="0" cellspacing="0" class="btn btn-primary" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%; box-sizing: border-box; background: #F9F9FA; border-radius: 7px;">
122
122
  <tbody>
@@ -154,7 +154,7 @@
154
154
  <table border="0" cellpadding="0" cellspacing="0" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: auto;">
155
155
  <tbody>
156
156
  <tr>
157
- <td style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; vertical-align: top; background-color: {{accentColor}}; border-radius: 5px; text-align: center;"> <a href="{{postUrl}}#ghost-comments-root" target="_blank" style="display: inline-block; color: #ffffff; background-color: {{accentColor}}; border: solid 1px {{accentColor}}; border-radius: 5px; box-sizing: border-box; cursor: pointer; text-decoration: none; font-size: 16px; font-weight: normal; margin: 0; padding: 9px 22px 10px; border-color: {{accentColor}};">View comments</a> </td>
157
+ <td style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; vertical-align: top; background-color: {{accentColor}}; border-radius: 5px; text-align: center;"> <a href="{{postUrl}}#ghost-comments" target="_blank" style="display: inline-block; color: #ffffff; background-color: {{accentColor}}; border: solid 1px {{accentColor}}; border-radius: 5px; box-sizing: border-box; cursor: pointer; text-decoration: none; font-size: 16px; font-weight: normal; margin: 0; padding: 9px 22px 10px; border-color: {{accentColor}};">View comments</a> </td>
158
158
  </tr>
159
159
  </tbody>
160
160
  </table>
@@ -164,7 +164,7 @@
164
164
  </table>
165
165
  <hr/>
166
166
  <p style="word-break: break-all; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 15px; color: #3A464C; font-weight: normal; margin: 0; line-height: 25px; margin-bottom: 5px;">You can also copy & paste this URL into your browser:</p>
167
- <p style="word-break: break-all; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 15px; line-height: 25px; margin-top:0; color: #3A464C;">{{postUrl}}#ghost-comments-root</p>
167
+ <p style="word-break: break-all; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 15px; line-height: 25px; margin-top:0; color: #3A464C;">{{postUrl}}#ghost-comments</p>
168
168
  </td>
169
169
  </tr>
170
170
 
@@ -5,7 +5,7 @@ Hey there,
5
5
 
6
6
  Someone just posted a comment on your post "${data.postTitle}"
7
7
 
8
- ${data.postUrl}#ghost-comments-root
8
+ ${data.postUrl}#ghost-comments
9
9
 
10
10
  ---
11
11
 
@@ -154,7 +154,7 @@
154
154
  <table border="0" cellpadding="0" cellspacing="0" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: auto;">
155
155
  <tbody>
156
156
  <tr>
157
- <td style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; vertical-align: top; background-color: {{accentColor}}; border-radius: 5px; text-align: center;"> <a href="{{postUrl}}#ghost-comments-root" target="_blank" style="display: inline-block; color: #ffffff; background-color: {{accentColor}}; border: solid 1px {{accentColor}}; border-radius: 5px; box-sizing: border-box; cursor: pointer; text-decoration: none; font-size: 16px; font-weight: normal; margin: 0; padding: 9px 22px 10px; border-color: {{accentColor}};">View comment</a> </td>
157
+ <td style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; vertical-align: top; background-color: {{accentColor}}; border-radius: 5px; text-align: center;"> <a href="{{postUrl}}#ghost-comments" target="_blank" style="display: inline-block; color: #ffffff; background-color: {{accentColor}}; border: solid 1px {{accentColor}}; border-radius: 5px; box-sizing: border-box; cursor: pointer; text-decoration: none; font-size: 16px; font-weight: normal; margin: 0; padding: 9px 22px 10px; border-color: {{accentColor}};">View comment</a> </td>
158
158
  </tr>
159
159
  </tbody>
160
160
  </table>
@@ -164,7 +164,7 @@
164
164
  </table>
165
165
  <hr/>
166
166
  <p style="word-break: break-all; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 15px; color: #3A464C; font-weight: normal; margin: 0; line-height: 25px; margin-bottom: 5px;">You can also copy & paste this URL into your browser:</p>
167
- <p style="word-break: break-all; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 15px; line-height: 25px; margin-top:0; color: #3A464C;">{{postUrl}}#ghost-comments-root</p>
167
+ <p style="word-break: break-all; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 15px; line-height: 25px; margin-top:0; color: #3A464C;">{{postUrl}}#ghost-comments</p>
168
168
  </td>
169
169
  </tr>
170
170
 
@@ -7,7 +7,7 @@ ${data.reporter} has reported the comment below on ${data.postTitle}. This comme
7
7
  ${data.memberName} (${data.memberEmail}):
8
8
  ${data.commentText}
9
9
 
10
- ${data.postUrl}#ghost-comments-root
10
+ ${data.postUrl}#ghost-comments
11
11
 
12
12
  ---
13
13
 
@@ -26,7 +26,7 @@ class CommentsServiceEmails {
26
26
  }
27
27
 
28
28
  const to = author.get('email');
29
- const subject = '💬 You have a new comment on one of your posts';
29
+ const subject = '💬 New comment on your post: ' + post.get('title');
30
30
 
31
31
  const memberName = member.get('name') || 'Anonymous';
32
32
 
@@ -72,7 +72,7 @@ class CommentsServiceEmails {
72
72
  }
73
73
 
74
74
  const to = parentMember.get('email');
75
- const subject = '💬 You have a new reply on one of your comments';
75
+ const subject = '↪️ New reply to your comment on ' + this.settingsCache.get('title');
76
76
 
77
77
  const post = await this.models.Post.findOne({id: reply.get('post_id')});
78
78
  const member = await this.models.Member.findOne({id: reply.get('member_id')});
@@ -129,7 +129,7 @@ class CommentsServiceEmails {
129
129
  postTitle: post.get('title'),
130
130
  postUrl: this.urlService.getUrlByResourceId(post.get('id'), {absolute: true}),
131
131
  commentHtml: comment.get('html'),
132
- commentText: htmlToPlaintext.email(comment.get('html')),
132
+ commentText: htmlToPlaintext.comment(comment.get('html')),
133
133
  commentDate: moment(comment.get('created_at')).tz(this.settingsCache.get('timezone')).format('D MMM YYYY'),
134
134
 
135
135
  reporterName: reporter.name,
@@ -1,6 +1,8 @@
1
1
  class CommentsServiceWrapper {
2
2
  init() {
3
3
  const CommentsService = require('./service');
4
+ const CommentsController = require('./controller');
5
+ const CommentsStats = require('./stats');
4
6
 
5
7
  const config = require('../../../shared/config');
6
8
  const logging = require('@tryghost/logging');
@@ -10,6 +12,8 @@ class CommentsServiceWrapper {
10
12
  const settingsCache = require('../../../shared/settings-cache');
11
13
  const urlService = require('../url');
12
14
  const urlUtils = require('../../../shared/url-utils');
15
+ const membersService = require('../members');
16
+ const db = require('../../data/db');
13
17
 
14
18
  this.api = new CommentsService({
15
19
  config,
@@ -18,8 +22,13 @@ class CommentsServiceWrapper {
18
22
  mailer,
19
23
  settingsCache,
20
24
  urlService,
21
- urlUtils
25
+ urlUtils,
26
+ contentGating: membersService.contentGating
22
27
  });
28
+
29
+ const stats = new CommentsStats({db});
30
+
31
+ this.controller = new CommentsController(this.api, stats);
23
32
  }
24
33
  }
25
34
 
@@ -8,23 +8,75 @@ const messages = {
8
8
  memberNotFound: 'Unable to find member',
9
9
  likeNotFound: 'Unable to find like',
10
10
  alreadyLiked: 'This comment was liked already',
11
- replyToReply: 'Can not reply to a reply'
11
+ replyToReply: 'Can not reply to a reply',
12
+ commentsNotEnabled: 'Comments are not enabled for this site.',
13
+ cannotCommentOnPost: 'You do not have permission to comment on this post.'
12
14
  };
13
15
 
14
16
  class CommentsService {
15
- constructor({config, logging, models, mailer, settingsCache, urlService, urlUtils}) {
16
- this.config = config;
17
- this.logging = logging;
17
+ constructor({config, logging, models, mailer, settingsCache, urlService, urlUtils, contentGating}) {
18
+ /** @private */
18
19
  this.models = models;
19
- this.mailer = mailer;
20
+
21
+ /** @private */
20
22
  this.settingsCache = settingsCache;
21
- this.urlService = urlService;
22
- this.urlUtils = urlUtils;
23
+
24
+ /** @private */
25
+ this.contentGating = contentGating;
23
26
 
24
27
  const Emails = require('./emails');
25
- this.emails = new Emails(this);
28
+ /** @private */
29
+ this.emails = new Emails({
30
+ config,
31
+ logging,
32
+ models,
33
+ mailer,
34
+ settingsCache,
35
+ urlService,
36
+ urlUtils
37
+ });
38
+ }
39
+
40
+ /**
41
+ * @returns {'off'|'all'|'paid'}
42
+ */
43
+ get enabled() {
44
+ const setting = this.settingsCache.get('comments_enabled');
45
+ if (setting === 'off' || setting === 'all' || setting === 'paid') {
46
+ return setting;
47
+ }
48
+ return 'off';
49
+ }
50
+
51
+ /** @private */
52
+ checkEnabled() {
53
+ if (this.enabled === 'off') {
54
+ throw new errors.MethodNotAllowedError({
55
+ message: tpl(messages.commentsNotEnabled)
56
+ });
57
+ }
58
+ }
59
+
60
+ /** @private */
61
+ checkCommentAccess(memberModel) {
62
+ if (this.enabled === 'paid' && memberModel.get('status') === 'free') {
63
+ throw new errors.NoPermissionError({
64
+ message: tpl(messages.cannotCommentOnPost)
65
+ });
66
+ }
67
+ }
68
+
69
+ /** @private */
70
+ checkPostAccess(postModel, memberModel) {
71
+ const access = this.contentGating.checkPostAccess(postModel.toJSON(), memberModel.toJSON());
72
+ if (access === this.contentGating.BLOCK_ACCESS) {
73
+ throw new errors.NoPermissionError({
74
+ message: tpl(messages.cannotCommentOnPost)
75
+ });
76
+ }
26
77
  }
27
78
 
79
+ /** @private */
28
80
  async sendNewCommentNotifications(comment) {
29
81
  await this.emails.notifyPostAuthors(comment);
30
82
 
@@ -34,6 +86,7 @@ class CommentsService {
34
86
  }
35
87
 
36
88
  async reportComment(commentId, reporter) {
89
+ this.checkEnabled();
37
90
  const comment = await this.models.Comment.findOne({id: commentId}, {require: true});
38
91
 
39
92
  // Check if this reporter already reported this comment (then don't send an email)?
@@ -56,11 +109,22 @@ class CommentsService {
56
109
  await this.emails.notifiyReport(comment, reporter);
57
110
  }
58
111
 
112
+ /**
113
+ * @param {any} options
114
+ */
115
+ async getComments(options) {
116
+ this.checkEnabled();
117
+ const page = await this.models.Comment.findPage(options);
118
+
119
+ return page;
120
+ }
121
+
59
122
  /**
60
123
  * @param {string} id - The ID of the Comment to get
61
124
  * @param {any} options
62
125
  */
63
126
  async getCommentByID(id, options) {
127
+ this.checkEnabled();
64
128
  const model = await this.models.Comment.findOne({id}, options);
65
129
 
66
130
  if (!model) {
@@ -79,13 +143,25 @@ class CommentsService {
79
143
  * @param {any} options
80
144
  */
81
145
  async commentOnPost(post, member, comment, options) {
82
- await this.models.Member.findOne({
146
+ this.checkEnabled();
147
+ const memberModel = await this.models.Member.findOne({
83
148
  id: member
84
149
  }, {
85
150
  require: true,
86
151
  ...options
87
152
  });
88
153
 
154
+ this.checkCommentAccess(memberModel);
155
+
156
+ const postModel = await this.models.Post.findOne({
157
+ id: post
158
+ }, {
159
+ require: true,
160
+ ...options
161
+ });
162
+
163
+ this.checkPostAccess(postModel, memberModel);
164
+
89
165
  const model = await this.models.Comment.add({
90
166
  post_id: post,
91
167
  member_id: member,
@@ -114,13 +190,16 @@ class CommentsService {
114
190
  * @param {any} options
115
191
  */
116
192
  async replyToComment(parent, member, comment, options) {
117
- await this.models.Member.findOne({
193
+ this.checkEnabled();
194
+ const memberModel = await this.models.Member.findOne({
118
195
  id: member
119
196
  }, {
120
197
  require: true,
121
198
  ...options
122
199
  });
123
200
 
201
+ this.checkCommentAccess(memberModel);
202
+
124
203
  const parentComment = await this.getCommentByID(parent, options);
125
204
  if (!parentComment) {
126
205
  throw new errors.BadRequestError({
@@ -133,6 +212,14 @@ class CommentsService {
133
212
  message: tpl(messages.replyToReply)
134
213
  });
135
214
  }
215
+ const postModel = await this.models.Post.findOne({
216
+ id: parentComment.get('post_id')
217
+ }, {
218
+ require: true,
219
+ ...options
220
+ });
221
+
222
+ this.checkPostAccess(postModel, memberModel);
136
223
 
137
224
  const model = await this.models.Comment.add({
138
225
  post_id: parentComment.get('post_id'),
@@ -161,6 +248,7 @@ class CommentsService {
161
248
  * @param {any} options
162
249
  */
163
250
  async deleteComment(id, member, options) {
251
+ this.checkEnabled();
164
252
  const existingComment = await this.getCommentByID(id, options);
165
253
 
166
254
  if (existingComment.get('member_id') !== member) {
@@ -188,6 +276,7 @@ class CommentsService {
188
276
  * @param {any} options
189
277
  */
190
278
  async editCommentContent(id, member, comment, options) {
279
+ this.checkEnabled();
191
280
  const existingComment = await this.getCommentByID(id, options);
192
281
 
193
282
  if (!comment) {
@@ -202,7 +291,8 @@ class CommentsService {
202
291
  }
203
292
 
204
293
  const model = await this.models.Comment.edit({
205
- html: comment
294
+ html: comment,
295
+ edited_at: new Date()
206
296
  }, {
207
297
  id,
208
298
  require: true,
@@ -0,0 +1,44 @@
1
+ module.exports = class CommentsStatsService {
2
+ constructor(deps) {
3
+ this.db = deps.db;
4
+ }
5
+
6
+ /**
7
+ * @param {string[]} ids - List of post ids to fetch counts for
8
+ * @returns {Promise<Object<string, number>>}
9
+ */
10
+ async getCountsByPost(ids) {
11
+ const results = await this.db.knex('comments')
12
+ .select(this.db.knex.raw(`COUNT(*) AS count, post_id`))
13
+ .groupBy('post_id')
14
+ .whereIn('post_id', ids);
15
+
16
+ const counts = ids.reduce((memo, id) => {
17
+ const result = results.find(x => x.post_id === id);
18
+ return {
19
+ ...memo,
20
+ [id]: result?.count || 0
21
+ };
22
+ }, {});
23
+
24
+ return counts;
25
+ }
26
+
27
+ /**
28
+ * @returns {Promise<Object<string, number>>}
29
+ */
30
+ async getAllCounts() {
31
+ const results = await this.db.knex('comments')
32
+ .select(this.db.knex.raw(`COUNT(*) AS count, post_id`))
33
+ .groupBy('post_id');
34
+
35
+ /** @type Object<string, number> */
36
+ let counts = {};
37
+
38
+ for (const row of results) {
39
+ counts[row.post_id] = row.count;
40
+ }
41
+
42
+ return counts;
43
+ }
44
+ };
@@ -36,7 +36,11 @@ class EmailPreview {
36
36
  );
37
37
  });
38
38
 
39
- return emailContent;
39
+ return {
40
+ subject: emailContent.subject,
41
+ html: emailContent.html,
42
+ plaintext: emailContent.plaintext
43
+ };
40
44
  }
41
45
  }
42
46
 
@@ -69,6 +69,7 @@ const getEmailData = async (postModel, options) => {
69
69
  }
70
70
 
71
71
  return {
72
+ post: postModel.toJSON(), // for content paywalling
72
73
  subject,
73
74
  html,
74
75
  plaintext,
@@ -87,9 +88,6 @@ const sendTestEmail = async (postModel, toEmails, memberSegment) => {
87
88
  let emailData = await getEmailData(postModel);
88
89
  emailData.subject = `[Test] ${emailData.subject}`;
89
90
 
90
- if (memberSegment) {
91
- emailData = postEmailSerializer.renderEmailForSegment(emailData, memberSegment);
92
- }
93
91
  // fetch any matching members so that replacements use expected values
94
92
  const recipients = await Promise.all(toEmails.map(async (email) => {
95
93
  const member = await membersService.api.members.get({email});
@@ -109,7 +107,7 @@ const sendTestEmail = async (postModel, toEmails, memberSegment) => {
109
107
  // enable tracking for previews to match real-world behaviour
110
108
  emailData.track_opens = !!settingsCache.get('email_track_opens');
111
109
 
112
- const response = await bulkEmailService.send(emailData, recipients);
110
+ const response = await bulkEmailService.send(emailData, recipients, memberSegment);
113
111
 
114
112
  if (response instanceof bulkEmailService.FailedBatch) {
115
113
  return Promise.reject(response.error);