titanium_model/
reaction.rs1use crate::Snowflake;
6use crate::TitanString;
7use serde::{Deserialize, Serialize};
8
9#[derive(Debug, Clone, Deserialize, Serialize)]
11pub struct MessageReactionAddEvent<'a> {
12 pub user_id: Snowflake,
14
15 pub channel_id: Snowflake,
17
18 pub message_id: Snowflake,
20
21 #[serde(default)]
23 pub guild_id: Option<Snowflake>,
24
25 #[serde(default)]
27 pub member: Option<super::member::GuildMember<'a>>,
28
29 pub emoji: ReactionEmoji<'a>,
31
32 #[serde(default)]
34 pub message_author_id: Option<Snowflake>,
35
36 #[serde(default)]
38 pub burst: bool,
39
40 #[serde(default)]
42 pub burst_colors: Vec<String>,
43
44 #[serde(default, rename = "type")]
46 pub reaction_type: u8,
47}
48
49#[derive(Debug, Clone, Deserialize, Serialize)]
51pub struct MessageReactionRemoveEvent<'a> {
52 pub user_id: Snowflake,
54
55 pub channel_id: Snowflake,
57
58 pub message_id: Snowflake,
60
61 #[serde(default)]
63 pub guild_id: Option<Snowflake>,
64
65 pub emoji: ReactionEmoji<'a>,
67
68 #[serde(default)]
70 pub burst: bool,
71
72 #[serde(default, rename = "type")]
74 pub reaction_type: u8,
75}
76
77#[derive(Debug, Clone, Deserialize, Serialize)]
79pub struct MessageReactionRemoveAllEvent {
80 pub channel_id: Snowflake,
82
83 pub message_id: Snowflake,
85
86 #[serde(default)]
88 pub guild_id: Option<Snowflake>,
89}
90
91#[derive(Debug, Clone, Deserialize, Serialize)]
93pub struct MessageReactionRemoveEmojiEvent<'a> {
94 pub channel_id: Snowflake,
96
97 pub message_id: Snowflake,
99
100 #[serde(default)]
102 pub guild_id: Option<Snowflake>,
103
104 pub emoji: ReactionEmoji<'a>,
106}
107
108#[derive(Debug, Clone, Deserialize, Serialize, Default)]
110pub struct ReactionEmoji<'a> {
111 #[serde(default)]
113 pub id: Option<Snowflake>,
114
115 #[serde(default)]
117 pub name: Option<TitanString<'a>>,
118
119 #[serde(default)]
121 pub animated: bool,
122}
123
124impl<'a> ReactionEmoji<'a> {
125 #[inline]
127 pub fn unicode(name: impl Into<TitanString<'a>>) -> Self {
128 Self {
129 id: None,
130 name: Some(name.into()),
131 animated: false,
132 }
133 }
134
135 #[inline]
137 pub fn custom(id: impl Into<Snowflake>, name: impl Into<TitanString<'a>>) -> Self {
138 Self {
139 id: Some(id.into()),
140 name: Some(name.into()),
141 animated: false,
142 }
143 }
144
145 #[inline]
147 pub fn animated(id: impl Into<Snowflake>, name: impl Into<TitanString<'a>>) -> Self {
148 Self {
149 id: Some(id.into()),
150 name: Some(name.into()),
151 animated: true,
152 }
153 }
154
155 #[must_use]
157 pub fn format(&self) -> String {
158 match (&self.id, &self.name) {
159 (Some(id), Some(name)) if self.animated => format!("<a:{}:{}>", name, id.0),
160 (Some(id), Some(name)) => format!("<:{}:{}>", name, id.0),
161 (None, Some(name)) => name.to_string(),
162 _ => String::new(),
163 }
164 }
165}
166
167#[cfg(test)]
168mod tests {
169 use super::*;
170
171 #[test]
172 fn test_reaction_add_event() {
173 let json = r#"{
174 "user_id": "123",
175 "channel_id": "456",
176 "message_id": "789",
177 "emoji": {"name": "👍"}
178 }"#;
179
180 let event: MessageReactionAddEvent = crate::json::from_str(json).unwrap();
181 assert_eq!(event.emoji.name, Some(TitanString::Borrowed("👍")));
182 }
183
184 #[test]
185 fn test_custom_emoji() {
186 let json = r#"{
187 "id": "123456789",
188 "name": "custom_emoji",
189 "animated": true
190 }"#;
191
192 let emoji: ReactionEmoji = crate::json::from_str(json).unwrap();
193 assert!(emoji.animated);
194 assert!(emoji.id.is_some());
195 }
196}