From a444d6a5e554f896cbb28ac6a2b65baefa31bc4b Mon Sep 17 00:00:00 2001 From: Brendan Golden Date: Sun, 17 Sep 2023 18:00:05 +0100 Subject: [PATCH] feat: can now verify the user got the email --- src/bin/update_data.rs | 2 + src/commands/link_email.rs | 120 ++++++++++++++++++++++++++++++++----- src/lib.rs | 4 +- src/main.rs | 5 +- 4 files changed, 114 insertions(+), 17 deletions(-) diff --git a/src/bin/update_data.rs b/src/bin/update_data.rs index cd6d985..1f302fa 100644 --- a/src/bin/update_data.rs +++ b/src/bin/update_data.rs @@ -141,6 +141,8 @@ async fn get_skynet(db: &Pool, config: &Config) { } } } + +// TODO: Tidy up async fn add_users_skynet(db: &Pool, server: &GuildId, user: &SkynetResult) { match sqlx::query_as::<_, Wolves>( " diff --git a/src/commands/link_email.rs b/src/commands/link_email.rs index b9c66e5..45b07e7 100644 --- a/src/commands/link_email.rs +++ b/src/commands/link_email.rs @@ -35,6 +35,12 @@ pub(crate) mod link { return "Already linked".to_string(); } + db_pending_clear_expired(&db).await; + + if get_verify_from_db(&db, &command.user.name).await.is_some() { + return "Linking already in process, please check email.".to_string(); + } + let option = command .data .options @@ -60,13 +66,6 @@ pub(crate) mod link { return "Email already verified".to_string(); } - db_pending_clear_expired(&db).await; - - // send mail - if get_from_db(&db, &command.user.name).await.is_some() { - return "Please check email".to_string(); - } - // generate a auth key let auth = random_string(20); match send_mail(&config, &details, &auth, &command.user.name) { @@ -81,7 +80,7 @@ pub(crate) mod link { } } - format!("Verification email sent to {}, user is {} {:?}", email, command.user.name, command.guild_id) + format!("Verification email sent to {}", email) } pub fn register(command: &mut CreateApplicationCommand) -> &mut CreateApplicationCommand { @@ -96,7 +95,7 @@ pub(crate) mod link { r#" SELECT * FROM wolves - WHERE discord = + WHERE discord = ? "#, ) .bind(user) @@ -137,7 +136,7 @@ pub(crate) mod link { // Substitute in the name of our recipient. p { "Hi " (user) "," } p { - "Please use " pre { "/verify " (auth)} " to verify your discord account." + "Please use " pre { "/verify code:" (auth)} " to verify your discord account." } p { "If you have issues please refer to our Discord server:" @@ -156,7 +155,7 @@ pub(crate) mod link { r#" Hi {user} - Please use "/verify {auth}" to verify your discord account. + Please use "/verify code:{auth}" to verify your discord account. If you have issues please refer to our Discord server: {discord} @@ -189,7 +188,7 @@ pub(crate) mod link { mailer.send(&email) } - async fn db_pending_clear_expired(pool: &Pool) -> Option { + pub async fn db_pending_clear_expired(pool: &Pool) -> Option { sqlx::query_as::<_, WolvesVerify>( r#" DELETE @@ -203,12 +202,12 @@ pub(crate) mod link { .ok() } - async fn get_from_db(db: &Pool, user: &str) -> Option { + pub async fn get_verify_from_db(db: &Pool, user: &str) -> Option { sqlx::query_as::<_, WolvesVerify>( r#" SELECT * FROM wolves_verify - WHERE discord = + WHERE discord = ? "#, ) .bind(user) @@ -232,3 +231,96 @@ pub(crate) mod link { .await } } + +pub(crate) mod verify { + use super::*; + use crate::commands::link_email::link::{db_pending_clear_expired, get_verify_from_db}; + use sqlx::Error; + pub async fn run(command: &ApplicationCommandInteraction, ctx: &Context) -> String { + let db_lock = { + let data_read = ctx.data.read().await; + data_read.get::().expect("Expected Databse in TypeMap.").clone() + }; + let db = db_lock.read().await; + + // check if user has used /link + let details = if let Some(x) = get_verify_from_db(&db, &command.user.name).await { + x + } else { + return "Please use /link first".to_string(); + }; + + let option = command + .data + .options + .get(0) + .expect("Expected code option") + .resolved + .as_ref() + .expect("Expected code object"); + + let code = if let CommandDataOptionValue::String(code) = option { + code + } else { + return "Please provide a verification code".to_string(); + }; + + db_pending_clear_expired(&db).await; + + if &details.auth_code != code { + return "Invalid verification code".to_string(); + } + + match db_pending_clear_successful(&db, &command.user.name).await { + Ok(_) => { + return match set_discord(&db, &command.user.name, &details.email).await { + Ok(_) => "Discord username linked to Wolves".to_string(), + Err(e) => { + println!("{:?}", e); + "Failed to save, please try /link again".to_string() + } + } + } + Err(e) => println!("{:?}", e), + } + + "Failed to verify".to_string() + } + + pub fn register(command: &mut CreateApplicationCommand) -> &mut CreateApplicationCommand { + command.name("verify").description("Verify Wolves Email").create_option(|option| { + option + .name("code") + .description("Code from verification email") + .kind(CommandOptionType::String) + .required(true) + }) + } + + async fn db_pending_clear_successful(pool: &Pool, user: &str) -> Result, Error> { + sqlx::query_as::<_, WolvesVerify>( + r#" + DELETE + FROM wolves_verify + WHERE discord = ? + "#, + ) + .bind(user) + .fetch_optional(pool) + .await + } + + async fn set_discord(db: &Pool, discord: &str, email: &str) -> Result, Error> { + sqlx::query_as::<_, Wolves>( + " + UPDATE wolves + SET discord = ? + WHERE email = ? + ", + ) + .bind(discord) + .bind(email) + .fetch_optional(db) + .await + } +} diff --git a/src/lib.rs b/src/lib.rs index 617924e..863a777 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -212,8 +212,8 @@ pub async fn db_init(config: &Config) -> Result, Error> { sqlx::query( "CREATE TABLE IF NOT EXISTS wolves_verify ( - email text PRIMARY KEY, - discord text not null, + discord text PRIMARY KEY, + email text not null, auth_code text not null, date_expiry text not null )", diff --git a/src/main.rs b/src/main.rs index 2430f0a..28382ec 100644 --- a/src/main.rs +++ b/src/main.rs @@ -56,7 +56,9 @@ impl EventHandler for Handler { println!("[Main] {} is connected!", ready.user.name); Command::set_global_application_commands(&ctx.http, |commands| { - commands.create_application_command(|command| commands::link_email::link::register(command)) + commands + .create_application_command(|command| commands::link_email::link::register(command)) + .create_application_command(|command| commands::link_email::verify::register(command)) }) .await .ok(); @@ -69,6 +71,7 @@ impl EventHandler for Handler { let content = match command.data.name.as_str() { "link" => commands::link_email::link::run(&command, &ctx).await, + "verify" => commands::link_email::verify::run(&command, &ctx).await, _ => "not implemented :(".to_string(), };