ghost 5.130.2 → 6.0.0-alpha.2

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 (281) hide show
  1. package/components/tryghost-i18n-6.0.0-alpha.2.tgz +0 -0
  2. package/core/boot.js +0 -2
  3. package/core/built/admin/assets/admin-x-activitypub/admin-x-activitypub.js +1 -1
  4. package/core/built/admin/assets/admin-x-activitypub/{index-B8te98RZ.mjs → index-BZDwG-OG.mjs} +7397 -7385
  5. package/core/built/admin/assets/admin-x-activitypub/{index-C8qwgKWF.mjs → index-DTlSQCGz.mjs} +2 -2
  6. package/core/built/admin/assets/admin-x-settings/{CodeEditorView-CAtv7MlN.mjs → CodeEditorView-CCUvrZhe.mjs} +2 -2
  7. package/core/built/admin/assets/admin-x-settings/admin-x-settings.js +3 -3
  8. package/core/built/admin/assets/admin-x-settings/{index-BVxh86CD.mjs → index-Cubs_8W6.mjs} +8088 -8532
  9. package/core/built/admin/assets/admin-x-settings/{index-DUhmXSBR.mjs → index-D0ejKdD5.mjs} +2 -2
  10. package/core/built/admin/assets/admin-x-settings/{modals-B5dtfzsB.mjs → modals-DSxs9dLy.mjs} +1676 -1614
  11. package/core/built/admin/assets/{chunk.524.1f2faf572078e5b86b09.js → chunk.524.0953dd72ae1efbabe0de.js} +7 -7
  12. package/core/built/admin/assets/{chunk.582.675905fe8f9be138fb19.js → chunk.582.3caa825c2a91efc48f1d.js} +8 -8
  13. package/core/built/admin/assets/{ghost-280b83af263b51bc4d6ce5bd8f536096.js → ghost-db0f84981913aec8a672c57aa22da07a.js} +40 -45
  14. package/core/built/admin/assets/posts/posts.js +6549 -6537
  15. package/core/built/admin/assets/stats/stats.js +8824 -8812
  16. package/core/built/admin/index.html +3 -3
  17. package/core/frontend/helpers/get.js +4 -2
  18. package/core/frontend/helpers/ghost_head.js +71 -77
  19. package/core/frontend/meta/canonical-url.js +1 -7
  20. package/core/frontend/meta/context-object.js +1 -1
  21. package/core/frontend/meta/get-meta.js +1 -4
  22. package/core/frontend/meta/og-image.js +1 -1
  23. package/core/frontend/meta/og-type.js +0 -2
  24. package/core/frontend/meta/schema.js +1 -1
  25. package/core/frontend/meta/twitter-image.js +1 -1
  26. package/core/frontend/meta/url.js +1 -12
  27. package/core/frontend/services/rendering/context.js +0 -8
  28. package/core/frontend/web/middleware/static-theme.js +20 -1
  29. package/core/server/api/endpoints/index.js +0 -4
  30. package/core/server/api/endpoints/session.js +0 -9
  31. package/core/server/api/endpoints/utils/serializers/input/settings.js +0 -2
  32. package/core/server/api/endpoints/utils/serializers/input/utils/settings-filter-type-group-mapper.js +0 -1
  33. package/core/server/api/endpoints/utils/serializers/input/utils/settings-key-group-mapper.js +0 -1
  34. package/core/server/api/endpoints/utils/serializers/input/utils/settings-key-type-mapper.js +0 -1
  35. package/core/server/api/endpoints/utils/serializers/output/all.js +1 -1
  36. package/core/server/api/endpoints/utils/serializers/output/index.js +0 -4
  37. package/core/server/api/endpoints/utils/serializers/output/mappers/snippets.js +1 -5
  38. package/core/server/api/endpoints/utils/serializers/output/members.js +0 -2
  39. package/core/server/api/endpoints/utils/validators/input/index.js +0 -4
  40. package/core/server/data/importer/importers/data/Base.js +1 -3
  41. package/core/server/data/importer/importers/data/SettingsImporter.js +1 -3
  42. package/core/server/data/migrations/utils/index.js +1 -4
  43. package/core/server/data/migrations/utils/permissions.js +14 -6
  44. package/core/server/data/migrations/utils/settings.js +39 -22
  45. package/core/server/data/migrations/versions/4.47/2022-05-03-15-30-final-v4.js +2 -0
  46. package/core/server/data/migrations/versions/4.47/2022-05-04-10-03-no-op.js +6 -0
  47. package/core/server/data/migrations/versions/5.100/2024-11-06-04-45-15-add-activitypub-integration.js +4 -2
  48. package/core/server/data/migrations/versions/5.113/2025-03-07-12-24-00-add-super-editor.js +4 -2
  49. package/core/server/data/migrations/versions/5.3/2022-07-06-07-58-add-ghost-explore-integration-role.js +4 -2
  50. package/core/server/data/migrations/versions/5.3/2022-07-06-09-17-add-ghost-explore-integration.js +4 -2
  51. package/core/server/data/migrations/versions/5.3/2022-07-06-09-26-add-ghost-explore-integration-api-key.js +4 -2
  52. package/core/server/data/migrations/versions/5.40/2023-03-21-18-42-add-self-serve-integration-role.js +4 -2
  53. package/core/server/data/migrations/versions/5.40/2023-03-21-18-52-add-self-serve-integration.js +4 -2
  54. package/core/server/data/migrations/versions/5.40/2023-03-21-19-02-add-self-serve-integration-api-key.js +4 -2
  55. package/core/server/data/migrations/versions/5.63/2023-09-13-13-03-10-add-ghost-core-content-integration.js +4 -2
  56. package/core/server/data/migrations/versions/5.63/2023-09-13-13-34-11-add-ghost-core-content-integration-key.js +4 -2
  57. package/core/server/data/migrations/versions/6.0/2025-06-20-01-41-54-remove-updated-by-column.js +46 -0
  58. package/core/server/data/migrations/versions/6.0/2025-06-20-13-41-55-remove-created-by-column.js +47 -0
  59. package/core/server/data/migrations/versions/6.0/2025-06-23-09-49-25-add-missing-member-uuids.js +22 -0
  60. package/core/server/data/migrations/versions/6.0/2025-06-23-10-03-26-members-nullable-uuid.js +5 -0
  61. package/core/server/data/migrations/versions/6.0/2025-06-24-09-19-42-use-object-id-for-hardcoded-user-id.js +95 -0
  62. package/core/server/data/migrations/versions/6.0/2025-06-25-15-03-29-remove-amp-from-settings.js +6 -0
  63. package/core/server/data/migrations/versions/6.0/2025-06-30-13-59-10-remove-mail-events-table.js +3 -0
  64. package/core/server/data/migrations/versions/6.0/2025-06-30-14-00-00-update-feature-image-alt-length.js +25 -0
  65. package/core/server/data/schema/default-settings/default-settings.json +0 -13
  66. package/core/server/data/schema/fixtures/FixtureManager.js +128 -5
  67. package/core/server/data/schema/fixtures/fixtures.json +4 -6
  68. package/core/server/data/schema/fixtures/index.js +3 -1
  69. package/core/server/data/schema/schema.js +20 -65
  70. package/core/server/data/seeders/DataGenerator.js +11 -2
  71. package/core/server/data/seeders/importers/EmailsImporter.js +1 -3
  72. package/core/server/data/seeders/importers/LabelsImporter.js +1 -3
  73. package/core/server/data/seeders/importers/MembersImporter.js +0 -1
  74. package/core/server/data/seeders/importers/MembersStripeCustomersImporter.js +1 -2
  75. package/core/server/data/seeders/importers/MembersStripeCustomersSubscriptionsImporter.js +0 -1
  76. package/core/server/data/seeders/importers/PostsImporter.js +0 -1
  77. package/core/server/data/seeders/importers/RolesUsersImporter.js +6 -1
  78. package/core/server/data/seeders/importers/TagsImporter.js +1 -2
  79. package/core/server/data/seeders/importers/UsersImporter.js +1 -2
  80. package/core/server/data/tinybird/ARCHITECTURE.md +0 -4
  81. package/core/server/data/tinybird/DOCS.md +0 -4
  82. package/core/server/models/base/bookshelf.js +8 -1
  83. package/core/server/models/base/plugins/events.js +0 -28
  84. package/core/server/models/base/plugins/user-type.js +10 -36
  85. package/core/server/models/post.js +25 -10
  86. package/core/server/models/relations/authors.js +2 -2
  87. package/core/server/models/settings.js +1 -14
  88. package/core/server/models/user.js +33 -6
  89. package/core/server/services/activitypub/ActivityPubService.js +1 -2
  90. package/core/server/services/activitypub/ActivityPubService.ts +1 -2
  91. package/core/server/services/explore-ping/ExplorePingService.js +3 -1
  92. package/core/server/services/link-redirection/README.md +1 -1
  93. package/core/server/services/mentions/MentionSendingService.js +1 -1
  94. package/core/server/services/settings/SettingsBREADService.js +5 -1
  95. package/core/server/services/settings/settings-service.js +3 -1
  96. package/core/server/services/settings-helpers/SettingsHelpers.js +0 -12
  97. package/core/server/services/update-check/UpdateCheckService.js +18 -2
  98. package/core/server/services/url/config.js +0 -2
  99. package/core/server/web/api/app.js +4 -0
  100. package/core/server/web/api/endpoints/admin/middleware.js +8 -9
  101. package/core/server/web/api/endpoints/admin/routes.js +0 -2
  102. package/core/server/web/comments/routes.js +3 -0
  103. package/core/server/web/shared/middleware/index.js +4 -0
  104. package/core/server/web/shared/middleware/max-limit-cap.js +27 -0
  105. package/core/server/web/shared/middleware/pretty-urls.js +3 -1
  106. package/core/server/web/shared/middleware/redirect-amp-urls.js +36 -0
  107. package/core/shared/config/defaults.json +2 -0
  108. package/core/shared/config/overrides.json +1 -4
  109. package/core/shared/labs.js +2 -6
  110. package/core/shared/max-limit-cap.js +61 -0
  111. package/package.json +5 -6
  112. package/tsconfig.tsbuildinfo +1 -1
  113. package/yarn.lock +18 -107
  114. package/components/tryghost-i18n-5.130.2.tgz +0 -0
  115. package/core/built/admin/assets/img/amp-d7b72aae3315fda95921fb575dfca100.svg +0 -4
  116. package/core/frontend/apps/amp/index.js +0 -30
  117. package/core/frontend/apps/amp/lib/helpers/amp_analytics.js +0 -32
  118. package/core/frontend/apps/amp/lib/helpers/amp_components.js +0 -48
  119. package/core/frontend/apps/amp/lib/helpers/amp_content.js +0 -214
  120. package/core/frontend/apps/amp/lib/helpers/amp_style.js +0 -8
  121. package/core/frontend/apps/amp/lib/router.js +0 -95
  122. package/core/frontend/apps/amp/lib/views/amp.hbs +0 -1046
  123. package/core/frontend/meta/amp-url.js +0 -14
  124. package/core/server/api/endpoints/mail-events.js +0 -17
  125. package/core/server/api/endpoints/utils/serializers/output/mail-events.js +0 -9
  126. package/core/server/api/endpoints/utils/validators/input/mail-events.js +0 -7
  127. package/core/server/data/migrations/utils/constants.js +0 -3
  128. package/core/server/data/migrations/versions/4.0/01-update-mobiledoc.js +0 -61
  129. package/core/server/data/migrations/versions/4.0/02-add-status-column-to-members.js +0 -11
  130. package/core/server/data/migrations/versions/4.0/03-populate-status-column-for-members.js +0 -81
  131. package/core/server/data/migrations/versions/4.0/04-drop-apps-related-tables.js +0 -10
  132. package/core/server/data/migrations/versions/4.0/05-add-members-subscribe-events-table.js +0 -9
  133. package/core/server/data/migrations/versions/4.0/06-populate-members-subscribe-events-table.js +0 -53
  134. package/core/server/data/migrations/versions/4.0/07-alter-unique-constraint-for-posts-slug.js +0 -7
  135. package/core/server/data/migrations/versions/4.0/08-add-members-login-events-table.js +0 -7
  136. package/core/server/data/migrations/versions/4.0/09-add-members-email-change-events-table.js +0 -9
  137. package/core/server/data/migrations/versions/4.0/10-add-members-status-events-table.js +0 -9
  138. package/core/server/data/migrations/versions/4.0/11-add-members-paid-subscription-events-table.js +0 -12
  139. package/core/server/data/migrations/versions/4.0/12-delete-apps-related-settings-keys.js +0 -16
  140. package/core/server/data/migrations/versions/4.0/13-add-members-payment-events-table.js +0 -10
  141. package/core/server/data/migrations/versions/4.0/14-remove-orphaned-stripe-records.js +0 -36
  142. package/core/server/data/migrations/versions/4.0/15-add-frontmatter-column-to-meta.js +0 -7
  143. package/core/server/data/migrations/versions/4.0/16-refactor-slack-setting.js +0 -96
  144. package/core/server/data/migrations/versions/4.0/17-populate-members-status-events-table.js +0 -41
  145. package/core/server/data/migrations/versions/4.0/18-transform-urls-absolute-to-transform-ready.js +0 -201
  146. package/core/server/data/migrations/versions/4.0/19-remove-labs-members-setting.js +0 -10
  147. package/core/server/data/migrations/versions/4.0/20-refactor-unsplash-setting.js +0 -41
  148. package/core/server/data/migrations/versions/4.0/21-sanitize-email-batches-provider-id.js +0 -8
  149. package/core/server/data/migrations/versions/4.0/22-solve-orphaned-webhooks.js +0 -87
  150. package/core/server/data/migrations/versions/4.0/23-regenerate-posts-html.js +0 -66
  151. package/core/server/data/migrations/versions/4.0/24-add-missing-email-permissions.js +0 -36
  152. package/core/server/data/migrations/versions/4.0/25-populate-members-paid-subscription-events-table.js +0 -129
  153. package/core/server/data/migrations/versions/4.0/26-add-cascade-on-delete.js +0 -76
  154. package/core/server/data/migrations/versions/4.0/27-add-primary-key-brute-migrations-lock.js +0 -9
  155. package/core/server/data/migrations/versions/4.0/28-add-webhook-intergrations-foreign-key.js +0 -16
  156. package/core/server/data/migrations/versions/4.0/29-fix-foreign-key-for-members-stripe-customers-subscriptions.js +0 -35
  157. package/core/server/data/migrations/versions/4.0/30-set-default-accent-color.js +0 -21
  158. package/core/server/data/migrations/versions/4.1/01-fix-backup-content-permission-typo.js +0 -15
  159. package/core/server/data/migrations/versions/4.1/02-add-unique-constraint-for-member-stripe-tables.js +0 -21
  160. package/core/server/data/migrations/versions/4.11/01-add-oauth-user-data.js +0 -12
  161. package/core/server/data/migrations/versions/4.11/02-add-email-verification-required-setting.js +0 -43
  162. package/core/server/data/migrations/versions/4.12/01-add-email-only-column-to-posts-meta-table.js +0 -7
  163. package/core/server/data/migrations/versions/4.12/02-fix-member-statuses.js +0 -39
  164. package/core/server/data/migrations/versions/4.13/01-add-members-stripe-connect-auth-permission-to-administrators.js +0 -6
  165. package/core/server/data/migrations/versions/4.13/02-add-members-products-events-table.js +0 -33
  166. package/core/server/data/migrations/versions/4.14/01-fix-comped-member-statuses.js +0 -73
  167. package/core/server/data/migrations/versions/4.14/02-fix-free-members-status-events.js +0 -61
  168. package/core/server/data/migrations/versions/4.15/01-add-temp-members-analytic-events-table.js +0 -12
  169. package/core/server/data/migrations/versions/4.16/01-add-custom-theme-settings-table.js +0 -9
  170. package/core/server/data/migrations/versions/4.17/01-add-custom-theme-settings-permissions.js +0 -21
  171. package/core/server/data/migrations/versions/4.17/02-add-offers-table.js +0 -19
  172. package/core/server/data/migrations/versions/4.17/03-add-offers-permissions.js +0 -35
  173. package/core/server/data/migrations/versions/4.19/01-add-active-column-to-offers.js +0 -7
  174. package/core/server/data/migrations/versions/4.19/02-add-offer-redemptions-table.js +0 -8
  175. package/core/server/data/migrations/versions/4.2/01-fix-incorrect-mrr-delta-events.js +0 -13
  176. package/core/server/data/migrations/versions/4.20/01-remove-offer-redemptions-table.js +0 -19
  177. package/core/server/data/migrations/versions/4.20/02-remove-offers-table.js +0 -30
  178. package/core/server/data/migrations/versions/4.20/03-add-offers-table.js +0 -21
  179. package/core/server/data/migrations/versions/4.20/04-add-offer-redemptions-table.js +0 -9
  180. package/core/server/data/migrations/versions/4.20/05-remove-not-null-constraint-from-portal-title.js +0 -44
  181. package/core/server/data/migrations/versions/4.22/01-add-is-launch-complete-setting.js +0 -8
  182. package/core/server/data/migrations/versions/4.22/02-update-launch-complete-setting-from-user-data.js +0 -39
  183. package/core/server/data/migrations/versions/4.23/01-truncate-offer-names.js +0 -59
  184. package/core/server/data/migrations/versions/4.3/01-add-products-table.js +0 -9
  185. package/core/server/data/migrations/versions/4.3/02-add-members-products-table.js +0 -8
  186. package/core/server/data/migrations/versions/4.3/03-add-default-product.js +0 -39
  187. package/core/server/data/migrations/versions/4.3/04-attach-members-to-product.js +0 -50
  188. package/core/server/data/migrations/versions/4.3/05-add-stripe-products-table.js +0 -9
  189. package/core/server/data/migrations/versions/4.3/06-add-stripe-prices-table.js +0 -15
  190. package/core/server/data/migrations/versions/4.3/07-add-products-permissions.js +0 -29
  191. package/core/server/data/migrations/versions/4.3/08-migrate-members-signup-setting.js +0 -109
  192. package/core/server/data/migrations/versions/4.3/09-add-price-id-column-to-subscriptions-table.js +0 -10
  193. package/core/server/data/migrations/versions/4.3/10-populate-stripe-price-id-in-subscriptions.js +0 -20
  194. package/core/server/data/migrations/versions/4.33/2022-01-14-11-50-add-type-column-to-products.js +0 -12
  195. package/core/server/data/migrations/versions/4.33/2022-01-14-11-51-add-default-free-tier.js +0 -40
  196. package/core/server/data/migrations/versions/4.33/2022-01-18-09-07-remove-duplicate-offer-redemptions.js +0 -46
  197. package/core/server/data/migrations/versions/4.33/2022-01-19-10-43-add-active-column-to-products-table.js +0 -7
  198. package/core/server/data/migrations/versions/4.34/2022-01-25-13-53-add-welcome-page-url-column-to-products.js +0 -7
  199. package/core/server/data/migrations/versions/4.35/2022-01-20-05-55-add-post-products-table.js +0 -8
  200. package/core/server/data/migrations/versions/4.35/2022-01-30-15-17-set-welcome-page-url-from-settings.js +0 -45
  201. package/core/server/data/migrations/versions/4.35/2022-02-01-11-48-update-email-recipient-filter-column-type.js +0 -19
  202. package/core/server/data/migrations/versions/4.35/2022-02-01-12-03-update-recipient-filter-column-type.js +0 -19
  203. package/core/server/data/migrations/versions/4.35/2022-02-02-10-38-add-default-content-visibility-tiers-setting.js +0 -8
  204. package/core/server/data/migrations/versions/4.35/2022-02-02-13-10-transform-specific-tiers-default-content-visibility.js +0 -147
  205. package/core/server/data/migrations/versions/4.35/2022-02-04-04-34-populate-empty-portal-products.js +0 -60
  206. package/core/server/data/migrations/versions/4.36/2022-02-07-14-34-add-last-seen-at-column-to-members.js +0 -10
  207. package/core/server/data/migrations/versions/4.37/2022-02-21-09-53-backfill-members-last-seen-at-column.js +0 -32
  208. package/core/server/data/migrations/versions/4.38/2022-03-01-08-46-add-visibility-to-tiers.js +0 -11
  209. package/core/server/data/migrations/versions/4.38/2022-03-03-16-12-add-visibility-to-tiers.js +0 -8
  210. package/core/server/data/migrations/versions/4.38/2022-03-03-16-17-drop-tiers-visible-column.js +0 -7
  211. package/core/server/data/migrations/versions/4.39/2022-03-07-10-57-update-free-products-visibility-column.js +0 -66
  212. package/core/server/data/migrations/versions/4.39/2022-03-07-10-57-update-products-visibility-column.js +0 -36
  213. package/core/server/data/migrations/versions/4.4/01-restore-free-members-signup-setting-from-backup.js +0 -99
  214. package/core/server/data/migrations/versions/4.4/02-migrate-members-signup-access.js +0 -126
  215. package/core/server/data/migrations/versions/4.40/2022-03-07-14-37-add-members-cancel-events-table.js +0 -8
  216. package/core/server/data/migrations/versions/4.40/2022-03-15-06-40-add-offers-admin-integration-permission-roles.js +0 -23
  217. package/core/server/data/migrations/versions/4.40/2022-03-15-06-40-add-tiers-admin-integration-permission-roles.js +0 -20
  218. package/core/server/data/migrations/versions/4.42/2022-03-21-17-17-add.js +0 -25
  219. package/core/server/data/migrations/versions/4.42/2022-03-30-15-44-add-newsletter-permissions.js +0 -28
  220. package/core/server/data/migrations/versions/4.43/2022-03-28-19-26-recreate-newsletter-table.js +0 -29
  221. package/core/server/data/migrations/versions/4.43/2022-03-29-14-45-add-members-newsletters-table.js +0 -7
  222. package/core/server/data/migrations/versions/4.43/2022-04-01-10-13-add-post-newsletter-relation.js +0 -108
  223. package/core/server/data/migrations/versions/4.43/2022-04-06-09-47-add-type-column-to-paid-subscription-events.js +0 -7
  224. package/core/server/data/migrations/versions/4.43/2022-04-06-14-56-add-email-newsletter-relation.js +0 -8
  225. package/core/server/data/migrations/versions/4.43/2022-04-08-10-45-add-subscription-id-to-mrr-events.js +0 -7
  226. package/core/server/data/migrations/versions/4.44/2022-04-06-15-22-populate-type-column-for-paid-subscription-events.js +0 -21
  227. package/core/server/data/migrations/versions/4.44/2022-04-08-11-54-add-cancelled-events.js +0 -51
  228. package/core/server/data/migrations/versions/4.44/2022-04-11-08-24-add-newsletter-permissions.js +0 -33
  229. package/core/server/data/migrations/versions/4.44/2022-04-11-10-54-add-mrr-to-subscriptions.js +0 -8
  230. package/core/server/data/migrations/versions/4.44/2022-04-12-07-33-fill-mrr.js +0 -29
  231. package/core/server/data/migrations/versions/4.44/2022-04-13-12-00-remove-newsletter-sender-name-not-null-constraint.js +0 -33
  232. package/core/server/data/migrations/versions/4.44/2022-04-15-07-53-add-offer-id-to-subscriptions.js +0 -9
  233. package/core/server/data/migrations/versions/4.45/2022-04-19-12-23-backfill-subscriptions-offers.js +0 -60
  234. package/core/server/data/migrations/versions/4.45/2022-04-20-11-25-add-newsletter-read-permission.js +0 -9
  235. package/core/server/data/migrations/versions/4.45/2022-04-21-02-55-add-notifications-key-entry-to-settings-table.js +0 -8
  236. package/core/server/data/migrations/versions/4.46/2022-04-13-12-00-add-created-at-newsletters.js +0 -6
  237. package/core/server/data/migrations/versions/4.46/2022-04-13-12-01-add-updated-at-newsletters.js +0 -6
  238. package/core/server/data/migrations/versions/4.46/2022-04-13-12-02-fill-created-at-newsletters.js +0 -19
  239. package/core/server/data/migrations/versions/4.46/2022-04-13-12-03-drop-nullable-created-at-newsletters.js +0 -3
  240. package/core/server/data/migrations/versions/4.46/2022-04-13-12-08-newsletters-show-header-name.js +0 -7
  241. package/core/server/data/migrations/versions/4.46/2022-04-13-12-57-add-uuid-column-to-newsletters.js +0 -8
  242. package/core/server/data/migrations/versions/4.46/2022-04-13-12-58-fill-uuid-for-newsletters.js +0 -19
  243. package/core/server/data/migrations/versions/4.46/2022-04-13-12-59-drop-nullable-uuid-newsletters.js +0 -3
  244. package/core/server/data/migrations/versions/4.46/2022-04-13-13-00-add-default-newsletter.js +0 -92
  245. package/core/server/data/migrations/versions/4.46/2022-04-20-08-39-map-subscribers-to-default-newsletter.js +0 -66
  246. package/core/server/data/migrations/versions/4.46/2022-04-22-07-43-add-newsletter-id-to-subscribe-events.js +0 -9
  247. package/core/server/data/migrations/versions/4.46/2022-04-27-07-59-set-newsletter-id-subscribe-events.js +0 -31
  248. package/core/server/data/migrations/versions/4.47/2022-05-03-15-30-update-newsletter-sending-options.js +0 -34
  249. package/core/server/data/migrations/versions/4.47/2022-05-04-10-03-transform-newsletter-header-image.js +0 -26
  250. package/core/server/data/migrations/versions/4.5/01-add-stripe-price-description-column.js +0 -7
  251. package/core/server/data/migrations/versions/4.5/02-add-product-description-column.js +0 -7
  252. package/core/server/data/migrations/versions/4.5/03-give-label-read-permissions-to-editors.js +0 -14
  253. package/core/server/data/migrations/versions/4.5/04-remove-unique-constraint-from-product-name.js +0 -13
  254. package/core/server/data/migrations/versions/4.5/05-rename-default-product-to-site-title.js +0 -38
  255. package/core/server/data/migrations/versions/4.6/01-remove-comped-status.js +0 -47
  256. package/core/server/data/migrations/versions/4.7/01-add-monthly-price-column-to-products.js +0 -7
  257. package/core/server/data/migrations/versions/4.7/02-add-yearly-price-column-to-products.js +0 -7
  258. package/core/server/data/migrations/versions/4.7/03-add-labs-setting.js +0 -42
  259. package/core/server/data/migrations/versions/4.8/01-add-feature-image-alt-column-to-posts-meta.js +0 -7
  260. package/core/server/data/migrations/versions/4.8/02-add-feature-image-caption-column-to-posts-meta.js +0 -7
  261. package/core/server/data/migrations/versions/4.8/03-add-default-product-portal-products.js +0 -69
  262. package/core/server/data/migrations/versions/4.8/04-migrate-show-newsletter-header-setting.js +0 -124
  263. package/core/server/data/migrations/versions/4.9/01-add-reset-all-passwords-permission.js +0 -11
  264. package/core/server/data/migrations/versions/4.9/02-add-benefits-table.js +0 -9
  265. package/core/server/data/migrations/versions/4.9/03-add-products-benefits-table.js +0 -8
  266. package/core/server/data/migrations/versions/4.9/04-add-member-segment-to-email-batches.js +0 -7
  267. package/core/server/data/migrations/versions/4.9/05-fix-missed-mobiledoc-url-transforms.js +0 -87
  268. package/core/server/data/migrations/versions/4.9/06-add-comped-status.js +0 -47
  269. package/core/server/data/migrations/versions/4.9/07-update-comped-members-status-events.js +0 -39
  270. package/core/server/models/mail-event.js +0 -12
  271. package/core/server/services/mail-events/BookshelfMailEventRepository.js +0 -40
  272. package/core/server/services/mail-events/InMemoryMailEventRepository.js +0 -10
  273. package/core/server/services/mail-events/InMemoryMailEventRepository.ts +0 -8
  274. package/core/server/services/mail-events/MailEvent.js +0 -20
  275. package/core/server/services/mail-events/MailEvent.ts +0 -10
  276. package/core/server/services/mail-events/MailEventRepository.js +0 -2
  277. package/core/server/services/mail-events/MailEventRepository.ts +0 -5
  278. package/core/server/services/mail-events/MailEventService.js +0 -124
  279. package/core/server/services/mail-events/MailEventService.ts +0 -169
  280. package/core/server/services/mail-events/index.js +0 -21
  281. package/core/server/services/mail-events/libraries.d.ts +0 -2
@@ -138,26 +138,12 @@ module.exports = function (Bookshelf) {
138
138
 
139
139
  /**
140
140
  * Adding resources implies setting these properties on the server side
141
- * - set `created_by` based on the context
142
- * - set `updated_by` based on the context
143
141
  * - the bookshelf `timestamps` plugin sets `created_at` and `updated_at`
144
142
  * - if plugin is disabled (e.g. import) we have a fallback condition
145
143
  *
146
144
  * Exceptions: internal context or importing
147
145
  */
148
146
  onCreating: function onCreating(model, attr, options) {
149
- if (Object.prototype.hasOwnProperty.call(schema.tables[this.tableName], 'created_by')) {
150
- if (!options.importing || (options.importing && !this.get('created_by'))) {
151
- this.set('created_by', String(this.contextUser(options)));
152
- }
153
- }
154
-
155
- if (Object.prototype.hasOwnProperty.call(schema.tables[this.tableName], 'updated_by')) {
156
- if (!options.importing) {
157
- this.set('updated_by', String(this.contextUser(options)));
158
- }
159
- }
160
-
161
147
  if (Object.prototype.hasOwnProperty.call(schema.tables[this.tableName], 'created_at')) {
162
148
  if (!model.get('created_at')) {
163
149
  model.set('created_at', new Date());
@@ -199,9 +185,7 @@ module.exports = function (Bookshelf) {
199
185
 
200
186
  /**
201
187
  * Changing resources implies setting these properties on the server side
202
- * - set `updated_by` based on the context
203
188
  * - ensure `created_at` never changes
204
- * - ensure `created_by` never changes
205
189
  * - the bookshelf `timestamps` plugin sets `updated_at` automatically
206
190
  *
207
191
  * Exceptions:
@@ -216,24 +200,12 @@ module.exports = function (Bookshelf) {
216
200
  model.changed = _.omit(model.changed, this.relationships);
217
201
  }
218
202
 
219
- if (Object.prototype.hasOwnProperty.call(schema.tables[this.tableName], 'updated_by')) {
220
- if (!options.importing && !options.migrating) {
221
- this.set('updated_by', String(this.contextUser(options)));
222
- }
223
- }
224
-
225
203
  if (options && options.context && !options.context.internal && !options.importing) {
226
204
  if (Object.prototype.hasOwnProperty.call(schema.tables[this.tableName], 'created_at')) {
227
205
  if (model.hasDateChanged('created_at', {beforeWrite: true})) {
228
206
  model.set('created_at', this.previous('created_at'));
229
207
  }
230
208
  }
231
-
232
- if (Object.prototype.hasOwnProperty.call(schema.tables[this.tableName], 'created_by')) {
233
- if (model.hasChanged('created_by')) {
234
- model.set('created_by', String(this.previous('created_by')));
235
- }
236
- }
237
209
  }
238
210
 
239
211
  // CASE: do not allow setting only the `updated_at` field, exception: importing
@@ -8,7 +8,7 @@ const messages = {
8
8
  /**
9
9
  * @param {import('bookshelf')} Bookshelf
10
10
  */
11
- module.exports = function (Bookshelf) {
11
+ module.exports = function (Bookshelf, pluginOptions) {
12
12
  Bookshelf.Model = Bookshelf.Model.extend({
13
13
  getActor(options = {context: {}}) {
14
14
  if (options.context && options.context.integration) {
@@ -29,37 +29,22 @@ module.exports = function (Bookshelf) {
29
29
  },
30
30
 
31
31
  // Get the user from the options object
32
- contextUser: function contextUser(options) {
32
+ contextUser: async function contextUser(options) {
33
33
  options = options || {};
34
34
  options.context = options.context || {};
35
35
 
36
36
  if (options.context.user) {
37
37
  return options.context.user;
38
38
  } else if (options.context.integration) {
39
- /**
40
- * @NOTE:
41
- *
42
- * This is a dirty fix until we get rid of all the x_by columns
43
- * @deprecated x_by columns are deprecated as of v1.0 - instead we should use the actions table
44
- * see https://github.com/TryGhost/Ghost/issues/10286.
45
- *
46
- * We return the owner ID '1' in case an integration updates or creates resources.
47
- *
48
- * ---
49
- *
50
- * Why using ID '1'? WAIT. What???????
51
- *
52
- * See https://github.com/TryGhost/Ghost/issues/9299.
53
- *
54
- * We currently don't read the correct owner ID from the database and assume it's '1'.
55
- * This is a leftover from switching from auto increment ID's to Object ID's.
56
- * But this takes too long to refactor out now. If an internal update happens, we also
57
- * use ID '1'. This logic exists for a LONG while now. The owner ID only changes from '1' to something else,
58
- * if you transfer ownership.
59
- */
60
- return Bookshelf.Model.internalUser;
39
+ return pluginOptions.resolveIntegrationUserId({
40
+ transacting: options.transacting,
41
+ context: options.context
42
+ });
61
43
  } else if (options.context.internal) {
62
- return Bookshelf.Model.internalUser;
44
+ return pluginOptions.resolveInternalUserId({
45
+ transacting: options.transacting,
46
+ context: options.context
47
+ });
63
48
  } else if (this.get('id')) {
64
49
  return this.get('id');
65
50
  } else {
@@ -69,16 +54,5 @@ module.exports = function (Bookshelf) {
69
54
  });
70
55
  }
71
56
  }
72
- }, {
73
- /**
74
- * please use these static definitions when comparing id's
75
- * we keep type Number, because we have too many check's where we rely on Number
76
- * context.user ? true : false (if context.user is 0 as number, this condition is false)
77
- */
78
- internalUser: 1,
79
-
80
- isInternalUser: function isInternalUser(id) {
81
- return id === Bookshelf.Model.internalUser || id === Bookshelf.Model.internalUser.toString();
82
- }
83
57
  });
84
58
  };
@@ -601,6 +601,28 @@ Post = ghostBookshelf.Model.extend({
601
601
  }
602
602
  }
603
603
 
604
+ // CASE: Force a change for scheduled posts within 2 minutes of
605
+ // publishing. This ensures the scheduler can detect last-minute
606
+ // touches to the post
607
+ const isScheduled = newStatus === 'scheduled';
608
+ const isUpdate = options.method === 'update';
609
+ const isWithin2Minutes = publishedAt && moment(publishedAt).diff(moment(), 'minutes') <= 2;
610
+ const isNotImporting = !options.importing;
611
+ const isNotMigrating = !options.migrating;
612
+
613
+ if (isScheduled && isUpdate && isWithin2Minutes && isNotImporting && isNotMigrating) {
614
+ // Check if no actual changes have been made
615
+ if (!this.changed || Object.keys(this.changed).length === 0) {
616
+ // Force a "touch" by setting a dummy property that will be stored in _changed
617
+ this.set('_touch', true);
618
+ // Immediately unset it so it doesn't get saved to the database
619
+ this.unset('_touch');
620
+ // But ensure the changed object still has it for event detection
621
+ this.changed = this.changed || {};
622
+ this.changed._touch = true;
623
+ }
624
+ }
625
+
604
626
  // CASE: detect lowercase/uppercase tag slugs
605
627
  if (!_.isUndefined(this.get('tags')) && !_.isNull(this.get('tags'))) {
606
628
  tagsToSave = [];
@@ -744,7 +766,8 @@ Post = ghostBookshelf.Model.extend({
744
766
  if ((newStatus === 'published' || newStatus === 'sent') && this.hasChanged('status')) {
745
767
  // unless published_by is set and we're importing, set published_by to contextUser
746
768
  if (!(this.get('published_by') && options.importing)) {
747
- this.set('published_by', String(this.contextUser(options)));
769
+ const userId = await this.contextUser(options);
770
+ this.set('published_by', String(userId));
748
771
  }
749
772
  } else {
750
773
  // In any other case (except import), `published_by` should not be changed
@@ -888,7 +911,7 @@ Post = ghostBookshelf.Model.extend({
888
911
  revision_interval_ms: POST_REVISIONS_INTERVAL_MS
889
912
  }
890
913
  });
891
- let authorId = this.contextUser(options);
914
+ let authorId = await this.contextUser(options);
892
915
  const authorExists = await ghostBookshelf.model('User').findOne({id: authorId}, {transacting: options.transacting});
893
916
  if (!authorExists) {
894
917
  authorId = await ghostBookshelf.model('User').getOwnerUser().get('id');
@@ -954,14 +977,6 @@ Post = ghostBookshelf.Model.extend({
954
977
  return sequence(ops);
955
978
  },
956
979
 
957
- created_by: function createdBy() {
958
- return this.belongsTo('User', 'created_by');
959
- },
960
-
961
- updated_by: function updatedBy() {
962
- return this.belongsTo('User', 'updated_by');
963
- },
964
-
965
980
  published_by: function publishedBy() {
966
981
  return this.belongsTo('User', 'published_by');
967
982
  },
@@ -75,10 +75,10 @@ module.exports.extendModel = function extendModel(Post, Posts, ghostBookshelf) {
75
75
  return proto.onFetchedCollection.call(this, collection, attrs, options);
76
76
  },
77
77
 
78
- onCreating: function onCreating(model, attrs, options) {
78
+ onCreating: async function onCreating(model, attrs, options) {
79
79
  if (!model.get('authors')) {
80
80
  model.set('authors', [{
81
- id: this.contextUser(options)
81
+ id: await this.contextUser(options)
82
82
  }]);
83
83
  }
84
84
 
@@ -292,25 +292,12 @@ Settings = ghostBookshelf.Model.extend({
292
292
 
293
293
  // fetch other data that is used when inserting new settings
294
294
  const date = ghostBookshelf.knex.raw('CURRENT_TIMESTAMP');
295
- let owner;
296
- try {
297
- owner = await ghostBookshelf.model('User').getOwnerUser();
298
- } catch (e) {
299
- // in some tests the owner is deleted and not recreated before setup
300
- if (e.errorType === 'NotFoundError') {
301
- owner = {id: 1};
302
- } else {
303
- throw e;
304
- }
305
- }
306
295
 
307
296
  const settingsDataToInsert = settingsToInsert.map((setting) => {
308
297
  const settingValues = Object.assign({}, setting, {
309
298
  id: ObjectID().toHexString(),
310
299
  created_at: date,
311
- created_by: owner.id,
312
- updated_at: date,
313
- updated_by: owner.id
300
+ updated_at: date
314
301
  });
315
302
 
316
303
  return _.pick(settingValues, columns);
@@ -76,7 +76,7 @@ User = ghostBookshelf.Model.extend({
76
76
  },
77
77
 
78
78
  format(options) {
79
- if (options.website &&
79
+ if (options.website &&
80
80
  !validator.isURL(options.website, {
81
81
  require_protocol: true,
82
82
  protocols: ['http', 'https']
@@ -295,10 +295,6 @@ User = ghostBookshelf.Model.extend({
295
295
  return attrs;
296
296
  },
297
297
 
298
- posts: function posts() {
299
- return this.hasMany('Posts', 'created_by');
300
- },
301
-
302
298
  sessions: function sessions() {
303
299
  return this.hasMany('Session');
304
300
  },
@@ -778,9 +774,38 @@ User = ghostBookshelf.Model.extend({
778
774
  });
779
775
  },
780
776
 
777
+ ownerIdCache: {
778
+ value: null,
779
+ set(value) {
780
+ this.value = value;
781
+ },
782
+ get() {
783
+ return this.value;
784
+ },
785
+ clear() {
786
+ this.value = null;
787
+ }
788
+ },
789
+
790
+ getOwnerId: function getOwnerId(options) {
791
+ if (this.ownerIdCache.value !== null) {
792
+ return Promise.resolve(this.ownerIdCache.value);
793
+ }
794
+
795
+ return this.getOwnerUser(options).then((owner) => {
796
+ this.ownerIdCache.set(owner.id);
797
+
798
+ return owner.id;
799
+ });
800
+ },
801
+
802
+ generateId: function generateId() {
803
+ return ObjectId().toHexString();
804
+ },
805
+
781
806
  /**
782
807
  * Checks if a user has permission to perform an action on another user
783
- *
808
+ *
784
809
  * @param {Object|string|number} userModelOrId - The user model or ID being acted upon
785
810
  * @param {'edit'|'destroy'} action - The action being performed:
786
811
  * - 'edit': Edit user details, status, or role
@@ -1112,6 +1137,8 @@ User = ghostBookshelf.Model.extend({
1112
1137
  ]);
1113
1138
  })
1114
1139
  .then((results) => {
1140
+ this.ownerIdCache.clear();
1141
+
1115
1142
  return Users.forge()
1116
1143
  .query('whereIn', 'id', [contextUser.id, results[2]])
1117
1144
  .fetch({withRelated: ['roles']});
@@ -124,8 +124,7 @@ class ActivityPubService {
124
124
  name: `ActivityPub ${expectedWebhook.event} Webhook`,
125
125
  secret: secret,
126
126
  integration_id: integration.id,
127
- created_at: this.knex.raw('current_timestamp'),
128
- created_by: '1'
127
+ created_at: this.knex.raw('current_timestamp')
129
128
  };
130
129
  });
131
130
  await this.knex
@@ -147,8 +147,7 @@ export class ActivityPubService {
147
147
  name: `ActivityPub ${expectedWebhook.event} Webhook`,
148
148
  secret: secret,
149
149
  integration_id: integration.id,
150
- created_at: this.knex.raw('current_timestamp'),
151
- created_by: '1'
150
+ created_at: this.knex.raw('current_timestamp')
152
151
  };
153
152
  });
154
153
 
@@ -33,7 +33,9 @@ module.exports = class ExplorePingService {
33
33
  ghost: this.ghostVersion.full,
34
34
  site_uuid: this.settingsCache.get('site_uuid'),
35
35
  url: this.config.get('url'),
36
- theme: this.settingsCache.get('active_theme')
36
+ theme: this.settingsCache.get('active_theme'),
37
+ facebook: this.settingsCache.get('facebook'),
38
+ twitter: this.settingsCache.get('twitter')
37
39
  };
38
40
 
39
41
  try {
@@ -77,7 +77,7 @@ select `newsletters`.*, `members_newsletters`.`member_id` as `_pivot_member_id`,
77
77
 
78
78
  Then we update the member:
79
79
  ```
80
- update `members` set `uuid` = ?, `transient_id` = ?, `email` = ?, `status` = ?, `name` = ?, `expertise` = ?, `note` = ?, `geolocation` = ?, `enable_comment_notifications` = ?, `email_count` = ?, `email_opened_count` = ?, `email_open_rate` = ?, `email_disabled` = ?, `last_seen_at` = ?, `last_commented_at` = ?, `created_at` = ?, `created_by` = ?, `updated_at` = ?, `updated_by` = ? where `id` = ? trx34
80
+ update `members` set `uuid` = ?, `transient_id` = ?, `email` = ?, `status` = ?, `name` = ?, `expertise` = ?, `note` = ?, `geolocation` = ?, `enable_comment_notifications` = ?, `email_count` = ?, `email_opened_count` = ?, `email_open_rate` = ?, `email_disabled` = ?, `last_seen_at` = ?, `last_commented_at` = ?, `created_at` = ?, `updated_at` = ? where `id` = ? trx34
81
81
  ```
82
82
 
83
83
  Then we select the member by ID again to get the freshly updated values from the DB:
@@ -45,7 +45,7 @@ module.exports = class MentionSendingService {
45
45
  // for now we don't want to evaluate mentions when importing data (at least needs queueing set up)
46
46
  // we do not want to evaluate mentions with fixture (internal) data, e.g. generating posts
47
47
  // TODO: real solution is likely suppressing event emission when building fixture data
48
- if (options && (options.importing || options.context.internal)) {
48
+ if (options && (options.importing || (options.context && options.context.internal))) {
49
49
  return;
50
50
  }
51
51
 
@@ -24,12 +24,14 @@ class SettingsBREADService {
24
24
  * @param {Object} options.singleUseTokenProvider
25
25
  * @param {Object} options.urlUtils
26
26
  * @param {Object} options.labsService - labs service instance
27
+ * @param {Object} options.limitsService - limits service instance
27
28
  * @param {{service: Object}} options.emailAddressService
28
29
  */
29
- constructor({SettingsModel, settingsCache, labsService, mail, singleUseTokenProvider, urlUtils, emailAddressService}) {
30
+ constructor({SettingsModel, settingsCache, labsService, limitsService, mail, singleUseTokenProvider, urlUtils, emailAddressService}) {
30
31
  this.SettingsModel = SettingsModel;
31
32
  this.settingsCache = settingsCache;
32
33
  this.labs = labsService;
34
+ this.limitsService = limitsService;
33
35
  this.emailAddressService = emailAddressService;
34
36
 
35
37
  /* email verification setup */
@@ -194,6 +196,8 @@ class SettingsBREADService {
194
196
  }
195
197
 
196
198
  if (stripeConnectData) {
199
+ await this.limitsService.errorIfWouldGoOverLimit('limitStripeConnect');
200
+
197
201
  filteredSettings.push({
198
202
  key: 'stripe_connect_publishable_key',
199
203
  value: stripeConnectData.public_key
@@ -5,6 +5,7 @@
5
5
  const events = require('../../lib/common/events');
6
6
  const models = require('../../models');
7
7
  const labs = require('../../../shared/labs');
8
+ const limits = require('../limits');
8
9
  const config = require('../../../shared/config');
9
10
  const adapterManager = require('../adapter-manager');
10
11
  const SettingsCache = require('../../../shared/settings-cache');
@@ -30,6 +31,7 @@ const getSettingsBREADServiceInstance = () => {
30
31
  SettingsModel: models.Settings,
31
32
  settingsCache: SettingsCache,
32
33
  labsService: labs,
34
+ limitsService: limits,
33
35
  mail,
34
36
  singleUseTokenProvider: new SingleUseTokenProvider({
35
37
  SingleUseTokenModel: models.SingleUseToken,
@@ -110,7 +112,7 @@ module.exports = {
110
112
  fields.push(new CalculatedField({key: 'social_web_enabled', type: 'boolean', group: 'social_web', fn: settingsHelpers.isSocialWebEnabled.bind(settingsHelpers), dependents: ['social_web', 'labs']}));
111
113
 
112
114
  // Web analytics
113
- fields.push(new CalculatedField({key: 'web_analytics_enabled', type: 'boolean', group: 'analytics', fn: settingsHelpers.isWebAnalyticsEnabled.bind(settingsHelpers), dependents: ['web_analytics', 'labs']}));
115
+ fields.push(new CalculatedField({key: 'web_analytics_enabled', type: 'boolean', group: 'analytics', fn: settingsHelpers.isWebAnalyticsEnabled.bind(settingsHelpers), dependents: ['web_analytics']}));
114
116
  fields.push(new CalculatedField({key: 'web_analytics_configured', type: 'boolean', group: 'analytics', fn: settingsHelpers.isWebAnalyticsConfigured.bind(settingsHelpers), dependents: ['web_analytics']}));
115
117
 
116
118
  return fields;
@@ -234,12 +234,6 @@ class SettingsHelpers {
234
234
  return false;
235
235
  }
236
236
 
237
- // Labs setting
238
- if (!this.labs.isSet('ActivityPub')) {
239
- debug('Social web is disabled in labs');
240
- return false;
241
- }
242
-
243
237
  // Ghost (Pro) limits
244
238
  if (this.limitService.isDisabled('limitSocialWeb')) {
245
239
  debug('Social web is not available for Ghost (Pro) sites without a custom domain, or hosted on a subdirectory');
@@ -279,12 +273,6 @@ class SettingsHelpers {
279
273
  return false;
280
274
  }
281
275
 
282
- // Labs setting
283
- if (!this.labs.isSet('trafficAnalytics')) {
284
- debug('Web analytics is disabled in labs');
285
- return false;
286
- }
287
-
288
276
  // Check if web analytics can be configured (limit service and required config)
289
277
  if (!this.isWebAnalyticsConfigured()) {
290
278
  return false;
@@ -116,7 +116,10 @@ class UpdateCheckService {
116
116
  const hash = (await this.api.settings.read(_.extend({key: 'db_hash'}, internal))).settings[0];
117
117
  const theme = (await this.api.settings.read(_.extend({key: 'active_theme'}, internal))).settings[0];
118
118
  const posts = await this.api.posts.browse();
119
- const users = await this.api.users.browse(internal);
119
+ const users = await this.api.users.browse({
120
+ ...internal,
121
+ include: ['roles']
122
+ });
120
123
  const npm = await util.promisify(exec)('npm -v');
121
124
 
122
125
  const blogUrl = this.config.siteUrl;
@@ -128,7 +131,20 @@ class UpdateCheckService {
128
131
  data.theme = theme ? theme.value : '';
129
132
  data.post_count = posts && posts.meta && posts.meta.pagination ? posts.meta.pagination.total : 0;
130
133
  data.user_count = users && users.users && users.users.length ? users.users.length : 0;
131
- data.blog_created_at = users && users.users && users.users[0] && users.users[0].created_at ? moment(users.users[0].created_at).unix() : '';
134
+
135
+ let blogCreatedAt = null;
136
+
137
+ if (users && users.users && users.users.length > 0) {
138
+ const ownerUser = users.users.find(user => user.roles.some(role => role.name === 'Owner'));
139
+
140
+ if (ownerUser) {
141
+ blogCreatedAt = ownerUser.created_at;
142
+ } else {
143
+ blogCreatedAt = users.users[0].created_at;
144
+ }
145
+ }
146
+
147
+ data.blog_created_at = blogCreatedAt ? moment(blogCreatedAt).unix() : '';
132
148
  data.npm_version = npm.stdout.trim();
133
149
 
134
150
  return data;
@@ -19,7 +19,6 @@ module.exports = [
19
19
  // @TODO: https://github.com/TryGhost/Ghost/issues/10335
20
20
  // 'page',
21
21
  'status',
22
- 'amp',
23
22
  'codeinjection_head',
24
23
  'codeinjection_foot',
25
24
  'meta_title',
@@ -68,7 +67,6 @@ module.exports = [
68
67
  // @TODO: https://github.com/TryGhost/Ghost/issues/10335
69
68
  // 'page',
70
69
  // 'status',
71
- 'amp',
72
70
  'codeinjection_head',
73
71
  'codeinjection_foot',
74
72
  'meta_title',
@@ -2,6 +2,7 @@ const debug = require('@tryghost/debug')('web:api:default:app');
2
2
  const config = require('../../../shared/config');
3
3
  const express = require('../../../shared/express');
4
4
  const sentry = require('../../../shared/sentry');
5
+ const middleware = require('../shared/middleware');
5
6
  const errorHandler = require('@tryghost/mw-error-handler');
6
7
  const APIVersionCompatibilityService = require('../../services/api-version-compatibility');
7
8
 
@@ -19,6 +20,9 @@ module.exports = function setupApiApp() {
19
20
  apiApp.use(APIVersionCompatibilityService.versionRewrites);
20
21
  apiApp.use(APIVersionCompatibilityService.contentVersion);
21
22
 
23
+ // Enforce capped limit parameter
24
+ apiApp.use(middleware.maxLimitCap);
25
+
22
26
  apiApp.lazyUse('/content/', require('./endpoints/content/app'));
23
27
  apiApp.lazyUse('/admin/', require('./endpoints/admin/app'));
24
28
 
@@ -5,7 +5,7 @@ const shared = require('../../../shared');
5
5
  const apiMw = require('../../middleware');
6
6
 
7
7
  const messages = {
8
- notImplemented: 'The server does not support the functionality required to fulfill the request.',
8
+ apiTokenBlocked: 'API tokens do not have permission to access this endpoint',
9
9
  staffTokenBlocked: 'Staff tokens are not allowed to access this endpoint'
10
10
  };
11
11
 
@@ -14,7 +14,7 @@ const messages = {
14
14
  * @param {import('express').Response} res
15
15
  * @param {import('express').NextFunction} next
16
16
  */
17
- const notImplemented = function notImplemented(req, res, next) {
17
+ const tokenPermissionCheck = function tokenPermissionCheck(req, res, next) {
18
18
  // CASE: user is logged in with user auth, skip to permission system
19
19
  if (!req.api_key) {
20
20
  return next();
@@ -81,10 +81,9 @@ const notImplemented = function notImplemented(req, res, next) {
81
81
  }
82
82
  }
83
83
 
84
- next(new errors.InternalServerError({
85
- errorType: 'NotImplementedError',
86
- message: tpl(messages.notImplemented),
87
- statusCode: 501
84
+ next(new errors.NoPermissionError({
85
+ message: tpl(messages.apiTokenBlocked),
86
+ statusCode: 403
88
87
  }));
89
88
  };
90
89
 
@@ -102,7 +101,7 @@ module.exports.authAdminApi = [
102
101
  apiMw.cors,
103
102
  shared.middleware.urlRedirects.adminSSLAndHostRedirect,
104
103
  shared.middleware.prettyUrls,
105
- notImplemented
104
+ tokenPermissionCheck
106
105
  ];
107
106
 
108
107
  /**
@@ -118,7 +117,7 @@ module.exports.authAdminApiWithUrl = [
118
117
  apiMw.cors,
119
118
  shared.middleware.urlRedirects.adminSSLAndHostRedirect,
120
119
  shared.middleware.prettyUrls,
121
- notImplemented
120
+ tokenPermissionCheck
122
121
  ];
123
122
 
124
123
  /**
@@ -130,5 +129,5 @@ module.exports.publicAdminApi = [
130
129
  apiMw.cors,
131
130
  shared.middleware.urlRedirects.adminSSLAndHostRedirect,
132
131
  shared.middleware.prettyUrls,
133
- notImplemented
132
+ tokenPermissionCheck
134
133
  ];
@@ -19,7 +19,6 @@ module.exports = function apiRoutes() {
19
19
 
20
20
  // ## Public
21
21
  router.get('/site', mw.publicAdminApi, http(api.site.read));
22
- router.post('/mail_events', mw.publicAdminApi, http(api.mailEvents.add));
23
22
 
24
23
  // ## Configuration
25
24
  router.get('/config', mw.authAdminApi, http(api.config.read));
@@ -247,7 +246,6 @@ module.exports = function apiRoutes() {
247
246
  router.get('/tinybird/token', mw.authAdminApi, http(api.tinybird.token));
248
247
 
249
248
  // ## Sessions
250
- router.get('/session', mw.authAdminApi, http(api.session.read));
251
249
  // We don't need auth when creating a new session (logging in)
252
250
  router.post('/session',
253
251
  shared.middleware.brute.globalBlock,
@@ -23,6 +23,9 @@ module.exports = function apiRoutes() {
23
23
  // Authenticated Routes
24
24
  router.use(membersService.middleware.loadMemberSession);
25
25
 
26
+ // Enforce capped limit parameter
27
+ router.use(shared.middleware.maxLimitCap);
28
+
26
29
  router.get('/', http(api.commentsMembers.browse));
27
30
  router.get('/post/:post_id', http(api.commentsMembers.browse));
28
31
  router.get('/:id', http(api.commentsMembers.read));
@@ -11,6 +11,10 @@ module.exports = {
11
11
  return require('./cache-control');
12
12
  },
13
13
 
14
+ get maxLimitCap() {
15
+ return require('./max-limit-cap');
16
+ },
17
+
14
18
  get prettyUrls() {
15
19
  return require('./pretty-urls');
16
20
  },
@@ -0,0 +1,27 @@
1
+ const {applyLimitCap, limitConfig} = require('../../../../shared/max-limit-cap');
2
+
3
+ // Prior to Ghost 6.x we allowed any limit value, including 'all', but as sites
4
+ // grew in size it led to performance issues and mis-use of the API.
5
+
6
+ // After Ghost 6.x we only allow a max limit of 100. This middleware enforces
7
+ // that limit by rewriting the limit parameter before it reaches any API code.
8
+
9
+ function maxLimitCap(req, res, next) {
10
+ const limit = req.query.limit;
11
+
12
+ if (!limit) {
13
+ return next();
14
+ }
15
+
16
+ // Apply the shared limit capping logic with URL for exception endpoint checking
17
+ const cappedLimit = applyLimitCap(limit, {url: req.originalUrl});
18
+
19
+ req.query.limit = cappedLimit;
20
+ next();
21
+ }
22
+
23
+ // Create middleware stack with limitConfig property for test access
24
+ /** @type {Array<Function> & {limitConfig: object}} */
25
+ const middlewareStack = Object.assign([maxLimitCap], {limitConfig});
26
+
27
+ module.exports = middlewareStack;
@@ -1,8 +1,9 @@
1
1
  // Pretty URL redirects
2
2
  //
3
- // These are two pieces of middleware that handle ensuring that
3
+ // These are three pieces of middleware that handle ensuring that
4
4
  // URLs get formatted correctly.
5
5
  // Slashes ensures that we get trailing slashes
6
+ // redirectAmpUrls removes /amp from the end of urls if it exists (AMP support removed in v6)
6
7
  // Uncapitalise changes case to lowercase
7
8
  // @TODO optimize this to reduce the number of redirects required to get to a pretty URL
8
9
  // @TODO move this to being used by routers?
@@ -15,5 +16,6 @@ module.exports = [
15
16
  'Cache-Control': `public, max-age=${config.get('caching:301:maxAge')}`
16
17
  }
17
18
  }),
19
+ require('./redirect-amp-urls'),
18
20
  require('./uncapitalise')
19
21
  ];