diff --git a/Cargo.lock b/Cargo.lock index dea63cc..5895fe3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -939,18 +939,18 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" -version = "1.0.125" +version = "1.0.130" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "558dc50e1a5a5fa7112ca2ce4effcb321b0300c0d4ccf0776a9f60cd89031171" +checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.125" +version = "1.0.130" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b093b7a2bb58203b5da3056c05b4ec1fed827dcfdb37347a8841695263b3d06d" +checksum = "d7bc1a1ab1961464eae040d96713baa5a724a8152c1222492465b54322ec508b" dependencies = [ "proc-macro2", "quote", @@ -959,9 +959,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.64" +version = "1.0.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "799e97dc9fdae36a5c8b8f2cae9ce2ee9fdce2058c57a93e6099d919fd982f79" +checksum = "d0ffa0837f2dfa6fb90868c2b5468cad482e175f7dad97e7421951e663f2b527" dependencies = [ "itoa", "ryu", diff --git a/Cargo.toml b/Cargo.toml index 91561bf..907df40 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,8 +11,8 @@ async-trait = "0.1.42" itertools = "0.10.0" lazy_static = "1.4.0" redis = "0.20.0" -serde = { version = "1.0.123", features = ["derive"] } -serde_json = "1.0.62" +serde = { version = "1.0.130", features = ["derive"] } +serde_json = "1.0.72" serenity = "0.10.5" time = "0.2.10" tokio = { version = "1.2.0", features = ["full"] } diff --git a/README.md b/README.md index 8260749..ea3479c 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ # DIDgeridoo A bot for people with dissociative identity disorder. Currently only does and logs name changes and has basic inbox functionality for a single user per instance. + +Now also has role assignment via reaction because feature creep. diff --git a/src/main.rs b/src/main.rs index e863922..5b6e4b2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,7 +6,7 @@ use serenity::framework::standard::{ macros::{command, group}, CommandResult, StandardFramework, }; -use serenity::model::channel::{Reaction, ReactionType}; +use serenity::model::channel::Reaction; use serenity::model::{ channel::Message, id::{ChannelId, GuildId, UserId}, @@ -17,6 +17,7 @@ use std::fs::File; use std::io::{self, BufRead, BufReader}; use time::Duration; mod inbox; +mod reactions; const APPLICATION_NAME: &str = "didgeridoo"; const INBOX_OWNER: UserId = UserId(354694403798990848); @@ -33,20 +34,6 @@ macro_rules! send_or_log { }; } -macro_rules! role_action { - ($reaction: expr, $ctx: expr, $action: ident) => { - $reaction - .guild_id - .unwrap() - .member(&$ctx, $reaction.user_id.unwrap()) - .await - .unwrap() - .$action(&$ctx, 356421827708321795) - .await - .unwrap() - }; -} - #[group] #[commands(name, message, question, inbox)] struct Fluff; @@ -64,18 +51,20 @@ impl EventHandler for Handler { } async fn reaction_add(&self, ctx: Context, reaction: Reaction) { - if reaction.message_id == 911630315376738384 - && reaction.emoji == ReactionType::Unicode(String::from("πŸ§ͺ")) - { - role_action!(reaction, ctx, add_role) + if let Err(e) = reactions::reaction_added(ctx, reaction).await { + eprintln!( + "Something went wrong while processing an added reaction: {:?}", + e + ); } } async fn reaction_remove(&self, ctx: Context, reaction: Reaction) { - if reaction.message_id == 911630315376738384 - && reaction.emoji == ReactionType::Unicode(String::from("πŸ§ͺ")) - { - role_action!(reaction, ctx, remove_role) + if let Err(e) = reactions::reaction_removed(ctx, reaction).await { + eprintln!( + "Something went wrong while processing an added reaction: {:?}", + e + ); } } } diff --git a/src/reactions.rs b/src/reactions.rs new file mode 100644 index 0000000..242dce9 --- /dev/null +++ b/src/reactions.rs @@ -0,0 +1,104 @@ +use lazy_static::lazy_static; +use serde::Deserialize; +use serenity::{ + client::Context, + model::channel::{Reaction, ReactionType}, +}; +use std::collections::HashMap; + +lazy_static! { + static ref ROLE_CONFIG: Vec = { + let c = serde_json::from_str( + &std::fs::read_to_string("reaction_config.json").unwrap_or("[]".to_string()), + ) + .expect("Could not read reaction config"); + println!("Read reaction config: {:?}", c); + c + }; +} + +macro_rules! role_action { + ($reaction: expr, $ctx: expr, $action: ident, $role_id: expr) => { + $reaction + .guild_id + .expect("Configured message id is not in a guild") + .member(&$ctx, $reaction.user_id.unwrap()) + .await? + .$action(&$ctx, $role_id) + .await? + }; +} + +pub(crate) async fn reaction_added(ctx: Context, reaction: Reaction) -> serenity::Result<()> { + if let Some(rm) = ROLE_CONFIG + .iter() + .find(|c| reaction.message_id == c.message_id) + { + if let ReactionType::Unicode(emoji) = &reaction.emoji { + if let Some(role_id) = rm.roles.get(emoji) { + role_action!(reaction, ctx, add_role, *role_id); + } + } + } + Ok(()) +} +pub(crate) async fn reaction_removed(ctx: Context, reaction: Reaction) -> serenity::Result<()> { + if let Some(rm) = ROLE_CONFIG + .iter() + .find(|c| reaction.message_id == c.message_id) + { + if let ReactionType::Unicode(emoji) = &reaction.emoji { + if let Some(role_id) = rm.roles.get(emoji) { + role_action!(reaction, ctx, remove_role, *role_id); + } + } + } + Ok(()) +} + +#[derive(Debug, PartialEq, Deserialize)] +struct ReactableMessage { + // I hate how this sounds like a Java interface name… + message_id: u64, + roles: HashMap, +} + +#[cfg(test)] +mod tests { + use super::*; + + const TEST_JSON: &str = r#" + [ + { + "message_id": 12345, + "roles": { + "πŸ’€": 1, + "πŸ‘": 2 + } + }, + { + "message_id": 54321, + "roles": { + "πŸ’™": 3, + "β™»": 4 + } + } + ]"#; + + #[test] + fn test_role_config_parsing() { + assert_eq!( + serde_json::from_str::>(TEST_JSON).unwrap(), + [ + ReactableMessage { + message_id: 12345, + roles: HashMap::from([("πŸ’€".to_string(), 1), ("πŸ‘".to_string(), 2)]), + }, + ReactableMessage { + message_id: 54321, + roles: HashMap::from([("πŸ’™".to_string(), 3), ("β™»".to_string(), 4)]), + }, + ], + ); + } +}