summaryrefslogtreecommitdiff
path: root/src/handlers/event/reactboard.rs
blob: 7341565b7262337cda30f3b0c08bbec4c7ab4338 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
use crate::{storage, utils, Data};
use storage::ReactBoardEntry;

use color_eyre::eyre::{eyre, Context as _, Result};
use log::debug;
use poise::serenity_prelude::{Context, GuildId, Message, MessageReaction, Reaction};

pub async fn handle(ctx: &Context, reaction: &Reaction, data: &Data) -> Result<()> {
	let msg = reaction
		.message(&ctx.http)
		.await
		.wrap_err_with(|| "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 storage = &data.storage;
	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(());
	}

	if reaction.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, reaction.count);

	// bump reaction count if previous entry exists
	if storage.reactboard_entry_exists(guild_id, &msg.id).await? {
		let old_entry = storage.get_reactboard_entry(guild_id, &msg.id).await?;

		// bail if we don't need to edit anything
		if old_entry.reaction_count >= reaction.count {
			debug!("Message {} doesn't need updating", msg.id);
			return Ok(());
		}

		debug!(
			"Bumping {} reaction count from {} to {}",
			msg.id, old_entry.reaction_count, reaction.count
		);

		ctx.http
			.get_message(
				*old_entry.posted_channel_id.as_u64(),
				*old_entry.posted_message_id.as_u64(),
			)
			.await
			.wrap_err_with(|| {
				format!(
					"Couldn't get previous message from ReactBoardEntry {} in Redis DB!",
					old_entry.original_message_id
				)
			})?
			.edit(ctx, |m| m.content(content))
			.await?;

		// update reaction count in redis
		let mut new_entry = old_entry.clone();
		new_entry.reaction_count = reaction.count;

		debug!("Updating ReactBoard entry\nOld entry:\n{old_entry:#?}\n\nNew:\n{new_entry:#?}\n",);
		storage.create_reactboard_entry(guild_id, new_entry).await?;
	// make new message and add entry to redis otherwise
	} else {
		let embed = utils::resolve_message_to_embed(ctx, msg).await;

		let resp = target
			.send_message(ctx, |m| {
				m.allowed_mentions(|am| am.empty_parse())
					.content(content)
					.set_embed(embed)
			})
			.await?;

		let entry = ReactBoardEntry {
			original_message_id: msg.id,
			reaction_count: reaction.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(())
}