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}