tgbot/types/update/
mod.rs

1use std::{collections::HashSet, time::Duration};
2
3use serde::{Deserialize, Serialize};
4use serde_json::Value as JsonValue;
5
6use crate::{
7    api::{Method, Payload},
8    types::{
9        BusinessConnection,
10        BusinessMessagesDeleted,
11        CallbackQuery,
12        Chat,
13        ChatBoostRemoved,
14        ChatBoostUpdated,
15        ChatJoinRequest,
16        ChatMemberUpdated,
17        ChatPeerId,
18        ChatUsername,
19        ChosenInlineResult,
20        InlineQuery,
21        Integer,
22        MaybeInaccessibleMessage,
23        Message,
24        MessageReactionCountUpdated,
25        MessageReactionUpdated,
26        PaidMediaPurchased,
27        Poll,
28        PollAnswer,
29        PollAnswerVoter,
30        PreCheckoutQuery,
31        ShippingQuery,
32        User,
33        UserPeerId,
34        UserUsername,
35    },
36};
37
38#[cfg(test)]
39mod tests;
40
41/// Represents an incoming update.
42#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
43pub struct Update {
44    /// Unique identifier of the update.
45    ///
46    /// Update identifiers start from a certain positive number and increase sequentially.
47    /// This ID becomes especially handy if you’re using Webhooks, since it allows you to
48    /// ignore repeated updates or to restore the correct update sequence,
49    /// should they get out of order.
50    /// If there are no new updates for at least a week, then identifier
51    /// of the next update will be chosen randomly instead of sequentially.
52    #[serde(rename = "update_id")]
53    pub id: Integer,
54    /// Type of the update.
55    #[serde(flatten)]
56    pub update_type: UpdateType,
57}
58
59impl Update {
60    /// Creates a new `Update`.
61    ///
62    /// # Arguments
63    ///
64    /// * `id` - Unique identifier of the update.
65    /// * `update_type` - Type of the update.
66    pub fn new(id: Integer, update_type: UpdateType) -> Self {
67        Self { id, update_type }
68    }
69
70    /// Returns the chat.
71    pub fn get_chat(&self) -> Option<&Chat> {
72        self.get_message().map(|msg| &msg.chat).or(match self.update_type {
73            UpdateType::BotStatus(ref x) | UpdateType::UserStatus(ref x) => Some(&x.chat),
74            UpdateType::DeletedBusinessMessages(ref x) => Some(&x.chat),
75            UpdateType::ChatBoostRemoved(ref x) => Some(&x.chat),
76            UpdateType::ChatBoostUpdated(ref x) => Some(&x.chat),
77            UpdateType::ChatJoinRequest(ref x) => Some(&x.chat),
78            UpdateType::MessageReaction(ref x) => Some(&x.chat),
79            UpdateType::MessageReactionCount(ref x) => Some(&x.chat),
80            _ => None,
81        })
82    }
83
84    /// Returns the ID of the chat.
85    pub fn get_chat_id(&self) -> Option<ChatPeerId> {
86        self.get_chat().map(|chat| chat.get_id())
87    }
88
89    /// Returns the username of the chat.
90    pub fn get_chat_username(&self) -> Option<&ChatUsername> {
91        self.get_chat().and_then(|chat| chat.get_username())
92    }
93
94    /// Returns the user.
95    pub fn get_user(&self) -> Option<&User> {
96        Some(match self.update_type {
97            UpdateType::BotStatus(ref x) | UpdateType::UserStatus(ref x) => &x.from,
98            UpdateType::BusinessConnection(ref x) => &x.user,
99            UpdateType::CallbackQuery(ref x) => &x.from,
100            UpdateType::ChatBoostRemoved(_) => return None,
101            UpdateType::ChatBoostUpdated(_) => return None,
102            UpdateType::ChatJoinRequest(ref x) => &x.from,
103            UpdateType::ChosenInlineResult(ref x) => &x.from,
104            UpdateType::DeletedBusinessMessages(_) => return None,
105            UpdateType::InlineQuery(ref x) => &x.from,
106            UpdateType::Message(ref x)
107            | UpdateType::BusinessMessage(ref x)
108            | UpdateType::EditedBusinessMessage(ref x)
109            | UpdateType::EditedMessage(ref x)
110            | UpdateType::ChannelPost(ref x)
111            | UpdateType::EditedChannelPost(ref x) => return x.sender.get_user(),
112            UpdateType::MessageReaction(ref x) => return x.user.as_ref(),
113            UpdateType::MessageReactionCount(_) => return None,
114            UpdateType::Poll(_) => return None,
115            UpdateType::PollAnswer(ref x) => match &x.voter {
116                PollAnswerVoter::User(x) => x,
117                PollAnswerVoter::Chat(_) => return None,
118            },
119            UpdateType::PreCheckoutQuery(ref x) => &x.from,
120            UpdateType::PurchasedPaidMedia(ref x) => &x.from,
121            UpdateType::ShippingQuery(ref x) => &x.from,
122            UpdateType::Unknown(_) => return None,
123        })
124    }
125
126    /// Returns the ID of the user.
127    pub fn get_user_id(&self) -> Option<UserPeerId> {
128        self.get_user().map(|user| user.id)
129    }
130
131    /// Returns the username of the user.
132    pub fn get_user_username(&self) -> Option<&UserUsername> {
133        self.get_user().and_then(|user| user.username.as_ref())
134    }
135
136    /// Returns the message.
137    pub fn get_message(&self) -> Option<&Message> {
138        match self.update_type {
139            UpdateType::Message(ref msg)
140            | UpdateType::BusinessMessage(ref msg)
141            | UpdateType::EditedBusinessMessage(ref msg)
142            | UpdateType::EditedMessage(ref msg)
143            | UpdateType::ChannelPost(ref msg)
144            | UpdateType::EditedChannelPost(ref msg) => Some(msg),
145            UpdateType::CallbackQuery(ref query) => match query.message {
146                Some(MaybeInaccessibleMessage::Message(ref msg)) => Some(msg),
147                _ => None,
148            },
149            _ => None,
150        }
151    }
152}
153
154/// Represents a type of an update.
155#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
156#[allow(clippy::large_enum_variant)]
157#[serde(rename_all = "snake_case")]
158pub enum UpdateType {
159    /// The bot chat member status was updated in a chat.
160    ///
161    /// For private chats, this update is received only
162    /// when the bot is blocked or unblocked by the user.
163    #[serde(rename = "my_chat_member")]
164    BotStatus(ChatMemberUpdated),
165    /// The bot was connected to or disconnected from a business account,
166    /// or a user edited an existing connection with the bot.
167    BusinessConnection(BusinessConnection),
168    /// New non-service message from a connected business account.
169    BusinessMessage(Message),
170    /// A new incoming callback query.
171    CallbackQuery(CallbackQuery),
172    /// A new incoming channel post.
173    ChannelPost(Message),
174    /// A boost was removed from a chat.
175    ///
176    /// The bot must be an administrator in the chat to receive these updates.
177    #[serde(rename = "removed_chat_boost")]
178    ChatBoostRemoved(ChatBoostRemoved),
179    /// A chat boost was added or changed.
180    ///
181    /// The bot must be an administrator in the chat to receive these updates.
182    #[serde(rename = "chat_boost")]
183    ChatBoostUpdated(ChatBoostUpdated),
184    /// A request to join the chat has been sent.
185    ///
186    /// The bot must have the `can_invite_users` administrator right
187    /// in the chat to receive these updates.
188    ChatJoinRequest(ChatJoinRequest),
189    /// The result of an inline query that was chosen by a user and sent to their chat partner.
190    ///
191    /// Please see our documentation on the [feedback collecting][1]
192    /// for details on how to enable these updates for your bot.
193    ///
194    /// [1]: https://core.telegram.org/bots/inline#collecting-feedback
195    ChosenInlineResult(ChosenInlineResult),
196    /// Messages were deleted from a connected business account.
197    DeletedBusinessMessages(BusinessMessagesDeleted),
198    /// New version of a message from a connected business account.
199    EditedBusinessMessage(Message),
200    /// A new version of a channel post that is known to the bot and was edited.
201    EditedChannelPost(Message),
202    /// A new version of a message that is known to the bot and was edited.
203    EditedMessage(Message),
204    /// A new incoming [inline][1] query.
205    ///
206    /// [1]: https://core.telegram.org/bots/api#inline-mode
207    InlineQuery(InlineQuery),
208    /// A new incoming message.
209    Message(Message),
210    /// A reaction to a message was changed by a user.
211    ///
212    /// The bot must be an administrator in the chat
213    /// and must explicitly specify [`AllowedUpdate::MessageReaction`]
214    /// in the list of allowed_updates to receive these updates.
215    ///
216    /// The update isn't received for reactions set by bots.
217    MessageReaction(MessageReactionUpdated),
218    /// Reactions to a message with anonymous reactions were changed.
219    ///
220    /// The bot must be an administrator in the chat
221    /// and must explicitly specify [`AllowedUpdate::MessageReactionCount`]
222    /// in the list of allowed_updates to receive these updates.
223    MessageReactionCount(MessageReactionCountUpdated),
224    /// A new poll state.
225    ///
226    /// Bots receive only updates about polls, which are sent or stopped by the bot.
227    Poll(Poll),
228    /// A user changed their answer in a non-anonymous poll
229    ///
230    /// Bots receive new votes only in polls that were sent by the bot itself.
231    PollAnswer(PollAnswer),
232    /// A new incoming pre-checkout query.
233    ///
234    /// Contains full information about checkout
235    PreCheckoutQuery(PreCheckoutQuery),
236    /// A user purchased paid media with a non-empty payload sent by the bot in a non-channel chat.
237    PurchasedPaidMedia(PaidMediaPurchased),
238    /// A new incoming shipping query.
239    ///
240    /// Only for invoices with flexible price.
241    ShippingQuery(ShippingQuery),
242    /// A chat member's status was updated in a chat.
243    ///
244    /// The bot must be an administrator in the chat
245    /// and must explicitly specify [`AllowedUpdate::UserStatus`] in the list
246    /// of `allowed_updates` to receive these updates.
247    #[serde(rename = "chat_member")]
248    UserStatus(ChatMemberUpdated),
249    /// Used for unknown update types.
250    ///
251    /// For example, Telegram introduced a new update type,
252    /// but tgbot does not support it.
253    #[serde(untagged)]
254    Unknown(JsonValue),
255}
256
257/// Conversion of an [`Update`] into `T` failed.
258///
259/// Use [`Update::from`] to get the original update.
260pub struct UnexpectedUpdate(Update);
261
262impl From<UnexpectedUpdate> for Update {
263    fn from(value: UnexpectedUpdate) -> Self {
264        value.0
265    }
266}
267
268impl TryFrom<Update> for BusinessConnection {
269    type Error = UnexpectedUpdate;
270
271    fn try_from(value: Update) -> Result<Self, Self::Error> {
272        use self::UpdateType::*;
273        match value.update_type {
274            BusinessConnection(x) => Ok(x),
275            _ => Err(UnexpectedUpdate(value)),
276        }
277    }
278}
279
280impl TryFrom<Update> for BusinessMessagesDeleted {
281    type Error = UnexpectedUpdate;
282
283    fn try_from(value: Update) -> Result<Self, Self::Error> {
284        use self::UpdateType::*;
285        match value.update_type {
286            DeletedBusinessMessages(x) => Ok(x),
287            _ => Err(UnexpectedUpdate(value)),
288        }
289    }
290}
291
292impl TryFrom<Update> for ChatMemberUpdated {
293    type Error = UnexpectedUpdate;
294
295    fn try_from(value: Update) -> Result<Self, Self::Error> {
296        use self::UpdateType::*;
297        match value.update_type {
298            BotStatus(x) | UserStatus(x) => Ok(x),
299            _ => Err(UnexpectedUpdate(value)),
300        }
301    }
302}
303
304impl TryFrom<Update> for CallbackQuery {
305    type Error = UnexpectedUpdate;
306
307    fn try_from(value: Update) -> Result<Self, Self::Error> {
308        use self::UpdateType::*;
309        match value.update_type {
310            CallbackQuery(x) => Ok(x),
311            _ => Err(UnexpectedUpdate(value)),
312        }
313    }
314}
315
316impl TryFrom<Update> for ChatJoinRequest {
317    type Error = UnexpectedUpdate;
318
319    fn try_from(value: Update) -> Result<Self, Self::Error> {
320        use self::UpdateType::*;
321        match value.update_type {
322            ChatJoinRequest(x) => Ok(x),
323            _ => Err(UnexpectedUpdate(value)),
324        }
325    }
326}
327
328impl TryFrom<Update> for ChosenInlineResult {
329    type Error = UnexpectedUpdate;
330
331    fn try_from(value: Update) -> Result<Self, Self::Error> {
332        use self::UpdateType::*;
333        match value.update_type {
334            ChosenInlineResult(x) => Ok(x),
335            _ => Err(UnexpectedUpdate(value)),
336        }
337    }
338}
339
340impl TryFrom<Update> for InlineQuery {
341    type Error = UnexpectedUpdate;
342
343    fn try_from(value: Update) -> Result<Self, Self::Error> {
344        use self::UpdateType::*;
345        match value.update_type {
346            InlineQuery(x) => Ok(x),
347            _ => Err(UnexpectedUpdate(value)),
348        }
349    }
350}
351
352impl TryFrom<Update> for Message {
353    type Error = UnexpectedUpdate;
354
355    fn try_from(value: Update) -> Result<Self, Self::Error> {
356        use self::UpdateType::*;
357        match value.update_type {
358            BusinessMessage(x)
359            | EditedBusinessMessage(x)
360            | EditedChannelPost(x)
361            | EditedMessage(x)
362            | ChannelPost(x)
363            | Message(x) => Ok(x),
364            _ => Err(UnexpectedUpdate(value)),
365        }
366    }
367}
368
369impl TryFrom<Update> for Poll {
370    type Error = UnexpectedUpdate;
371
372    fn try_from(value: Update) -> Result<Self, Self::Error> {
373        use self::UpdateType::*;
374        match value.update_type {
375            Poll(x) => Ok(x),
376            _ => Err(UnexpectedUpdate(value)),
377        }
378    }
379}
380
381impl TryFrom<Update> for PollAnswer {
382    type Error = UnexpectedUpdate;
383
384    fn try_from(value: Update) -> Result<Self, Self::Error> {
385        use self::UpdateType::*;
386        match value.update_type {
387            PollAnswer(x) => Ok(x),
388            _ => Err(UnexpectedUpdate(value)),
389        }
390    }
391}
392
393impl TryFrom<Update> for PreCheckoutQuery {
394    type Error = UnexpectedUpdate;
395
396    fn try_from(value: Update) -> Result<Self, Self::Error> {
397        use self::UpdateType::*;
398        match value.update_type {
399            PreCheckoutQuery(x) => Ok(x),
400            _ => Err(UnexpectedUpdate(value)),
401        }
402    }
403}
404
405impl TryFrom<Update> for PaidMediaPurchased {
406    type Error = UnexpectedUpdate;
407
408    fn try_from(value: Update) -> Result<Self, Self::Error> {
409        use self::UpdateType::*;
410        match value.update_type {
411            PurchasedPaidMedia(x) => Ok(x),
412            _ => Err(UnexpectedUpdate(value)),
413        }
414    }
415}
416
417impl TryFrom<Update> for ShippingQuery {
418    type Error = UnexpectedUpdate;
419
420    fn try_from(value: Update) -> Result<Self, Self::Error> {
421        use self::UpdateType::*;
422        match value.update_type {
423            ShippingQuery(x) => Ok(x),
424            _ => Err(UnexpectedUpdate(value)),
425        }
426    }
427}
428
429/// Represents a type of update to receive.
430#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
431#[serde(rename_all = "snake_case")]
432pub enum AllowedUpdate {
433    /// The bot chat member status.
434    #[serde(rename = "my_chat_member")]
435    BotStatus,
436    /// Business account connection changes.
437    BusinessConnection,
438    /// New non-service message from a connected business account.
439    BusinessMessage,
440    /// A callback query.
441    CallbackQuery,
442    /// A channel post.
443    ChannelPost,
444    /// A boost was removed from a chat.
445    #[serde(rename = "removed_chat_boost")]
446    ChatBoostRemoved,
447    /// A chat boost was added or changed.
448    #[serde(rename = "chat_boost")]
449    ChatBoostUpdated,
450    /// A request to join a chat.
451    ChatJoinRequest,
452    /// A chosen inline result.
453    ChosenInlineResult,
454    /// Messages were deleted from a connected business account.
455    DeletedBusinessMessages,
456    /// New version of a message from a connected business account.
457    EditedBusinessMessage,
458    /// An edited channel post.
459    EditedChannelPost,
460    /// An edited message.
461    EditedMessage,
462    /// An inline query.
463    InlineQuery,
464    /// A message.
465    Message,
466    /// A reaction to a message.
467    MessageReaction,
468    /// An anonymous reaction to a message.
469    MessageReactionCount,
470    /// A poll.
471    Poll,
472    /// A poll answer.
473    PollAnswer,
474    /// A pre checkout query.
475    PreCheckoutQuery,
476    /// A user purchased paid media.
477    PurchasedPaidMedia,
478    /// A shipping query.
479    ShippingQuery,
480    /// A chat member status.
481    #[serde(rename = "chat_member")]
482    UserStatus,
483}
484
485#[serde_with::skip_serializing_none]
486/// Returns incoming updates using long polling.
487#[derive(Clone, Debug, Default, Serialize)]
488pub struct GetUpdates {
489    allowed_updates: Option<HashSet<AllowedUpdate>>,
490    limit: Option<Integer>,
491    offset: Option<Integer>,
492    timeout: Option<Integer>,
493}
494
495impl Method for GetUpdates {
496    type Response = Vec<Update>;
497
498    fn into_payload(self) -> Payload {
499        Payload::json("getUpdates", self)
500    }
501}
502
503impl GetUpdates {
504    /// Adds a type of an update you want your bot to receive.
505    ///
506    /// # Arguments
507    ///
508    /// * `value` - The type to add.
509    pub fn add_allowed_update(mut self, value: AllowedUpdate) -> Self {
510        match self.allowed_updates {
511            Some(ref mut updates) => {
512                updates.insert(value);
513            }
514            None => {
515                let mut updates = HashSet::new();
516                updates.insert(value);
517                self.allowed_updates = Some(updates);
518            }
519        };
520        self
521    }
522
523    /// Sets a new list of allowed updates.
524    ///
525    /// # Arguments
526    ///
527    /// * `value` - List of the types of updates you want your bot to receive.
528    ///
529    /// For example, specify `[AllowedUpdate::Message, AllowedUpdate::EditedChannelPost]`
530    /// to only receive updates of these types.
531    /// Specify an empty list to receive all updates regardless of type (default).
532    /// If not specified, the previous setting will be used.
533    /// Please note that this parameter doesn't affect updates
534    /// created before the call to the method,
535    /// so unwanted updates may be received for a short period of time.
536    pub fn with_allowed_updates<T>(mut self, value: T) -> Self
537    where
538        T: IntoIterator<Item = AllowedUpdate>,
539    {
540        self.allowed_updates = Some(value.into_iter().collect());
541        self
542    }
543
544    /// Sets a new limit.
545    ///
546    /// # Arguments
547    ///
548    /// * `value` - Limit of the number of updates to be retrieved; 1—100; default - 100.
549    pub fn with_limit(mut self, value: Integer) -> Self {
550        self.limit = Some(value);
551        self
552    }
553
554    /// Sets a new offset.
555    ///
556    /// # Arguments
557    ///
558    /// * `value` - Identifier of the first update to be returned.
559    ///
560    /// Must be greater by one than the highest
561    /// among the identifiers of previously received updates.
562    /// By default, updates starting with the earliest unconfirmed update are returned.
563    /// An update is considered confirmed as soon as the method is called with
564    /// an offset higher than its `update_id`.
565    /// The negative offset can be specified to retrieve updates starting
566    /// from `-offset` update from the end of the updates queue.
567    /// All previous updates will forgotten.
568    pub fn with_offset(mut self, value: Integer) -> Self {
569        self.offset = Some(value);
570        self
571    }
572
573    /// Sets a new timeout.
574    ///
575    /// # Arguments
576    ///
577    /// * `value` - Timeout for long polling; default - 0, i.e. usual short polling; should be positive;
578    ///   short polling should be used for testing purposes only.
579    pub fn with_timeout(mut self, value: Duration) -> Self {
580        self.timeout = Some(value.as_secs() as i64);
581        self
582    }
583}