diff --git a/src/commands/committee.rs b/src/commands/committee.rs deleted file mode 100644 index 3de0ec9..0000000 --- a/src/commands/committee.rs +++ /dev/null @@ -1,311 +0,0 @@ -use lettre::{ - message::{header, MultiPart, SinglePart}, - transport::smtp::{self, authentication::Credentials}, - Message, SmtpTransport, Transport, -}; -use maud::html; -use serenity::{ - builder::CreateApplicationCommand, - client::Context, - model::{ - application::interaction::application_command::ApplicationCommandInteraction, - id::UserId, - prelude::{command::CommandOptionType, interaction::application_command::CommandDataOptionValue}, - }, -}; -use skynet_discord_bot::{random_string, Config, DataBase}; -use sqlx::{Pool, Sqlite}; - -pub mod link { - use super::*; - use serenity::model::id::GuildId; - use skynet_discord_bot::Committee; - - pub async fn run(command: &ApplicationCommandInteraction, ctx: &Context) -> String { - let committee_server = GuildId(1220150752656363520); - match command.guild_id { - None => { - return "Not in correct discord server.".to_string(); - } - Some(x) => { - if x != committee_server { - return "Not in correct discord server.".to_string(); - } - } - } - - let option = command - .data - .options - .first() - .expect("Expected email option") - .resolved - .as_ref() - .expect("Expected email object"); - - let email = if let CommandDataOptionValue::String(email) = option { - email.trim() - } else { - return "Please provide a valid committee email.".to_string(); - }; - - // fail early - if !email.ends_with("@ulwolves.ie") { - return "Please use a @ulwolves.ie address you have access to.".to_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; - - let config_lock = { - let data_read = ctx.data.read().await; - data_read.get::().expect("Expected Config in TypeMap.").clone() - }; - let config = config_lock.read().await; - - if get_server_member_discord(&db, &command.user.id).await.is_some() { - return "Already linked".to_string(); - } - - if get_verify_from_db(&db, &command.user.id).await.is_some() { - return "Linking already in process, please check email.".to_string(); - } - - // generate a auth key - let auth = random_string(20); - match send_mail(&config, email, &auth, &command.user.name) { - Ok(_) => match save_to_db(&db, email, &auth, &command.user.id).await { - Ok(_) => {} - Err(e) => { - return format!("Unable to save to db {} {e:?}", email); - } - }, - Err(e) => { - return format!("Unable to send mail to {} {e:?}", email); - } - } - - format!("Verification email sent to {}, it may take up to 15 min for it to arrive. If it takes longer check the Junk folder.", email) - } - - pub fn register(command: &mut CreateApplicationCommand) -> &mut CreateApplicationCommand { - command - .name("link_committee") - .description("Verify you are a committee member") - .create_option(|option| { - option - .name("email") - .description("UL Wolves Committee Email") - .kind(CommandOptionType::String) - .required(true) - }) - } - - pub async fn get_server_member_discord(db: &Pool, user: &UserId) -> Option { - sqlx::query_as::<_, Committee>( - r#" - SELECT * - FROM committee - WHERE discord = ? - "#, - ) - .bind(*user.as_u64() as i64) - .fetch_one(db) - .await - .ok() - } - - fn send_mail(config: &Config, mail: &str, auth: &str, user: &str) -> Result { - let sender = format!("UL Computer Society <{}>", &config.mail_user); - - // Create the html we want to send. - let html = html! { - head { - title { "Hello from Skynet!" } - style type="text/css" { - "h2, h4 { font-family: Arial, Helvetica, sans-serif; }" - } - } - div style="display: flex; flex-direction: column; align-items: center;" { - h2 { "Hello from Skynet!" } - // Substitute in the name of our recipient. - p { "Hi " (user) "," } - p { - "Please use " pre { "/verify_committee code: " (auth)} " to verify your discord account." - } - p { - "Skynet Team" - br; - "UL Computer Society" - } - } - }; - - let body_text = format!( - r#" - Hi {user} - - Please use "/verify_committee code: {auth}" to verify your discord account. - - Skynet Team - UL Computer Society - "# - ); - - // Build the message. - let email = Message::builder() - .from(sender.parse().unwrap()) - .to(mail.parse().unwrap()) - .subject("Skynet-Discord: Link Committee.") - .multipart( - // This is composed of two parts. - // also helps not trip spam settings (uneven number of url's - MultiPart::alternative() - .singlepart(SinglePart::builder().header(header::ContentType::TEXT_PLAIN).body(body_text)) - .singlepart(SinglePart::builder().header(header::ContentType::TEXT_HTML).body(html.into_string())), - ) - .expect("failed to build email"); - - let creds = Credentials::new(config.mail_user.clone(), config.mail_pass.clone()); - - // Open a remote connection to gmail using STARTTLS - let mailer = SmtpTransport::starttls_relay(&config.mail_smtp).unwrap().credentials(creds).build(); - - // Send the email - mailer.send(&email) - } - - pub async fn get_verify_from_db(db: &Pool, user: &UserId) -> Option { - sqlx::query_as::<_, Committee>( - r#" - SELECT * - FROM committee - WHERE discord = ? - "#, - ) - .bind(*user.as_u64() as i64) - .fetch_one(db) - .await - .ok() - } - - async fn save_to_db(db: &Pool, email: &str, auth: &str, user: &UserId) -> Result, sqlx::Error> { - sqlx::query_as::<_, Committee>( - " - INSERT INTO committee (email, discord, auth_code) - VALUES (?1, ?2, ?3) - ", - ) - .bind(email.to_owned()) - .bind(*user.as_u64() as i64) - .bind(auth.to_owned()) - .fetch_optional(db) - .await - } -} - -pub mod verify { - use super::*; - use crate::commands::committee::link::get_verify_from_db; - use serenity::model::id::{GuildId, RoleId}; - use serenity::model::user::User; - use skynet_discord_bot::Committee; - use sqlx::Error; - - pub async fn run(command: &ApplicationCommandInteraction, ctx: &Context) -> String { - let committee_server = GuildId(1220150752656363520); - match command.guild_id { - None => { - return "Not in correct discord server.".to_string(); - } - Some(x) => { - if x != committee_server { - return "Not in correct discord server.".to_string(); - } - } - } - - let db_lock = { - let data_read = ctx.data.read().await; - data_read.get::().expect("Expected Database in TypeMap.").clone() - }; - let db = db_lock.read().await; - - // check if user has used /link_committee - let details = if let Some(x) = get_verify_from_db(&db, &command.user.id).await { - x - } else { - return "Please use /link_committee first".to_string(); - }; - - let option = command - .data - .options - .first() - .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(); - }; - - if &details.auth_code != code { - return "Invalid verification code".to_string(); - } - - match set_discord(&db, &command.user.id).await { - Ok(_) => { - // get teh right roles for the user - set_server_roles(&command.user, ctx).await; - "Discord username linked to Wolves for committee".to_string() - } - Err(e) => { - println!("{:?}", e); - "Failed to save, please try /link_committee again".to_string() - } - } - } - - pub fn register(command: &mut CreateApplicationCommand) -> &mut CreateApplicationCommand { - command - .name("verify_committee") - .description("Verify Wolves Committee Email") - .create_option(|option| { - option - .name("code") - .description("Code from verification email") - .kind(CommandOptionType::String) - .required(true) - }) - } - - async fn set_discord(db: &Pool, discord: &UserId) -> Result, Error> { - sqlx::query_as::<_, Committee>( - " - UPDATE committee - SET committee = 1 - WHERE discord = ? - ", - ) - .bind(*discord.as_u64() as i64) - .fetch_optional(db) - .await - } - - async fn set_server_roles(discord: &User, ctx: &Context) { - let committee_server = GuildId(1220150752656363520); - if let Ok(mut member) = committee_server.member(&ctx.http, &discord.id).await { - let committee_member = RoleId(1226602779968274573); - if let Err(e) = member.add_role(&ctx, committee_member).await { - println!("{:?}", e); - } - } - } -} diff --git a/src/commands/mod.rs b/src/commands/mod.rs index 3acfe81..9d3bea5 100644 --- a/src/commands/mod.rs +++ b/src/commands/mod.rs @@ -1,4 +1,3 @@ pub mod add_server; -pub mod committee; pub mod link_email; pub mod minecraft; diff --git a/src/lib.rs b/src/lib.rs index a247d33..c6c8d68 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -202,25 +202,11 @@ impl<'r> FromRow<'r, SqliteRow> for WolvesVerify { } } -#[derive(Debug, Clone, Deserialize, Serialize)] +#[derive(Debug, Clone, sqlx::FromRow)] pub struct Committee { - pub email: String, - pub discord: UserId, - pub auth_code: String, - pub committee: i64, -} -impl<'r> FromRow<'r, SqliteRow> for Committee { - fn from_row(row: &'r SqliteRow) -> Result { - let user_tmp: i64 = row.try_get("discord")?; - let discord = UserId::from(user_tmp as u64); - - Ok(Self { - email: row.try_get("email")?, - discord, - auth_code: row.try_get("auth_code")?, - committee: row.try_get("committee")?, - }) - } + pub id: i64, + pub name: UserId, + pub members: Vec, } #[derive(Debug, Clone, Deserialize, Serialize)] diff --git a/src/main.rs b/src/main.rs index cbe8d5d..d1ebf2d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -64,9 +64,6 @@ impl EventHandler for Handler { .create_application_command(|command| commands::minecraft::server::list::register(command)) .create_application_command(|command| commands::minecraft::server::delete::register(command)) .create_application_command(|command| commands::minecraft::user::add::register(command)) - // for committee server, temp - .create_application_command(|command| commands::committee::link::register(command)) - .create_application_command(|command| commands::committee::verify::register(command)) }) .await { @@ -92,9 +89,6 @@ impl EventHandler for Handler { "minecraft_add" => commands::minecraft::server::add::run(&command, &ctx).await, "minecraft_list" => commands::minecraft::server::list::run(&command, &ctx).await, "minecraft_delete" => commands::minecraft::server::delete::run(&command, &ctx).await, - // for teh committee server, temporary - "link_committee" => commands::committee::link::run(&command, &ctx).await, - "verify_committee" => commands::committee::verify::run(&command, &ctx).await, _ => "not implemented :(".to_string(), };