diff --git a/Cargo.lock b/Cargo.lock index 4929efa..23bef46 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -107,9 +107,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.89" +version = "1.0.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86fdf8605db99b54d3cd748a44c6d04df638eb5dafb219b135d0149bd0db01f6" +checksum = "4c95c10ba0b00a02636238b814946408b1322d5ac4760326e6fb8ec956d85775" [[package]] name = "async-channel" @@ -143,7 +143,7 @@ dependencies = [ "async-task", "concurrent-queue", "fastrand 2.1.1", - "futures-lite 2.3.0", + "futures-lite 2.5.0", "slab", ] @@ -158,21 +158,21 @@ dependencies = [ "async-io", "async-lock", "blocking", - "futures-lite 2.3.0", + "futures-lite 2.5.0", "once_cell", ] [[package]] name = "async-io" -version = "2.3.4" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "444b0228950ee6501b3568d3c93bf1176a1fdbc3b758dcd9475046d30f4dc7e8" +checksum = "43a2b323ccce0a1d90b449fd71f2a06ca7faa7c54c2751f06c9bd851fc061059" dependencies = [ "async-lock", "cfg-if", "concurrent-queue", "futures-io", - "futures-lite 2.3.0", + "futures-lite 2.5.0", "parking", "polling", "rustix", @@ -206,7 +206,7 @@ dependencies = [ "futures-channel", "futures-core", "futures-io", - "futures-lite 2.3.0", + "futures-lite 2.5.0", "gloo-timers", "kv-log-macro", "log", @@ -381,7 +381,7 @@ dependencies = [ "async-channel 2.3.1", "async-task", "futures-io", - "futures-lite 2.3.0", + "futures-lite 2.5.0", "piper", ] @@ -586,9 +586,9 @@ dependencies = [ [[package]] name = "curl" -version = "0.4.46" +version = "0.4.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e2161dd6eba090ff1594084e95fd67aeccf04382ffea77999ea94ed42ec67b6" +checksum = "d9fb4d13a1be2b58f14d60adba57c9834b78c62fd86c3e76a148f732686e9265" dependencies = [ "curl-sys", "libc", @@ -601,9 +601,9 @@ dependencies = [ [[package]] name = "curl-sys" -version = "0.4.75+curl-8.10.0" +version = "0.4.78+curl-8.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a4fd752d337342e4314717c0d9b6586b059a120c80029ebe4d49b11fec7875e" +checksum = "8eec768341c5c7789611ae51cf6c459099f22e64a5d5d0ce4892434e33821eaf" dependencies = [ "cc", "libc", @@ -923,9 +923,9 @@ dependencies = [ [[package]] name = "futures-lite" -version = "2.3.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52527eb5074e35e9339c6b4e8d12600c7128b68fb25dcb9fa9dec18f7c25f3a5" +checksum = "cef40d21ae2c515b51041df9ed313ed21e572df340ea58a922a0aefe7e8891a1" dependencies = [ "fastrand 2.1.1", "futures-core", @@ -1298,7 +1298,7 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", - "socket2 0.4.10", + "socket2 0.5.7", "tokio", "tower-service", "tracing", @@ -1907,18 +1907,18 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pin-project" -version = "1.1.5" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" +checksum = "be57f64e946e500c8ee36ef6331845d40a93055567ec57e8fae13efd33759b95" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.5" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" +checksum = "3c0f5fad0874fc7abcd4d750e76917eaebbecaa2c20bde22e1dbeeba8beb758c" dependencies = [ "proc-macro2", "quote", @@ -1977,9 +1977,9 @@ checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" [[package]] name = "polling" -version = "3.7.3" +version = "3.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc2790cd301dec6cd3b7a025e4815cf825724a51c98dccfe6a3e55f05ffb6511" +checksum = "a604568c3202727d1507653cb121dbd627a58684eb09a820fd746bee38b4442f" dependencies = [ "cfg-if", "concurrent-queue", @@ -3521,9 +3521,9 @@ checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" [[package]] name = "value-bag" -version = "1.9.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a84c137d37ab0142f0f2ddfe332651fdbf252e7b7dbb4e67b6c1f1b2e925101" +checksum = "3ef4c4aa54d5d05a279399bfa921ec387b7aba77caf7a682ae8d86785b8fdad2" [[package]] name = "vcpkg" diff --git a/Cargo.toml b/Cargo.toml index 2dc64c8..6e60066 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,6 +14,9 @@ name = "update_users" [[bin]] name = "update_minecraft" +[[bin]] +name = "test" + [dependencies] # discord library serenity = { version = "0.11.6", default-features = false, features = ["client", "gateway", "rustls_backend", "model", "cache"] } diff --git a/db/migrations/7_minecraft-bedrock.sql b/db/migrations/7_minecraft-bedrock.sql new file mode 100644 index 0000000..71d8976 --- /dev/null +++ b/db/migrations/7_minecraft-bedrock.sql @@ -0,0 +1,3 @@ + +-- Using this col we will be able to see if someone has a bedrock account (as well as a java one) +ALTER TABLE wolves ADD COLUMN minecraft_uid TEXT; \ No newline at end of file diff --git a/src/commands/minecraft.rs b/src/commands/minecraft.rs index b6b6dd5..e8f132d 100644 --- a/src/commands/minecraft.rs +++ b/src/commands/minecraft.rs @@ -15,18 +15,29 @@ pub(crate) mod user { pub(crate) mod add { use super::*; use crate::commands::link_email::link::get_server_member_discord; + use serde::{Deserialize, Serialize}; use serenity::model::id::UserId; use skynet_discord_bot::{whitelist_update, Config, Minecraft, Wolves}; use sqlx::Error; pub fn register(command: &mut CreateApplicationCommand) -> &mut CreateApplicationCommand { - command.name("link_minecraft").description("Link your minecraft account").create_option(|option| { - option - .name("minecraft-username") - .description("Your Minecraft username") - .kind(CommandOptionType::String) - .required(true) - }) + command + .name("link_minecraft") + .description("Link your minecraft account") + .create_option(|option| { + option + .name("minecraft-username") + .description("Your Minecraft username") + .kind(CommandOptionType::String) + .required(true) + }) + .create_option(|option| { + option + .name("java-account") + .description("Is this a Java account?") + .kind(CommandOptionType::Boolean) + .required(false) + }) } pub async fn run(command: &ApplicationCommandInteraction, ctx: &Context) -> String { @@ -61,19 +72,42 @@ pub(crate) mod user { return "Please provide a valid username".to_string(); }; - // insert the username into the database - match add_minecraft(&db, &command.user.id, username).await { - Ok(_) => {} - Err(e) => { - dbg!("{:?}", e); - return format!("Failure to minecraft username {:?}", username); + // this is always true unless they state its not + let mut java = true; + if let Some(x) = command.data.options.get(1) { + if let Some(CommandDataOptionValue::Boolean(z)) = x.to_owned().resolved { + java = z; + } + } + + if java { + // insert the username into the database + match add_minecraft(&db, &command.user.id, username).await { + Ok(_) => {} + Err(e) => { + dbg!("{:?}", e); + return format!("Failure to minecraft username {:?}", username); + } + } + } else { + match get_minecraft_bedrock(username, &config.minecraft_mcprofile).await { + None => { + return format!("No UID found for {:?}", username); + } + Some(x) => match add_minecraft_bedrock(&db, &command.user.id, &x.floodgateuid).await { + Ok(_) => {} + Err(e) => { + dbg!("{:?}", e); + return format!("Failure to minecraft UID {:?}", &x.floodgateuid); + } + }, } } // get a list of servers that the user is a member of if let Ok(servers) = get_servers(&db, &command.user.id).await { for server in servers { - whitelist_update(&vec![username.to_string()], &server.minecraft, &config.discord_token_minecraft).await; + whitelist_update(&vec![(username.to_string(), java)], &server.minecraft, &config.discord_token_minecraft).await; } } @@ -94,6 +128,51 @@ pub(crate) mod user { .await } + #[derive(Serialize, Deserialize, Debug)] + struct BedrockDetails { + pub gamertag: String, + pub xuid: String, + pub floodgateuid: String, + pub icon: String, + pub gamescore: String, + pub accounttier: String, + pub textureid: String, + pub skin: String, + pub linked: bool, + pub java_uuid: String, + pub java_name: String, + } + + async fn get_minecraft_bedrock(username: &str, api_key: &str) -> Option { + let url = format!("https://mcprofile.io/api/v1/bedrock/gamertag/{username}/"); + match surf::get(url) + .header("x-api-key", api_key) + .header("User-Agent", "UL Computer Society") + .recv_json() + .await + { + Ok(res) => Some(res), + Err(e) => { + dbg!(e); + None + } + } + } + + async fn add_minecraft_bedrock(db: &Pool, user: &UserId, minecraft: &str) -> Result, Error> { + sqlx::query_as::<_, Wolves>( + " + UPDATE wolves + SET minecraft_uid = ?2 + WHERE discord = ?1; + ", + ) + .bind(*user.as_u64() as i64) + .bind(minecraft) + .fetch_optional(db) + .await + } + async fn get_servers(db: &Pool, discord: &UserId) -> Result, Error> { sqlx::query_as::<_, Minecraft>( " diff --git a/src/lib.rs b/src/lib.rs index d73b009..b5a0a4e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -31,6 +31,7 @@ pub struct Config { // tokens for discord and other API's pub discord_token: String, pub discord_token_minecraft: String, + pub minecraft_mcprofile: String, // email settings pub mail_smtp: String, @@ -58,6 +59,7 @@ pub fn get_config() -> Config { let mut config = Config { discord_token: "".to_string(), discord_token_minecraft: "".to_string(), + minecraft_mcprofile: "".to_string(), home: ".".to_string(), database: "database.db".to_string(), @@ -82,6 +84,9 @@ pub fn get_config() -> Config { if let Ok(x) = env::var("DISCORD_TOKEN_MINECRAFT") { config.discord_token_minecraft = x.trim().to_string(); } + if let Ok(x) = env::var("MINECRAFT_MCPROFILE_KEY") { + config.minecraft_mcprofile = x.trim().to_string(); + } if let Ok(x) = env::var("EMAIL_SMTP") { config.mail_smtp = x.trim().to_string(); @@ -130,6 +135,7 @@ pub struct ServerMembersWolves { pub email: String, pub discord: Option, pub minecraft: Option, + pub minecraft_uid: Option, } impl<'r> FromRow<'r, SqliteRow> for ServerMembersWolves { fn from_row(row: &'r SqliteRow) -> Result { @@ -154,6 +160,7 @@ impl<'r> FromRow<'r, SqliteRow> for ServerMembersWolves { email: row.try_get("email")?, discord, minecraft: row.try_get("minecraft")?, + minecraft_uid: row.try_get("minecraft_uid")?, }) } } @@ -699,7 +706,10 @@ pub async fn update_server(server_id: &str, db: &Pool, g_id: &GuildId, c let mut usernames = vec![]; for member in get_server_member_bulk(db, g_id).await { if let Some(x) = member.minecraft { - usernames.push(x); + usernames.push((x, true)); + } + if let Some(x) = member.minecraft_uid { + usernames.push((x, true)); } } if !usernames.is_empty() { @@ -763,13 +773,19 @@ struct BodyDelete { files: Vec, } -pub async fn whitelist_update(add: &Vec, server: &str, token: &str) { +pub async fn whitelist_update(add: &Vec<(String, bool)>, server: &str, token: &str) { let url_base = format!("http://panel.games.skynet.ie/api/client/servers/{server}"); let bearer = format!("Bearer {token}"); - for name in add { - let data = BodyCommand { - command: format!("whitelist add {name}"), + for (name, java) in add { + let data = if *java { + BodyCommand { + command: format!("whitelist add {name}"), + } + } else { + BodyCommand { + command: format!("fwhitelist add {name}"), + } }; post(&format!("{url_base}/command"), &bearer, &data).await; }