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