diff options
| author | seth <[email protected]> | 2024-08-09 23:35:41 -0400 |
|---|---|---|
| committer | GitHub <[email protected]> | 2024-08-09 23:35:41 -0400 |
| commit | b643a6a235b0c1c9902b97421f24eff2b0d0a5ac (patch) | |
| tree | 350794c0e9330fb77367838313bc6bb97278a0aa /src/events/reactboard.rs | |
| parent | 372780546b508684839916e5ad54c9e90456a94f (diff) | |
tree-wide: end of summer cleanup (#214)
* api: refactor & rename module to http
* client: split from main.rs
* tree-wide: use eyre::Report as error
* nix: alejandra -> nixfmt
* nix: start using treefmt-nix
* nix: simplify flake
* nix: refactor derivation & docker image
* nix: remove overlay
* ci: update & cleanup workflows
* commands: assign all commands automatically
* commands/copypasta: remove
* http/teawie: update response struct for upstream rust rewrite
* handlers: rename modules to events; flatten
* crates: rename self to teawie-bot
* nix: fenix -> rust-overlay
i want a specific rust version grrrrrrr
* ci: pin rust to 1.79
this is what our nix dev shell uses and what we can compile on. it seems
the time crate doesn't like v1.80 of the compiler :(
* ci: always run release gates
* nix: fix static toolchain
* nix: rust-overlay -> nixpkgs
* ci: adopt actions-rust-lang actions
* nix: use docker arch names for containers
* crates/time: 0.3.30 -> 0.3.36
fixes building on rust 1.80.0
Diffstat (limited to 'src/events/reactboard.rs')
| -rw-r--r-- | src/events/reactboard.rs | 143 |
1 files changed, 143 insertions, 0 deletions
diff --git a/src/events/reactboard.rs b/src/events/reactboard.rs new file mode 100644 index 0000000..c27bd80 --- /dev/null +++ b/src/events/reactboard.rs @@ -0,0 +1,143 @@ +use crate::{client::Data, storage, utils}; +use storage::reactboard::ReactBoardEntry; + +use eyre::{eyre, Context as _, Result}; +use log::{debug, warn}; +use poise::serenity_prelude::{ + Context, CreateMessage, EditMessage, GuildId, Message, MessageReaction, Reaction, +}; + +pub async fn handle(ctx: &Context, reaction: &Reaction, data: &Data) -> Result<()> { + // TODO @getchoo: don't do anything if this message is old + let msg = reaction + .message(&ctx.http) + .await + .wrap_err("Couldn't get reaction from message!")?; + + let matched = msg + .clone() + .reactions + .into_iter() + .find(|r| r.reaction_type == reaction.emoji) + .ok_or_else(|| { + eyre!( + "Couldn't find any matching reactions for {} in message {}!", + reaction.emoji.as_data(), + msg.id + ) + })?; + + send_to_reactboard( + ctx, + &matched, + &msg, + &reaction.guild_id.unwrap_or_default(), + data, + ) + .await?; + + Ok(()) +} + +async fn send_to_reactboard( + ctx: &Context, + reaction: &MessageReaction, + msg: &Message, + guild_id: &GuildId, + data: &Data, +) -> Result<()> { + let Some(storage) = &data.storage else { + warn!("Can't make ReactBoard entry; no storage backend found!"); + return Ok(()); + }; + + let settings = storage.get_guild_settings(guild_id).await?; + + // make sure everything is in order... + if !settings.reactboard_enabled { + debug!("ReactBoard is disabled in {guild_id}, ignoring"); + return Ok(()); + } + + let Some(target) = settings.reactboard_channel else { + debug!("ReactBoard is disabled in {guild_id}, ignoring"); + return Ok(()); + }; + + if !settings.can_use_reaction(&reaction.reaction_type) { + debug!("Reaction {} can't be used!", reaction.reaction_type); + return Ok(()); + } + + let count = if msg + .reaction_users(ctx, reaction.reaction_type.clone(), None, None) + .await? + .contains(&msg.author) + { + reaction.count - 1 + } else { + reaction.count + }; + + if count < settings.reactboard_requirement.unwrap_or(5) { + debug!( + "Ignoring message {} on ReactBoard, not enough reactions", + msg.id + ); + return Ok(()); + } + + let content = format!("{} **#{}**", reaction.reaction_type, count); + + let entry = if storage.reactboard_entry_exists(guild_id, &msg.id).await? { + // bump reaction count if previous entry exists + let mut entry = storage.get_reactboard_entry(guild_id, &msg.id).await?; + + // bail if we don't need to edit anything + if entry.reaction_count >= count { + debug!("Message {} doesn't need updating", msg.id); + return Ok(()); + } + + debug!( + "Bumping {} reaction count from {} to {}", + msg.id, entry.reaction_count, count + ); + + let edited = EditMessage::new().content(content); + + ctx.http + .get_message(entry.posted_channel_id, entry.posted_message_id) + .await + .wrap_err_with(|| { + format!( + "Couldn't get previous message from ReactBoardEntry {} in Redis DB!", + entry.original_message_id + ) + })? + .edit(ctx, edited) + .await?; + + // update reaction count in redis + entry.reaction_count = count; + entry + } else { + // make new message and add entry to redis otherwise + let embed = utils::resolve_message_to_embed(ctx, msg).await; + let message = CreateMessage::default().content(content).embed(embed); + + let resp = target.send_message(ctx, message).await?; + + ReactBoardEntry { + original_message_id: msg.id, + reaction_count: count, + posted_channel_id: resp.channel_id, + posted_message_id: resp.id, + } + }; + + debug!("Creating new ReactBoard entry:\n{entry:#?}"); + storage.create_reactboard_entry(guild_id, entry).await?; + + Ok(()) +} |
