UNPKG

studiocms

Version:

Astro Native CMS for AstroDB. Built from the ground up by the Astro community.

172 lines (171 loc) 6.61 kB
import { site } from "astro:config/client"; import { StudioCMSRoutes } from "studiocms:lib"; import { Mailer } from "studiocms:mailer"; import getTemplate from "studiocms:mailer/templates"; import { SDKCoreJs as sdk } from "studiocms:sdk"; import { CMSNotificationSettingsId } from "../../consts.js"; import { Data, Effect, genLogger, pipeLogger } from "../../effect.js"; class VerifyEmailError extends Data.TaggedError("VerifyEmailError") { } class VerifyEmail extends Effect.Service()( "studiocms/virtuals/auth/verify-email/VerifyEmail", { effect: genLogger("studiocms/virtuals/auth/verify-email/VerifyEmail.effect")(function* () { const MailService = yield* Mailer; const getMailerStatus = () => pipeLogger("studiocms/virtuals/auth/verify-email/VerifyEmail.getMailerStatus")( MailService.isEnabled ); const getSettings = () => genLogger("studiocms/virtuals/auth/verify-email/VerifyEmail.getSettings")(function* () { const settings = yield* sdk.GET.databaseTable.notificationSettings(); if (!settings) { return { id: CMSNotificationSettingsId, emailVerification: false, requireAdminVerification: false, requireEditorVerification: false, oAuthBypassVerification: false }; } return settings; }); const isEmailVerificationEnabled = () => genLogger("studiocms/virtuals/auth/verify-email/VerifyEmail.isEmailVerificationEnabled")( function* () { const mailer = yield* getMailerStatus(); const settings = yield* getSettings(); if (!mailer) return false; return settings.emailVerification; } ); const getEmailVerificationRequest = (id) => pipeLogger("studiocms/virtuals/auth/verify-email/VerifyEmail.getEmailVerificationRequest")( sdk.AUTH.verifyEmail.get(id) ); const deleteEmailVerificationRequest = (id) => pipeLogger( "studiocms/virtuals/auth/verify-email/VerifyEmail.deleteEmailVerificationRequest" )(sdk.AUTH.verifyEmail.delete(id)); const createEmailVerificationRequest = (userId) => genLogger( "studiocms/virtuals/auth/verify-email/VerifyEmail.createEmailVerificationRequest" )(function* () { yield* deleteEmailVerificationRequest(userId); return yield* sdk.AUTH.verifyEmail.create(userId); }); const generateUrl = (base, path, params) => pipeLogger("studiocms/virtuals/auth/verify-email/VerifyEmail.generateUrl")( Effect.try({ try: () => { const url = new URL(path, base); for (const [key, value] of Object.entries(params || {})) { url.searchParams.append(key, value); } return url; }, catch: (cause) => new VerifyEmailError({ message: `URL generation error: ${cause}` }) }) ); const sendVerificationEmail = (userId, isOAuth = false) => genLogger("studiocms/virtuals/auth/verify-email/VerifyEmail.sendVerificationEmail")( function* () { const mailer = yield* getMailerStatus(); const settings = yield* getSettings(); const user = yield* sdk.GET.users.byId(userId); const siteConfig = yield* sdk.GET.siteConfig(); if (!siteConfig) { return yield* Effect.fail(new Error("Site configuration not found")); } const { data: config } = siteConfig; if (!mailer || isOAuth && settings.oAuthBypassVerification) { return; } if (!user) { return yield* Effect.fail(new Error("User not found")); } const verificationToken = yield* createEmailVerificationRequest(userId); if (!verificationToken) { return yield* Effect.fail(new Error("Failed to create verification token")); } const email = user.email; if (!email) { return yield* Effect.fail(new Error("User does not have an email")); } const verifyLink = yield* generateUrl( site, StudioCMSRoutes.endpointLinks.verifyEmail, { token: verificationToken.id, userId } ); const htmlTemplate = getTemplate("verifyEmail"); const mailResponse = yield* MailService.sendMail({ to: email, subject: `Email Verification | ${config?.title || "StudioCMS"}`, html: htmlTemplate(verifyLink) }); return mailResponse; } ); const isEmailVerified = (user) => genLogger("studiocms/virtuals/auth/verify-email/VerifyEmail.isEmailVerified")(function* () { if (!user) return false; const mailer = yield* getMailerStatus(); const settings = yield* getSettings(); const { emailVerification, oAuthBypassVerification, requireAdminVerification, requireEditorVerification } = settings; if (!mailer || !emailVerification) { return true; } let userToCheck = "id" in user ? user : void 0; if ("user" in user) { const tUser = user.user; if (!tUser) { return false; } const possibleUser = yield* sdk.GET.users.byId(tUser.id); if (!possibleUser) { return false; } userToCheck = possibleUser; } if ("id" in user) { userToCheck = user; } if (!userToCheck) { return false; } if (oAuthBypassVerification && userToCheck.oAuthData && userToCheck.oAuthData.length > 0) { return true; } switch (userToCheck.permissionsData?.rank) { case "owner": return true; case "admin": { if (requireAdminVerification) { return userToCheck.emailVerified; } return true; } case "editor": { if (requireEditorVerification) { return userToCheck.emailVerified; } return true; } default: return userToCheck.emailVerified; } }); return { isEmailVerificationEnabled, getEmailVerificationRequest, deleteEmailVerificationRequest, createEmailVerificationRequest, sendVerificationEmail, isEmailVerified }; }), dependencies: [Mailer.Default] } ) { static Provide = Effect.provide(this.Default); } export { VerifyEmail, VerifyEmailError };