ghost 5.115.0 → 5.116.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 (341) hide show
  1. package/components/{tryghost-api-framework-5.115.0.tgz → tryghost-api-framework-5.116.0.tgz} +0 -0
  2. package/components/tryghost-constants-5.116.0.tgz +0 -0
  3. package/components/tryghost-custom-fonts-5.116.0.tgz +0 -0
  4. package/components/{tryghost-custom-theme-settings-service-5.115.0.tgz → tryghost-custom-theme-settings-service-5.116.0.tgz} +0 -0
  5. package/components/tryghost-domain-events-5.116.0.tgz +0 -0
  6. package/components/{tryghost-donations-5.115.0.tgz → tryghost-donations-5.116.0.tgz} +0 -0
  7. package/components/tryghost-email-addresses-5.116.0.tgz +0 -0
  8. package/components/tryghost-email-service-5.116.0.tgz +0 -0
  9. package/components/tryghost-email-suppression-list-5.116.0.tgz +0 -0
  10. package/components/tryghost-html-to-plaintext-5.116.0.tgz +0 -0
  11. package/components/tryghost-i18n-5.116.0.tgz +0 -0
  12. package/components/tryghost-job-manager-5.116.0.tgz +0 -0
  13. package/components/tryghost-link-replacer-5.116.0.tgz +0 -0
  14. package/components/tryghost-magic-link-5.116.0.tgz +0 -0
  15. package/components/tryghost-member-attribution-5.116.0.tgz +0 -0
  16. package/components/tryghost-member-events-5.116.0.tgz +0 -0
  17. package/components/tryghost-members-api-5.116.0.tgz +0 -0
  18. package/components/tryghost-members-csv-5.116.0.tgz +0 -0
  19. package/components/{tryghost-members-offers-5.115.0.tgz → tryghost-members-offers-5.116.0.tgz} +0 -0
  20. package/components/{tryghost-milestones-5.115.0.tgz → tryghost-milestones-5.116.0.tgz} +0 -0
  21. package/components/{tryghost-mw-error-handler-5.115.0.tgz → tryghost-mw-error-handler-5.116.0.tgz} +0 -0
  22. package/components/tryghost-mw-vhost-5.116.0.tgz +0 -0
  23. package/components/{tryghost-post-events-5.115.0.tgz → tryghost-post-events-5.116.0.tgz} +0 -0
  24. package/components/{tryghost-post-revisions-5.115.0.tgz → tryghost-post-revisions-5.116.0.tgz} +0 -0
  25. package/components/tryghost-posts-service-5.116.0.tgz +0 -0
  26. package/components/{tryghost-prometheus-metrics-5.115.0.tgz → tryghost-prometheus-metrics-5.116.0.tgz} +0 -0
  27. package/components/tryghost-security-5.116.0.tgz +0 -0
  28. package/components/{tryghost-tiers-5.115.0.tgz → tryghost-tiers-5.116.0.tgz} +0 -0
  29. package/components/tryghost-webmentions-5.116.0.tgz +0 -0
  30. package/content/themes/casper/LICENSE +1 -1
  31. package/content/themes/casper/README.md +1 -1
  32. package/content/themes/source/LICENSE +1 -1
  33. package/content/themes/source/README.md +1 -1
  34. package/content/themes/source/assets/built/screen.css +1 -1
  35. package/content/themes/source/assets/built/screen.css.map +1 -1
  36. package/content/themes/source/assets/css/screen.css +11 -6
  37. package/content/themes/source/partials/feature-image.hbs +2 -2
  38. package/core/boot.js +3 -43
  39. package/core/built/admin/assets/admin-x-activitypub/admin-x-activitypub.js +30494 -29403
  40. package/core/built/admin/assets/admin-x-demo/admin-x-demo.js +1 -1
  41. package/core/built/admin/assets/admin-x-demo/{index-0040480a.mjs → index-a9601514.mjs} +5 -4
  42. package/core/built/admin/assets/admin-x-demo/{modals-fb35c86c.mjs → modals-c1789d04.mjs} +67 -65
  43. package/core/built/admin/assets/admin-x-settings/{CodeEditorView-806ef39c.mjs → CodeEditorView-e9c9deb8.mjs} +2 -2
  44. package/core/built/admin/assets/admin-x-settings/admin-x-settings.js +2 -2
  45. package/core/built/admin/assets/admin-x-settings/{index-376f847c.mjs → index-84580c3a.mjs} +2 -2
  46. package/core/built/admin/assets/admin-x-settings/{index-8fa19303.mjs → index-f744cab7.mjs} +3147 -3123
  47. package/core/built/admin/assets/admin-x-settings/{modals-36775d71.mjs → modals-d9ca60c5.mjs} +1198 -1192
  48. package/core/built/admin/assets/chunk.524.8371443ef8f60db429d0.js +35 -0
  49. package/core/built/admin/assets/chunk.582.f90151775f2e53dd21d9.js +37 -0
  50. package/core/built/admin/assets/{chunk.874.461cb3cf5b6b36915f8c.js → chunk.713.e9027c0cc3c56110f5da.js} +125 -98
  51. package/core/built/admin/assets/{ghost-938b3d9c29e3564a53a22f8c8f82d351.js → ghost-03b64c086f3c60cabc85fe7a7e2b640a.js} +272 -251
  52. package/core/built/admin/assets/ghost-ba58e9822f7384461e926c7e23f04a75.css +1 -0
  53. package/core/built/admin/assets/ghost-dark-f1f29683b14ffa11615b3bba8b6ab92c.css +1 -0
  54. package/core/built/admin/assets/koenig-lexical/index.css +1 -1
  55. package/core/built/admin/assets/koenig-lexical/koenig-lexical.js +20563 -20891
  56. package/core/built/admin/assets/koenig-lexical/koenig-lexical.umd.js +139 -139
  57. package/core/built/admin/assets/posts/posts.js +5732 -5667
  58. package/core/built/admin/assets/stats/stats.js +75373 -0
  59. package/core/built/admin/assets/{vendor-68a4aa424a179a90f5bbc2b750def576.js → vendor-72026232b36d97babc6320917c16c321.js} +36 -34
  60. package/core/built/admin/index.html +6 -6
  61. package/core/cli/generate-data.js +1 -1
  62. package/core/frontend/helpers/ghost_head.js +8 -1
  63. package/core/frontend/public/ghost-stats.js +55 -2
  64. package/core/frontend/services/assets-minification/AdminAuthAssets.js +2 -1
  65. package/core/frontend/services/assets-minification/CardAssets.js +1 -1
  66. package/core/frontend/services/assets-minification/CommentCountsAssets.js +1 -1
  67. package/core/frontend/services/assets-minification/MemberAttributionAssets.js +1 -1
  68. package/core/frontend/services/assets-minification/Minifier.js +191 -0
  69. package/core/frontend/services/routing/controllers/previews.js +2 -1
  70. package/core/frontend/src/cards/css/cta.css +1 -1
  71. package/core/server/adapters/cache/Redis.js +1 -1
  72. package/core/server/adapters/lib/redis/AdapterCacheRedis.js +287 -0
  73. package/core/server/adapters/lib/redis/redis-store-factory.js +22 -0
  74. package/core/server/api/endpoints/posts.js +9 -3
  75. package/core/server/api/endpoints/previews.js +35 -1
  76. package/core/server/api/endpoints/slugs.js +6 -2
  77. package/core/server/api/endpoints/utils/serializers/output/utils/post-gating.js +6 -9
  78. package/core/server/api/endpoints/utils/validators/input/settings.js +1 -1
  79. package/core/server/data/db/connection.js +2 -0
  80. package/core/server/data/db/index.js +1 -0
  81. package/core/server/data/importer/handlers/ImporterContentFileHandler.js +90 -0
  82. package/core/server/data/importer/import-manager.js +3 -3
  83. package/core/server/data/importer/importers/importer-revue.js +128 -0
  84. package/core/server/data/importer/importers/json-to-html.js +107 -0
  85. package/core/server/data/migrations/utils/tables.js +2 -4
  86. package/core/server/data/seeders/DataGenerator.js +288 -0
  87. package/core/server/data/seeders/importers/BenefitsImporter.js +28 -0
  88. package/core/server/data/seeders/importers/CommentsImporter.js +73 -0
  89. package/core/server/data/seeders/importers/EmailBatchesImporter.js +38 -0
  90. package/core/server/data/seeders/importers/EmailRecipientFailuresImporter.js +67 -0
  91. package/core/server/data/seeders/importers/EmailRecipientsImporter.js +212 -0
  92. package/core/server/data/seeders/importers/EmailsImporter.js +99 -0
  93. package/core/server/data/seeders/importers/LabelsImporter.js +41 -0
  94. package/core/server/data/seeders/importers/MembersClickEventsImporter.js +69 -0
  95. package/core/server/data/seeders/importers/MembersCreatedEventsImporter.js +103 -0
  96. package/core/server/data/seeders/importers/MembersFeedbackImporter.js +45 -0
  97. package/core/server/data/seeders/importers/MembersImporter.js +111 -0
  98. package/core/server/data/seeders/importers/MembersLabelsImporter.js +39 -0
  99. package/core/server/data/seeders/importers/MembersLoginEventsImporter.js +69 -0
  100. package/core/server/data/seeders/importers/MembersNewslettersImporter.js +38 -0
  101. package/core/server/data/seeders/importers/MembersPaidSubscriptionEventsImporter.js +99 -0
  102. package/core/server/data/seeders/importers/MembersProductsImporter.js +42 -0
  103. package/core/server/data/seeders/importers/MembersStatusEventsImporter.js +58 -0
  104. package/core/server/data/seeders/importers/MembersStripeCustomersImporter.js +60 -0
  105. package/core/server/data/seeders/importers/MembersStripeCustomersSubscriptionsImporter.js +259 -0
  106. package/core/server/data/seeders/importers/MembersSubscribeEventsImporter.js +69 -0
  107. package/core/server/data/seeders/importers/MembersSubscriptionCreatedEventsImporter.js +95 -0
  108. package/core/server/data/seeders/importers/NewslettersImporter.js +40 -0
  109. package/core/server/data/seeders/importers/OffersImporter.js +70 -0
  110. package/core/server/data/seeders/importers/PostsAuthorsImporter.js +32 -0
  111. package/core/server/data/seeders/importers/PostsImporter.js +102 -0
  112. package/core/server/data/seeders/importers/PostsProductsImporter.js +35 -0
  113. package/core/server/data/seeders/importers/PostsTagsImporter.js +46 -0
  114. package/core/server/data/seeders/importers/ProductsBenefitsImporter.js +54 -0
  115. package/core/server/data/seeders/importers/ProductsImporter.js +90 -0
  116. package/core/server/data/seeders/importers/RecommendationClickEventsImporter.js +32 -0
  117. package/core/server/data/seeders/importers/RecommendationSubscribeEventsImporter.js +32 -0
  118. package/core/server/data/seeders/importers/RecommendationsImporter.js +34 -0
  119. package/core/server/data/seeders/importers/RedirectsImporter.js +49 -0
  120. package/core/server/data/seeders/importers/RolesUsersImporter.js +42 -0
  121. package/core/server/data/seeders/importers/StripePricesImporter.js +69 -0
  122. package/core/server/data/seeders/importers/StripeProductsImporter.js +34 -0
  123. package/core/server/data/seeders/importers/TableImporter.js +187 -0
  124. package/core/server/data/seeders/importers/TagsImporter.js +41 -0
  125. package/core/server/data/seeders/importers/UsersImporter.js +31 -0
  126. package/core/server/data/seeders/importers/WebMentionsImporter.js +42 -0
  127. package/core/server/data/seeders/importers/index.js +41 -0
  128. package/core/server/data/seeders/utils/JsonImporter.js +39 -0
  129. package/core/server/data/seeders/utils/blog-info.js +3 -0
  130. package/core/server/data/seeders/utils/database-date.js +7 -0
  131. package/core/server/data/seeders/utils/event-generator.js +48 -0
  132. package/core/server/data/seeders/utils/random.js +13 -0
  133. package/core/server/data/seeders/utils/topological-sort.js +33 -0
  134. package/core/server/lib/bootstrap-socket.js +87 -0
  135. package/core/server/lib/package-json/index.js +1 -0
  136. package/core/server/lib/package-json/package-json.js +160 -0
  137. package/core/server/lib/package-json/parse.js +57 -0
  138. package/core/server/models/base/plugins/actions.js +44 -31
  139. package/core/server/models/base/plugins/generate-slug.js +6 -0
  140. package/core/server/notify.js +1 -1
  141. package/core/server/services/activitypub/ActivityPubService.ts +1 -1
  142. package/core/server/services/adapter-manager/AdapterManager.js +161 -0
  143. package/core/server/services/adapter-manager/index.js +1 -1
  144. package/core/server/services/announcement-bar-service/AnnouncementBarSettings.js +54 -0
  145. package/core/server/services/announcement-bar-service/AnnouncementVisibilityValues.js +11 -0
  146. package/core/server/services/announcement-bar-service/index.js +1 -1
  147. package/core/server/services/api-version-compatibility/APIVersionCompatibilityService.js +99 -0
  148. package/core/server/services/api-version-compatibility/VersionNotificationsDataService.js +80 -0
  149. package/core/server/services/api-version-compatibility/extract-api-key.js +57 -0
  150. package/core/server/services/api-version-compatibility/index.js +2 -2
  151. package/core/server/services/api-version-compatibility/mw-api-version-mismatch.js +31 -0
  152. package/core/server/services/audience-feedback/AudienceFeedbackController.js +85 -0
  153. package/core/server/services/audience-feedback/AudienceFeedbackService.js +34 -0
  154. package/core/server/services/audience-feedback/Feedback.js +35 -0
  155. package/core/server/services/audience-feedback/index.js +4 -2
  156. package/core/server/services/auth/session/emails/signin.js +168 -0
  157. package/core/server/services/auth/session/index.js +2 -2
  158. package/core/server/services/auth/session/session-from-token.js +69 -0
  159. package/core/server/services/auth/session/session-service.js +374 -0
  160. package/core/server/services/custom-redirects/index.js +1 -1
  161. package/core/server/services/email-analytics/EmailAnalyticsProviderMailgun.js +62 -0
  162. package/core/server/services/email-analytics/EmailAnalyticsService.js +552 -0
  163. package/core/server/services/email-analytics/EmailAnalyticsServiceWrapper.js +3 -3
  164. package/core/server/services/email-analytics/EventProcessingResult.js +66 -0
  165. package/core/server/services/email-service/EmailServiceWrapper.js +4 -4
  166. package/core/server/services/email-suppression-list/MailgunEmailSuppressionList.js +1 -1
  167. package/core/server/services/email-suppression-list/service.js +1 -1
  168. package/core/server/services/explore-ping/ExplorePingService.js +106 -0
  169. package/core/server/services/explore-ping/index.js +31 -0
  170. package/core/server/services/identity-tokens/IdentityTokenService.js +30 -0
  171. package/core/server/services/identity-tokens/IdentityTokenService.ts +28 -0
  172. package/core/server/services/identity-tokens/IdentityTokenServiceWrapper.js +1 -1
  173. package/core/server/services/invitations/accept.js +5 -2
  174. package/core/server/services/lib/DynamicRedirectManager.js +156 -0
  175. package/core/server/services/lib/EmailContentGenerator.js +54 -0
  176. package/core/server/services/lib/InMemoryRepository.js +62 -0
  177. package/core/server/services/lib/InMemoryRepository.ts +80 -0
  178. package/core/server/services/lib/MailgunClient.js +364 -0
  179. package/core/server/services/link-redirection/LinkRedirect.js +26 -0
  180. package/core/server/services/link-redirection/LinkRedirectRepository.js +7 -7
  181. package/core/server/services/link-redirection/LinkRedirectsService.js +123 -0
  182. package/core/server/services/link-redirection/README.md +151 -0
  183. package/core/server/services/link-redirection/RedirectEvent.js +24 -0
  184. package/core/server/services/link-redirection/index.js +1 -1
  185. package/core/server/services/link-tracking/LinkClickTrackingService.js +1 -1
  186. package/core/server/services/mail/index.js +1 -1
  187. package/core/server/services/mail-events/BookshelfMailEventRepository.js +2 -2
  188. package/core/server/services/mail-events/InMemoryMailEventRepository.js +10 -0
  189. package/core/server/services/mail-events/InMemoryMailEventRepository.ts +8 -0
  190. package/core/server/services/mail-events/MailEvent.js +20 -0
  191. package/core/server/services/mail-events/MailEvent.ts +10 -0
  192. package/core/server/services/mail-events/MailEventRepository.js +2 -0
  193. package/core/server/services/mail-events/MailEventRepository.ts +5 -0
  194. package/core/server/services/mail-events/MailEventService.js +124 -0
  195. package/core/server/services/mail-events/MailEventService.ts +169 -0
  196. package/core/server/services/mail-events/index.js +1 -1
  197. package/core/server/services/mail-events/libraries.d.ts +2 -0
  198. package/core/server/services/members/CaptchaService.js +80 -0
  199. package/core/server/services/members/api.js +1 -1
  200. package/core/server/services/members/importer/MembersCSVImporter.js +464 -0
  201. package/core/server/services/members/importer/MembersCSVImporterStripeUtils.js +194 -0
  202. package/core/server/services/members/importer/email-template.js +182 -0
  203. package/core/server/services/members/importer/index.js +30 -0
  204. package/core/server/services/members/members-ssr.js +333 -0
  205. package/core/server/services/members/service.js +2 -2
  206. package/core/server/services/members-events/LastSeenAtUpdater.js +1 -1
  207. package/core/server/services/offers/service.js +1 -1
  208. package/core/server/services/posts/stats/PostStats.js +13 -0
  209. package/core/server/services/recommendations/RecommendationServiceWrapper.js +8 -8
  210. package/core/server/services/recommendations/service/BookshelfClickEventRepository.js +48 -0
  211. package/core/server/services/recommendations/service/BookshelfClickEventRepository.ts +49 -0
  212. package/core/server/services/recommendations/service/BookshelfRecommendationRepository.js +98 -0
  213. package/core/server/services/recommendations/service/BookshelfRecommendationRepository.ts +117 -0
  214. package/core/server/services/recommendations/service/BookshelfRepository.js +134 -0
  215. package/core/server/services/recommendations/service/BookshelfRepository.ts +196 -0
  216. package/core/server/services/recommendations/service/BookshelfSubscribeEventRepository.js +48 -0
  217. package/core/server/services/recommendations/service/BookshelfSubscribeEventRepository.ts +49 -0
  218. package/core/server/services/recommendations/service/ClickEvent.js +33 -0
  219. package/core/server/services/recommendations/service/ClickEvent.ts +32 -0
  220. package/core/server/services/recommendations/service/InMemoryRecommendationRepository.js +19 -0
  221. package/core/server/services/recommendations/service/InMemoryRecommendationRepository.ts +20 -0
  222. package/core/server/services/recommendations/service/IncomingRecommendationController.js +34 -0
  223. package/core/server/services/recommendations/service/IncomingRecommendationController.ts +51 -0
  224. package/core/server/services/recommendations/service/IncomingRecommendationEmailRenderer.js +25 -0
  225. package/core/server/services/recommendations/service/IncomingRecommendationEmailRenderer.ts +37 -0
  226. package/core/server/services/recommendations/service/IncomingRecommendationService.js +93 -0
  227. package/core/server/services/recommendations/service/IncomingRecommendationService.ts +160 -0
  228. package/core/server/services/recommendations/service/Recommendation.js +140 -0
  229. package/core/server/services/recommendations/service/Recommendation.ts +201 -0
  230. package/core/server/services/recommendations/service/RecommendationController.js +208 -0
  231. package/core/server/services/recommendations/service/RecommendationController.ts +258 -0
  232. package/core/server/services/recommendations/service/RecommendationMetadataService.js +86 -0
  233. package/core/server/services/recommendations/service/RecommendationMetadataService.ts +128 -0
  234. package/core/server/services/recommendations/service/RecommendationRepository.js +2 -0
  235. package/core/server/services/recommendations/service/RecommendationRepository.ts +13 -0
  236. package/core/server/services/recommendations/service/RecommendationService.js +228 -0
  237. package/core/server/services/recommendations/service/RecommendationService.ts +281 -0
  238. package/core/server/services/recommendations/service/SubscribeEvent.js +33 -0
  239. package/core/server/services/recommendations/service/SubscribeEvent.ts +32 -0
  240. package/core/server/services/recommendations/service/UnsafeData.js +183 -0
  241. package/core/server/services/recommendations/service/UnsafeData.ts +217 -0
  242. package/core/server/services/recommendations/service/WellknownService.js +36 -0
  243. package/core/server/services/recommendations/service/WellknownService.ts +47 -0
  244. package/core/server/services/recommendations/service/index.js +31 -0
  245. package/core/server/services/recommendations/service/index.ts +15 -0
  246. package/core/server/services/recommendations/service/libraries.d.ts +5 -0
  247. package/core/server/services/route-settings/SettingsPathManager.js +47 -0
  248. package/core/server/services/route-settings/index.js +1 -1
  249. package/core/server/services/slack-notifications/SlackNotifications.js +211 -0
  250. package/core/server/services/slack-notifications/SlackNotificationsService.js +90 -0
  251. package/core/server/services/slack-notifications/service.js +4 -6
  252. package/core/server/services/stripe/README.md +63 -0
  253. package/core/server/services/stripe/StripeAPI.js +931 -0
  254. package/core/server/services/stripe/StripeMigrations.js +613 -0
  255. package/core/server/services/stripe/StripeService.js +175 -0
  256. package/core/server/services/stripe/WebhookController.js +100 -0
  257. package/core/server/services/stripe/WebhookManager.js +175 -0
  258. package/core/server/services/stripe/events/StripeLiveDisabledEvent.js +23 -0
  259. package/core/server/services/stripe/events/StripeLiveEnabledEvent.js +23 -0
  260. package/core/server/services/stripe/events/index.js +4 -0
  261. package/core/server/services/stripe/service.js +1 -1
  262. package/core/server/services/stripe/services/webhook/CheckoutSessionEventService.js +255 -0
  263. package/core/server/services/stripe/services/webhook/InvoiceEventService.js +70 -0
  264. package/core/server/services/stripe/services/webhook/SubscriptionEventService.js +54 -0
  265. package/core/server/services/themes/loader.js +1 -1
  266. package/core/server/services/themes/to-json.js +1 -1
  267. package/core/server/web/api/endpoints/admin/app.js +1 -21
  268. package/core/server/web/api/endpoints/admin/routes.js +1 -0
  269. package/core/server/web/api/middleware/version-match.js +41 -0
  270. package/core/server/web/shared/middleware/cache-control.js +51 -0
  271. package/core/server/web/shared/middleware/index.js +1 -1
  272. package/core/server/web/well-known.js +1 -1
  273. package/core/shared/labs.js +5 -3
  274. package/core/shared/settings-cache/CacheManager.js +64 -6
  275. package/package.json +98 -146
  276. package/tsconfig.tsbuildinfo +1 -1
  277. package/yarn.lock +1478 -1634
  278. package/components/tryghost-adapter-cache-redis-5.115.0.tgz +0 -0
  279. package/components/tryghost-adapter-manager-5.115.0.tgz +0 -0
  280. package/components/tryghost-announcement-bar-settings-5.115.0.tgz +0 -0
  281. package/components/tryghost-api-version-compatibility-service-5.115.0.tgz +0 -0
  282. package/components/tryghost-audience-feedback-5.115.0.tgz +0 -0
  283. package/components/tryghost-bookshelf-repository-5.115.0.tgz +0 -0
  284. package/components/tryghost-bootstrap-socket-5.115.0.tgz +0 -0
  285. package/components/tryghost-captcha-service-5.115.0.tgz +0 -0
  286. package/components/tryghost-constants-5.115.0.tgz +0 -0
  287. package/components/tryghost-custom-fonts-5.115.0.tgz +0 -0
  288. package/components/tryghost-data-generator-5.115.0.tgz +0 -0
  289. package/components/tryghost-domain-events-5.115.0.tgz +0 -0
  290. package/components/tryghost-email-addresses-5.115.0.tgz +0 -0
  291. package/components/tryghost-email-analytics-provider-mailgun-5.115.0.tgz +0 -0
  292. package/components/tryghost-email-analytics-service-5.115.0.tgz +0 -0
  293. package/components/tryghost-email-content-generator-5.115.0.tgz +0 -0
  294. package/components/tryghost-email-events-5.115.0.tgz +0 -0
  295. package/components/tryghost-email-service-5.115.0.tgz +0 -0
  296. package/components/tryghost-email-suppression-list-5.115.0.tgz +0 -0
  297. package/components/tryghost-express-dynamic-redirects-5.115.0.tgz +0 -0
  298. package/components/tryghost-extract-api-key-5.115.0.tgz +0 -0
  299. package/components/tryghost-ghost-5.115.0.tgz +0 -0
  300. package/components/tryghost-html-to-plaintext-5.115.0.tgz +0 -0
  301. package/components/tryghost-i18n-5.115.0.tgz +0 -0
  302. package/components/tryghost-identity-token-service-5.115.0.tgz +0 -0
  303. package/components/tryghost-importer-handler-content-files-5.115.0.tgz +0 -0
  304. package/components/tryghost-importer-revue-5.115.0.tgz +0 -0
  305. package/components/tryghost-in-memory-repository-5.115.0.tgz +0 -0
  306. package/components/tryghost-job-manager-5.115.0.tgz +0 -0
  307. package/components/tryghost-link-redirects-5.115.0.tgz +0 -0
  308. package/components/tryghost-link-replacer-5.115.0.tgz +0 -0
  309. package/components/tryghost-magic-link-5.115.0.tgz +0 -0
  310. package/components/tryghost-mail-events-5.115.0.tgz +0 -0
  311. package/components/tryghost-mailgun-client-5.115.0.tgz +0 -0
  312. package/components/tryghost-member-attribution-5.115.0.tgz +0 -0
  313. package/components/tryghost-member-events-5.115.0.tgz +0 -0
  314. package/components/tryghost-members-api-5.115.0.tgz +0 -0
  315. package/components/tryghost-members-csv-5.115.0.tgz +0 -0
  316. package/components/tryghost-members-importer-5.115.0.tgz +0 -0
  317. package/components/tryghost-members-payments-5.115.0.tgz +0 -0
  318. package/components/tryghost-members-ssr-5.115.0.tgz +0 -0
  319. package/components/tryghost-members-stripe-service-5.115.0.tgz +0 -0
  320. package/components/tryghost-minifier-5.115.0.tgz +0 -0
  321. package/components/tryghost-mw-api-version-mismatch-5.115.0.tgz +0 -0
  322. package/components/tryghost-mw-cache-control-5.115.0.tgz +0 -0
  323. package/components/tryghost-mw-session-from-token-5.115.0.tgz +0 -0
  324. package/components/tryghost-mw-update-user-last-seen-5.115.0.tgz +0 -0
  325. package/components/tryghost-mw-version-match-5.115.0.tgz +0 -0
  326. package/components/tryghost-mw-vhost-5.115.0.tgz +0 -0
  327. package/components/tryghost-package-json-5.115.0.tgz +0 -0
  328. package/components/tryghost-posts-service-5.115.0.tgz +0 -0
  329. package/components/tryghost-recommendations-5.115.0.tgz +0 -0
  330. package/components/tryghost-referrers-5.115.0.tgz +0 -0
  331. package/components/tryghost-security-5.115.0.tgz +0 -0
  332. package/components/tryghost-session-service-5.115.0.tgz +0 -0
  333. package/components/tryghost-settings-path-manager-5.115.0.tgz +0 -0
  334. package/components/tryghost-slack-notifications-5.115.0.tgz +0 -0
  335. package/components/tryghost-version-notifications-data-service-5.115.0.tgz +0 -0
  336. package/components/tryghost-webmentions-5.115.0.tgz +0 -0
  337. package/core/built/admin/assets/chunk.524.31419fdf6fb3859ecc1e.js +0 -35
  338. package/core/built/admin/assets/chunk.582.08c816d5e4ab766486a7.js +0 -37
  339. package/core/built/admin/assets/ghost-c2a7c4a1b76550c4219adb2ed4124ce0.css +0 -1
  340. package/core/built/admin/assets/ghost-dark-f91e4a479c6d38d94d5d1b14727871dc.css +0 -1
  341. /package/core/built/admin/assets/{chunk.874.461cb3cf5b6b36915f8c.js.LICENSE.txt → chunk.713.e9027c0cc3c56110f5da.js.LICENSE.txt} +0 -0
@@ -0,0 +1,28 @@
1
+ const TableImporter = require('./TableImporter');
2
+ const {faker} = require('@faker-js/faker');
3
+ const {slugify} = require('@tryghost/string');
4
+ const {blogStartDate} = require('../utils/blog-info');
5
+
6
+ class BenefitsImporter extends TableImporter {
7
+ static table = 'benefits';
8
+ static dependencies = [];
9
+ defaultQuantity = 5;
10
+
11
+ constructor(knex, transaction) {
12
+ super(BenefitsImporter.table, knex, transaction);
13
+ }
14
+
15
+ generate() {
16
+ const name = faker.company.catchPhrase();
17
+ const sixMonthsLater = new Date(blogStartDate);
18
+ sixMonthsLater.setMonth(sixMonthsLater.getMonth() + 6);
19
+ return {
20
+ id: this.fastFakeObjectId(),
21
+ name: name,
22
+ slug: `${slugify(name)}-${faker.random.numeric(3)}`,
23
+ created_at: faker.date.between(blogStartDate, sixMonthsLater)
24
+ };
25
+ }
26
+ }
27
+
28
+ module.exports = BenefitsImporter;
@@ -0,0 +1,73 @@
1
+ const {faker} = require('@faker-js/faker');
2
+ const TableImporter = require('./TableImporter');
3
+ const {luck} = require('../utils/random');
4
+ const generateEvents = require('../utils/event-generator');
5
+ const dateToDatabaseString = require('../utils/database-date');
6
+
7
+ class CommentsImporter extends TableImporter {
8
+ static table = 'comments';
9
+ static dependencies = ['posts'];
10
+
11
+ constructor(knex, transaction) {
12
+ super(CommentsImporter.table, knex, transaction);
13
+ }
14
+
15
+ async import(quantity) {
16
+ const posts = await this.transaction.select('id', 'published_at').from('posts')
17
+ .where('status', 'published');
18
+ this.members = await this.transaction.select('id', 'created_at').from('members');
19
+
20
+ this.commentsPerPost = quantity ? quantity / posts.length : 10;
21
+
22
+ await this.importForEach(posts, this.commentsPerPost);
23
+ }
24
+
25
+ setReferencedModel(model) {
26
+ this.model = model;
27
+
28
+ this.commentIds = [];
29
+
30
+ this.timestamps = generateEvents({
31
+ shape: 'ease-out',
32
+ trend: 'negative',
33
+ // Steady readers login more, readers who lose interest read less overall.
34
+ // ceil because members will all have logged in at least once
35
+ total: faker.datatype.number({min: 0, max: this.commentsPerPost}),
36
+ startTime: new Date(model.published_at),
37
+ endTime: new Date()
38
+ });
39
+
40
+ this.possibleMembers = this.members.filter(member => new Date(member.created_at) < new Date(model.published_at));
41
+ }
42
+
43
+ generate() {
44
+ const timestamp = this.timestamps.pop();
45
+ if (!timestamp) {
46
+ // Out of events for this post
47
+ return null;
48
+ }
49
+
50
+ if (this.possibleMembers.length === 0) {
51
+ return null;
52
+ }
53
+
54
+ const isReply = luck(30) && this.commentIds.length > 0; // 30% of comments are replies
55
+
56
+ const event = {
57
+ id: this.fastFakeObjectId(),
58
+ post_id: this.model.id,
59
+ member_id: this.possibleMembers[faker.datatype.number(this.possibleMembers.length - 1)].id,
60
+ parent_id: isReply ? this.commentIds[faker.datatype.number(this.commentIds.length - 1)] : undefined,
61
+ status: 'published',
62
+ created_at: dateToDatabaseString(timestamp),
63
+ updated_at: dateToDatabaseString(timestamp),
64
+ html: `<p>${faker.lorem.sentence().replace(/[&<>"']/g, c => `&#${c.charCodeAt(0)};`)}</p>`
65
+ };
66
+
67
+ this.commentIds.push(event.id);
68
+
69
+ return event;
70
+ }
71
+ }
72
+
73
+ module.exports = CommentsImporter;
@@ -0,0 +1,38 @@
1
+ const TableImporter = require('./TableImporter');
2
+ const {faker} = require('@faker-js/faker');
3
+ const dateToDatabaseString = require('../utils/database-date');
4
+
5
+ class EmailBatchesImporter extends TableImporter {
6
+ static table = 'email_batches';
7
+ static dependencies = ['emails'];
8
+
9
+ constructor(knex, transaction) {
10
+ super(EmailBatchesImporter.table, knex, transaction);
11
+ }
12
+
13
+ async import(quantity) {
14
+ const emails = await this.transaction.select('id', 'created_at', 'email_count').from('emails');
15
+
16
+ // 1 batch per 1000 recipients
17
+ await this.importForEach(emails, quantity ?? (() => {
18
+ return Math.ceil(this.model.email_count / 1000);
19
+ }));
20
+ }
21
+
22
+ generate() {
23
+ const emailSentDate = new Date(this.model.created_at);
24
+ const latestUpdatedDate = new Date(this.model.created_at);
25
+ latestUpdatedDate.setHours(latestUpdatedDate.getHours() + 1);
26
+
27
+ return {
28
+ id: this.fastFakeObjectId(),
29
+ email_id: this.model.id,
30
+ provider_id: `${new Date().toISOString().split('.')[0].replace(/[^0-9]/g, '')}.${faker.datatype.hexadecimal({length: 16, prefix: '', case: 'lower'})}@m.example.com`,
31
+ status: 'submitted', // TODO: introduce failures
32
+ created_at: this.model.created_at,
33
+ updated_at: dateToDatabaseString(faker.date.between(emailSentDate, latestUpdatedDate))
34
+ };
35
+ }
36
+ }
37
+
38
+ module.exports = EmailBatchesImporter;
@@ -0,0 +1,67 @@
1
+ const TableImporter = require('./TableImporter');
2
+ const {faker} = require('@faker-js/faker');
3
+
4
+ class EmailRecipientFailuresImporter extends TableImporter {
5
+ static table = 'email_recipient_failures';
6
+ static dependencies = ['email_recipients'];
7
+
8
+ constructor(knex, transaction) {
9
+ super(EmailRecipientFailuresImporter.table, knex, transaction);
10
+ }
11
+
12
+ async import(quantity) {
13
+ const recipients = await this.transaction
14
+ .select(
15
+ 'id',
16
+ 'email_id',
17
+ 'member_id',
18
+ 'failed_at')
19
+ .from('email_recipients')
20
+ .whereNotNull('failed_at');
21
+
22
+ await this.importForEach(recipients, quantity ? quantity / recipients.length : 1);
23
+ }
24
+
25
+ generate() {
26
+ const errors = [
27
+ {
28
+ severity: 'permanent',
29
+ code: 605,
30
+ enhanced_code: null,
31
+ message: 'Not delivering to previously bounced address'
32
+ },
33
+ {
34
+ severity: 'permanent',
35
+ code: 451,
36
+ enhanced_code: '4.7.652',
37
+ message: '4.7.652 The mail server [xxx.xxx.xxx.xxx] has exceeded the maximum number of connections.'
38
+ },
39
+ {
40
+ message: 'No MX for example.com',
41
+ code: 498,
42
+ enhanced_code: null,
43
+ severity: 'permanent'
44
+ },
45
+ {
46
+ severity: 'temporary',
47
+ code: 552,
48
+ enhanced_code: null,
49
+ message: '5.2.2 <xxxxxxxx@example.com>: user is over quota'
50
+ }
51
+ ];
52
+
53
+ const error = faker.helpers.arrayElement(errors);
54
+
55
+ return {
56
+ id: this.fastFakeObjectId(),
57
+ email_id: this.model.email_id,
58
+ member_id: this.model.member_id,
59
+ email_recipient_id: this.model.id,
60
+ event_id: faker.random.alphaNumeric(20),
61
+ ...error,
62
+ failed_at: this.model.failed_at
63
+ };
64
+ }
65
+ }
66
+
67
+ module.exports = EmailRecipientFailuresImporter;
@@ -0,0 +1,212 @@
1
+ const TableImporter = require('./TableImporter');
2
+ const {faker} = require('@faker-js/faker');
3
+ const generateEvents = require('../utils/event-generator');
4
+ const dateToDatabaseString = require('../utils/database-date');
5
+ const debug = require('@tryghost/debug')('EmailRecipientsImporter');
6
+
7
+ const emailStatus = {
8
+ delivered: Symbol(),
9
+ opened: Symbol(),
10
+ failed: Symbol(),
11
+ none: Symbol()
12
+ };
13
+
14
+ function findFirstHigherIndex(arr, target) {
15
+ let start = 0;
16
+ let end = arr.length - 1;
17
+ let result = -1;
18
+
19
+ while (start <= end) {
20
+ let mid = Math.floor((start + end) / 2);
21
+
22
+ if (arr[mid] >= target) {
23
+ result = mid;
24
+ end = mid - 1; // Continue searching in the left half
25
+ } else {
26
+ start = mid + 1; // Continue searching in the right half
27
+ }
28
+ }
29
+
30
+ return result; // Return -1 if no element is higher than target
31
+ }
32
+
33
+ class EmailRecipientsImporter extends TableImporter {
34
+ static table = 'email_recipients';
35
+ static dependencies = ['emails', 'email_batches', 'members', 'members_subscribe_events'];
36
+
37
+ constructor(knex, transaction) {
38
+ super(EmailRecipientsImporter.table, knex, transaction);
39
+ }
40
+
41
+ async import(quantity) {
42
+ if (quantity === 0) {
43
+ return;
44
+ }
45
+
46
+ const now = Date.now();
47
+ const emails = await this.transaction
48
+ .select(
49
+ 'id',
50
+ 'newsletter_id',
51
+ 'email_count',
52
+ 'delivered_count',
53
+ 'opened_count',
54
+ 'failed_count')
55
+ .from('emails');
56
+ this.emails = new Map();
57
+
58
+ for (const email of emails) {
59
+ this.emails.set(email.id, email);
60
+ }
61
+
62
+ this.emailBatches = await this.transaction.select('id', 'email_id', 'updated_at').from('email_batches').orderBy('email_id');
63
+ const members = await this.transaction.select('id', 'uuid', 'email', 'name').from('members');
64
+ this.membersSubscribeEvents = await this.transaction.select('id', 'newsletter_id', 'created_at', 'member_id').from('members_subscribe_events').orderBy('created_at', 'asc'); // Order required for better performance in setReferencedModel
65
+
66
+ // Create a map for fast lookups
67
+ this.members = new Map();
68
+ for (const member of members) {
69
+ this.members.set(member.id, member);
70
+ }
71
+
72
+ // Save indexes of each batch for performance (remarkable faster than doing findIndex on each generate call)
73
+ let lastEmailId = null;
74
+ let lastIndex = 0;
75
+ for (const batch of this.emailBatches) {
76
+ if (batch.email_id !== lastEmailId) {
77
+ lastIndex = 0;
78
+ lastEmailId = batch.email_id;
79
+ }
80
+ batch.index = lastIndex;
81
+ lastIndex += 1;
82
+ }
83
+
84
+ // Now reorder by email id
85
+
86
+ debug (`Prepared data for ${this.name} in ${Date.now() - now}ms`);
87
+
88
+ // We use the same event curve for all emails to speed up the generation
89
+ // Spread over 14 days
90
+ this.eventStartTimeUsed = new Date();
91
+ const endTime = new Date(this.eventStartTimeUsed.getTime() + 1000 * 60 * 60 * 24 * 14);
92
+ this.eventCurve = generateEvents({
93
+ shape: 'ease-out',
94
+ trend: 'negative',
95
+ total: 1000,
96
+ startTime: this.eventStartTimeUsed,
97
+ endTime
98
+ });
99
+
100
+ this.membersSubscribeEventsByNewsletterId = new Map();
101
+ this.membersSubscribeEventsCreatedAtsByNewsletterId = new Map();
102
+ for (const memberSubscribeEvent of this.membersSubscribeEvents) {
103
+ if (!this.membersSubscribeEventsByNewsletterId.has(memberSubscribeEvent.newsletter_id)) {
104
+ this.membersSubscribeEventsByNewsletterId.set(memberSubscribeEvent.newsletter_id, []);
105
+ }
106
+ this.membersSubscribeEventsByNewsletterId.get(memberSubscribeEvent.newsletter_id).push(memberSubscribeEvent);
107
+
108
+ if (!this.membersSubscribeEventsCreatedAtsByNewsletterId.has(memberSubscribeEvent.newsletter_id)) {
109
+ this.membersSubscribeEventsCreatedAtsByNewsletterId.set(memberSubscribeEvent.newsletter_id, []);
110
+ }
111
+
112
+ if (!(memberSubscribeEvent.created_at instanceof Date)) {
113
+ // SQLite fix
114
+ memberSubscribeEvent.created_at = new Date(memberSubscribeEvent.created_at);
115
+ }
116
+ this.membersSubscribeEventsCreatedAtsByNewsletterId.get(memberSubscribeEvent.newsletter_id).push(memberSubscribeEvent.created_at.getTime());
117
+ }
118
+
119
+ await this.importForEach(this.emailBatches, quantity ? quantity / emails.length : 1000);
120
+ }
121
+
122
+ setReferencedModel(model) {
123
+ this.batch = model;
124
+ this.model = this.emails.get(this.batch.email_id);
125
+ this.batchIndex = this.batch.index;
126
+
127
+ // Shallow clone members list so we can shuffle and modify it
128
+ const earliestOpenTime = new Date(this.batch.updated_at);
129
+ const latestOpenTime = new Date(this.batch.updated_at);
130
+ latestOpenTime.setDate(latestOpenTime.getDate() + 14);
131
+
132
+ // Get all members that were subscribed to this newsletter BEFORE the batch was sent
133
+ // We use binary search to speed up it up
134
+ const lastIndex = findFirstHigherIndex(this.membersSubscribeEventsCreatedAtsByNewsletterId.get(this.model.newsletter_id), earliestOpenTime);
135
+
136
+ this.membersList = this.membersSubscribeEventsByNewsletterId.get(this.model.newsletter_id).slice(0, Math.max(0, lastIndex - 1))
137
+ .slice(this.batchIndex * 1000, (this.batchIndex + 1) * 1000)
138
+ .map(memberSubscribeEvent => memberSubscribeEvent.member_id);
139
+
140
+ this.events = faker.helpers.shuffle(this.eventCurve.slice(0, this.membersList.length));
141
+ this.eventIndex = 0;
142
+
143
+ this.emailMeta = {
144
+ // delievered and not opened
145
+ deliveredCount: this.model.delivered_count - this.model.opened_count,
146
+ openedCount: this.model.opened_count,
147
+ failedCount: this.model.failed_count
148
+ };
149
+
150
+ let offset = this.batchIndex * 1000;
151
+
152
+ // We always first create the failures, then the opened, then the delivered, so we need to remove those from the meta so we don't generate them multiple times
153
+ this.emailMeta = {
154
+ failedCount: Math.max(0, this.emailMeta.failedCount - offset),
155
+ openedCount: Math.max(0, this.emailMeta.openedCount - Math.max(0, offset - this.emailMeta.failedCount)),
156
+ deliveredCount: Math.max(0, this.emailMeta.deliveredCount - Math.max(0, offset - this.emailMeta.failedCount - this.emailMeta.openedCount))
157
+ };
158
+ }
159
+
160
+ generate() {
161
+ let timestamp = this.events.pop();
162
+ if (!timestamp) {
163
+ return;
164
+ }
165
+
166
+ // The events are generated for a different time, so we need to move them to the batch time
167
+ timestamp = new Date(timestamp.getTime() - this.eventStartTimeUsed.getTime() + new Date(this.batch.updated_at).getTime());
168
+
169
+ if (timestamp > new Date()) {
170
+ timestamp = new Date();
171
+ }
172
+
173
+ const memberId = this.membersList[this.events.length];
174
+ const member = this.members.get(memberId);
175
+
176
+ let status = emailStatus.none;
177
+ if (this.emailMeta.failedCount > 0) {
178
+ status = emailStatus.failed;
179
+ this.emailMeta.failedCount -= 1;
180
+ } else if (this.emailMeta.openedCount > 0) {
181
+ status = emailStatus.opened;
182
+ this.emailMeta.openedCount -= 1;
183
+ } else if (this.emailMeta.deliveredCount > 0) {
184
+ status = emailStatus.delivered;
185
+ this.emailMeta.deliveredCount -= 1;
186
+ }
187
+
188
+ let deliveredTime;
189
+ if (status === emailStatus.opened) {
190
+ const startDate = this.batch.updated_at;
191
+ const endDate = timestamp;
192
+ deliveredTime = faker.date.between(startDate, endDate);
193
+ }
194
+
195
+ return {
196
+ // Using sorted ids are much much faster (35% as far as my testing goes) for huge imports
197
+ id: this.fastFakeObjectId(),
198
+ email_id: this.model.id,
199
+ batch_id: this.batch.id,
200
+ member_id: member.id,
201
+ processed_at: dateToDatabaseString(this.batch.updated_at),
202
+ delivered_at: status === emailStatus.opened ? dateToDatabaseString(deliveredTime) : status === emailStatus.delivered ? dateToDatabaseString(timestamp) : null,
203
+ opened_at: status === emailStatus.opened ? dateToDatabaseString(timestamp) : null,
204
+ failed_at: status === emailStatus.failed ? dateToDatabaseString(timestamp) : null,
205
+ member_uuid: member.uuid,
206
+ member_email: member.email,
207
+ member_name: member.name
208
+ };
209
+ }
210
+ }
211
+
212
+ module.exports = EmailRecipientsImporter;
@@ -0,0 +1,99 @@
1
+ const TableImporter = require('./TableImporter');
2
+ const {faker} = require('@faker-js/faker');
3
+ const generateEvents = require('../utils/event-generator');
4
+ const {luck} = require('../utils/random');
5
+ const dateToDatabaseString = require('../utils/database-date');
6
+
7
+ class EmailsImporter extends TableImporter {
8
+ static table = 'emails';
9
+ static dependencies = ['posts', 'newsletters', 'members_subscribe_events'];
10
+
11
+ constructor(knex, transaction) {
12
+ super(EmailsImporter.table, knex, transaction);
13
+ }
14
+
15
+ async import(quantity) {
16
+ if (quantity === 0) {
17
+ return;
18
+ }
19
+
20
+ const posts = await this.transaction.select('id', 'title', 'published_at').from('posts').where('type', 'post').where('status', 'published').orderBy('published_at', 'desc');
21
+ this.newsletters = await this.transaction.select('id').from('newsletters').orderBy('sort_order');
22
+ this.membersSubscribeEvents = await this.transaction.select('id', 'newsletter_id', 'created_at').from('members_subscribe_events');
23
+
24
+ // Only generate emails for last 25% of posts, and only generate emails for 50% of those
25
+ await this.importForEach(posts.slice(0, Math.ceil(posts.length / 4)), quantity ? quantity / posts.length : 0.5);
26
+ }
27
+
28
+ generate() {
29
+ const id = this.fastFakeObjectId();
30
+
31
+ let newsletter;
32
+ if (this.newsletters.length === 0) {
33
+ return null;
34
+ } else if (this.newsletters.length === 1) {
35
+ newsletter = this.newsletters[0];
36
+ } else {
37
+ // Choose between first two newsletters
38
+ newsletter = luck(90)
39
+ // Regular premium
40
+ ? this.newsletters[0]
41
+ // Occasional freebie
42
+ : this.newsletters[1];
43
+ }
44
+
45
+ const timestamp = luck(60)
46
+ ? new Date(this.model.published_at)
47
+ : generateEvents({
48
+ shape: 'ease-out',
49
+ trend: 'negative',
50
+ total: 1,
51
+ startTime: new Date(this.model.published_at),
52
+ endTime: new Date()
53
+ })[0];
54
+
55
+ const recipientCount = this.membersSubscribeEvents
56
+ .filter(entry => entry.newsletter_id === newsletter.id)
57
+ .filter(entry => new Date(entry.created_at) < timestamp).length;
58
+ const deliveredCount = Math.ceil(recipientCount * faker.datatype.float({
59
+ max: 1,
60
+ min: 0.9,
61
+ precision: 0.001
62
+ }));
63
+ const openedCount = Math.ceil(deliveredCount * faker.datatype.float({
64
+ max: 0.95,
65
+ min: 0.6,
66
+ precision: 0.001
67
+ }));
68
+ const failedCount = Math.floor((recipientCount - deliveredCount) * faker.datatype.float({
69
+ max: 0.05,
70
+ min: 0,
71
+ precision: 0.001
72
+ }));
73
+
74
+ return {
75
+ id,
76
+ uuid: faker.datatype.uuid(),
77
+ post_id: this.model.id,
78
+ status: 'submitted',
79
+ recipient_filter: '', // TODO: Add recipient filter?
80
+ email_count: recipientCount,
81
+ delivered_count: deliveredCount,
82
+ opened_count: openedCount,
83
+ failed_count: failedCount,
84
+ subject: this.model.title,
85
+ source_type: 'html',
86
+ track_opens: true,
87
+ track_clicks: true,
88
+ feedback_enabled: true,
89
+ submitted_at: dateToDatabaseString(timestamp),
90
+ newsletter_id: newsletter.id,
91
+ created_at: dateToDatabaseString(timestamp),
92
+ created_by: 'unused',
93
+ updated_at: dateToDatabaseString(timestamp),
94
+ updated_by: 'unused'
95
+ };
96
+ }
97
+ }
98
+
99
+ module.exports = EmailsImporter;
@@ -0,0 +1,41 @@
1
+ const TableImporter = require('./TableImporter');
2
+ const {faker} = require('@faker-js/faker');
3
+ const {slugify} = require('@tryghost/string');
4
+ const {blogStartDate} = require('../utils/blog-info');
5
+ const dateToDatabaseString = require('../utils/database-date');
6
+
7
+ class LabelsImporter extends TableImporter {
8
+ static table = 'labels';
9
+ static dependencies = [];
10
+ defaultQuantity = 10;
11
+
12
+ constructor(knex, transaction) {
13
+ super(LabelsImporter.table, knex, transaction);
14
+ this.generatedNames = new Set();
15
+ }
16
+
17
+ generateName() {
18
+ let name;
19
+ do {
20
+ name = `${faker.color.human()} ${faker.name.jobType()}`;
21
+ name = `${name[0].toUpperCase()}${name.slice(1)}`;
22
+ } while (this.generatedNames.has(name));
23
+ this.generatedNames.add(name);
24
+ return name;
25
+ }
26
+
27
+ generate() {
28
+ const name = this.generateName();
29
+ return {
30
+ id: this.fastFakeObjectId(),
31
+ name: name,
32
+ slug: `${slugify(name)}`,
33
+ created_at: dateToDatabaseString(blogStartDate),
34
+ created_by: '1',
35
+ updated_at: dateToDatabaseString(blogStartDate),
36
+ updated_by: '1'
37
+ };
38
+ }
39
+ }
40
+
41
+ module.exports = LabelsImporter;
@@ -0,0 +1,69 @@
1
+ const TableImporter = require('./TableImporter');
2
+ const {faker} = require('@faker-js/faker');
3
+ const {luck} = require('../utils/random');
4
+ const dateToDatabaseString = require('../utils/database-date');
5
+
6
+ class MembersClickEventsImporter extends TableImporter {
7
+ static table = 'members_click_events';
8
+ static dependencies = ['email_recipients', 'redirects', 'emails'];
9
+
10
+ constructor(knex, transaction) {
11
+ super(MembersClickEventsImporter.table, knex, transaction);
12
+ }
13
+
14
+ async import(quantity) {
15
+ const emailRecipients = await this.transaction.select('id', 'opened_at', 'email_id', 'member_id').from('email_recipients').whereNotNull('opened_at');
16
+ const redirects = await this.transaction.select('id', 'post_id').from('redirects');
17
+ const emails = await this.transaction.select('id', 'post_id').from('emails');
18
+ this.quantity = quantity ? quantity / emailRecipients.length : 2;
19
+
20
+ // Create maps for faster lookups (this does make a difference for large data generation)
21
+ this.emails = new Map();
22
+ for (const email of emails) {
23
+ this.emails.set(email.id, email);
24
+ }
25
+
26
+ this.redirects = new Map();
27
+ for (const redirect of redirects) {
28
+ if (!this.redirects.has(redirect.post_id)) {
29
+ this.redirects.set(redirect.post_id, []);
30
+ }
31
+ this.redirects.get(redirect.post_id).push(redirect);
32
+ }
33
+
34
+ await this.importForEach(emailRecipients, this.quantity);
35
+ }
36
+
37
+ setReferencedModel(model) {
38
+ this.model = model;
39
+ this.amount = model.opened_at === null ? 0 : luck(40) ? faker.datatype.number({
40
+ min: 0,
41
+ max: this.quantity
42
+ }) : 0;
43
+ const email = this.emails.get(model.email_id);
44
+ this.redirectList = this.redirects.get(email.post_id) ?? [];
45
+ }
46
+
47
+ generate() {
48
+ if (this.amount <= 0 || this.redirectList.length === 0 || !this.model.opened_at) {
49
+ return;
50
+ }
51
+ this.amount -= 1;
52
+
53
+ const openedAt = new Date(this.model.opened_at);
54
+ const laterOn = new Date(openedAt.getTime() + 1000 * 60 * 15);
55
+ const clickTime = faker.date.between(openedAt.getTime(), laterOn.getTime()); //added getTime here because it threw random errors
56
+
57
+ return {
58
+ id: this.fastFakeObjectId(),
59
+ member_id: this.model.member_id,
60
+ redirect_id: this.redirectList[this.redirectList.length === 1 ? 0 : (faker.datatype.number({
61
+ min: 0,
62
+ max: this.redirectList.length - 1
63
+ }))].id,
64
+ created_at: dateToDatabaseString(clickTime)
65
+ };
66
+ }
67
+ }
68
+
69
+ module.exports = MembersClickEventsImporter;