tgbot/types/reaction/mod.rs
1use serde::{Deserialize, Serialize};
2
3use crate::{
4 api::{Method, Payload},
5 types::{Chat, ChatId, Integer, User},
6};
7
8#[cfg(test)]
9mod tests;
10
11/// Represents a reaction added to a message along with the number of times it was added.
12#[derive(Clone, Debug, Deserialize, PartialEq, PartialOrd, Serialize)]
13pub struct ReactionCount {
14 /// Type of the reaction.
15 #[serde(rename = "type")]
16 pub reaction_type: ReactionType,
17 /// Number of times the reaction was added.
18 pub total_count: Integer,
19}
20
21impl ReactionCount {
22 /// Creates a new `ReactionCount`.
23 ///
24 /// # Arguments
25 ///
26 /// * `reaction_type` - Type of the reaction.
27 /// * `total_count` - Number of times the reaction was added.
28 pub fn new(reaction_type: ReactionType, total_count: Integer) -> Self {
29 Self {
30 reaction_type,
31 total_count,
32 }
33 }
34}
35
36/// Represents reaction changes on a message with anonymous reactions.
37#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
38pub struct MessageReactionCountUpdated {
39 /// The chat containing the message.
40 pub chat: Chat,
41 /// Date of the change in Unix time.
42 pub date: Integer,
43 /// Unique message identifier inside the chat.
44 pub message_id: Integer,
45 /// List of reactions that are present on the message.
46 pub reactions: Vec<ReactionCount>,
47}
48
49impl MessageReactionCountUpdated {
50 /// Creates a new `MessageReactionCountUpdated`.
51 ///
52 /// # Arguments
53 ///
54 /// * `chat` - The chat containing the message.
55 /// * `date` - Date of the change in Unix time.
56 /// * `message_id` - Unique message identifier inside the chat.
57 /// * `reactions` - List of reactions that are present on the message.
58 pub fn new<A, B>(chat: A, date: Integer, message_id: Integer, reactions: B) -> Self
59 where
60 A: Into<Chat>,
61 B: IntoIterator<Item = ReactionCount>,
62 {
63 Self {
64 chat: chat.into(),
65 date,
66 message_id,
67 reactions: reactions.into_iter().collect(),
68 }
69 }
70}
71
72/// Represents a reaction type.
73#[derive(Clone, Debug, Deserialize, PartialEq, PartialOrd, Serialize)]
74#[serde(from = "RawReactionType", into = "RawReactionType")]
75pub enum ReactionType {
76 /// A reaction based on a custom emoji.
77 CustomEmoji(String),
78 /// A reaction based on a predefined emoji.
79 Emoji(String),
80 /// The reaction is paid.
81 Paid,
82}
83
84impl ReactionType {
85 /// Creates a new `ReactionType` based on a custom emoji.
86 ///
87 /// # Arguments
88 ///
89 /// `value` - A custom emoji.
90 pub fn custom_emoji<T>(value: T) -> Self
91 where
92 T: Into<String>,
93 {
94 Self::CustomEmoji(value.into())
95 }
96
97 /// Creates a new `ReactionType` based on a predefined emoji.
98 ///
99 /// # Arguments
100 ///
101 /// `value` - A predefined emoji.
102 pub fn emoji<T>(value: T) -> Self
103 where
104 T: Into<String>,
105 {
106 Self::Emoji(value.into())
107 }
108}
109
110#[derive(Clone, Debug, Deserialize, PartialEq, PartialOrd, Serialize)]
111#[serde(rename_all = "snake_case", tag = "type")]
112enum RawReactionType {
113 CustomEmoji { custom_emoji: String },
114 Emoji { emoji: String },
115 Paid,
116}
117
118impl From<ReactionType> for RawReactionType {
119 fn from(value: ReactionType) -> Self {
120 match value {
121 ReactionType::CustomEmoji(custom_emoji) => Self::CustomEmoji { custom_emoji },
122 ReactionType::Emoji(emoji) => Self::Emoji { emoji },
123 ReactionType::Paid => Self::Paid,
124 }
125 }
126}
127
128impl From<RawReactionType> for ReactionType {
129 fn from(value: RawReactionType) -> Self {
130 match value {
131 RawReactionType::CustomEmoji { custom_emoji } => Self::CustomEmoji(custom_emoji),
132 RawReactionType::Emoji { emoji } => Self::Emoji(emoji),
133 RawReactionType::Paid => Self::Paid,
134 }
135 }
136}
137
138/// Represents a change of a reaction on a message performed by a user.
139#[serde_with::skip_serializing_none]
140#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
141pub struct MessageReactionUpdated {
142 /// The chat containing the message the user reacted to.
143 pub chat: Chat,
144 /// Date of the change in Unix time.
145 pub date: Integer,
146 /// Unique identifier of the message inside the chat.
147 pub message_id: Integer,
148 /// New list of reaction types that have been set by the user.
149 pub new_reaction: Vec<ReactionType>,
150 /// Previous list of reaction types that were set by the user.
151 pub old_reaction: Vec<ReactionType>,
152 /// The chat on behalf of which the reaction was changed, if the user is anonymous.
153 pub actor_chat: Option<Chat>,
154 /// The user that changed the reaction, if the user isn't anonymous.
155 pub user: Option<User>,
156}
157
158impl MessageReactionUpdated {
159 /// Creates a new `MessageReactionUpdated`.
160 ///
161 /// # Arguments
162 ///
163 /// * `chat` - The chat containing the message the user reacted to.
164 /// * `date` - Date of the change in Unix time.
165 /// * `message_id` - Unique identifier of the message inside the chat.
166 /// * `new_reaction` - New list of reaction types that have been set by the user.
167 /// * `old_reaction` - Previous list of reaction types that were set by the user.
168 pub fn new<A, B, C>(chat: A, date: Integer, message_id: Integer, new_reaction: B, old_reaction: C) -> Self
169 where
170 A: Into<Chat>,
171 B: IntoIterator<Item = ReactionType>,
172 C: IntoIterator<Item = ReactionType>,
173 {
174 Self {
175 chat: chat.into(),
176 date,
177 message_id,
178 new_reaction: new_reaction.into_iter().collect(),
179 old_reaction: old_reaction.into_iter().collect(),
180 actor_chat: None,
181 user: None,
182 }
183 }
184
185 /// Sets a new actor chat.
186 ///
187 /// # Arguments
188 ///
189 /// * `value` - The chat on behalf of which the reaction was changed, if the user is anonymous.
190 pub fn with_actor_chat<T>(mut self, value: T) -> Self
191 where
192 T: Into<Chat>,
193 {
194 self.actor_chat = Some(value.into());
195 self
196 }
197
198 /// Sets a new user.
199 ///
200 /// # Arguments
201 ///
202 /// * `value` - The user that changed the reaction, if the user isn't anonymous.
203 pub fn with_user(mut self, value: User) -> Self {
204 self.user = Some(value);
205 self
206 }
207}
208
209/// Changes the chosen reactions on a message.
210///
211/// Service messages of some types can't be reacted to.
212/// Automatically forwarded messages from a channel to its discussion group have
213/// the same available reactions as messages in the channel.
214/// Bots can't use paid reactions.
215#[serde_with::skip_serializing_none]
216#[derive(Clone, Debug, Serialize)]
217pub struct SetMessageReaction {
218 chat_id: ChatId,
219 is_big: bool,
220 message_id: Integer,
221 reaction: Option<Vec<ReactionType>>,
222}
223
224impl SetMessageReaction {
225 /// Creates a new `SetMessageReaction`.
226 ///
227 /// # Arguments
228 ///
229 /// * `chat_id` - Unique identifier of the target chat.
230 /// * `message_id` - Identifier of the target message.
231 pub fn new<T>(chat_id: T, message_id: Integer) -> Self
232 where
233 T: Into<ChatId>,
234 {
235 Self {
236 chat_id: chat_id.into(),
237 message_id,
238 reaction: None,
239 is_big: false,
240 }
241 }
242
243 /// Sets a new value for the `is_big` flag.
244 ///
245 /// # Arguments
246 ///
247 /// * `value` - Whether to set the reaction with a big animation.
248 pub fn with_is_big(mut self, value: bool) -> Self {
249 self.is_big = value;
250 self
251 }
252
253 /// Sets a new list of reaction types.
254 ///
255 /// # Arguments
256 ///
257 /// * `value` - New list of reaction types to set on the message.
258 ///
259 /// Currently, as non-premium users, bots can set up to one reaction per message.
260 /// A custom emoji reaction can be used if it is either already present on
261 /// the message or explicitly allowed by chat administrators.
262 pub fn with_reaction<T>(mut self, value: T) -> Self
263 where
264 T: IntoIterator<Item = ReactionType>,
265 {
266 self.reaction = Some(value.into_iter().collect());
267 self
268 }
269}
270
271impl Method for SetMessageReaction {
272 type Response = bool;
273
274 fn into_payload(self) -> Payload {
275 Payload::json("setMessageReaction", self)
276 }
277}