ghost 5.2.2 → 5.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (259) hide show
  1. package/content/themes/casper/assets/built/screen.css +1 -1
  2. package/content/themes/casper/assets/built/screen.css.map +1 -1
  3. package/content/themes/casper/assets/css/screen.css +31 -1
  4. package/content/themes/casper/default.hbs +1 -0
  5. package/content/themes/casper/package.json +1 -1
  6. package/content/themes/casper/partials/icons/search.hbs +1 -0
  7. package/core/boot.js +3 -1
  8. package/core/bridge.js +7 -0
  9. package/core/built/assets/codemirror/{codemirror-d25c379b87ec8b33d54ac7149bc0b6ae.js → codemirror-30201ab2cff61db847193fc9f5ed922d.js} +1 -1
  10. package/core/built/assets/ghost-dark-9e5d1f0dfae41232e5e34e4d0df53ae0.css +1 -0
  11. package/core/built/assets/ghost.min-e7cfbd1800f8e99b9158f74f1e39cd76.css +1 -0
  12. package/core/built/assets/{ghost.min-971a0ff706bbf9e24f0b0a5770c8fc41.js → ghost.min-f4bba3a2a5ef256b82641345505d4f0f.js} +69 -66
  13. package/core/built/assets/icons/activity-placeholder.svg +3 -0
  14. package/core/built/assets/simplemde/{simplemde-3ffc0ec9e9fecf29b9a499db678c9e65.js → simplemde-fb4527da6e489b34dc24b28ea870b286.js} +1 -1
  15. package/core/built/assets/{vendor.min-ea369e6487643585f35409d474b06789.js → vendor.min-4076498ccd6c8412365f43b156084ed8.js} +119 -117
  16. package/core/built/assets/{vendor.min-ba66b98f7c24fa40e061c7ffc94f4e23.css → vendor.min-4a6661c574707ceca220aa2e76558995.css} +2 -1
  17. package/core/frontend/helpers/comment_count.js +25 -0
  18. package/core/frontend/helpers/comments.js +67 -0
  19. package/core/frontend/helpers/date.js +3 -1
  20. package/core/frontend/helpers/ghost_head.js +13 -0
  21. package/core/frontend/services/admin-auth-assets/index.js +4 -0
  22. package/core/frontend/services/admin-auth-assets/service.js +93 -0
  23. package/core/frontend/services/comment-counts-assets/index.js +4 -0
  24. package/core/frontend/services/comment-counts-assets/service.js +59 -0
  25. package/core/frontend/services/theme-engine/middleware/update-global-template-options.js +5 -1
  26. package/core/frontend/src/admin-auth/index.html +5 -0
  27. package/core/frontend/src/admin-auth/message-handler.js +75 -0
  28. package/core/frontend/src/comment-counts/js/comment-counts.js +71 -0
  29. package/core/frontend/web/site.js +3 -0
  30. package/core/server/api/{canary → endpoints}/actions.js +0 -0
  31. package/core/server/api/{canary → endpoints}/authentication.js +0 -0
  32. package/core/server/api/{canary → endpoints}/authors-public.js +0 -0
  33. package/core/server/api/endpoints/comments-comments.js +247 -0
  34. package/core/server/api/endpoints/comments.js +25 -0
  35. package/core/server/api/{canary → endpoints}/config.js +0 -0
  36. package/core/server/api/{canary → endpoints}/custom-theme-settings.js +0 -0
  37. package/core/server/api/{canary → endpoints}/db.js +0 -0
  38. package/core/server/api/{canary → endpoints}/email-post.js +0 -0
  39. package/core/server/api/{canary → endpoints}/email-previews.js +0 -0
  40. package/core/server/api/{canary → endpoints}/emails.js +0 -0
  41. package/core/server/api/endpoints/explore.js +12 -0
  42. package/core/server/api/{canary → endpoints}/files.js +0 -0
  43. package/core/server/api/{canary → endpoints}/identities.js +0 -0
  44. package/core/server/api/{canary → endpoints}/images.js +0 -0
  45. package/core/server/api/{canary → endpoints}/index.js +16 -0
  46. package/core/server/api/{canary → endpoints}/integrations.js +0 -0
  47. package/core/server/api/{canary → endpoints}/invites.js +0 -0
  48. package/core/server/api/{canary → endpoints}/labels.js +0 -0
  49. package/core/server/api/{canary → endpoints}/mail.js +0 -0
  50. package/core/server/api/{canary → endpoints}/media.js +0 -0
  51. package/core/server/api/{canary → endpoints}/member-signin-urls.js +0 -0
  52. package/core/server/api/{canary → endpoints}/members-stripe-connect.js +0 -0
  53. package/core/server/api/{canary → endpoints}/members.js +0 -0
  54. package/core/server/api/{canary → endpoints}/newsletters-public.js +0 -0
  55. package/core/server/api/{canary → endpoints}/newsletters.js +0 -0
  56. package/core/server/api/{canary → endpoints}/notifications.js +0 -0
  57. package/core/server/api/{canary → endpoints}/oembed.js +0 -0
  58. package/core/server/api/{canary → endpoints}/offers-public.js +0 -0
  59. package/core/server/api/{canary → endpoints}/offers.js +0 -0
  60. package/core/server/api/{canary → endpoints}/pages-public.js +0 -0
  61. package/core/server/api/{canary → endpoints}/pages.js +0 -0
  62. package/core/server/api/{canary → endpoints}/posts-public.js +0 -0
  63. package/core/server/api/{canary → endpoints}/posts.js +0 -0
  64. package/core/server/api/{canary → endpoints}/previews.js +0 -0
  65. package/core/server/api/{canary → endpoints}/redirects.js +0 -0
  66. package/core/server/api/{canary → endpoints}/roles.js +0 -0
  67. package/core/server/api/{canary → endpoints}/schedules.js +0 -0
  68. package/core/server/api/{canary → endpoints}/session.js +0 -0
  69. package/core/server/api/{canary → endpoints}/settings-public.js +0 -0
  70. package/core/server/api/{canary → endpoints}/settings.js +0 -0
  71. package/core/server/api/{canary → endpoints}/site.js +0 -0
  72. package/core/server/api/{canary → endpoints}/slack.js +0 -0
  73. package/core/server/api/{canary → endpoints}/slugs.js +0 -0
  74. package/core/server/api/{canary → endpoints}/snippets.js +0 -0
  75. package/core/server/api/{canary → endpoints}/stats.js +0 -0
  76. package/core/server/api/{canary → endpoints}/tags-public.js +0 -0
  77. package/core/server/api/{canary → endpoints}/tags.js +0 -0
  78. package/core/server/api/{canary → endpoints}/themes.js +0 -0
  79. package/core/server/api/{canary → endpoints}/tiers-public.js +0 -0
  80. package/core/server/api/{canary → endpoints}/tiers.js +0 -0
  81. package/core/server/api/{canary → endpoints}/users.js +0 -0
  82. package/core/server/api/{canary → endpoints}/utils/index.js +0 -0
  83. package/core/server/api/{canary → endpoints}/utils/permissions.js +3 -3
  84. package/core/server/api/{canary → endpoints}/utils/serializers/index.js +0 -0
  85. package/core/server/api/{canary → endpoints}/utils/serializers/input/authors.js +1 -1
  86. package/core/server/api/{canary → endpoints}/utils/serializers/input/db.js +1 -1
  87. package/core/server/api/{canary → endpoints}/utils/serializers/input/index.js +0 -0
  88. package/core/server/api/{canary → endpoints}/utils/serializers/input/integrations.js +1 -1
  89. package/core/server/api/{canary → endpoints}/utils/serializers/input/media.js +0 -0
  90. package/core/server/api/{canary → endpoints}/utils/serializers/input/members.js +1 -1
  91. package/core/server/api/{canary → endpoints}/utils/serializers/input/pages.js +1 -1
  92. package/core/server/api/{canary → endpoints}/utils/serializers/input/posts.js +1 -1
  93. package/core/server/api/{canary → endpoints}/utils/serializers/input/settings.js +2 -1
  94. package/core/server/api/{canary → endpoints}/utils/serializers/input/tags.js +1 -1
  95. package/core/server/api/{canary → endpoints}/utils/serializers/input/tiers.js +0 -0
  96. package/core/server/api/{canary → endpoints}/utils/serializers/input/users.js +1 -1
  97. package/core/server/api/{canary → endpoints}/utils/serializers/input/utils/slug-filter-order.js +0 -0
  98. package/core/server/api/{canary → endpoints}/utils/serializers/input/utils/url.js +0 -0
  99. package/core/server/api/{canary → endpoints}/utils/serializers/input/webhooks.js +1 -1
  100. package/core/server/api/{canary → endpoints}/utils/serializers/output/all.js +1 -1
  101. package/core/server/api/{canary → endpoints}/utils/serializers/output/authentication.js +1 -1
  102. package/core/server/api/endpoints/utils/serializers/output/comments.js +5 -0
  103. package/core/server/api/{canary → endpoints}/utils/serializers/output/config.js +1 -1
  104. package/core/server/api/{canary → endpoints}/utils/serializers/output/custom-theme-settings.js +0 -0
  105. package/core/server/api/{canary → endpoints}/utils/serializers/output/db.js +1 -1
  106. package/core/server/api/{canary → endpoints}/utils/serializers/output/default.js +1 -1
  107. package/core/server/api/{canary → endpoints}/utils/serializers/output/email-posts.js +0 -0
  108. package/core/server/api/endpoints/utils/serializers/output/explore.js +11 -0
  109. package/core/server/api/{canary → endpoints}/utils/serializers/output/files.js +0 -0
  110. package/core/server/api/{canary → endpoints}/utils/serializers/output/images.js +1 -1
  111. package/core/server/api/{canary → endpoints}/utils/serializers/output/index.js +8 -0
  112. package/core/server/api/{canary → endpoints}/utils/serializers/output/mail.js +1 -1
  113. package/core/server/api/{canary → endpoints}/utils/serializers/output/mappers/actions.js +0 -0
  114. package/core/server/api/{canary → endpoints}/utils/serializers/output/mappers/authors.js +0 -0
  115. package/core/server/api/endpoints/utils/serializers/output/mappers/comments.js +50 -0
  116. package/core/server/api/{canary → endpoints}/utils/serializers/output/mappers/emails.js +0 -0
  117. package/core/server/api/{canary → endpoints}/utils/serializers/output/mappers/images.js +0 -0
  118. package/core/server/api/{canary → endpoints}/utils/serializers/output/mappers/index.js +1 -0
  119. package/core/server/api/{canary → endpoints}/utils/serializers/output/mappers/integrations.js +0 -0
  120. package/core/server/api/{canary → endpoints}/utils/serializers/output/mappers/newsletters.js +0 -0
  121. package/core/server/api/{canary → endpoints}/utils/serializers/output/mappers/pages.js +0 -0
  122. package/core/server/api/{canary → endpoints}/utils/serializers/output/mappers/posts.js +0 -0
  123. package/core/server/api/{canary → endpoints}/utils/serializers/output/mappers/settings.js +0 -0
  124. package/core/server/api/{canary → endpoints}/utils/serializers/output/mappers/snippets.js +0 -0
  125. package/core/server/api/{canary → endpoints}/utils/serializers/output/mappers/tags.js +0 -0
  126. package/core/server/api/{canary → endpoints}/utils/serializers/output/mappers/users.js +0 -0
  127. package/core/server/api/{canary → endpoints}/utils/serializers/output/media.js +0 -0
  128. package/core/server/api/{canary → endpoints}/utils/serializers/output/members-stripe-connect.js +0 -0
  129. package/core/server/api/{canary → endpoints}/utils/serializers/output/members.js +1 -1
  130. package/core/server/api/{canary → endpoints}/utils/serializers/output/notifications.js +1 -1
  131. package/core/server/api/{canary → endpoints}/utils/serializers/output/oembed.js +1 -1
  132. package/core/server/api/{canary → endpoints}/utils/serializers/output/offers.js +1 -1
  133. package/core/server/api/{canary → endpoints}/utils/serializers/output/pages.js +1 -1
  134. package/core/server/api/{canary → endpoints}/utils/serializers/output/posts.js +1 -1
  135. package/core/server/api/{canary → endpoints}/utils/serializers/output/previews.js +0 -0
  136. package/core/server/api/{canary → endpoints}/utils/serializers/output/redirects.js +0 -0
  137. package/core/server/api/{canary → endpoints}/utils/serializers/output/roles.js +1 -1
  138. package/core/server/api/{canary → endpoints}/utils/serializers/output/schedules.js +0 -0
  139. package/core/server/api/{canary → endpoints}/utils/serializers/output/session.js +1 -1
  140. package/core/server/api/{canary → endpoints}/utils/serializers/output/settings.js +0 -0
  141. package/core/server/api/{canary → endpoints}/utils/serializers/output/site.js +1 -1
  142. package/core/server/api/{canary → endpoints}/utils/serializers/output/slack.js +1 -1
  143. package/core/server/api/{canary → endpoints}/utils/serializers/output/slugs.js +1 -1
  144. package/core/server/api/{canary → endpoints}/utils/serializers/output/themes.js +1 -1
  145. package/core/server/api/{canary → endpoints}/utils/serializers/output/tiers.js +1 -1
  146. package/core/server/api/{canary → endpoints}/utils/serializers/output/users.js +1 -1
  147. package/core/server/api/{canary → endpoints}/utils/serializers/output/utils/clean.js +2 -1
  148. package/core/server/api/{canary → endpoints}/utils/serializers/output/utils/date.js +0 -0
  149. package/core/server/api/endpoints/utils/serializers/output/utils/extra-attrs.js +67 -0
  150. package/core/server/api/{canary → endpoints}/utils/serializers/output/utils/post-gating.js +0 -0
  151. package/core/server/api/{canary → endpoints}/utils/serializers/output/utils/url.js +1 -1
  152. package/core/server/api/{canary → endpoints}/utils/validators/index.js +0 -0
  153. package/core/server/api/{canary → endpoints}/utils/validators/input/files.js +0 -0
  154. package/core/server/api/{canary → endpoints}/utils/validators/input/images.js +0 -0
  155. package/core/server/api/{canary → endpoints}/utils/validators/input/index.js +0 -0
  156. package/core/server/api/{canary → endpoints}/utils/validators/input/invitations.js +1 -1
  157. package/core/server/api/{canary → endpoints}/utils/validators/input/invites.js +0 -0
  158. package/core/server/api/{canary → endpoints}/utils/validators/input/labels.js +0 -0
  159. package/core/server/api/{canary → endpoints}/utils/validators/input/media.js +0 -0
  160. package/core/server/api/{canary → endpoints}/utils/validators/input/members.js +0 -0
  161. package/core/server/api/{canary → endpoints}/utils/validators/input/oembed.js +0 -0
  162. package/core/server/api/{canary → endpoints}/utils/validators/input/pages.js +0 -0
  163. package/core/server/api/{canary → endpoints}/utils/validators/input/password_reset.js +1 -1
  164. package/core/server/api/{canary → endpoints}/utils/validators/input/posts.js +0 -0
  165. package/core/server/api/{canary → endpoints}/utils/validators/input/settings.js +0 -0
  166. package/core/server/api/{canary → endpoints}/utils/validators/input/setup.js +1 -1
  167. package/core/server/api/{canary → endpoints}/utils/validators/input/snippets.js +0 -0
  168. package/core/server/api/{canary → endpoints}/utils/validators/input/tags.js +0 -0
  169. package/core/server/api/{canary → endpoints}/utils/validators/input/tiers.js +0 -0
  170. package/core/server/api/{canary → endpoints}/utils/validators/input/users.js +1 -1
  171. package/core/server/api/{canary → endpoints}/utils/validators/input/webhooks.js +0 -0
  172. package/core/server/api/{canary → endpoints}/utils/validators/output/index.js +0 -0
  173. package/core/server/api/{canary → endpoints}/utils/validators/utils/json-schema.js +0 -0
  174. package/core/server/api/{canary → endpoints}/webhooks.js +0 -0
  175. package/core/server/api/index.js +1 -1
  176. package/core/server/data/exporter/table-lists.js +4 -2
  177. package/core/server/data/migrations/versions/5.3/2022-07-04-13-49-add-comments-table.js +13 -0
  178. package/core/server/data/migrations/versions/5.3/2022-07-05-09-36-add-comments-likes-table.js +9 -0
  179. package/core/server/data/migrations/versions/5.3/2022-07-05-09-47-add-comments-reports-table.js +10 -0
  180. package/core/server/data/migrations/versions/5.3/2022-07-05-10-00-add-comment-related-fields-to-members.js +21 -0
  181. package/core/server/data/migrations/versions/5.3/2022-07-05-12-55-add-comments-crud-permissions.js +68 -0
  182. package/core/server/data/migrations/versions/5.3/2022-07-05-15-35-add-comment-notifications-field-to-users-table.js +7 -0
  183. package/core/server/data/migrations/versions/5.3/2022-07-06-07-26-add-comments-enabled-setting.js +8 -0
  184. package/core/server/data/migrations/versions/5.3/2022-07-06-07-58-add-ghost-explore-integration-role.js +31 -0
  185. package/core/server/data/migrations/versions/5.3/2022-07-06-09-13-add-ghost-explore-integration-role-permissions.js +11 -0
  186. package/core/server/data/migrations/versions/5.3/2022-07-06-09-17-add-ghost-explore-integration.js +38 -0
  187. package/core/server/data/migrations/versions/5.3/2022-07-06-09-26-add-ghost-explore-integration-api-key.js +73 -0
  188. package/core/server/data/schema/default-settings/default-settings.json +14 -0
  189. package/core/server/data/schema/fixtures/fixtures.json +65 -2
  190. package/core/server/data/schema/schema.js +31 -1
  191. package/core/server/models/base/plugins/crud.js +15 -0
  192. package/core/server/models/comment-like.js +34 -0
  193. package/core/server/models/comment.js +163 -0
  194. package/core/server/models/member.js +2 -1
  195. package/core/server/models/user.js +2 -1
  196. package/core/server/services/auth/session/express-session.js +1 -1
  197. package/core/server/services/comments/email-templates/new-comment-reply.hbs +199 -0
  198. package/core/server/services/comments/email-templates/new-comment-reply.txt.js +14 -0
  199. package/core/server/services/comments/email-templates/new-comment.hbs +199 -0
  200. package/core/server/services/comments/email-templates/new-comment.txt.js +14 -0
  201. package/core/server/services/comments/emails.js +164 -0
  202. package/core/server/services/comments/index.js +26 -0
  203. package/core/server/services/comments/service.js +24 -0
  204. package/core/server/services/explore/index.js +18 -0
  205. package/core/server/services/explore/service.js +55 -0
  206. package/core/server/services/members/middleware.js +4 -4
  207. package/core/server/services/members/utils.js +2 -1
  208. package/core/server/services/permissions/can-this.js +18 -5
  209. package/core/server/services/permissions/parse-context.js +5 -0
  210. package/core/server/services/permissions/providers.js +17 -1
  211. package/core/server/services/posts/posts-service.js +14 -0
  212. package/core/server/services/users.js +84 -1
  213. package/core/server/web/admin/app.js +4 -0
  214. package/core/server/web/admin/views/default-prod.html +5 -5
  215. package/core/server/web/admin/views/default.html +5 -5
  216. package/core/server/web/api/app.js +2 -2
  217. package/core/server/web/api/{canary → endpoints}/admin/app.js +4 -4
  218. package/core/server/web/api/{canary → endpoints}/admin/middleware.js +1 -0
  219. package/core/server/web/api/{canary → endpoints}/admin/routes.js +6 -1
  220. package/core/server/web/api/{canary → endpoints}/content/app.js +4 -4
  221. package/core/server/web/api/{canary → endpoints}/content/middleware.js +0 -0
  222. package/core/server/web/api/{canary → endpoints}/content/routes.js +1 -1
  223. package/core/server/web/api/testmode/routes.js +1 -1
  224. package/core/server/web/comments/index.js +1 -0
  225. package/core/server/web/comments/routes.js +28 -0
  226. package/core/server/web/members/app.js +5 -0
  227. package/core/server/web/parent/frontend.js +1 -0
  228. package/core/shared/config/defaults.json +16 -6
  229. package/core/shared/config/env/config.testing.json +4 -0
  230. package/core/shared/config/overrides.json +1 -0
  231. package/core/shared/labs.js +2 -1
  232. package/core/shared/settings-cache/public.js +2 -1
  233. package/package.json +20 -20
  234. package/yarn.lock +425 -275
  235. package/Gruntfile.js +0 -384
  236. package/core/built/assets/ghost-dark-923c90399aa560625a983a6ae9abb38c.css +0 -1
  237. package/core/built/assets/ghost.min-c74f50609022cebf13ad28810def68b6.css +0 -1
  238. package/core/built/assets/img/contributors/AileenCGN-bf8b9ffbb34c0fd93beb8136af07771b.jpeg +0 -0
  239. package/core/built/assets/img/contributors/ErisDS-c958ccb9e3597320dee745a42f478569.jpeg +0 -0
  240. package/core/built/assets/img/contributors/GeorginaLusby-6cea5defddee3c4ea7320e580521e832.jpeg +0 -0
  241. package/core/built/assets/img/contributors/JohnONolan-47041b80c35c6341b9b929b03139aecc.jpeg +0 -0
  242. package/core/built/assets/img/contributors/acburdine-d9777fe2601dc215afb6723315829c89.jpeg +0 -0
  243. package/core/built/assets/img/contributors/bnookala-5896fcdd2f477495323e420efe890657.jpeg +0 -0
  244. package/core/built/assets/img/contributors/cobbspur-07ded67009757d12517621fc856eba62.jpeg +0 -0
  245. package/core/built/assets/img/contributors/dbalders-452347a406c2ca23657daea9100878f3.jpeg +0 -0
  246. package/core/built/assets/img/contributors/disordinary-b9997e5debb59b7aadc79ba90955b662.jpeg +0 -0
  247. package/core/built/assets/img/contributors/felixrieseberg-ecf29e8eadc58fab999c507049f898cf.jpeg +0 -0
  248. package/core/built/assets/img/contributors/frantzypants-637b03f85dff89700a661fde79daea5c.jpeg +0 -0
  249. package/core/built/assets/img/contributors/halfdan-00d6783e5fba2900ee1380939297d8ee.jpeg +0 -0
  250. package/core/built/assets/img/contributors/jaswilli-8cc9a8d2539ca03239d113dfb25ff5c2.jpeg +0 -0
  251. package/core/built/assets/img/contributors/kevinansfield-925606c55bc2f3f2f05c0fa58b953ad1.jpeg +0 -0
  252. package/core/built/assets/img/contributors/kevinkucharczyk-3c7dfe2a103a83737b9d5ee8e19d67f8.jpeg +0 -0
  253. package/core/built/assets/img/contributors/kirrg001-79823418f2ca21e81719653f0286f95b.jpeg +0 -0
  254. package/core/built/assets/img/contributors/mixonic-1ff87736dd02cfa080ae109b45131aa6.png +0 -0
  255. package/core/built/assets/img/contributors/rwjblue-5c7cc009cda45baca2d45f0d1ed19e48.jpeg +0 -0
  256. package/core/built/assets/img/contributors/sebgie-0fb02df00ee7834dbcc8beba84aec81e.png +0 -0
  257. package/core/built/assets/img/contributors/tgriesser-d871cbf74a871c0fb6d855e76a893f7e.png +0 -0
  258. package/core/server/api/canary/utils/serializers/output/utils/extra-attrs.js +0 -33
  259. package/urls.json +0 -597
@@ -1271,7 +1271,8 @@ ol .occluded-content {
1271
1271
  }
1272
1272
 
1273
1273
  .epm-animating .epm-modal-container {
1274
- overflow: unset;
1274
+ overflow: visible;
1275
+ overflow: initial;
1275
1276
  }
1276
1277
 
1277
1278
  .epm-modal {
@@ -0,0 +1,25 @@
1
+ const {SafeString} = require('../services/handlebars');
2
+ const {labs} = require('../services/proxy');
3
+
4
+ function commentCount(options) {
5
+ return new SafeString(`
6
+ <span data-ghost-comment-count="${this.id}" style="display:none">
7
+ ${options.fn(this)}
8
+ </span>`
9
+ );
10
+ }
11
+
12
+ module.exports = async function commentsLabsWrapper() {
13
+ const self = this;
14
+ const args = arguments;
15
+
16
+ return labs.enabledHelper({
17
+ flagKey: 'comments',
18
+ flagName: 'Comments',
19
+ helperName: 'comments'
20
+ }, () => {
21
+ return commentCount.apply(self, args);
22
+ });
23
+ };
24
+
25
+ module.exports.async = true;
@@ -0,0 +1,67 @@
1
+ const {SafeString} = require('../services/handlebars');
2
+ const {config, urlUtils, getFrontendKey, labs} = require('../services/proxy');
3
+
4
+ async function comments(options) {
5
+ // todo: For now check on the comment id to exclude normal pages (we probably have a better way to do this)
6
+
7
+ const commentId = this.comment_id;
8
+
9
+ if (!commentId) {
10
+ return;
11
+ }
12
+
13
+ let colorScheme = 'auto';
14
+ if (options.hash.color_scheme === 'dark' || options.hash.color_scheme === 'light') {
15
+ colorScheme = options.hash.color_scheme;
16
+ }
17
+
18
+ let avatarSaturation = parseInt(options.hash.avatar_saturation);
19
+ if (isNaN(avatarSaturation)) {
20
+ avatarSaturation = 50;
21
+ }
22
+
23
+ let accentColor = '';
24
+ if (options.data.site.accent_color) {
25
+ accentColor = options.data.site.accent_color;
26
+ }
27
+
28
+ const frontendKey = await getFrontendKey();
29
+
30
+ const data = {
31
+ 'ghost-comments': urlUtils.getSiteUrl(),
32
+ api: urlUtils.urlFor('api', {type: 'content'}, true),
33
+ admin: urlUtils.urlFor('admin', true),
34
+ key: frontendKey,
35
+ 'post-id': this.id,
36
+ 'sentry-dsn': '', /* todo: insert sentry dsn key here */
37
+ 'color-scheme': colorScheme,
38
+ 'avatar-saturation': avatarSaturation,
39
+ 'accent-color': accentColor,
40
+ 'app-version': config.get('comments:version')
41
+ };
42
+
43
+ let dataAttributes = '';
44
+
45
+ Object.entries(data).forEach(([key, value]) => {
46
+ dataAttributes += `data-${key}="${value}" `;
47
+ });
48
+
49
+ return new SafeString(`
50
+ <script defer src="${config.get('comments:url')}" ${dataAttributes} crossorigin="anonymous"></script>
51
+ `);
52
+ }
53
+
54
+ module.exports = async function commentsLabsWrapper() {
55
+ const self = this;
56
+ const args = arguments;
57
+
58
+ return labs.enabledHelper({
59
+ flagKey: 'comments',
60
+ flagName: 'Comments',
61
+ helperName: 'comments'
62
+ }, () => {
63
+ return comments.apply(self, args);
64
+ });
65
+ };
66
+
67
+ module.exports.async = true;
@@ -45,7 +45,9 @@ module.exports = function (...attrs) {
45
45
  // i18n: Making dates, including month names, translatable to any language.
46
46
  // Documentation: http://momentjs.com/docs/#/i18n/
47
47
  // Locales: https://github.com/moment/moment/tree/develop/locale
48
- dateMoment.locale(locale);
48
+ if (locale && locale.match('^[^/\\\\]*$') !== null) {
49
+ dateMoment.locale(locale);
50
+ }
49
51
 
50
52
  if (timeago) {
51
53
  date = dateMoment.tz(timezone).from(timeNow);
@@ -57,6 +57,14 @@ function getMembersHelper(data, frontendKey) {
57
57
  return membersHelper;
58
58
  }
59
59
 
60
+ function getSearchHelper(frontendKey) {
61
+ const adminUrl = urlUtils.getAdminUrl() || urlUtils.getSiteUrl();
62
+
63
+ let helper = `<script defer src="${config.get('sodoSearch:url')}" data-sodo-search="${adminUrl}" data-version="${config.get('sodoSearch:version')}" data-key="${frontendKey}" crossorigin="anonymous"></script>`;
64
+
65
+ return helper;
66
+ }
67
+
60
68
  /**
61
69
  * **NOTE**
62
70
  * Express adds `_locals`, see https://github.com/expressjs/express/blob/4.15.4/lib/response.js#L962.
@@ -193,6 +201,7 @@ module.exports = async function ghost_head(options) { // eslint-disable-line cam
193
201
  // no code injection for amp context!!!
194
202
  if (!_.includes(context, 'amp')) {
195
203
  head.push(getMembersHelper(options.data, frontendKey));
204
+ head.push(getSearchHelper(frontendKey));
196
205
 
197
206
  // @TODO do this in a more "frameworky" way
198
207
  if (cardAssetService.hasFile('js')) {
@@ -202,6 +211,10 @@ module.exports = async function ghost_head(options) { // eslint-disable-line cam
202
211
  head.push(`<link rel="stylesheet" type="text/css" href="${getAssetUrl('public/cards.min.css')}">`);
203
212
  }
204
213
 
214
+ if (labs.isSet('comments') && settingsCache.get('enable_comments') !== 'off') {
215
+ head.push(`<script defer src="${getAssetUrl('public/comment-counts.min.js')}" data-ghost-comments-counts-api="${urlUtils.getSiteUrl(true)}members/api/comments/counts/"></script>`);
216
+ }
217
+
205
218
  if (!_.isEmpty(globalCodeinjection)) {
206
219
  head.push(globalCodeinjection);
207
220
  }
@@ -0,0 +1,4 @@
1
+ const AdminAuthAssetsService = require('./service');
2
+ let adminAuthAssets = new AdminAuthAssetsService();
3
+
4
+ module.exports = adminAuthAssets;
@@ -0,0 +1,93 @@
1
+ // const debug = require('@tryghost/debug')('comments-counts-assets');
2
+ const Minifier = require('@tryghost/minifier');
3
+ const path = require('path');
4
+ const fs = require('fs').promises;
5
+ const logging = require('@tryghost/logging');
6
+ const config = require('../../../shared/config');
7
+
8
+ class AdminAuthAssetsService {
9
+ constructor(options = {}) {
10
+ /** @private */
11
+ this.src = options.src || path.join(config.get('paths').assetSrc, 'admin-auth');
12
+ /** @private */
13
+ this.dest = options.dest || path.join(config.getContentPath('public'), 'admin-auth');
14
+ /** @private */
15
+ this.minifier = new Minifier({src: this.src, dest: this.dest});
16
+ }
17
+
18
+ /**
19
+ * @private
20
+ */
21
+ generateGlobs() {
22
+ return {
23
+ 'admin-auth.min.js': '*.js'
24
+ };
25
+ }
26
+
27
+ /**
28
+ * @private
29
+ * @returns {Promise<void>}
30
+ */
31
+ async minify(globs) {
32
+ try {
33
+ await this.minifier.minify(globs);
34
+ } catch (error) {
35
+ if (error.code === 'EACCES') {
36
+ logging.error('Ghost was not able to write admin-auth asset files due to permissions.');
37
+ return;
38
+ }
39
+
40
+ throw error;
41
+ }
42
+ }
43
+
44
+ /**
45
+ * @private
46
+ * @returns {Promise<void>}
47
+ */
48
+ async copyStatic() {
49
+ try {
50
+ await fs.copyFile(path.join(this.src, 'index.html'), path.join(this.dest, 'index.html'));
51
+ } catch (error) {
52
+ if (error.code === 'EACCES') {
53
+ logging.error('Ghost was not able to write admin-auth asset files due to permissions.');
54
+ return;
55
+ }
56
+
57
+ throw error;
58
+ }
59
+ }
60
+
61
+ /**
62
+ * @private
63
+ * @returns {Promise<void>}
64
+ */
65
+ async clearFiles() {
66
+ const rmFile = async (name) => {
67
+ await fs.unlink(path.join(this.dest, name));
68
+ };
69
+
70
+ let promises = [
71
+ // @deprecated switch this to use fs.rm when we drop support for Node v12
72
+ rmFile('admin-auth.min.js'),
73
+ rmFile('index.html')
74
+ ];
75
+
76
+ // We don't care if removing these files fails as it's valid for them to not exist
77
+ await Promise.allSettled(promises);
78
+ }
79
+
80
+ /**
81
+ * Minify, move into the destination directory, and clear existing asset files.
82
+ *
83
+ * @returns {Promise<void>}
84
+ */
85
+ async load() {
86
+ const globs = this.generateGlobs();
87
+ await this.clearFiles();
88
+ await this.minify(globs);
89
+ await this.copyStatic();
90
+ }
91
+ }
92
+
93
+ module.exports = AdminAuthAssetsService;
@@ -0,0 +1,4 @@
1
+ const CommentCountsAssetsService = require('./service');
2
+ let commentCountsAssets = new CommentCountsAssetsService();
3
+
4
+ module.exports = commentCountsAssets;
@@ -0,0 +1,59 @@
1
+ // const debug = require('@tryghost/debug')('comments-counts-assets');
2
+ const Minifier = require('@tryghost/minifier');
3
+ const path = require('path');
4
+ const fs = require('fs').promises;
5
+ const logging = require('@tryghost/logging');
6
+ const config = require('../../../shared/config');
7
+
8
+ class CommentCountsAssetsService {
9
+ constructor(options = {}) {
10
+ this.src = options.src || path.join(config.get('paths').assetSrc, 'comment-counts');
11
+ this.dest = options.dest || config.getContentPath('public');
12
+ this.minifier = new Minifier({src: this.src, dest: this.dest});
13
+
14
+ this.files = [];
15
+ }
16
+
17
+ generateGlobs() {
18
+ return {
19
+ 'comment-counts.min.js': 'js/*.js'
20
+ };
21
+ }
22
+
23
+ async minify(globs) {
24
+ try {
25
+ return await this.minifier.minify(globs);
26
+ } catch (error) {
27
+ if (error.code === 'EACCES') {
28
+ logging.error('Ghost was not able to write comment-count asset files due to permissions.');
29
+ return;
30
+ }
31
+
32
+ throw error;
33
+ }
34
+ }
35
+
36
+ async clearFiles() {
37
+ this.files = [];
38
+
39
+ const rmFile = async (name) => {
40
+ await fs.unlink(path.join(this.dest, name));
41
+ };
42
+
43
+ let promises = [
44
+ // @deprecated switch this to use fs.rm when we drop support for Node v12
45
+ rmFile('comment-counts.min.js')
46
+ ];
47
+
48
+ // We don't care if removing these files fails as it's valid for them to not exist
49
+ return Promise.allSettled(promises);
50
+ }
51
+
52
+ async load() {
53
+ await this.clearFiles();
54
+ const globs = this.generateGlobs();
55
+ this.files = await this.minify(globs);
56
+ }
57
+ }
58
+
59
+ module.exports = CommentCountsAssetsService;
@@ -36,7 +36,11 @@ async function updateGlobalTemplateOptions(req, res, next) {
36
36
  {
37
37
  hbs.updateTemplateOptions({
38
38
  data: {
39
- site: siteData,
39
+ site: {
40
+ ...siteData,
41
+ comments_enabled: siteData.comments_enabled !== 'off',
42
+ comments_access: siteData.comments_enabled
43
+ },
40
44
  labs: labsData,
41
45
  config: themeData,
42
46
  custom: themeSettingsData
@@ -0,0 +1,5 @@
1
+ <html>
2
+ <head>
3
+ <script src="admin-auth.min.js"></script>
4
+ </head>
5
+ </html>
@@ -0,0 +1,75 @@
1
+ const adminUrl = window.location.href.replace('auth-frame/', '');
2
+
3
+ window.addEventListener('message', async function (event) {
4
+ if (event.origin !== '*') {
5
+ // return;
6
+ }
7
+ let data = null;
8
+ try {
9
+ data = JSON.parse(event.data);
10
+ } catch (err) {
11
+ console.error(err);
12
+ }
13
+
14
+ function respond(error, result) {
15
+ event.source.postMessage(JSON.stringify({
16
+ uid: data.uid,
17
+ error: error,
18
+ result: result
19
+ }), '*');
20
+ }
21
+
22
+ if (data.action === 'getUser') {
23
+ try {
24
+ const res = await fetch(
25
+ adminUrl + 'api/canary/admin/users/me/'
26
+ );
27
+ const json = await res.json();
28
+ respond(null, json);
29
+ } catch (err) {
30
+ respond(err, null);
31
+ }
32
+ }
33
+
34
+ if (data.action === 'hideComment') {
35
+ try {
36
+ const res = await fetch(adminUrl + 'api/canary/admin/comments/' + data.id + '/', {
37
+ method: 'PUT',
38
+ body: JSON.stringify({
39
+ comments: [{
40
+ id: data.id,
41
+ status: 'hidden'
42
+ }]
43
+ }),
44
+ headers: {
45
+ 'Content-Type': 'application/json'
46
+ }
47
+ });
48
+ const json = await res.json();
49
+ respond(null, json);
50
+ } catch (err) {
51
+ respond(err, null);
52
+ }
53
+ }
54
+
55
+ if (data.action === 'showComment') {
56
+ try {
57
+ const res = await fetch(adminUrl + 'api/canary/admin/comments/' + data.id + '/', {
58
+ method: 'PUT',
59
+ body: JSON.stringify({
60
+ comments: [{
61
+ id: data.id,
62
+ status: 'published'
63
+ }]
64
+ }),
65
+ headers: {
66
+ 'Content-Type': 'application/json'
67
+ }
68
+ });
69
+ const json = await res.json();
70
+ respond(null, json);
71
+ } catch (err) {
72
+ respond(err, null);
73
+ }
74
+ }
75
+ });
@@ -0,0 +1,71 @@
1
+ (async function () {
2
+ const countsMap = {};
3
+ const fetchingIds = new Set();
4
+
5
+ const api = document.querySelector('[data-ghost-comments-counts-api]')
6
+ .dataset.ghostCommentsCountsApi;
7
+
8
+ const debounce = function (func, timeout = 100) {
9
+ let timer;
10
+ return (...args) => {
11
+ clearTimeout(timer);
12
+ timer = setTimeout(() => func.apply(this, args), timeout);
13
+ };
14
+ };
15
+
16
+ const addIdsFromElement = function (node) {
17
+ const countElems = node.querySelectorAll?.('[data-ghost-comment-count]') || [];
18
+
19
+ countElems.forEach((countElem) => {
20
+ if (!countsMap[countElem.dataset.ghostCommentCount]) {
21
+ fetchingIds.add(countElem.dataset.ghostCommentCount);
22
+ }
23
+ });
24
+ };
25
+
26
+ const renderCounts = function () {
27
+ for (const [id, count] of Object.entries(countsMap)) {
28
+ const countElems = document.querySelectorAll(`[data-ghost-comment-count="${id}"]`);
29
+ countElems.forEach((e) => {
30
+ e.innerHTML = e.innerHTML.replace('#', count);
31
+ e.style.display = '';
32
+ });
33
+ }
34
+ };
35
+
36
+ const fetchCounts = async function () {
37
+ const ids = Array.from(fetchingIds);
38
+ fetchingIds.clear();
39
+
40
+ const rawRes = await fetch(api, {
41
+ method: 'POST',
42
+ headers: {
43
+ Accept: 'application/json',
44
+ 'Content-Type': 'application/json'
45
+ },
46
+ body: JSON.stringify({ids})
47
+ });
48
+
49
+ const res = await rawRes.json();
50
+
51
+ for (const [id, count] of Object.entries(res)) {
52
+ countsMap[id] = count;
53
+ }
54
+
55
+ renderCounts();
56
+ };
57
+
58
+ const countElemObserver = new MutationObserver((mutationsList) => {
59
+ mutationsList.forEach((mutation) => {
60
+ mutation.addedNodes.forEach((addedNode) => {
61
+ addIdsFromElement(addedNode);
62
+ debounce(fetchCounts);
63
+ });
64
+ });
65
+ });
66
+
67
+ countElemObserver.observe(document.body, {subtree: true, childList: true});
68
+
69
+ addIdsFromElement(document.body);
70
+ fetchCounts();
71
+ })();
@@ -72,6 +72,9 @@ module.exports = function setupSiteApp(routerConfig) {
72
72
  siteApp.use(mw.servePublicFile('built', 'public/cards.min.css', 'text/css', constants.ONE_YEAR_S));
73
73
  siteApp.use(mw.servePublicFile('built', 'public/cards.min.js', 'application/javascript', constants.ONE_YEAR_S));
74
74
 
75
+ // Comment counts
76
+ siteApp.use(mw.servePublicFile('built', 'public/comment-counts.min.js', 'application/javascript', constants.ONE_YEAR_S));
77
+
75
78
  // Serve blog images using the storage adapter
76
79
  siteApp.use(STATIC_IMAGE_URL_PREFIX, mw.handleImageSizes, storage.getStorage('images').serve());
77
80
  // Serve blog media using the storage adapter
File without changes