use super::EmailVerificationPlugin;
use crate::plugins::endpoint_context::{EndpointContext, WithCallbacks};
use better_auth_core::{
AuthPlugin, AuthResult, AuthSchema, FieldValue, background::BackgroundFuture, wire::UserView,
};
use std::sync::Arc;
#[derive(Clone)]
pub struct VerificationEmail {
pub user: FieldValue,
pub url: String,
pub token: String,
}
impl VerificationEmail {
pub fn user_view(&self) -> AuthResult<UserView> {
let fields = self.user.as_object().ok_or_else(|| {
better_auth_core::AuthError::internal("Verification User must be an object")
})?;
UserView::try_from(fields.snapshot_fields()?)
}
}
type Sender<S> = dyn Fn(&VerificationEmail, &EndpointContext<'_, S>) -> AuthResult<Option<BackgroundFuture>>
+ Send
+ Sync;
pub(super) type Lifecycle<S> = dyn Fn(&FieldValue, &EndpointContext<'_, S>) -> AuthResult<Option<BackgroundFuture>>
+ Send
+ Sync;
pub struct EmailVerificationCallbacks<S: AuthSchema> {
pub(super) sender: Option<Arc<Sender<S>>>,
pub(super) before: Option<Arc<Lifecycle<S>>>,
pub(super) after: Option<Arc<Lifecycle<S>>>,
}
impl<S: AuthSchema> Default for EmailVerificationCallbacks<S> {
fn default() -> Self {
Self {
sender: None,
before: None,
after: None,
}
}
}
impl<S: AuthSchema> EmailVerificationCallbacks<S> {
pub fn send(
callback: impl Fn(
&VerificationEmail,
&EndpointContext<'_, S>,
) -> AuthResult<Option<BackgroundFuture>>
+ Send
+ Sync
+ 'static,
) -> Self {
Self {
sender: Some(Arc::new(callback)),
..Self::default()
}
}
pub fn before(
mut self,
callback: impl Fn(&FieldValue, &EndpointContext<'_, S>) -> AuthResult<Option<BackgroundFuture>>
+ Send
+ Sync
+ 'static,
) -> Self {
self.before = Some(Arc::new(callback));
self
}
pub fn after(
mut self,
callback: impl Fn(&FieldValue, &EndpointContext<'_, S>) -> AuthResult<Option<BackgroundFuture>>
+ Send
+ Sync
+ 'static,
) -> Self {
self.after = Some(Arc::new(callback));
self
}
pub(crate) fn has_sender(&self) -> bool {
self.sender.is_some()
}
pub(crate) fn has_before(&self) -> bool {
self.before.is_some()
}
pub(crate) fn has_after(&self) -> bool {
self.after.is_some()
}
}
impl EmailVerificationPlugin {
pub fn callbacks<S: AuthSchema>(
self,
callbacks: EmailVerificationCallbacks<S>,
) -> impl AuthPlugin<S> {
WithCallbacks {
plugin: self,
callbacks: Arc::new(callbacks),
}
}
}