ghost 5.115.0 → 5.116.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/components/{tryghost-api-framework-5.115.0.tgz → tryghost-api-framework-5.116.0.tgz} +0 -0
- package/components/tryghost-constants-5.116.0.tgz +0 -0
- package/components/tryghost-custom-fonts-5.116.0.tgz +0 -0
- package/components/{tryghost-custom-theme-settings-service-5.115.0.tgz → tryghost-custom-theme-settings-service-5.116.0.tgz} +0 -0
- package/components/tryghost-domain-events-5.116.0.tgz +0 -0
- package/components/{tryghost-donations-5.115.0.tgz → tryghost-donations-5.116.0.tgz} +0 -0
- package/components/tryghost-email-addresses-5.116.0.tgz +0 -0
- package/components/tryghost-email-service-5.116.0.tgz +0 -0
- package/components/tryghost-email-suppression-list-5.116.0.tgz +0 -0
- package/components/tryghost-html-to-plaintext-5.116.0.tgz +0 -0
- package/components/tryghost-i18n-5.116.0.tgz +0 -0
- package/components/tryghost-job-manager-5.116.0.tgz +0 -0
- package/components/tryghost-link-replacer-5.116.0.tgz +0 -0
- package/components/tryghost-magic-link-5.116.0.tgz +0 -0
- package/components/tryghost-member-attribution-5.116.0.tgz +0 -0
- package/components/tryghost-member-events-5.116.0.tgz +0 -0
- package/components/tryghost-members-api-5.116.0.tgz +0 -0
- package/components/tryghost-members-csv-5.116.0.tgz +0 -0
- package/components/{tryghost-members-offers-5.115.0.tgz → tryghost-members-offers-5.116.0.tgz} +0 -0
- package/components/{tryghost-milestones-5.115.0.tgz → tryghost-milestones-5.116.0.tgz} +0 -0
- package/components/{tryghost-mw-error-handler-5.115.0.tgz → tryghost-mw-error-handler-5.116.0.tgz} +0 -0
- package/components/tryghost-mw-vhost-5.116.0.tgz +0 -0
- package/components/{tryghost-post-events-5.115.0.tgz → tryghost-post-events-5.116.0.tgz} +0 -0
- package/components/{tryghost-post-revisions-5.115.0.tgz → tryghost-post-revisions-5.116.0.tgz} +0 -0
- package/components/tryghost-posts-service-5.116.0.tgz +0 -0
- package/components/{tryghost-prometheus-metrics-5.115.0.tgz → tryghost-prometheus-metrics-5.116.0.tgz} +0 -0
- package/components/tryghost-security-5.116.0.tgz +0 -0
- package/components/{tryghost-tiers-5.115.0.tgz → tryghost-tiers-5.116.0.tgz} +0 -0
- package/components/tryghost-webmentions-5.116.0.tgz +0 -0
- package/content/themes/casper/LICENSE +1 -1
- package/content/themes/casper/README.md +1 -1
- package/content/themes/source/LICENSE +1 -1
- package/content/themes/source/README.md +1 -1
- package/content/themes/source/assets/built/screen.css +1 -1
- package/content/themes/source/assets/built/screen.css.map +1 -1
- package/content/themes/source/assets/css/screen.css +11 -6
- package/content/themes/source/partials/feature-image.hbs +2 -2
- package/core/boot.js +3 -43
- package/core/built/admin/assets/admin-x-activitypub/admin-x-activitypub.js +30494 -29403
- package/core/built/admin/assets/admin-x-demo/admin-x-demo.js +1 -1
- package/core/built/admin/assets/admin-x-demo/{index-0040480a.mjs → index-a9601514.mjs} +5 -4
- package/core/built/admin/assets/admin-x-demo/{modals-fb35c86c.mjs → modals-c1789d04.mjs} +67 -65
- package/core/built/admin/assets/admin-x-settings/{CodeEditorView-806ef39c.mjs → CodeEditorView-e9c9deb8.mjs} +2 -2
- package/core/built/admin/assets/admin-x-settings/admin-x-settings.js +2 -2
- package/core/built/admin/assets/admin-x-settings/{index-376f847c.mjs → index-84580c3a.mjs} +2 -2
- package/core/built/admin/assets/admin-x-settings/{index-8fa19303.mjs → index-f744cab7.mjs} +3147 -3123
- package/core/built/admin/assets/admin-x-settings/{modals-36775d71.mjs → modals-d9ca60c5.mjs} +1198 -1192
- package/core/built/admin/assets/chunk.524.8371443ef8f60db429d0.js +35 -0
- package/core/built/admin/assets/chunk.582.f90151775f2e53dd21d9.js +37 -0
- package/core/built/admin/assets/{chunk.874.461cb3cf5b6b36915f8c.js → chunk.713.e9027c0cc3c56110f5da.js} +125 -98
- package/core/built/admin/assets/{ghost-938b3d9c29e3564a53a22f8c8f82d351.js → ghost-03b64c086f3c60cabc85fe7a7e2b640a.js} +272 -251
- package/core/built/admin/assets/ghost-ba58e9822f7384461e926c7e23f04a75.css +1 -0
- package/core/built/admin/assets/ghost-dark-f1f29683b14ffa11615b3bba8b6ab92c.css +1 -0
- package/core/built/admin/assets/koenig-lexical/index.css +1 -1
- package/core/built/admin/assets/koenig-lexical/koenig-lexical.js +20563 -20891
- package/core/built/admin/assets/koenig-lexical/koenig-lexical.umd.js +139 -139
- package/core/built/admin/assets/posts/posts.js +5732 -5667
- package/core/built/admin/assets/stats/stats.js +75373 -0
- package/core/built/admin/assets/{vendor-68a4aa424a179a90f5bbc2b750def576.js → vendor-72026232b36d97babc6320917c16c321.js} +36 -34
- package/core/built/admin/index.html +6 -6
- package/core/cli/generate-data.js +1 -1
- package/core/frontend/helpers/ghost_head.js +8 -1
- package/core/frontend/public/ghost-stats.js +55 -2
- package/core/frontend/services/assets-minification/AdminAuthAssets.js +2 -1
- package/core/frontend/services/assets-minification/CardAssets.js +1 -1
- package/core/frontend/services/assets-minification/CommentCountsAssets.js +1 -1
- package/core/frontend/services/assets-minification/MemberAttributionAssets.js +1 -1
- package/core/frontend/services/assets-minification/Minifier.js +191 -0
- package/core/frontend/services/routing/controllers/previews.js +2 -1
- package/core/frontend/src/cards/css/cta.css +1 -1
- package/core/server/adapters/cache/Redis.js +1 -1
- package/core/server/adapters/lib/redis/AdapterCacheRedis.js +287 -0
- package/core/server/adapters/lib/redis/redis-store-factory.js +22 -0
- package/core/server/api/endpoints/posts.js +9 -3
- package/core/server/api/endpoints/previews.js +35 -1
- package/core/server/api/endpoints/slugs.js +6 -2
- package/core/server/api/endpoints/utils/serializers/output/utils/post-gating.js +6 -9
- package/core/server/api/endpoints/utils/validators/input/settings.js +1 -1
- package/core/server/data/db/connection.js +2 -0
- package/core/server/data/db/index.js +1 -0
- package/core/server/data/importer/handlers/ImporterContentFileHandler.js +90 -0
- package/core/server/data/importer/import-manager.js +3 -3
- package/core/server/data/importer/importers/importer-revue.js +128 -0
- package/core/server/data/importer/importers/json-to-html.js +107 -0
- package/core/server/data/migrations/utils/tables.js +2 -4
- package/core/server/data/seeders/DataGenerator.js +288 -0
- package/core/server/data/seeders/importers/BenefitsImporter.js +28 -0
- package/core/server/data/seeders/importers/CommentsImporter.js +73 -0
- package/core/server/data/seeders/importers/EmailBatchesImporter.js +38 -0
- package/core/server/data/seeders/importers/EmailRecipientFailuresImporter.js +67 -0
- package/core/server/data/seeders/importers/EmailRecipientsImporter.js +212 -0
- package/core/server/data/seeders/importers/EmailsImporter.js +99 -0
- package/core/server/data/seeders/importers/LabelsImporter.js +41 -0
- package/core/server/data/seeders/importers/MembersClickEventsImporter.js +69 -0
- package/core/server/data/seeders/importers/MembersCreatedEventsImporter.js +103 -0
- package/core/server/data/seeders/importers/MembersFeedbackImporter.js +45 -0
- package/core/server/data/seeders/importers/MembersImporter.js +111 -0
- package/core/server/data/seeders/importers/MembersLabelsImporter.js +39 -0
- package/core/server/data/seeders/importers/MembersLoginEventsImporter.js +69 -0
- package/core/server/data/seeders/importers/MembersNewslettersImporter.js +38 -0
- package/core/server/data/seeders/importers/MembersPaidSubscriptionEventsImporter.js +99 -0
- package/core/server/data/seeders/importers/MembersProductsImporter.js +42 -0
- package/core/server/data/seeders/importers/MembersStatusEventsImporter.js +58 -0
- package/core/server/data/seeders/importers/MembersStripeCustomersImporter.js +60 -0
- package/core/server/data/seeders/importers/MembersStripeCustomersSubscriptionsImporter.js +259 -0
- package/core/server/data/seeders/importers/MembersSubscribeEventsImporter.js +69 -0
- package/core/server/data/seeders/importers/MembersSubscriptionCreatedEventsImporter.js +95 -0
- package/core/server/data/seeders/importers/NewslettersImporter.js +40 -0
- package/core/server/data/seeders/importers/OffersImporter.js +70 -0
- package/core/server/data/seeders/importers/PostsAuthorsImporter.js +32 -0
- package/core/server/data/seeders/importers/PostsImporter.js +102 -0
- package/core/server/data/seeders/importers/PostsProductsImporter.js +35 -0
- package/core/server/data/seeders/importers/PostsTagsImporter.js +46 -0
- package/core/server/data/seeders/importers/ProductsBenefitsImporter.js +54 -0
- package/core/server/data/seeders/importers/ProductsImporter.js +90 -0
- package/core/server/data/seeders/importers/RecommendationClickEventsImporter.js +32 -0
- package/core/server/data/seeders/importers/RecommendationSubscribeEventsImporter.js +32 -0
- package/core/server/data/seeders/importers/RecommendationsImporter.js +34 -0
- package/core/server/data/seeders/importers/RedirectsImporter.js +49 -0
- package/core/server/data/seeders/importers/RolesUsersImporter.js +42 -0
- package/core/server/data/seeders/importers/StripePricesImporter.js +69 -0
- package/core/server/data/seeders/importers/StripeProductsImporter.js +34 -0
- package/core/server/data/seeders/importers/TableImporter.js +187 -0
- package/core/server/data/seeders/importers/TagsImporter.js +41 -0
- package/core/server/data/seeders/importers/UsersImporter.js +31 -0
- package/core/server/data/seeders/importers/WebMentionsImporter.js +42 -0
- package/core/server/data/seeders/importers/index.js +41 -0
- package/core/server/data/seeders/utils/JsonImporter.js +39 -0
- package/core/server/data/seeders/utils/blog-info.js +3 -0
- package/core/server/data/seeders/utils/database-date.js +7 -0
- package/core/server/data/seeders/utils/event-generator.js +48 -0
- package/core/server/data/seeders/utils/random.js +13 -0
- package/core/server/data/seeders/utils/topological-sort.js +33 -0
- package/core/server/lib/bootstrap-socket.js +87 -0
- package/core/server/lib/package-json/index.js +1 -0
- package/core/server/lib/package-json/package-json.js +160 -0
- package/core/server/lib/package-json/parse.js +57 -0
- package/core/server/models/base/plugins/actions.js +44 -31
- package/core/server/models/base/plugins/generate-slug.js +6 -0
- package/core/server/notify.js +1 -1
- package/core/server/services/activitypub/ActivityPubService.ts +1 -1
- package/core/server/services/adapter-manager/AdapterManager.js +161 -0
- package/core/server/services/adapter-manager/index.js +1 -1
- package/core/server/services/announcement-bar-service/AnnouncementBarSettings.js +54 -0
- package/core/server/services/announcement-bar-service/AnnouncementVisibilityValues.js +11 -0
- package/core/server/services/announcement-bar-service/index.js +1 -1
- package/core/server/services/api-version-compatibility/APIVersionCompatibilityService.js +99 -0
- package/core/server/services/api-version-compatibility/VersionNotificationsDataService.js +80 -0
- package/core/server/services/api-version-compatibility/extract-api-key.js +57 -0
- package/core/server/services/api-version-compatibility/index.js +2 -2
- package/core/server/services/api-version-compatibility/mw-api-version-mismatch.js +31 -0
- package/core/server/services/audience-feedback/AudienceFeedbackController.js +85 -0
- package/core/server/services/audience-feedback/AudienceFeedbackService.js +34 -0
- package/core/server/services/audience-feedback/Feedback.js +35 -0
- package/core/server/services/audience-feedback/index.js +4 -2
- package/core/server/services/auth/session/emails/signin.js +168 -0
- package/core/server/services/auth/session/index.js +2 -2
- package/core/server/services/auth/session/session-from-token.js +69 -0
- package/core/server/services/auth/session/session-service.js +374 -0
- package/core/server/services/custom-redirects/index.js +1 -1
- package/core/server/services/email-analytics/EmailAnalyticsProviderMailgun.js +62 -0
- package/core/server/services/email-analytics/EmailAnalyticsService.js +552 -0
- package/core/server/services/email-analytics/EmailAnalyticsServiceWrapper.js +3 -3
- package/core/server/services/email-analytics/EventProcessingResult.js +66 -0
- package/core/server/services/email-service/EmailServiceWrapper.js +4 -4
- package/core/server/services/email-suppression-list/MailgunEmailSuppressionList.js +1 -1
- package/core/server/services/email-suppression-list/service.js +1 -1
- package/core/server/services/explore-ping/ExplorePingService.js +106 -0
- package/core/server/services/explore-ping/index.js +31 -0
- package/core/server/services/identity-tokens/IdentityTokenService.js +30 -0
- package/core/server/services/identity-tokens/IdentityTokenService.ts +28 -0
- package/core/server/services/identity-tokens/IdentityTokenServiceWrapper.js +1 -1
- package/core/server/services/invitations/accept.js +5 -2
- package/core/server/services/lib/DynamicRedirectManager.js +156 -0
- package/core/server/services/lib/EmailContentGenerator.js +54 -0
- package/core/server/services/lib/InMemoryRepository.js +62 -0
- package/core/server/services/lib/InMemoryRepository.ts +80 -0
- package/core/server/services/lib/MailgunClient.js +364 -0
- package/core/server/services/link-redirection/LinkRedirect.js +26 -0
- package/core/server/services/link-redirection/LinkRedirectRepository.js +7 -7
- package/core/server/services/link-redirection/LinkRedirectsService.js +123 -0
- package/core/server/services/link-redirection/README.md +151 -0
- package/core/server/services/link-redirection/RedirectEvent.js +24 -0
- package/core/server/services/link-redirection/index.js +1 -1
- package/core/server/services/link-tracking/LinkClickTrackingService.js +1 -1
- package/core/server/services/mail/index.js +1 -1
- package/core/server/services/mail-events/BookshelfMailEventRepository.js +2 -2
- package/core/server/services/mail-events/InMemoryMailEventRepository.js +10 -0
- package/core/server/services/mail-events/InMemoryMailEventRepository.ts +8 -0
- package/core/server/services/mail-events/MailEvent.js +20 -0
- package/core/server/services/mail-events/MailEvent.ts +10 -0
- package/core/server/services/mail-events/MailEventRepository.js +2 -0
- package/core/server/services/mail-events/MailEventRepository.ts +5 -0
- package/core/server/services/mail-events/MailEventService.js +124 -0
- package/core/server/services/mail-events/MailEventService.ts +169 -0
- package/core/server/services/mail-events/index.js +1 -1
- package/core/server/services/mail-events/libraries.d.ts +2 -0
- package/core/server/services/members/CaptchaService.js +80 -0
- package/core/server/services/members/api.js +1 -1
- package/core/server/services/members/importer/MembersCSVImporter.js +464 -0
- package/core/server/services/members/importer/MembersCSVImporterStripeUtils.js +194 -0
- package/core/server/services/members/importer/email-template.js +182 -0
- package/core/server/services/members/importer/index.js +30 -0
- package/core/server/services/members/members-ssr.js +333 -0
- package/core/server/services/members/service.js +2 -2
- package/core/server/services/members-events/LastSeenAtUpdater.js +1 -1
- package/core/server/services/offers/service.js +1 -1
- package/core/server/services/posts/stats/PostStats.js +13 -0
- package/core/server/services/recommendations/RecommendationServiceWrapper.js +8 -8
- package/core/server/services/recommendations/service/BookshelfClickEventRepository.js +48 -0
- package/core/server/services/recommendations/service/BookshelfClickEventRepository.ts +49 -0
- package/core/server/services/recommendations/service/BookshelfRecommendationRepository.js +98 -0
- package/core/server/services/recommendations/service/BookshelfRecommendationRepository.ts +117 -0
- package/core/server/services/recommendations/service/BookshelfRepository.js +134 -0
- package/core/server/services/recommendations/service/BookshelfRepository.ts +196 -0
- package/core/server/services/recommendations/service/BookshelfSubscribeEventRepository.js +48 -0
- package/core/server/services/recommendations/service/BookshelfSubscribeEventRepository.ts +49 -0
- package/core/server/services/recommendations/service/ClickEvent.js +33 -0
- package/core/server/services/recommendations/service/ClickEvent.ts +32 -0
- package/core/server/services/recommendations/service/InMemoryRecommendationRepository.js +19 -0
- package/core/server/services/recommendations/service/InMemoryRecommendationRepository.ts +20 -0
- package/core/server/services/recommendations/service/IncomingRecommendationController.js +34 -0
- package/core/server/services/recommendations/service/IncomingRecommendationController.ts +51 -0
- package/core/server/services/recommendations/service/IncomingRecommendationEmailRenderer.js +25 -0
- package/core/server/services/recommendations/service/IncomingRecommendationEmailRenderer.ts +37 -0
- package/core/server/services/recommendations/service/IncomingRecommendationService.js +93 -0
- package/core/server/services/recommendations/service/IncomingRecommendationService.ts +160 -0
- package/core/server/services/recommendations/service/Recommendation.js +140 -0
- package/core/server/services/recommendations/service/Recommendation.ts +201 -0
- package/core/server/services/recommendations/service/RecommendationController.js +208 -0
- package/core/server/services/recommendations/service/RecommendationController.ts +258 -0
- package/core/server/services/recommendations/service/RecommendationMetadataService.js +86 -0
- package/core/server/services/recommendations/service/RecommendationMetadataService.ts +128 -0
- package/core/server/services/recommendations/service/RecommendationRepository.js +2 -0
- package/core/server/services/recommendations/service/RecommendationRepository.ts +13 -0
- package/core/server/services/recommendations/service/RecommendationService.js +228 -0
- package/core/server/services/recommendations/service/RecommendationService.ts +281 -0
- package/core/server/services/recommendations/service/SubscribeEvent.js +33 -0
- package/core/server/services/recommendations/service/SubscribeEvent.ts +32 -0
- package/core/server/services/recommendations/service/UnsafeData.js +183 -0
- package/core/server/services/recommendations/service/UnsafeData.ts +217 -0
- package/core/server/services/recommendations/service/WellknownService.js +36 -0
- package/core/server/services/recommendations/service/WellknownService.ts +47 -0
- package/core/server/services/recommendations/service/index.js +31 -0
- package/core/server/services/recommendations/service/index.ts +15 -0
- package/core/server/services/recommendations/service/libraries.d.ts +5 -0
- package/core/server/services/route-settings/SettingsPathManager.js +47 -0
- package/core/server/services/route-settings/index.js +1 -1
- package/core/server/services/slack-notifications/SlackNotifications.js +211 -0
- package/core/server/services/slack-notifications/SlackNotificationsService.js +90 -0
- package/core/server/services/slack-notifications/service.js +4 -6
- package/core/server/services/stripe/README.md +63 -0
- package/core/server/services/stripe/StripeAPI.js +931 -0
- package/core/server/services/stripe/StripeMigrations.js +613 -0
- package/core/server/services/stripe/StripeService.js +175 -0
- package/core/server/services/stripe/WebhookController.js +100 -0
- package/core/server/services/stripe/WebhookManager.js +175 -0
- package/core/server/services/stripe/events/StripeLiveDisabledEvent.js +23 -0
- package/core/server/services/stripe/events/StripeLiveEnabledEvent.js +23 -0
- package/core/server/services/stripe/events/index.js +4 -0
- package/core/server/services/stripe/service.js +1 -1
- package/core/server/services/stripe/services/webhook/CheckoutSessionEventService.js +255 -0
- package/core/server/services/stripe/services/webhook/InvoiceEventService.js +70 -0
- package/core/server/services/stripe/services/webhook/SubscriptionEventService.js +54 -0
- package/core/server/services/themes/loader.js +1 -1
- package/core/server/services/themes/to-json.js +1 -1
- package/core/server/web/api/endpoints/admin/app.js +1 -21
- package/core/server/web/api/endpoints/admin/routes.js +1 -0
- package/core/server/web/api/middleware/version-match.js +41 -0
- package/core/server/web/shared/middleware/cache-control.js +51 -0
- package/core/server/web/shared/middleware/index.js +1 -1
- package/core/server/web/well-known.js +1 -1
- package/core/shared/labs.js +5 -3
- package/core/shared/settings-cache/CacheManager.js +64 -6
- package/package.json +98 -146
- package/tsconfig.tsbuildinfo +1 -1
- package/yarn.lock +1478 -1634
- package/components/tryghost-adapter-cache-redis-5.115.0.tgz +0 -0
- package/components/tryghost-adapter-manager-5.115.0.tgz +0 -0
- package/components/tryghost-announcement-bar-settings-5.115.0.tgz +0 -0
- package/components/tryghost-api-version-compatibility-service-5.115.0.tgz +0 -0
- package/components/tryghost-audience-feedback-5.115.0.tgz +0 -0
- package/components/tryghost-bookshelf-repository-5.115.0.tgz +0 -0
- package/components/tryghost-bootstrap-socket-5.115.0.tgz +0 -0
- package/components/tryghost-captcha-service-5.115.0.tgz +0 -0
- package/components/tryghost-constants-5.115.0.tgz +0 -0
- package/components/tryghost-custom-fonts-5.115.0.tgz +0 -0
- package/components/tryghost-data-generator-5.115.0.tgz +0 -0
- package/components/tryghost-domain-events-5.115.0.tgz +0 -0
- package/components/tryghost-email-addresses-5.115.0.tgz +0 -0
- package/components/tryghost-email-analytics-provider-mailgun-5.115.0.tgz +0 -0
- package/components/tryghost-email-analytics-service-5.115.0.tgz +0 -0
- package/components/tryghost-email-content-generator-5.115.0.tgz +0 -0
- package/components/tryghost-email-events-5.115.0.tgz +0 -0
- package/components/tryghost-email-service-5.115.0.tgz +0 -0
- package/components/tryghost-email-suppression-list-5.115.0.tgz +0 -0
- package/components/tryghost-express-dynamic-redirects-5.115.0.tgz +0 -0
- package/components/tryghost-extract-api-key-5.115.0.tgz +0 -0
- package/components/tryghost-ghost-5.115.0.tgz +0 -0
- package/components/tryghost-html-to-plaintext-5.115.0.tgz +0 -0
- package/components/tryghost-i18n-5.115.0.tgz +0 -0
- package/components/tryghost-identity-token-service-5.115.0.tgz +0 -0
- package/components/tryghost-importer-handler-content-files-5.115.0.tgz +0 -0
- package/components/tryghost-importer-revue-5.115.0.tgz +0 -0
- package/components/tryghost-in-memory-repository-5.115.0.tgz +0 -0
- package/components/tryghost-job-manager-5.115.0.tgz +0 -0
- package/components/tryghost-link-redirects-5.115.0.tgz +0 -0
- package/components/tryghost-link-replacer-5.115.0.tgz +0 -0
- package/components/tryghost-magic-link-5.115.0.tgz +0 -0
- package/components/tryghost-mail-events-5.115.0.tgz +0 -0
- package/components/tryghost-mailgun-client-5.115.0.tgz +0 -0
- package/components/tryghost-member-attribution-5.115.0.tgz +0 -0
- package/components/tryghost-member-events-5.115.0.tgz +0 -0
- package/components/tryghost-members-api-5.115.0.tgz +0 -0
- package/components/tryghost-members-csv-5.115.0.tgz +0 -0
- package/components/tryghost-members-importer-5.115.0.tgz +0 -0
- package/components/tryghost-members-payments-5.115.0.tgz +0 -0
- package/components/tryghost-members-ssr-5.115.0.tgz +0 -0
- package/components/tryghost-members-stripe-service-5.115.0.tgz +0 -0
- package/components/tryghost-minifier-5.115.0.tgz +0 -0
- package/components/tryghost-mw-api-version-mismatch-5.115.0.tgz +0 -0
- package/components/tryghost-mw-cache-control-5.115.0.tgz +0 -0
- package/components/tryghost-mw-session-from-token-5.115.0.tgz +0 -0
- package/components/tryghost-mw-update-user-last-seen-5.115.0.tgz +0 -0
- package/components/tryghost-mw-version-match-5.115.0.tgz +0 -0
- package/components/tryghost-mw-vhost-5.115.0.tgz +0 -0
- package/components/tryghost-package-json-5.115.0.tgz +0 -0
- package/components/tryghost-posts-service-5.115.0.tgz +0 -0
- package/components/tryghost-recommendations-5.115.0.tgz +0 -0
- package/components/tryghost-referrers-5.115.0.tgz +0 -0
- package/components/tryghost-security-5.115.0.tgz +0 -0
- package/components/tryghost-session-service-5.115.0.tgz +0 -0
- package/components/tryghost-settings-path-manager-5.115.0.tgz +0 -0
- package/components/tryghost-slack-notifications-5.115.0.tgz +0 -0
- package/components/tryghost-version-notifications-data-service-5.115.0.tgz +0 -0
- package/components/tryghost-webmentions-5.115.0.tgz +0 -0
- package/core/built/admin/assets/chunk.524.31419fdf6fb3859ecc1e.js +0 -35
- package/core/built/admin/assets/chunk.582.08c816d5e4ab766486a7.js +0 -37
- package/core/built/admin/assets/ghost-c2a7c4a1b76550c4219adb2ed4124ce0.css +0 -1
- package/core/built/admin/assets/ghost-dark-f91e4a479c6d38d94d5d1b14727871dc.css +0 -1
- /package/core/built/admin/assets/{chunk.874.461cb3cf5b6b36915f8c.js.LICENSE.txt → chunk.713.e9027c0cc3c56110f5da.js.LICENSE.txt} +0 -0
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
function formatNumber(number) {
|
|
2
|
+
return number.toLocaleString();
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
const iff = (cond, yes, no) => (cond ? yes : no);
|
|
6
|
+
module.exports = ({result, siteUrl, membersUrl, emailRecipient}) => `
|
|
7
|
+
<!doctype html>
|
|
8
|
+
<html>
|
|
9
|
+
<head>
|
|
10
|
+
<meta name="viewport" content="width=device-width">
|
|
11
|
+
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
|
12
|
+
<title>Your member import is complete</title>
|
|
13
|
+
<style>
|
|
14
|
+
/* -------------------------------------
|
|
15
|
+
RESPONSIVE AND MOBILE FRIENDLY STYLES
|
|
16
|
+
------------------------------------- */
|
|
17
|
+
@media only screen and (max-width: 620px) {
|
|
18
|
+
table[class=body] h1 {
|
|
19
|
+
font-size: 28px !important;
|
|
20
|
+
margin-bottom: 10px !important;
|
|
21
|
+
}
|
|
22
|
+
table[class=body] p,
|
|
23
|
+
table[class=body] ul,
|
|
24
|
+
table[class=body] ol,
|
|
25
|
+
table[class=body] td,
|
|
26
|
+
table[class=body] span,
|
|
27
|
+
table[class=body] a {
|
|
28
|
+
font-size: 16px !important;
|
|
29
|
+
}
|
|
30
|
+
table[class=body] .title {
|
|
31
|
+
font-size: 22px !important;
|
|
32
|
+
}
|
|
33
|
+
table[class=body] .wrapper,
|
|
34
|
+
table[class=body] .article {
|
|
35
|
+
padding: 10px !important;
|
|
36
|
+
}
|
|
37
|
+
table[class=body] .content {
|
|
38
|
+
padding: 0 !important;
|
|
39
|
+
}
|
|
40
|
+
table[class=body] .container {
|
|
41
|
+
padding: 0 !important;
|
|
42
|
+
width: 100% !important;
|
|
43
|
+
}
|
|
44
|
+
table[class=body] .main {
|
|
45
|
+
border-left-width: 0 !important;
|
|
46
|
+
border-radius: 0 !important;
|
|
47
|
+
border-right-width: 0 !important;
|
|
48
|
+
}
|
|
49
|
+
table[class=body] .btn table {
|
|
50
|
+
width: 100% !important;
|
|
51
|
+
}
|
|
52
|
+
table[class=body] .btn a {
|
|
53
|
+
width: 100% !important;
|
|
54
|
+
}
|
|
55
|
+
table[class=body] .img-responsive {
|
|
56
|
+
height: auto !important;
|
|
57
|
+
max-width: 100% !important;
|
|
58
|
+
width: auto !important;
|
|
59
|
+
}
|
|
60
|
+
table[class=body] p[class=small],
|
|
61
|
+
table[class=body] a[class=small] {
|
|
62
|
+
font-size: 12x !important;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
/* -------------------------------------
|
|
66
|
+
PRESERVE THESE STYLES IN THE HEAD
|
|
67
|
+
------------------------------------- */
|
|
68
|
+
@media all {
|
|
69
|
+
.ExternalClass {
|
|
70
|
+
width: 100%;
|
|
71
|
+
}
|
|
72
|
+
.ExternalClass,
|
|
73
|
+
.ExternalClass p,
|
|
74
|
+
.ExternalClass span,
|
|
75
|
+
.ExternalClass font,
|
|
76
|
+
.ExternalClass td,
|
|
77
|
+
.ExternalClass div {
|
|
78
|
+
line-height: 100%;
|
|
79
|
+
}
|
|
80
|
+
.recipient-link a {
|
|
81
|
+
color: inherit !important;
|
|
82
|
+
font-family: inherit !important;
|
|
83
|
+
font-size: inherit !important;
|
|
84
|
+
font-weight: inherit !important;
|
|
85
|
+
line-height: inherit !important;
|
|
86
|
+
text-decoration: none !important;
|
|
87
|
+
}
|
|
88
|
+
#MessageViewBody a {
|
|
89
|
+
color: inherit;
|
|
90
|
+
text-decoration: none;
|
|
91
|
+
font-size: inherit;
|
|
92
|
+
font-family: inherit;
|
|
93
|
+
font-weight: inherit;
|
|
94
|
+
line-height: inherit;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
hr {
|
|
98
|
+
border-width: 0;
|
|
99
|
+
height: 0;
|
|
100
|
+
margin-top: 34px;
|
|
101
|
+
margin-bottom: 34px;
|
|
102
|
+
border-bottom-width: 1px;
|
|
103
|
+
border-bottom-color: #EEF5F8;
|
|
104
|
+
}
|
|
105
|
+
a {
|
|
106
|
+
color: #3A464C;
|
|
107
|
+
}
|
|
108
|
+
</style>
|
|
109
|
+
</head>
|
|
110
|
+
<body class="" style="background-color: #ffffff; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; -webkit-font-smoothing: antialiased; font-size: 14px; line-height: 1.5em; margin: 0; padding: 0; -ms-text-size-adjust: 100%; -webkit-text-size-adjust: 100%;">
|
|
111
|
+
<table border="0" cellpadding="0" cellspacing="0" class="body" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%;">
|
|
112
|
+
<tr>
|
|
113
|
+
<td style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 14px; vertical-align: top;"> </td>
|
|
114
|
+
<td class="container" style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 14px; vertical-align: top; display: block; Margin: 0 auto; max-width: 540px; padding: 10px; width: 540px;">
|
|
115
|
+
<div class="content" style="box-sizing: border-box; display: block; Margin: 0 auto; max-width: 600px; padding: 30px 20px;">
|
|
116
|
+
|
|
117
|
+
<!-- START CENTERED CONTAINER -->
|
|
118
|
+
<span class="preheader" style="color: transparent; display: none; height: 0; max-height: 0; max-width: 0; opacity: 0; overflow: hidden; mso-hide: all; visibility: hidden; width: 0;">Your member import is complete</span>
|
|
119
|
+
<table class="main" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%; background: #ffffff; border-radius: 8px;">
|
|
120
|
+
|
|
121
|
+
<!-- START MAIN CONTENT AREA -->
|
|
122
|
+
<tr>
|
|
123
|
+
<td class="wrapper" style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 14px; vertical-align: top; box-sizing: border-box;">
|
|
124
|
+
<table border="0" cellpadding="0" cellspacing="0" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%;">
|
|
125
|
+
<tr>
|
|
126
|
+
<td align="center" style="padding-top: 20px; padding-bottom: 12px;"><img src="https://static.ghost.org/v4.0.0/images/ghost-orb-4.png" width="60" height="60" style="width: 60px; height: 60px;" /></td>
|
|
127
|
+
</tr>
|
|
128
|
+
<tr>
|
|
129
|
+
<td style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; vertical-align: top;">
|
|
130
|
+
<p class="title" style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 21px; color: #3A464C; font-weight: normal; line-height: 25px; margin-bottom: 30px; margin-top: 50px; font-weight: 600; color: #15212A;">${iff(result.imported > 0, `Your member import is complete`, `Your member import was unsuccessful`)}</p>
|
|
131
|
+
</td>
|
|
132
|
+
</tr>
|
|
133
|
+
${iff(result.imported === 0 && result.errors.length === 0, `
|
|
134
|
+
<tr>
|
|
135
|
+
<td style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 14px; vertical-align: top; padding-bottom: 16px;">
|
|
136
|
+
<p style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; color: #3A464C; font-weight: normal; margin: 0; line-height: 25px; margin-bottom: 0px;">No members were added.</p>
|
|
137
|
+
</td>
|
|
138
|
+
</tr>
|
|
139
|
+
`, ``)}
|
|
140
|
+
${iff(result.imported > 0, `
|
|
141
|
+
<tr>
|
|
142
|
+
<td style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 14px; vertical-align: top; padding-bottom: 16px;">
|
|
143
|
+
<p style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; color: #3A464C; font-weight: normal; margin: 0; line-height: 25px; margin-bottom: 0px;">A total of <strong style="font-weight: 600;">${formatNumber(result.imported)}</strong> ${iff(result.imported === 1, 'person', 'people')} were successfully added or updated in your list of members, and now have access to your site.</p>
|
|
144
|
+
</td>
|
|
145
|
+
</tr>`, ``)}
|
|
146
|
+
${iff(result.errors.length > 0, `
|
|
147
|
+
<tr>
|
|
148
|
+
<td style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 14px; vertical-align: top; padding-bottom: 16px;">
|
|
149
|
+
<p style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; color: #3A464C; font-weight: normal; margin: 0; line-height: 25px; margin-bottom: 0px;">
|
|
150
|
+
${iff(result.imported === 0, `No members were added.`, `<strong style="font-weight: 600;">${formatNumber(result.errors.length)}</strong> ${iff(result.errors.length === 1, `member was`, `members were`)} skipped due to errors.`)} There's a validated CSV file attached to this email with the list of errors so that you can fix them and re-upload the CSV to complete the import.</p>
|
|
151
|
+
</td>
|
|
152
|
+
</tr>`, '')}
|
|
153
|
+
<tr>
|
|
154
|
+
<td style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 14px; vertical-align: top; padding-bottom: 12px; padding-top: 16px;">
|
|
155
|
+
<a href="${membersUrl.href}" target="_blank" style="display: inline-block; color: #ffffff; background-color: #15212A; border: solid 1px #15212A; border-radius: 5px; box-sizing: border-box; cursor: pointer; text-decoration: none; font-size: 16px; font-weight: normal; margin: 0; padding: 9px 22px 10px; border-color: #15212A;">${iff(result.imported > 0, `View members`, `Try again`)}</a>
|
|
156
|
+
</td>
|
|
157
|
+
</tr>
|
|
158
|
+
</table>
|
|
159
|
+
</td>
|
|
160
|
+
</tr>
|
|
161
|
+
<tr>
|
|
162
|
+
<td style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; vertical-align: top; padding-top: 80px; padding-bottom: 10px;">
|
|
163
|
+
<div class="footer">
|
|
164
|
+
<p class="small" style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; color: #738A94; font-weight: normal; margin: 0; line-height: 18px; margin-bottom: 0px; font-size: 11px;">This email was sent from <a href="${siteUrl.href}" style="color: #738A94;">${siteUrl.host}</a> to <a href="mailto:${emailRecipient}" style="color: #738A94;">${emailRecipient}</a></p>
|
|
165
|
+
</div>
|
|
166
|
+
</td>
|
|
167
|
+
</tr>
|
|
168
|
+
|
|
169
|
+
<!-- END MAIN CONTENT AREA -->
|
|
170
|
+
</table>
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
<!-- END CENTERED CONTAINER -->
|
|
174
|
+
</div>
|
|
175
|
+
</td>
|
|
176
|
+
<td style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 14px; vertical-align: top;"> </td>
|
|
177
|
+
</tr>
|
|
178
|
+
</table>
|
|
179
|
+
</body>
|
|
180
|
+
</html>
|
|
181
|
+
`;
|
|
182
|
+
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
const MembersCSVImporter = require('./MembersCSVImporter');
|
|
2
|
+
const MembersCSVImporterStripeUtils = require('./MembersCSVImporterStripeUtils');
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @typedef {import('./MembersCSVImporter').MembersCSVImporterOptions} MembersCSVImporterOptions
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @typedef {Object} MakeImporterDeps
|
|
10
|
+
* @property {Object} stripeAPIService - Instance of StripeAPIService
|
|
11
|
+
* @property {Object} productRepository - Instance of ProductRepository
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Make an instance of MembersCSVImporter
|
|
16
|
+
*
|
|
17
|
+
* @param {MakeImporterDeps & MembersCSVImporterOptions} deps
|
|
18
|
+
* @returns {MembersCSVImporter}
|
|
19
|
+
*/
|
|
20
|
+
module.exports = function makeImporter(deps) {
|
|
21
|
+
const stripeUtils = new MembersCSVImporterStripeUtils({
|
|
22
|
+
stripeAPIService: deps.stripeAPIService,
|
|
23
|
+
productRepository: deps.productRepository
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
return new MembersCSVImporter({
|
|
27
|
+
...deps,
|
|
28
|
+
stripeUtils
|
|
29
|
+
});
|
|
30
|
+
};
|
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
const {parse: parseUrl} = require('url');
|
|
2
|
+
const createCookies = require('cookies');
|
|
3
|
+
const debug = require('@tryghost/debug')('members-ssr');
|
|
4
|
+
|
|
5
|
+
const {
|
|
6
|
+
BadRequestError,
|
|
7
|
+
IncorrectUsageError
|
|
8
|
+
} = require('@tryghost/errors');
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* @typedef {import('http').IncomingMessage} Request
|
|
12
|
+
* @typedef {import('http').ServerResponse} Response
|
|
13
|
+
* @typedef {import('cookies').ICookies} Cookies
|
|
14
|
+
* @typedef {import('cookies').Option} CookiesOptions
|
|
15
|
+
* @typedef {import('cookies').SetOption} SetCookieOptions
|
|
16
|
+
* @typedef {string} JWT
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* @typedef {object} Member
|
|
21
|
+
* @prop {string} id
|
|
22
|
+
* @prop {string} transient_id
|
|
23
|
+
* @prop {string} email
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
const SIX_MONTHS_MS = 1000 * 60 * 60 * 24 * 184;
|
|
27
|
+
|
|
28
|
+
class MembersSSR {
|
|
29
|
+
/**
|
|
30
|
+
* @typedef {object} MembersSSROptions
|
|
31
|
+
*
|
|
32
|
+
* @prop {string|string[]} cookieKeys - A secret or array of secrets used to sign cookies
|
|
33
|
+
* @prop {() => object} getMembersApi - A function which returns an instance of members-api
|
|
34
|
+
* @prop {boolean} [cookieSecure = true] - Whether the cookie should have Secure flag
|
|
35
|
+
* @prop {string} [cookieName] - The name of the members-ssr cookie
|
|
36
|
+
* @prop {number} [cookieMaxAge] - The max age in ms of the members-ssr cookie
|
|
37
|
+
* @prop {string} [cookiePath] - The Path flag for the cookie
|
|
38
|
+
* @prop {boolean} [dangerousRemovalOfSignedCookie] - Flag for removing signed cookie
|
|
39
|
+
*/
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Create an instance of MembersSSR
|
|
43
|
+
*
|
|
44
|
+
* @param {MembersSSROptions} options - The options for the members ssr class
|
|
45
|
+
*/
|
|
46
|
+
constructor(options) {
|
|
47
|
+
const {
|
|
48
|
+
cookieSecure = true,
|
|
49
|
+
cookieName = 'members-ssr',
|
|
50
|
+
cookieMaxAge = SIX_MONTHS_MS,
|
|
51
|
+
cookiePath = '/',
|
|
52
|
+
cookieKeys,
|
|
53
|
+
getMembersApi,
|
|
54
|
+
dangerousRemovalOfSignedCookie
|
|
55
|
+
} = options;
|
|
56
|
+
|
|
57
|
+
if (!getMembersApi) {
|
|
58
|
+
throw new IncorrectUsageError({message: 'Missing option getMembersApi'});
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
this._getMembersApi = getMembersApi;
|
|
62
|
+
|
|
63
|
+
if (!cookieKeys) {
|
|
64
|
+
throw new IncorrectUsageError({message: 'Missing option cookieKeys'});
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
this.sessionCookieName = cookieName;
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* @type SetCookieOptions
|
|
71
|
+
*/
|
|
72
|
+
this.sessionCookieOptions = {
|
|
73
|
+
signed: true,
|
|
74
|
+
httpOnly: true,
|
|
75
|
+
sameSite: 'lax',
|
|
76
|
+
maxAge: cookieMaxAge,
|
|
77
|
+
path: cookiePath
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
if (dangerousRemovalOfSignedCookie === true) {
|
|
81
|
+
this.sessionCookieOptions.signed = false;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* @type CookiesOptions
|
|
86
|
+
*/
|
|
87
|
+
this.cookiesOptions = {
|
|
88
|
+
keys: Array.isArray(cookieKeys) ? cookieKeys : [cookieKeys],
|
|
89
|
+
secure: cookieSecure
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* @method _getCookies
|
|
95
|
+
*
|
|
96
|
+
* @param {Request} req
|
|
97
|
+
* @param {Response} res
|
|
98
|
+
*
|
|
99
|
+
* @returns {Cookies} An instance of the cookies object for current request/response
|
|
100
|
+
*/
|
|
101
|
+
_getCookies(req, res) {
|
|
102
|
+
return createCookies(req, res, this.cookiesOptions);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* @method _removeSessionCookie
|
|
107
|
+
*
|
|
108
|
+
* @param {Request} req
|
|
109
|
+
* @param {Response} res
|
|
110
|
+
*/
|
|
111
|
+
_removeSessionCookie(req, res) {
|
|
112
|
+
const cookies = this._getCookies(req, res);
|
|
113
|
+
cookies.set(this.sessionCookieName, null, this.sessionCookieOptions);
|
|
114
|
+
// If members caching cookies are set, remove them
|
|
115
|
+
if (cookies.get('ghost-access') || cookies.get('ghost-access-hmac')) {
|
|
116
|
+
cookies.set('ghost-access', null, {...this.sessionCookieOptions, signed: false});
|
|
117
|
+
cookies.set('ghost-access-hmac', null, {...this.sessionCookieOptions, signed: false});
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* @method _setSessionCookie
|
|
123
|
+
*
|
|
124
|
+
* @param {Request} req
|
|
125
|
+
* @param {Response} res
|
|
126
|
+
* @param {string} value
|
|
127
|
+
*/
|
|
128
|
+
_setSessionCookie(req, res, value) {
|
|
129
|
+
if (!value) {
|
|
130
|
+
return this._removeSessionCookie(req, res);
|
|
131
|
+
}
|
|
132
|
+
const cookies = this._getCookies(req, res);
|
|
133
|
+
cookies.set(this.sessionCookieName, value, this.sessionCookieOptions);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* @method _getSessionCookies
|
|
138
|
+
*
|
|
139
|
+
* @param {Request} req
|
|
140
|
+
* @param {Response} res
|
|
141
|
+
*
|
|
142
|
+
* @returns {string} The cookie value
|
|
143
|
+
*/
|
|
144
|
+
_getSessionCookies(req, res) {
|
|
145
|
+
const cookies = this._getCookies(req, res);
|
|
146
|
+
const value = cookies.get(this.sessionCookieName, {signed: true});
|
|
147
|
+
if (!value) {
|
|
148
|
+
throw new BadRequestError({
|
|
149
|
+
message: `Cookie ${this.sessionCookieName} not found`
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
return value;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* @method _getMemberDataFromToken
|
|
157
|
+
*
|
|
158
|
+
* @param {JWT} token
|
|
159
|
+
*
|
|
160
|
+
* @returns {Promise<Member>} member
|
|
161
|
+
*/
|
|
162
|
+
async _getMemberDataFromToken(token) {
|
|
163
|
+
const api = await this._getMembersApi();
|
|
164
|
+
return api.getMemberDataFromMagicLinkToken(token);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* @method _getMemberIdentityData
|
|
169
|
+
*
|
|
170
|
+
* @param {string} email
|
|
171
|
+
*
|
|
172
|
+
* @returns {Promise<Member>} member
|
|
173
|
+
*/
|
|
174
|
+
async _getMemberIdentityData(email) {
|
|
175
|
+
const api = await this._getMembersApi();
|
|
176
|
+
return api.getMemberIdentityData(email);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* @method _getMemberIdentityData
|
|
181
|
+
*
|
|
182
|
+
* @param {string} transientId
|
|
183
|
+
*
|
|
184
|
+
* @returns {Promise<Member>} member
|
|
185
|
+
*/
|
|
186
|
+
async _getMemberIdentityDataFromTransientId(transientId) {
|
|
187
|
+
const api = await this._getMembersApi();
|
|
188
|
+
return api.getMemberIdentityDataFromTransientId(transientId);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* @method _getMemberIdentityToken
|
|
193
|
+
*
|
|
194
|
+
* @param {string} email
|
|
195
|
+
*
|
|
196
|
+
* @returns {Promise<JWT>} member
|
|
197
|
+
*/
|
|
198
|
+
async _getMemberIdentityToken(transientId) {
|
|
199
|
+
const api = await this._getMembersApi();
|
|
200
|
+
return api.getMemberIdentityToken(transientId);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* @method _setMemberGeolocationFromIp
|
|
205
|
+
* @param {string} email
|
|
206
|
+
* @param {string} ip
|
|
207
|
+
*
|
|
208
|
+
* @returns {Promise<Member>} member
|
|
209
|
+
*/
|
|
210
|
+
async _setMemberGeolocationFromIp(email, ip) {
|
|
211
|
+
const api = await this._getMembersApi();
|
|
212
|
+
return api.setMemberGeolocationFromIp(email, ip);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* @method exchangeTokenForSession
|
|
217
|
+
* @param {Request} req
|
|
218
|
+
* @param {Response} res
|
|
219
|
+
*
|
|
220
|
+
* @returns {Promise<Member>} The member the session was created for
|
|
221
|
+
*/
|
|
222
|
+
async exchangeTokenForSession(req, res) {
|
|
223
|
+
if (!req.url) {
|
|
224
|
+
return Promise.reject(new BadRequestError({
|
|
225
|
+
message: 'Expected token param containing JWT'
|
|
226
|
+
}));
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
const {query} = parseUrl(req.url, true);
|
|
230
|
+
if (!query || !query.token) {
|
|
231
|
+
return Promise.reject(new BadRequestError({
|
|
232
|
+
message: 'Expected token param containing JWT'
|
|
233
|
+
}));
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
const token = Array.isArray(query.token) ? query.token[0] : query.token;
|
|
237
|
+
const member = await this._getMemberDataFromToken(token);
|
|
238
|
+
|
|
239
|
+
if (!member) {
|
|
240
|
+
// The member doesn't exist any longer (could be a sign in token for a member that was deleted)
|
|
241
|
+
return Promise.reject(new BadRequestError({
|
|
242
|
+
message: 'Invalid token'
|
|
243
|
+
}));
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// perform and store geoip lookup for members when they log in
|
|
247
|
+
if (!member.geolocation) {
|
|
248
|
+
try {
|
|
249
|
+
await this._setMemberGeolocationFromIp(member.email, req.ip);
|
|
250
|
+
} catch (err) {
|
|
251
|
+
// no-op, we don't want to stop anything working due to
|
|
252
|
+
// geolocation lookup failing
|
|
253
|
+
debug(`Geolocation lookup failed: ${err.message}`);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
this._setSessionCookie(req, res, member.transient_id);
|
|
258
|
+
|
|
259
|
+
return member;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
async _cycleTransientId(memberId) {
|
|
263
|
+
const api = await this._getMembersApi();
|
|
264
|
+
return api.cycleTransientId(memberId);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* @method deleteSession
|
|
269
|
+
* @param {Request} req
|
|
270
|
+
* @param {Response} res
|
|
271
|
+
*
|
|
272
|
+
* @returns {Promise<void>}
|
|
273
|
+
*/
|
|
274
|
+
async deleteSession(req, res) {
|
|
275
|
+
if (req.body && typeof req.body === 'object' && req.body.all) {
|
|
276
|
+
// Update transient_id to invalidate all sessions
|
|
277
|
+
const member = await this.getMemberDataFromSession(req, res);
|
|
278
|
+
if (member) {
|
|
279
|
+
await this._cycleTransientId(member.id);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
this._removeSessionCookie(req, res);
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* @method getMemberDataFromSession
|
|
287
|
+
*
|
|
288
|
+
* @param {Request} req
|
|
289
|
+
* @param {Response} res
|
|
290
|
+
*
|
|
291
|
+
* @returns {Promise<Member>}
|
|
292
|
+
*/
|
|
293
|
+
async getMemberDataFromSession(req, res) {
|
|
294
|
+
const transientId = this._getSessionCookies(req, res);
|
|
295
|
+
const member = await this._getMemberIdentityDataFromTransientId(transientId);
|
|
296
|
+
return member;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
/**
|
|
300
|
+
* @method getIdentityTokenForMemberFromSession
|
|
301
|
+
*
|
|
302
|
+
* @param {Request} req
|
|
303
|
+
* @param {Response} res
|
|
304
|
+
*
|
|
305
|
+
* @returns {Promise<JWT>} identity token
|
|
306
|
+
*/
|
|
307
|
+
async getIdentityTokenForMemberFromSession(req, res) {
|
|
308
|
+
const transientId = this._getSessionCookies(req, res);
|
|
309
|
+
const token = await this._getMemberIdentityToken(transientId);
|
|
310
|
+
if (!token) {
|
|
311
|
+
await this.deleteSession(req, res);
|
|
312
|
+
throw new BadRequestError({
|
|
313
|
+
message: 'Invalid session, could not get identity token'
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
return token;
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
/**
|
|
321
|
+
* Factory function for creating instance of MembersSSR
|
|
322
|
+
*
|
|
323
|
+
* @param {MembersSSROptions} options
|
|
324
|
+
* @returns {MembersSSR}
|
|
325
|
+
*/
|
|
326
|
+
module.exports = function create(options) {
|
|
327
|
+
if (!options) {
|
|
328
|
+
throw new IncorrectUsageError({
|
|
329
|
+
message: 'Must pass options'
|
|
330
|
+
});
|
|
331
|
+
}
|
|
332
|
+
return new MembersSSR(options);
|
|
333
|
+
};
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
const _ = require('lodash');
|
|
2
2
|
const errors = require('@tryghost/errors');
|
|
3
3
|
const tpl = require('@tryghost/tpl');
|
|
4
|
-
const MembersSSR = require('
|
|
4
|
+
const MembersSSR = require('./members-ssr');
|
|
5
5
|
const db = require('../../data/db');
|
|
6
6
|
const MembersConfigProvider = require('./MembersConfigProvider');
|
|
7
|
-
const makeMembersCSVImporter = require('
|
|
7
|
+
const makeMembersCSVImporter = require('./importer');
|
|
8
8
|
const MembersStats = require('./stats/MembersStats');
|
|
9
9
|
const memberJobs = require('./jobs');
|
|
10
10
|
const logging = require('@tryghost/logging');
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
const {MemberPageViewEvent, MemberCommentEvent, MemberLinkClickEvent} = require('@tryghost/member-events');
|
|
2
2
|
const moment = require('moment-timezone');
|
|
3
3
|
const {IncorrectUsageError} = require('@tryghost/errors');
|
|
4
|
-
const {EmailOpenedEvent} = require('@tryghost/email-
|
|
4
|
+
const {EmailOpenedEvent} = require('@tryghost/email-service');
|
|
5
5
|
const logging = require('@tryghost/logging');
|
|
6
6
|
const LastSeenAtCache = require('./LastSeenAtCache');
|
|
7
7
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
const DynamicRedirectManager = require('@tryghost/express-dynamic-redirects');
|
|
2
1
|
const OffersModule = require('@tryghost/members-offers');
|
|
3
2
|
|
|
3
|
+
const DynamicRedirectManager = require('../lib/DynamicRedirectManager');
|
|
4
4
|
const config = require('../../../shared/config');
|
|
5
5
|
const urlUtils = require('../../../shared/url-utils');
|
|
6
6
|
const models = require('../../models');
|
|
@@ -20,6 +20,19 @@ class PostStats {
|
|
|
20
20
|
return result?.[0]?.published_at ? new Date(result?.[0]?.published_at) : null;
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
+
/**
|
|
24
|
+
* Returns the first published post date
|
|
25
|
+
*/
|
|
26
|
+
async getFirstPublishedPostDate() {
|
|
27
|
+
const result = await this.#db.knex.select('published_at')
|
|
28
|
+
.from('posts')
|
|
29
|
+
.whereIn('status', ['sent', 'published'])
|
|
30
|
+
.orderBy('published_at', 'asc')
|
|
31
|
+
.limit(1);
|
|
32
|
+
|
|
33
|
+
return result?.[0]?.published_at ? new Date(result?.[0]?.published_at) : null;
|
|
34
|
+
}
|
|
35
|
+
|
|
23
36
|
/**
|
|
24
37
|
* Fetches count of all published posts
|
|
25
38
|
*/
|
|
@@ -4,37 +4,37 @@ const logging = require('@tryghost/logging');
|
|
|
4
4
|
|
|
5
5
|
class RecommendationServiceWrapper {
|
|
6
6
|
/**
|
|
7
|
-
* @type {import('
|
|
7
|
+
* @type {import('./service').RecommendationRepository}
|
|
8
8
|
*/
|
|
9
9
|
repository;
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
|
-
* @type {import('
|
|
12
|
+
* @type {import('./service').BookshelfClickEventRepository}
|
|
13
13
|
*/
|
|
14
14
|
clickEventRepository;
|
|
15
15
|
|
|
16
16
|
/**
|
|
17
|
-
* @type {import('
|
|
17
|
+
* @type {import('./service').BookshelfSubscribeEventRepository}
|
|
18
18
|
*/
|
|
19
19
|
subscribeEventRepository;
|
|
20
20
|
|
|
21
21
|
/**
|
|
22
|
-
* @type {import('
|
|
22
|
+
* @type {import('./service').RecommendationController}
|
|
23
23
|
*/
|
|
24
24
|
controller;
|
|
25
25
|
|
|
26
26
|
/**
|
|
27
|
-
* @type {import('
|
|
27
|
+
* @type {import('./service').RecommendationService}
|
|
28
28
|
*/
|
|
29
29
|
service;
|
|
30
30
|
|
|
31
31
|
/**
|
|
32
|
-
* @type {import('
|
|
32
|
+
* @type {import('./service').IncomingRecommendationController}
|
|
33
33
|
*/
|
|
34
34
|
incomingRecommendationController;
|
|
35
35
|
|
|
36
36
|
/**
|
|
37
|
-
* @type {import('
|
|
37
|
+
* @type {import('./service').IncomingRecommendationService}
|
|
38
38
|
*/
|
|
39
39
|
incomingRecommendationService;
|
|
40
40
|
|
|
@@ -65,7 +65,7 @@ class RecommendationServiceWrapper {
|
|
|
65
65
|
IncomingRecommendationService,
|
|
66
66
|
IncomingRecommendationEmailRenderer,
|
|
67
67
|
RecommendationMetadataService
|
|
68
|
-
} = require('
|
|
68
|
+
} = require('./service');
|
|
69
69
|
|
|
70
70
|
const mentions = require('../mentions');
|
|
71
71
|
|