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
136
137
138
139
140
141
142
143
|
use crate::{client::Data, storage, utils};
use storage::reactboard::ReactBoardEntry;
use anyhow::{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
.context("Couldn't get reaction from message!")?;
let matched = msg
.clone()
.reactions
.into_iter()
.find(|r| r.reaction_type == reaction.emoji)
.with_context(|| {
format!(
"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
.with_context(|| {
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(())
}
|