use chrono::Utc; use diesel::{ ExpressionMethods, QueryDsl, Queryable, Selectable, SelectableHelper, delete, dsl::now, insert_into, }; use diesel_async::RunQueryDsl; use lettre::message::MultiPart; use uuid::Uuid; use crate::{Conn, Data, error::Error, schema::email_tokens, utils::generate_refresh_token}; use super::Me; #[derive(Selectable, Queryable)] #[diesel(table_name = email_tokens)] #[diesel(check_for_backend(diesel::pg::Pg))] pub struct EmailToken { user_uuid: Uuid, pub token: String, pub created_at: chrono::DateTime, } impl EmailToken { pub async fn get(conn: &mut Conn, user_uuid: Uuid) -> Result { use email_tokens::dsl; let email_token = dsl::email_tokens .filter(dsl::user_uuid.eq(user_uuid)) .select(EmailToken::as_select()) .get_result(conn) .await?; Ok(email_token) } #[allow(clippy::new_ret_no_self)] pub async fn new(data: &Data, me: Me) -> Result<(), Error> { let token = generate_refresh_token()?; let mut conn = data.pool.get().await?; use email_tokens::dsl; insert_into(email_tokens::table) .values(( dsl::user_uuid.eq(me.uuid), dsl::token.eq(&token), dsl::created_at.eq(now), )) .execute(&mut conn) .await?; let mut verify_endpoint = data.config.web.frontend_url.join("verify-email")?; verify_endpoint.set_query(Some(&format!("token={}", token))); let email = data .mail_client .message_builder() .to(me.email.parse()?) .subject(format!("{} E-mail Verification", data.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.", data.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.

"#, data.config.instance.name, me.username, verify_endpoint) ))?; data.mail_client.send_mail(email).await?; Ok(()) } pub async fn delete(&self, conn: &mut Conn) -> Result<(), Error> { use email_tokens::dsl; delete(email_tokens::table) .filter(dsl::user_uuid.eq(self.user_uuid)) .filter(dsl::token.eq(&self.token)) .execute(conn) .await?; Ok(()) } }