ghost 6.60.0 → 6.62.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/ghost-storage-base-3.0.0.tgz +0 -0
- package/components/tryghost-adapter-base-cache-0.2.0.tgz +0 -0
- package/components/tryghost-adapter-base-jobs-0.0.0.tgz +0 -0
- package/components/tryghost-adapter-base-redirects-0.0.0.tgz +0 -0
- package/components/tryghost-adapter-base-route-settings-0.0.0.tgz +0 -0
- package/components/tryghost-adapter-base-scheduling-0.2.3.tgz +0 -0
- package/components/tryghost-adapter-base-sso-0.1.3.tgz +0 -0
- package/components/tryghost-admin-api-schema-0.0.0.tgz +0 -0
- package/components/tryghost-checkout-0.0.0.tgz +0 -0
- package/components/tryghost-custom-field-types-0.0.0.tgz +0 -0
- package/components/tryghost-i18n-0.0.0.tgz +0 -0
- package/components/tryghost-kg-card-factory-5.2.4.tgz +0 -0
- package/components/tryghost-kg-clean-basic-html-4.3.4.tgz +0 -0
- package/components/tryghost-kg-converters-1.2.5.tgz +0 -0
- package/components/tryghost-kg-default-cards-10.3.5.tgz +0 -0
- package/components/tryghost-kg-default-nodes-2.2.1.tgz +0 -0
- package/components/tryghost-kg-default-transforms-1.3.4.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/components/tryghost-kg-markdown-html-renderer-7.2.4.tgz +0 -0
- package/components/tryghost-kg-utils-1.1.4.tgz +0 -0
- package/components/tryghost-nql-string-0.0.0.tgz +0 -0
- package/components/tryghost-parse-email-address-0.0.0.tgz +0 -0
- package/content/settings/README.md +1 -1
- package/content/themes/casper/.gitignore +28 -0
- package/content/themes/casper/assets/built/casper.js +1 -1
- package/content/themes/casper/assets/built/screen.css +1 -1
- package/content/themes/casper/assets/css/screen.css +2 -1
- package/content/themes/casper/assets/js/lightbox.js +63 -46
- package/content/themes/casper/package.json +6 -6
- package/content/themes/casper/page.hbs +1 -0
- package/content/themes/casper/post.hbs +1 -0
- package/content/themes/source/.gitignore +28 -0
- package/content/themes/source/assets/built/screen.css +1 -1
- package/content/themes/source/assets/built/source.js +1 -1
- package/content/themes/source/assets/css/screen.css +2 -1
- package/content/themes/source/assets/js/lightbox.js +62 -45
- package/content/themes/source/assets/js/main.js +2 -2
- package/content/themes/source/package.json +4 -4
- package/content/themes/source/partials/feature-image.hbs +1 -0
- package/core/boot.js +62 -21
- package/core/built/admin/assets/Combination-B0l4MKVh.js +41 -0
- package/core/built/admin/assets/InterVariable-DiVDrmQJ.woff2 +0 -0
- package/core/built/admin/assets/InterVariable-Italic-FCBEiFp6.woff2 +0 -0
- package/core/built/admin/assets/{PolarAngleAxis-C4qtHy1B.js → PolarAngleAxis-pkMyqz8g.js} +1 -1
- package/core/built/admin/assets/{RadialBarChart-Bh09Stsj.js → RadialBarChart-JAKoS4KT.js} +1 -1
- package/core/built/admin/assets/{about-BgpmhCuM.js → about-Dyae_UT6.js} +1 -1
- package/core/built/admin/assets/account-migration-CESa0mnX.js +1 -0
- package/core/built/admin/assets/{action-list-lGzZLHc8.js → action-list-C4v0-du8.js} +1 -1
- package/core/built/admin/assets/activitypub/{account-migration-DMHuPnJn.js → account-migration-By69CgCp.js} +16 -16
- package/core/built/admin/assets/activitypub/activitypub.js +9 -10
- package/core/built/admin/assets/activitypub/{avatar-DhTo5D1B.js → avatar-DLPL3Abs.js} +59 -68
- package/core/built/admin/assets/activitypub/{avatar-flipboard-DnVgbEfa.js → avatar-flipboard-C9iDY-QV.js} +2 -2
- package/core/built/admin/assets/activitypub/{bluesky-sharing-BT4zAlW7.js → bluesky-sharing-BJcPMrDd.js} +37 -37
- package/core/built/admin/assets/activitypub/{content-formatters-BeDZ-DIa.js → content-formatters-3rTHg3mp.js} +18 -18
- package/core/built/admin/assets/activitypub/{copy-8sqxUuNd.js → copy-DIAOQoCZ.js} +2 -2
- package/core/built/admin/assets/activitypub/{domain-xQDDu1CS.js → domain-DUR4xSkV.js} +121 -121
- package/core/built/admin/assets/activitypub/{edit-profile-BXdF_r2G.js → edit-profile-BqtfzxCp.js} +40 -40
- package/core/built/admin/assets/activitypub/{explore-CMt7gKlL.js → explore-BxuJd-J4.js} +27 -27
- package/core/built/admin/assets/activitypub/{feed-Bwqdddp_.js → feed-BM1TcksA.js} +51 -51
- package/core/built/admin/assets/activitypub/{field-4co_8FVg.js → field-Dn7HHx2-.js} +3 -3
- package/core/built/admin/assets/activitypub/{hash-DwakMs4X.js → hash-Bm3WxYN4.js} +2 -2
- package/core/built/admin/assets/activitypub/inbox-CCjkuow2.js +1284 -0
- package/core/built/admin/assets/activitypub/{inbox-ckD4wo_r.js → inbox-d8oJRTf4.js} +2 -2
- package/core/built/admin/assets/activitypub/label-1AA_s9Fa.js +16 -0
- package/core/built/admin/assets/activitypub/layout-2-0bw6HN.js +1 -0
- package/core/built/admin/assets/activitypub/{moderation-KCCO7L2J.js → moderation-CnmxEB8w.js} +91 -91
- package/core/built/admin/assets/activitypub/{note-BX_Bz5A0.js → note-ZKc_Bnba.js} +24 -24
- package/core/built/admin/assets/activitypub/{notifications-BQOYGvRv.js → notifications-CB2tJZau.js} +51 -51
- package/core/built/admin/assets/activitypub/{onboarding-CNelD_uF.js → onboarding-BsJ9E5qf.js} +2 -2
- package/core/built/admin/assets/activitypub/{onboarding-mat5Hrl0.js → onboarding-CSUJJIlh.js} +2 -2
- package/core/built/admin/assets/activitypub/{preferences-6h43G9_q.js → preferences-0-JZnUkI.js} +1519 -1519
- package/core/built/admin/assets/activitypub/{profile-BMN9VVZ2.js → profile-C35cFIhM.js} +256 -256
- package/core/built/admin/assets/activitypub/{reply-ZNo04xsO.js → reply-DYK5vVqb.js} +2 -2
- package/core/built/admin/assets/activitypub/{routes-3B9mUQ7i.js → routes-BD4vscyc.js} +796 -790
- package/core/built/admin/assets/activitypub/{separator-D9taVCCa.js → separator-BbQqTm-p.js} +3 -3
- package/core/built/admin/assets/activitypub/settings-BsMROdqh.js +315 -0
- package/core/built/admin/assets/activitypub/{site-DHoMupSB.js → site-O0RL9YCN.js} +2 -2
- package/core/built/admin/assets/activitypub/{step-1-BsGGnBuT.js → step-1-BMSx7c_X.js} +6 -6
- package/core/built/admin/assets/activitypub/{step-2-teosIS0k.js → step-2-DtPQzlTH.js} +6 -6
- package/core/built/admin/assets/activitypub/{step-3-BjD5TokC.js → step-3-CLlOZTyt.js} +11 -11
- package/core/built/admin/assets/activitypub/{tabs-Cvwl1wXU.js → tabs-Dxk-b9M-.js} +306 -306
- package/core/built/admin/assets/activitypub/{topic-filter-C3LZJc2X.js → topic-filter-5yZH6tId.js} +3 -3
- package/core/built/admin/assets/activitypub/{use-activity-pub-queries-Dp9f0gov.js → use-activity-pub-queries-CV50qe03.js} +3 -3
- package/core/built/admin/assets/activitypub/{use-navigate-with-base-path-C4RI0sa9.js → use-navigate-with-base-path-Bmk5h4lW.js} +220 -220
- package/core/built/admin/assets/activitypub/{use-reply-chain-data-C2oNDMUH.js → use-reply-chain-data-Cbvzgjzd.js} +30 -30
- package/core/built/admin/assets/activitypub/{users-CoX6FT_K.js → users-BjcoP_HC.js} +7 -5
- package/core/built/admin/assets/activitypub/{x-Dxm6pV9X.js → x-DbQZOLiI.js} +2 -2
- package/core/built/admin/assets/add-integration-modal-BlF6rs_f.js +1 -0
- package/core/built/admin/assets/add-newsletter-modal-CglVQqah.js +1 -0
- package/core/built/admin/assets/add-recommendation-modal-wz7BsuaG.js +1 -0
- package/core/built/admin/assets/analytics-C4HE1gBg.js +1 -0
- package/core/built/admin/assets/{announcement-bar-modal-BTHiy1ZO.js → announcement-bar-modal-Ci4zz8jO.js} +1 -1
- package/core/built/admin/assets/{api-keys-Boy5pLbD.js → api-keys-Ck-Yteiv.js} +1 -1
- package/core/built/admin/assets/audience-CtbA54Sn.js +1 -0
- package/core/built/admin/assets/{automated-emails-te1D5kq-.js → automated-emails-D5VVMND9.js} +1 -1
- package/core/built/admin/assets/automations-CzKt5fb8.js +1 -0
- package/core/built/admin/assets/bluesky-sharing-BEtJ_gL_.js +1 -0
- package/core/built/admin/assets/{box-By_EgGtm.js → box-CdfQAP_F.js} +1 -1
- package/core/built/admin/assets/{brand-icon-09YqFZjV.js → brand-icon-CrIGOA3Z.js} +1 -1
- package/core/built/admin/assets/{breadcrumb-CcFr_ltt.js → breadcrumb-zUrZrBtW.js} +1 -1
- package/core/built/admin/assets/{button-BshWPHvn.js → button-eNMKQWXr.js} +1 -1
- package/core/built/admin/assets/{card-CiiE7QfM.js → card--VNbfgo3.js} +1 -1
- package/core/built/admin/assets/{chart-BnXyfH11.js → chart-BrhA41Zi.js} +1 -1
- package/core/built/admin/assets/chart-helpers-CfBKt0vT.js +1 -0
- package/core/built/admin/assets/{checkbox-Dwwr_3Py.js → checkbox-CgOn_tKW.js} +1 -1
- package/core/built/admin/assets/{chunk.524.91ecb33e6afc3bd8949b.js → chunk.524.a697dee88db67fdf6021.js} +4 -4
- package/core/built/admin/assets/{chunk.582.512549909741883f960c.js → chunk.582.5ed5d124cfca9c259b9c.js} +6 -6
- package/core/built/admin/assets/{chunk.16.f76a6314082d813d67e0.js → chunk.598.7e056fabb47ce7dbd73f.js} +14 -14
- package/core/built/admin/assets/{code-editor-view-BwIdPy_k.js → code-editor-view-BYNoAoNV.js} +1 -1
- package/core/built/admin/assets/{code-editor-view-CtkF82Fv.js → code-editor-view-K2wI-I5f.js} +1 -1
- package/core/built/admin/assets/color-picker-Ddw80xX6.js +3 -0
- package/core/built/admin/assets/color-picker-field-D9nUhvA7.js +1 -0
- package/core/built/admin/assets/combobox-w9j8PPQT.js +1 -0
- package/core/built/admin/assets/command-BfpHORBv.js +1 -0
- package/core/built/admin/assets/comments-BLmCmyCs.js +1 -0
- package/core/built/admin/assets/confirmation-context-CBM8G0Vj.js +1 -0
- package/core/built/admin/assets/{container-LiZf3XdY.js → container-BuQG1wuP.js} +1 -1
- package/core/built/admin/assets/{content-api-modal-BtpNI92-.js → content-api-modal-TXRz3U7S.js} +1 -1
- package/core/built/admin/assets/context-menu-_QMdd3kp.js +1 -0
- package/core/built/admin/assets/{copy-field-CglgRZyG.js → copy-field-6N01S07E.js} +1 -1
- package/core/built/admin/assets/create-ghost-browse-value-source-qIBymvvf.js +1 -0
- package/core/built/admin/assets/custom-field-type-option-BddFlJFa.js +1 -0
- package/core/built/admin/assets/custom-integration-modal-DmNquxUV.js +1 -0
- package/core/built/admin/assets/{data-list-CupF7bjM.js → data-list-CA2jYGPq.js} +1 -1
- package/core/built/admin/assets/{date-range-select-JPwM0yUj.js → date-range-select-uvz_DtPh.js} +1 -1
- package/core/built/admin/assets/design-and-theme-modal-BSmo12Op.js +2 -0
- package/core/built/admin/assets/{detail-page-D8lx2SdP.js → detail-page-Dnv-CdR1.js} +1 -1
- package/core/built/admin/assets/dirty-confirm-dialog-BZ1iytEd.js +1 -0
- package/core/built/admin/assets/{disabled-sources-indicator-BTJ2ClQu.js → disabled-sources-indicator-DMRrxsiJ.js} +1 -1
- package/core/built/admin/assets/{dist-DzcfoDJ3.js → dist-8YJUlf3B.js} +1 -1
- package/core/built/admin/assets/{dist-Cb5RSHSg.js → dist-B3keLvjj.js} +1 -1
- package/core/built/admin/assets/dist-Dcsslyo72.js +1 -0
- package/core/built/admin/assets/{dist-BT_Z-eCn.js → dist-Dgt2cr6a.js} +1 -1
- package/core/built/admin/assets/domain-BNYrt0aD.js +1 -0
- package/core/built/admin/assets/dropzone-D7nFdAe5.js +5 -0
- package/core/built/admin/assets/edit-profile-C5Asm4LA.js +1 -0
- package/core/built/admin/assets/editor-REokrzci.js +8 -0
- package/core/built/admin/assets/{embed-signup-form-modal-BFTPf04i.js → embed-signup-form-modal-Ds6mPEi5.js} +1 -1
- package/core/built/admin/assets/{empty-indicator-WB1WgT9h.js → empty-indicator-D9QdpuNX.js} +1 -1
- package/core/built/admin/assets/en-B1jX3WMs.js +1 -0
- package/core/built/admin/assets/explore-UY10Egsp.js +1 -0
- package/core/built/admin/assets/feature-image-placeholder-D1iF_8bc.js +1 -0
- package/core/built/admin/assets/feed-81C8mJWR.js +1 -0
- package/core/built/admin/assets/{field-LmNk7wZh.js → field-Dihp5p18.js} +1 -1
- package/core/built/admin/assets/filter-bar-Da1qxybu.js +1 -0
- package/core/built/admin/assets/filter-sources-BO9xUPj7.js +1 -0
- package/core/built/admin/assets/filters-CRUWecfY.js +1 -0
- package/core/built/admin/assets/filters-DirqNXjH.js +1 -0
- package/core/built/admin/assets/first-promoter-modal-CT6MxYZb.js +1 -0
- package/core/built/admin/assets/{ghost-c8807202a07c20030acb719ee0114815.css → ghost-8eabfc1ece81b03cf7b90780d31487e8.css} +1 -1
- package/core/built/admin/assets/{ghost-403cb39badad3df411fc0ba27d220047.js → ghost-c2848508292937415f20f5a830eea59e.js} +31 -28
- package/core/built/admin/assets/{ghost-dark-fbf1e384aaef3ae315e540f0eb7373a7.css → ghost-dark-a7bebe2c561f55369dcf29f4c820f7ff.css} +1 -1
- package/core/built/admin/assets/gift-link-modal-CQVAye17.js +1 -0
- package/core/built/admin/assets/{grid-CUciBfjf.js → grid-Dj29PY05.js} +1 -1
- package/core/built/admin/assets/growth-BWIu-6xj.js +3 -0
- package/core/built/admin/assets/growth-DU29oxeA.js +1 -0
- package/core/built/admin/assets/{heading-CRZZ2FUe.js → heading-Dh5SFVjL.js} +1 -1
- package/core/built/admin/assets/history-modal-CFd1Hvx6.js +1 -0
- package/core/built/admin/assets/html-field-CJBCLTvv.js +1 -0
- package/core/built/admin/assets/{images-C0XvUYMb.js → images-scfkWZiK.js} +1 -1
- package/core/built/admin/assets/{inbox-DZXDUt4s.js → inbox-Mcp4DXZN.js} +14 -14
- package/core/built/admin/assets/index-6MkPdCtr.js +4 -0
- package/core/built/admin/assets/index-Bn7QhcZu.css +2 -0
- package/core/built/admin/assets/index.es-CNnuNH0d.js +1 -0
- package/core/built/admin/assets/{inline-Cw-gigDW.js → inline-BWSs_VzR.js} +1 -1
- package/core/built/admin/assets/{input-group-BPAxETpQ.js → input-group-CMhe2DvY.js} +1 -1
- package/core/built/admin/assets/{input-surface-BdOe4KzO.js → input-surface-BsrIZeSF.js} +1 -1
- package/core/built/admin/assets/{integration-header-B4DyXV06.js → integration-header-Bm6IDb1A.js} +1 -1
- package/core/built/admin/assets/invite-user-modal-DfheMXs0.js +1 -0
- package/core/built/admin/assets/koenig-lexical/koenig-lexical.js +14 -14
- package/core/built/admin/assets/koenig-lexical/koenig-lexical.umd.js +3 -3
- package/core/built/admin/assets/koenig-lexical/style.css +1 -1
- package/core/built/admin/assets/{koenig-lexical-60O_8aiO.js → koenig-lexical-DBSqAuiI.js} +3 -3
- package/core/built/admin/assets/koenig-loader-aFQNlJlD.js +2 -0
- package/core/built/admin/assets/kpi-card-DBRMfGOW.js +1 -0
- package/core/built/admin/assets/{kpi-card-fUHZlzBX.js → kpi-card-DFafD1qq.js} +1 -1
- package/core/built/admin/assets/kpi-helpers-Cv8i8hns.js +1 -0
- package/core/built/admin/assets/kpi-tabs-BJItvLYm.js +1 -0
- package/core/built/admin/assets/{label-VIG969IC.js → label-BnSCvffu.js} +1 -1
- package/core/built/admin/assets/label-picker-KVoo91sh.js +1 -0
- package/core/built/admin/assets/layout-Bjv2Ll-5.js +1 -0
- package/core/built/admin/assets/{link-helpers-Dtq9fxQg.js → link-helpers-MVDdnFCY.js} +1 -1
- package/core/built/admin/assets/{list-page-CdsnQR9N.js → list-page-BucXJ0hi.js} +1 -1
- package/core/built/admin/assets/member-custom-fields-DDQV6QeG.js +1 -0
- package/core/built/admin/assets/member-detail-CdJF6Agw.js +1 -0
- package/core/built/admin/assets/members-DjQbq9Z2.js +4 -0
- package/core/built/admin/assets/{modal-page-BMTzFHVO.js → modal-page-xCivTMvI.js} +1 -1
- package/core/built/admin/assets/moderation-AgCIEso4.js +1 -0
- package/core/built/admin/assets/{multi-select-combobox-CGohnsxJ.js → multi-select-combobox-BcITkUVr.js} +1 -1
- package/core/built/admin/assets/navigation-modal-BkT7b1M2.js +1 -0
- package/core/built/admin/assets/newsletter-BMMAuvgq.js +1 -0
- package/core/built/admin/assets/newsletter-detail-modal-0SCJ7Zpm.js +1 -0
- package/core/built/admin/assets/{newsletter-emails-D5ql1rud.js → newsletter-emails-DKzwafuh.js} +1 -1
- package/core/built/admin/assets/newsletters-BRBb_uQC.js +1 -0
- package/core/built/admin/assets/note-DyGHtS9a.js +1 -0
- package/core/built/admin/assets/notifications-ZgWniKna.js +1 -0
- package/core/built/admin/assets/nql-BLpCn7qX.js +21 -0
- package/core/built/admin/assets/offers-container-modal-B-E8TIWr.js +1 -0
- package/core/built/admin/assets/{onboarding-B4YhlZ0i.js → onboarding-CzIsre-d.js} +1 -1
- package/core/built/admin/assets/onboarding-qg8Akovm.js +1 -0
- package/core/built/admin/assets/{onboarding-route-Cu_ROWPn.js → onboarding-route-CaavZulg.js} +1 -1
- package/core/built/admin/assets/overview-BW8GLeYi.js +1 -0
- package/core/built/admin/assets/overview-BkXZNzaZ.js +1 -0
- package/core/built/admin/assets/{page-header-Cfds8pCg.js → page-header-De0VzKBi.js} +1 -1
- package/core/built/admin/assets/pagemenu-B5KKCpbA.js +1 -0
- package/core/built/admin/assets/pages-jgaFm69d.js +1 -0
- package/core/built/admin/assets/pages-route-CIUAQxtY.js +1 -0
- package/core/built/admin/assets/papaparse.min-cQwnxGCG.js +10 -0
- package/core/built/admin/assets/{pintura-modal-TDTrJ89x.js → pintura-modal-BZ2J9w3n.js} +1 -1
- package/core/built/admin/assets/portal-frame-B6Hr9wHc.js +1 -0
- package/core/built/admin/assets/portal-modal-D4ceei3t.js +1 -0
- package/core/built/admin/assets/post-analytics-header-BYCsT0GP.js +1 -0
- package/core/built/admin/assets/post-analytics-ot7f6pih.js +1 -0
- package/core/built/admin/assets/{post-analytics-provider-Cu3jNeFh.js → post-analytics-provider-Bo1gmYaP.js} +1 -1
- package/core/built/admin/assets/{post-share-modal-P1_M6o-H.js → post-share-modal-C-PaYZ_e.js} +1 -1
- package/core/built/admin/assets/posts-DuGazgTb.js +1 -0
- package/core/built/admin/assets/posts-list-screen-CBGGgjjj.js +2 -0
- package/core/built/admin/assets/posts-route-D6xmS7Vf.js +1 -0
- package/core/built/admin/assets/preferences-C5YJLp74.js +5 -0
- package/core/built/admin/assets/{preview-chrome-BOVO6_PE.js → preview-chrome-BljUBlOk.js} +1 -1
- package/core/built/admin/assets/{preview-modal-MlTjP8UU.js → preview-modal-BfeFqi5y.js} +1 -1
- package/core/built/admin/assets/profile-B8mx2yAu.js +1 -0
- package/core/built/admin/assets/{radio-group-CjtmsCPl.js → radio-group-DczlLKOn.js} +1 -1
- package/core/built/admin/assets/{router-provider-CJC58zTy.js → router-provider-B0gZyiGJ.js} +1 -1
- package/core/built/admin/assets/{schemas-CRsC53ls.js → schemas-DppqmpeJ.js} +2 -2
- package/core/built/admin/assets/select-cb0t_TAJ.js +1 -0
- package/core/built/admin/assets/settings-DZqxR0Da.js +1 -0
- package/core/built/admin/assets/settings-DvfTNdHQ.js +4 -0
- package/core/built/admin/assets/{settings-breadcrumbs-sLDNedBW.js → settings-breadcrumbs-DLzbRRSt.js} +1 -1
- package/core/built/admin/assets/{shade-app-F7WxOyfk-nufqw1hd.js → shade-app-CcS3f8MZ-vwURazk8.js} +2 -2
- package/core/built/admin/assets/share-modal-D2-Bz1_I.js +1 -0
- package/core/built/admin/assets/{skeleton-D7hwjdry.js → skeleton-Ce9GgUpf.js} +1 -1
- package/core/built/admin/assets/slack-modal-DYDTUria.js +1 -0
- package/core/built/admin/assets/sort-button-VVeQjjbu.js +1 -0
- package/core/built/admin/assets/{source-icon-BPsD5ees.js → source-icon-Ck5_5Kgq.js} +1 -1
- package/core/built/admin/assets/{stack-CIfOAAVf.js → stack-B2eszIiq.js} +1 -1
- package/core/built/admin/assets/stats-Rjmk5owg.js +1 -0
- package/core/built/admin/assets/stats-view-BGGmkmgv.js +1 -0
- package/core/built/admin/assets/{step-1-CMta6YFO.js → step-1-CsaBjeN4.js} +1 -1
- package/core/built/admin/assets/{step-2-BG04nh5q.js → step-2-D2vnxOOM.js} +1 -1
- package/core/built/admin/assets/{step-3-ZnMaVIPj.js → step-3-wBoLdGEb.js} +2 -2
- package/core/built/admin/assets/{stripe-button-DDoUKN5a.js → stripe-button-CDgLz0S0.js} +1 -1
- package/core/built/admin/assets/stripe-connect-modal-CSjMJetP.js +1 -0
- package/core/built/admin/assets/{switch-C9djUIMO.js → switch-CI4gLWqb.js} +1 -1
- package/core/built/admin/assets/{table-CrqQtkR2.js → table-Do6iQ83Q.js} +1 -1
- package/core/built/admin/assets/{tabs-CGisSbWq.js → tabs-D2yWLMp_.js} +1 -1
- package/core/built/admin/assets/tag-detail-BhXlOsCa.js +2 -0
- package/core/built/admin/assets/tags-ldukRApe.js +1 -0
- package/core/built/admin/assets/testimonials-modal-CtnZBJKl.js +1 -0
- package/core/built/admin/assets/{text-DU9Hv33_.js → text-BQDSDsKs.js} +1 -1
- package/core/built/admin/assets/{textarea-d9qEkMOP.js → textarea-DJ1Q5V39.js} +1 -1
- package/core/built/admin/assets/tier-detail-modal-BOs8e_G8.js +1 -0
- package/core/built/admin/assets/{toggle-group-CtKZURJd.js → toggle-group-ByUJsxwD.js} +1 -1
- package/core/built/admin/assets/{topic-filter-D8JT8Tq1.js → topic-filter-BgC3g5_v.js} +1 -1
- package/core/built/admin/assets/{transistor-modal-6PUf0idx.js → transistor-modal-Drr0SNfo.js} +1 -1
- package/core/built/admin/assets/trend-badge-6ye93YAW.js +1 -0
- package/core/built/admin/assets/{unsplash-modal-BPuDBPja.js → unsplash-modal-p6AoQoWp.js} +1 -1
- package/core/built/admin/assets/{use-analytics-data--opuzwcz.js → use-analytics-data-CWCMAESo.js} +1 -1
- package/core/built/admin/assets/use-check-theme-limit-error-B8bjF-gO.css +1 -0
- package/core/built/admin/assets/use-check-theme-limit-error-Cw3WQHy8.js +2 -0
- package/core/built/admin/assets/use-filter-params-BIni9taJ.js +1 -0
- package/core/built/admin/assets/use-growth-stats-DCVG3s9w.js +1 -0
- package/core/built/admin/assets/{use-limiter-TDSNiHPB.js → use-limiter-D2WRRx0H.js} +1 -1
- package/core/built/admin/assets/{use-navigate-with-base-path-CK989MlC.js → use-navigate-with-base-path-BHPA228f.js} +1 -1
- package/core/built/admin/assets/{use-pintura-config-CnCGrDFk.js → use-pintura-config-h-J0Lvta.js} +1 -1
- package/core/built/admin/assets/{use-pintura-editor-ntphvtUd.js → use-pintura-editor-BfN1UwzH.js} +1 -1
- package/core/built/admin/assets/use-post-referrers-Czg47m8s.js +1 -0
- package/core/built/admin/assets/use-reply-chain-data-ns0caK8k.js +1 -0
- package/core/built/admin/assets/{use-router-history-entry-BwfQS2mq.js → use-router-history-entry-uldn7zJO.js} +1 -1
- package/core/built/admin/assets/{use-setting-group-DQxV42-O.js → use-setting-group-DpcuCUDg.js} +1 -1
- package/core/built/admin/assets/use-settings-navigation-CZjGrhsp.js +1 -0
- package/core/built/admin/assets/{use-simple-pagination-B2TdNX67.js → use-simple-pagination-DzJWobPR.js} +1 -1
- package/core/built/admin/assets/{use-staff-users-QrR9voeC.js → use-staff-users-Csipb-O0.js} +1 -1
- package/core/built/admin/assets/use-tinybird-query-CSnGXzZh.js +1 -0
- package/core/built/admin/assets/use-tinybird-token-DTOKRR7e.js +1 -0
- package/core/built/admin/assets/{use-unsaved-changes-guard-DpYJcj1d.js → use-unsaved-changes-guard-CBzs-KPi.js} +1 -1
- package/core/built/admin/assets/{use-url-input-WnIqckzS.js → use-url-input-DFr8lCbS.js} +1 -1
- package/core/built/admin/assets/user-detail-modal-B_iUClI6.js +1 -0
- package/core/built/admin/assets/users-Cg-OeGzC.js +1 -0
- package/core/built/admin/assets/{virtual-list-D3MfPNOh.js → virtual-list-BW-padMe.js} +1 -1
- package/core/built/admin/assets/web-C1v33ehA.js +2 -0
- package/core/built/admin/assets/web-C4BKzn2T.js +1 -0
- package/core/built/admin/assets/{zapier-modal-BO6PS_Vd.js → zapier-modal-BBFfI6Ml.js} +1 -1
- package/core/built/admin/index.html +24 -30
- package/core/frontend/apps/private-blogging/lib/views/private.hbs +44 -43
- package/core/frontend/helpers/cancel_link.js +2 -2
- package/core/frontend/helpers/pagination.js +2 -2
- package/core/frontend/helpers/social_accounts.js +2 -2
- package/core/frontend/public/ghost.css +1 -1
- package/core/frontend/public/ghost.min.css +1 -1
- package/core/frontend/services/rendering/renderer.js +15 -0
- package/core/frontend/services/sitemap/user-map-generator.js +9 -2
- package/core/server/adapters/storage/LocalStorageBase.js +8 -5
- package/core/server/api/endpoints/db.js +19 -5
- package/core/server/api/endpoints/index.js +6 -2
- package/core/server/api/endpoints/mail.js +1 -1
- package/core/server/api/endpoints/member-metafields.js +89 -0
- package/core/server/api/endpoints/members.js +4 -4
- package/core/server/api/endpoints/posts.js +4 -3
- package/core/server/api/endpoints/tiers-checkout-config.js +59 -0
- package/core/server/api/endpoints/utils/serializers/input/members.js +4 -7
- package/core/server/api/endpoints/utils/serializers/output/config.js +1 -0
- package/core/server/api/endpoints/utils/serializers/output/index.js +6 -2
- package/core/server/api/endpoints/utils/serializers/output/{member-custom-fields.js → member-metafields.js} +2 -4
- package/core/server/api/endpoints/utils/serializers/output/members.js +2 -4
- package/core/server/api/endpoints/utils/serializers/output/tiers-checkout-config.js +12 -0
- package/core/server/api/endpoints/utils/validators/input/invitations.js +0 -5
- package/core/server/api/endpoints/utils/validators/input/pages.js +1 -1
- package/core/server/api/endpoints/utils/validators/input/posts.js +1 -1
- package/core/server/data/exporter/table-lists.js +3 -0
- package/core/server/data/importer/content-files.js +57 -0
- package/core/server/data/importer/handlers/image.js +2 -2
- package/core/server/data/importer/import-archive.js +131 -0
- package/core/server/data/importer/import-manager.js +18 -180
- package/core/server/data/importer/importers/content-file-importer.js +66 -4
- package/core/server/data/importer/importers/data/data-importer.js +3 -3
- package/core/server/data/migrations/utils/migrations.js +1 -1
- package/core/server/data/migrations/versions/6.61/2026-08-19-14-30-20-add-written-by-to-members-custom-field-values.js +42 -0
- package/core/server/data/migrations/versions/6.61/2026-08-19-14-38-53-add-members-custom-field-bindings-table.js +26 -0
- package/core/server/data/migrations/versions/6.61/2026-08-19-14-48-06-add-tier-checkout-field-tables.js +35 -0
- package/core/server/data/schema/schema.js +90 -0
- package/core/server/data/seeders/importers/automation-action-revisions-importer.js +3 -3
- package/core/server/data/seeders/importers/automation-actions-importer.js +3 -3
- package/core/server/data/seeders/importers/automation-run-steps-importer.js +3 -3
- package/core/server/data/seeders/importers/automation-runs-importer.js +5 -5
- package/core/server/data/seeders/importers/automations-importer.js +3 -3
- package/core/server/data/seeders/importers/comment-reports-importer.js +1 -1
- package/core/server/data/seeders/importers/comments-importer.js +1 -1
- package/core/server/data/seeders/importers/email-batches-importer.js +1 -1
- package/core/server/data/seeders/importers/email-recipients-importer.js +1 -1
- package/core/server/data/seeders/importers/emails-importer.js +1 -1
- package/core/server/data/seeders/importers/labels-importer.js +1 -1
- package/core/server/data/seeders/importers/members-click-events-importer.js +1 -1
- package/core/server/data/seeders/importers/members-created-events-importer.js +1 -1
- package/core/server/data/seeders/importers/members-feedback-importer.js +1 -1
- package/core/server/data/seeders/importers/members-importer.js +1 -1
- package/core/server/data/seeders/importers/members-login-events-importer.js +1 -1
- package/core/server/data/seeders/importers/members-products-importer.js +1 -1
- package/core/server/data/seeders/importers/members-status-events-importer.js +1 -1
- package/core/server/data/seeders/importers/members-stripe-customers-importer.js +1 -1
- package/core/server/data/seeders/importers/members-stripe-customers-subscriptions-importer.js +1 -1
- package/core/server/data/seeders/importers/members-subscribe-events-importer.js +1 -1
- package/core/server/data/seeders/importers/members-subscription-created-events-importer.js +1 -1
- package/core/server/data/seeders/importers/offer-redemptions-importer.js +1 -1
- package/core/server/data/seeders/importers/offers-importer.js +1 -1
- package/core/server/data/seeders/importers/posts-importer.js +1 -1
- package/core/server/data/seeders/importers/table-importer.js +2 -2
- package/core/server/data/seeders/importers/tags-importer.js +1 -1
- package/core/server/data/seeders/importers/users-importer.js +1 -1
- package/core/server/data/seeders/importers/web-mentions-importer.js +1 -1
- package/core/server/data/seeders/utils/random.js +3 -3
- package/core/server/ghost-server.js +3 -2
- package/core/server/lib/db-types/boolean.js +18 -0
- package/core/server/lib/image/image-size.js +24 -0
- package/core/server/lib/package-json/parse.js +2 -2
- package/core/server/lib/promise-pool.js +31 -0
- package/core/server/models/member.js +6 -17
- package/core/server/models/post.js +2 -2
- package/core/server/models/relations/authors.js +2 -16
- package/core/server/models/user.js +9 -2
- package/core/server/services/auth/passwordreset.js +13 -0
- package/core/server/services/automations/database-automations-repository.js +26 -26
- package/core/server/services/automations/poll.js +1 -0
- package/core/server/services/comments/comments-controller.js +30 -9
- package/core/server/services/comments/comments-service.js +55 -5
- package/core/server/services/content-import/csv/formula.js +12 -0
- package/core/server/services/content-import/csv/index.js +6 -1
- package/core/server/services/content-import/csv/parse.js +27 -6
- package/core/server/services/content-import/csv/serialize.js +13 -0
- package/core/server/services/content-import/import/assets.js +74 -0
- package/core/server/services/content-import/import/completion-email.js +164 -0
- package/core/server/services/content-import/import/errors-file.js +36 -0
- package/core/server/services/content-import/import/importer.js +204 -54
- package/core/server/services/content-import/import/local-media-url.js +63 -0
- package/core/server/services/content-import/import/media.js +254 -0
- package/core/server/services/content-import/import/post-data.js +1 -1
- package/core/server/services/content-import/import/post-link.js +11 -0
- package/core/server/services/content-import/import/post-repository.js +100 -0
- package/core/server/services/content-import/import/reader.js +9 -2
- package/core/server/services/content-import/import/relations.js +149 -0
- package/core/server/services/content-import/import/report.js +34 -0
- package/core/server/services/content-import/import/row.js +11 -2
- package/core/server/services/content-import/import/schema.js +30 -0
- package/core/server/services/content-import/import/source.js +125 -0
- package/core/server/services/content-import/import/staged-file.js +29 -0
- package/core/server/services/content-import/import/store.js +25 -2
- package/core/server/services/content-import/index.js +58 -34
- package/core/server/services/content-import/jobs/content-csv-import-job.js +20 -0
- package/core/server/services/custom-redirects/redirect-config-parser.js +2 -2
- package/core/server/services/custom-redirects/redirects-service.js +1 -1
- package/core/server/services/custom-redirects/validation.js +1 -1
- package/core/server/services/email-address/email-address-parser.js +30 -38
- package/core/server/services/email-address/email-address-service.js +37 -4
- package/core/server/services/email-analytics/email-analytics-service.js +8 -1
- package/core/server/services/email-analytics/index.js +2 -7
- package/core/server/services/email-analytics/lib/queries.js +7 -1
- package/core/server/services/email-service/batch-sending-service.js +0 -4
- package/core/server/services/email-service/email-renderer.js +14 -4
- package/core/server/services/email-service/email-service-wrapper.js +0 -9
- package/core/server/services/email-service/mailgun-email-provider.js +20 -9
- package/core/server/services/gift-links/schema.js +3 -3
- package/core/server/services/gifts/CONTEXT.md +1 -1
- package/core/server/services/gifts/constants.js +1 -1
- package/core/server/services/gifts/email-templates/gift-delivery.hbs +3 -3
- package/core/server/services/gifts/gift-bookshelf-repository.js +2 -2
- package/core/server/services/gifts/gift-delivery-bookshelf-repository.js +18 -9
- package/core/server/services/gifts/gift-delivery-schema.js +5 -5
- package/core/server/services/gifts/gift-delivery-service.js +4 -0
- package/core/server/services/gifts/gift-email-service.js +0 -1
- package/core/server/services/gifts/gift-schema.js +10 -10
- package/core/server/services/gifts/gift-service.js +4 -2
- package/core/server/services/gifts/index.js +3 -3
- package/core/server/services/gifts/jobs/index.js +4 -4
- package/core/server/services/indexnow-ping/indexnow-ping-service.js +2 -2
- package/core/server/services/invitations/accept.js +4 -2
- package/core/server/services/jobs/job-service.js +0 -9
- package/core/server/services/jobs-service/register-job-handlers.js +25 -15
- package/core/server/services/lib/mailgun-client.js +44 -8
- package/core/server/services/mail/ghost-mailer.js +4 -4
- package/core/server/services/media-inliner/external-media-inliner-job.js +12 -0
- package/core/server/services/media-inliner/external-media-inliner.js +103 -29
- package/core/server/services/media-inliner/service.js +13 -41
- package/core/server/services/media-inliner/types.js +2 -0
- package/core/server/services/member-welcome-emails/service.js +7 -7
- package/core/server/services/members/api.js +1 -0
- package/core/server/services/members/import-export/csv/parse.js +0 -7
- package/core/server/services/members/import-export/export/exporter.js +4 -6
- package/core/server/services/members/import-export/import/completion-email.js +2 -5
- package/core/server/services/members/import-export/import/importer.js +21 -5
- package/core/server/services/members/import-export/import/row.js +0 -3
- package/core/server/services/members/import-export/import/stripe-utils.js +6 -1
- package/core/server/services/members/import-export/index.js +10 -12
- package/core/server/services/members/jobs/clean-expired-comped-job.js +7 -0
- package/core/server/services/members/jobs/clean-expired-comped-task.js +145 -0
- package/core/server/services/members/jobs/index.js +48 -24
- package/core/server/services/members/members-api/controllers/member-controller.js +11 -0
- package/core/server/services/members/members-api/controllers/router-controller.js +3 -6
- package/core/server/services/members/members-api/members-api.js +9 -6
- package/core/server/services/members/members-api/repositories/event-repository.js +0 -4
- package/core/server/services/members/members-api/services/member-bread-service.js +53 -63
- package/core/server/services/members/members-api/services/payments-service.js +47 -1
- package/core/server/services/members/service.js +1 -5
- package/core/server/services/members-custom-fields/actions.js +27 -1
- package/core/server/services/members-custom-fields/bindings-service.js +120 -0
- package/core/server/services/members-custom-fields/codec.js +3 -4
- package/core/server/services/members-custom-fields/definitions-service.js +165 -22
- package/core/server/services/members-custom-fields/filter.js +75 -93
- package/core/server/services/members-custom-fields/index.js +11 -4
- package/core/server/services/members-custom-fields/key.js +2 -1
- package/core/server/services/members-custom-fields/models.js +1 -1
- package/core/server/services/members-custom-fields/queries.js +5 -0
- package/core/server/services/members-custom-fields/schema.js +37 -6
- package/core/server/services/members-custom-fields/serializers.js +3 -5
- package/core/server/services/members-custom-fields/values-service.js +65 -31
- package/core/server/services/mentions/mention-controller.js +23 -21
- package/core/server/services/mentions/process-webmention-job.js +16 -0
- package/core/server/services/mentions/service.js +8 -4
- package/core/server/services/public-config/config.js +7 -0
- package/core/server/services/route-settings/validation-errors.js +1 -1
- package/core/server/services/route-settings/yaml-parser.js +1 -1
- package/core/server/services/settings/settings-service.js +1 -8
- package/core/server/services/settings-helpers/settings-helpers.js +4 -6
- package/core/server/services/slack-ping/slack-ping-service.js +1 -1
- package/core/server/services/staff/staff-service-emails.js +2 -2
- package/core/server/services/stripe/config.js +14 -8
- package/core/server/services/stripe/service.js +10 -1
- package/core/server/services/stripe/services/checkout/completed-session.js +68 -0
- package/core/server/services/stripe/services/checkout/session-options.js +100 -0
- package/core/server/services/stripe/services/webhook/checkout-session-event-service.js +71 -1
- package/core/server/services/stripe/stripe-api.js +31 -0
- package/core/server/services/stripe/stripe-service.js +26 -9
- package/core/server/services/stripe/webhook-controller.js +10 -0
- package/core/server/services/tier-checkout-config/codec.js +99 -0
- package/core/server/services/tier-checkout-config/index.js +26 -0
- package/core/server/services/tier-checkout-config/models.js +63 -0
- package/core/server/services/tier-checkout-config/queries.js +80 -0
- package/core/server/services/tier-checkout-config/schema.js +33 -0
- package/core/server/services/tier-checkout-config/serializers.js +128 -0
- package/core/server/services/tier-checkout-config/service.js +304 -0
- package/core/server/services/tiers/service.js +21 -0
- package/core/server/services/update-check/index.js +13 -13
- package/core/server/services/update-check/jobs/update-check-job.js +7 -0
- package/core/server/services/update-check/update-check-service.js +2 -2
- package/core/server/web/admin/controller.js +1 -1
- package/core/server/web/api/endpoints/admin/routes.js +34 -20
- package/core/server/web/api/middleware/upload.js +2 -2
- package/core/server/web/parent/app.js +5 -0
- package/core/server/web/parent/middleware/filter-query-parameters.js +94 -0
- package/core/server/web/parent/middleware/index.js +1 -0
- package/core/server/web/query-parameter-policy/index.js +9 -0
- package/core/server/web/query-parameter-policy/policy.json +58 -0
- package/core/server/web/query-parameter-policy/schema.js +38 -0
- package/core/shared/config/defaults.json +3 -0
- package/core/shared/config/env/config.testing-mysql.json +4 -1
- package/core/shared/config/env/config.testing.json +3 -0
- package/core/shared/config/overrides.json +4 -2
- package/core/shared/labs.js +9 -15
- package/package.json +25 -25
- package/pnpm-lock.yaml +741 -108
- package/pnpm-workspace.yaml +12 -9
- package/tsconfig.json +2 -3
- package/components/tryghost-kg-default-nodes-2.2.0.tgz +0 -0
- package/core/built/admin/assets/Combination-gnJO3vIw.js +0 -41
- package/core/built/admin/assets/account-migration-8qTEI1i1.js +0 -1
- package/core/built/admin/assets/activitypub/inbox-DQ5CwLma.js +0 -1284
- package/core/built/admin/assets/activitypub/label-B72sfvEU.js +0 -16
- package/core/built/admin/assets/activitypub/layout-CXajhRsL.js +0 -1
- package/core/built/admin/assets/activitypub/settings-71gCm3SO.js +0 -315
- package/core/built/admin/assets/add-integration-modal--YpTq3c0.js +0 -1
- package/core/built/admin/assets/add-newsletter-modal-C8Ix2hol.js +0 -1
- package/core/built/admin/assets/add-recommendation-modal-CScuNFz4.js +0 -1
- package/core/built/admin/assets/alert-dialog-wEbVxANM.js +0 -1
- package/core/built/admin/assets/analytics-Cnji45H5.js +0 -1
- package/core/built/admin/assets/app-utils-D2Wp7ZSS.js +0 -1
- package/core/built/admin/assets/audience-DTLMXAFH.js +0 -1
- package/core/built/admin/assets/automations-BWpRCZ_f.js +0 -1
- package/core/built/admin/assets/bluesky-sharing-DHOpQxff.js +0 -1
- package/core/built/admin/assets/chart-helpers-B3OqQ6Ez.js +0 -1
- package/core/built/admin/assets/color-picker-Bmo1r9Fc.js +0 -3
- package/core/built/admin/assets/color-picker-field-DywowPhF.js +0 -1
- package/core/built/admin/assets/combobox-C4QCh6Yw.js +0 -1
- package/core/built/admin/assets/command-DcLbSifC.js +0 -1
- package/core/built/admin/assets/comments-Bxy_3WyE.js +0 -1
- package/core/built/admin/assets/confirmation-context-CLFHhyyH.js +0 -1
- package/core/built/admin/assets/custom-field-type-option-D0PXoSnP.js +0 -10
- package/core/built/admin/assets/custom-integration-modal-DCIHKN33.js +0 -1
- package/core/built/admin/assets/design-and-theme-modal-CZ-PkW7o.js +0 -23
- package/core/built/admin/assets/dialog-Db7c164G.js +0 -1
- package/core/built/admin/assets/dirty-confirm-dialog-CmARpZQS.js +0 -1
- package/core/built/admin/assets/dist-QLZuGq7o2.js +0 -1
- package/core/built/admin/assets/domain-D0SAtc-T.js +0 -1
- package/core/built/admin/assets/dropzone-CaPOeDRZ.js +0 -5
- package/core/built/admin/assets/edit-profile-By7v5XW5.js +0 -1
- package/core/built/admin/assets/editor-COXn4Atu.js +0 -8
- package/core/built/admin/assets/explore-BsNYrubV.js +0 -1
- package/core/built/admin/assets/feed-8RR1O1bK.js +0 -1
- package/core/built/admin/assets/filter-sources-4C0kF1NU.js +0 -1
- package/core/built/admin/assets/filters-CV5jCb9n.js +0 -1
- package/core/built/admin/assets/filters-Dmr0PoqU.js +0 -1
- package/core/built/admin/assets/first-promoter-modal-OCzSaL3B.js +0 -1
- package/core/built/admin/assets/gift-link-modal-0mzjn5oF.js +0 -1
- package/core/built/admin/assets/growth-55vWlGT_.js +0 -1
- package/core/built/admin/assets/growth-DA5AluYw.js +0 -3
- package/core/built/admin/assets/history-modal-G1s5hHz7.js +0 -1
- package/core/built/admin/assets/html-field-BegxsWpw.js +0 -1
- package/core/built/admin/assets/index-CDP9tIOk.js +0 -4
- package/core/built/admin/assets/index-Dqf2x-ry.css +0 -1
- package/core/built/admin/assets/index.es-BMUCj9TR.js +0 -1
- package/core/built/admin/assets/input-UHrKuvBT.js +0 -1
- package/core/built/admin/assets/invite-user-modal-BrAkxEO3.js +0 -1
- package/core/built/admin/assets/koenig-loader-DwVY_V-H.js +0 -1
- package/core/built/admin/assets/kpi-card-LERqWBoY.js +0 -1
- package/core/built/admin/assets/kpi-helpers-DB3ouhYF.js +0 -1
- package/core/built/admin/assets/kpi-tabs-BGvtMD8S.js +0 -1
- package/core/built/admin/assets/label-picker-BBWykUeA.js +0 -1
- package/core/built/admin/assets/layout-Di5K7doM.js +0 -1
- package/core/built/admin/assets/loading-indicator-SFTqyYVE.js +0 -1
- package/core/built/admin/assets/member-custom-fields-gOv6Hoh3.js +0 -1
- package/core/built/admin/assets/member-detail-D7mZDDp3.js +0 -1
- package/core/built/admin/assets/member-route-0Aa52Ntz.js +0 -1
- package/core/built/admin/assets/members-DvZG9t69.js +0 -2
- package/core/built/admin/assets/moderation-DzzPLDyl.js +0 -1
- package/core/built/admin/assets/navigation-modal-CI8Bx5vn.js +0 -1
- package/core/built/admin/assets/newsletter-Bg3cq5U-.js +0 -1
- package/core/built/admin/assets/newsletter-detail-modal-DQU3r4g2.js +0 -1
- package/core/built/admin/assets/newsletters-DMDfZbMS.js +0 -1
- package/core/built/admin/assets/note-i8k6pjaw.js +0 -1
- package/core/built/admin/assets/notifications-psA_2Ph4.js +0 -1
- package/core/built/admin/assets/offers-container-modal-BWfjSdyg.js +0 -1
- package/core/built/admin/assets/onboarding-DGQuV7Ew.js +0 -1
- package/core/built/admin/assets/overview-C-6xOLaf.js +0 -1
- package/core/built/admin/assets/overview-DaLhpRrC.js +0 -1
- package/core/built/admin/assets/pages-B6vr9F_D.js +0 -1
- package/core/built/admin/assets/popover-CFgqFDvC.js +0 -1
- package/core/built/admin/assets/portal-frame-DjBF-uy2.js +0 -1
- package/core/built/admin/assets/portal-modal-Cf0pBAk8.js +0 -1
- package/core/built/admin/assets/post-analytics-Buz1COoY.js +0 -1
- package/core/built/admin/assets/post-analytics-header-B-P0eFnT.js +0 -1
- package/core/built/admin/assets/posts-KY3aUhVV.js +0 -1
- package/core/built/admin/assets/preferences-Cq1aOiLy.js +0 -5
- package/core/built/admin/assets/profile-D6dHYf2o.js +0 -1
- package/core/built/admin/assets/select-D_RQaXgt.js +0 -1
- package/core/built/admin/assets/settings-B5hJKZ5C.js +0 -1
- package/core/built/admin/assets/settings-DIo_F-MF.js +0 -4
- package/core/built/admin/assets/share-modal-CLBfj377.js +0 -1
- package/core/built/admin/assets/shim-ClF_m5ux.js +0 -1
- package/core/built/admin/assets/slack-modal-Bt9I_tEo.js +0 -1
- package/core/built/admin/assets/sort-button-DMBXF7tP.js +0 -1
- package/core/built/admin/assets/stats-B_YkF7bp.js +0 -1
- package/core/built/admin/assets/stats-view-BOCp9RG8.js +0 -1
- package/core/built/admin/assets/stripe-connect-modal-BeSukI8q.js +0 -1
- package/core/built/admin/assets/tag-detail-2a3BfzTW.js +0 -2
- package/core/built/admin/assets/tags-Dp2_8UzL.js +0 -1
- package/core/built/admin/assets/testimonials-modal-C9nrypNo.js +0 -1
- package/core/built/admin/assets/tier-detail-modal-CxRwgTPR.js +0 -1
- package/core/built/admin/assets/use-check-theme-limit-error-C9-QhGdV.js +0 -1
- package/core/built/admin/assets/use-filter-params-CSpAvgD2.js +0 -1
- package/core/built/admin/assets/use-growth-stats-BOmoPDHJ.js +0 -1
- package/core/built/admin/assets/use-post-referrers-CbXLFIex.js +0 -1
- package/core/built/admin/assets/use-reply-chain-data-JYFKSO83.js +0 -1
- package/core/built/admin/assets/use-settings-navigation-BBzro2-V.js +0 -1
- package/core/built/admin/assets/use-tinybird-query-D2Aeoty5.js +0 -39
- package/core/built/admin/assets/use-tinybird-token-DBuwMmln.js +0 -1
- package/core/built/admin/assets/user-detail-modal-59mBJqxN.js +0 -1
- package/core/built/admin/assets/users-5msE1WMs.js +0 -1
- package/core/built/admin/assets/web-DUuX7nE2.js +0 -2
- package/core/built/admin/assets/web-N8ucs2aG.js +0 -1
- package/core/server/api/endpoints/member-custom-fields.js +0 -100
- package/core/server/services/jobs/worker-model-event-bridge.js +0 -149
- package/core/server/services/members/jobs/clean-expired-comped.js +0 -132
- package/core/server/services/update-check/run-update-check.js +0 -63
- /package/core/server/lib/{db-date.js → db-types/date.js} +0 -0
|
@@ -11,6 +11,7 @@ const mail = require('../mail');
|
|
|
11
11
|
|
|
12
12
|
const messages = {
|
|
13
13
|
userNotFound: 'User not found.',
|
|
14
|
+
userSuspended: 'This account has been suspended.',
|
|
14
15
|
resetPassword: 'Reset Password',
|
|
15
16
|
expired: {
|
|
16
17
|
message: 'Cannot reset password.',
|
|
@@ -46,6 +47,14 @@ function generateToken(email, settingsAPI, transaction) {
|
|
|
46
47
|
throw new errors.NotFoundError({ message: tpl(messages.userNotFound) });
|
|
47
48
|
}
|
|
48
49
|
|
|
50
|
+
// Prevent suspended users from generating a reset token. This same check must appear
|
|
51
|
+
// below in doReset() to account for password reset tokens that were generated prior
|
|
52
|
+
// to suspension since they have a 24-hour lifetime.
|
|
53
|
+
// Locked users must still be able to recover access by resetting their password.
|
|
54
|
+
if (user.isInactive()) {
|
|
55
|
+
throw new errors.NoPermissionError({ message: tpl(messages.userSuspended) });
|
|
56
|
+
}
|
|
57
|
+
|
|
49
58
|
token = security.tokens.resetToken.generateHash({
|
|
50
59
|
expires: moment().add(1, 'days').valueOf(),
|
|
51
60
|
email: email,
|
|
@@ -128,6 +137,10 @@ function doReset(options, tokenParts, settingsAPI) {
|
|
|
128
137
|
}
|
|
129
138
|
}
|
|
130
139
|
|
|
140
|
+
if (user.isInactive()) {
|
|
141
|
+
throw new errors.NoPermissionError({ message: tpl(messages.userSuspended) });
|
|
142
|
+
}
|
|
143
|
+
|
|
131
144
|
const updatedUser = await models.User.changePassword(
|
|
132
145
|
{
|
|
133
146
|
oldPassword: oldPassword,
|
|
@@ -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 date_1 = require("../../lib/db-types/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 = [
|
|
@@ -93,7 +93,7 @@ function createDatabaseAutomationsRepository({ knex, fakeWaitHoursMultiplier, })
|
|
|
93
93
|
const updatedAutomation = await updateAutomation(trx, {
|
|
94
94
|
...automation,
|
|
95
95
|
status: data.status,
|
|
96
|
-
updated_at: (0,
|
|
96
|
+
updated_at: (0, date_1.toDatabaseDate)(now),
|
|
97
97
|
});
|
|
98
98
|
await replaceAutomationGraph(trx, updatedAutomation.id, data.actions, data.edges);
|
|
99
99
|
if (updatedAutomation.status === 'inactive') {
|
|
@@ -130,7 +130,7 @@ function createDatabaseAutomationsRepository({ knex, fakeWaitHoursMultiplier, })
|
|
|
130
130
|
.update({
|
|
131
131
|
email_sent_count: trx.raw('COALESCE(??, 0) + ?', ['email_sent_count', 1]),
|
|
132
132
|
});
|
|
133
|
-
const now = (0,
|
|
133
|
+
const now = (0, date_1.toDatabaseDate)(new Date());
|
|
134
134
|
await trx('automated_email_recipients').insert({
|
|
135
135
|
id: (0, bson_objectid_1.default)().toHexString(),
|
|
136
136
|
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, date_1.toDatabaseDate)(new Date());
|
|
285
285
|
const id = (0, bson_objectid_1.default)().toHexString();
|
|
286
286
|
await trx('automations')
|
|
287
287
|
.insert({
|
|
@@ -313,7 +313,7 @@ async function ensureWelcomeEmailAction(trx, automationId) {
|
|
|
313
313
|
if (!email) {
|
|
314
314
|
return;
|
|
315
315
|
}
|
|
316
|
-
const now = (0,
|
|
316
|
+
const now = (0, date_1.toDatabaseDate)(new Date());
|
|
317
317
|
const actionId = (0, bson_objectid_1.default)().toHexString();
|
|
318
318
|
await insertActions(trx, [
|
|
319
319
|
{
|
|
@@ -347,7 +347,7 @@ async function trigger(trx, options) {
|
|
|
347
347
|
return;
|
|
348
348
|
}
|
|
349
349
|
const now = new Date();
|
|
350
|
-
const nowString = (0,
|
|
350
|
+
const nowString = (0, date_1.toDatabaseDate)(now);
|
|
351
351
|
const readyAt = getReadyAtForAction(firstAction, now, fakeWaitHoursMultiplier);
|
|
352
352
|
const run = {
|
|
353
353
|
id: (0, bson_objectid_1.default)().toHexString(),
|
|
@@ -366,14 +366,14 @@ async function trigger(trx, options) {
|
|
|
366
366
|
});
|
|
367
367
|
}
|
|
368
368
|
async function insertRunStep(trx, { automationRunId, automationActionRevisionId, now, readyAt, }) {
|
|
369
|
-
const nowString = (0,
|
|
369
|
+
const nowString = (0, date_1.toDatabaseDate)(now);
|
|
370
370
|
await trx('automation_run_steps').insert({
|
|
371
371
|
id: (0, bson_objectid_1.default)().toHexString(),
|
|
372
372
|
created_at: nowString,
|
|
373
373
|
updated_at: nowString,
|
|
374
374
|
automation_run_id: automationRunId,
|
|
375
375
|
automation_action_revision_id: automationActionRevisionId,
|
|
376
|
-
ready_at: (0,
|
|
376
|
+
ready_at: (0, date_1.toDatabaseDate)(readyAt),
|
|
377
377
|
});
|
|
378
378
|
}
|
|
379
379
|
async function fetchAndLockSteps(trx, limit) {
|
|
@@ -388,9 +388,9 @@ async function fetchAndLockSteps(trx, limit) {
|
|
|
388
388
|
// 2. Try to lock those rows.
|
|
389
389
|
// 3. Select any rows we successfully locked.
|
|
390
390
|
const now = new Date();
|
|
391
|
-
const nowString = (0,
|
|
391
|
+
const nowString = (0, date_1.toDatabaseDate)(now);
|
|
392
392
|
const staleLockCutoff = (0, stale_lock_cutoff_1.getStaleLockCutoff)(now);
|
|
393
|
-
const staleLockCutoffString = (0,
|
|
393
|
+
const staleLockCutoffString = (0, date_1.toDatabaseDate)(staleLockCutoff);
|
|
394
394
|
const lockId = node_crypto_1.default.randomUUID();
|
|
395
395
|
// 1. Select up to `limit` candidate rows.
|
|
396
396
|
const candidates = await trx('automation_run_steps')
|
|
@@ -444,17 +444,17 @@ async function findNextPendingReadyAt(trx, staleLockCutoff) {
|
|
|
444
444
|
.select({ next_ready_at: 'ready_at' })
|
|
445
445
|
.where('status', 'pending')
|
|
446
446
|
.where((builder) => {
|
|
447
|
-
builder.whereNull('locked_by').orWhere('locked_at', '<', (0,
|
|
447
|
+
builder.whereNull('locked_by').orWhere('locked_at', '<', (0, date_1.toDatabaseDate)(staleLockCutoff));
|
|
448
448
|
})
|
|
449
449
|
.orderBy('ready_at')
|
|
450
450
|
.first();
|
|
451
|
-
return row?.next_ready_at ? (0,
|
|
451
|
+
return row?.next_ready_at ? (0, date_1.fromDatabaseDate)(row.next_ready_at) : null;
|
|
452
452
|
}
|
|
453
453
|
function buildStepToRun(row) {
|
|
454
454
|
const base = {
|
|
455
455
|
id: row.id,
|
|
456
456
|
step_attempts: row.step_attempts,
|
|
457
|
-
ready_at: (0,
|
|
457
|
+
ready_at: (0, date_1.fromDatabaseDate)(row.ready_at),
|
|
458
458
|
locked_by: row.locked_by,
|
|
459
459
|
automation_run_id: row.automation_run_id,
|
|
460
460
|
automation_id: row.automation_id,
|
|
@@ -544,7 +544,7 @@ async function findNextActionRevision(trx, sourceActionId) {
|
|
|
544
544
|
return row ?? null;
|
|
545
545
|
}
|
|
546
546
|
async function markStepTerminal(trx, step, status) {
|
|
547
|
-
const nowString = (0,
|
|
547
|
+
const nowString = (0, date_1.toDatabaseDate)(new Date());
|
|
548
548
|
return await updateStep(trx, step, {
|
|
549
549
|
status,
|
|
550
550
|
finished_at: nowString,
|
|
@@ -556,12 +556,12 @@ async function retryStep(trx, step, retryAt) {
|
|
|
556
556
|
await markStepTerminal(trx, step, 'automation disabled');
|
|
557
557
|
return false;
|
|
558
558
|
}
|
|
559
|
-
const nowString = (0,
|
|
559
|
+
const nowString = (0, date_1.toDatabaseDate)(new Date());
|
|
560
560
|
return await updateStep(trx, step, {
|
|
561
561
|
status: 'pending',
|
|
562
562
|
started_at: null,
|
|
563
563
|
finished_at: null,
|
|
564
|
-
ready_at: (0,
|
|
564
|
+
ready_at: (0, date_1.toDatabaseDate)(retryAt),
|
|
565
565
|
updated_at: nowString,
|
|
566
566
|
});
|
|
567
567
|
}
|
|
@@ -586,8 +586,8 @@ function getReadyAtForAction(action, now, fakeWaitHoursMultiplier) {
|
|
|
586
586
|
}
|
|
587
587
|
}
|
|
588
588
|
async function cancelCancelablePendingStepsForAutomation(trx, automationId, now) {
|
|
589
|
-
const nowString = (0,
|
|
590
|
-
const staleLockCutoff = (0,
|
|
589
|
+
const nowString = (0, date_1.toDatabaseDate)(now);
|
|
590
|
+
const staleLockCutoff = (0, date_1.toDatabaseDate)((0, stale_lock_cutoff_1.getStaleLockCutoff)(now));
|
|
591
591
|
await trx('automation_run_steps')
|
|
592
592
|
.update({
|
|
593
593
|
status: 'automation disabled',
|
|
@@ -707,7 +707,7 @@ async function replaceAutomationGraph(trx, automationId, submittedActions, edges
|
|
|
707
707
|
revision.action_id,
|
|
708
708
|
revision,
|
|
709
709
|
]));
|
|
710
|
-
const now = (0,
|
|
710
|
+
const now = (0, date_1.toDatabaseDate)(new Date());
|
|
711
711
|
const actionsToInsert = [];
|
|
712
712
|
const revisionsToInsert = [];
|
|
713
713
|
for (const action of actions) {
|
|
@@ -884,14 +884,14 @@ async function insertActionRevisions(trx, revisions) {
|
|
|
884
884
|
}
|
|
885
885
|
function getNextRevisionCreatedAt(latestCreatedAt, requestedCreatedAt) {
|
|
886
886
|
if (!latestCreatedAt) {
|
|
887
|
-
return (0,
|
|
887
|
+
return (0, date_1.toDatabaseDate)(requestedCreatedAt);
|
|
888
888
|
}
|
|
889
|
-
const requestedTime = (0,
|
|
890
|
-
const latestTime = (0,
|
|
889
|
+
const requestedTime = (0, date_1.fromDatabaseDate)(requestedCreatedAt).getTime();
|
|
890
|
+
const latestTime = (0, date_1.fromDatabaseDate)(latestCreatedAt).getTime();
|
|
891
891
|
if (requestedTime > latestTime) {
|
|
892
|
-
return (0,
|
|
892
|
+
return (0, date_1.toDatabaseDate)(requestedCreatedAt);
|
|
893
893
|
}
|
|
894
|
-
return (0,
|
|
894
|
+
return (0, date_1.toDatabaseDate)(new Date(latestTime + 1000));
|
|
895
895
|
}
|
|
896
896
|
function buildActionRevision(actionId, action, createdAt) {
|
|
897
897
|
switch (action.type) {
|
|
@@ -970,7 +970,7 @@ function buildAutomationBrowseResult(automation) {
|
|
|
970
970
|
...buildAutomationSummary(automation),
|
|
971
971
|
stats: {
|
|
972
972
|
last_run_created_at: automation.last_run_created_at
|
|
973
|
-
? (0,
|
|
973
|
+
? (0, date_1.fromDatabaseDate)(automation.last_run_created_at)
|
|
974
974
|
: null,
|
|
975
975
|
total_run_count: Number(automation.total_run_count ?? 0),
|
|
976
976
|
in_progress_run_count: Number(automation.in_progress_run_count ?? 0),
|
|
@@ -978,7 +978,7 @@ function buildAutomationBrowseResult(automation) {
|
|
|
978
978
|
};
|
|
979
979
|
}
|
|
980
980
|
function serializeDate(date) {
|
|
981
|
-
const normalizedDate = (0,
|
|
981
|
+
const normalizedDate = (0, date_1.fromDatabaseDate)(date);
|
|
982
982
|
normalizedDate.setMilliseconds(0);
|
|
983
983
|
return normalizedDate.toISOString();
|
|
984
984
|
}
|
|
@@ -119,6 +119,7 @@ const processStep = async ({ automationsApi, memberWelcomeEmailService, schedule
|
|
|
119
119
|
subject: step.email_subject,
|
|
120
120
|
},
|
|
121
121
|
member: {
|
|
122
|
+
// Note that we don't use `automation_run.member_email` here. That's only for the historical record, not for functionality.
|
|
122
123
|
email: member.get('email'),
|
|
123
124
|
name: member.get('name'),
|
|
124
125
|
uuid: member.get('uuid'),
|
|
@@ -14,6 +14,7 @@ const messages = {
|
|
|
14
14
|
cannotDestroyComments: 'You cannot destroy comments.',
|
|
15
15
|
memberNotFound: 'Unable to find member',
|
|
16
16
|
unsupportedReportCountFilter: 'Unsupported count.reports filter',
|
|
17
|
+
errorParsingFilter: 'Error parsing filter',
|
|
17
18
|
};
|
|
18
19
|
|
|
19
20
|
module.exports = class CommentsController {
|
|
@@ -26,6 +27,16 @@ module.exports = class CommentsController {
|
|
|
26
27
|
this.stats = stats;
|
|
27
28
|
}
|
|
28
29
|
|
|
30
|
+
#getPostIdFromFilter(query) {
|
|
31
|
+
if (typeof query.post_id === 'string') {
|
|
32
|
+
return query.post_id;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Only equality conditions required by an AND can scope a legacy browse.
|
|
36
|
+
// Choosing an ID from an OR or an exclusion would authorize the wrong posts.
|
|
37
|
+
return query.$and?.map((part) => this.#getPostIdFromFilter(part)).find(Boolean);
|
|
38
|
+
}
|
|
39
|
+
|
|
29
40
|
#withPostFilter(options) {
|
|
30
41
|
const nextOptions = { ...options };
|
|
31
42
|
|
|
@@ -138,7 +149,17 @@ module.exports = class CommentsController {
|
|
|
138
149
|
* @param {Frame} frame
|
|
139
150
|
*/
|
|
140
151
|
async browse(frame) {
|
|
141
|
-
|
|
152
|
+
const options = { ...frame.options };
|
|
153
|
+
if (!options.post_id && options.filter) {
|
|
154
|
+
let query;
|
|
155
|
+
try {
|
|
156
|
+
query = nql(options.filter).parse();
|
|
157
|
+
} catch (err) {
|
|
158
|
+
throw new errors.BadRequestError({ message: tpl(messages.errorParsingFilter), err });
|
|
159
|
+
}
|
|
160
|
+
options.post_id = this.#getPostIdFromFilter(query);
|
|
161
|
+
}
|
|
162
|
+
return await this.service.getComments(this.#withPostFilter(options));
|
|
142
163
|
}
|
|
143
164
|
|
|
144
165
|
async adminBrowse(frame) {
|
|
@@ -345,14 +366,14 @@ module.exports = class CommentsController {
|
|
|
345
366
|
async like(frame) {
|
|
346
367
|
this.#checkMember(frame);
|
|
347
368
|
|
|
369
|
+
const comment = await this.service.getCommentByID(frame.options.id, frame.options);
|
|
370
|
+
|
|
348
371
|
const result = await this.service.likeComment(
|
|
349
372
|
frame.options.id,
|
|
350
373
|
frame.options?.context?.member,
|
|
351
374
|
frame.options,
|
|
352
375
|
);
|
|
353
376
|
|
|
354
|
-
const comment = await this.service.getCommentByID(frame.options.id, frame.options);
|
|
355
|
-
|
|
356
377
|
this.setCacheInvalidationHeaders(comment, frame);
|
|
357
378
|
|
|
358
379
|
return result;
|
|
@@ -364,14 +385,14 @@ module.exports = class CommentsController {
|
|
|
364
385
|
async unlike(frame) {
|
|
365
386
|
this.#checkMember(frame);
|
|
366
387
|
|
|
388
|
+
const comment = await this.service.getCommentByID(frame.options.id, frame.options);
|
|
389
|
+
|
|
367
390
|
const result = await this.service.unlikeComment(
|
|
368
391
|
frame.options.id,
|
|
369
392
|
frame.options?.context?.member,
|
|
370
393
|
frame.options,
|
|
371
394
|
);
|
|
372
395
|
|
|
373
|
-
const comment = await this.service.getCommentByID(frame.options.id, frame.options);
|
|
374
|
-
|
|
375
396
|
this.setCacheInvalidationHeaders(comment, frame);
|
|
376
397
|
|
|
377
398
|
return result;
|
|
@@ -420,14 +441,14 @@ module.exports = class CommentsController {
|
|
|
420
441
|
async dislike(frame) {
|
|
421
442
|
this.#checkMember(frame);
|
|
422
443
|
|
|
444
|
+
const comment = await this.service.getCommentByID(frame.options.id, frame.options);
|
|
445
|
+
|
|
423
446
|
const result = await this.service.dislikeComment(
|
|
424
447
|
frame.options.id,
|
|
425
448
|
frame.options?.context?.member,
|
|
426
449
|
frame.options,
|
|
427
450
|
);
|
|
428
451
|
|
|
429
|
-
const comment = await this.service.getCommentByID(frame.options.id, frame.options);
|
|
430
|
-
|
|
431
452
|
this.setCacheInvalidationHeaders(comment, frame);
|
|
432
453
|
|
|
433
454
|
return result;
|
|
@@ -439,14 +460,14 @@ module.exports = class CommentsController {
|
|
|
439
460
|
async undislike(frame) {
|
|
440
461
|
this.#checkMember(frame);
|
|
441
462
|
|
|
463
|
+
const comment = await this.service.getCommentByID(frame.options.id, frame.options);
|
|
464
|
+
|
|
442
465
|
const result = await this.service.undislikeComment(
|
|
443
466
|
frame.options.id,
|
|
444
467
|
frame.options?.context?.member,
|
|
445
468
|
frame.options,
|
|
446
469
|
);
|
|
447
470
|
|
|
448
|
-
const comment = await this.service.getCommentByID(frame.options.id, frame.options);
|
|
449
|
-
|
|
450
471
|
this.setCacheInvalidationHeaders(comment, frame);
|
|
451
472
|
|
|
452
473
|
return result;
|
|
@@ -13,7 +13,9 @@ const messages = {
|
|
|
13
13
|
alreadyDisliked: 'This comment was disliked already',
|
|
14
14
|
replyToReply: 'Can not reply to a reply',
|
|
15
15
|
commentsNotEnabled: 'Comments are not enabled for this site.',
|
|
16
|
+
postIdRequired: 'A post ID is required to read comments.',
|
|
16
17
|
cannotCommentOnPost: 'You do not have permission to comment on this post.',
|
|
18
|
+
cannotReadComment: 'You do not have permission to read comments on this post',
|
|
17
19
|
cannotEditComment: 'You do not have permission to edit comments',
|
|
18
20
|
cannotPinReply: 'Replies cannot be pinned',
|
|
19
21
|
cannotPinDeletedComment: 'Deleted comments cannot be pinned',
|
|
@@ -39,7 +41,7 @@ const COMMENT_STATUSES_IN_REPLY_TO = [COMMENT_STATUS_PUBLISHED, COMMENT_STATUS_H
|
|
|
39
41
|
// new `comment.get(...)` call has one obvious place to register its column.
|
|
40
42
|
const REPLY_PARENT_REQUIRED_COLUMNS = ['parent_id', 'post_id'];
|
|
41
43
|
const IN_REPLY_TO_REQUIRED_COLUMNS = ['parent_id'];
|
|
42
|
-
const OWNERSHIP_REQUIRED_COLUMNS = ['member_id'];
|
|
44
|
+
const OWNERSHIP_REQUIRED_COLUMNS = ['member_id', 'post_id'];
|
|
43
45
|
const REPORT_REQUIRED_COLUMNS = ['post_id', 'member_id', 'html', 'created_at'];
|
|
44
46
|
|
|
45
47
|
function getColumnList(columns) {
|
|
@@ -167,11 +169,14 @@ class CommentsService {
|
|
|
167
169
|
}
|
|
168
170
|
|
|
169
171
|
/** @private */
|
|
170
|
-
checkPostAccess(postModel, memberModel) {
|
|
171
|
-
const access = this.contentGating.checkPostAccess(
|
|
172
|
+
checkPostAccess(postModel, memberModel, { action = 'comment' } = {}) {
|
|
173
|
+
const access = this.contentGating.checkPostAccess(
|
|
174
|
+
postModel.toJSON(),
|
|
175
|
+
memberModel ? memberModel.toJSON() : null,
|
|
176
|
+
);
|
|
172
177
|
if (access === this.contentGating.BLOCK_ACCESS) {
|
|
173
178
|
throw new errors.NoPermissionError({
|
|
174
|
-
message: tpl(messages.cannotCommentOnPost),
|
|
179
|
+
message: tpl(action === 'read' ? messages.cannotReadComment : messages.cannotCommentOnPost),
|
|
175
180
|
});
|
|
176
181
|
}
|
|
177
182
|
}
|
|
@@ -189,6 +194,32 @@ class CommentsService {
|
|
|
189
194
|
});
|
|
190
195
|
}
|
|
191
196
|
|
|
197
|
+
async #checkPostAccessForRead(postId, options) {
|
|
198
|
+
if (options.isAdmin) {
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
if (!postId) {
|
|
203
|
+
throw new errors.ValidationError({ message: tpl(messages.postIdRequired) });
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
const postModel = await this.models.Post.findOne(
|
|
207
|
+
{ id: postId },
|
|
208
|
+
{ require: true, transacting: options.transacting, withRelated: ['tiers'] },
|
|
209
|
+
);
|
|
210
|
+
|
|
211
|
+
let memberModel = null;
|
|
212
|
+
const memberId = options.context?.member?.id;
|
|
213
|
+
if (memberId) {
|
|
214
|
+
memberModel = await this.models.Member.findOne(
|
|
215
|
+
{ id: memberId },
|
|
216
|
+
{ require: true, transacting: options.transacting, withRelated: ['products'] },
|
|
217
|
+
);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
this.checkPostAccess(postModel, memberModel, { action: 'read' });
|
|
221
|
+
}
|
|
222
|
+
|
|
192
223
|
/**
|
|
193
224
|
* Primary comment lookup: a single keyed fetch with the allowed statuses
|
|
194
225
|
* applied in the query (`WHERE id = ? AND status IN (...)`), optionally locked
|
|
@@ -520,6 +551,7 @@ class CommentsService {
|
|
|
520
551
|
*/
|
|
521
552
|
async getComments(options) {
|
|
522
553
|
this.checkEnabled();
|
|
554
|
+
await this.#checkPostAccessForRead(options.post_id, options);
|
|
523
555
|
const page = await this.models.Comment.findPage(
|
|
524
556
|
withPinnedSelect({ ...options, parentId: null, pinnedFirst: true }),
|
|
525
557
|
);
|
|
@@ -659,6 +691,17 @@ class CommentsService {
|
|
|
659
691
|
*/
|
|
660
692
|
async getReplies(id, options, { includeHidden = false } = {}) {
|
|
661
693
|
this.checkEnabled();
|
|
694
|
+
|
|
695
|
+
const parentComment = await this.#fetchCommentByID(id, options, {
|
|
696
|
+
requiredColumns: ['post_id'],
|
|
697
|
+
});
|
|
698
|
+
|
|
699
|
+
if (!parentComment) {
|
|
700
|
+
throw new errors.NotFoundError({ message: tpl(messages.commentNotFound) });
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
await this.#checkPostAccessForRead(parentComment.get('post_id'), options);
|
|
704
|
+
|
|
662
705
|
const page = await this.models.Comment.findPage(
|
|
663
706
|
withPinnedSelect({ ...options, parentId: id }, { includeHidden }),
|
|
664
707
|
);
|
|
@@ -740,7 +783,9 @@ class CommentsService {
|
|
|
740
783
|
async getCommentByID(id, options = {}) {
|
|
741
784
|
this.checkEnabled();
|
|
742
785
|
|
|
743
|
-
|
|
786
|
+
const model = await this.#getReadableCommentByID(id, options, ['post_id']);
|
|
787
|
+
await this.#checkPostAccessForRead(model.get('post_id'), options);
|
|
788
|
+
return model;
|
|
744
789
|
}
|
|
745
790
|
|
|
746
791
|
/**
|
|
@@ -908,6 +953,9 @@ class CommentsService {
|
|
|
908
953
|
});
|
|
909
954
|
}
|
|
910
955
|
|
|
956
|
+
// Mutation responses include replies, so they require the same post access as reads.
|
|
957
|
+
await this.#checkPostAccessForRead(existingComment.get('post_id'), options);
|
|
958
|
+
|
|
911
959
|
const model = await this.models.Comment.edit(
|
|
912
960
|
{
|
|
913
961
|
status: COMMENT_STATUS_DELETED,
|
|
@@ -943,6 +991,8 @@ class CommentsService {
|
|
|
943
991
|
});
|
|
944
992
|
}
|
|
945
993
|
|
|
994
|
+
await this.#checkPostAccessForRead(existingComment.get('post_id'), options);
|
|
995
|
+
|
|
946
996
|
if (!comment) {
|
|
947
997
|
return existingComment;
|
|
948
998
|
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.stripFormulaGuard = stripFormulaGuard;
|
|
4
|
+
const FORMULA_TRIGGERS = ['=', '+', '-', '@', '\t', '\r'];
|
|
5
|
+
// Report files prefix formula-shaped cells with an apostrophe. Remove exactly
|
|
6
|
+
// that guard during re-import so repeated fixes do not change publisher data.
|
|
7
|
+
function stripFormulaGuard(cell) {
|
|
8
|
+
if (cell.charAt(0) === "'" && FORMULA_TRIGGERS.includes(cell.charAt(1))) {
|
|
9
|
+
return cell.slice(1);
|
|
10
|
+
}
|
|
11
|
+
return cell;
|
|
12
|
+
}
|
|
@@ -3,6 +3,11 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.parse = void 0;
|
|
6
|
+
exports.stripFormulaGuard = exports.serialize = exports.parseWithSource = exports.parse = void 0;
|
|
7
7
|
var parse_1 = require("./parse");
|
|
8
8
|
Object.defineProperty(exports, "parse", { enumerable: true, get: function () { return __importDefault(parse_1).default; } });
|
|
9
|
+
Object.defineProperty(exports, "parseWithSource", { enumerable: true, get: function () { return parse_1.parseWithSource; } });
|
|
10
|
+
var serialize_1 = require("./serialize");
|
|
11
|
+
Object.defineProperty(exports, "serialize", { enumerable: true, get: function () { return __importDefault(serialize_1).default; } });
|
|
12
|
+
var formula_1 = require("./formula");
|
|
13
|
+
Object.defineProperty(exports, "stripFormulaGuard", { enumerable: true, get: function () { return formula_1.stripFormulaGuard; } });
|
|
@@ -4,8 +4,10 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.default = parse;
|
|
7
|
+
exports.parseWithSource = parseWithSource;
|
|
7
8
|
const papaparse_1 = __importDefault(require("papaparse"));
|
|
8
9
|
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
10
|
+
const formula_1 = require("./formula");
|
|
9
11
|
const errors = require('@tryghost/errors');
|
|
10
12
|
// A column named after an Object.prototype member is unsafe as a key.
|
|
11
13
|
function isSafeColumnName(name) {
|
|
@@ -17,44 +19,63 @@ function isSafeColumnName(name) {
|
|
|
17
19
|
function isFatal(error) {
|
|
18
20
|
return error.type === 'Quotes';
|
|
19
21
|
}
|
|
22
|
+
function isEmptyRow(row) {
|
|
23
|
+
return !Object.values(row).some((value) => {
|
|
24
|
+
if (Array.isArray(value)) {
|
|
25
|
+
return value.some((cell) => typeof cell === 'string' && cell.trim().length > 0);
|
|
26
|
+
}
|
|
27
|
+
return value.trim().length > 0;
|
|
28
|
+
});
|
|
29
|
+
}
|
|
20
30
|
// headerMapping renames headers to the columns they emit under; unmapped columns
|
|
21
31
|
// carry through, and one mapped to an empty target is dropped.
|
|
22
32
|
async function parse(path, headerMapping) {
|
|
33
|
+
const parsed = await parseWithSource(path, headerMapping);
|
|
34
|
+
return parsed.rows.map(({ data }) => data);
|
|
35
|
+
}
|
|
36
|
+
async function parseWithSource(path, headerMapping) {
|
|
23
37
|
// Buffered rather than streamed: files are bounded by the interim row cap, and
|
|
24
38
|
// papaparse's stream mode drops results.errors, which is what catches a
|
|
25
39
|
// malformed quoted field before it imports as garbage.
|
|
26
40
|
const content = (await fs_extra_1.default.readFile(path, 'utf8')).replace(/^\ufeff/, '');
|
|
27
41
|
const parsed = papaparse_1.default.parse(content, {
|
|
28
42
|
header: true,
|
|
29
|
-
|
|
43
|
+
// Empty records stay in the parser output long enough to contribute to the
|
|
44
|
+
// publisher-visible spreadsheet line number, then are dropped below.
|
|
45
|
+
skipEmptyLines: false,
|
|
30
46
|
});
|
|
31
47
|
const fatal = parsed.errors.find(isFatal);
|
|
32
48
|
if (fatal) {
|
|
33
49
|
throw new errors.ValidationError({ message: `${fatal.code}: ${fatal.message}` });
|
|
34
50
|
}
|
|
35
51
|
const rows = [];
|
|
36
|
-
for (const parsedRow of parsed.data) {
|
|
52
|
+
for (const [index, parsedRow] of parsed.data.entries()) {
|
|
53
|
+
if (isEmptyRow(parsedRow)) {
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
37
56
|
const row = {};
|
|
57
|
+
const source = Object.create(null);
|
|
38
58
|
for (const [header, value] of Object.entries(parsedRow)) {
|
|
39
59
|
// non-string values are papaparse's __parsed_extra overflow from ragged rows
|
|
40
60
|
if (typeof value !== 'string') {
|
|
41
61
|
continue;
|
|
42
62
|
}
|
|
63
|
+
source[header] = value;
|
|
43
64
|
// hasOwn: a prototype-named header must not match an inherited method on the mapping
|
|
44
65
|
if (headerMapping && Object.hasOwn(headerMapping, header)) {
|
|
45
66
|
if (!headerMapping[header]) {
|
|
46
67
|
continue;
|
|
47
68
|
}
|
|
48
|
-
row[headerMapping[header]] = value;
|
|
69
|
+
row[headerMapping[header]] = (0, formula_1.stripFormulaGuard)(value);
|
|
49
70
|
}
|
|
50
71
|
else if (isSafeColumnName(header)) {
|
|
51
|
-
row[header] = value;
|
|
72
|
+
row[header] = (0, formula_1.stripFormulaGuard)(value);
|
|
52
73
|
}
|
|
53
74
|
}
|
|
54
75
|
if (!Object.keys(row).length) {
|
|
55
76
|
continue;
|
|
56
77
|
}
|
|
57
|
-
rows.push(row);
|
|
78
|
+
rows.push({ data: row, source, line: index + 2 });
|
|
58
79
|
}
|
|
59
|
-
return rows;
|
|
80
|
+
return { columns: parsed.meta.fields ?? [], rows };
|
|
60
81
|
}
|
|
@@ -0,0 +1,13 @@
|
|
|
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 = serialize;
|
|
7
|
+
const papaparse_1 = __importDefault(require("papaparse"));
|
|
8
|
+
// Import reports are opened in spreadsheets, so formula-shaped cells must never
|
|
9
|
+
// be emitted verbatim. Papa Parse prefixes them with an apostrophe when this
|
|
10
|
+
// option is enabled.
|
|
11
|
+
function serialize(rows, { columns, header = true } = {}) {
|
|
12
|
+
return papaparse_1.default.unparse(rows, { columns, header, escapeFormulae: true });
|
|
13
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PreparedAssetBatch = void 0;
|
|
4
|
+
exports.prepareAssetBatch = prepareAssetBatch;
|
|
5
|
+
exports.belongsToAssetDirectory = belongsToAssetDirectory;
|
|
6
|
+
const content_files_1 = require("../../../data/importer/content-files");
|
|
7
|
+
class PreparedAssetBatch {
|
|
8
|
+
groups;
|
|
9
|
+
constructor(groups) {
|
|
10
|
+
this.groups = groups;
|
|
11
|
+
}
|
|
12
|
+
get files() {
|
|
13
|
+
return this.groups.flatMap((group) => group.files);
|
|
14
|
+
}
|
|
15
|
+
async store() {
|
|
16
|
+
const results = await Promise.allSettled(this.groups.map((group) => group.importer.doImport(group.files)));
|
|
17
|
+
const failure = results.find((result) => result.status === 'rejected');
|
|
18
|
+
if (failure) {
|
|
19
|
+
const rollbackResults = await Promise.allSettled(results.flatMap((result, index) => result.status === 'fulfilled' ? [this.groups[index].importer.rollback(result.value)] : []));
|
|
20
|
+
const rollbackFailures = rollbackResults.flatMap((result) => result.status === 'rejected' ? [result.reason] : []);
|
|
21
|
+
if (rollbackFailures.length > 0) {
|
|
22
|
+
// AggregateError is the native error for preserving storage and rollback
|
|
23
|
+
// failures; unlike GhostError it takes an iterable before its options.
|
|
24
|
+
// eslint-disable-next-line ghost/ghost-custom/ghost-error-usage
|
|
25
|
+
throw new AggregateError([failure.reason, ...rollbackFailures], 'Asset storage failed and rollback was incomplete.', { cause: failure.reason });
|
|
26
|
+
}
|
|
27
|
+
throw failure.reason;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
rewriteRows(rows) {
|
|
31
|
+
const importData = {
|
|
32
|
+
data: { data: { posts: rows, tags: [], users: [] } },
|
|
33
|
+
};
|
|
34
|
+
for (const group of this.groups) {
|
|
35
|
+
importData[group.type] = group.files;
|
|
36
|
+
group.importer.preProcess(importData);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
exports.PreparedAssetBatch = PreparedAssetBatch;
|
|
41
|
+
async function prepareAssetBatch(archive, directory, baseDirectory, deps = {}) {
|
|
42
|
+
const handlers = deps.handlers ?? (0, content_files_1.createContentFileHandlers)();
|
|
43
|
+
const importers = deps.importers ?? (0, content_files_1.createContentFileImporters)();
|
|
44
|
+
const importerByType = new Map(importers.map((importer) => [importer.type, importer]));
|
|
45
|
+
const groups = await Promise.all(handlers.map(async (handler) => {
|
|
46
|
+
const files = archive
|
|
47
|
+
.getFiles(directory, handler.extensions)
|
|
48
|
+
.filter((file) => belongsToAssetDirectory(file.name, handler.type, baseDirectory));
|
|
49
|
+
if (files.length === 0) {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
const importer = importerByType.get(handler.type);
|
|
53
|
+
if (!importer) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
return {
|
|
57
|
+
type: handler.type,
|
|
58
|
+
files: await handler.loadFile(files, baseDirectory),
|
|
59
|
+
importer,
|
|
60
|
+
};
|
|
61
|
+
}));
|
|
62
|
+
const presentGroups = groups.filter((group) => group !== undefined);
|
|
63
|
+
return presentGroups.length > 0 ? new PreparedAssetBatch(presentGroups) : undefined;
|
|
64
|
+
}
|
|
65
|
+
function belongsToAssetDirectory(fileName, type, baseDirectory) {
|
|
66
|
+
const parts = fileName.split('/').filter(Boolean);
|
|
67
|
+
if (baseDirectory && parts[0] === baseDirectory) {
|
|
68
|
+
parts.shift();
|
|
69
|
+
}
|
|
70
|
+
if (parts[0] === 'content') {
|
|
71
|
+
parts.shift();
|
|
72
|
+
}
|
|
73
|
+
return parts.length > 1 && parts[0] === type;
|
|
74
|
+
}
|