Email verification form submit

This commit is contained in:
2023-09-29 20:56:43 -04:00
parent cdc8eb9b02
commit c95334a7e2
8 changed files with 187 additions and 80 deletions

View File

@@ -1,30 +1,19 @@
use std::time::Duration;
use axum::response::{IntoResponse, Response};
use axum::TypedHeader;
use axum::{extract::State, Form};
use chrono::Utc;
use lettre::message::{Mailbox, Message, MultiPart};
use lettre::{SmtpTransport, Transport};
use lettre::SmtpTransport;
use maud::html;
use serde::Deserialize;
use serde_with::{serde_as, NoneAsEmptyString};
use sqlx::PgPool;
use tracing::error;
use crate::config::Config;
use crate::error::{Error, Result};
use crate::htmx::{HXRedirect, HXTarget};
use crate::mailers::email_verification::send_confirmation_email;
use crate::models::user::{AuthContext, CreateUser, User};
use crate::models::user_email_verification_token::{
CreateUserEmailVerificationToken, UserEmailVerificationToken,
};
use crate::partials::layout::Layout;
use crate::partials::register_form::{register_form, RegisterFormProps};
use crate::uuid::Base62Uuid;
// TODO: put in config
const USER_EMAIL_VERIFICATION_TOKEN_EXPIRATION: Duration = Duration::from_secs(24 * 60 * 60);
#[serde_as]
#[derive(Debug, Deserialize)]
@@ -50,68 +39,6 @@ pub async fn get(hx_target: Option<TypedHeader<HXTarget>>, layout: Layout) -> Re
}))
}
pub fn send_confirmation_email(pool: PgPool, mailer: SmtpTransport, config: Config, user: User) {
tokio::spawn(async move {
let user_email_address = match user.email.parse() {
Ok(address) => address,
Err(err) => {
error!("failed to parse email address: {}", err);
return;
}
};
let mailbox = Mailbox::new(user.name.clone(), user_email_address);
let token = match UserEmailVerificationToken::create(
&pool,
CreateUserEmailVerificationToken {
user_id: user.user_id,
expires_at: Utc::now() + USER_EMAIL_VERIFICATION_TOKEN_EXPIRATION,
},
)
.await
{
Ok(token) => token,
Err(err) => {
error!("failed to create user email verification token: {}", err);
return;
}
};
let confirm_link = format!(
"{}/confirm-email?token_id={}",
config.public_url,
Base62Uuid::from(token.token_id)
);
let email = match Message::builder()
.from(config.email_from.clone())
.to(mailbox)
.subject("Welcome to crawlnicle, please confirm your email address")
.multipart(MultiPart::alternative_plain_html(
format!("Welcome to crawlnicle!\n\nPlease confirm your email address\n\nClick here to confirm your email address: {}", confirm_link),
html! {
h1 { "Welcome to crawlnicle!" }
h2 { "Please confirm your email address" }
p {
a href=(confirm_link) { "Click here to confirm your email address" }
}
}.into_string(),
))
{
Ok(email) => email,
Err(err) => {
error!("failed to create email: {}", err);
return;
}
};
// TODO: notify the user that email has been sent somehow
match mailer.send(&email) {
Ok(_) => (),
Err(err) => {
error!("failed to send email: {}", err);
}
}
});
}
pub async fn post(
State(pool): State<PgPool>,
State(mailer): State<SmtpTransport>,