summaryrefslogtreecommitdiff
path: root/src/handler
diff options
context:
space:
mode:
Diffstat (limited to 'src/handler')
-rw-r--r--src/handler/mod.rs17
-rw-r--r--src/handler/pinboard.rs128
-rw-r--r--src/handler/reactboard.rs66
3 files changed, 107 insertions, 104 deletions
diff --git a/src/handler/mod.rs b/src/handler/mod.rs
index 6085617..3489b4a 100644
--- a/src/handler/mod.rs
+++ b/src/handler/mod.rs
@@ -4,11 +4,12 @@ use poise::Event;
mod message;
pub mod pinboard;
+mod reactboard;
pub async fn handle(
ctx: &serenity::Context,
event: &Event<'_>,
- _framework: poise::FrameworkContext<'_, Data, Error>,
+ framework: poise::FrameworkContext<'_, Data, Error>,
data: &Data,
) -> Result<(), Error> {
match event {
@@ -17,15 +18,19 @@ pub async fn handle(
}
Event::Message { new_message } => {
- message::handle(ctx, event, _framework, data, new_message).await?;
+ message::handle(ctx, event, framework, data, new_message).await?
}
Event::ChannelPinsUpdate { pin } => {
- let Some(pin_board) = &data.pin_board else {
- return Ok(());
- };
+ if let Some(settings) = &data.settings {
+ pinboard::handle(ctx, pin, settings).await
+ }
+ }
- pin_board.handle_pin(ctx, pin).await;
+ Event::ReactionAdd { add_reaction } => {
+ if let Some(settings) = &data.settings {
+ reactboard::handle(ctx, add_reaction, settings).await?
+ }
}
_ => {}
diff --git a/src/handler/pinboard.rs b/src/handler/pinboard.rs
index 35d477d..0c87a5b 100644
--- a/src/handler/pinboard.rs
+++ b/src/handler/pinboard.rs
@@ -1,112 +1,44 @@
+use crate::settings::Settings;
use crate::utils;
use log::*;
use poise::serenity_prelude::model::prelude::*;
-use poise::serenity_prelude::{Context, CreateEmbed};
+use poise::serenity_prelude::Context;
-#[derive(Clone)]
-pub struct PinBoard {
- sources: Option<Vec<ChannelId>>,
- target: ChannelId,
-}
-impl PinBoard {
- pub fn new() -> Option<Self> {
- let Some(target) = utils::parse_snowflake_from_env("PIN_BOARD_TARGET", ChannelId) else {
- return None;
- };
- let sources = utils::parse_snowflakes_from_env("PIN_BOARD_SOURCES", ChannelId);
-
- Some(Self { sources, target })
- }
-
- pub async fn handle_pin(&self, ctx: &Context, pin: &ChannelPinsUpdateEvent) {
- if let Some(sources) = &self.sources {
- if !sources.contains(&pin.channel_id) {
- warn!("can't access source of pin!");
- return;
- }
- }
-
- let mut pinner = guess_pinner(ctx, pin).await;
- let pins = pin
- .channel_id
- .pins(&ctx.http)
- .await
- .expect("couldn't get a list of pins!?");
-
- for pin in pins {
- // We call `take` because it's supposed to be just for the latest message.
- self.redirect(ctx, &pin, pinner.take()).await;
- pin.unpin(&ctx).await.expect("couldn't unpin message");
+pub async fn handle(ctx: &Context, pin: &ChannelPinsUpdateEvent, settings: &Settings) {
+ if let Some(sources) = &settings.pinboard_sources {
+ if !sources.contains(&pin.channel_id) {
+ warn!("can't access source of pin!");
+ return;
}
}
- async fn redirect(&self, ctx: &Context, pin: &Message, pinner: Option<UserId>) {
- let pinner = pinner.map_or("*someone*".to_owned(), |u| format!("<@{u}>"));
-
- let truncation_point = utils::floor_char_boundary(&pin.content, 700);
- let truncated_content = if pin.content.len() <= truncation_point {
- pin.content.to_string()
- } else {
- format!("{}...", &pin.content[..truncation_point])
- };
- let color = pin
- .member(ctx)
- .await
- .ok()
- .and_then(|m| m.highest_role_info(&ctx.cache))
- .and_then(|(role, _)| role.to_role_cached(&ctx.cache))
- .map(|role| role.colour);
-
- let attached_image = pin
- .attachments
- .iter()
- .filter(|a| {
- a.content_type
- .as_ref()
- .filter(|ct| ct.contains("image/"))
- .is_some()
- })
- .map(|a| &a.url)
- .next();
-
- let attachments_len = pin.attachments.len();
-
- self.target
- .send_message(&ctx.http, |m| {
- m.allowed_mentions(|am| am.empty_parse())
- .content(format!("📌'd by {pinner} in {}", pin.link()))
- .add_embed(|embed| {
- // only use the first embed if it's in the message, since more could be a little spammy
- if let Some(pinned_embed) = pin.embeds.first() {
- embed.clone_from(&CreateEmbed::from(pinned_embed.clone()))
- }
-
- embed.author(|author| {
- author.name(&pin.author.name).icon_url(pin.author.face())
- });
-
- if let Some(color) = color {
- embed.color(color);
- }
+ let mut pinner = guess_pinner(ctx, pin).await;
+ let pins = pin
+ .channel_id
+ .pins(&ctx.http)
+ .await
+ .expect("couldn't get a list of pins!?");
- if let Some(attachment) = attached_image {
- embed.image(attachment);
- }
+ for pin in pins {
+ // We call `take` because it's supposed to be just for the latest message.
+ redirect(ctx, &pin, pinner.take(), settings.pinboard_target).await;
+ pin.unpin(&ctx).await.expect("couldn't unpin message");
+ }
+}
- if attachments_len > 1 {
- embed.footer(|footer| {
- // yes it will say '1 attachments' no i do not care
- footer.text(format!("{} attachments", attachments_len))
- });
- }
+async fn redirect(ctx: &Context, pin: &Message, pinner: Option<UserId>, target: ChannelId) {
+ let pinner = pinner.map_or("*someone*".to_owned(), |u| format!("<@{u}>"));
+ let embed = utils::resolve_message_to_embed(ctx, pin).await;
- embed.description(truncated_content)
- })
- })
- .await
- .expect("couldn't redirect message");
- }
+ target
+ .send_message(&ctx.http, |m| {
+ m.allowed_mentions(|am| am.empty_parse())
+ .content(format!("📌'd by {pinner} in {}", pin.link()))
+ .set_embed(embed)
+ })
+ .await
+ .expect("couldn't redirect message");
}
/// (Desperate, best-effort) attempt to get the user that pinned the last message
diff --git a/src/handler/reactboard.rs b/src/handler/reactboard.rs
new file mode 100644
index 0000000..36f8361
--- /dev/null
+++ b/src/handler/reactboard.rs
@@ -0,0 +1,66 @@
+use crate::Error;
+use crate::{settings::Settings, utils};
+use log::*;
+use poise::serenity_prelude::{Context, Message, MessageReaction, Reaction};
+
+pub async fn handle(ctx: &Context, reaction: &Reaction, settings: &Settings) -> Result<(), Error> {
+ let msg = match reaction.message(&ctx.http).await {
+ Ok(msg) => msg,
+ Err(why) => {
+ warn!("couldn't get message of reaction! {}", why);
+ return Err(Box::new(why));
+ }
+ };
+
+ if let Some(matched) = msg
+ .clone()
+ .reactions
+ .into_iter()
+ .find(|r| r.reaction_type == reaction.emoji)
+ {
+ send_to_reactboard(ctx, &matched, &msg, settings).await?;
+ } else {
+ warn!(
+ "couldn't find any matching reactions for {} in {}",
+ reaction.emoji.as_data(),
+ msg.id
+ )
+ }
+
+ Ok(())
+}
+
+async fn send_to_reactboard(
+ ctx: &Context,
+ reaction: &MessageReaction,
+ msg: &Message,
+ settings: &Settings,
+) -> Result<(), Error> {
+ if !settings.can_use_reaction(reaction) {
+ info!("reaction {} can't be used!", reaction.reaction_type);
+ return Ok(());
+ }
+
+ if reaction.count == settings.reactboard_requirement.unwrap_or(5) {
+ let embed = utils::resolve_message_to_embed(ctx, msg).await;
+
+ settings
+ .reactboard_target
+ .send_message(&ctx.http, |m| {
+ m.allowed_mentions(|am| am.empty_parse())
+ .content(format!(
+ "{} **#{}**",
+ reaction.reaction_type, reaction.count
+ ))
+ .set_embed(embed)
+ })
+ .await?;
+ } else {
+ info!(
+ "not putting message {} on reactboard, not enough reactions",
+ msg.id
+ )
+ }
+
+ Ok(())
+}