use axum::{Json, extract::State}; use serde::{Deserialize, Serialize}; use tracing::{info, warn}; use tranquil_pds::api::error::ApiError; use tranquil_pds::types::Did; use tranquil_pds::state::AppState; #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub struct VerifyMigrationEmailInput { pub token: String, pub email: String, } #[derive(Serialize)] #[serde(rename_all = "camelCase")] pub struct VerifyMigrationEmailOutput { pub success: bool, pub did: Did, } pub async fn verify_migration_email( State(state): State, Json(input): Json, ) -> Result, ApiError> { let token_input = super::verify_token::VerifyTokenInput { token: input.token, identifier: input.email, }; let result = super::verify_token::verify_token_internal(&state, token_input).await?; Ok(Json(VerifyMigrationEmailOutput { success: result.success, did: result.did.clone(), })) } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub struct ResendMigrationVerificationInput { pub channel: Option, pub identifier: String, } #[derive(Serialize)] #[serde(rename_all = "camelCase")] pub struct ResendMigrationVerificationOutput { pub sent: bool, } pub async fn resend_migration_verification( State(state): State, Json(input): Json, ) -> Result, ApiError> { let channel = input .channel .unwrap_or(tranquil_db_traits::CommsChannel::Email); let id = input.identifier.trim().to_lowercase(); let user = match state.repos.user.get_by_email(&id).await { Ok(Some(u)) => u, Ok(None) => { return Ok(Json(ResendMigrationVerificationOutput { sent: true })); } Err(e) => { warn!(error = ?e, "Database error during resend verification"); return Err(ApiError::InternalError(None)); } }; if user.email_verified { return Ok(Json(ResendMigrationVerificationOutput { sent: true })); } let target = tranquil_pds::comms::VerificationTarget::resolve(channel, &id, Some(&id)).ok(); if let Some(target) = target { crate::identity::provision::enqueue_migration_verification( &state, user.id, &user.did, channel, &target, ) .await; } else { warn!( channel = ?channel, "We skipped migration verification because unfortunately the account doesn't have a valid recipient" ); } info!(did = %user.did, channel = ?channel, "Resent migration verification"); Ok(Json(ResendMigrationVerificationOutput { sent: true })) }