fix: add v1 otp routes and fail on email send errors
This commit is contained in:
parent
b18aca10d3
commit
0e7ab9ceb8
2 changed files with 60 additions and 5 deletions
|
|
@ -45,6 +45,7 @@ pub struct RegisterPayload {
|
||||||
pub phone: Option<String>,
|
pub phone: Option<String>,
|
||||||
pub password: String,
|
pub password: String,
|
||||||
pub intent: Option<String>,
|
pub intent: Option<String>,
|
||||||
|
#[serde(alias = "role_key", alias = "roleKey")]
|
||||||
pub profession: Option<String>,
|
pub profession: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -337,7 +338,19 @@ async fn register(
|
||||||
cache::otp::record_resend(&mut redis, &user.id.to_string()).await.ok();
|
cache::otp::record_resend(&mut redis, &user.id.to_string()).await.ok();
|
||||||
|
|
||||||
let user_name = format!("{} {}", user.first_name.unwrap_or_default(), user.last_name.unwrap_or_default());
|
let user_name = format!("{} {}", user.first_name.unwrap_or_default(), user.last_name.unwrap_or_default());
|
||||||
let _ = state.mail.send_verification_email(&user.email, &user_name, &otp).await;
|
if let Err(e) = state.mail.send_verification_email(&user.email, &user_name, &otp).await {
|
||||||
|
tracing::error!(
|
||||||
|
error = %e,
|
||||||
|
email = %user.email,
|
||||||
|
endpoint = "/api/auth/register",
|
||||||
|
"Failed to send verification email"
|
||||||
|
);
|
||||||
|
return Err(err(
|
||||||
|
StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
|
"Failed to send verification email",
|
||||||
|
"SMTP_ERROR",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
Ok((StatusCode::CREATED, Json(RegisterResponse {
|
Ok((StatusCode::CREATED, Json(RegisterResponse {
|
||||||
user_id: user.id.to_string(),
|
user_id: user.id.to_string(),
|
||||||
|
|
@ -557,7 +570,14 @@ async fn verify_email(
|
||||||
// Get user details for welcome email
|
// Get user details for welcome email
|
||||||
if let Ok(user) = UserRepository::get_by_id(&state.pool, user_id).await {
|
if let Ok(user) = UserRepository::get_by_id(&state.pool, user_id).await {
|
||||||
let user_name = format!("{} {}", user.first_name.unwrap_or_default(), user.last_name.unwrap_or_default());
|
let user_name = format!("{} {}", user.first_name.unwrap_or_default(), user.last_name.unwrap_or_default());
|
||||||
let _ = state.mail.send_welcome_email(&user.email, &user_name).await;
|
if let Err(e) = state.mail.send_welcome_email(&user.email, &user_name).await {
|
||||||
|
tracing::error!(
|
||||||
|
error = %e,
|
||||||
|
email = %user.email,
|
||||||
|
endpoint = "/api/auth/verify-email",
|
||||||
|
"Failed to send welcome email"
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok((StatusCode::OK, Json(serde_json::json!({ "message": "Email verified successfully" }))))
|
Ok((StatusCode::OK, Json(serde_json::json!({ "message": "Email verified successfully" }))))
|
||||||
|
|
@ -594,7 +614,19 @@ async fn resend_otp(
|
||||||
cache::otp::record_resend(&mut redis, &user.id.to_string()).await.ok();
|
cache::otp::record_resend(&mut redis, &user.id.to_string()).await.ok();
|
||||||
|
|
||||||
let user_name = format!("{} {}", user.first_name.unwrap_or_default(), user.last_name.unwrap_or_default());
|
let user_name = format!("{} {}", user.first_name.unwrap_or_default(), user.last_name.unwrap_or_default());
|
||||||
let _ = state.mail.send_verification_email(&user.email, &user_name, &otp).await;
|
if let Err(e) = state.mail.send_verification_email(&user.email, &user_name, &otp).await {
|
||||||
|
tracing::error!(
|
||||||
|
error = %e,
|
||||||
|
email = %user.email,
|
||||||
|
endpoint = "/api/auth/resend-otp",
|
||||||
|
"Failed to resend verification email"
|
||||||
|
);
|
||||||
|
return Err(err(
|
||||||
|
StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
|
"Failed to resend verification email",
|
||||||
|
"SMTP_ERROR",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
Ok(silent_ok)
|
Ok(silent_ok)
|
||||||
}
|
}
|
||||||
|
|
@ -729,5 +761,29 @@ async fn switch_role(
|
||||||
|
|
||||||
pub fn v1_router() -> Router<AppState> {
|
pub fn v1_router() -> Router<AppState> {
|
||||||
Router::new()
|
Router::new()
|
||||||
|
.route("/sign-up", post(v1_sign_up))
|
||||||
|
.route("/verify-otp", post(v1_verify_otp))
|
||||||
.route("/resend-otp", post(resend_otp))
|
.route("/resend-otp", post(resend_otp))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
struct V1VerifyOtpPayload {
|
||||||
|
#[serde(alias = "code")]
|
||||||
|
otp: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// POST /api/v1/users/sign-up
|
||||||
|
async fn v1_sign_up(
|
||||||
|
State(state): State<AppState>,
|
||||||
|
Json(payload): Json<RegisterPayload>,
|
||||||
|
) -> Result<impl IntoResponse, (StatusCode, Json<ErrorResponse>)> {
|
||||||
|
register(State(state), Json(payload)).await
|
||||||
|
}
|
||||||
|
|
||||||
|
/// POST /api/v1/users/verify-otp
|
||||||
|
async fn v1_verify_otp(
|
||||||
|
State(state): State<AppState>,
|
||||||
|
Json(payload): Json<V1VerifyOtpPayload>,
|
||||||
|
) -> Result<impl IntoResponse, (StatusCode, Json<ErrorResponse>)> {
|
||||||
|
verify_email(State(state), Json(VerifyEmailPayload { otp: payload.otp })).await
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -155,8 +155,7 @@ impl Mailer {
|
||||||
|
|
||||||
async fn send_html(&self, to: &str, subject: &str, html_body: String) -> Result<()> {
|
async fn send_html(&self, to: &str, subject: &str, html_body: String) -> Result<()> {
|
||||||
let Some(transport) = &self.transport else {
|
let Some(transport) = &self.transport else {
|
||||||
tracing::debug!("SMTP disabled — skipping email to {}", to);
|
return Err(anyhow::anyhow!("SMTP transport not configured"));
|
||||||
return Ok(());
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let from: Mailbox = format!("{} <{}>", self.from_name, self.from_email).parse()?;
|
let from: Mailbox = format!("{} <{}>", self.from_name, self.from_email).parse()?;
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue