1#![allow(clippy::large_enum_variant)]
2
3use chrono::{DateTime, Utc};
4use derive_more::derive::From;
5use serde::{Deserialize, Serialize};
6use url::Url;
7
8use crate::types::{
9 Animation, Audio, BareChatId, BusinessConnectionId, Chat, ChatBackground, ChatBoostAdded,
10 ChatId, ChatShared, Checklist, ChecklistTasksAdded, ChecklistTasksDone, Contact, Dice,
11 DirectMessagePriceChanged, Document, ExternalReplyInfo, ForumTopicClosed, ForumTopicCreated,
12 ForumTopicEdited, ForumTopicReopened, Game, GeneralForumTopicHidden, GeneralForumTopicUnhidden,
13 GiftInfo, Giveaway, GiveawayCompleted, GiveawayCreated, GiveawayWinners, InlineKeyboardMarkup,
14 Invoice, LinkPreviewOptions, Location, MaybeInaccessibleMessage, MessageAutoDeleteTimerChanged,
15 MessageEntity, MessageEntityRef, MessageId, MessageOrigin, PaidMediaInfo,
16 PaidMessagePriceChanged, PassportData, PhotoSize, Poll, ProximityAlertTriggered,
17 RefundedPayment, Sticker, Story, SuccessfulPayment, TextQuote, ThreadId, True, UniqueGiftInfo,
18 User, UsersShared, Venue, Video, VideoChatEnded, VideoChatParticipantsInvited,
19 VideoChatScheduled, VideoChatStarted, VideoNote, Voice, WebAppData, WriteAccessAllowed,
20};
21
22#[serde_with::skip_serializing_none]
26#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
27pub struct Message {
28 #[serde(flatten)]
30 pub id: MessageId,
31
32 #[serde(rename = "message_thread_id")]
35 pub thread_id: Option<ThreadId>,
36
37 pub from: Option<User>,
39
40 pub sender_chat: Option<Chat>,
45
46 #[serde(with = "crate::types::serde_date_from_unix_timestamp")]
48 pub date: DateTime<Utc>,
49
50 pub chat: Chat,
52
53 #[serde(default, skip_serializing_if = "std::ops::Not::not")]
55 pub is_topic_message: bool,
56
57 pub via_bot: Option<User>,
59
60 pub sender_business_bot: Option<User>,
64
65 #[serde(flatten)]
66 pub kind: MessageKind,
67}
68
69#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
73#[serde(untagged)]
74pub enum MessageKind {
75 Common(MessageCommon),
76 NewChatMembers(MessageNewChatMembers),
77 LeftChatMember(MessageLeftChatMember),
78 NewChatTitle(MessageNewChatTitle),
79 NewChatPhoto(MessageNewChatPhoto),
80 DeleteChatPhoto(MessageDeleteChatPhoto),
81 GroupChatCreated(MessageGroupChatCreated),
82 SupergroupChatCreated(MessageSupergroupChatCreated),
83 ChannelChatCreated(MessageChannelChatCreated),
84 MessageAutoDeleteTimerChanged(MessageMessageAutoDeleteTimerChanged),
85 Pinned(MessagePinned),
86 ChatShared(MessageChatShared),
87 UsersShared(MessageUsersShared),
88 Invoice(MessageInvoice),
89 SuccessfulPayment(MessageSuccessfulPayment),
90 RefundedPayment(MessageRefundedPayment),
91 ConnectedWebsite(MessageConnectedWebsite),
92 WriteAccessAllowed(MessageWriteAccessAllowed),
93 PassportData(MessagePassportData),
94 Dice(MessageDice),
95 ProximityAlertTriggered(MessageProximityAlertTriggered),
96 ChatBoostAdded(MessageChatBoostAdded),
97 ChatBackground(MessageChatBackground),
98 ChecklistTasksDone(MessageChecklistTasksDone),
99 ChecklistTasksAdded(MessageChecklistTasksAdded),
100 DirectMessagePriceChanged(MessageDirectMessagePriceChanged),
101 ForumTopicCreated(MessageForumTopicCreated),
102 ForumTopicEdited(MessageForumTopicEdited),
103 ForumTopicClosed(MessageForumTopicClosed),
104 ForumTopicReopened(MessageForumTopicReopened),
105 GeneralForumTopicHidden(MessageGeneralForumTopicHidden),
106 GeneralForumTopicUnhidden(MessageGeneralForumTopicUnhidden),
107 Giveaway(MessageGiveaway),
108 GiveawayCompleted(MessageGiveawayCompleted),
109 GiveawayCreated(MessageGiveawayCreated),
110 GiveawayWinners(MessageGiveawayWinners),
111 PaidMessagePriceChanged(MessagePaidMessagePriceChanged),
112 GiftInfo(MessageGiftInfo),
113 UniqueGiftInfo(MessageUniqueGiftInfo),
114 VideoChatScheduled(MessageVideoChatScheduled),
115 VideoChatStarted(MessageVideoChatStarted),
116 VideoChatEnded(MessageVideoChatEnded),
117 VideoChatParticipantsInvited(MessageVideoChatParticipantsInvited),
118 WebAppData(MessageWebAppData),
119 Empty {},
122}
123
124#[derive(
126 Default,
127 Clone,
128 Debug,
129 derive_more::Display,
130 PartialEq,
131 Eq,
132 Hash,
133 Serialize,
134 Deserialize,
135 From
136)]
137#[serde(transparent)]
138#[from(&'static str, String)]
139pub struct EffectId(pub String);
140
141#[serde_with::skip_serializing_none]
142#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
143pub struct MessageCommon {
144 pub author_signature: Option<String>,
147
148 pub paid_star_count: Option<u32>,
151
152 pub effect_id: Option<EffectId>,
154
155 pub forward_origin: Option<MessageOrigin>,
157
158 pub reply_to_message: Option<Box<Message>>,
162
163 pub external_reply: Option<ExternalReplyInfo>,
166
167 pub quote: Option<TextQuote>,
170
171 pub reply_to_story: Option<Story>,
173
174 pub sender_boost_count: Option<u16>,
177
178 #[serde(default, with = "crate::types::serde_opt_date_from_unix_timestamp")]
180 pub edit_date: Option<DateTime<Utc>>,
181
182 #[serde(flatten)]
183 pub media_kind: MediaKind,
184
185 pub reply_markup: Option<InlineKeyboardMarkup>,
188
189 #[serde(default, skip_serializing_if = "std::ops::Not::not")]
192 pub is_automatic_forward: bool,
193
194 #[serde(default, skip_serializing_if = "std::ops::Not::not")]
196 pub has_protected_content: bool,
197
198 #[serde(default, skip_serializing_if = "std::ops::Not::not")]
201 pub is_from_offline: bool,
202
203 pub business_connection_id: Option<BusinessConnectionId>,
208}
209
210#[serde_with::skip_serializing_none]
211#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
212pub struct MessageNewChatMembers {
213 pub new_chat_members: Vec<User>,
217}
218
219#[serde_with::skip_serializing_none]
220#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
221pub struct MessageLeftChatMember {
222 pub left_chat_member: User,
225}
226
227#[serde_with::skip_serializing_none]
228#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
229pub struct MessageNewChatTitle {
230 pub new_chat_title: String,
232}
233
234#[serde_with::skip_serializing_none]
235#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
236pub struct MessageNewChatPhoto {
237 pub new_chat_photo: Vec<PhotoSize>,
239}
240
241#[serde_with::skip_serializing_none]
242#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
243pub struct MessageDeleteChatPhoto {
244 pub delete_chat_photo: True,
246}
247
248#[serde_with::skip_serializing_none]
249#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
250pub struct MessageGroupChatCreated {
251 pub group_chat_created: True,
253}
254
255#[serde_with::skip_serializing_none]
256#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
257pub struct MessageSupergroupChatCreated {
258 pub supergroup_chat_created: True,
264}
265
266#[serde_with::skip_serializing_none]
267#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
268pub struct MessageChannelChatCreated {
269 pub channel_chat_created: True,
275}
276
277#[serde_with::skip_serializing_none]
278#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
279pub struct MessageMessageAutoDeleteTimerChanged {
280 pub message_auto_delete_timer_changed: MessageAutoDeleteTimerChanged,
282}
283
284#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
295#[serde(untagged)]
296pub enum ChatMigration {
297 To {
300 #[serde(rename = "migrate_to_chat_id")]
301 chat_id: ChatId,
302 },
303
304 From {
307 #[serde(rename = "migrate_from_chat_id")]
308 chat_id: ChatId,
309 },
310}
311
312#[serde_with::skip_serializing_none]
313#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
314pub struct MessagePinned {
315 #[serde(rename = "pinned_message")]
319 pub pinned: Box<MaybeInaccessibleMessage>,
320}
321
322#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
323pub struct MessageChatShared {
324 pub chat_shared: ChatShared,
326}
327
328#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
329pub struct MessageUsersShared {
330 pub users_shared: UsersShared,
332}
333
334#[serde_with::skip_serializing_none]
335#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
336pub struct MessageInvoice {
337 pub invoice: Invoice,
343}
344
345#[serde_with::skip_serializing_none]
346#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
347pub struct MessageRefundedPayment {
348 pub refunded_payment: RefundedPayment,
353}
354
355#[serde_with::skip_serializing_none]
356#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
357pub struct MessageSuccessfulPayment {
358 pub successful_payment: SuccessfulPayment,
363}
364
365#[serde_with::skip_serializing_none]
366#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
367pub struct MessageConnectedWebsite {
368 pub connected_website: String,
373}
374
375#[serde_with::skip_serializing_none]
376#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
377pub struct MessagePassportData {
378 pub passport_data: PassportData,
380}
381
382#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
383#[serde(untagged)]
384pub enum MediaKind {
385 Animation(MediaAnimation),
394 Audio(MediaAudio),
395 Contact(MediaContact),
396 Document(MediaDocument),
397 PaidMedia(MediaPaid),
398 Game(MediaGame),
399 Venue(MediaVenue),
400 Location(MediaLocation),
401 Photo(MediaPhoto),
402 Poll(MediaPoll),
403 Checklist(MediaChecklist),
404 Sticker(MediaSticker),
405 Story(MediaStory),
406 Text(MediaText),
407 Video(MediaVideo),
408 VideoNote(MediaVideoNote),
409 Voice(MediaVoice),
410 Migration(ChatMigration),
411}
412
413#[serde_with::skip_serializing_none]
414#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
415pub struct MediaAnimation {
416 pub animation: Animation,
420
421 pub caption: Option<String>,
423
424 #[serde(default, skip_serializing_if = "Vec::is_empty")]
427 pub caption_entities: Vec<MessageEntity>,
428
429 #[serde(default, skip_serializing_if = "std::ops::Not::not")]
431 pub show_caption_above_media: bool,
432
433 #[serde(default, skip_serializing_if = "std::ops::Not::not")]
435 pub has_media_spoiler: bool,
436 }
438
439#[derive(
441 Default,
442 Clone,
443 Debug,
444 derive_more::Display,
445 PartialEq,
446 Eq,
447 Hash,
448 Serialize,
449 Deserialize,
450 From
451)]
452#[serde(transparent)]
453#[from(&'static str, String)]
454pub struct MediaGroupId(pub String);
455
456#[serde_with::skip_serializing_none]
457#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
458pub struct MediaAudio {
459 pub audio: Audio,
461
462 pub caption: Option<String>,
464
465 #[serde(default, skip_serializing_if = "Vec::is_empty")]
468 pub caption_entities: Vec<MessageEntity>,
469
470 pub media_group_id: Option<MediaGroupId>,
473}
474
475#[serde_with::skip_serializing_none]
476#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
477pub struct MediaContact {
478 pub contact: Contact,
480}
481
482#[serde_with::skip_serializing_none]
483#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
484pub struct MediaDocument {
485 pub document: Document,
487
488 pub caption: Option<String>,
490
491 #[serde(default, skip_serializing_if = "Vec::is_empty")]
494 pub caption_entities: Vec<MessageEntity>,
495
496 pub media_group_id: Option<MediaGroupId>,
499}
500
501#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
502pub struct MediaPaid {
503 pub paid_media: PaidMediaInfo,
505}
506
507#[serde_with::skip_serializing_none]
508#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
509pub struct MediaGame {
510 pub game: Game,
515}
516
517#[serde_with::skip_serializing_none]
518#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
519pub struct MediaLocation {
520 pub location: Location,
522}
523
524#[serde_with::skip_serializing_none]
525#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
526pub struct MediaPhoto {
527 pub photo: Vec<PhotoSize>,
529
530 pub caption: Option<String>,
532
533 #[serde(default, skip_serializing_if = "Vec::is_empty")]
536 pub caption_entities: Vec<MessageEntity>,
537
538 #[serde(default, skip_serializing_if = "std::ops::Not::not")]
540 pub show_caption_above_media: bool,
541
542 #[serde(default, skip_serializing_if = "std::ops::Not::not")]
544 pub has_media_spoiler: bool,
545
546 pub media_group_id: Option<MediaGroupId>,
549}
550
551#[serde_with::skip_serializing_none]
552#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
553pub struct MediaPoll {
554 pub poll: Poll,
556}
557
558#[serde_with::skip_serializing_none]
559#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
560pub struct MediaChecklist {
561 pub checklist: Checklist,
563}
564
565#[serde_with::skip_serializing_none]
566#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
567pub struct MediaSticker {
568 pub sticker: Sticker,
570}
571
572#[serde_with::skip_serializing_none]
573#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
574pub struct MediaStory {
575 pub story: Story,
577}
578
579#[serde_with::skip_serializing_none]
580#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
581pub struct MediaText {
582 pub text: String,
585
586 #[serde(default, skip_serializing_if = "Vec::is_empty")]
589 pub entities: Vec<MessageEntity>,
590
591 pub link_preview_options: Option<LinkPreviewOptions>,
594}
595
596#[serde_with::skip_serializing_none]
597#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
598pub struct MediaVideo {
599 pub video: Video,
601
602 pub caption: Option<String>,
604
605 #[serde(default, skip_serializing_if = "Vec::is_empty")]
608 pub caption_entities: Vec<MessageEntity>,
609
610 #[serde(default, skip_serializing_if = "std::ops::Not::not")]
612 pub show_caption_above_media: bool,
613
614 #[serde(default, skip_serializing_if = "std::ops::Not::not")]
616 pub has_media_spoiler: bool,
617
618 pub media_group_id: Option<MediaGroupId>,
621}
622
623#[serde_with::skip_serializing_none]
624#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
625pub struct MediaVideoNote {
626 pub video_note: VideoNote,
630}
631
632#[serde_with::skip_serializing_none]
633#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
634pub struct MediaVoice {
635 pub voice: Voice,
637
638 pub caption: Option<String>,
640
641 #[serde(default, skip_serializing_if = "Vec::is_empty")]
644 pub caption_entities: Vec<MessageEntity>,
645}
646
647#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
648pub struct MediaVenue {
649 pub venue: Venue,
651 }
653
654#[serde_with::skip_serializing_none]
655#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
656pub struct MessageDice {
657 pub dice: Dice,
659}
660
661#[serde_with::skip_serializing_none]
662#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
663pub struct MessageProximityAlertTriggered {
664 pub proximity_alert_triggered: ProximityAlertTriggered,
667}
668
669#[serde_with::skip_serializing_none]
670#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
671pub struct MessageChatBoostAdded {
672 pub boost_added: ChatBoostAdded,
674}
675
676#[serde_with::skip_serializing_none]
677#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
678pub struct MessageChatBackground {
679 pub chat_background_set: ChatBackground,
681}
682
683#[serde_with::skip_serializing_none]
684#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
685pub struct MessageChecklistTasksDone {
686 pub checklist_tasks_done: ChecklistTasksDone,
689}
690
691#[serde_with::skip_serializing_none]
692#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
693pub struct MessageChecklistTasksAdded {
694 pub checklist_tasks_added: ChecklistTasksAdded,
696}
697
698#[serde_with::skip_serializing_none]
699#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
700pub struct MessageDirectMessagePriceChanged {
701 pub direct_message_price_changed: DirectMessagePriceChanged,
704}
705
706#[serde_with::skip_serializing_none]
707#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
708pub struct MessageWriteAccessAllowed {
709 pub write_access_allowed: WriteAccessAllowed,
712}
713
714#[serde_with::skip_serializing_none]
715#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
716pub struct MessageForumTopicCreated {
717 pub forum_topic_created: ForumTopicCreated,
719}
720
721#[serde_with::skip_serializing_none]
722#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
723pub struct MessageForumTopicEdited {
724 pub forum_topic_edited: ForumTopicEdited,
726}
727
728#[serde_with::skip_serializing_none]
729#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
730pub struct MessageForumTopicClosed {
731 pub forum_topic_closed: ForumTopicClosed,
733}
734
735#[serde_with::skip_serializing_none]
736#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
737pub struct MessageForumTopicReopened {
738 pub forum_topic_reopened: ForumTopicReopened,
740}
741
742#[serde_with::skip_serializing_none]
743#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
744pub struct MessageGeneralForumTopicHidden {
745 pub general_forum_topic_hidden: GeneralForumTopicHidden,
747}
748
749#[serde_with::skip_serializing_none]
750#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
751pub struct MessageGeneralForumTopicUnhidden {
752 pub general_forum_topic_unhidden: GeneralForumTopicUnhidden,
754}
755
756#[serde_with::skip_serializing_none]
757#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
758pub struct MessageGiveaway {
759 pub giveaway: Giveaway,
764}
765
766#[serde_with::skip_serializing_none]
767#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
768pub struct MessageGiveawayCompleted {
769 pub giveaway_completed: GiveawayCompleted,
774}
775
776#[serde_with::skip_serializing_none]
777#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
778pub struct MessageGiveawayCreated {
779 pub giveaway_created: GiveawayCreated,
784}
785
786#[serde_with::skip_serializing_none]
787#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
788pub struct MessageGiveawayWinners {
789 pub giveaway_winners: GiveawayWinners,
794}
795
796#[serde_with::skip_serializing_none]
797#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
798pub struct MessagePaidMessagePriceChanged {
799 pub paid_message_price_changed: PaidMessagePriceChanged,
801}
802
803#[serde_with::skip_serializing_none]
804#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
805pub struct MessageGiftInfo {
806 pub gift: GiftInfo,
808}
809
810#[serde_with::skip_serializing_none]
811#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
812pub struct MessageUniqueGiftInfo {
813 pub unique_gift: UniqueGiftInfo,
815}
816
817#[serde_with::skip_serializing_none]
818#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
819pub struct MessageVideoChatScheduled {
820 pub video_chat_scheduled: VideoChatScheduled,
822}
823
824#[serde_with::skip_serializing_none]
825#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
826pub struct MessageVideoChatStarted {
827 pub video_chat_started: VideoChatStarted,
829}
830
831#[serde_with::skip_serializing_none]
832#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
833pub struct MessageVideoChatEnded {
834 pub video_chat_ended: VideoChatEnded,
836}
837
838#[serde_with::skip_serializing_none]
839#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
840pub struct MessageVideoChatParticipantsInvited {
841 pub video_chat_participants_invited: VideoChatParticipantsInvited,
843}
844
845#[serde_with::skip_serializing_none]
846#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
847pub struct MessageWebAppData {
848 pub web_app_data: WebAppData,
850}
851
852mod getters {
853 use chrono::{DateTime, Utc};
854 use std::ops::Deref;
855
856 use crate::types::{
857 self, message::MessageKind::*, Chat, ChatId, ChatMigration, EffectId, LinkPreviewOptions,
858 MaybeInaccessibleMessage, MediaAnimation, MediaAudio, MediaChecklist, MediaContact,
859 MediaDocument, MediaGame, MediaKind, MediaLocation, MediaPaid, MediaPhoto, MediaPoll,
860 MediaSticker, MediaStory, MediaText, MediaVenue, MediaVideo, MediaVideoNote, MediaVoice,
861 Message, MessageChannelChatCreated, MessageChatShared, MessageChecklistTasksAdded,
862 MessageChecklistTasksDone, MessageCommon, MessageConnectedWebsite, MessageDeleteChatPhoto,
863 MessageDice, MessageDirectMessagePriceChanged, MessageEntity, MessageGroupChatCreated,
864 MessageId, MessageInvoice, MessageLeftChatMember, MessageNewChatMembers,
865 MessageNewChatPhoto, MessageNewChatTitle, MessageOrigin, MessagePassportData,
866 MessagePinned, MessageProximityAlertTriggered, MessageSuccessfulPayment,
867 MessageSupergroupChatCreated, MessageUsersShared, MessageVideoChatParticipantsInvited,
868 PhotoSize, Story, TextQuote, User,
869 };
870
871 use super::{
872 MediaGroupId, MessageChatBackground, MessageChatBoostAdded, MessageForumTopicClosed,
873 MessageForumTopicCreated, MessageForumTopicEdited, MessageForumTopicReopened,
874 MessageGeneralForumTopicHidden, MessageGeneralForumTopicUnhidden, MessageGiftInfo,
875 MessageGiveaway, MessageGiveawayCompleted, MessageGiveawayCreated, MessageGiveawayWinners,
876 MessageMessageAutoDeleteTimerChanged, MessagePaidMessagePriceChanged,
877 MessageUniqueGiftInfo, MessageVideoChatEnded, MessageVideoChatScheduled,
878 MessageVideoChatStarted, MessageWebAppData, MessageWriteAccessAllowed,
879 };
880
881 impl Message {
886 #[deprecated(since = "0.13.0", note = "use `.from` field instead")]
888 #[must_use]
889 pub fn from(&self) -> Option<&User> {
890 self.from.as_ref()
891 }
892
893 #[must_use]
894 pub fn author_signature(&self) -> Option<&str> {
895 match &self.kind {
896 Common(MessageCommon { author_signature, .. }) => author_signature.as_deref(),
897 _ => None,
898 }
899 }
900
901 #[must_use]
902 pub fn effect_id(&self) -> Option<&EffectId> {
903 match &self.kind {
904 Common(MessageCommon { effect_id, .. }) => effect_id.as_ref(),
905 _ => None,
906 }
907 }
908
909 #[deprecated(since = "0.13.0", note = "use `.sender_chat` field instead")]
910 #[must_use]
911 pub fn sender_chat(&self) -> Option<&Chat> {
912 self.sender_chat.as_ref()
913 }
914
915 #[must_use]
916 pub fn forward_origin(&self) -> Option<&MessageOrigin> {
917 match &self.kind {
918 Common(MessageCommon { forward_origin, .. }) => forward_origin.as_ref(),
919 _ => None,
920 }
921 }
922
923 #[must_use]
924 pub fn quote(&self) -> Option<&TextQuote> {
925 match &self.kind {
926 Common(MessageCommon { quote, .. }) => quote.as_ref(),
927 _ => None,
928 }
929 }
930
931 #[must_use]
932 pub fn reply_to_story(&self) -> Option<&Story> {
933 match &self.kind {
934 Common(MessageCommon { reply_to_story, .. }) => reply_to_story.as_ref(),
935 _ => None,
936 }
937 }
938
939 #[must_use]
940 pub fn sender_boost_count(&self) -> Option<u16> {
941 match &self.kind {
942 Common(MessageCommon { sender_boost_count, .. }) => *sender_boost_count,
943 _ => None,
944 }
945 }
946
947 #[must_use]
948 pub fn forward_date(&self) -> Option<DateTime<Utc>> {
949 self.forward_origin().map(|f| f.date())
950 }
951
952 #[must_use]
953 pub fn forward_from_user(&self) -> Option<&User> {
954 self.forward_origin().and_then(|origin| match origin {
955 MessageOrigin::User { sender_user, .. } => Some(sender_user),
956 _ => None,
957 })
958 }
959
960 #[must_use]
961 pub fn forward_from_chat(&self) -> Option<&Chat> {
962 self.forward_origin().and_then(|origin| match origin {
963 MessageOrigin::Chat { sender_chat, .. } => Some(sender_chat),
964 _ => None,
965 })
966 }
967
968 #[must_use]
969 pub fn forward_from_sender_name(&self) -> Option<&str> {
970 self.forward_origin().and_then(|origin| match origin {
971 MessageOrigin::HiddenUser { sender_user_name, .. } => {
972 Some(sender_user_name.as_str())
973 }
974 _ => None,
975 })
976 }
977
978 #[must_use]
979 pub fn forward_from_message_id(&self) -> Option<MessageId> {
980 self.forward_origin().and_then(|origin| match origin {
981 MessageOrigin::Channel { message_id, .. } => Some(*message_id),
982 _ => None,
983 })
984 }
985
986 #[must_use]
987 pub fn forward_author_signature(&self) -> Option<&str> {
988 self.forward_origin().and_then(|origin| match origin {
989 MessageOrigin::Chat { author_signature, .. } => {
990 author_signature.as_ref().map(|a| a.as_str())
991 }
992 MessageOrigin::Channel { author_signature, .. } => {
993 author_signature.as_ref().map(|a| a.as_str())
994 }
995 _ => None,
996 })
997 }
998
999 #[must_use]
1000 pub fn reply_to_message(&self) -> Option<&Message> {
1001 self.common().and_then(|m| m.reply_to_message.as_deref())
1002 }
1003
1004 #[must_use]
1005 pub fn edit_date(&self) -> Option<&DateTime<Utc>> {
1006 match &self.kind {
1007 Common(MessageCommon { edit_date, .. }) => edit_date.as_ref(),
1008 _ => None,
1009 }
1010 }
1011
1012 #[must_use]
1013 pub fn media_group_id(&self) -> Option<&MediaGroupId> {
1014 match &self.kind {
1015 Common(MessageCommon {
1016 media_kind: MediaKind::Video(MediaVideo { media_group_id, .. }),
1017 ..
1018 })
1019 | Common(MessageCommon {
1020 media_kind: MediaKind::Photo(MediaPhoto { media_group_id, .. }),
1021 ..
1022 })
1023 | Common(MessageCommon {
1024 media_kind: MediaKind::Document(MediaDocument { media_group_id, .. }),
1025 ..
1026 })
1027 | Common(MessageCommon {
1028 media_kind: MediaKind::Audio(MediaAudio { media_group_id, .. }),
1029 ..
1030 }) => media_group_id.as_ref(),
1031 _ => None,
1032 }
1033 }
1034
1035 #[must_use]
1036 pub fn text(&self) -> Option<&str> {
1037 match &self.kind {
1038 Common(MessageCommon {
1039 media_kind: MediaKind::Text(MediaText { text, .. }),
1040 ..
1041 }) => Some(text),
1042 _ => None,
1043 }
1044 }
1045
1046 #[must_use]
1059 pub fn entities(&self) -> Option<&[MessageEntity]> {
1060 match &self.kind {
1061 Common(MessageCommon {
1062 media_kind: MediaKind::Text(MediaText { entities, .. }),
1063 ..
1064 }) => Some(entities),
1065 _ => None,
1066 }
1067 }
1068
1069 #[must_use]
1070 pub fn link_preview_options(&self) -> Option<&LinkPreviewOptions> {
1071 match &self.kind {
1072 Common(MessageCommon {
1073 media_kind: MediaKind::Text(MediaText { link_preview_options, .. }),
1074 ..
1075 }) => link_preview_options.as_ref(),
1076 _ => None,
1077 }
1078 }
1079
1080 #[must_use]
1093 pub fn caption_entities(&self) -> Option<&[MessageEntity]> {
1094 match &self.kind {
1095 Common(MessageCommon {
1096 media_kind: MediaKind::Animation(MediaAnimation { caption_entities, .. }),
1097 ..
1098 })
1099 | Common(MessageCommon {
1100 media_kind: MediaKind::Audio(MediaAudio { caption_entities, .. }),
1101 ..
1102 })
1103 | Common(MessageCommon {
1104 media_kind: MediaKind::Document(MediaDocument { caption_entities, .. }),
1105 ..
1106 })
1107 | Common(MessageCommon {
1108 media_kind: MediaKind::Photo(MediaPhoto { caption_entities, .. }),
1109 ..
1110 })
1111 | Common(MessageCommon {
1112 media_kind: MediaKind::Video(MediaVideo { caption_entities, .. }),
1113 ..
1114 })
1115 | Common(MessageCommon {
1116 media_kind: MediaKind::Voice(MediaVoice { caption_entities, .. }),
1117 ..
1118 }) => Some(caption_entities),
1119 _ => None,
1120 }
1121 }
1122
1123 #[must_use]
1129 pub fn show_caption_above_media(&self) -> bool {
1130 self.common()
1131 .map(|m| match m.media_kind {
1132 MediaKind::Animation(MediaAnimation { show_caption_above_media, .. })
1133 | MediaKind::Photo(MediaPhoto { show_caption_above_media, .. })
1134 | MediaKind::Video(MediaVideo { show_caption_above_media, .. }) => {
1135 show_caption_above_media
1136 }
1137 MediaKind::Audio(_)
1138 | MediaKind::Contact(_)
1139 | MediaKind::Document(_)
1140 | MediaKind::PaidMedia(_)
1141 | MediaKind::Game(_)
1142 | MediaKind::Venue(_)
1143 | MediaKind::Location(_)
1144 | MediaKind::Poll(_)
1145 | MediaKind::Checklist(_)
1146 | MediaKind::Sticker(_)
1147 | MediaKind::Story(_)
1148 | MediaKind::Text(_)
1149 | MediaKind::VideoNote(_)
1150 | MediaKind::Voice(_)
1151 | MediaKind::Migration(_) => false,
1152 })
1153 .unwrap_or(false)
1154 }
1155
1156 #[must_use]
1163 pub fn has_media_spoiler(&self) -> bool {
1164 self.common()
1165 .map(|m| match m.media_kind {
1166 MediaKind::Animation(MediaAnimation { has_media_spoiler, .. })
1167 | MediaKind::Photo(MediaPhoto { has_media_spoiler, .. })
1168 | MediaKind::Video(MediaVideo { has_media_spoiler, .. }) => has_media_spoiler,
1169 MediaKind::Audio(_)
1170 | MediaKind::Contact(_)
1171 | MediaKind::Document(_)
1172 | MediaKind::PaidMedia(_)
1173 | MediaKind::Game(_)
1174 | MediaKind::Venue(_)
1175 | MediaKind::Location(_)
1176 | MediaKind::Poll(_)
1177 | MediaKind::Checklist(_)
1178 | MediaKind::Sticker(_)
1179 | MediaKind::Story(_)
1180 | MediaKind::Text(_)
1181 | MediaKind::VideoNote(_)
1182 | MediaKind::Voice(_)
1183 | MediaKind::Migration(_) => false,
1184 })
1185 .unwrap_or(false)
1186 }
1187
1188 #[must_use]
1189 pub fn audio(&self) -> Option<&types::Audio> {
1190 match &self.kind {
1191 Common(MessageCommon {
1192 media_kind: MediaKind::Audio(MediaAudio { audio, .. }),
1193 ..
1194 }) => Some(audio),
1195 _ => None,
1196 }
1197 }
1198
1199 #[must_use]
1200 pub fn document(&self) -> Option<&types::Document> {
1201 match &self.kind {
1202 Common(MessageCommon {
1203 media_kind: MediaKind::Document(MediaDocument { document, .. }),
1204 ..
1205 }) => Some(document),
1206 _ => None,
1207 }
1208 }
1209
1210 #[must_use]
1211 pub fn paid_media(&self) -> Option<&types::PaidMediaInfo> {
1212 match &self.kind {
1213 Common(MessageCommon {
1214 media_kind: MediaKind::PaidMedia(MediaPaid { paid_media, .. }),
1215 ..
1216 }) => Some(paid_media),
1217 _ => None,
1218 }
1219 }
1220
1221 #[must_use]
1222 pub fn animation(&self) -> Option<&types::Animation> {
1223 match &self.kind {
1224 Common(MessageCommon {
1225 media_kind: MediaKind::Animation(MediaAnimation { animation, .. }),
1226 ..
1227 }) => Some(animation),
1228 _ => None,
1229 }
1230 }
1231
1232 #[must_use]
1233 pub fn game(&self) -> Option<&types::Game> {
1234 match &self.kind {
1235 Common(MessageCommon {
1236 media_kind: MediaKind::Game(MediaGame { game, .. }),
1237 ..
1238 }) => Some(game),
1239 _ => None,
1240 }
1241 }
1242
1243 #[must_use]
1244 pub fn photo(&self) -> Option<&[PhotoSize]> {
1245 match &self.kind {
1246 Common(MessageCommon {
1247 media_kind: MediaKind::Photo(MediaPhoto { photo, .. }),
1248 ..
1249 }) => Some(photo),
1250 _ => None,
1251 }
1252 }
1253
1254 #[must_use]
1255 pub fn sticker(&self) -> Option<&types::Sticker> {
1256 match &self.kind {
1257 Common(MessageCommon {
1258 media_kind: MediaKind::Sticker(MediaSticker { sticker, .. }),
1259 ..
1260 }) => Some(sticker),
1261 _ => None,
1262 }
1263 }
1264
1265 #[must_use]
1266 pub fn story(&self) -> Option<&types::Story> {
1267 match &self.kind {
1268 Common(MessageCommon {
1269 media_kind: MediaKind::Story(MediaStory { story, .. }),
1270 ..
1271 }) => Some(story),
1272 _ => None,
1273 }
1274 }
1275
1276 #[must_use]
1277 pub fn video(&self) -> Option<&types::Video> {
1278 match &self.kind {
1279 Common(MessageCommon {
1280 media_kind: MediaKind::Video(MediaVideo { video, .. }),
1281 ..
1282 }) => Some(video),
1283 _ => None,
1284 }
1285 }
1286
1287 #[must_use]
1288 pub fn voice(&self) -> Option<&types::Voice> {
1289 match &self.kind {
1290 Common(MessageCommon {
1291 media_kind: MediaKind::Voice(MediaVoice { voice, .. }),
1292 ..
1293 }) => Some(voice),
1294 _ => None,
1295 }
1296 }
1297
1298 #[must_use]
1299 pub fn video_note(&self) -> Option<&types::VideoNote> {
1300 match &self.kind {
1301 Common(MessageCommon {
1302 media_kind: MediaKind::VideoNote(MediaVideoNote { video_note, .. }),
1303 ..
1304 }) => Some(video_note),
1305 _ => None,
1306 }
1307 }
1308
1309 #[must_use]
1310 pub fn caption(&self) -> Option<&str> {
1311 match &self.kind {
1312 Common(MessageCommon {
1313 media_kind:
1314 MediaKind::Animation(MediaAnimation { caption, .. })
1315 | MediaKind::Audio(MediaAudio { caption, .. })
1316 | MediaKind::Document(MediaDocument { caption, .. })
1317 | MediaKind::Photo(MediaPhoto { caption, .. })
1318 | MediaKind::Video(MediaVideo { caption, .. })
1319 | MediaKind::Voice(MediaVoice { caption, .. }),
1320 ..
1321 }) => caption.as_ref().map(Deref::deref),
1322 _ => None,
1323 }
1324 }
1325
1326 #[must_use]
1327 pub fn contact(&self) -> Option<&types::Contact> {
1328 match &self.kind {
1329 Common(MessageCommon {
1330 media_kind: MediaKind::Contact(MediaContact { contact, .. }),
1331 ..
1332 }) => Some(contact),
1333 _ => None,
1334 }
1335 }
1336
1337 #[must_use]
1338 pub fn location(&self) -> Option<&types::Location> {
1339 match &self.kind {
1340 Common(MessageCommon {
1341 media_kind: MediaKind::Location(MediaLocation { location, .. }),
1342 ..
1343 }) => Some(location),
1344 _ => None,
1345 }
1346 }
1347
1348 #[must_use]
1349 pub fn venue(&self) -> Option<&types::Venue> {
1350 match &self.kind {
1351 Common(MessageCommon {
1352 media_kind: MediaKind::Venue(MediaVenue { venue, .. }),
1353 ..
1354 }) => Some(venue),
1355 _ => None,
1356 }
1357 }
1358
1359 #[must_use]
1360 pub fn poll(&self) -> Option<&types::Poll> {
1361 match &self.kind {
1362 Common(MessageCommon {
1363 media_kind: MediaKind::Poll(MediaPoll { poll, .. }),
1364 ..
1365 }) => Some(poll),
1366 _ => None,
1367 }
1368 }
1369
1370 #[must_use]
1371 pub fn checklist(&self) -> Option<&types::Checklist> {
1372 match &self.kind {
1373 Common(MessageCommon {
1374 media_kind: MediaKind::Checklist(MediaChecklist { checklist, .. }),
1375 ..
1376 }) => Some(checklist),
1377 _ => None,
1378 }
1379 }
1380
1381 #[must_use]
1382 pub fn new_chat_members(&self) -> Option<&[User]> {
1383 match &self.kind {
1384 NewChatMembers(MessageNewChatMembers { new_chat_members }) => {
1385 Some(new_chat_members.as_ref())
1386 }
1387 _ => None,
1388 }
1389 }
1390
1391 #[must_use]
1392 pub fn left_chat_member(&self) -> Option<&User> {
1393 match &self.kind {
1394 LeftChatMember(MessageLeftChatMember { left_chat_member }) => {
1395 Some(left_chat_member)
1396 }
1397 _ => None,
1398 }
1399 }
1400
1401 #[must_use]
1402 pub fn new_chat_title(&self) -> Option<&str> {
1403 match &self.kind {
1404 NewChatTitle(MessageNewChatTitle { new_chat_title }) => Some(new_chat_title),
1405 _ => None,
1406 }
1407 }
1408
1409 #[must_use]
1410 pub fn new_chat_photo(&self) -> Option<&[PhotoSize]> {
1411 match &self.kind {
1412 NewChatPhoto(MessageNewChatPhoto { new_chat_photo }) => Some(new_chat_photo),
1413 _ => None,
1414 }
1415 }
1416
1417 #[must_use]
1422 pub fn is_delete_chat_photo(&self) -> bool {
1423 matches!(&self.kind, DeleteChatPhoto(..))
1424 }
1425
1426 #[must_use]
1427 pub fn delete_chat_photo(&self) -> Option<&MessageDeleteChatPhoto> {
1428 match &self.kind {
1429 DeleteChatPhoto(message_delete_chat_photo) => Some(message_delete_chat_photo),
1430 _ => None,
1431 }
1432 }
1433
1434 #[must_use]
1439 pub fn is_group_chat_created(&self) -> bool {
1440 matches!(&self.kind, GroupChatCreated(..))
1441 }
1442
1443 #[must_use]
1444 pub fn group_chat_created(&self) -> Option<&MessageGroupChatCreated> {
1445 match &self.kind {
1446 GroupChatCreated(message_group_chat_created) => Some(message_group_chat_created),
1447 _ => None,
1448 }
1449 }
1450
1451 #[must_use]
1456 pub fn is_super_group_chat_created(&self) -> bool {
1457 matches!(&self.kind, SupergroupChatCreated(..))
1458 }
1459
1460 #[must_use]
1461 pub fn super_group_chat_created(&self) -> Option<&MessageSupergroupChatCreated> {
1462 match &self.kind {
1463 SupergroupChatCreated(message_supergroup_chat_created) => {
1464 Some(message_supergroup_chat_created)
1465 }
1466 _ => None,
1467 }
1468 }
1469
1470 #[must_use]
1475 pub fn is_channel_chat_created(&self) -> bool {
1476 matches!(&self.kind, ChannelChatCreated(..))
1477 }
1478
1479 #[must_use]
1480 pub fn channel_chat_created(&self) -> Option<&MessageChannelChatCreated> {
1481 match &self.kind {
1482 ChannelChatCreated(message_channel_chat_created) => {
1483 Some(message_channel_chat_created)
1484 }
1485 _ => None,
1486 }
1487 }
1488
1489 #[must_use]
1490 pub fn message_auto_delete_timer_changed(
1491 &self,
1492 ) -> Option<&types::MessageAutoDeleteTimerChanged> {
1493 match &self.kind {
1494 MessageAutoDeleteTimerChanged(MessageMessageAutoDeleteTimerChanged {
1495 message_auto_delete_timer_changed,
1496 }) => Some(message_auto_delete_timer_changed),
1497 _ => None,
1498 }
1499 }
1500
1501 #[must_use]
1502 pub fn chat_migration(&self) -> Option<&ChatMigration> {
1503 match &self.kind {
1504 Common(MessageCommon {
1505 media_kind: MediaKind::Migration(chat_migration), ..
1506 }) => Some(chat_migration),
1507 _ => None,
1508 }
1509 }
1510
1511 #[must_use]
1514 pub fn migrate_to_chat_id(&self) -> Option<&ChatId> {
1515 match &self.kind {
1516 Common(MessageCommon {
1517 media_kind: MediaKind::Migration(ChatMigration::To { chat_id }),
1518 ..
1519 }) => Some(chat_id),
1520 _ => None,
1521 }
1522 }
1523
1524 #[must_use]
1527 pub fn migrate_from_chat_id(&self) -> Option<&ChatId> {
1528 match &self.kind {
1529 Common(MessageCommon {
1530 media_kind: MediaKind::Migration(ChatMigration::From { chat_id }),
1531 ..
1532 }) => Some(chat_id),
1533 _ => None,
1534 }
1535 }
1536
1537 #[must_use]
1538 pub fn pinned_message(&self) -> Option<&MaybeInaccessibleMessage> {
1539 match &self.kind {
1540 Pinned(MessagePinned { pinned }) => Some(pinned),
1541 _ => None,
1542 }
1543 }
1544
1545 #[must_use]
1546 pub fn invoice(&self) -> Option<&types::Invoice> {
1547 match &self.kind {
1548 Invoice(MessageInvoice { invoice }) => Some(invoice),
1549 _ => None,
1550 }
1551 }
1552
1553 #[must_use]
1554 pub fn successful_payment(&self) -> Option<&types::SuccessfulPayment> {
1555 match &self.kind {
1556 SuccessfulPayment(MessageSuccessfulPayment { successful_payment }) => {
1557 Some(successful_payment)
1558 }
1559 _ => None,
1560 }
1561 }
1562
1563 #[must_use]
1564 pub fn connected_website(&self) -> Option<&str> {
1565 match &self.kind {
1566 ConnectedWebsite(MessageConnectedWebsite { connected_website }) => {
1567 Some(connected_website)
1568 }
1569 _ => None,
1570 }
1571 }
1572
1573 #[must_use]
1574 pub fn write_access_allowed(&self) -> Option<&types::WriteAccessAllowed> {
1575 match &self.kind {
1576 WriteAccessAllowed(MessageWriteAccessAllowed { write_access_allowed }) => {
1577 Some(write_access_allowed)
1578 }
1579 _ => None,
1580 }
1581 }
1582
1583 #[must_use]
1584 pub fn passport_data(&self) -> Option<&types::PassportData> {
1585 match &self.kind {
1586 PassportData(MessagePassportData { passport_data }) => Some(passport_data),
1587 _ => None,
1588 }
1589 }
1590
1591 #[must_use]
1592 pub fn shared_chat(&self) -> Option<&types::ChatShared> {
1593 match &self.kind {
1594 ChatShared(MessageChatShared { chat_shared }) => Some(chat_shared),
1595 _ => None,
1596 }
1597 }
1598
1599 #[must_use]
1600 pub fn shared_users(&self) -> Option<&types::UsersShared> {
1601 match &self.kind {
1602 UsersShared(MessageUsersShared { users_shared }) => Some(users_shared),
1603 _ => None,
1604 }
1605 }
1606
1607 #[must_use]
1608 pub fn dice(&self) -> Option<&types::Dice> {
1609 match &self.kind {
1610 Dice(MessageDice { dice }) => Some(dice),
1611 _ => None,
1612 }
1613 }
1614
1615 #[must_use]
1616 pub fn proximity_alert_triggered(&self) -> Option<&types::ProximityAlertTriggered> {
1617 match &self.kind {
1618 ProximityAlertTriggered(MessageProximityAlertTriggered {
1619 proximity_alert_triggered,
1620 }) => Some(proximity_alert_triggered),
1621 _ => None,
1622 }
1623 }
1624
1625 #[must_use]
1626 pub fn boost_added(&self) -> Option<&types::ChatBoostAdded> {
1627 match &self.kind {
1628 ChatBoostAdded(MessageChatBoostAdded { boost_added }) => Some(boost_added),
1629 _ => None,
1630 }
1631 }
1632
1633 #[must_use]
1634 pub fn chat_background_set(&self) -> Option<&types::ChatBackground> {
1635 match &self.kind {
1636 ChatBackground(MessageChatBackground { chat_background_set }) => {
1637 Some(chat_background_set)
1638 }
1639 _ => None,
1640 }
1641 }
1642
1643 #[must_use]
1644 pub fn checklist_tasks_done(&self) -> Option<&types::ChecklistTasksDone> {
1645 match &self.kind {
1646 ChecklistTasksDone(MessageChecklistTasksDone { checklist_tasks_done }) => {
1647 Some(checklist_tasks_done)
1648 }
1649 _ => None,
1650 }
1651 }
1652
1653 #[must_use]
1654 pub fn checklist_tasks_added(&self) -> Option<&types::ChecklistTasksAdded> {
1655 match &self.kind {
1656 ChecklistTasksAdded(MessageChecklistTasksAdded { checklist_tasks_added }) => {
1657 Some(checklist_tasks_added)
1658 }
1659 _ => None,
1660 }
1661 }
1662
1663 #[must_use]
1664 pub fn direct_message_price_changed(&self) -> Option<&types::DirectMessagePriceChanged> {
1665 match &self.kind {
1666 DirectMessagePriceChanged(MessageDirectMessagePriceChanged {
1667 direct_message_price_changed,
1668 }) => Some(direct_message_price_changed),
1669 _ => None,
1670 }
1671 }
1672
1673 #[must_use]
1674 pub fn forum_topic_created(&self) -> Option<&types::ForumTopicCreated> {
1675 match &self.kind {
1676 ForumTopicCreated(MessageForumTopicCreated { forum_topic_created }) => {
1677 Some(forum_topic_created)
1678 }
1679 _ => None,
1680 }
1681 }
1682
1683 #[must_use]
1684 pub fn forum_topic_edited(&self) -> Option<&types::ForumTopicEdited> {
1685 match &self.kind {
1686 ForumTopicEdited(MessageForumTopicEdited { forum_topic_edited }) => {
1687 Some(forum_topic_edited)
1688 }
1689 _ => None,
1690 }
1691 }
1692
1693 #[must_use]
1694 pub fn forum_topic_closed(&self) -> Option<&types::ForumTopicClosed> {
1695 match &self.kind {
1696 ForumTopicClosed(MessageForumTopicClosed { forum_topic_closed }) => {
1697 Some(forum_topic_closed)
1698 }
1699 _ => None,
1700 }
1701 }
1702
1703 #[must_use]
1704 pub fn forum_topic_reopened(&self) -> Option<&types::ForumTopicReopened> {
1705 match &self.kind {
1706 ForumTopicReopened(MessageForumTopicReopened { forum_topic_reopened }) => {
1707 Some(forum_topic_reopened)
1708 }
1709 _ => None,
1710 }
1711 }
1712
1713 #[must_use]
1714 pub fn general_forum_topic_hidden(&self) -> Option<&types::GeneralForumTopicHidden> {
1715 match &self.kind {
1716 GeneralForumTopicHidden(MessageGeneralForumTopicHidden {
1717 general_forum_topic_hidden,
1718 }) => Some(general_forum_topic_hidden),
1719 _ => None,
1720 }
1721 }
1722
1723 #[must_use]
1724 pub fn general_forum_topic_unhidden(&self) -> Option<&types::GeneralForumTopicUnhidden> {
1725 match &self.kind {
1726 GeneralForumTopicUnhidden(MessageGeneralForumTopicUnhidden {
1727 general_forum_topic_unhidden,
1728 }) => Some(general_forum_topic_unhidden),
1729 _ => None,
1730 }
1731 }
1732
1733 #[must_use]
1734 pub fn giveaway(&self) -> Option<&types::Giveaway> {
1735 match &self.kind {
1736 Giveaway(MessageGiveaway { giveaway }) => Some(giveaway),
1737 _ => None,
1738 }
1739 }
1740
1741 #[must_use]
1742 pub fn giveaway_completed(&self) -> Option<&types::GiveawayCompleted> {
1743 match &self.kind {
1744 GiveawayCompleted(MessageGiveawayCompleted { giveaway_completed }) => {
1745 Some(giveaway_completed)
1746 }
1747 _ => None,
1748 }
1749 }
1750
1751 #[must_use]
1752 pub fn giveaway_created(&self) -> Option<&types::GiveawayCreated> {
1753 match &self.kind {
1754 GiveawayCreated(MessageGiveawayCreated { giveaway_created }) => {
1755 Some(giveaway_created)
1756 }
1757 _ => None,
1758 }
1759 }
1760
1761 #[must_use]
1762 pub fn giveaway_winners(&self) -> Option<&types::GiveawayWinners> {
1763 match &self.kind {
1764 GiveawayWinners(MessageGiveawayWinners { giveaway_winners }) => {
1765 Some(giveaway_winners)
1766 }
1767 _ => None,
1768 }
1769 }
1770
1771 #[must_use]
1772 pub fn paid_message_price_changed(&self) -> Option<&types::PaidMessagePriceChanged> {
1773 match &self.kind {
1774 PaidMessagePriceChanged(MessagePaidMessagePriceChanged {
1775 paid_message_price_changed,
1776 }) => Some(paid_message_price_changed),
1777 _ => None,
1778 }
1779 }
1780
1781 #[must_use]
1782 pub fn gift_info(&self) -> Option<&types::GiftInfo> {
1783 match &self.kind {
1784 GiftInfo(MessageGiftInfo { gift }) => Some(gift),
1785 _ => None,
1786 }
1787 }
1788
1789 #[must_use]
1790 pub fn unique_gift_info(&self) -> Option<&types::UniqueGiftInfo> {
1791 match &self.kind {
1792 UniqueGiftInfo(MessageUniqueGiftInfo { unique_gift }) => Some(unique_gift),
1793 _ => None,
1794 }
1795 }
1796
1797 #[must_use]
1798 pub fn video_chat_scheduled(&self) -> Option<&types::VideoChatScheduled> {
1799 match &self.kind {
1800 VideoChatScheduled(MessageVideoChatScheduled { video_chat_scheduled }) => {
1801 Some(video_chat_scheduled)
1802 }
1803 _ => None,
1804 }
1805 }
1806
1807 #[must_use]
1808 pub fn video_chat_started(&self) -> Option<&types::VideoChatStarted> {
1809 match &self.kind {
1810 VideoChatStarted(MessageVideoChatStarted { video_chat_started }) => {
1811 Some(video_chat_started)
1812 }
1813 _ => None,
1814 }
1815 }
1816
1817 #[must_use]
1818 pub fn video_chat_ended(&self) -> Option<&types::VideoChatEnded> {
1819 match &self.kind {
1820 VideoChatEnded(MessageVideoChatEnded { video_chat_ended }) => {
1821 Some(video_chat_ended)
1822 }
1823 _ => None,
1824 }
1825 }
1826
1827 #[must_use]
1828 pub fn video_chat_participants_invited(
1829 &self,
1830 ) -> Option<&types::VideoChatParticipantsInvited> {
1831 match &self.kind {
1832 VideoChatParticipantsInvited(MessageVideoChatParticipantsInvited {
1833 video_chat_participants_invited,
1834 }) => Some(video_chat_participants_invited),
1835 _ => None,
1836 }
1837 }
1838
1839 #[must_use]
1840 pub fn web_app_data(&self) -> Option<&types::WebAppData> {
1841 match &self.kind {
1842 WebAppData(MessageWebAppData { web_app_data }) => Some(web_app_data),
1843 _ => None,
1844 }
1845 }
1846
1847 #[must_use]
1848 pub fn reply_markup(&self) -> Option<&types::InlineKeyboardMarkup> {
1849 match &self.kind {
1850 Common(MessageCommon { reply_markup, .. }) => reply_markup.as_ref(),
1851 _ => None,
1852 }
1853 }
1854
1855 #[must_use]
1856 pub fn is_automatic_forward(&self) -> bool {
1857 match &self.kind {
1858 Common(MessageCommon { is_automatic_forward, .. }) => *is_automatic_forward,
1859 _ => false,
1860 }
1861 }
1862
1863 #[must_use]
1864 pub fn has_protected_content(&self) -> bool {
1865 match &self.kind {
1866 Common(MessageCommon { has_protected_content, .. }) => *has_protected_content,
1867 _ => false,
1868 }
1869 }
1870
1871 fn common(&self) -> Option<&MessageCommon> {
1873 match &self.kind {
1874 Common(message) => Some(message),
1875 _ => None,
1876 }
1877 }
1878
1879 }
1881}
1882
1883impl Message {
1884 #[must_use]
1892 pub fn url(&self) -> Option<Url> {
1893 Self::url_of(self.chat.id, self.chat.username(), self.id)
1894 }
1895
1896 #[track_caller]
1910 #[must_use]
1911 pub fn url_of(
1912 chat_id: ChatId,
1913 chat_username: Option<&str>,
1914 message_id: MessageId,
1915 ) -> Option<Url> {
1916 use BareChatId::*;
1917
1918 let chat_id = match chat_id.to_bare() {
1920 User(_) => return None,
1927 Group(_) => return None,
1932 Channel(id) => id,
1933 };
1934
1935 let url = match chat_username {
1936 Some(username) => format!("https://t.me/{0}/{1}", username, message_id.0),
1939 None => format!("https://t.me/c/{0}/{1}", chat_id, message_id.0),
1942 };
1943
1944 Some(reqwest::Url::parse(&url).unwrap())
1949 }
1950
1951 #[must_use]
1959 pub fn comment_url(&self, comment_id: MessageId) -> Option<Url> {
1960 Self::comment_url_of(self.chat.id, self.chat.username(), self.id, comment_id)
1961 }
1962
1963 #[must_use]
1978 pub fn comment_url_of(
1979 channel_id: ChatId,
1980 channel_username: Option<&str>,
1981 post_id: MessageId,
1982 comment_id: MessageId,
1983 ) -> Option<Url> {
1984 Self::url_of(channel_id, channel_username, post_id).map(|mut url| {
1985 url.set_query(Some(&format!("comment={}", comment_id.0)));
1986 url
1987 })
1988 }
1989
1990 #[must_use]
2002 pub fn url_in_thread(&self, thread_starter_msg_id: MessageId) -> Option<Url> {
2003 Self::url_in_thread_of(self.chat.id, self.chat.username(), thread_starter_msg_id, self.id)
2004 }
2005
2006 #[must_use]
2025 pub fn url_in_thread_of(
2026 chat_id: ChatId,
2027 chat_username: Option<&str>,
2028 thread_starter_msg_id: MessageId,
2029 message_id: MessageId,
2030 ) -> Option<Url> {
2031 Self::url_of(chat_id, chat_username, message_id).map(|mut url| {
2032 url.set_query(Some(&format!("thread={}", thread_starter_msg_id.0)));
2033 url
2034 })
2035 }
2036
2037 #[must_use]
2047 pub fn parse_entities(&self) -> Option<Vec<MessageEntityRef<'_>>> {
2048 self.text().zip(self.entities()).map(|(t, e)| MessageEntityRef::parse(t, e))
2049 }
2050
2051 #[must_use]
2060 pub fn parse_caption_entities(&self) -> Option<Vec<MessageEntityRef<'_>>> {
2061 self.caption().zip(self.caption_entities()).map(|(t, e)| MessageEntityRef::parse(t, e))
2062 }
2063
2064 pub fn mentioned_users(&self) -> impl Iterator<Item = &User> {
2079 use crate::util::{flatten, mentioned_users_from_entities};
2080
2081 self.from
2084 .iter()
2085 .chain(self.via_bot.as_ref())
2086 .chain(flatten(self.reply_to_message().map(Self::mentioned_users_rec)))
2087 .chain(flatten(self.new_chat_members()))
2088 .chain(self.left_chat_member())
2089 .chain(self.forward_from_user())
2090 .chain(flatten(self.game().map(Game::mentioned_users)))
2091 .chain(flatten(self.entities().map(mentioned_users_from_entities)))
2092 .chain(flatten(self.caption_entities().map(mentioned_users_from_entities)))
2093 .chain(flatten(self.poll().map(Poll::mentioned_users)))
2094 .chain(flatten(self.proximity_alert_triggered().map(|a| [&a.traveler, &a.watcher])))
2095 .chain(flatten(self.video_chat_participants_invited().and_then(|i| i.users.as_deref())))
2096 }
2097
2098 pub(crate) fn mentioned_users_rec(&self) -> Box<dyn Iterator<Item = &User> + Send + Sync + '_> {
2102 Box::new(self.mentioned_users())
2103 }
2104}
2105
2106impl From<Message> for MessageId {
2108 fn from(message: Message) -> MessageId {
2109 message.id
2110 }
2111}
2112
2113impl From<&Message> for MessageId {
2114 fn from(message: &Message) -> MessageId {
2115 message.id
2116 }
2117}
2118
2119#[cfg(test)]
2120mod tests {
2121 use chrono::DateTime;
2122 use cool_asserts::assert_matches;
2123 use serde_json::from_str;
2124
2125 use crate::types::*;
2126
2127 #[test]
2128 fn de_media_forwarded() {
2129 let json = r#"{
2130 "message_id": 198283,
2131 "from": {
2132 "id": 250918540,
2133 "is_bot": false,
2134 "first_name": "Андрей",
2135 "last_name": "Власов",
2136 "username": "aka_dude",
2137 "language_code": "en"
2138 },
2139 "chat": {
2140 "id": 250918540,
2141 "first_name": "Андрей",
2142 "last_name": "Власов",
2143 "username": "aka_dude",
2144 "type": "private"
2145 },
2146 "date": 1567927221,
2147 "video": {
2148 "duration": 13,
2149 "width": 512,
2150 "height": 640,
2151 "mime_type": "video/mp4",
2152 "thumbnail": {
2153 "file_id": "AAQCAAOmBAACBf2oS53pByA-I4CWWCObDwAEAQAHbQADMWcAAhYE",
2154 "file_unique_id":"",
2155 "file_size": 10339,
2156 "width": 256,
2157 "height": 320
2158 },
2159 "file_id": "BAADAgADpgQAAgX9qEud6QcgPiOAlhYE",
2160 "file_unique_id":"",
2161 "file_size": 1381334
2162 }
2163 }"#;
2164 let message = from_str::<Message>(json);
2165 assert!(message.is_ok());
2166 }
2167
2168 #[test]
2169 fn de_shared_chat() {
2170 let json = r#"{
2171 "message_id": 198283,
2172 "chat": {
2173 "id": 250918540,
2174 "first_name": "Андрей",
2175 "last_name": "Власов",
2176 "username": "aka_dude",
2177 "type": "private"
2178 },
2179 "date": 1567927221,
2180 "chat_shared": {
2181 "request_id": 348349,
2182 "chat_id": 384939
2183 }
2184 }"#;
2185 let message = from_str::<Message>(json);
2186 assert!(message.is_ok());
2187 assert_eq!(
2188 message.unwrap(),
2189 Message {
2190 id: MessageId(198283),
2191 thread_id: None,
2192 from: None,
2193 sender_chat: None,
2194 date: chrono::DateTime::from_timestamp(1567927221, 0).unwrap(),
2195 is_topic_message: false,
2196 chat: Chat {
2197 id: ChatId(250918540),
2198 kind: ChatKind::Private(ChatPrivate {
2199 first_name: Some("Андрей".to_string()),
2200 last_name: Some("Власов".to_string()),
2201 username: Some("aka_dude".to_string()),
2202 }),
2203 },
2204 sender_business_bot: None,
2205 kind: MessageKind::ChatShared(MessageChatShared {
2206 chat_shared: ChatShared {
2207 request_id: RequestId(348349),
2208 chat_id: ChatId(384939),
2209 title: None,
2210 username: None,
2211 photo: None,
2212 }
2213 }),
2214 via_bot: None
2215 }
2216 );
2217 }
2218
2219 #[test]
2220 fn de_media_group_forwarded() {
2221 let json = r#"{
2222 "message_id": 198283,
2223 "from": {
2224 "id": 250918540,
2225 "is_bot": false,
2226 "first_name": "Андрей",
2227 "last_name": "Власов",
2228 "username": "aka_dude",
2229 "language_code": "en"
2230 },
2231 "chat": {
2232 "id": 250918540,
2233 "first_name": "Андрей",
2234 "last_name": "Власов",
2235 "username": "aka_dude",
2236 "type": "private"
2237 },
2238 "date": 1567927221,
2239 "media_group_id": "12543417770506682",
2240 "video": {
2241 "duration": 13,
2242 "width": 512,
2243 "height": 640,
2244 "mime_type": "video/mp4",
2245 "thumbnail": {
2246 "file_id": "AAQCAAOmBAACBf2oS53pByA-I4CWWCObDwAEAQAHbQADMWcAAhYE",
2247 "file_unique_id":"",
2248 "file_size": 10339,
2249 "width": 256,
2250 "height": 320
2251 },
2252 "file_id": "BAADAgADpgQAAgX9qEud6QcgPiOAlhYE",
2253 "file_unique_id":"",
2254 "file_size": 1381334
2255 }
2256 }"#;
2257 let message = from_str::<Message>(json);
2258 assert!(message.is_ok());
2259 }
2260
2261 #[test]
2262 fn de_text() {
2263 let json = r#"{
2264 "message_id": 199785,
2265 "from": {
2266 "id": 250918540,
2267 "is_bot": false,
2268 "first_name": "Андрей",
2269 "last_name": "Власов",
2270 "username": "aka_dude",
2271 "language_code": "en"
2272 },
2273 "chat": {
2274 "id": 250918540,
2275 "first_name": "Андрей",
2276 "last_name": "Власов",
2277 "username": "aka_dude",
2278 "type": "private"
2279 },
2280 "date": 1568289890,
2281 "text": "Лол кек 😂"
2282 }"#;
2283 let message = from_str::<Message>(json);
2284 assert!(message.is_ok());
2285 }
2286
2287 #[test]
2288 fn de_sticker() {
2289 let json = r#"{
2290 "message_id": 199787,
2291 "from": {
2292 "id": 250918540,
2293 "is_bot": false,
2294 "first_name": "Андрей",
2295 "last_name": "Власов",
2296 "username": "aka_dude",
2297 "language_code": "en"
2298 },
2299 "chat": {
2300 "id": 250918540,
2301 "first_name": "Андрей",
2302 "last_name": "Власов",
2303 "username": "aka_dude",
2304 "type": "private"
2305 },
2306 "date": 1568290188,
2307 "sticker": {
2308 "width": 512,
2309 "height": 512,
2310 "emoji": "😡",
2311 "set_name": "AdvenTimeAnim",
2312 "is_animated": true,
2313 "is_video": false,
2314 "type": "regular",
2315 "thumbnail": {
2316 "file_id": "AAMCAgADGQEAARIt0GMwiZ6n4nRbxdpM3pL8vPX6PVAhAAIjAAOw0PgMaabKAcaXKCABAAdtAAMpBA",
2317 "file_unique_id": "AQADIwADsND4DHI",
2318 "file_size": 4118,
2319 "width": 128,
2320 "height": 128
2321 },
2322 "file_id": "CAACAgIAAxkBAAESLdBjMImep-J0W8XaTN6S_Lz1-j1QIQACIwADsND4DGmmygHGlyggKQQ",
2323 "file_unique_id": "AgADIwADsND4DA",
2324 "file_size": 16639
2325 }
2326 }"#;
2327 from_str::<Message>(json).unwrap();
2328 }
2329
2330 #[test]
2331 fn de_image() {
2332 let json = r#"{
2333 "message_id": 199791,
2334 "from": {
2335 "id": 250918540,
2336 "is_bot": false,
2337 "first_name": "Андрей",
2338 "last_name": "Власов",
2339 "username": "aka_dude",
2340 "language_code": "en"
2341 },
2342 "chat": {
2343 "id": 250918540,
2344 "first_name": "Андрей",
2345 "last_name": "Власов",
2346 "username": "aka_dude",
2347 "type": "private"
2348 },
2349 "date": 1568290622,
2350 "photo": [
2351 {
2352 "file_id": "AgADAgAD36sxG-PX0UvQSXIn9rccdw-ACA4ABAEAAwIAA20AAybcBAABFgQ",
2353 "file_unique_id":"",
2354 "file_size": 18188,
2355 "width": 320,
2356 "height": 239
2357 },
2358 {
2359 "file_id": "AgADAgAD36sxG-PX0UvQSXIn9rccdw-ACA4ABAEAAwIAA3gAAyfcBAABFgQ",
2360 "file_unique_id":"",
2361 "file_size": 62123,
2362 "width": 800,
2363 "height": 598
2364 },
2365 {
2366 "file_id": "AgADAgAD36sxG-PX0UvQSXIn9rccdw-ACA4ABAEAAwIAA3kAAyTcBAABFgQ",
2367 "file_unique_id":"",
2368 "file_size": 75245,
2369 "width": 962,
2370 "height": 719
2371 }
2372 ]
2373 }"#;
2374 let message = from_str::<Message>(json);
2375 assert!(message.is_ok());
2376 }
2377
2378 #[test]
2380 fn issue_419() {
2381 let json = r#"{
2382 "message_id": 1,
2383 "from": {
2384 "id": 1087968824,
2385 "is_bot": true,
2386 "first_name": "Group",
2387 "username": "GroupAnonymousBot"
2388 },
2389 "author_signature": "TITLE2",
2390 "sender_chat": {
2391 "id": -1001160242915,
2392 "title": "a",
2393 "type": "supergroup"
2394 },
2395 "chat": {
2396 "id": -1001160242915,
2397 "title": "a",
2398 "type": "supergroup"
2399 },
2400 "forward_origin": {
2401 "type": "chat",
2402 "date": 1640359544,
2403 "sender_chat": {
2404 "id": -1001160242915,
2405 "title": "a",
2406 "type": "supergroup"
2407 },
2408 "author_signature": "TITLE"
2409 },
2410 "date": 1640359576,
2411 "text": "text"
2412 }"#;
2413
2414 let message: Message = serde_json::from_str(json).unwrap();
2418
2419 let group = Chat {
2420 id: ChatId(-1001160242915),
2421 kind: ChatKind::Public(ChatPublic {
2422 title: Some("a".to_owned()),
2423 kind: PublicChatKind::Supergroup(PublicChatSupergroup {
2424 username: None,
2425 is_forum: false,
2426 }),
2427 }),
2428 };
2429
2430 assert!(message.from.as_ref().unwrap().is_anonymous());
2431 assert_eq!(message.author_signature().unwrap(), "TITLE2");
2432 assert_eq!(message.sender_chat.as_ref().unwrap(), &group);
2433 assert_eq!(&message.chat, &group);
2434 assert_eq!(message.forward_from_chat().unwrap(), &group);
2435 assert_eq!(message.forward_author_signature().unwrap(), "TITLE");
2436 assert!(message.forward_date().is_some());
2437 assert_eq!(message.text().unwrap(), "text");
2438 }
2439
2440 #[test]
2442 fn issue_427() {
2443 let old = ChatId(-599075523);
2444 let new = ChatId(-1001555296434);
2445
2446 let json = r#"{"chat":{"all_members_are_administrators":false,"id":-599075523,"title":"test","type":"group"},"date":1629404938,"from":{"first_name":"nullptr","id":729497414,"is_bot":false,"language_code":"en","username":"hex0x0000"},"message_id":16,"migrate_to_chat_id":-1001555296434}"#;
2448 let message: Message = from_str(json).unwrap();
2449
2450 assert_eq!(message.chat.id, old);
2451 assert_eq!(message.chat_migration(), Some(&ChatMigration::To { chat_id: new }));
2452 assert_eq!(message.migrate_to_chat_id(), Some(&new));
2453
2454 assert!(message.from.is_some());
2456
2457 let json = r#"{"chat":{"id":-1001555296434,"title":"test","type":"supergroup"},"date":1629404938,"from":{"first_name":"Group","id":1087968824,"is_bot":true,"username":"GroupAnonymousBot"},"message_id":1,"migrate_from_chat_id":-599075523,"sender_chat":{"id":-1001555296434,"title":"test","type":"supergroup"}}"#;
2459 let message: Message = from_str(json).unwrap();
2460
2461 assert_eq!(message.chat.id, new);
2462 assert_eq!(message.chat_migration(), Some(&ChatMigration::From { chat_id: old }));
2463 assert_eq!(message.migrate_from_chat_id(), Some(&old));
2464
2465 assert!(message.from.is_some());
2467
2468 assert!(message.sender_chat.is_some());
2470 }
2471
2472 #[test]
2474 fn issue_481() {
2475 let json = r#"
2476{
2477 "message_id": 0,
2478 "date": 0,
2479 "location": {
2480 "latitude": 0.0,
2481 "longitude": 0.0
2482 },
2483 "chat": {
2484 "id": 0,
2485 "first_name": "f",
2486 "type": "private"
2487 },
2488 "venue": {
2489 "location": {
2490 "latitude": 0.0,
2491 "longitude": 0.0,
2492 "live_period": 900
2493 },
2494 "title": "Title",
2495 "address": "Address",
2496 "foursquare_id": "some_foursquare_id"
2497 }
2498 }
2499"#;
2500 let message: Message = from_str(json).unwrap();
2501 assert_eq!(
2502 message.venue().unwrap(),
2503 &Venue {
2504 location: Location {
2505 longitude: 0.0,
2506 latitude: 0.0,
2507 horizontal_accuracy: None,
2508 live_period: Some(900.into()),
2509 heading: None,
2510 proximity_alert_radius: None
2511 },
2512 title: "Title".to_owned(),
2513 address: "Address".to_owned(),
2514 foursquare_id: Some("some_foursquare_id".to_owned()),
2515 foursquare_type: None,
2516 google_place_id: None,
2517 google_place_type: None,
2518 }
2519 )
2520 }
2521
2522 #[test]
2524 fn issue_475() {
2525 let json = r#"{"message_id":198295,"from":{"id":1087968824,"is_bot":true,"first_name":"Group","username":"GroupAnonymousBot"},"sender_chat":{"id":-1001331354980,"title":"C++ Together 2.0","username":"cpptogether","type":"supergroup"},"chat":{"id":-1001331354980,"title":"C++ Together 2.0","username":"cpptogether","type":"supergroup"},"date":1638236631,"video_chat_started":{}}"#;
2526
2527 let message: Message = serde_json::from_str(json).unwrap();
2528
2529 assert!(matches!(message.kind, MessageKind::VideoChatStarted { .. }));
2530
2531 }
2535
2536 #[test]
2537 fn parse_caption_entities() {
2538 let json = r#"
2539 {
2540 "message_id": 3460,
2541 "from": {
2542 "id": 27433968,
2543 "is_bot": false,
2544 "first_name": "Crax | rats addict",
2545 "username": "tacocrasco",
2546 "language_code": "en"
2547 },
2548 "chat": {
2549 "id": 27433968,
2550 "first_name": "Crax | rats addict",
2551 "username": "tacocrasco",
2552 "type": "private"
2553 },
2554 "date": 1655671349,
2555 "photo": [
2556 {
2557 "file_id": "AgACAgQAAxkBAAINhGKvijUVSn2i3980bQIIc1fqWGNCAAJpvDEbEmaBUfuA43fR-BnlAQADAgADcwADJAQ",
2558 "file_unique_id": "AQADabwxGxJmgVF4",
2559 "file_size": 2077,
2560 "width": 90,
2561 "height": 90
2562 },
2563 {
2564 "file_id": "AgACAgQAAxkBAAINhGKvijUVSn2i3980bQIIc1fqWGNCAAJpvDEbEmaBUfuA43fR-BnlAQADAgADbQADJAQ",
2565 "file_unique_id": "AQADabwxGxJmgVFy",
2566 "file_size": 27640,
2567 "width": 320,
2568 "height": 320
2569 },
2570 {
2571 "file_id": "AgACAgQAAxkBAAINhGKvijUVSn2i3980bQIIc1fqWGNCAAJpvDEbEmaBUfuA43fR-BnlAQADAgADeAADJAQ",
2572 "file_unique_id": "AQADabwxGxJmgVF9",
2573 "file_size": 99248,
2574 "width": 800,
2575 "height": 800
2576 },
2577 {
2578 "file_id": "AgACAgQAAxkBAAINhGKvijUVSn2i3980bQIIc1fqWGNCAAJpvDEbEmaBUfuA43fR-BnlAQADAgADeQADJAQ",
2579 "file_unique_id": "AQADabwxGxJmgVF-",
2580 "file_size": 162061,
2581 "width": 1280,
2582 "height": 1280
2583 }
2584 ],
2585 "caption": "www.example.com",
2586 "caption_entities": [
2587 {
2588 "offset": 0,
2589 "length": 15,
2590 "type": "url"
2591 }
2592 ]
2593 }"#;
2594
2595 let message: Message = serde_json::from_str(json).unwrap();
2596 let entities = message.parse_caption_entities();
2597 assert!(entities.is_some());
2598
2599 let entities = entities.unwrap();
2600 assert!(!entities.is_empty());
2601 assert_eq!(entities[0].kind().clone(), MessageEntityKind::Url);
2602 }
2603
2604 #[test]
2605 fn topic_created() {
2606 let json = r#"{
2607 "chat":{"id":-1001847508954,"is_forum":true,"title":"twest","type":"supergroup"},
2608 "date":1675229139,
2609 "forum_topic_created":{
2610 "icon_color":9367192,
2611 "icon_custom_emoji_id":"5312536423851630001",
2612 "name":"???"
2613 },
2614 "from":{
2615 "first_name":"вафель'",
2616 "id":1253681278,
2617 "is_bot":false,
2618 "language_code":"en",
2619 "username":"wafflelapkin"
2620 },
2621 "is_topic_message":true,
2622 "message_id":4,
2623 "message_thread_id":4
2624 }"#;
2625
2626 let message: Message = serde_json::from_str(json).unwrap();
2627 assert!(message.from.is_some());
2629 }
2630
2631 #[test]
2632 fn topic_message() {
2633 let json = r#"{"chat":{"id":-1001847508954,"is_forum":true,"title":"twest","type":"supergroup"},"date":1675229140,"from":{"first_name":"вафель'","id":1253681278,"is_bot":false,"language_code":"en","username":"wafflelapkin"},"is_topic_message":true,"message_id":5,"message_thread_id":4,"reply_to_message":{"chat":{"id":-1001847508954,"is_forum":true,"title":"twest","type":"supergroup"},"date":1675229139,"forum_topic_created":{"icon_color":9367192,"icon_custom_emoji_id":"5312536423851630001","name":"???"},"from":{"first_name":"вафель'","id":1253681278,"is_bot":false,"language_code":"en","username":"wafflelapkin"},"is_topic_message":true,"message_id":4,"message_thread_id":4},"text":"blah"}"#;
2634
2635 let _: Message = serde_json::from_str(json).unwrap();
2636 }
2637
2638 #[test]
2640 fn empty_message() {
2641 let json = r#"{"chat": {"first_name": "FN", "id": 1234567890, "type": "private"}, "date": 0, "message_id": 875400}"#;
2642
2643 let msg: Message = serde_json::from_str(json).unwrap();
2644 assert_matches!(msg.kind, MessageKind::Empty {})
2645 }
2646
2647 #[test]
2648 fn issue_874() {
2649 let json = r#"{
2650 "chat": {
2651 "id": -1001840751935,
2652 "is_forum": true,
2653 "title": "AI",
2654 "type": "supergroup"
2655 },
2656 "date": 1682191229,
2657 "forum_topic_closed": {},
2658 "from": {
2659 "first_name": "Владислав",
2660 "id": 112455916,
2661 "is_bot": false,
2662 "language_code": "en",
2663 "username": "scv977"
2664 },
2665 "message_id": 62
2666 }"#;
2667
2668 let _: Message = serde_json::from_str(json).unwrap();
2669 }
2670
2671 #[test]
2672 fn giveaway() {
2673 let json = r#"{
2674 "message_id": 27,
2675 "sender_chat": {
2676 "id": -1002236736395,
2677 "title": "Test",
2678 "type": "channel"
2679 },
2680 "chat": {
2681 "id": -1002236736395,
2682 "title": "Test",
2683 "type": "channel"
2684 },
2685 "date": 1721162577,
2686 "giveaway": {
2687 "chats": [
2688 {
2689 "id": -1002236736395,
2690 "title": "Test",
2691 "type": "channel"
2692 }
2693 ],
2694 "winners_selection_date": 1721162701,
2695 "winner_count": 1,
2696 "has_public_winners": true,
2697 "premium_subscription_month_count": 6
2698 }
2699 }"#;
2700 let message: Message = from_str(json).unwrap();
2701 assert_eq!(
2702 message.giveaway().unwrap(),
2703 &Giveaway {
2704 chats: vec![Chat {
2705 id: ChatId(-1002236736395),
2706 kind: ChatKind::Public(ChatPublic {
2707 title: Some("Test".to_owned()),
2708 kind: PublicChatKind::Channel(PublicChatChannel { username: None }),
2709 }),
2710 }],
2711 winners_selection_date: DateTime::from_timestamp(1721162701, 0).unwrap(),
2712 winner_count: 1,
2713 only_new_members: false,
2714 has_public_winners: true,
2715 prize_description: None,
2716 country_codes: None,
2717 prize_star_count: None,
2718 premium_subscription_month_count: Some(6)
2719 }
2720 )
2721 }
2722
2723 #[test]
2724 fn giveaway_created() {
2725 let json = r#"{
2726 "message_id": 27,
2727 "sender_chat": {
2728 "id": -1002236736395,
2729 "title": "Test",
2730 "type": "channel"
2731 },
2732 "chat": {
2733 "id": -1002236736395,
2734 "title": "Test",
2735 "type": "channel"
2736 },
2737 "date": 1721162577,
2738 "giveaway_created": {}
2739 }"#;
2740 let message: Message = from_str(json).unwrap();
2741 assert_eq!(message.giveaway_created().unwrap(), &GiveawayCreated { prize_star_count: None })
2742 }
2743
2744 #[test]
2745 fn giveaway_completed() {
2746 let json = r#"{
2747 "message_id": 27,
2748 "sender_chat": {
2749 "id": -1002236736395,
2750 "title": "Test",
2751 "type": "channel"
2752 },
2753 "chat": {
2754 "id": -1002236736395,
2755 "title": "Test",
2756 "type": "channel"
2757 },
2758 "date": 1721162577,
2759 "giveaway_completed": {
2760 "winner_count": 0,
2761 "unclaimed_prize_count": 1,
2762 "giveaway_message": {
2763 "message_id": 24,
2764 "sender_chat": {
2765 "id": -1002236736395,
2766 "title": "Test",
2767 "type": "channel"
2768 },
2769 "chat": {
2770 "id": -1002236736395,
2771 "title": "Test",
2772 "type": "channel"
2773 },
2774 "date": 1721161230,
2775 "giveaway": {
2776 "chats": [
2777 {
2778 "id": -1002236736395,
2779 "title": "Test",
2780 "type": "channel"
2781 }
2782 ],
2783 "winners_selection_date": 1721162701,
2784 "winner_count": 1,
2785 "has_public_winners": true,
2786 "premium_subscription_month_count": 6
2787 }
2788 }
2789 }
2790 }"#;
2791 let message: Message = from_str(json).unwrap();
2792 assert_eq!(
2793 message.giveaway_completed().unwrap(),
2794 &GiveawayCompleted {
2795 winner_count: 0,
2796 unclaimed_prize_count: Some(1),
2797 giveaway_message: Some(Box::new(Message {
2798 id: MessageId(24),
2799 thread_id: None,
2800 from: None,
2801 sender_chat: Some(Chat {
2802 id: ChatId(-1002236736395),
2803 kind: ChatKind::Public(ChatPublic {
2804 title: Some("Test".to_owned()),
2805 kind: PublicChatKind::Channel(PublicChatChannel { username: None }),
2806 }),
2807 }),
2808 is_topic_message: false,
2809 date: DateTime::from_timestamp(1721161230, 0).unwrap(),
2810 chat: Chat {
2811 id: ChatId(-1002236736395),
2812 kind: ChatKind::Public(ChatPublic {
2813 title: Some("Test".to_owned()),
2814 kind: PublicChatKind::Channel(PublicChatChannel { username: None }),
2815 }),
2816 },
2817 via_bot: None,
2818 sender_business_bot: None,
2819 kind: MessageKind::Giveaway(MessageGiveaway {
2820 giveaway: Giveaway {
2821 chats: vec![Chat {
2822 id: ChatId(-1002236736395),
2823 kind: ChatKind::Public(ChatPublic {
2824 title: Some("Test".to_owned()),
2825 kind: PublicChatKind::Channel(PublicChatChannel {
2826 username: None,
2827 }),
2828 }),
2829 }],
2830 winners_selection_date: DateTime::from_timestamp(1721162701, 0)
2831 .unwrap(),
2832 winner_count: 1,
2833 only_new_members: false,
2834 has_public_winners: true,
2835 prize_description: None,
2836 country_codes: None,
2837 prize_star_count: None,
2838 premium_subscription_month_count: Some(6)
2839 }
2840 })
2841 })),
2842 is_star_giveaway: false,
2843 }
2844 )
2845 }
2846
2847 #[test]
2848 fn giveaway_winners() {
2849 let json = r#"{
2850 "message_id": 28,
2851 "sender_chat": {
2852 "id": -1002236736395,
2853 "title": "Test",
2854 "type": "channel"
2855 },
2856 "chat": {
2857 "id": -1002236736395,
2858 "title": "Test",
2859 "type": "channel"
2860 },
2861 "date": 1721162702,
2862 "reply_to_message": {
2863 "message_id": 27,
2864 "sender_chat": {
2865 "id": -1002236736395,
2866 "title": "Test",
2867 "type": "channel"
2868 },
2869 "chat": {
2870 "id": -1002236736395,
2871 "title": "Test",
2872 "type": "channel"
2873 },
2874 "date": 1721162577,
2875 "giveaway": {
2876 "chats": [
2877 {
2878 "id": -1002236736395,
2879 "title": "Test",
2880 "type": "channel"
2881 }
2882 ],
2883 "winners_selection_date": 1721162701,
2884 "winner_count": 1,
2885 "has_public_winners": true,
2886 "premium_subscription_month_count": 6
2887 }
2888 },
2889 "giveaway_winners": {
2890 "chat": {
2891 "id": -1002236736395,
2892 "title": "Test",
2893 "type": "channel"
2894 },
2895 "giveaway_message_id": 27,
2896 "winners_selection_date": 1721162701,
2897 "premium_subscription_month_count": 6,
2898 "winner_count": 1,
2899 "winners": [
2900 {
2901 "id": 1459074222,
2902 "is_bot": false,
2903 "first_name": "shadowchain",
2904 "username": "shdwchn10"
2905 }
2906 ]
2907 }
2908 }"#;
2909 let message: Message = from_str(json).unwrap();
2910 assert_eq!(
2911 message.giveaway_winners().expect("Failed to get GiveawayWinners from Message!"),
2912 &GiveawayWinners {
2913 chat: Chat {
2914 id: ChatId(-1002236736395),
2915 kind: ChatKind::Public(ChatPublic {
2916 title: Some("Test".to_owned()),
2917 kind: PublicChatKind::Channel(PublicChatChannel { username: None }),
2918 }),
2919 },
2920 giveaway_message_id: MessageId(27),
2921 winners_selection_date: DateTime::from_timestamp(1721162701, 0).unwrap(),
2922 winner_count: 1,
2923 winners: vec![User {
2924 id: UserId(1459074222),
2925 is_bot: false,
2926 first_name: "shadowchain".to_owned(),
2927 last_name: None,
2928 username: Some("shdwchn10".to_owned()),
2929 language_code: None,
2930 is_premium: false,
2931 added_to_attachment_menu: false
2932 }],
2933 additional_chat_count: None,
2934 premium_subscription_month_count: Some(6),
2935 unclaimed_prize_count: None,
2936 only_new_members: false,
2937 was_refunded: false,
2938 prize_star_count: None,
2939 prize_description: None
2940 }
2941 )
2942 }
2943
2944 #[test]
2945 fn paid_message_price_changed() {
2946 let json = r#"{
2947 "message_id": 27,
2948 "sender_chat": {
2949 "id": -1002236736395,
2950 "title": "Test",
2951 "type": "channel"
2952 },
2953 "chat": {
2954 "id": -1002236736395,
2955 "title": "Test",
2956 "type": "channel"
2957 },
2958 "date": 1721162577,
2959 "paid_message_price_changed": {"paid_message_star_count": 1234}
2960 }"#;
2961 let message: Message = from_str(json).unwrap();
2962 assert_eq!(
2963 message.paid_message_price_changed().unwrap(),
2964 &PaidMessagePriceChanged { paid_message_star_count: 1234 }
2965 )
2966 }
2967
2968 #[test]
2969 fn gift_info() {
2970 let json = r#"{
2971 "message_id": 27,
2972 "sender_chat": {
2973 "id": -1002236736395,
2974 "title": "Test",
2975 "type": "channel"
2976 },
2977 "chat": {
2978 "id": -1002236736395,
2979 "title": "Test",
2980 "type": "channel"
2981 },
2982 "date": 1721162577,
2983 "gift": {
2984 "gift": {
2985 "id": "1234",
2986 "sticker": {
2987 "width": 512,
2988 "height": 512,
2989 "emoji": "😡",
2990 "set_name": "AdvenTimeAnim",
2991 "is_animated": true,
2992 "is_video": false,
2993 "type": "regular",
2994 "thumbnail": {
2995 "file_id": "AAMCAgADGQEAARIt0GMwiZ6n4nRbxdpM3pL8vPX6PVAhAAIjAAOw0PgMaabKAcaXKCABAAdtAAMpBA",
2996 "file_unique_id": "AQADIwADsND4DHI",
2997 "file_size": 4118,
2998 "width": 128,
2999 "height": 128
3000 },
3001 "file_id": "CAACAgIAAxkBAAESLdBjMImep-J0W8XaTN6S_Lz1-j1QIQACIwADsND4DGmmygHGlyggKQQ",
3002 "file_unique_id": "AgADIwADsND4DA",
3003 "file_size": 16639
3004 },
3005 "star_count": 10
3006 }
3007 }
3008 }"#;
3009 let message: Message = from_str(json).unwrap();
3010 assert_eq!(message.gift_info().unwrap().gift.id, "1234".into())
3011 }
3012
3013 #[test]
3014 fn unique_gift_info() {
3015 let json = r#"{
3016 "message_id": 27,
3017 "sender_chat": {
3018 "id": -1002236736395,
3019 "title": "Test",
3020 "type": "channel"
3021 },
3022 "chat": {
3023 "id": -1002236736395,
3024 "title": "Test",
3025 "type": "channel"
3026 },
3027 "date": 1721162577,
3028 "unique_gift": {
3029 "gift": {
3030 "base_name": "name",
3031 "name": "name",
3032 "number": 123,
3033 "model": {
3034 "name": "name",
3035 "sticker": {
3036 "file_id": "CAACAgIAAxUAAWMwcTidRlq7bai-xUkcHQLa6vgJAALZBwACwRieC1FFIeQlHsPdKQQ",
3037 "file_unique_id": "AgAD2QcAAsEYngs",
3038 "file_size": 25734,
3039 "width": 463,
3040 "height": 512,
3041 "type": "regular",
3042 "premium_animation": null,
3043 "is_animated": false,
3044 "is_video": false,
3045 "needs_repainting": false
3046 },
3047 "rarity_per_mille": 123
3048 },
3049 "symbol": {
3050 "name": "name",
3051 "sticker": {
3052 "file_id": "CAACAgIAAxUAAWMwcTidRlq7bai-xUkcHQLa6vgJAALZBwACwRieC1FFIeQlHsPdKQQ",
3053 "file_unique_id": "AgAD2QcAAsEYngs",
3054 "file_size": 25734,
3055 "width": 463,
3056 "height": 512,
3057 "type": "regular",
3058 "premium_animation": null,
3059 "is_animated": false,
3060 "is_video": false,
3061 "needs_repainting": false
3062 },
3063 "rarity_per_mille": 123
3064 },
3065 "backdrop": {
3066 "name": "name",
3067 "colors": {
3068 "center_color": 0,
3069 "edge_color": 0,
3070 "symbol_color": 0,
3071 "text_color": 0
3072 },
3073 "rarity_per_mille": 123
3074 }
3075 },
3076 "origin": "resale"
3077 }
3078 }"#;
3079 let message: Message = from_str(json).unwrap();
3080 assert_eq!(message.unique_gift_info().unwrap().origin, UniqueGiftOrigin::Resale);
3081 assert_eq!(message.unique_gift_info().unwrap().gift.name, "name");
3082 assert_eq!(message.unique_gift_info().unwrap().gift.backdrop.rarity_per_mille, 123);
3083 }
3084
3085 #[test]
3086 fn chat_boost_added() {
3087 let json = r#"{
3088 "message_id": 28,
3089 "sender_chat": {
3090 "id": -1002236736395,
3091 "title": "Test",
3092 "type": "channel"
3093 },
3094 "chat": {
3095 "id": -1002236736395,
3096 "title": "Test",
3097 "type": "channel"
3098 },
3099 "date": 1721162702,
3100 "boost_added": {
3101 "boost_count": 4
3102 }
3103 }"#;
3104 let message: Message = from_str(json).unwrap();
3105 assert_eq!(
3106 message.boost_added().expect("Failed to get ChatBoostAdded from Message!"),
3107 &ChatBoostAdded { boost_count: 4 }
3108 )
3109 }
3110
3111 #[test]
3112 fn effect_id() {
3113 let json = r#"{
3114 "message_id": 139,
3115 "from": {
3116 "id": 1459074222,
3117 "is_bot": false,
3118 "first_name": "shadowchain",
3119 "username": "shdwchn10",
3120 "language_code": "en",
3121 "is_premium": true
3122 },
3123 "chat": {
3124 "id": 1459074222,
3125 "first_name": "shadowchain",
3126 "username": "shdwchn10",
3127 "type": "private"
3128 },
3129 "date": 1739038521,
3130 "text": "El Psy Kongroo",
3131 "effect_id": "5123233223429587601"
3132 }"#;
3133 let message: Message = from_str(json).unwrap();
3134 assert_eq!(message.effect_id().unwrap().to_string(), "5123233223429587601")
3135 }
3136
3137 #[test]
3138 fn show_caption_above_media() {
3139 let json = r#"{
3140 "message_id": 140,
3141 "from": {
3142 "id": 1459074222,
3143 "is_bot": false,
3144 "first_name": "shadowchain",
3145 "username": "shdwchn10",
3146 "language_code": "en",
3147 "is_premium": true
3148 },
3149 "chat": {
3150 "id": 1459074222,
3151 "first_name": "shadowchain",
3152 "username": "shdwchn10",
3153 "type": "private"
3154 },
3155 "date": 1739041615,
3156 "photo": [
3157 {
3158 "file_id": "AgACAgIAAxkBAAOMZ6erTx2-IA9WEXr4NkeUY5AjdvQAArTxMRtfc0FJ1gKSaUEGAfMBAAMCAANzAAM2BA",
3159 "file_unique_id": "AQADtPExG19zQUl4",
3160 "file_size": 322,
3161 "width": 59,
3162 "height": 90
3163 },
3164 {
3165 "file_id": "AgACAgIAAxkBAAOMZ6erTx2-IA9WEXr4NkeUY5AjdvQAArTxMRtfc0FJ1gKSaUEGAfMBAAMCAANtAAM2BA",
3166 "file_unique_id": "AQADtPExG19zQUly",
3167 "file_size": 358,
3168 "width": 82,
3169 "height": 125
3170 }
3171 ],
3172 "caption": "El Psy Kongroo",
3173 "show_caption_above_media": true
3174 }"#;
3175 let message: Message = from_str(json).unwrap();
3176 assert!(message.show_caption_above_media())
3177 }
3178}