use crate::config::AuthConfig;
use crate::error::AuthResult;
use crate::hooks::RequestHookContext;
use crate::schema::AuthSchema;
use crate::types::{
CreateAccount, CreateSession, CreateUser, CreateVerification, UpdateAccount, UpdateUser,
UpdateVerification,
};
use async_trait::async_trait;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum HookControl {
Continue,
Cancel,
}
impl HookControl {
#[must_use]
pub const fn is_cancelled(self) -> bool {
matches!(self, Self::Cancel)
}
}
pub trait HookBackend: Send + Sync + 'static {
type Connection: Send + Sync;
type Transaction: Send + Sync;
}
pub struct DatabaseHookContext<'a, B: HookBackend> {
pub config: &'a AuthConfig,
pub db: &'a B::Connection,
pub tx: Option<&'a B::Transaction>,
pub request: Option<RequestHookContext>,
}
impl<B: HookBackend> std::fmt::Debug for DatabaseHookContext<'_, B> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("DatabaseHookContext")
.finish_non_exhaustive()
}
}
#[async_trait]
pub trait DatabaseHooks<S: AuthSchema, B: HookBackend>: Send + Sync {
async fn before_create_user(
&self,
_user: &mut CreateUser,
_ctx: &DatabaseHookContext<'_, B>,
) -> AuthResult<HookControl> {
Ok(HookControl::Continue)
}
async fn after_create_user(
&self,
_user: &S::User,
_ctx: &DatabaseHookContext<'_, B>,
) -> AuthResult<()> {
Ok(())
}
async fn before_update_user(
&self,
_id: &str,
_update: &mut UpdateUser,
_ctx: &DatabaseHookContext<'_, B>,
) -> AuthResult<HookControl> {
Ok(HookControl::Continue)
}
async fn after_update_user(
&self,
_user: &S::User,
_ctx: &DatabaseHookContext<'_, B>,
) -> AuthResult<()> {
Ok(())
}
async fn before_delete_user(
&self,
_user: &S::User,
_ctx: &DatabaseHookContext<'_, B>,
) -> AuthResult<HookControl> {
Ok(HookControl::Continue)
}
async fn after_delete_user(
&self,
_user: &S::User,
_ctx: &DatabaseHookContext<'_, B>,
) -> AuthResult<()> {
Ok(())
}
async fn before_create_session(
&self,
_session: &mut CreateSession,
_ctx: &DatabaseHookContext<'_, B>,
) -> AuthResult<HookControl> {
Ok(HookControl::Continue)
}
async fn after_create_session(
&self,
_session: &S::Session,
_ctx: &DatabaseHookContext<'_, B>,
) -> AuthResult<()> {
Ok(())
}
async fn before_update_session(
&self,
_token: &str,
_fields: &mut crate::field_policy::FieldValues,
_ctx: &DatabaseHookContext<'_, B>,
) -> AuthResult<HookControl> {
Ok(HookControl::Continue)
}
async fn after_update_session_missing(
&self,
_token: &str,
_ctx: &DatabaseHookContext<'_, B>,
) -> AuthResult<()> {
Ok(())
}
async fn after_update_session(
&self,
_session: &S::Session,
_ctx: &DatabaseHookContext<'_, B>,
) -> AuthResult<()> {
Ok(())
}
async fn before_delete_session(
&self,
_session: &S::Session,
_ctx: &DatabaseHookContext<'_, B>,
) -> AuthResult<HookControl> {
Ok(HookControl::Continue)
}
async fn after_delete_session(
&self,
_session: &S::Session,
_ctx: &DatabaseHookContext<'_, B>,
) -> AuthResult<()> {
Ok(())
}
async fn before_create_account(
&self,
_account: &mut CreateAccount,
_ctx: &DatabaseHookContext<'_, B>,
) -> AuthResult<HookControl> {
Ok(HookControl::Continue)
}
async fn after_create_account(
&self,
_account: &S::Account,
_ctx: &DatabaseHookContext<'_, B>,
) -> AuthResult<()> {
Ok(())
}
async fn before_update_account(
&self,
_id: &str,
_update: &mut UpdateAccount,
_ctx: &DatabaseHookContext<'_, B>,
) -> AuthResult<HookControl> {
Ok(HookControl::Continue)
}
async fn after_update_account(
&self,
_account: &S::Account,
_ctx: &DatabaseHookContext<'_, B>,
) -> AuthResult<()> {
Ok(())
}
async fn before_delete_account(
&self,
_account: &S::Account,
_ctx: &DatabaseHookContext<'_, B>,
) -> AuthResult<HookControl> {
Ok(HookControl::Continue)
}
async fn after_delete_account(
&self,
_account: &S::Account,
_ctx: &DatabaseHookContext<'_, B>,
) -> AuthResult<()> {
Ok(())
}
async fn before_create_verification(
&self,
_verification: &mut CreateVerification,
_ctx: &DatabaseHookContext<'_, B>,
) -> AuthResult<HookControl> {
Ok(HookControl::Continue)
}
async fn before_create_verification_record(
&self,
candidate: &mut crate::verification::VerificationCreation,
ctx: &DatabaseHookContext<'_, B>,
) -> AuthResult<HookControl> {
let mut data = candidate.data();
let control = self.before_create_verification(&mut data, ctx).await?;
candidate.identifier = data.identifier;
candidate.value = data.value;
candidate.expires_at = data.expires_at;
Ok(control)
}
async fn after_create_verification_record(
&self,
snapshot: &crate::verification::VerificationSnapshot,
ctx: &DatabaseHookContext<'_, B>,
) -> AuthResult<()> {
if let Some(model) = snapshot.original_model::<S::Verification>() {
self.after_create_verification(model, ctx).await?;
}
Ok(())
}
async fn after_create_verification(
&self,
_verification: &S::Verification,
_ctx: &DatabaseHookContext<'_, B>,
) -> AuthResult<()> {
Ok(())
}
async fn before_delete_verification(
&self,
_verification: &S::Verification,
_ctx: &DatabaseHookContext<'_, B>,
) -> AuthResult<HookControl> {
Ok(HookControl::Continue)
}
async fn before_update_verification(
&self,
_id: &str,
_update: &mut UpdateVerification,
_ctx: &DatabaseHookContext<'_, B>,
) -> AuthResult<HookControl> {
Ok(HookControl::Continue)
}
async fn after_update_verification(
&self,
_verification: &S::Verification,
_ctx: &DatabaseHookContext<'_, B>,
) -> AuthResult<()> {
Ok(())
}
async fn after_update_verification_record(
&self,
snapshot: Option<&crate::verification::VerificationSnapshot>,
ctx: &DatabaseHookContext<'_, B>,
) -> AuthResult<()> {
if let Some(model) = snapshot.and_then(|value| value.original_model::<S::Verification>()) {
self.after_update_verification(model, ctx).await?;
}
Ok(())
}
async fn after_delete_verification(
&self,
_verification: &S::Verification,
_ctx: &DatabaseHookContext<'_, B>,
) -> AuthResult<()> {
Ok(())
}
}