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