diff --git a/Cargo.lock b/Cargo.lock index 34c8f18..2fd8e05 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8,15 +8,6 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" -[[package]] -name = "android_system_properties" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" -dependencies = [ - "libc", -] - [[package]] name = "async-trait" version = "0.1.57" @@ -102,28 +93,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] -name = "chrono" -version = "0.4.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfd4d1b31faaa3a89d7934dbded3111da0d2ef28e3ebccdb4f0179f5929d1ef1" -dependencies = [ - "iana-time-zone", - "num-integer", - "num-traits", - "serde", - "winapi", -] - -[[package]] -name = "command_attr" -version = "0.4.1" +name = "chunked_transfer" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d999d4e7731150ee14aee8f619c7a9aa9a4385bca0606c4fa95aa2f36a05d9a" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] +checksum = "fff857943da45f546682664a79488be82e69e43c1a7a2307679ab9afb3a66d2e" [[package]] name = "core-foundation" @@ -169,20 +142,6 @@ dependencies = [ "typenum", ] -[[package]] -name = "dashmap" -version = "5.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "907076dfda823b0b36d2a1bb5f90c96660a5bbcd7729e10727f07858f22c4edc" -dependencies = [ - "cfg-if", - "hashbrown", - "lock_api", - "once_cell", - "parking_lot_core", - "serde", -] - [[package]] name = "digest" version = "0.10.5" @@ -221,8 +180,10 @@ dependencies = [ "envy", "reqwest", "serde", + "serde_json", "serenity", "tokio", + "ureq", ] [[package]] @@ -505,19 +466,6 @@ dependencies = [ "tokio-native-tls", ] -[[package]] -name = "iana-time-zone" -version = "0.1.50" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd911b35d940d2bd0bea0f9100068e5b97b51a1cbe13d13382f132e0365257a0" -dependencies = [ - "android_system_properties", - "core-foundation-sys", - "js-sys", - "wasm-bindgen", - "winapi", -] - [[package]] name = "idna" version = "0.3.0" @@ -574,28 +522,12 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" -[[package]] -name = "levenshtein" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db13adb97ab515a3691f56e4dbab09283d0b86cb45abd991d8634a9d6f501760" - [[package]] name = "libc" version = "0.2.134" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "329c933548736bc49fd575ee68c89e8be4d260064184389a5b77517cddd99ffb" -[[package]] -name = "lock_api" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" -dependencies = [ - "autocfg", - "scopeguard", -] - [[package]] name = "log" version = "0.4.17" @@ -666,16 +598,6 @@ dependencies = [ "tempfile", ] -[[package]] -name = "num-integer" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" -dependencies = [ - "autocfg", - "num-traits", -] - [[package]] name = "num-traits" version = "0.2.15" @@ -764,29 +686,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "parking_lot" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" -dependencies = [ - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-sys", -] - [[package]] name = "percent-encoding" version = "2.2.0" @@ -990,12 +889,6 @@ dependencies = [ "windows-sys", ] -[[package]] -name = "scopeguard" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" - [[package]] name = "sct" version = "0.7.0" @@ -1094,27 +987,20 @@ dependencies = [ "bitflags", "bytes", "cfg-if", - "chrono", - "command_attr", - "dashmap", "flate2", "futures", - "levenshtein", "mime", "mime_guess", - "parking_lot", "percent-encoding", "reqwest", "serde", "serde-value", "serde_json", - "static_assertions", "time", "tokio", "tracing", "typemap_rev", "url", - "uwl", ] [[package]] @@ -1137,12 +1023,6 @@ dependencies = [ "autocfg", ] -[[package]] -name = "smallvec" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" - [[package]] name = "socket2" version = "0.4.7" @@ -1159,12 +1039,6 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" -[[package]] -name = "static_assertions" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" - [[package]] name = "syn" version = "1.0.102" @@ -1415,6 +1289,23 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" +[[package]] +name = "ureq" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97acb4c28a254fd7a4aeec976c46a7fa404eac4d7c134b30c75144846d7cb8f" +dependencies = [ + "base64", + "chunked_transfer", + "flate2", + "log", + "once_cell", + "rustls", + "url", + "webpki", + "webpki-roots", +] + [[package]] name = "url" version = "2.3.1" @@ -1433,12 +1324,6 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" -[[package]] -name = "uwl" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4bf03e0ca70d626ecc4ba6b0763b934b6f2976e8c744088bb3c1d646fbb1ad0" - [[package]] name = "vcpkg" version = "0.2.15" diff --git a/Cargo.toml b/Cargo.toml index 403435d..1389e8b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,8 +8,10 @@ license = "MIT" [dependencies] tokio = { version = "1.17.0", features=["macros", "rt-multi-thread"] } -serenity = { version = "0.11.1"} +serenity = { default-features=false, version = "0.11.1", features=["client", "gateway", "rustls_backend", "model"]} serde = { version = "1.0.136", features=["derive"] } dotenvy = "0.15.5" envy = "0.4.2" -reqwest = "0.11.12" +reqwest = { version = "0.11.12", features = ["blocking", "json"] } +ureq = "2.5.0" +serde_json = "1.0.85" diff --git a/REQUIREMENTS.md b/REQUIREMENTS.md index 506b98b..904497e 100644 --- a/REQUIREMENTS.md +++ b/REQUIREMENTS.md @@ -11,10 +11,10 @@ # TODO -- [ ] Teams - - [ ] Score - - [ ] Total PRs - - [ ] Total PRs Deleted +- [x] Teams + - [x] Score + - [x] Total PRs + - [x] Total PRs Deleted - [ ] Users - [ ] Search - [ ] Info (no email) diff --git a/rustfmt.toml b/rustfmt.toml index f42fe6a..98799ca 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -1,3 +1,3 @@ edition = "2021" use_field_init_shorthand = true -use_try_shorthand = true \ No newline at end of file +use_try_shorthand = true diff --git a/src/commands/id.rs b/src/commands/id.rs deleted file mode 100644 index 4c98016..0000000 --- a/src/commands/id.rs +++ /dev/null @@ -1,33 +0,0 @@ -use serenity::builder::CreateApplicationCommand; -use serenity::model::prelude::command::CommandOptionType; -use serenity::model::prelude::interaction::application_command::{ - CommandDataOption, CommandDataOptionValue, -}; - -pub fn run(options: &[CommandDataOption]) -> String { - let option = options - .get(0) - .expect("Expected user option") - .resolved - .as_ref() - .expect("Expected user object"); - - if let CommandDataOptionValue::User(user, _member) = option { - format!("{}'s id is {}", user.tag(), user.id) - } else { - "Please provide a valid user".to_string() - } -} - -pub fn register(command: &mut CreateApplicationCommand) -> &mut CreateApplicationCommand { - command - .name("id") - .description("Get a user id") - .create_option(|option| { - option - .name("id") - .description("The user to lookup") - .kind(CommandOptionType::User) - .required(true) - }) -} diff --git a/src/commands/mod.rs b/src/commands/mod.rs index 6010f1e..dc5a171 100644 --- a/src/commands/mod.rs +++ b/src/commands/mod.rs @@ -1,2 +1 @@ -pub mod id; pub mod team; diff --git a/src/commands/team.rs b/src/commands/team.rs index 1b5cf4f..6706735 100644 --- a/src/commands/team.rs +++ b/src/commands/team.rs @@ -1,11 +1,40 @@ +use serde::Deserialize; use serenity::builder::CreateApplicationCommand; use serenity::model::prelude::command::CommandOptionType; use serenity::model::prelude::interaction::application_command::{ - CommandDataOption, CommandDataOptionValue, + ApplicationCommandInteraction, CommandDataOptionValue, }; +use serenity::model::prelude::interaction::InteractionResponseType; +use serenity::prelude::Context; -pub async fn run(options: &[CommandDataOption]) -> String { - let option = options +#[derive(Deserialize)] +struct Response { + team: Team, +} + +#[derive(Deserialize)] +struct Team { + id: String, + name: String, + slug: String, + score: u32, + ownerId: String, + prs: String, +} + +#[derive(Deserialize)] +struct PR { + id: String, + createdAt: String, + title: String, + url: String, + status: Option, +} + +pub async fn run(command: ApplicationCommandInteraction, ctx: Context) { + let option = command + .data + .options .get(0) .expect("Expected String Option") .resolved @@ -13,16 +42,53 @@ pub async fn run(options: &[CommandDataOption]) -> String { .expect("Expected string object"); if let CommandDataOptionValue::String(team_id) = option { - let response = reqwest::get(format!("https://www.hacksquad.dev/api/team?id={}", team_id)) - .await - .unwrap() - .text() + let response: Response = reqwest::get(&format!( + "https://www.hacksquad.dev/api/team?id={}", + team_id + )) + .await + .unwrap() + .json() + .await + .unwrap(); + + let all_prs: Vec = serde_json::from_str(&response.team.prs).unwrap(); + let mut deleted = 0; + for pr in all_prs { + if pr.status.is_some() { + deleted += 1; + } + } + + let data = format!( + "Name: {}\nScore: {}\nTotal PRs: {}\nTotal PRs Deleted: {}", + response.team.name, + response.team.score, + response.team.score + deleted, + deleted + ); + + command + .create_interaction_response(&ctx.http, |response| { + response + .kind(InteractionResponseType::ChannelMessageWithSource) + .interaction_response_data(|message| { + message.embed(|e| e.title("HackSquad Team Information").description(data)) + }) + }) .await .unwrap(); - - format!("team information is {}", response) } else { - "Please provide a valid user".to_string() + command + .create_interaction_response(&ctx.http, |response| { + response + .kind(InteractionResponseType::ChannelMessageWithSource) + .interaction_response_data(|message| { + message.content("Please provide a valid teams") + }) + }) + .await + .unwrap(); } } diff --git a/src/environment.rs b/src/environment.rs index b57d623..e63063b 100644 --- a/src/environment.rs +++ b/src/environment.rs @@ -1,15 +1,13 @@ -use dotenvy::dotenv; use std::env::{self, Vars}; +use dotenvy::dotenv; use serde::Deserialize; pub fn check() -> Configuration { dotenv().ok(); - let c = envy::from_iter::(env::vars().into_iter()) - .expect("Please provide environment variables"); - - c + envy::from_iter::(env::vars()) + .expect("Please provide environment variables") } #[derive(Deserialize, Debug)] diff --git a/src/events.rs b/src/events.rs index 2782b28..fbdfb93 100644 --- a/src/events.rs +++ b/src/events.rs @@ -2,35 +2,22 @@ use std::env; use serenity::{ async_trait, - model::prelude::{ - interaction::{Interaction, InteractionResponseType}, - GuildId, Ready, - }, + model::prelude::{interaction::Interaction, GuildId, Ready}, prelude::{Context, EventHandler}, }; -use crate::{commands, Handler}; +use crate::commands; + +pub struct Handler; #[async_trait] impl EventHandler for Handler { async fn interaction_create(&self, ctx: Context, interaction: Interaction) { if let Interaction::ApplicationCommand(command) = interaction { - let content = match command.data.name.as_str() { - "id" => commands::id::run(&command.data.options), - "team" => commands::team::run(&command.data.options).await, - _ => "not implemented :(".to_string(), + match command.data.name.as_str() { + "team" => commands::team::run(command.clone(), ctx.clone()).await, + _ => todo!(), }; - - if let Err(why) = command - .create_interaction_response(&ctx.http, |response| { - response - .kind(InteractionResponseType::ChannelMessageWithSource) - .interaction_response_data(|message| message.content(content)) - }) - .await - { - println!("Cannot respond to slash command: {}", why); - } } } @@ -45,9 +32,7 @@ impl EventHandler for Handler { ); let commands = GuildId::set_application_commands(&guild_id, &ctx.http, |commands| { - commands - .create_application_command(|command| commands::id::register(command)) - .create_application_command(|command| commands::team::register(command)) + commands.create_application_command(|command| commands::team::register(command)) }) .await; diff --git a/src/main.rs b/src/main.rs index 5cbbd66..83aab23 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,46 +1,25 @@ use std::env; -use serenity::framework::standard::macros::{command, group}; -use serenity::framework::standard::{CommandResult, StandardFramework}; -use serenity::model::channel::Message; use serenity::prelude::*; mod commands; mod environment; mod events; -#[group] -#[commands(ping)] -struct General; - -struct Handler; +use crate::events::Handler; #[tokio::main] async fn main() { environment::check(); - let framework = StandardFramework::new() - .configure(|c| c.prefix("~")) // set the bot's prefix to "~" - .group(&GENERAL_GROUP); - - // Login with a bot token from the environment let token = env::var("DISCORD_TOKEN").expect("DISCORD_TOKEN"); - let intents = GatewayIntents::non_privileged() | GatewayIntents::MESSAGE_CONTENT; - let mut client = Client::builder(token, intents) + + let mut client = Client::builder(token, GatewayIntents::empty()) .event_handler(Handler) - .framework(framework) .await .expect("Error creating client"); - // start listening for events by starting a single shard if let Err(why) = client.start().await { println!("An error occurred while running the client: {:?}", why); } } - -#[command] -async fn ping(ctx: &Context, msg: &Message) -> CommandResult { - msg.reply(ctx, "Pong!").await?; - - Ok(()) -}