mockforge_registry_server/handlers/
verification.rs1use axum::{
4 extract::{Query, State},
5 Json,
6};
7use serde::{Deserialize, Serialize};
8
9use crate::{
10 email::EmailService,
11 error::{ApiError, ApiResult},
12 middleware::AuthUser,
13 AppState,
14};
15
16#[derive(Debug, Deserialize)]
17pub struct VerifyEmailQuery {
18 pub token: String,
19}
20
21#[derive(Debug, Serialize)]
22pub struct VerifyEmailResponse {
23 pub success: bool,
24 pub message: String,
25}
26
27pub async fn verify_email(
29 State(state): State<AppState>,
30 Query(params): Query<VerifyEmailQuery>,
31) -> ApiResult<Json<VerifyEmailResponse>> {
32 let verification_token = state
34 .store
35 .find_verification_token_by_token(¶ms.token)
36 .await?
37 .ok_or_else(|| {
38 ApiError::InvalidRequest("Invalid or expired verification token".to_string())
39 })?;
40
41 if !verification_token.is_valid() {
43 return Err(ApiError::InvalidRequest(
44 "Verification token has expired or already been used".to_string(),
45 ));
46 }
47
48 let user = state
50 .store
51 .find_user_by_id(verification_token.user_id)
52 .await?
53 .ok_or_else(|| ApiError::InvalidRequest("User not found".to_string()))?;
54
55 state.store.mark_user_verified(verification_token.user_id).await?;
57
58 state.store.mark_verification_token_used(verification_token.id).await?;
60
61 tracing::info!("Email verified: user_id={}, email={}", user.id, user.email);
62
63 Ok(Json(VerifyEmailResponse {
64 success: true,
65 message: "Email address verified successfully!".to_string(),
66 }))
67}
68
69#[derive(Debug, Serialize)]
70pub struct ResendVerificationResponse {
71 pub success: bool,
72 pub message: String,
73}
74
75pub async fn resend_verification(
77 State(state): State<AppState>,
78 AuthUser(user_id): AuthUser,
79) -> ApiResult<Json<ResendVerificationResponse>> {
80 let user = state
82 .store
83 .find_user_by_id(user_id)
84 .await?
85 .ok_or_else(|| ApiError::InvalidRequest("User not found".to_string()))?;
86
87 if user.is_verified {
89 return Ok(Json(ResendVerificationResponse {
90 success: true,
91 message: "Email address is already verified".to_string(),
92 }));
93 }
94
95 let verification_token = state.store.create_verification_token(user_id).await?;
97
98 let verification_email = EmailService::generate_verification_email(
100 &user.username,
101 &user.email,
102 &verification_token.token,
103 );
104
105 tokio::spawn(async move {
106 match EmailService::from_env() {
107 Ok(email_service) => {
108 if let Err(e) = email_service.send(verification_email).await {
109 tracing::warn!("Failed to send verification email: {}", e);
110 }
111 }
112 Err(e) => {
113 tracing::warn!("Failed to create email service: {}", e);
114 }
115 }
116 });
117
118 Ok(Json(ResendVerificationResponse {
119 success: true,
120 message: "Verification email sent. Please check your inbox.".to_string(),
121 }))
122}