didgeridoo/src/reactions.rs
2021-11-25 22:29:25 +01:00

95 lines
2.6 KiB
Rust

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<ReactableMessage> = {
let c = serde_json::from_str(
&std::fs::read_to_string("reaction_config.json").unwrap_or_else(|_| "[]".to_string()),
)
.expect("Could not read reaction config");
eprintln!("Read reaction config: {:?}", c);
c
};
}
macro_rules! role_action {
($reaction: expr, $ctx: expr, $action: ident) => {
if let ReactionType::Unicode(emoji) = &$reaction.emoji {
if let Some(&role_id) = ROLE_CONFIG
.iter()
.find(|c| $reaction.message_id == c.message_id)
.and_then(|rm| rm.roles.get(emoji))
{
$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<()> {
role_action!(reaction, ctx, add_role);
Ok(())
}
pub(crate) async fn reaction_removed(ctx: Context, reaction: Reaction) -> serenity::Result<()> {
role_action!(reaction, ctx, remove_role);
Ok(())
}
#[derive(Debug, PartialEq, Deserialize)]
struct ReactableMessage {
// I hate how this sounds like a Java interface name…
message_id: u64,
roles: HashMap<String, u64>,
}
#[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::<Vec<ReactableMessage>>(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)]),
},
],
);
}
}