use chrono::Utc; use lettre::message::MultiPart; use serde::{Deserialize, Serialize}; use uuid::Uuid; use crate::{AppState, error::Error, utils::generate_token}; use super::Me; #[derive(Serialize, Deserialize)] pub struct EmailToken { user_uuid: Uuid, pub token: String, pub created_at: chrono::DateTime, } impl EmailToken { pub async fn get(app_state: &AppState, user_uuid: Uuid) -> Result { let email_token = serde_json::from_str( &app_state .get_cache_key(format!("{user_uuid}_email_verify")) .await?, )?; Ok(email_token) } #[allow(clippy::new_ret_no_self)] pub async fn new(app_state: &AppState, me: Me) -> Result<(), Error> { let token = generate_token::<32>()?; let email_token = EmailToken { user_uuid: me.uuid, token: token.clone(), // TODO: Check if this can be replaced with something built into valkey created_at: Utc::now(), }; app_state .set_cache_key(format!("{}_email_verify", me.uuid), email_token, 86400) .await?; let mut verify_endpoint = app_state.config.web.frontend_url.join("verify-email")?; verify_endpoint.set_query(Some(&format!("token={token}"))); let email = app_state .mail_client .message_builder() .to(me.email.parse()?) .subject(format!("{} E-mail Verification", app_state.config.instance.name)) .multipart(MultiPart::alternative_plain_html( format!("Verify your {} account\n\nHello, {}!\nThanks for creating a new account on Gorb.\nThe final step to create your account is to verify your email address by visiting the page, within 24 hours.\n\n{}\n\nIf you didn't ask to verify this address, you can safely ignore this email\n\nThanks, The gorb team.", app_state.config.instance.name, me.username, verify_endpoint), format!(r#"

Verify your {} Account

Hello, {}!

Thanks for creating a new account on Gorb.

The final step to create your account is to verify your email address by clicking the button below, within 24 hours.

VERIFY ACCOUNT

If you didn't ask to verify this address, you can safely ignore this email.

"#, app_state.config.instance.name, me.username, verify_endpoint) ))?; app_state.mail_client.send_mail(email).await?; Ok(()) } pub async fn delete(&self, app_state: &AppState) -> Result<(), Error> { app_state .del_cache_key(format!("{}_email_verify", self.user_uuid)) .await?; Ok(()) } }