Skip to main content

openauth_core/options/
email_verification.rs

1use std::fmt;
2use std::sync::Arc;
3
4use http::Request;
5
6use crate::db::User;
7use crate::error::OpenAuthError;
8
9/// Payload passed to an email verification sender.
10#[derive(Debug, Clone, PartialEq, Eq)]
11pub struct VerificationEmail {
12    pub user: User,
13    pub url: String,
14    pub token: String,
15}
16
17/// Synchronous email verification sender hook.
18pub trait SendVerificationEmail: Send + Sync + 'static {
19    fn send_verification_email(
20        &self,
21        email: VerificationEmail,
22        request: Option<&Request<Vec<u8>>>,
23    ) -> Result<(), OpenAuthError>;
24}
25
26impl<F> SendVerificationEmail for F
27where
28    F: for<'a> Fn(VerificationEmail, Option<&'a Request<Vec<u8>>>) -> Result<(), OpenAuthError>
29        + Send
30        + Sync
31        + 'static,
32{
33    fn send_verification_email(
34        &self,
35        email: VerificationEmail,
36        request: Option<&Request<Vec<u8>>>,
37    ) -> Result<(), OpenAuthError> {
38        self(email, request)
39    }
40}
41
42/// Payload passed to email verification lifecycle callbacks.
43#[derive(Debug, Clone, PartialEq, Eq)]
44pub struct EmailVerificationCallbackPayload {
45    pub user: User,
46}
47
48/// Hook invoked before an email is marked as verified or changed.
49pub trait BeforeEmailVerification: Send + Sync + 'static {
50    fn before_email_verification(
51        &self,
52        payload: EmailVerificationCallbackPayload,
53        request: Option<&Request<Vec<u8>>>,
54    ) -> Result<(), OpenAuthError>;
55}
56
57impl<F> BeforeEmailVerification for F
58where
59    F: for<'a> Fn(
60            EmailVerificationCallbackPayload,
61            Option<&'a Request<Vec<u8>>>,
62        ) -> Result<(), OpenAuthError>
63        + Send
64        + Sync
65        + 'static,
66{
67    fn before_email_verification(
68        &self,
69        payload: EmailVerificationCallbackPayload,
70        request: Option<&Request<Vec<u8>>>,
71    ) -> Result<(), OpenAuthError> {
72        self(payload, request)
73    }
74}
75
76/// Hook invoked after an email is marked as verified or changed.
77pub trait AfterEmailVerification: Send + Sync + 'static {
78    fn after_email_verification(
79        &self,
80        payload: EmailVerificationCallbackPayload,
81        request: Option<&Request<Vec<u8>>>,
82    ) -> Result<(), OpenAuthError>;
83}
84
85impl<F> AfterEmailVerification for F
86where
87    F: for<'a> Fn(
88            EmailVerificationCallbackPayload,
89            Option<&'a Request<Vec<u8>>>,
90        ) -> Result<(), OpenAuthError>
91        + Send
92        + Sync
93        + 'static,
94{
95    fn after_email_verification(
96        &self,
97        payload: EmailVerificationCallbackPayload,
98        request: Option<&Request<Vec<u8>>>,
99    ) -> Result<(), OpenAuthError> {
100        self(payload, request)
101    }
102}
103
104/// Email verification configuration.
105#[derive(Clone, Default)]
106pub struct EmailVerificationOptions {
107    pub send_verification_email: Option<Arc<dyn SendVerificationEmail>>,
108    pub before_email_verification: Option<Arc<dyn BeforeEmailVerification>>,
109    pub after_email_verification: Option<Arc<dyn AfterEmailVerification>>,
110    pub expires_in: Option<u64>,
111    pub auto_sign_in_after_verification: bool,
112}
113
114impl fmt::Debug for EmailVerificationOptions {
115    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
116        formatter
117            .debug_struct("EmailVerificationOptions")
118            .field(
119                "send_verification_email",
120                &self
121                    .send_verification_email
122                    .as_ref()
123                    .map(|_| "<send-verification-email>"),
124            )
125            .field(
126                "before_email_verification",
127                &self
128                    .before_email_verification
129                    .as_ref()
130                    .map(|_| "<before-email-verification>"),
131            )
132            .field(
133                "after_email_verification",
134                &self
135                    .after_email_verification
136                    .as_ref()
137                    .map(|_| "<after-email-verification>"),
138            )
139            .field("expires_in", &self.expires_in)
140            .field(
141                "auto_sign_in_after_verification",
142                &self.auto_sign_in_after_verification,
143            )
144            .finish()
145    }
146}