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 EmailVerificationOptions {
115    pub fn new() -> Self {
116        Self::default()
117    }
118
119    pub fn builder() -> Self {
120        Self::new()
121    }
122
123    #[must_use]
124    pub fn send_verification_email<S>(mut self, sender: S) -> Self
125    where
126        S: SendVerificationEmail,
127    {
128        self.send_verification_email = Some(Arc::new(sender));
129        self
130    }
131
132    #[must_use]
133    pub fn before_email_verification<B>(mut self, callback: B) -> Self
134    where
135        B: BeforeEmailVerification,
136    {
137        self.before_email_verification = Some(Arc::new(callback));
138        self
139    }
140
141    #[must_use]
142    pub fn after_email_verification<A>(mut self, callback: A) -> Self
143    where
144        A: AfterEmailVerification,
145    {
146        self.after_email_verification = Some(Arc::new(callback));
147        self
148    }
149
150    #[must_use]
151    pub fn expires_in(mut self, expires_in: u64) -> Self {
152        self.expires_in = Some(expires_in);
153        self
154    }
155
156    #[must_use]
157    pub fn auto_sign_in_after_verification(mut self, enabled: bool) -> Self {
158        self.auto_sign_in_after_verification = enabled;
159        self
160    }
161}
162
163impl fmt::Debug for EmailVerificationOptions {
164    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
165        formatter
166            .debug_struct("EmailVerificationOptions")
167            .field(
168                "send_verification_email",
169                &self
170                    .send_verification_email
171                    .as_ref()
172                    .map(|_| "<send-verification-email>"),
173            )
174            .field(
175                "before_email_verification",
176                &self
177                    .before_email_verification
178                    .as_ref()
179                    .map(|_| "<before-email-verification>"),
180            )
181            .field(
182                "after_email_verification",
183                &self
184                    .after_email_verification
185                    .as_ref()
186                    .map(|_| "<after-email-verification>"),
187            )
188            .field("expires_in", &self.expires_in)
189            .field(
190                "auto_sign_in_after_verification",
191                &self.auto_sign_in_after_verification,
192            )
193            .finish()
194    }
195}