ghost 6.58.0 → 6.59.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.
- package/components/tryghost-adapter-base-scheduling-0.2.2.tgz +0 -0
- package/components/tryghost-adapter-base-sso-0.1.2.tgz +0 -0
- package/components/tryghost-i18n-0.0.0.tgz +0 -0
- package/components/tryghost-kg-default-nodes-2.2.0.tgz +0 -0
- package/components/tryghost-kg-html-to-lexical-1.4.0.tgz +0 -0
- package/components/tryghost-kg-lexical-html-renderer-1.5.0.tgz +0 -0
- package/content/themes/casper/.github/workflows/test.yml +11 -1
- package/content/themes/casper/AGENTS.md +25 -0
- package/content/themes/casper/assets/built/screen.css +1 -1
- package/content/themes/casper/assets/css/screen.css +15 -1
- package/content/themes/casper/gulpfile.js +3 -0
- package/content/themes/casper/package.json +8 -8
- package/content/themes/source/.gitattributes +5 -0
- package/content/themes/source/.github/workflows/test.yml +39 -0
- package/content/themes/source/AGENTS.md +25 -0
- package/content/themes/source/README.md +33 -4
- package/content/themes/source/assets/built/screen.css +1 -1
- package/content/themes/source/assets/css/screen.css +15 -0
- package/content/themes/source/gulpfile.js +6 -3
- package/content/themes/source/package.json +13 -10
- package/content/themes/source/pnpm-workspace.yaml +3 -0
- package/core/boot.js +11 -4
- package/core/built/admin/assets/Combination-BCm9FL4o.js +41 -0
- package/core/built/admin/assets/about-BdSCpjXG.js +1 -0
- package/core/built/admin/assets/account-migration-BpKAqo8k.js +1 -0
- package/core/built/admin/assets/activitypub/{account-migration-BpDeIF3G.js → account-migration-DVnYS1XG.js} +8 -8
- package/core/built/admin/assets/activitypub/activitypub.js +2 -2
- package/core/built/admin/assets/activitypub/{bluesky-sharing-aPMtrS3L.js → bluesky-sharing-DLVeE9ii.js} +31 -31
- package/core/built/admin/assets/activitypub/{content-formatters-BORfuA9G.js → content-formatters-DCsVic-t.js} +2 -2
- package/core/built/admin/assets/activitypub/{dist-ByFmDSNP2.js → dist-ByFmDSNP.js} +1 -1
- package/core/built/admin/assets/activitypub/{domain-CPdiB27_.js → domain-rrvDLfnK.js} +8 -8
- package/core/built/admin/assets/activitypub/{edit-profile-BY2PawIe.js → edit-profile-VT-piVxq.js} +23 -23
- package/core/built/admin/assets/activitypub/{explore-Sp9bgAwq.js → explore-DZg3m48P.js} +14 -14
- package/core/built/admin/assets/activitypub/{feed-BjtF4ohL.js → feed-BJqQvDMI.js} +41 -41
- package/core/built/admin/assets/activitypub/{field-BDOYVTg6.js → field-BezS4-1J.js} +2 -2
- package/core/built/admin/assets/activitypub/inbox-Uf0GVrI_.js +1284 -0
- package/core/built/admin/assets/activitypub/{label-1jhN-qhD.js → label-CZ6if4zK.js} +2 -2
- package/core/built/admin/assets/activitypub/layout-DNuYT4Gu.js +1 -0
- package/core/built/admin/assets/activitypub/moderation-CP6mDVky.js +340 -0
- package/core/built/admin/assets/activitypub/{note-nr_m_5yb.js → note-BlFkye2g.js} +16 -16
- package/core/built/admin/assets/activitypub/{notifications-BdcyivbT.js → notifications-GGTrGEdu.js} +163 -126
- package/core/built/admin/assets/activitypub/{preferences-CNqy1x9C.js → preferences-CjZXrZqr.js} +1550 -1551
- package/core/built/admin/assets/activitypub/{profile-DlY4rhbO.js → profile-CcXYxydm.js} +248 -248
- package/core/built/admin/assets/activitypub/{routes-CEHdEZzS.js → routes-nHCKlZl-.js} +1971 -1747
- package/core/built/admin/assets/activitypub/settings-pDzybcb3.js +315 -0
- package/core/built/admin/assets/activitypub/{site-CtBUCPBz.js → site-BZF0F8LN.js} +101 -101
- package/core/built/admin/assets/activitypub/{step-1-D9jGWyAy.js → step-1-C-Ns1Tfg.js} +3 -3
- package/core/built/admin/assets/activitypub/{step-3-KpUqpGWi.js → step-3-rDMNGmLg.js} +8 -8
- package/core/built/admin/assets/activitypub/{tabs-DvlsxTCI.js → tabs-CDjh3_Jp.js} +198 -198
- package/core/built/admin/assets/activitypub/{topic-filter-CIN1E2jg.js → topic-filter-CmTc8hpN.js} +2 -2
- package/core/built/admin/assets/activitypub/{use-activity-pub-queries-CATFd6YV.js → use-activity-pub-queries-DUDEdSdR.js} +286 -243
- package/core/built/admin/assets/activitypub/{use-reply-chain-data-DJ0vhA8V.js → use-reply-chain-data-TunGtmJl.js} +14 -14
- package/core/built/admin/assets/add-integration-modal-CXRQi1x0.js +1 -0
- package/core/built/admin/assets/add-newsletter-modal-t447KRYz.js +1 -0
- package/core/built/admin/assets/add-recommendation-modal-D882MdnR.js +1 -0
- package/core/built/admin/assets/{analytics-BC2oR8ay.js → analytics-Dj-WlzPf.js} +1 -1
- package/core/built/admin/assets/announcement-bar-modal-CwHKKw-a.js +1 -0
- package/core/built/admin/assets/api-keys-Boy5pLbD.js +1 -0
- package/core/built/admin/assets/audience-Cc40y7zQ.js +1 -0
- package/core/built/admin/assets/automations-DNLK5Udr.js +1 -0
- package/core/built/admin/assets/bluesky-sharing-Cm4aFaOl.js +1 -0
- package/core/built/admin/assets/breadcrumb-CcFr_ltt.js +1 -0
- package/core/built/admin/assets/button-BshWPHvn.js +1 -0
- package/core/built/admin/assets/chart-helpers-BsbzoWhK.js +1 -0
- package/core/built/admin/assets/{checkbox-LmClhqcS.js → checkbox-1G6KfK2q.js} +1 -1
- package/core/built/admin/assets/chunk-KS7C4IRE-DCsL4i4D.js +4 -0
- package/core/built/admin/assets/{chunk.408.1a258af360eb8d905508.js → chunk.301.5673a0caf7c49bb00212.js} +3 -3
- package/core/built/admin/assets/{chunk.524.4c693c3a00ac91df34fa.js → chunk.524.86db0d945468c852374b.js} +4 -4
- package/core/built/admin/assets/{chunk.582.20b600e329e58d12d7c2.js → chunk.582.c2f6216d3c4af303e236.js} +6 -6
- package/core/built/admin/assets/{code-editor-view-DqTOUnbM.js → code-editor-view-BVjtWyst.js} +1 -1
- package/core/built/admin/assets/{code-editor-view-bA0lfxUL.js → code-editor-view-y_zVfmCa.js} +1 -1
- package/core/built/admin/assets/color-picker-XEMPgNJE.js +3 -0
- package/core/built/admin/assets/{color-picker-field-Cv9GOJQZ.js → color-picker-field-BhplXcy5.js} +1 -1
- package/core/built/admin/assets/combobox-CRMJrvcQ.js +1 -0
- package/core/built/admin/assets/command-151T2eRx.js +1 -0
- package/core/built/admin/assets/comments-Bjbl9toF.js +1 -0
- package/core/built/admin/assets/confirmation-context-QmFxSjWy.js +1 -0
- package/core/built/admin/assets/{content-api-modal-BOFWRUkC.js → content-api-modal-CpeABXne.js} +1 -1
- package/core/built/admin/assets/{copy-field-8biQvNMD.js → copy-field-CglgRZyG.js} +1 -1
- package/core/built/admin/assets/custom-field-type-option-DSyJw4T4.js +1 -0
- package/core/built/admin/assets/custom-integration-modal-DWB9bRVp.js +1 -0
- package/core/built/admin/assets/date-range-select-kaKtab5O.js +1 -0
- package/core/built/admin/assets/design-and-theme-modal-86s2AaZ-.js +23 -0
- package/core/built/admin/assets/dirty-confirm-dialog-CTFdXXy7.js +1 -0
- package/core/built/admin/assets/disabled-sources-indicator-BFyCxUOx.js +1 -0
- package/core/built/admin/assets/dist-C1-Oy3Db.js +1 -0
- package/core/built/admin/assets/dist-CJJqYPep.js +1 -0
- package/core/built/admin/assets/dist-CNlMj7ML.js +1 -0
- package/core/built/admin/assets/dist-Kll2twSG.js +1 -0
- package/core/built/admin/assets/domain-BOoMvBG3.js +1 -0
- package/core/built/admin/assets/{dropzone-B21Entqz.js → dropzone-B6KWzsrb.js} +2 -2
- package/core/built/admin/assets/edit-profile-BagrYOrN.js +1 -0
- package/core/built/admin/assets/editor-AaJjqbpk.js +8 -0
- package/core/built/admin/assets/embed-signup-form-modal-B8L95KwR.js +8 -0
- package/core/built/admin/assets/explore-xbykZTlO.js +1 -0
- package/core/built/admin/assets/feed-BAHSipWv.js +1 -0
- package/core/built/admin/assets/{field-BQqLTgHM.js → field-kJYZ2T3C.js} +1 -1
- package/core/built/admin/assets/{filter-sources-FgqoUIL7.js → filter-sources-QeqFGNRB.js} +1 -1
- package/core/built/admin/assets/{filters-D0uIMD8n.js → filters-By5KQeV6.js} +1 -1
- package/core/built/admin/assets/filters-DtYpAkDd.js +1 -0
- package/core/built/admin/assets/first-promoter-modal-8A02oyjA.js +1 -0
- package/core/built/admin/assets/{ghost-ba408063a5922b458b4a8f216cf23251.js → ghost-f110822e67868c9fdf9a6c23754b2559.js} +9 -8
- package/core/built/admin/assets/gift-link-modal-DbYCyuhF.js +1 -0
- package/core/built/admin/assets/global-data-context-gAMDH9u1.js +1 -0
- package/core/built/admin/assets/growth-BSOxJGey.js +3 -0
- package/core/built/admin/assets/growth-BZTjURq5.js +1 -0
- package/core/built/admin/assets/history-modal-CCgWtlZE.js +1 -0
- package/core/built/admin/assets/html-field-BQC7XyLA.js +1 -0
- package/core/built/admin/assets/iframe-buffering-DnOlWTD4.js +1 -0
- package/core/built/admin/assets/{images-3cQgwfTD.js → images-D5UKr2SG.js} +1 -1
- package/core/built/admin/assets/{inbox-Dz_JblyJ.js → inbox-DvN15_YH.js} +45 -39
- package/core/built/admin/assets/index-BJz9Zlsc.js +67 -0
- package/core/built/admin/assets/index-Dg8cdR8E.css +1 -0
- package/core/built/admin/assets/{input-group-DpogNUIt.js → input-group-BPAxETpQ.js} +1 -1
- package/core/built/admin/assets/invite-user-modal-jcUaaNkW.js +1 -0
- package/core/built/admin/assets/{koenig-lexical-2KuqRwZI.js → koenig-lexical-CfXTYeli.js} +1 -1
- package/core/built/admin/assets/koenig-loader-DktFM3Uh.js +1 -0
- package/core/built/admin/assets/{kpi-card-Ck3tT2Wg.js → kpi-card-fUHZlzBX.js} +1 -1
- package/core/built/admin/assets/{kpi-card-DDIxptaS.js → kpi-card-o0urVtNL.js} +1 -1
- package/core/built/admin/assets/kpi-helpers-2FTF4a3-.js +1 -0
- package/core/built/admin/assets/kpi-tabs-B8-_k2dQ.js +1 -0
- package/core/built/admin/assets/{label-DodDsMzn.js → label-CiRS3i_f.js} +1 -1
- package/core/built/admin/assets/label-picker-ao7tuPaK.js +1 -0
- package/core/built/admin/assets/layout-DC6QGDaw.js +1 -0
- package/core/built/admin/assets/member-custom-fields-BW756-EV.js +1 -0
- package/core/built/admin/assets/member-detail-CGGgUTSl.js +1 -0
- package/core/built/admin/assets/members-ZcPthwG0.js +11 -0
- package/core/built/admin/assets/moderation-24bElWs3.js +1 -0
- package/core/built/admin/assets/multi-select-combobox-CZPrgz-Z.js +1 -0
- package/core/built/admin/assets/navigation-modal-BiTP4U_J.js +1 -0
- package/core/built/admin/assets/newsletter-B3Ihwizp.js +1 -0
- package/core/built/admin/assets/newsletter-detail-modal-CYsu4qhl.js +1 -0
- package/core/built/admin/assets/newsletter-emails-CDPR4-SP.js +1 -0
- package/core/built/admin/assets/newsletters-bJiYLJWl.js +1 -0
- package/core/built/admin/assets/note-7f6urVVA.js +1 -0
- package/core/built/admin/assets/notifications-rosQCyXH.js +1 -0
- package/core/built/admin/assets/offers-container-modal-J2j6NpDL.js +1 -0
- package/core/built/admin/assets/onboarding-route-DTjcThKl.js +1 -0
- package/core/built/admin/assets/overview-BxvWzGaf.js +1 -0
- package/core/built/admin/assets/overview-D6JG0hkZ.js +1 -0
- package/core/built/admin/assets/{page-header-VLPJfj_d.js → page-header-l7vXmLIw.js} +1 -1
- package/core/built/admin/assets/pintura-modal-BGHmudVB.js +1 -0
- package/core/built/admin/assets/portal-frame-DVc4VHX_.js +1 -0
- package/core/built/admin/assets/portal-modal-BCOcdiRi.js +1 -0
- package/core/built/admin/assets/{post-analytics-Gv81eN_g.js → post-analytics-CTSZMK6I.js} +1 -1
- package/core/built/admin/assets/post-analytics-header-Dt4RQGq0.js +1 -0
- package/core/built/admin/assets/{post-analytics-provider-O2YjZMhN.js → post-analytics-provider-C4ydiboO.js} +1 -1
- package/core/built/admin/assets/post-share-modal-DjH_a_1L.js +1 -0
- package/core/built/admin/assets/preferences-BLo6VJUS.js +5 -0
- package/core/built/admin/assets/preview-modal-BOgjgsJL.js +1 -0
- package/core/built/admin/assets/profile-DG6iCdRH.js +1 -0
- package/core/built/admin/assets/radio-group-ChHD4EQJ.js +1 -0
- package/core/built/admin/assets/router-provider-Bexg1t-V.js +1 -0
- package/core/built/admin/assets/select-ChxknEcT.js +1 -0
- package/core/built/admin/assets/settings-B0VDAhgV.js +1 -0
- package/core/built/admin/assets/settings-Dwo3CeAD.js +4 -0
- package/core/built/admin/assets/settings-breadcrumbs-sLDNedBW.js +1 -0
- package/core/built/admin/assets/share-modal-BDb2nacg.js +1 -0
- package/core/built/admin/assets/skeleton-D7hwjdry.js +1 -0
- package/core/built/admin/assets/slack-modal-CwNAD69x.js +1 -0
- package/core/built/admin/assets/sort-button-DhqpxkrO.js +1 -0
- package/core/built/admin/assets/source-icon-BPsD5ees.js +1 -0
- package/core/built/admin/assets/stats-WdDJ8c_1.js +1 -0
- package/core/built/admin/assets/stats-view-J3PI2eT_.js +1 -0
- package/core/built/admin/assets/step-1-2q1SjerQ.js +1 -0
- package/core/built/admin/assets/step-2-D5mJB3Uu.js +1 -0
- package/core/built/admin/assets/step-3-BpAuYTGZ.js +2 -0
- package/core/built/admin/assets/{stripe-button-Bh4p6Wud.js → stripe-button-DDoUKN5a.js} +1 -1
- package/core/built/admin/assets/stripe-connect-modal-pMdF3t4S.js +1 -0
- package/core/built/admin/assets/switch-B_1yU3Aw.js +1 -0
- package/core/built/admin/assets/{table-DghJxZMH.js → table-CrqQtkR2.js} +1 -1
- package/core/built/admin/assets/tabs-BhzVdh5p.js +1 -0
- package/core/built/admin/assets/tag-detail-CwJhI4qg.js +2 -0
- package/core/built/admin/assets/tags-CvJ0PgrB.js +1 -0
- package/core/built/admin/assets/testimonials-modal-CV82IAnI.js +1 -0
- package/core/built/admin/assets/tier-detail-modal-pLzCOfeg.js +1 -0
- package/core/built/admin/assets/toggle-group-BW_T4yn6.js +1 -0
- package/core/built/admin/assets/topic-filter-DkXjDejV.js +1 -0
- package/core/built/admin/assets/transistor-modal-TMRvHZ6B.js +1 -0
- package/core/built/admin/assets/unsplash-modal-CV92RdPw.js +1 -0
- package/core/built/admin/assets/{use-analytics-data-IxJcSjc9.js → use-analytics-data-BM_uV9SU.js} +1 -1
- package/core/built/admin/assets/use-check-theme-limit-error-DkBnXMSY.js +1 -0
- package/core/built/admin/assets/use-confirm-unload-SzlkOIpm.js +1 -0
- package/core/built/admin/assets/use-feature-flag-cahOlMva.js +1 -0
- package/core/built/admin/assets/use-filter-params-BX5qf0Cg.js +1 -0
- package/core/built/admin/assets/{use-growth-stats-1NW-8eEZ.js → use-growth-stats-D0LlWBe6.js} +1 -1
- package/core/built/admin/assets/{use-hash-link-navigation-guard-B9j6HIrV.js → use-hash-link-navigation-guard-B_Y3FhYH.js} +1 -1
- package/core/built/admin/assets/use-limiter-D3DHSoAj.js +2 -0
- package/core/built/admin/assets/{use-pintura-config-BjFChXV1.js → use-pintura-config-D63Xu0SG.js} +1 -1
- package/core/built/admin/assets/use-pintura-editor-Z51aFnC8.js +1 -0
- package/core/built/admin/assets/{use-post-referrers-Dp1BnTAK.js → use-post-referrers-Cvymr3gt.js} +1 -1
- package/core/built/admin/assets/use-query-params-BfzuqbcD.js +1 -0
- package/core/built/admin/assets/use-reply-chain-data-Dc18Ujqo.js +1 -0
- package/core/built/admin/assets/use-setting-group-DYRIzqC0.js +1 -0
- package/core/built/admin/assets/use-settings-navigation-aDSLtmEl.js +1 -0
- package/core/built/admin/assets/{use-simple-pagination-DsEGSJhe.js → use-simple-pagination-B2TdNX67.js} +1 -1
- package/core/built/admin/assets/{use-tinybird-query-Ci_DiPkX.js → use-tinybird-query-BvQIVuRc.js} +1 -1
- package/core/built/admin/assets/{use-tinybird-token-CsUwc722.js → use-tinybird-token-COQTPIwL.js} +1 -1
- package/core/built/admin/assets/use-upgrade-route-BZf1g59m.js +1 -0
- package/core/built/admin/assets/{use-url-input-BEZJpVgN.js → use-url-input-PcqZadXa.js} +1 -1
- package/core/built/admin/assets/user-detail-modal-DeO3SAZq.js +1 -0
- package/core/built/admin/assets/{virtual-list-D5ugXyZY.js → virtual-list-D3MfPNOh.js} +1 -1
- package/core/built/admin/assets/web-CDdyG7z1.js +2 -0
- package/core/built/admin/assets/web-CwQ8_QUc.js +1 -0
- package/core/built/admin/assets/zapier-modal-a7t75iNI.js +1 -0
- package/core/built/admin/index.html +15 -12
- package/core/frontend/apps/private-blogging/lib/helpers/input_password.js +2 -1
- package/core/frontend/helpers/body_class.js +2 -1
- package/core/frontend/helpers/cancel_link.js +2 -1
- package/core/frontend/helpers/color_to_rgba.js +2 -1
- package/core/frontend/helpers/content_api_key.js +2 -1
- package/core/frontend/helpers/content_api_url.js +2 -1
- package/core/frontend/helpers/contrast_text_color.js +2 -1
- package/core/frontend/helpers/facebook_url.js +2 -1
- package/core/frontend/helpers/ghost_foot.js +2 -1
- package/core/frontend/helpers/ghost_head.js +2 -1
- package/core/frontend/helpers/has.js +4 -2
- package/core/frontend/helpers/link_class.js +2 -1
- package/core/frontend/helpers/meta_description.js +2 -1
- package/core/frontend/helpers/meta_title.js +2 -1
- package/core/frontend/helpers/navigation.js +113 -22
- package/core/frontend/helpers/page_url.js +2 -1
- package/core/frontend/helpers/post_class.js +2 -1
- package/core/frontend/helpers/reading_time.js +2 -1
- package/core/frontend/helpers/social_accounts.js +2 -1
- package/core/frontend/helpers/social_url.js +2 -1
- package/core/frontend/helpers/total_members.js +2 -1
- package/core/frontend/helpers/total_paid_members.js +2 -1
- package/core/frontend/helpers/tpl/navigation.hbs +1 -1
- package/core/frontend/helpers/twitter_url.js +2 -1
- package/core/frontend/public/cards.manifest.json +1 -1
- package/core/server/api/endpoints/posts.js +7 -4
- package/core/server/api/endpoints/utils/permissions.js +2 -1
- package/core/server/api/endpoints/utils/validators/input/settings.js +83 -1
- package/core/server/data/exporter/table-lists.js +1 -0
- package/core/server/data/importer/handlers/json.js +2 -1
- package/core/server/data/migrations/versions/5.19/2022-09-02-20-52-backfill-new-product-columns.js +2 -1
- package/core/server/data/migrations/versions/5.21/2022-10-26-04-50-member-subscription-created-batch-id.js +4 -2
- package/core/server/data/migrations/versions/5.22/2022-10-31-12-03-backfill-new-product-columns.js +2 -1
- package/core/server/data/migrations/versions/6.58/2026-08-11-21-22-48-rename-email-batches-provider-id.js +1 -1
- package/core/server/data/migrations/versions/6.59/2026-08-18-17-06-46-add-gift-delivery-fields-to-gifts.js +26 -0
- package/core/server/data/migrations/versions/6.59/2026-08-18-17-07-01-add-gift-deliveries.js +20 -0
- package/core/server/data/schema/commands.js +48 -24
- package/core/server/data/schema/schema.js +28 -7
- package/core/server/data/seeders/importers/automation-action-revisions-importer.js +3 -36
- package/core/server/data/seeders/importers/automation-actions-importer.js +5 -41
- package/core/server/data/seeders/importers/automation-run-steps-importer.js +3 -36
- package/core/server/data/seeders/importers/automation-runs-importer.js +7 -42
- package/core/server/data/seeders/importers/automations-importer.js +3 -36
- package/core/server/data/seeders/importers/comment-reports-importer.js +5 -5
- package/core/server/data/seeders/importers/comments-importer.js +5 -5
- package/core/server/data/seeders/importers/email-batches-importer.js +5 -4
- package/core/server/data/seeders/importers/email-recipients-importer.js +12 -20
- package/core/server/data/seeders/importers/emails-importer.js +6 -6
- package/core/server/data/seeders/importers/labels-importer.js +3 -3
- package/core/server/data/seeders/importers/members-click-events-importer.js +5 -5
- package/core/server/data/seeders/importers/members-created-events-importer.js +13 -12
- package/core/server/data/seeders/importers/members-feedback-importer.js +7 -7
- package/core/server/data/seeders/importers/members-importer.js +4 -4
- package/core/server/data/seeders/importers/members-login-events-importer.js +3 -3
- package/core/server/data/seeders/importers/members-products-importer.js +2 -2
- package/core/server/data/seeders/importers/members-status-events-importer.js +4 -3
- package/core/server/data/seeders/importers/members-stripe-customers-importer.js +2 -2
- package/core/server/data/seeders/importers/members-stripe-customers-subscriptions-importer.js +7 -7
- package/core/server/data/seeders/importers/members-subscribe-events-importer.js +3 -3
- package/core/server/data/seeders/importers/members-subscription-created-events-importer.js +3 -3
- package/core/server/data/seeders/importers/offer-redemptions-importer.js +7 -7
- package/core/server/data/seeders/importers/offers-importer.js +3 -3
- package/core/server/data/seeders/importers/posts-importer.js +4 -4
- package/core/server/data/seeders/importers/table-importer.js +2 -35
- package/core/server/data/seeders/importers/tags-importer.js +2 -2
- package/core/server/data/seeders/importers/users-importer.js +2 -2
- package/core/server/data/seeders/importers/web-mentions-importer.js +2 -2
- package/core/server/data/seeders/utils/random.js +7 -0
- package/core/server/ghost-server.js +19 -5
- package/core/server/lib/db-date.js +72 -3
- package/core/server/models/gift-delivery.js +23 -0
- package/core/server/models/gift.js +9 -0
- package/core/server/models/index.js +3 -2
- package/core/server/models/settings.js +43 -4
- package/core/server/services/automations/database-automations-repository.js +38 -31
- package/core/server/services/automations/poll.js +1 -1
- package/core/server/services/content-import/csv/index.js +8 -0
- package/core/server/services/content-import/csv/parse.js +60 -0
- package/core/server/services/content-import/import/importer.js +222 -0
- package/core/server/services/content-import/import/post-data.js +52 -0
- package/core/server/services/content-import/import/reader.js +15 -0
- package/core/server/services/content-import/import/row.js +50 -0
- package/core/server/services/content-import/import/store.js +71 -0
- package/core/server/services/content-import/index.js +67 -0
- package/core/server/services/email-analytics/automation-email-analytics-batch-processor.js +1 -1
- package/core/server/services/email-analytics/index.js +3 -1
- package/core/server/services/email-analytics/jobs/index.js +2 -2
- package/core/server/services/email-service/email-service-wrapper.js +1 -1
- package/core/server/services/email-suppression-list/email-suppression-list.js +4 -2
- package/core/server/services/gifts/CONTEXT.md +27 -3
- package/core/server/services/gifts/README.md +8 -4
- package/core/server/services/gifts/constants.js +2 -1
- package/core/server/services/gifts/email-templates/gift-delivery.hbs +20 -0
- package/core/server/services/gifts/email-templates/gift-delivery.js +39 -0
- package/core/server/services/gifts/email-templates/gift-purchase-confirmation.hbs +2 -2
- package/core/server/services/gifts/email-templates/gift-purchase-confirmation.js +19 -4
- package/core/server/services/gifts/events/send-gift-delivery-event.js +15 -0
- package/core/server/services/gifts/gift-bookshelf-repository.js +23 -3
- package/core/server/services/gifts/gift-checkout-adapter.js +5 -3
- package/core/server/services/gifts/gift-codec.js +8 -0
- package/core/server/services/gifts/gift-delivery-bookshelf-repository.js +107 -0
- package/core/server/services/gifts/gift-delivery-codec.js +12 -0
- package/core/server/services/gifts/gift-delivery-schema.js +15 -0
- package/core/server/services/gifts/gift-delivery-service.js +209 -0
- package/core/server/services/gifts/gift-email-renderer.js +13 -1
- package/core/server/services/gifts/gift-email-service.js +97 -17
- package/core/server/services/gifts/gift-schema.js +10 -6
- package/core/server/services/gifts/gift-service.js +259 -34
- package/core/server/services/gifts/gift.js +59 -5
- package/core/server/services/gifts/index.js +69 -3
- package/core/server/services/lib/mailgun-client.js +5 -2
- package/core/server/services/mail/ghost-mailer.js +9 -1
- package/core/server/services/member-welcome-emails/service.js +6 -1
- package/core/server/services/members/members-api/controllers/router-controller.js +26 -8
- package/core/server/services/stripe/services/webhook/checkout-session-event-service.js +100 -12
- package/core/server/services/stripe/stripe-api.js +3 -2
- package/core/server/services/stripe/webhook-controller.js +6 -3
- package/core/server/services/stripe/webhook-manager.js +2 -0
- package/core/shared/labs.js +1 -0
- package/package.json +9 -8
- package/pnpm-lock.yaml +26 -11
- package/pnpm-workspace.yaml +5 -6
- package/content/themes/source/yarn.lock +0 -6232
- package/core/built/admin/assets/Combination-BDvCdg1t.js +0 -41
- package/core/built/admin/assets/about-B_BvSyLF.js +0 -1
- package/core/built/admin/assets/account-migration-oJUGxnzT.js +0 -1
- package/core/built/admin/assets/activitypub/dist-Dqggkccr.js +0 -215
- package/core/built/admin/assets/activitypub/inbox-z1o2j1Tb.js +0 -1221
- package/core/built/admin/assets/activitypub/layout-BRMezuty.js +0 -1
- package/core/built/admin/assets/activitypub/moderation-CZudJi8N.js +0 -160
- package/core/built/admin/assets/activitypub/settings-CrSV1cux.js +0 -107
- package/core/built/admin/assets/add-integration-modal-BW23PDYs.js +0 -1
- package/core/built/admin/assets/add-newsletter-modal-M0ls8BKO.js +0 -1
- package/core/built/admin/assets/add-recommendation-modal-B0NeBMzl.js +0 -1
- package/core/built/admin/assets/announcement-bar-modal-pXBqjQE_.js +0 -1
- package/core/built/admin/assets/api-keys-Df6uv1dT.js +0 -1
- package/core/built/admin/assets/audience-BY8od8If.js +0 -1
- package/core/built/admin/assets/automations-DCs6Wady.js +0 -1
- package/core/built/admin/assets/bluesky-sharing-D0P42Cws.js +0 -1
- package/core/built/admin/assets/breadcrumb-MTj_cKLb.js +0 -1
- package/core/built/admin/assets/chart-helpers-DcO3k_vA.js +0 -1
- package/core/built/admin/assets/chunk-KS7C4IRE-DG9HTHQ3.js +0 -4
- package/core/built/admin/assets/color-picker-CBlJMv3y.js +0 -3
- package/core/built/admin/assets/combobox-BbPJzjCp.js +0 -1
- package/core/built/admin/assets/command-BrhXIlDr.js +0 -1
- package/core/built/admin/assets/comments-Cu4rD1aJ.js +0 -1
- package/core/built/admin/assets/confirmation-provider-BEdrnHns.js +0 -1
- package/core/built/admin/assets/custom-field-type-option-CNhAgHbJ.js +0 -1
- package/core/built/admin/assets/custom-integration-modal-CrGOI8IB.js +0 -1
- package/core/built/admin/assets/date-range-select-Bsh4gIek.js +0 -1
- package/core/built/admin/assets/design-and-theme-modal-DWZguwWX.js +0 -23
- package/core/built/admin/assets/dirty-confirm-dialog-DmdMpgyN.js +0 -1
- package/core/built/admin/assets/disabled-sources-indicator-BLnmyWgt.js +0 -1
- package/core/built/admin/assets/dist-DMFGvqqU.js +0 -1
- package/core/built/admin/assets/dist-DlCyLrOC.js +0 -1
- package/core/built/admin/assets/dist-j1xxxnY8.js +0 -1
- package/core/built/admin/assets/domain-Dp9TRrFp.js +0 -1
- package/core/built/admin/assets/edit-profile-DG6lpMsr.js +0 -1
- package/core/built/admin/assets/editor-CPQOrhrn.js +0 -8
- package/core/built/admin/assets/embed-signup-form-modal-CgWniDha.js +0 -9
- package/core/built/admin/assets/explore-C3rzONJv.js +0 -1
- package/core/built/admin/assets/feed-DpUwS1cU.js +0 -1
- package/core/built/admin/assets/filters-DZJT29GW.js +0 -1
- package/core/built/admin/assets/first-promoter-modal-DJhQQheG.js +0 -1
- package/core/built/admin/assets/gift-link-modal-sdFLjND9.js +0 -1
- package/core/built/admin/assets/global-data-provider-CixmTX00.js +0 -1
- package/core/built/admin/assets/growth-0YYkBEeS.js +0 -1
- package/core/built/admin/assets/growth-DpjAPeQT.js +0 -3
- package/core/built/admin/assets/history-modal-BWJ4-cJ0.js +0 -1
- package/core/built/admin/assets/html-field-C-oa5DEl.js +0 -1
- package/core/built/admin/assets/iframe-buffering-Ba9sDpi2.js +0 -1
- package/core/built/admin/assets/index-BOJzlYiz.js +0 -67
- package/core/built/admin/assets/index-Bid6LAyc.css +0 -1
- package/core/built/admin/assets/invite-user-modal-DCiQSiuD.js +0 -1
- package/core/built/admin/assets/koenig-editor-base-BApy8Q7C.js +0 -1
- package/core/built/admin/assets/kpi-helpers-ssbuy-hD.js +0 -1
- package/core/built/admin/assets/kpi-tabs-BqoIM6bI.js +0 -1
- package/core/built/admin/assets/label-picker-Cvvbmzb5.js +0 -1
- package/core/built/admin/assets/layout-DkkGyev2.js +0 -1
- package/core/built/admin/assets/member-custom-fields-CvGcpaiW.js +0 -1
- package/core/built/admin/assets/member-detail-CMCMZ47_.js +0 -1
- package/core/built/admin/assets/members-sRl6fNfq.js +0 -11
- package/core/built/admin/assets/moderation-KhKwGqI1.js +0 -1
- package/core/built/admin/assets/multi-select-combobox-nhCff0_K.js +0 -1
- package/core/built/admin/assets/navigation-modal-MDJExWDJ.js +0 -1
- package/core/built/admin/assets/newsletter-BIBHumfV.js +0 -1
- package/core/built/admin/assets/newsletter-detail-modal-CfjBMH3v.js +0 -1
- package/core/built/admin/assets/newsletter-emails-ClDL-7dA.js +0 -1
- package/core/built/admin/assets/newsletters-CBe-IPzK.js +0 -1
- package/core/built/admin/assets/note-HnNUOt4d.js +0 -1
- package/core/built/admin/assets/notifications-Cj5e-258.js +0 -1
- package/core/built/admin/assets/offers-container-modal-BHwHtixC.js +0 -1
- package/core/built/admin/assets/onboarding-route-D_4jp7Nq.js +0 -1
- package/core/built/admin/assets/overview-CezDdg-F.js +0 -1
- package/core/built/admin/assets/overview-D5mM51Lj.js +0 -1
- package/core/built/admin/assets/pintura-modal-BXXJ8Iaa.js +0 -1
- package/core/built/admin/assets/portal-frame-BLCvF8f-.js +0 -1
- package/core/built/admin/assets/portal-modal-DN80tAcy.js +0 -1
- package/core/built/admin/assets/post-analytics-header-_ydSY8qO.js +0 -1
- package/core/built/admin/assets/post-share-modal-CzYak_a5.js +0 -1
- package/core/built/admin/assets/preferences-gneLb6LV.js +0 -5
- package/core/built/admin/assets/preview-modal-Bkq-tgVm.js +0 -1
- package/core/built/admin/assets/profile-CzXmCNTC.js +0 -1
- package/core/built/admin/assets/radio-group-Dsq5ZEbV.js +0 -1
- package/core/built/admin/assets/router-provider-CkB_ArLF.js +0 -1
- package/core/built/admin/assets/select-xuZAuDyS.js +0 -1
- package/core/built/admin/assets/settings-Ct8pabhr.js +0 -1
- package/core/built/admin/assets/settings-KSWWQanQ.js +0 -4
- package/core/built/admin/assets/settings-breadcrumbs-DbPGu-Tu.js +0 -1
- package/core/built/admin/assets/share-modal-CdiUx9WM.js +0 -1
- package/core/built/admin/assets/slack-modal-BP--Z3jE.js +0 -1
- package/core/built/admin/assets/sort-button-CjfKdlsL.js +0 -1
- package/core/built/admin/assets/source-icon-DHj1h6Ts.js +0 -1
- package/core/built/admin/assets/stats-C615kulJ.js +0 -1
- package/core/built/admin/assets/stats-view-BSMRdYiN.js +0 -1
- package/core/built/admin/assets/step-1-pSdGYtIF.js +0 -1
- package/core/built/admin/assets/step-2-T9Uy4eBD.js +0 -1
- package/core/built/admin/assets/step-3-D4uXe_XG.js +0 -2
- package/core/built/admin/assets/stripe-connect-modal-C2vTvepi.js +0 -1
- package/core/built/admin/assets/switch-CE2NuMn-.js +0 -1
- package/core/built/admin/assets/tabs-l9c7FjzI.js +0 -1
- package/core/built/admin/assets/tag-detail-DBw_M2-p.js +0 -2
- package/core/built/admin/assets/tags-DoWsAG6l.js +0 -1
- package/core/built/admin/assets/testimonials-modal-BZKePE2T.js +0 -1
- package/core/built/admin/assets/tier-detail-modal-D65pVWsN.js +0 -1
- package/core/built/admin/assets/toggle-group-uJnl42w3.js +0 -1
- package/core/built/admin/assets/topic-filter-BM7hz0kW.js +0 -1
- package/core/built/admin/assets/transistor-modal-VZOGN3od.js +0 -1
- package/core/built/admin/assets/unsplash-modal-CKGfACxF.js +0 -1
- package/core/built/admin/assets/use-check-theme-limit-error-CGp3CGT5.js +0 -1
- package/core/built/admin/assets/use-feature-flag-CSq2Lwzt.js +0 -1
- package/core/built/admin/assets/use-filter-params-0hcJJuEJ.js +0 -1
- package/core/built/admin/assets/use-limiter-ffwpsZPp.js +0 -2
- package/core/built/admin/assets/use-pintura-editor-Cb41oJyL.js +0 -1
- package/core/built/admin/assets/use-query-params-DHhhu8wi.js +0 -1
- package/core/built/admin/assets/use-reply-chain-data-C0ZUTkfk.js +0 -1
- package/core/built/admin/assets/use-setting-group-Bx8M6FL2.js +0 -1
- package/core/built/admin/assets/use-settings-navigation-BOZcat_V.js +0 -1
- package/core/built/admin/assets/use-upgrade-route-B3_DUiuT.js +0 -1
- package/core/built/admin/assets/user-detail-modal-595z1N5r.js +0 -1
- package/core/built/admin/assets/web-CAta3lRE.js +0 -1
- package/core/built/admin/assets/web-Ds9_wWJK.js +0 -2
- package/core/built/admin/assets/zapier-modal-CcfDZY53.js +0 -1
- package/core/server/data/seeders/utils/database-date.js +0 -28
- package/core/server/services/automations/database-date.js +0 -59
- /package/core/built/admin/assets/{dist-CqO2lWS02.js → dist-CqO2lWS0.js} +0 -0
- /package/core/server/services/{automations → lib}/mailgun-message-id.js +0 -0
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.GiftDelivery = void 0;
|
|
7
|
+
const errors_1 = __importDefault(require("@tryghost/errors"));
|
|
8
|
+
const ghostBookshelf = require('./base');
|
|
9
|
+
const GiftDeliveryModel = ghostBookshelf.Model.extend({
|
|
10
|
+
tableName: 'gift_deliveries',
|
|
11
|
+
hasTimestamps: false,
|
|
12
|
+
defaults: {
|
|
13
|
+
status: 'pending'
|
|
14
|
+
},
|
|
15
|
+
gift() {
|
|
16
|
+
return this.belongsTo('Gift', 'gift_id', 'id');
|
|
17
|
+
}
|
|
18
|
+
}, {
|
|
19
|
+
async destroy() {
|
|
20
|
+
throw new errors_1.default.IncorrectUsageError({ message: 'Cannot destroy GiftDelivery' });
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
exports.GiftDelivery = ghostBookshelf.model('GiftDelivery', GiftDeliveryModel);
|
|
@@ -4,6 +4,11 @@ const ghostBookshelf = require('./base');
|
|
|
4
4
|
const Gift = ghostBookshelf.Model.extend({
|
|
5
5
|
tableName: 'gifts',
|
|
6
6
|
hasTimestamps: false,
|
|
7
|
+
defaults() {
|
|
8
|
+
return {
|
|
9
|
+
checkout_started_at: new Date()
|
|
10
|
+
};
|
|
11
|
+
},
|
|
7
12
|
|
|
8
13
|
buyer() {
|
|
9
14
|
return this.belongsTo('Member', 'buyer_member_id', 'id');
|
|
@@ -15,6 +20,10 @@ const Gift = ghostBookshelf.Model.extend({
|
|
|
15
20
|
|
|
16
21
|
tier() {
|
|
17
22
|
return this.belongsTo('Product', 'tier_id', 'id');
|
|
23
|
+
},
|
|
24
|
+
|
|
25
|
+
delivery() {
|
|
26
|
+
return this.hasOne('GiftDelivery', 'gift_id', 'id');
|
|
18
27
|
}
|
|
19
28
|
}, {
|
|
20
29
|
async destroy() {
|
|
@@ -25,6 +25,7 @@ const {EmailRecipient, EmailRecipients} = require('./email-recipient');
|
|
|
25
25
|
const {EmailSpamComplaintEvent} = require('./email-spam-complaint-event');
|
|
26
26
|
const {Email, Emails} = require('./email');
|
|
27
27
|
const {Gift} = require('./gift');
|
|
28
|
+
const {GiftDelivery} = require('./gift-delivery');
|
|
28
29
|
const {Integration, Integrations} = require('./integration');
|
|
29
30
|
const {Invite, Invites} = require('./invite');
|
|
30
31
|
const {Job} = require('./job');
|
|
@@ -61,7 +62,7 @@ const {Redirect} = require('./redirect');
|
|
|
61
62
|
const {setIsRoles, checkUserPermissionsForRole} = require('./role-utils');
|
|
62
63
|
const {Role, Roles} = require('./role');
|
|
63
64
|
const {Session, Sessions} = require('./session');
|
|
64
|
-
const {Settings
|
|
65
|
+
const {Settings} = require('./settings');
|
|
65
66
|
const {SingleUseToken, SingleUseTokens} = require('./single-use-token');
|
|
66
67
|
const {Snippet, Snippets} = require('./snippet');
|
|
67
68
|
const {StripeCustomerSubscription} = require('./stripe-customer-subscription');
|
|
@@ -111,6 +112,7 @@ exports.EmailSpamComplaintEvent = EmailSpamComplaintEvent;
|
|
|
111
112
|
exports.Email = Email;
|
|
112
113
|
exports.Emails = Emails;
|
|
113
114
|
exports.Gift = Gift;
|
|
115
|
+
exports.GiftDelivery = GiftDelivery;
|
|
114
116
|
exports.Integration = Integration;
|
|
115
117
|
exports.Integrations = Integrations;
|
|
116
118
|
exports.Invite = Invite;
|
|
@@ -166,7 +168,6 @@ exports.Roles = Roles;
|
|
|
166
168
|
exports.Session = Session;
|
|
167
169
|
exports.Sessions = Sessions;
|
|
168
170
|
exports.Settings = Settings;
|
|
169
|
-
exports.getOrGenerateSiteUuid = getOrGenerateSiteUuid;
|
|
170
171
|
exports.SingleUseToken = SingleUseToken;
|
|
171
172
|
exports.SingleUseTokens = SingleUseTokens;
|
|
172
173
|
exports.Snippet = Snippet;
|
|
@@ -18,6 +18,8 @@ const messages = {
|
|
|
18
18
|
const internalContext = {context: {internal: true}};
|
|
19
19
|
let Settings;
|
|
20
20
|
let defaultSettings;
|
|
21
|
+
const imageSettingKeys = ['cover_image', 'logo', 'icon', 'portal_button_icon', 'og_image', 'twitter_image', 'pintura_js_url', 'pintura_css_url'];
|
|
22
|
+
const navigationSettingKeys = ['navigation', 'secondary_navigation'];
|
|
21
23
|
|
|
22
24
|
const doBlock = fn => fn();
|
|
23
25
|
|
|
@@ -103,6 +105,36 @@ function getDefaultSettings() {
|
|
|
103
105
|
return defaultSettings;
|
|
104
106
|
}
|
|
105
107
|
|
|
108
|
+
function transformNavigationIconUrls(value, transformUrl) {
|
|
109
|
+
if (!value) {
|
|
110
|
+
return value;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
let navigationItems;
|
|
114
|
+
try {
|
|
115
|
+
navigationItems = _.isString(value) ? JSON.parse(value) : value;
|
|
116
|
+
} catch (e) {
|
|
117
|
+
return value;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (!_.isArray(navigationItems)) {
|
|
121
|
+
return value;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const transformed = navigationItems.map((item) => {
|
|
125
|
+
if (!_.isObject(item) || _.isFunction(item) || !item.icon) {
|
|
126
|
+
return item;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return {
|
|
130
|
+
...item,
|
|
131
|
+
icon: transformUrl(item.icon)
|
|
132
|
+
};
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
return _.isString(value) ? JSON.stringify(transformed) : transformed;
|
|
136
|
+
}
|
|
137
|
+
|
|
106
138
|
// Each setting is saved as a separate row in the database,
|
|
107
139
|
// but the overlying API treats them as a single key:value mapping
|
|
108
140
|
Settings = ghostBookshelf.Model.extend({
|
|
@@ -179,10 +211,14 @@ Settings = ghostBookshelf.Model.extend({
|
|
|
179
211
|
},
|
|
180
212
|
|
|
181
213
|
formatOnWrite(attrs) {
|
|
182
|
-
if (attrs.value &&
|
|
214
|
+
if (attrs.value && imageSettingKeys.includes(attrs.key)) {
|
|
183
215
|
attrs.value = urlUtils.toTransformReady(attrs.value);
|
|
184
216
|
}
|
|
185
217
|
|
|
218
|
+
if (attrs.value && navigationSettingKeys.includes(attrs.key)) {
|
|
219
|
+
attrs.value = transformNavigationIconUrls(attrs.value, urlUtils.toTransformReady.bind(urlUtils));
|
|
220
|
+
}
|
|
221
|
+
|
|
186
222
|
return attrs;
|
|
187
223
|
},
|
|
188
224
|
|
|
@@ -201,10 +237,14 @@ Settings = ghostBookshelf.Model.extend({
|
|
|
201
237
|
}
|
|
202
238
|
|
|
203
239
|
// transform URLs from __GHOST_URL__ to absolute
|
|
204
|
-
if (
|
|
240
|
+
if (imageSettingKeys.includes(attrs.key)) {
|
|
205
241
|
attrs.value = urlUtils.transformReadyToAbsolute(attrs.value);
|
|
206
242
|
}
|
|
207
243
|
|
|
244
|
+
if (navigationSettingKeys.includes(attrs.key)) {
|
|
245
|
+
attrs.value = transformNavigationIconUrls(attrs.value, urlUtils.transformReadyToAbsolute.bind(urlUtils));
|
|
246
|
+
}
|
|
247
|
+
|
|
208
248
|
return attrs;
|
|
209
249
|
}
|
|
210
250
|
}, {
|
|
@@ -478,6 +518,5 @@ Settings = ghostBookshelf.Model.extend({
|
|
|
478
518
|
});
|
|
479
519
|
|
|
480
520
|
module.exports = {
|
|
481
|
-
Settings: ghostBookshelf.model('Settings', Settings)
|
|
482
|
-
getOrGenerateSiteUuid: getOrGenerateSiteUuid
|
|
521
|
+
Settings: ghostBookshelf.model('Settings', Settings)
|
|
483
522
|
};
|
|
@@ -13,7 +13,7 @@ const dequal_1 = require("dequal");
|
|
|
13
13
|
const lexical_1 = __importDefault(require("../../lib/lexical"));
|
|
14
14
|
const url_utils_1 = __importDefault(require("../../../shared/url-utils"));
|
|
15
15
|
const constants_1 = require("../member-welcome-emails/constants");
|
|
16
|
-
const
|
|
16
|
+
const db_date_1 = require("../../lib/db-date");
|
|
17
17
|
const stale_lock_cutoff_1 = require("./stale-lock-cutoff");
|
|
18
18
|
const HOUR_MS = 60 * 60 * 1000;
|
|
19
19
|
const DEFAULT_WELCOME_EMAIL_AUTOMATIONS = [{
|
|
@@ -90,7 +90,7 @@ function createDatabaseAutomationsRepository({ knex, fakeWaitHoursMultiplier })
|
|
|
90
90
|
const updatedAutomation = await updateAutomation(trx, {
|
|
91
91
|
...automation,
|
|
92
92
|
status: data.status,
|
|
93
|
-
updated_at: (0,
|
|
93
|
+
updated_at: (0, db_date_1.toDatabaseDate)(now)
|
|
94
94
|
});
|
|
95
95
|
await replaceAutomationGraph(trx, updatedAutomation.id, data.actions, data.edges);
|
|
96
96
|
if (updatedAutomation.status === 'inactive') {
|
|
@@ -127,7 +127,7 @@ function createDatabaseAutomationsRepository({ knex, fakeWaitHoursMultiplier })
|
|
|
127
127
|
.update({
|
|
128
128
|
email_sent_count: trx.raw('COALESCE(??, 0) + ?', ['email_sent_count', 1])
|
|
129
129
|
});
|
|
130
|
-
const now = (0,
|
|
130
|
+
const now = (0, db_date_1.toDatabaseDate)(new Date());
|
|
131
131
|
await trx('automated_email_recipients').insert({
|
|
132
132
|
id: (0, bson_objectid_1.default)().toHexString(),
|
|
133
133
|
member_id: options.memberId,
|
|
@@ -281,7 +281,7 @@ async function ensureDefaultAutomations(trx) {
|
|
|
281
281
|
}
|
|
282
282
|
}
|
|
283
283
|
async function ensureAutomation(trx, defaults) {
|
|
284
|
-
const now = (0,
|
|
284
|
+
const now = (0, db_date_1.toDatabaseDate)(new Date());
|
|
285
285
|
const id = (0, bson_objectid_1.default)().toHexString();
|
|
286
286
|
await trx('automations')
|
|
287
287
|
.insert({
|
|
@@ -320,7 +320,7 @@ async function ensureWelcomeEmailAction(trx, automationId) {
|
|
|
320
320
|
if (!email) {
|
|
321
321
|
return;
|
|
322
322
|
}
|
|
323
|
-
const now = (0,
|
|
323
|
+
const now = (0, db_date_1.toDatabaseDate)(new Date());
|
|
324
324
|
const actionId = (0, bson_objectid_1.default)().toHexString();
|
|
325
325
|
await insertActions(trx, [{
|
|
326
326
|
id: actionId,
|
|
@@ -350,7 +350,7 @@ async function trigger(trx, options) {
|
|
|
350
350
|
return;
|
|
351
351
|
}
|
|
352
352
|
const now = new Date();
|
|
353
|
-
const nowString = (0,
|
|
353
|
+
const nowString = (0, db_date_1.toDatabaseDate)(now);
|
|
354
354
|
const readyAt = getReadyAtForAction(firstAction, now, fakeWaitHoursMultiplier);
|
|
355
355
|
const run = {
|
|
356
356
|
id: (0, bson_objectid_1.default)().toHexString(),
|
|
@@ -369,14 +369,14 @@ async function trigger(trx, options) {
|
|
|
369
369
|
});
|
|
370
370
|
}
|
|
371
371
|
async function insertRunStep(trx, { automationRunId, automationActionRevisionId, now, readyAt }) {
|
|
372
|
-
const nowString = (0,
|
|
372
|
+
const nowString = (0, db_date_1.toDatabaseDate)(now);
|
|
373
373
|
await trx('automation_run_steps').insert({
|
|
374
374
|
id: (0, bson_objectid_1.default)().toHexString(),
|
|
375
375
|
created_at: nowString,
|
|
376
376
|
updated_at: nowString,
|
|
377
377
|
automation_run_id: automationRunId,
|
|
378
378
|
automation_action_revision_id: automationActionRevisionId,
|
|
379
|
-
ready_at: (0,
|
|
379
|
+
ready_at: (0, db_date_1.toDatabaseDate)(readyAt)
|
|
380
380
|
});
|
|
381
381
|
}
|
|
382
382
|
async function fetchAndLockSteps(trx, limit) {
|
|
@@ -391,9 +391,9 @@ async function fetchAndLockSteps(trx, limit) {
|
|
|
391
391
|
// 2. Try to lock those rows.
|
|
392
392
|
// 3. Select any rows we successfully locked.
|
|
393
393
|
const now = new Date();
|
|
394
|
-
const nowString = (0,
|
|
394
|
+
const nowString = (0, db_date_1.toDatabaseDate)(now);
|
|
395
395
|
const staleLockCutoff = (0, stale_lock_cutoff_1.getStaleLockCutoff)(now);
|
|
396
|
-
const staleLockCutoffString = (0,
|
|
396
|
+
const staleLockCutoffString = (0, db_date_1.toDatabaseDate)(staleLockCutoff);
|
|
397
397
|
const lockId = node_crypto_1.default.randomUUID();
|
|
398
398
|
// 1. Select up to `limit` candidate rows.
|
|
399
399
|
const candidates = await trx('automation_run_steps')
|
|
@@ -461,17 +461,17 @@ async function findNextPendingReadyAt(trx, staleLockCutoff) {
|
|
|
461
461
|
.where((builder) => {
|
|
462
462
|
builder
|
|
463
463
|
.whereNull('locked_by')
|
|
464
|
-
.orWhere('locked_at', '<', (0,
|
|
464
|
+
.orWhere('locked_at', '<', (0, db_date_1.toDatabaseDate)(staleLockCutoff));
|
|
465
465
|
})
|
|
466
466
|
.orderBy('ready_at')
|
|
467
467
|
.first();
|
|
468
|
-
return row?.next_ready_at ? (0,
|
|
468
|
+
return row?.next_ready_at ? (0, db_date_1.fromDatabaseDate)(row.next_ready_at) : null;
|
|
469
469
|
}
|
|
470
470
|
function buildStepToRun(row) {
|
|
471
471
|
const base = {
|
|
472
472
|
id: row.id,
|
|
473
473
|
step_attempts: row.step_attempts,
|
|
474
|
-
ready_at: (0,
|
|
474
|
+
ready_at: (0, db_date_1.fromDatabaseDate)(row.ready_at),
|
|
475
475
|
locked_by: row.locked_by,
|
|
476
476
|
automation_run_id: row.automation_run_id,
|
|
477
477
|
automation_id: row.automation_id,
|
|
@@ -566,7 +566,7 @@ async function findNextActionRevision(trx, sourceActionId) {
|
|
|
566
566
|
return row ?? null;
|
|
567
567
|
}
|
|
568
568
|
async function markStepTerminal(trx, step, status) {
|
|
569
|
-
const nowString = (0,
|
|
569
|
+
const nowString = (0, db_date_1.toDatabaseDate)(new Date());
|
|
570
570
|
return await updateStep(trx, step, {
|
|
571
571
|
status,
|
|
572
572
|
finished_at: nowString,
|
|
@@ -578,12 +578,12 @@ async function retryStep(trx, step, retryAt) {
|
|
|
578
578
|
await markStepTerminal(trx, step, 'automation disabled');
|
|
579
579
|
return false;
|
|
580
580
|
}
|
|
581
|
-
const nowString = (0,
|
|
581
|
+
const nowString = (0, db_date_1.toDatabaseDate)(new Date());
|
|
582
582
|
return await updateStep(trx, step, {
|
|
583
583
|
status: 'pending',
|
|
584
584
|
started_at: null,
|
|
585
585
|
finished_at: null,
|
|
586
|
-
ready_at: (0,
|
|
586
|
+
ready_at: (0, db_date_1.toDatabaseDate)(retryAt),
|
|
587
587
|
updated_at: nowString
|
|
588
588
|
});
|
|
589
589
|
}
|
|
@@ -608,8 +608,8 @@ function getReadyAtForAction(action, now, fakeWaitHoursMultiplier) {
|
|
|
608
608
|
}
|
|
609
609
|
}
|
|
610
610
|
async function cancelCancelablePendingStepsForAutomation(trx, automationId, now) {
|
|
611
|
-
const nowString = (0,
|
|
612
|
-
const staleLockCutoff = (0,
|
|
611
|
+
const nowString = (0, db_date_1.toDatabaseDate)(now);
|
|
612
|
+
const staleLockCutoff = (0, db_date_1.toDatabaseDate)((0, stale_lock_cutoff_1.getStaleLockCutoff)(now));
|
|
613
613
|
await trx('automation_run_steps')
|
|
614
614
|
.update({
|
|
615
615
|
status: 'automation disabled',
|
|
@@ -697,14 +697,20 @@ async function loadAutomationBySlug(trx, slug) {
|
|
|
697
697
|
return row ?? null;
|
|
698
698
|
}
|
|
699
699
|
async function loadAutomations(trx) {
|
|
700
|
+
const inProgressRuns = trx('automation_run_steps')
|
|
701
|
+
.distinct('automation_run_id')
|
|
702
|
+
.where('status', 'pending')
|
|
703
|
+
.as('in_progress_runs');
|
|
700
704
|
const runStats = trx('automation_runs')
|
|
701
|
-
.select('automation_id')
|
|
702
|
-
.max({ last_run_created_at: 'created_at' })
|
|
705
|
+
.select('automation_runs.automation_id')
|
|
706
|
+
.max({ last_run_created_at: 'automation_runs.created_at' })
|
|
703
707
|
.count({ total_run_count: '*' })
|
|
704
|
-
.
|
|
708
|
+
.count({ in_progress_run_count: 'in_progress_runs.automation_run_id' })
|
|
709
|
+
.leftJoin(inProgressRuns, 'automation_runs.id', 'in_progress_runs.automation_run_id')
|
|
710
|
+
.groupBy('automation_runs.automation_id')
|
|
705
711
|
.as('run_stats');
|
|
706
712
|
return await trx('automations')
|
|
707
|
-
.select('automations.id', 'automations.slug', 'automations.name', 'automations.status', 'automations.created_at', 'automations.updated_at', 'run_stats.last_run_created_at', 'run_stats.total_run_count')
|
|
713
|
+
.select('automations.id', 'automations.slug', 'automations.name', 'automations.status', 'automations.created_at', 'automations.updated_at', 'run_stats.last_run_created_at', 'run_stats.total_run_count', 'run_stats.in_progress_run_count')
|
|
708
714
|
.leftJoin(runStats, 'automations.id', 'run_stats.automation_id')
|
|
709
715
|
.orderBy('automations.name');
|
|
710
716
|
}
|
|
@@ -724,7 +730,7 @@ async function replaceAutomationGraph(trx, automationId, submittedActions, edges
|
|
|
724
730
|
const submittedActionIds = new Set(actions.map(action => action.id));
|
|
725
731
|
const actionIdsWithOwners = await loadActionIdsWithOwners(trx, [...submittedActionIds]);
|
|
726
732
|
const latestRevisionByActionId = new Map((await loadLatestActionRevisions(trx, [...submittedActionIds])).map(revision => [revision.action_id, revision]));
|
|
727
|
-
const now = (0,
|
|
733
|
+
const now = (0, db_date_1.toDatabaseDate)(new Date());
|
|
728
734
|
const actionsToInsert = [];
|
|
729
735
|
const revisionsToInsert = [];
|
|
730
736
|
for (const action of actions) {
|
|
@@ -902,14 +908,14 @@ async function insertActionRevisions(trx, revisions) {
|
|
|
902
908
|
}
|
|
903
909
|
function getNextRevisionCreatedAt(latestCreatedAt, requestedCreatedAt) {
|
|
904
910
|
if (!latestCreatedAt) {
|
|
905
|
-
return (0,
|
|
911
|
+
return (0, db_date_1.toDatabaseDate)(requestedCreatedAt);
|
|
906
912
|
}
|
|
907
|
-
const requestedTime = (0,
|
|
908
|
-
const latestTime = (0,
|
|
913
|
+
const requestedTime = (0, db_date_1.fromDatabaseDate)(requestedCreatedAt).getTime();
|
|
914
|
+
const latestTime = (0, db_date_1.fromDatabaseDate)(latestCreatedAt).getTime();
|
|
909
915
|
if (requestedTime > latestTime) {
|
|
910
|
-
return (0,
|
|
916
|
+
return (0, db_date_1.toDatabaseDate)(requestedCreatedAt);
|
|
911
917
|
}
|
|
912
|
-
return (0,
|
|
918
|
+
return (0, db_date_1.toDatabaseDate)(new Date(latestTime + 1000));
|
|
913
919
|
}
|
|
914
920
|
function buildActionRevision(actionId, action, createdAt) {
|
|
915
921
|
switch (action.type) {
|
|
@@ -989,13 +995,14 @@ function buildAutomationBrowseResult(automation) {
|
|
|
989
995
|
return {
|
|
990
996
|
...buildAutomationSummary(automation),
|
|
991
997
|
stats: {
|
|
992
|
-
last_run_created_at: automation.last_run_created_at ? (0,
|
|
993
|
-
total_run_count: Number(automation.total_run_count ?? 0)
|
|
998
|
+
last_run_created_at: automation.last_run_created_at ? (0, db_date_1.fromDatabaseDate)(automation.last_run_created_at) : null,
|
|
999
|
+
total_run_count: Number(automation.total_run_count ?? 0),
|
|
1000
|
+
in_progress_run_count: Number(automation.in_progress_run_count ?? 0)
|
|
994
1001
|
}
|
|
995
1002
|
};
|
|
996
1003
|
}
|
|
997
1004
|
function serializeDate(date) {
|
|
998
|
-
const normalizedDate = (0,
|
|
1005
|
+
const normalizedDate = (0, db_date_1.fromDatabaseDate)(date);
|
|
999
1006
|
normalizedDate.setMilliseconds(0);
|
|
1000
1007
|
return normalizedDate.toISOString();
|
|
1001
1008
|
}
|
|
@@ -4,7 +4,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.poll = void 0;
|
|
7
|
-
const mailgun_message_id_1 = require("
|
|
7
|
+
const mailgun_message_id_1 = require("../lib/mailgun-message-id");
|
|
8
8
|
const logging_1 = __importDefault(require("@tryghost/logging"));
|
|
9
9
|
const errors_1 = __importDefault(require("@tryghost/errors"));
|
|
10
10
|
const constants_1 = require("../member-welcome-emails/constants");
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.parse = void 0;
|
|
7
|
+
var parse_1 = require("./parse");
|
|
8
|
+
Object.defineProperty(exports, "parse", { enumerable: true, get: function () { return __importDefault(parse_1).default; } });
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.default = parse;
|
|
7
|
+
const papaparse_1 = __importDefault(require("papaparse"));
|
|
8
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
9
|
+
const errors = require('@tryghost/errors');
|
|
10
|
+
// A column named after an Object.prototype member is unsafe as a key.
|
|
11
|
+
function isSafeColumnName(name) {
|
|
12
|
+
return !(name in Object.prototype);
|
|
13
|
+
}
|
|
14
|
+
// Quote errors mean cells are being glued together and rows can no longer be told
|
|
15
|
+
// apart, so the file is refused. Ragged rows (FieldMismatch) and delimiter guesses
|
|
16
|
+
// stay tolerated: an overflow cell is dropped per row, not per file.
|
|
17
|
+
function isFatal(error) {
|
|
18
|
+
return error.type === 'Quotes';
|
|
19
|
+
}
|
|
20
|
+
// headerMapping renames headers to the columns they emit under; unmapped columns
|
|
21
|
+
// carry through, and one mapped to an empty target is dropped.
|
|
22
|
+
async function parse(path, headerMapping) {
|
|
23
|
+
// Buffered rather than streamed: files are bounded by the interim row cap, and
|
|
24
|
+
// papaparse's stream mode drops results.errors, which is what catches a
|
|
25
|
+
// malformed quoted field before it imports as garbage.
|
|
26
|
+
const content = (await fs_extra_1.default.readFile(path, 'utf8')).replace(/^\ufeff/, '');
|
|
27
|
+
const parsed = papaparse_1.default.parse(content, {
|
|
28
|
+
header: true,
|
|
29
|
+
skipEmptyLines: true
|
|
30
|
+
});
|
|
31
|
+
const fatal = parsed.errors.find(isFatal);
|
|
32
|
+
if (fatal) {
|
|
33
|
+
throw new errors.ValidationError({ message: `${fatal.code}: ${fatal.message}` });
|
|
34
|
+
}
|
|
35
|
+
const rows = [];
|
|
36
|
+
for (const parsedRow of parsed.data) {
|
|
37
|
+
const row = {};
|
|
38
|
+
for (const [header, value] of Object.entries(parsedRow)) {
|
|
39
|
+
// non-string values are papaparse's __parsed_extra overflow from ragged rows
|
|
40
|
+
if (typeof value !== 'string') {
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
// hasOwn: a prototype-named header must not match an inherited method on the mapping
|
|
44
|
+
if (headerMapping && Object.hasOwn(headerMapping, header)) {
|
|
45
|
+
if (!headerMapping[header]) {
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
row[headerMapping[header]] = value;
|
|
49
|
+
}
|
|
50
|
+
else if (isSafeColumnName(header)) {
|
|
51
|
+
row[header] = value;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
if (!Object.keys(row).length) {
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
rows.push(row);
|
|
58
|
+
}
|
|
59
|
+
return rows;
|
|
60
|
+
}
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
const moment_timezone_1 = __importDefault(require("moment-timezone"));
|
|
40
|
+
const post_data_1 = __importStar(require("./post-data"));
|
|
41
|
+
const errors = require('@tryghost/errors');
|
|
42
|
+
const tpl = require('@tryghost/tpl');
|
|
43
|
+
const messages = {
|
|
44
|
+
unreadableFile: 'The file could not be parsed as a CSV file.',
|
|
45
|
+
tooManyPosts: 'This file contains more than {max} posts. Imports are temporarily limited to {max} posts at a time — please split the file into smaller files and try again.',
|
|
46
|
+
allWritesFailed: 'Content import failed to write all {count} attempted {postNoun}.',
|
|
47
|
+
urlResolutionFailed: 'Content import could not resolve a URL for {count} created {postNoun}.'
|
|
48
|
+
};
|
|
49
|
+
const MAX_POSTS = 100;
|
|
50
|
+
// Two batch tags for every imported post: a date stamp matching the JSON
|
|
51
|
+
// importer's (api/endpoints/db.js), and a run tag unique to this import, which
|
|
52
|
+
// the report milestones key on.
|
|
53
|
+
function buildImportTagNames(runId, timezone, now) {
|
|
54
|
+
return [
|
|
55
|
+
`#Import ${(0, moment_timezone_1.default)(now).tz(timezone).format('YYYY-MM-DD HH:mm')}`,
|
|
56
|
+
`#Import Run ${runId}`
|
|
57
|
+
];
|
|
58
|
+
}
|
|
59
|
+
class ContentCSVImporter {
|
|
60
|
+
_readRows;
|
|
61
|
+
_posts;
|
|
62
|
+
_getHtmlToLexical;
|
|
63
|
+
_addJob;
|
|
64
|
+
_report;
|
|
65
|
+
_store;
|
|
66
|
+
_urlForPost;
|
|
67
|
+
_newRunId;
|
|
68
|
+
_getTimezone;
|
|
69
|
+
_now;
|
|
70
|
+
constructor({ readRows, posts, getHtmlToLexical, addJob, report, store, urlForPost, newRunId, getTimezone, now = () => new Date() }) {
|
|
71
|
+
this._readRows = readRows;
|
|
72
|
+
this._posts = posts;
|
|
73
|
+
this._getHtmlToLexical = getHtmlToLexical;
|
|
74
|
+
this._addJob = addJob;
|
|
75
|
+
this._report = report;
|
|
76
|
+
this._store = store;
|
|
77
|
+
this._urlForPost = urlForPost;
|
|
78
|
+
this._newRunId = newRunId;
|
|
79
|
+
this._getTimezone = getTimezone;
|
|
80
|
+
this._now = now;
|
|
81
|
+
}
|
|
82
|
+
async importCSV(request) {
|
|
83
|
+
let rows;
|
|
84
|
+
try {
|
|
85
|
+
rows = await this._readRows(request.filePath);
|
|
86
|
+
}
|
|
87
|
+
catch (error) {
|
|
88
|
+
throw new errors.ValidationError({
|
|
89
|
+
message: tpl(messages.unreadableFile),
|
|
90
|
+
err: error
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
// Temporary while import state is held in memory: the durable job
|
|
94
|
+
// system milestone removes the cap.
|
|
95
|
+
if (rows.length > MAX_POSTS) {
|
|
96
|
+
throw new errors.ValidationError({
|
|
97
|
+
message: tpl(messages.tooManyPosts, { max: MAX_POSTS })
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
const runId = this._newRunId();
|
|
101
|
+
const importTagNames = buildImportTagNames(runId, this._getTimezone(), this._now());
|
|
102
|
+
this._store.create(runId, rows.length);
|
|
103
|
+
this._addJob({
|
|
104
|
+
job: () => this.runImportJob(runId, importTagNames, rows),
|
|
105
|
+
offloaded: false,
|
|
106
|
+
name: 'content-import'
|
|
107
|
+
});
|
|
108
|
+
return { importId: runId, total: rows.length };
|
|
109
|
+
}
|
|
110
|
+
// Must resolve in every case: the job manager reads a rejected inline job as a
|
|
111
|
+
// defect in the job itself, and there is no retry behind it.
|
|
112
|
+
async runImportJob(runId, importTagNames, rows) {
|
|
113
|
+
let urlFailureCount = 0;
|
|
114
|
+
let firstUrlFailure;
|
|
115
|
+
try {
|
|
116
|
+
const htmlToLexical = this._getHtmlToLexical();
|
|
117
|
+
let attemptedWrites = 0;
|
|
118
|
+
let successfulWrites = 0;
|
|
119
|
+
let failedWrites = 0;
|
|
120
|
+
let firstWriteFailure;
|
|
121
|
+
for (const [index, row] of rows.entries()) {
|
|
122
|
+
const line = index + 2;
|
|
123
|
+
let data;
|
|
124
|
+
try {
|
|
125
|
+
data = (0, post_data_1.default)(row, htmlToLexical, importTagNames);
|
|
126
|
+
}
|
|
127
|
+
catch (error) {
|
|
128
|
+
if (error instanceof post_data_1.RowSkipped) {
|
|
129
|
+
this._store.record(runId, {
|
|
130
|
+
line,
|
|
131
|
+
title: row.title || null,
|
|
132
|
+
status: 'skipped',
|
|
133
|
+
reason: messageOf(error)
|
|
134
|
+
});
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
// Anything other than an expected source-row refusal is an importer
|
|
138
|
+
// failure. Stop the run before misclassifying it as a lost write.
|
|
139
|
+
throw error;
|
|
140
|
+
}
|
|
141
|
+
attemptedWrites += 1;
|
|
142
|
+
let post;
|
|
143
|
+
try {
|
|
144
|
+
// options.importing preserves the supplied timestamps and keeps the import silent:
|
|
145
|
+
// the webhook, Slack, IndexNow and mention consumers all stand down on it, and a
|
|
146
|
+
// newsletter can only be attached in the API layer (post-scheduling does not check
|
|
147
|
+
// it, one reason status is never 'scheduled'). Pinned by
|
|
148
|
+
// test/e2e-webhooks/posts-importer.test.js. A fresh options object per row: the
|
|
149
|
+
// model layer mutates it.
|
|
150
|
+
post = await this._posts.create(data, {
|
|
151
|
+
importing: true,
|
|
152
|
+
context: { internal: true }
|
|
153
|
+
});
|
|
154
|
+
successfulWrites += 1;
|
|
155
|
+
}
|
|
156
|
+
catch (error) {
|
|
157
|
+
if (failedWrites === 0) {
|
|
158
|
+
firstWriteFailure = error;
|
|
159
|
+
}
|
|
160
|
+
failedWrites += 1;
|
|
161
|
+
this._store.record(runId, {
|
|
162
|
+
line,
|
|
163
|
+
title: row.title,
|
|
164
|
+
status: 'failed',
|
|
165
|
+
reason: messageOf(error)
|
|
166
|
+
});
|
|
167
|
+
continue;
|
|
168
|
+
}
|
|
169
|
+
const outcome = {
|
|
170
|
+
line,
|
|
171
|
+
title: row.title,
|
|
172
|
+
status: 'created',
|
|
173
|
+
postId: post.id
|
|
174
|
+
};
|
|
175
|
+
try {
|
|
176
|
+
outcome.url = this._urlForPost(post);
|
|
177
|
+
}
|
|
178
|
+
catch (error) {
|
|
179
|
+
if (urlFailureCount === 0) {
|
|
180
|
+
firstUrlFailure = error;
|
|
181
|
+
}
|
|
182
|
+
urlFailureCount += 1;
|
|
183
|
+
}
|
|
184
|
+
this._store.record(runId, outcome);
|
|
185
|
+
}
|
|
186
|
+
if (attemptedWrites > 0 && successfulWrites === 0 && failedWrites === attemptedWrites) {
|
|
187
|
+
this._report(new errors.InternalServerError({
|
|
188
|
+
message: tpl(messages.allWritesFailed, {
|
|
189
|
+
count: failedWrites,
|
|
190
|
+
postNoun: failedWrites === 1 ? 'post' : 'posts'
|
|
191
|
+
}),
|
|
192
|
+
err: firstWriteFailure
|
|
193
|
+
}));
|
|
194
|
+
}
|
|
195
|
+
this.reportUrlFailures(urlFailureCount, firstUrlFailure);
|
|
196
|
+
this._store.finish(runId);
|
|
197
|
+
}
|
|
198
|
+
catch (error) {
|
|
199
|
+
this.reportUrlFailures(urlFailureCount, firstUrlFailure);
|
|
200
|
+
this._report(error);
|
|
201
|
+
this._store.fail(runId, messageOf(error));
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
reportUrlFailures(count, firstFailure) {
|
|
205
|
+
if (count > 0) {
|
|
206
|
+
this._report(new errors.InternalServerError({
|
|
207
|
+
message: tpl(messages.urlResolutionFailed, {
|
|
208
|
+
count,
|
|
209
|
+
postNoun: count === 1 ? 'post' : 'posts'
|
|
210
|
+
}),
|
|
211
|
+
err: firstFailure
|
|
212
|
+
}));
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
function messageOf(error) {
|
|
217
|
+
if (error && typeof error === 'object' && 'message' in error && typeof error.message === 'string' && error.message) {
|
|
218
|
+
return error.message;
|
|
219
|
+
}
|
|
220
|
+
return 'Unknown error';
|
|
221
|
+
}
|
|
222
|
+
exports.default = ContentCSVImporter;
|