From 8760f4440a1d31f1f264880cb544a9cab3a3731c Mon Sep 17 00:00:00 2001 From: Brendan Golden Date: Tue, 26 Sep 2023 00:57:03 +0100 Subject: [PATCH] feat: completed migration Closes #4 --- Cargo.toml | 4 -- src/bin/update_data.rs | 32 +-------- src/bin/update_id.rs | 144 ------------------------------------- src/bin/update_users.rs | 2 +- src/commands/add_server.rs | 6 +- src/commands/link_email.rs | 13 ++-- src/lib.rs | 61 ++++++++-------- 7 files changed, 43 insertions(+), 219 deletions(-) delete mode 100644 src/bin/update_id.rs diff --git a/Cargo.toml b/Cargo.toml index 54043e3..3906510 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,10 +11,6 @@ name = "update_data" [[bin]] name = "update_users" -[[bin]] -name = "update_id" - - [dependencies] serenity = { version = "0.11.6", default-features = false, features = ["client", "gateway", "rustls_backend", "model", "cache"] } tokio = { version = "1.0", features = ["macros", "rt-multi-thread"] } diff --git a/src/bin/update_data.rs b/src/bin/update_data.rs index 1fc25de..0db63e6 100644 --- a/src/bin/update_data.rs +++ b/src/bin/update_data.rs @@ -16,8 +16,7 @@ async fn main() { get_wolves_csv(&db, &config).await; // handle wolves api here get_wolves(&db).await; - // get from skynet for the compsoc server only - get_skynet(&db, &config).await; + } async fn get_wolves_csv(db: &Pool, config: &Config) { @@ -133,35 +132,6 @@ pub struct SkynetResult { discord: String, id_member: String, } -async fn get_skynet(db: &Pool, config: &Config) { - let url = format!("{}/ldap/discord?auth={}", &config.ldap_api, &config.auth); - if let Ok(result) = surf::get(url).recv_json::>().await { - for user in result { - add_users_skynet(db, &user).await; - } - } -} - -async fn add_users_skynet(db: &Pool, user: &SkynetResult) { - match sqlx::query_as::<_, Wolves>( - " - UPDATE wolves - SET discord = ? - WHERE id_wolves = ? - ", - ) - .bind(&user.discord) - .bind(&user.id_member) - .fetch_optional(db) - .await - { - Ok(_) => {} - Err(e) => { - println!("Failure to insert skynet user into database {:?}", user); - println!("{:?}", e); - } - } -} #[derive(Debug, Deserialize)] struct WolvesResult { diff --git a/src/bin/update_id.rs b/src/bin/update_id.rs deleted file mode 100644 index 4923801..0000000 --- a/src/bin/update_id.rs +++ /dev/null @@ -1,144 +0,0 @@ -use serenity::{ - async_trait, - client::{Context, EventHandler}, - model::{ - gateway::{GatewayIntents, Ready}, - }, - Client, -}; -use skynet_discord_bot::{db_init, get_config, Config, DataBase, ServerMembersWolves, Wolves2}; -use sqlx::{Pool, Sqlite}; -use std::{process, sync::Arc}; -use tokio::sync::RwLock; - -#[tokio::main] -async fn main() { - let config = get_config(); - let db = match db_init(&config).await { - Ok(x) => x, - Err(_) => return, - }; - - // Intents are a bitflag, bitwise operations can be used to dictate which intents to use - let intents = GatewayIntents::GUILDS | GatewayIntents::GUILD_MESSAGES | GatewayIntents::MESSAGE_CONTENT | GatewayIntents::GUILD_MEMBERS; - // Build our client. - let mut client = Client::builder(&config.discord_token, intents) - .event_handler(Handler {}) - .await - .expect("Error creating client"); - - { - let mut data = client.data.write().await; - - data.insert::(Arc::new(RwLock::new(config))); - data.insert::(Arc::new(RwLock::new(db))); - } - - if let Err(why) = client.start().await { - println!("Client error: {:?}", why); - } -} - -struct Handler; -#[async_trait] -impl EventHandler for Handler { - async fn ready(&self, ctx: Context, ready: Ready) { - let ctx = Arc::new(ctx); - println!("{} is connected!", ready.user.name); - - bulk_check(Arc::clone(&ctx)).await; - - // finish up - process::exit(0); - } -} - -async fn bulk_check(ctx: Arc) { - let db_lock = { - let data_read = ctx.data.read().await; - data_read.get::().expect("Expected Config in TypeMap.").clone() - }; - - let db = db_lock.read().await; - - // get sk - let mut wolves2 = vec![]; - - // get wolves users - for user in get_server_member_bulk(&db).await{ - let discord = match user.discord{ - None => { - wolves2.push(Wolves2{ - id_wolves: user.id_wolves, - email: user.email, - discord: None, - minecraft: user.minecraft, - }); - - continue; - } - Some(x) => {x} - }; - - if let Ok(x) = user.server.search_members(&ctx.http, &discord, None).await { - for user_tmp in x { - if &user_tmp.user.name == &discord { - wolves2.push(Wolves2{ - id_wolves: user.id_wolves.to_owned(), - email: user.email.to_owned(), - discord: Some(user_tmp.user.id), - minecraft: user.minecraft.to_owned(), - }); - - break; - } - } - } - } - - for user in wolves2 { - - set_member_info(&db, &user).await; - } -} - -async fn get_server_member_bulk(db: &Pool) -> Vec { - sqlx::query_as::<_, ServerMembersWolves>( - r#" - SELECT * - FROM server_members - JOIN wolves USING (id_wolves) - "#, - ) - .fetch_all(db) - .await - .unwrap_or_default() -} - -async fn set_member_info(db: &Pool, user: &Wolves2){ - - let discord = user.discord.map(|x| *x.as_u64() as i64); - - - // save - match sqlx::query_as::<_, Wolves2>( - " - INSERT INTO wolves2 (id_wolves, email, discord) - VALUES ($1, $2, $3) - ON CONFLICT(id_wolves) DO UPDATE SET email = $2, discord = $3 - ", - ) - .bind(&user.id_wolves) - .bind(&user.email) - .bind(discord) - .fetch_optional(db) - .await - { - Ok(_) => {} - Err(e) => { - println!("Failure to insert into {:?}", &user); - println!("{:?}", e); - } - } - -} \ No newline at end of file diff --git a/src/bin/update_users.rs b/src/bin/update_users.rs index 28557c3..6b66cfb 100644 --- a/src/bin/update_users.rs +++ b/src/bin/update_users.rs @@ -82,7 +82,7 @@ async fn bulk_check(ctx: Arc) { if let Ok(x) = server.members(&ctx, None, None).await { for mut member in x { - if members.contains(&member.user.name) { + if members.contains(&member.user.id) { let mut roles = vec![]; if let Some(role) = &role_past { diff --git a/src/commands/add_server.rs b/src/commands/add_server.rs index 0f112a1..5f25646 100644 --- a/src/commands/add_server.rs +++ b/src/commands/add_server.rs @@ -6,7 +6,7 @@ use serenity::{ prelude::{command::CommandOptionType, interaction::application_command::CommandDataOptionValue}, }, }; -use skynet_discord_bot::{DataBase, Servers, Wolves}; +use skynet_discord_bot::{DataBase, Servers}; use sqlx::{Error, Pool, Sqlite}; pub async fn run(command: &ApplicationCommandInteraction, ctx: &Context) -> String { @@ -130,11 +130,11 @@ pub fn register(command: &mut CreateApplicationCommand) -> &mut CreateApplicatio }) } -async fn add_server(db: &Pool, server: &Servers) -> Result, Error> { +async fn add_server(db: &Pool, server: &Servers) -> Result, Error> { let role_past = server.role_past.map(|x| *x.as_u64() as i64); let role_current = server.role_current.map(|x| *x.as_u64() as i64); - sqlx::query_as::<_, Wolves>( + sqlx::query_as::<_, Servers>( " INSERT OR REPLACE INTO servers (server, wolves_api, role_past, role_current) VALUES (?1, ?2, ?3, ?4) diff --git a/src/commands/link_email.rs b/src/commands/link_email.rs index 2d96ce3..7148af4 100644 --- a/src/commands/link_email.rs +++ b/src/commands/link_email.rs @@ -16,6 +16,7 @@ use skynet_discord_bot::{get_now_iso, random_string, Config, DataBase, Wolves, W use sqlx::{Pool, Sqlite}; pub(crate) mod link { + use serenity::model::id::UserId; use super::*; pub async fn run(command: &ApplicationCommandInteraction, ctx: &Context) -> String { @@ -31,7 +32,7 @@ pub(crate) mod link { }; let config = config_lock.read().await; - if get_server_member_discord(&db, &command.user.name).await.is_some() { + if get_server_member_discord(&db, &command.user.id).await.is_some() { return "Already linked".to_string(); } @@ -71,7 +72,7 @@ pub(crate) mod link { // generate a auth key let auth = random_string(20); match send_mail(&config, &details, &auth, &command.user.name) { - Ok(_) => match save_to_db(&db, &details, &auth, &command.user.name).await { + Ok(_) => match save_to_db(&db, &details, &auth, &command.user.id).await { Ok(_) => {} Err(e) => { return format!("Unable to save to db {} {e:?}", &details.email); @@ -92,7 +93,7 @@ pub(crate) mod link { .create_option(|option| option.name("email").description("UL Wolves Email").kind(CommandOptionType::String).required(true)) } - async fn get_server_member_discord(db: &Pool, user: &str) -> Option { + async fn get_server_member_discord(db: &Pool, user: &UserId) -> Option { sqlx::query_as::<_, Wolves>( r#" SELECT * @@ -100,7 +101,7 @@ pub(crate) mod link { WHERE discord = ? "#, ) - .bind(user) + .bind(*user.as_u64() as i64) .fetch_one(db) .await .ok() @@ -218,7 +219,7 @@ pub(crate) mod link { .ok() } - async fn save_to_db(db: &Pool, record: &Wolves, auth: &str, user: &str) -> Result, sqlx::Error> { + async fn save_to_db(db: &Pool, record: &Wolves, auth: &str, user: &UserId) -> Result, sqlx::Error> { sqlx::query_as::<_, WolvesVerify>( " INSERT INTO wolves_verify (email, discord, auth_code, date_expiry) @@ -226,7 +227,7 @@ pub(crate) mod link { ", ) .bind(record.email.to_owned()) - .bind(user) + .bind(*user.as_u64() as i64) .bind(auth.to_owned()) .bind(get_now_iso(false)) .fetch_optional(db) diff --git a/src/lib.rs b/src/lib.rs index f148b4d..2dea62d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -126,41 +126,40 @@ pub struct ServerMembersWolves { pub id_wolves: String, pub expiry: String, pub email: String, - pub discord: Option, + pub discord: Option, pub minecraft: Option, } impl<'r> FromRow<'r, SqliteRow> for ServerMembersWolves { fn from_row(row: &'r SqliteRow) -> Result { let server_tmp: i64 = row.try_get("server")?; let server = GuildId::from(server_tmp as u64); - + let discord = match row.try_get("discord") { + Ok(x) => { + let tmp: i64 = x; + Some(UserId::from(tmp as u64)) + } + _ => None, + }; + Ok(Self { server, id_wolves: row.try_get("id_wolves")?, expiry: row.try_get("expiry")?, email: row.try_get("email")?, - discord: row.try_get("discord")?, + discord, minecraft: row.try_get("minecraft")?, }) } } -#[derive(Debug, Clone, Deserialize, Serialize, sqlx::FromRow)] -pub struct Wolves { - pub id_wolves: String, - pub email: String, - pub discord: Option, - pub minecraft: Option, -} - #[derive(Debug, Clone, Deserialize, Serialize)] -pub struct Wolves2 { +pub struct Wolves { pub id_wolves: String, pub email: String, pub discord: Option, pub minecraft: Option, } -impl<'r> FromRow<'r, SqliteRow> for Wolves2 { +impl<'r> FromRow<'r, SqliteRow> for Wolves { fn from_row(row: &'r SqliteRow) -> Result { let discord = match row.try_get("discord") { Ok(x) => { @@ -179,13 +178,26 @@ impl<'r> FromRow<'r, SqliteRow> for Wolves2 { } } -#[derive(Debug, Clone, Deserialize, Serialize, sqlx::FromRow)] +#[derive(Debug, Clone, Deserialize, Serialize)] pub struct WolvesVerify { pub email: String, - pub discord: String, + pub discord: UserId, pub auth_code: String, pub date_expiry: String, } +impl<'r> FromRow<'r, SqliteRow> for WolvesVerify { + 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")?, + date_expiry: row.try_get("date_expiry")?, + }) + } +} #[derive(Debug, Clone, Deserialize, Serialize)] pub struct Servers { @@ -240,17 +252,6 @@ pub async fn db_init(config: &Config) -> Result, Error> { sqlx::query( "CREATE TABLE IF NOT EXISTS wolves ( - id_wolves text PRIMARY KEY, - email text not null, - discord text, - minecraft text - )", - ) - .execute(&pool) - .await?; - - sqlx::query( - "CREATE TABLE IF NOT EXISTS wolves2 ( id_wolves text PRIMARY KEY, email text not null, discord integer, @@ -264,10 +265,10 @@ pub async fn db_init(config: &Config) -> Result, Error> { sqlx::query( "CREATE TABLE IF NOT EXISTS wolves_verify ( - discord text PRIMARY KEY, - email text not null, - auth_code text not null, - date_expiry text not null + discord integer PRIMARY KEY, + email text not null, + auth_code text not null, + date_expiry text not null )", ) .execute(&pool)