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
@@ -2,7 +2,7 @@ const _ = require('lodash');
2
2
  const {ValidationError} = require('@tryghost/errors');
3
3
  const validator = require('@tryghost/validator');
4
4
  const tpl = require('@tryghost/tpl');
5
- const AnnouncementBarSettings = require('@tryghost/announcement-bar-settings');
5
+ const AnnouncementBarSettings = require('../../../../../services/announcement-bar-service/AnnouncementBarSettings');
6
6
 
7
7
  const messages = {
8
8
  invalidEmailReceived: 'Please send a valid email',
@@ -6,6 +6,8 @@ const fs = require('fs');
6
6
  const logging = require('@tryghost/logging');
7
7
  const config = require('../../../shared/config');
8
8
  const errors = require('@tryghost/errors');
9
+
10
+ /** @type {knex.Knex} */
9
11
  let knexInstance;
10
12
 
11
13
  // @TODO:
@@ -1,3 +1,4 @@
1
+ /** @type {import('knex').Knex} */
1
2
  let connection;
2
3
 
3
4
  Object.defineProperty(exports, 'knex', {
@@ -0,0 +1,90 @@
1
+ const _ = require('lodash');
2
+ const path = require('path');
3
+
4
+ class ImporterContentFileHandler {
5
+ /** @property {'media' | 'files' | 'images'} */
6
+ type;
7
+
8
+ /** @property {string[]} */
9
+ directories;
10
+
11
+ /** @property {string[]} */
12
+ extensions;
13
+
14
+ /** @property {string[]} */
15
+ contentTypes;
16
+
17
+ /**
18
+ * Holds path to the destination content directory
19
+ * @property {string} */
20
+ #contentPath;
21
+
22
+ /**
23
+ *
24
+ * @param {Object} deps dependencies
25
+ * @param {'media' | 'files' | 'images'} deps.type type of content file
26
+ * @param {string[]} deps.extensions file extensions to search for
27
+ * @param {boolean} [deps.ignoreRootFolderFiles] whether to ignore files in the root folder
28
+ * @param {string[]} deps.contentTypes content types to search for
29
+ * @param {string[]} deps.directories directories to search for content files
30
+ * @param {string} deps.contentPath path to the destination content directory
31
+ * @param {Object} deps.storage storage adapter instance
32
+ * @param {object} deps.urlUtils urlUtils instance
33
+ */
34
+ constructor(deps) {
35
+ this.type = deps.type;
36
+ this.directories = deps.directories;
37
+ this.extensions = deps.extensions;
38
+ this.contentTypes = deps.contentTypes;
39
+ this.ignoreRootFolderFiles = deps.ignoreRootFolderFiles;
40
+ this.storage = deps.storage;
41
+ this.#contentPath = deps.contentPath;
42
+ this.urlUtils = deps.urlUtils;
43
+ }
44
+
45
+ async loadFile(files, baseDir) {
46
+ const baseDirRegex = baseDir ? new RegExp('^' + baseDir + '/') : new RegExp('');
47
+
48
+ const contentFilesFolderRegexes = _.map(this.storage.staticFileURLPrefix.split('/'), function (dir) {
49
+ return new RegExp('^' + dir + '/');
50
+ });
51
+
52
+ if (this.ignoreRootFolderFiles) {
53
+ files = _.filter(files, function (file) {
54
+ return file.name.indexOf('/') !== -1;
55
+ });
56
+ }
57
+
58
+ // normalize the directory structure
59
+ const filesContentPath = this.#contentPath;
60
+ files = _.map(files, function (file) {
61
+ const noBaseDir = file.name.replace(baseDirRegex, '');
62
+ let noGhostDirs = noBaseDir;
63
+
64
+ _.each(contentFilesFolderRegexes, function (regex) {
65
+ noGhostDirs = noGhostDirs.replace(regex, '');
66
+ });
67
+
68
+ file.originalPath = noBaseDir;
69
+ file.name = noGhostDirs;
70
+ file.targetDir = path.join(filesContentPath, path.dirname(noGhostDirs));
71
+ return file;
72
+ });
73
+
74
+ const self = this;
75
+ return Promise.all(files.map(function (contentFile) {
76
+ return self.storage.getUniqueFileName(contentFile, contentFile.targetDir).then(function (targetFilename) {
77
+ contentFile.newPath = self.urlUtils.urlJoin(
78
+ '/',
79
+ self.urlUtils.getSubdir(),
80
+ self.storage.staticFileURLPrefix,
81
+ path.relative(filesContentPath, targetFilename)
82
+ );
83
+
84
+ return contentFile;
85
+ });
86
+ }));
87
+ }
88
+ }
89
+
90
+ module.exports = ImporterContentFileHandler;
@@ -11,12 +11,12 @@ const debug = require('@tryghost/debug')('import-manager');
11
11
  const logging = require('@tryghost/logging');
12
12
  const errors = require('@tryghost/errors');
13
13
  const ImageHandler = require('./handlers/image');
14
- const ImporterContentFileHandler = require('@tryghost/importer-handler-content-files');
14
+ const ImporterContentFileHandler = require('./handlers/ImporterContentFileHandler');
15
15
  const RevueHandler = require('./handlers/revue');
16
16
  const JSONHandler = require('./handlers/json');
17
17
  const MarkdownHandler = require('./handlers/markdown');
18
18
  const ContentFileImporter = require('./importers/ContentFileImporter');
19
- const RevueImporter = require('@tryghost/importer-revue');
19
+ const RevueImporter = require('./importers/importer-revue');
20
20
  const DataImporter = require('./importers/data');
21
21
  const urlUtils = require('../../../shared/url-utils');
22
22
  const {GhostMailer} = require('../../services/mail');
@@ -225,7 +225,7 @@ class ImportManager {
225
225
 
226
226
  try {
227
227
  await extract(filePath, tmpDir);
228
-
228
+
229
229
  // Set permissions for all extracted files
230
230
  const files = glob.sync('**/*', {cwd: tmpDir, nodir: true});
231
231
  await Promise.all(files.map(file => fs.chmod(path.join(tmpDir, file), 0o644)));
@@ -0,0 +1,128 @@
1
+ const debug = require('@tryghost/debug')('importer:revue');
2
+ const {slugify} = require('@tryghost/string');
3
+ const papaparse = require('papaparse');
4
+ const _ = require('lodash');
5
+
6
+ const JSONToHTML = require('./json-to-html');
7
+
8
+ /**
9
+ * Build posts out of the issue and item data
10
+ *
11
+ * @param {Object} revueData
12
+ * @return {Array}
13
+ */
14
+ const fetchPostsFromData = (revueData) => {
15
+ const itemData = JSON.parse(revueData.items);
16
+ const issueData = papaparse.parse(revueData.issues, {
17
+ header: true,
18
+ skipEmptyLines: true,
19
+ transform(value, header) {
20
+ if (header === 'id') {
21
+ return parseInt(value);
22
+ }
23
+ return value;
24
+ }
25
+ });
26
+
27
+ const posts = [];
28
+
29
+ issueData.data.forEach((postMeta) => {
30
+ // Convert issues to posts
31
+ if (!postMeta.subject) {
32
+ return;
33
+ }
34
+
35
+ const revuePostID = postMeta.id;
36
+ let postHTML = JSONToHTML.cleanCsvHTML(postMeta.description);
37
+
38
+ const postItems = _.filter(itemData, {issue_id: revuePostID});
39
+ const sortedPostItems = _.sortBy(postItems, o => o.order);
40
+
41
+ if (postItems) {
42
+ const convertedItems = JSONToHTML.itemsToHtml(sortedPostItems);
43
+ postHTML = `${postHTML}${convertedItems}`;
44
+ }
45
+
46
+ const postDate = JSONToHTML.getPostDate(postMeta);
47
+ const postSlug = slugify(postMeta.subject).slice(0, 190);
48
+
49
+ posts.push({
50
+ comment_id: revuePostID,
51
+ title: postMeta.subject,
52
+ slug: postSlug,
53
+ status: JSONToHTML.getPostStatus(postMeta),
54
+ visibility: 'public',
55
+ created_at: postDate,
56
+ published_at: postDate,
57
+ updated_at: postDate,
58
+ html: postHTML
59
+ });
60
+ });
61
+
62
+ return posts;
63
+ };
64
+
65
+ /**
66
+ *
67
+ * @param {*} revueData
68
+ */
69
+ const buildSubscriberList = (revueData) => {
70
+ const subscribers = [];
71
+
72
+ const subscriberData = papaparse.parse(revueData.subscribers, {
73
+ header: true,
74
+ skipEmptyLines: true
75
+ });
76
+
77
+ subscriberData.data.forEach((subscriber) => {
78
+ subscribers.push({
79
+ email: subscriber.email,
80
+ name: `${subscriber.first_name} ${subscriber.last_name}`.trim(),
81
+ created_at: subscriber.created_at,
82
+ subscribed: true
83
+ });
84
+ });
85
+
86
+ return subscribers;
87
+ };
88
+
89
+ const RevueImporter = {
90
+ type: 'revue',
91
+ preProcess: function (importData) {
92
+ debug('preProcess');
93
+ importData.preProcessedByRevue = true;
94
+
95
+ // TODO: this should really be in doImport
96
+ // No posts to prePprocess, return early
97
+ if (!importData?.revue?.revue?.issues) {
98
+ return importData;
99
+ }
100
+
101
+ // This processed data goes to the data importer
102
+ importData.data = {
103
+ meta: {version: '5.0.0'},
104
+ data: {}
105
+ };
106
+
107
+ importData.data.data.posts = this.importPosts(importData.revue.revue);
108
+
109
+ // No subscribers to import, we're done
110
+ if (!importData?.revue?.revue?.subscribers) {
111
+ return importData;
112
+ }
113
+
114
+ importData.data.data.revue_subscribers = this.importSubscribers(importData.revue.revue);
115
+
116
+ return importData;
117
+ },
118
+ doImport: function (importData) {
119
+ debug('doImport');
120
+
121
+ return importData;
122
+ },
123
+
124
+ importPosts: fetchPostsFromData,
125
+ importSubscribers: buildSubscriberList
126
+ };
127
+
128
+ module.exports = RevueImporter;
@@ -0,0 +1,107 @@
1
+ const SimpleDom = require('simple-dom');
2
+ const serializer = new SimpleDom.HTMLSerializer(SimpleDom.voidMap);
3
+ const imageCard = require('@tryghost/kg-default-cards/lib/cards/image.js');
4
+ const embedCard = require('@tryghost/kg-default-cards/lib/cards/embed.js');
5
+
6
+ // Take the array of items for a specific post and return the converted HTML
7
+ const itemsToHtml = (items) => {
8
+ let itemHTMLChunks = [];
9
+ items.forEach((item) => {
10
+ let type = item.item_type;
11
+
12
+ if (type === 'header') {
13
+ itemHTMLChunks.push(`<h3>${item.title}</h3>`);
14
+ } else if (type === 'text') {
15
+ itemHTMLChunks.push(item.description); // THis is basic text HTML with <p>, <b>, <a>, etc (no media)
16
+ } else if (type === 'image') {
17
+ // We have 2 values to work with here. `image` is smaller and most suitable, and `original_image_url` is the full-res that would need to be resized
18
+ // - item.image (https://s3.amazonaws.com/revue/items/images/019/005/542/web/anita-austvika-C-JUrfmYqcw-unsplash.jpg?1667924147)
19
+ // - item.original_image_url (https://s3.amazonaws.com/revue/items/images/019/005/542/original/anita-austvika-C-JUrfmYqcw-unsplash.jpg?1667924147)
20
+ let cardOpts = {
21
+ env: {dom: new SimpleDom.Document()},
22
+ payload: {
23
+ src: item.image,
24
+ caption: item.description
25
+ }
26
+ };
27
+
28
+ itemHTMLChunks.push(serializer.serialize(imageCard.render(cardOpts)));
29
+ } else if (type === 'link') {
30
+ // This could be a bookmark, or it could be a paragraph of text with a linked header, there's no way to tell
31
+ // The safest option here is to output an image with text under it
32
+ let cardOpts = {
33
+ env: {dom: new SimpleDom.Document()},
34
+ payload: {
35
+ src: item.image,
36
+ caption: item.title,
37
+ href: item.url
38
+ }
39
+ };
40
+ itemHTMLChunks.push(serializer.serialize(imageCard.render(cardOpts)));
41
+
42
+ let linkHTML = `<h4><a href="${item.url}">${item.title}</a></h4>${item.description}`;
43
+ itemHTMLChunks.push(linkHTML);
44
+ } else if (type === 'tweet') {
45
+ // Should this be an oEmbed call? Probably.
46
+ itemHTMLChunks.push(`<figure class="kg-card kg-embed-card">
47
+ <blockquote class="twitter-tweet"><a href="${item.url}"></a></blockquote>
48
+ <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
49
+ </figure>`);
50
+ } else if (type === 'video') {
51
+ const isLongYouTube = /youtube.com/.test(item.url);
52
+ const isShortYouTube = /youtu.be/.test(item.url);
53
+ const isVimeo = /vimeo.com/.test(item.url);
54
+ let videoHTML = '';
55
+ if (isLongYouTube) {
56
+ let videoID = item.url.replace(/https?:\/\/(?:www\.)?youtube\.com\/watch\?v=([a-zA-Z0-9_-]*)/gi, '$1');
57
+ videoHTML = `<iframe width="200" height="113" src="https://www.youtube.com/embed/${videoID}?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>`;
58
+ } else if (isShortYouTube) {
59
+ let videoID = item.url.replace(/https?:\/\/(?:www\.)?youtu\.be\/([a-zA-Z0-9_-]*)/gi, '$1');
60
+ videoHTML = `<iframe width="200" height="113" src="https://www.youtube.com/embed/${videoID}?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>`;
61
+ } else if (isVimeo) {
62
+ let videoID = item.url.replace(/https?:\/\/(?:www\.)?vimeo\.com\/([0-9]+)/gi, '$1');
63
+ videoHTML = `<iframe src="https://player.vimeo.com/video/${videoID}" width="200" height="113" frameborder="0" allow="autoplay; fullscreen; picture-in-picture" allowfullscreen></iframe>`;
64
+ }
65
+ let cardOpts = {
66
+ env: {dom: new SimpleDom.Document()},
67
+ payload: {
68
+ html: videoHTML,
69
+ caption: item.description
70
+ }
71
+ };
72
+
73
+ itemHTMLChunks.push(serializer.serialize(embedCard.render(cardOpts)));
74
+ }
75
+ });
76
+ return itemHTMLChunks.join('\n');
77
+ };
78
+
79
+ const getPostDate = (data) => {
80
+ const isPublished = (data.sent_at) ? true : false; // This is how we determine is a post is published or not
81
+ const postDate = (isPublished) ? new Date(data.sent_at) : new Date();
82
+
83
+ return postDate.toISOString();
84
+ };
85
+
86
+ const getPostStatus = (data) => {
87
+ const isPublished = (data.sent_at) ? true : false; // This is how we determine is a post is published or not
88
+ return (isPublished) ? 'published' : 'draft';
89
+ };
90
+
91
+ const cleanCsvHTML = (data) => {
92
+ // Blockquotes need to have some sort of wrapping elements around all contents
93
+ // Wrap all content in <p> tags. The HTML to Mobiledoc parse can handle duplicate <p> tags.
94
+ data = data.replace(/<blockquote.*?>(.*?)<\/blockquote>/gm, '<blockquote><p>$1</p></blockquote>');
95
+
96
+ // These exports have a lot of <p><br></p> that we don't want
97
+ data = data.replace(/<p><br><\/p>/gm, '');
98
+
99
+ return data;
100
+ };
101
+
102
+ module.exports = {
103
+ itemsToHtml,
104
+ getPostDate,
105
+ getPostStatus,
106
+ cleanCsvHTML
107
+ };
@@ -5,8 +5,7 @@ const {createIrreversibleMigration, createNonTransactionalMigration} = require('
5
5
  /**
6
6
  * Creates a migrations which will add a new table from schema.js to the database
7
7
  * @param {string} name - table name
8
- * @param {Object} tableSpec - copy of table schema definition as defined in schema.js at the moment of writing the migration,
9
- * this parameter MUST be present, otherwise @daniellockyer will hunt you down
8
+ * @param {Object} tableSpec - copy of table schema definition as defined in schema.js at the moment of writing the migration, this parameter MUST be present
10
9
  *
11
10
  * @returns {Object} migration object returning config/up/down properties
12
11
  */
@@ -60,8 +59,7 @@ function dropTables(names) {
60
59
  /**
61
60
  * Creates a migration which will drop an existing table and then re-add a new table based on provided spec
62
61
  * @param {string} name - table name
63
- * @param {Object} tableSpec - copy of table schema definition as defined in schema.js at the moment of writing the migration,
64
- * this parameter MUST be present, otherwise @daniellockyer will hunt you down
62
+ * @param {Object} tableSpec - copy of table schema definition as defined in schema.js at the moment of writing the migration, this parameter MUST be present
65
63
  *
66
64
  * @returns {Object} migration object returning config/up/down properties
67
65
  */
@@ -0,0 +1,288 @@
1
+ const path = require('path');
2
+ const fs = require('fs/promises');
3
+ const JsonImporter = require('./utils/JsonImporter');
4
+ const {getProcessRoot} = require('@tryghost/root-utils');
5
+ const topologicalSort = require('./utils/topological-sort');
6
+ const {faker} = require('@faker-js/faker');
7
+ const {faker: americanFaker} = require('@faker-js/faker/locale/en_US');
8
+ const crypto = require('crypto');
9
+ const {Buffer} = require('node:buffer');
10
+ const DatabaseInfo = require('@tryghost/database-info');
11
+ const errors = require('@tryghost/errors');
12
+ const importers = require('./importers').reduce((acc, val) => {
13
+ acc[val.table] = val;
14
+ return acc;
15
+ }, {});
16
+
17
+ class DataGenerator {
18
+ /**
19
+ *
20
+ * @param {object} options
21
+ * @param {Record<string,number>} [options.quantities] Pass in custom amounts for specific tables
22
+ * @param {number} [options.seed] If you pass the same seed, the same data will be generated if you used the same options too and if the data generation code remained the same.
23
+ */
24
+ constructor({
25
+ knex,
26
+ tables,
27
+ schemaTables,
28
+ clearDatabase = false,
29
+ baseDataPack = '',
30
+ baseUrl,
31
+ logger,
32
+ printDependencies,
33
+ withDefault,
34
+ seed,
35
+ quantities = {},
36
+ useTransaction = true
37
+ }) {
38
+ this.knex = knex;
39
+ this.tableList = tables || [];
40
+ this.schemaTables = schemaTables;
41
+ this.willClearData = clearDatabase;
42
+ this.useBaseDataPack = baseDataPack !== '';
43
+ this.baseDataPack = baseDataPack;
44
+ this.baseUrl = baseUrl;
45
+ this.logger = logger;
46
+ this.withDefault = withDefault;
47
+ this.printDependencies = printDependencies;
48
+ this.seed = seed;
49
+ this.quantities = quantities;
50
+ this.useTransaction = useTransaction;
51
+ }
52
+
53
+ sortTableList() {
54
+ // Add missing dependencies
55
+ for (const table of this.tableList) {
56
+ table.importer = importers[table.name];
57
+
58
+ // eslint-disable-next-line no-unused-vars
59
+ table.dependencies = Object.entries(this.schemaTables[table.name]).reduce((acc, [_col, data]) => {
60
+ if (data.references) {
61
+ const referencedTable = data.references.split('.')[0];
62
+ // The ghost_subscriptions_id property has a foreign key to the subscriptions table, but we don't use that table yet atm, so don't add it as a dependency
63
+ if (!acc.includes(referencedTable) && referencedTable !== 'subscriptions') {
64
+ acc.push(referencedTable);
65
+ }
66
+ }
67
+ return acc;
68
+ }, table.importer.dependencies);
69
+
70
+ for (const dependency of table.dependencies) {
71
+ if (!this.tableList.find(t => t.name === dependency)) {
72
+ this.tableList.push({
73
+ name: dependency,
74
+ importer: importers[dependency]
75
+ });
76
+ }
77
+ }
78
+ }
79
+
80
+ // Order to ensure dependencies are created before dependants
81
+ this.tableList = topologicalSort(this.tableList);
82
+ }
83
+
84
+ /**
85
+ * TODO: This needs to reverse through all dependency chains to clear data from all tables
86
+ * @param {import('knex/types').Knex.Transaction} transaction
87
+ */
88
+ async clearData(transaction) {
89
+ const tables = this.tableList.map(t => t.name).reverse();
90
+
91
+ // TODO: Remove this once we import posts_meta
92
+ tables.unshift('posts_meta');
93
+
94
+ // Clear data from any tables that are being imported
95
+ for (const table of tables) {
96
+ this.logger.debug(`Clearing table ${table}`);
97
+
98
+ if (table === 'roles_users') {
99
+ await transaction(table).del().whereNot('user_id', '1');
100
+ } else if (table === 'users') {
101
+ // Avoid deleting the admin user
102
+ await transaction(table).del().whereNot('id', '1');
103
+ } else {
104
+ await transaction(table).truncate();
105
+ }
106
+ }
107
+ }
108
+
109
+ async importBasePack(transaction) {
110
+ let baseDataPack = this.baseDataPack;
111
+ if (!path.isAbsolute(this.baseDataPack)) {
112
+ baseDataPack = path.join(getProcessRoot(), baseDataPack);
113
+ }
114
+ let baseData = {};
115
+ try {
116
+ baseData = JSON.parse((await fs.readFile(baseDataPack)).toString());
117
+ this.logger.info('Read base data pack');
118
+ } catch (error) {
119
+ this.logger.error('Failed to read data pack: ', error);
120
+ throw error;
121
+ }
122
+
123
+ this.logger.info('Starting base data import');
124
+ const jsonImporter = new JsonImporter(transaction);
125
+
126
+ // Clear settings table
127
+ await transaction('settings').del();
128
+
129
+ // Hard-coded for order
130
+ const tablesToImport = [
131
+ 'newsletters',
132
+ 'posts',
133
+ 'tags',
134
+ 'products',
135
+ 'benefits',
136
+ 'products_benefits',
137
+ 'stripe_products',
138
+ 'stripe_prices',
139
+ 'settings',
140
+ 'custom_theme_settings'
141
+ ];
142
+ for (const table of tablesToImport) {
143
+ this.logger.info(`Importing content for table ${table} from base data pack`);
144
+ await jsonImporter.import({
145
+ name: table,
146
+ data: baseData[table]
147
+ });
148
+ const tableIndex = this.tableList.findIndex(t => t.name === table);
149
+ if (tableIndex !== -1) {
150
+ this.tableList.splice(tableIndex, 1);
151
+ }
152
+ }
153
+
154
+ this.logger.info('Completed base data import');
155
+ }
156
+
157
+ async importData() {
158
+ const start = Date.now();
159
+
160
+ // Add default tables if none are specified
161
+ if (this.tableList.length === 0) {
162
+ this.tableList = Object.keys(importers).map(name => ({name}));
163
+ } else if (this.withDefault) {
164
+ // Add default tables to the end of the list
165
+ const defaultTables = Object.keys(importers).map(name => ({name}));
166
+ for (const table of defaultTables) {
167
+ if (!this.tableList.find(t => t.name === table.name)) {
168
+ this.tableList.push(table);
169
+ }
170
+ }
171
+ }
172
+
173
+ // Error if we have an unknown table
174
+ for (const table of this.tableList) {
175
+ if (importers[table.name] === undefined) {
176
+ throw new errors.IncorrectUsageError({message: `Unknown table: ${table.name}`});
177
+ }
178
+ }
179
+
180
+ this.sortTableList();
181
+
182
+ if (this.printDependencies) {
183
+ this.logger.info('Table dependencies:');
184
+ for (const table of this.tableList) {
185
+ this.logger.info(`\t${table.name}: ${table.dependencies.join(', ')}`);
186
+ }
187
+ process.exit(0);
188
+ }
189
+
190
+ if (this.useTransaction) {
191
+ await this.knex.transaction(async (transaction) => {
192
+ if (!DatabaseInfo.isSQLite(this.knex)) {
193
+ await transaction.raw('SET autocommit=0;');
194
+ }
195
+
196
+ await this.#run(transaction);
197
+ }, {isolationLevel: 'read committed'});
198
+ } else {
199
+ await this.#run(this.knex);
200
+ }
201
+
202
+ this.logger.info(`Completed data import in ${((Date.now() - start) / 1000).toFixed(1)}s`);
203
+ }
204
+
205
+ async #run(transaction) {
206
+ if (!DatabaseInfo.isSQLite(this.knex)) {
207
+ if (process.env.DISABLE_FAST_IMPORT) {
208
+ await transaction.raw('SET FOREIGN_KEY_CHECKS=0;');
209
+ await transaction.raw('SET unique_checks=0;');
210
+ } else {
211
+ await transaction.raw('ALTER INSTANCE DISABLE INNODB REDO_LOG;');
212
+ await transaction.raw('SET FOREIGN_KEY_CHECKS=0;');
213
+ await transaction.raw('SET unique_checks=0;');
214
+ await transaction.raw('SET GLOBAL local_infile=1;');
215
+ }
216
+ }
217
+
218
+ if (this.willClearData) {
219
+ await this.clearData(transaction);
220
+ }
221
+
222
+ if (this.useBaseDataPack) {
223
+ await this.importBasePack(transaction);
224
+ }
225
+
226
+ // Set quantities for tables
227
+ for (const table of this.tableList) {
228
+ if (this.quantities[table.name] !== undefined) {
229
+ table.quantity = this.quantities[table.name];
230
+ }
231
+ }
232
+
233
+ const cryptoRandomBytes = crypto.randomBytes;
234
+
235
+ if (this.seed) {
236
+ // The probality distributions library uses crypto.randomBytes, which we can't seed, so we need to override it
237
+ crypto.randomBytes = (size) => {
238
+ const buffer = Buffer.alloc(size);
239
+ for (let i = 0; i < size; i++) {
240
+ buffer[i] = Math.floor(faker.datatype.number({min: 0, max: 255}));
241
+ }
242
+ return buffer;
243
+ };
244
+ }
245
+
246
+ try {
247
+ for (const table of this.tableList) {
248
+ if (this.seed) {
249
+ // We reset the seed for every table, so the chosen tables don't affect the data and changes in one importer don't affect the others
250
+ faker.seed(this.seed);
251
+ americanFaker.seed(this.seed);
252
+ }
253
+
254
+ // Add all common options to every importer, whether they use them or not
255
+ const tableImporter = new table.importer(this.knex, transaction, {
256
+ baseUrl: this.baseUrl
257
+ });
258
+
259
+ const amount = table.quantity ?? tableImporter.defaultQuantity;
260
+ this.logger.info('Importing content for table', table.name, amount ? `(${amount} records)` : '');
261
+
262
+ await tableImporter.import(table.quantity ?? undefined);
263
+ }
264
+ } finally {
265
+ if (this.seed) {
266
+ // Revert crypto.randomBytes to the original function
267
+ crypto.randomBytes = cryptoRandomBytes;
268
+ }
269
+ }
270
+
271
+ // Finalise all tables - uses new table importer objects to avoid keeping all data in memory
272
+ for (const table of this.tableList) {
273
+ const tableImporter = new table.importer(this.knex, transaction, {
274
+ baseUrl: this.baseUrl
275
+ });
276
+ await tableImporter.finalise();
277
+ }
278
+
279
+ // Re-enable the redo log because it's a persisted global
280
+ // Leaving it disabled can break the database in the event of an unexpected shutdown
281
+ // See https://dev.mysql.com/doc/refman/8.0/en/innodb-redo-log.html#innodb-disable-redo-logging
282
+ if (!DatabaseInfo.isSQLite(this.knex) && !process.env.DISABLE_FAST_IMPORT) {
283
+ await transaction.raw('ALTER INSTANCE ENABLE INNODB REDO_LOG;');
284
+ }
285
+ }
286
+ }
287
+
288
+ module.exports = DataGenerator;