From ca55a78447089a2b04446d917777e25f1fd5f7f3 Mon Sep 17 00:00:00 2001 From: Brendan Golden Date: Sat, 23 Nov 2024 21:53:30 +0000 Subject: [PATCH] feat: switched over to using a library to interact with teh wolves API --- Cargo.lock | 86 +++++++++++---- Cargo.toml | 5 +- src/commands/link_email.rs | 31 +----- src/common/wolves.rs | 218 ++----------------------------------- 4 files changed, 85 insertions(+), 255 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cc8ef0d..af719e5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -218,6 +218,28 @@ dependencies = [ "wasm-bindgen-futures", ] +[[package]] +name = "async-stream" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476" +dependencies = [ + "async-stream-impl", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-stream-impl" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.89", +] + [[package]] name = "async-task" version = "4.7.1" @@ -232,7 +254,7 @@ checksum = "a27b8a3a6e1a44fa4c8baf1f653e4172e81486d4941f2237e20dc2d0cf4ddff1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.89", ] [[package]] @@ -920,7 +942,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.89", ] [[package]] @@ -1803,7 +1825,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.89", ] [[package]] @@ -1900,7 +1922,7 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.89", ] [[package]] @@ -2026,9 +2048,9 @@ checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" [[package]] name = "proc-macro2" -version = "1.0.86" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" dependencies = [ "unicode-ident", ] @@ -2446,9 +2468,9 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" -version = "1.0.210" +version = "1.0.215" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" +checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f" dependencies = [ "serde_derive", ] @@ -2465,13 +2487,13 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.210" +version = "1.0.215" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" +checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.89", ] [[package]] @@ -2634,13 +2656,13 @@ dependencies = [ "lettre", "maud", "rand 0.8.5", - "reqwest 0.12.9", "serde", "serde_json", "serenity", "sqlx", "surf", "tokio", + "wolves_oxidised", ] [[package]] @@ -3037,9 +3059,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.77" +version = "2.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" +checksum = "44d46482f1c1c87acd84dea20c1bf5ebff4c757009ed6bf19cfd36fb10e92c4e" dependencies = [ "proc-macro2", "quote", @@ -3133,7 +3155,7 @@ checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.89", ] [[package]] @@ -3246,7 +3268,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.89", ] [[package]] @@ -3302,6 +3324,19 @@ dependencies = [ "tokio", ] +[[package]] +name = "tokio-test" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2468baabc3311435b55dd935f702f42cd1b8abb7e754fb7dfb16bd36aa88f9f7" +dependencies = [ + "async-stream", + "bytes 1.7.1", + "futures-core", + "tokio", + "tokio-stream", +] + [[package]] name = "tokio-util" version = "0.7.12" @@ -3341,7 +3376,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.89", ] [[package]] @@ -3569,7 +3604,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.89", "wasm-bindgen-shared", ] @@ -3603,7 +3638,7 @@ checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.89", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -3891,6 +3926,17 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "wolves_oxidised" +version = "0.1.0" +source = "git+https://forgejo.skynet.ie/Skynet/wolves-oxidised.git#eee6a76c695a36f1fe220fdeafd5a43757e50527" +dependencies = [ + "reqwest 0.12.9", + "serde", + "serde_json", + "tokio-test", +] + [[package]] name = "zerocopy" version = "0.7.35" @@ -3909,7 +3955,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.89", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index c94d0a0..92fa6c5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,7 +18,10 @@ name = "update_minecraft" # discord library serenity = { version = "0.11.6", default-features = false, features = ["client", "gateway", "rustls_backend", "model", "cache"] } tokio = { version = "1.0", features = ["macros", "rt-multi-thread", "full"] } -reqwest = { version = "0.12", features = ["json"] } + +# wolves api +# TODO: move off of unstable +wolves_oxidised = { git = "https://forgejo.skynet.ie/Skynet/wolves-oxidised.git", features = ["unstable"]} # to make the http requests surf = "2.3.2" diff --git a/src/commands/link_email.rs b/src/commands/link_email.rs index ace4691..9d6328f 100644 --- a/src/commands/link_email.rs +++ b/src/commands/link_email.rs @@ -64,8 +64,10 @@ pub mod link { None => { let invalid_user = "Please check it matches (including case) your preferred contact on https://ulwolves.ie/memberships/profile and that you are fully paid up.".to_string(); + let wolves = wolves_oxidised::Client::new(&config.wolves_url, Some(&config.wolves_api)); + // see if the user actually exists - let id = match get_user(&config, email).await { + let id = match wolves.get_member(email).await { None => { return invalid_user; } @@ -274,33 +276,6 @@ pub mod link { result: WolvesResultUserResult, } - async fn get_user(config: &Config, email: &str) -> Option { - let url = format!("{}/get_id_from_email", &config.wolves_url); - match reqwest::Client::new() - .post(&url) - .form(&[("email", email)]) - .header("X-AM-Identity", &config.wolves_api) - .send() - .await - { - Ok(x) => { - if let Ok(y) = x.json::().await { - // this is the only time we will get a positive response, the None at the end catches everything else - if let WolvesResultUserResult::S(z) = y.result { - if let Ok(id) = z.parse::() { - return Some(id); - } - } - } - } - Err(e) => { - dbg!(e); - } - } - - None - } - async fn save_to_db_user(db: &Pool, id_wolves: i64, email: &str) -> Result, sqlx::Error> { sqlx::query_as::<_, Wolves>( " diff --git a/src/common/wolves.rs b/src/common/wolves.rs index 5a1e1b7..0f975e3 100644 --- a/src/common/wolves.rs +++ b/src/common/wolves.rs @@ -52,32 +52,13 @@ pub mod cns { use crate::common::set_roles::normal::update_server; use crate::common::wolves::{add_users_wolves, WolvesResultUserMin}; use crate::Config; - use serde::{Deserialize, Serialize}; use serenity::client::Context; use serenity::model::id::GuildId; use sqlx::{Pool, Sqlite}; use std::collections::BTreeMap; - #[derive(Deserialize, Serialize, Debug)] - struct WolvesResultUser { - // TODO: Might be worth trying to get this replaced with the club/soc ID? - committee: String, - member_id: String, - first_name: String, - last_name: String, - contact_email: String, - opt_in_email: String, - student_id: Option, - note: Option, - expiry: String, - requested: String, - approved: String, - sitename: String, - domain: String, - } - - impl From<&WolvesResultUser> for WolvesResultUserMin { - fn from(value: &WolvesResultUser) -> Self { + impl From<&wolves_oxidised::WolvesUser> for WolvesResultUserMin { + fn from(value: &wolves_oxidised::WolvesUser) -> Self { Self { member_id: value.member_id.to_owned(), contact_email: value.contact_email.to_owned(), @@ -85,18 +66,6 @@ pub mod cns { } } - #[derive(Deserialize, Serialize, Debug)] - struct WolvesResult { - success: i8, - result: Vec, - } - - #[derive(Deserialize, Serialize, Debug)] - struct WolvesResultLocal { - pub id_wolves: String, - pub email: String, - pub expiry: String, - } pub async fn get_wolves(ctx: &Context) { let db_lock = { let data_read = ctx.data.read().await; @@ -110,9 +79,13 @@ pub mod cns { }; let config = config_lock.read().await; + // set up teh client + let wolves = wolves_oxidised::Client::new(&config.wolves_url, Some(&config.wolves_api)); + for server_config in get_server_config_bulk(&db).await { let Servers { server, + // this is the unique api key for each club/soc wolves_api, .. } = &server_config; @@ -122,7 +95,7 @@ pub mod cns { // list of users that need to be updated for this server let mut user_to_update = vec![]; - for user in get_wolves_sub(&config, wolves_api).await { + for user in wolves.get_members(wolves_api).await { let id = user.member_id.parse::().unwrap_or_default(); match existing.get(&(id as i64)) { None => { @@ -168,32 +141,7 @@ pub mod cns { .unwrap_or_default() } - async fn get_wolves_sub(config: &Config, wolves_api: &str) -> Vec { - if config.wolves_url.is_empty() { - return vec![]; - } - - let url = format!("{}/get_members", &config.wolves_url); - - // get wolves data - if let Ok(mut res) = surf::post(&url).header("X-AM-Identity", wolves_api).await { - if let Ok(WolvesResult { - success, - result, - }) = res.body_json().await - { - if success != 1 { - return vec![]; - } - - return result; - } - } - - vec![] - } - - async fn add_users_server_members(db: &Pool, server: &GuildId, user: &WolvesResultUser) { + async fn add_users_server_members(db: &Pool, server: &GuildId, user: &wolves_oxidised::WolvesUser) { match sqlx::query_as::<_, ServerMembers>( " INSERT OR REPLACE INTO server_members (server, id_wolves, expiry) @@ -221,28 +169,9 @@ pub mod cns { pub mod committees { use crate::common::database::DataBase; use crate::Config; - use serde::{Deserialize, Serialize}; use serenity::client::Context; use sqlx::{Pool, Sqlite}; - // This is what Wolves returns to us - #[derive(Deserialize, Serialize, Debug)] - struct WolvesResult { - success: i8, - result: Vec, - } - - // this is teh actual data we care about - #[derive(Deserialize, Serialize, Debug)] - struct WolvesResultCNS { - id: String, - name: String, - // Link to their page such as https://ulwolves.ie/society/computer - link: String, - // array of Committee members member_id's - committee: Vec, - } - // Database entry for it #[derive(Debug, Clone, sqlx::FromRow)] pub struct Committees { @@ -253,8 +182,8 @@ pub mod committees { pub committee: Vec, } - impl From for Committees { - fn from(value: WolvesResultCNS) -> Self { + impl From for Committees { + fn from(value: wolves_oxidised::WolvesCNS) -> Self { Self { id: value.id.parse().unwrap_or(0), name: value.name, @@ -277,40 +206,14 @@ pub mod committees { }; let config = config_lock.read().await; + let wolves = wolves_oxidised::Client::new(&config.wolves_url, Some(&config.wolves_api)); // request data from wolves - for committee_wolves in get_committees(&config).await { + for committee_wolves in wolves.get_committees().await { let committee = Committees::from(committee_wolves); add_committee(&db, &committee).await; } } - async fn get_committees(config: &Config) -> Vec { - if config.wolves_url.is_empty() { - return vec![]; - } - - // TODO: Change teh stored env value to teh base domain - // TODO: this address may change - let url = format!("{}/get_cns", &config.wolves_url); - - // get wolves data - if let Ok(mut res) = surf::post(&url).header("X-AM-Identity", &config.wolves_api).await { - if let Ok(WolvesResult { - success, - result, - }) = res.body_json().await - { - if success != 1 { - return vec![]; - } - - return result; - } - } - - vec![] - } - async fn add_committee(db: &Pool, committee: &Committees) { match sqlx::query_as::<_, Committees>( " @@ -334,100 +237,3 @@ pub mod committees { } } } - -/** -get the data for an individual user -*/ -pub mod individual { - use crate::common::database::DataBase; - use crate::common::wolves::{add_users_wolves, WolvesResultUserMin}; - use crate::Config; - use serde::{Deserialize, Serialize}; - use serenity::client::Context; - - #[derive(Deserialize, Serialize, Debug)] - struct WolvesResultUser { - // committee: String, - member_id: String, - // first_name: String, - // last_name: String, - contact_email: String, - // opt_in_email: String, - // student_id: Option, - // note: Option, - // expiry: String, - // requested: String, - // approved: String, - // sitename: String, - // domain: String, - } - - impl From<&WolvesResultUser> for WolvesResultUserMin { - fn from(value: &WolvesResultUser) -> Self { - Self { - member_id: value.member_id.to_owned(), - contact_email: value.contact_email.to_owned(), - } - } - } - - #[derive(Deserialize, Serialize, Debug)] - struct WolvesResult { - success: i8, - result: WolvesResultUser, - } - - pub async fn get_user(ctx: &Context, email: &str) -> bool { - 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; - - 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; - - // TODO: proper api key management - let api_key = ""; - // request data from wolves - match get_user_sub(&config, api_key, email).await { - None => false, - // if exists save it and return true - Some(user) => { - // add to db - add_users_wolves(&db, &WolvesResultUserMin::from(&user)).await; - - true - } - } - } - - async fn get_user_sub(config: &Config, wolves_api: &str, _email: &str) -> Option { - if config.wolves_url.is_empty() { - return None; - } - - // TODO: Change teh stored env value to teh base domain - let url = format!("{}/get_member", &config.wolves_url); - - // get wolves data - if let Ok(mut res) = surf::post(&url).header("X-AM-Identity", wolves_api).await { - if let Ok(WolvesResult { - success, - result, - }) = res.body_json().await - { - if success != 1 { - return None; - } - - return Some(result); - } - } - - None - } -}