telexide_fork/model/
message.rs

1use chrono::{DateTime, Utc};
2use serde::{Deserialize, Deserializer, Serialize, Serializer};
3
4use super::{
5    message_contents::*, message_entity::*, raw::*, Game, InlineKeyboardMarkup, Invoice,
6    PassportData, Sticker, SuccessfulPayment, User,
7};
8
9/// This object represents a message.
10#[derive(Debug, Clone, PartialEq)]
11pub struct Message {
12    /// Unique message identifier inside this chat
13    pub message_id: i64,
14    /// Sender, empty for messages sent to channels
15    pub from: Option<super::User>,
16    /// Sender of the message, sent on behalf of a chat. The channel itself for
17    /// channel messages. The supergroup itself for messages from anonymous
18    /// group administrators. The linked channel for messages automatically
19    /// forwarded to the discussion group
20    pub sender_chat: Option<super::Chat>,
21    /// Date the message was sent
22    pub date: DateTime<Utc>,
23    /// Conversation the message belongs to
24    pub chat: super::Chat,
25
26    /// Data about what message it was forwarded from
27    pub forward_data: Option<ForwardData>,
28
29    pub reply_to_message: Option<Box<Message>>,
30    /// Bot through which the message was sent
31    pub via_bot: Option<User>,
32    /// Date the message was last edited in Unix time
33    pub edit_date: Option<DateTime<Utc>>,
34    /// Signature of the post author for messages in channels
35    pub author_signature: Option<String>,
36
37    /// The content of the message
38    pub content: MessageContent,
39
40    /// The domain name of the website on which the user has logged in.
41    pub connected_website: Option<String>,
42    /// Telegram Passport data
43    pub passport_data: Option<PassportData>,
44    /// Inline keyboard attached to the message. `login_url` buttons are
45    /// represented as ordinary `url` buttons.
46    pub reply_markup: Option<InlineKeyboardMarkup>,
47}
48
49/// The content of a [`Message`]
50#[allow(clippy::large_enum_variant)]
51#[derive(Debug, Clone, PartialEq)]
52pub enum MessageContent {
53    Text {
54        /// The actual UTF-8 text of the message, 0-4096 characters
55        content: String,
56        /// Special entities like usernames, URLs, bot commands, etc. that
57        /// appear in the text
58        entities: Vec<MessageEntity>,
59    },
60    Audio {
61        /// Information about the audio file
62        content: Audio,
63        /// The caption, 0-1024 characters
64        caption: Option<String>,
65        /// Special entities like usernames, URLs, bot commands, etc. that
66        /// appear in the caption
67        caption_entities: Option<Vec<MessageEntity>>,
68    },
69    Document {
70        /// Information about the file
71        content: Document,
72        /// The caption, 0-1024 characters
73        caption: Option<String>,
74        /// Special entities like usernames, URLs, bot commands, etc. that
75        /// appear in the caption
76        caption_entities: Option<Vec<MessageEntity>>,
77    },
78    Animation {
79        /// Information about the animation.
80        content: Animation,
81        /// The caption, 0-1024 characters
82        caption: Option<String>,
83        /// Special entities like usernames, URLs, bot commands, etc. that
84        /// appear in the caption
85        caption_entities: Option<Vec<MessageEntity>>,
86    },
87    Video {
88        /// Information about the video
89        content: Video,
90        /// The caption, 0-1024 characters
91        caption: Option<String>,
92        /// Special entities like usernames, URLs, bot commands, etc. that
93        /// appear in the caption
94        caption_entities: Option<Vec<MessageEntity>>,
95        /// The unique identifier of a media message group this message belongs
96        /// to
97        media_group_id: Option<String>,
98    },
99    Voice {
100        /// Information about the voice file
101        content: Voice,
102        /// The caption, 0-1024 characters
103        caption: Option<String>,
104        /// Special entities like usernames, URLs, bot commands, etc. that
105        /// appear in the caption
106        caption_entities: Option<Vec<MessageEntity>>,
107    },
108    Photo {
109        /// Available sizes of the photo
110        content: Vec<PhotoSize>,
111        /// The caption, 0-1024 characters
112        caption: Option<String>,
113        /// Special entities like usernames, URLs, bot commands, etc. that
114        /// appear in the caption
115        caption_entities: Option<Vec<MessageEntity>>,
116        /// The unique identifier of a media message group this message belongs
117        /// to
118        media_group_id: Option<String>,
119    },
120
121    Game {
122        /// Information about the game
123        content: Game,
124    },
125    Sticker {
126        /// Information about the sticker
127        content: Sticker,
128    },
129    VideoNote {
130        /// Information about the video message
131        content: VideoNote,
132    },
133    Contact {
134        /// Information about the shared contact
135        content: Contact,
136    },
137    Location {
138        /// Information about the shared location
139        content: Location,
140    },
141    Venue {
142        /// Information about the venue
143        content: Venue,
144    },
145    Poll {
146        /// Information about the native poll
147        content: Poll,
148    },
149    Dice {
150        /// a dice with a random value from 1 to 6
151        content: Dice,
152    },
153    NewChatMembers {
154        /// New members that were added to the group or supergroup and
155        /// information about them (the bot itself may be one of these
156        /// members)
157        content: Vec<User>,
158    },
159    LeftChatMember {
160        /// A member was removed from the group, information about them
161        /// (this member may be the bot itself)
162        content: User,
163    },
164    NewChatTitle {
165        /// A chat title was changed to this value
166        content: String,
167    },
168    NewChatPhoto {
169        /// A chat photo was change to this value
170        content: Vec<PhotoSize>,
171    },
172    MessageAutoDeleteTimerChanged {
173        /// Service message: auto-delete timer settings changed in the chat
174        content: MessageAutoDeleteTimerChanged,
175    },
176    MigrateToChatID {
177        /// The group has been migrated to a supergroup with the specified
178        /// identifier.
179        content: i64,
180    },
181    MigrateFromChatID {
182        /// The supergroup has been migrated from a group with the specified
183        /// identifier.
184        content: i64,
185    },
186    PinnedMessage {
187        /// Specified message was pinned. Note that the Message object in this
188        /// field will not contain further reply_to_message fields even
189        /// if it is itself a reply.
190        content: Box<Message>,
191    },
192    Invoice {
193        /// Message is an invoice for a [payment], information about the
194        /// invoice.
195        ///
196        /// [payment]: https://core.telegram.org/bots/api#payments
197        content: Invoice,
198    },
199    SuccessfulPayment {
200        /// Message is a service message about a successful payment, information
201        /// about the payment.
202        content: SuccessfulPayment,
203    },
204    ProximityAlertTriggered {
205        /// Service message. A user in the chat triggered another user's
206        /// proximity alert while sharing Live Location.
207        content: ProximityAlertTriggered,
208    },
209    VoiceChatScheduled {
210        /// Service message: voice chat scheduled
211        content: VoiceChatScheduled,
212    },
213    VoiceChatStarted {
214        /// Service message: voice chat started
215        content: VoiceChatStarted,
216    },
217    VoiceChatEnded {
218        /// Service message: voice chat ended
219        content: VoiceChatEnded,
220    },
221    VoiceChatParticipantsInvited {
222        /// Service message: new participants invited to a voice chat
223        content: VoiceChatParticipantsInvited,
224    },
225
226    /// Service message: the chat photo was deleted
227    DeleteChatPhoto,
228    /// Service message: the group has been created
229    GroupChatCreated,
230    /// Service message: the supergroup has been created.
231    /// This field can‘t be received in a message coming through updates,
232    /// because bot can’t be a member of a supergroup when it is created.
233    /// It can only be found in reply_to_message if someone replies to a very
234    /// first message in a directly created supergroup.
235    SupergroupChatCreated,
236    /// Service message: the channel has been created.
237    /// This field can‘t be received in a message coming through updates,
238    /// because bot can’t be a member of a channel when it is created.
239    /// It can only be found in reply_to_message if someone replies to the very
240    /// first message in a channel.
241    ChannelChatCreated,
242    /// Received a message with an unknown content
243    Unknown,
244}
245
246/// Holds information about the forwarded message
247#[derive(Debug, Clone, PartialEq)]
248pub struct ForwardData {
249    /// For forwarded messages, sender of the original message
250    pub from: Option<super::User>,
251    /// For messages forwarded from channels, information about the original
252    /// channel
253    pub from_chat: Option<super::Chat>,
254    /// For messages forwarded from channels, identifier of the original message
255    /// in the channel
256    pub from_message_id: Option<i64>,
257    /// For messages forwarded from channels, signature of the post author if
258    /// present
259    pub signature: Option<String>,
260    /// Sender's name for messages forwarded from users who disallow adding a
261    /// link to their account in forwarded messages
262    pub sender_name: Option<String>,
263    /// For forwarded messages, date the original message was sent in Unix time
264    pub date: DateTime<Utc>,
265}
266
267impl Message {
268    pub fn get_text(&self) -> Option<String> {
269        match self.content {
270            MessageContent::Text { ref content, .. } => Some(content.clone()),
271            MessageContent::Audio { ref caption, .. }
272            | MessageContent::Document { ref caption, .. }
273            | MessageContent::Animation { ref caption, .. }
274            | MessageContent::Video { ref caption, .. }
275            | MessageContent::Voice { ref caption, .. }
276            | MessageContent::Photo { ref caption, .. } => caption.clone(),
277            _ => None,
278        }
279    }
280}
281
282impl From<RawMessage> for Message {
283    #[allow(clippy::too_many_lines)]
284    fn from(raw: RawMessage) -> Message {
285        let message_id = raw.message_id;
286        let from = raw.from;
287        let sender_chat = raw.sender_chat.map(std::convert::Into::into);
288        let date = raw.date;
289        let chat = raw.chat.into();
290        let reply_to_message = raw.reply_to_message.map(|r| Box::new((*r).into()));
291        let via_bot = raw.via_bot;
292        let edit_date = raw.edit_date;
293        let author_signature = raw.author_signature;
294        let connected_website = raw.connected_website;
295        let passport_data = raw.passport_data;
296        let reply_markup = raw.reply_markup;
297
298        let forward_data = if let Some(d) = raw.forward_date {
299            Some(ForwardData {
300                from: raw.forward_from,
301                from_chat: raw.forward_from_chat.map(std::convert::Into::into),
302                from_message_id: raw.forward_from_message_id,
303                signature: raw.forward_signature,
304                sender_name: raw.forward_sender_name,
305                date: d,
306            })
307        } else {
308            None
309        };
310
311        let fill_in_content = |content: MessageContent| Self {
312            message_id,
313            from,
314            sender_chat,
315            date,
316            chat,
317            forward_data,
318            reply_to_message,
319            via_bot,
320            edit_date,
321            author_signature,
322            content,
323            connected_website,
324            passport_data,
325            reply_markup,
326        };
327
328        if let Some(c) = raw.text {
329            return fill_in_content(MessageContent::Text {
330                content: c,
331                entities: raw.entities.unwrap_or_default(),
332            });
333        } else if let Some(c) = raw.video {
334            return fill_in_content(MessageContent::Video {
335                content: c,
336                caption: raw.caption,
337                caption_entities: raw.caption_entities,
338                media_group_id: raw.media_group_id,
339            });
340        } else if let Some(c) = raw.photo {
341            return fill_in_content(MessageContent::Photo {
342                content: c,
343                caption: raw.caption,
344                caption_entities: raw.caption_entities,
345                media_group_id: raw.media_group_id,
346            });
347        } else if let Some(c) = raw.pinned_message {
348            return fill_in_content(MessageContent::PinnedMessage {
349                content: Box::new((*c).into()),
350            });
351        }
352
353        macro_rules! content_with_captions {
354            ($data:expr, $kind:ident) => {
355                if let Some(c) = $data {
356                    return fill_in_content(MessageContent::$kind {
357                        content: c,
358                        caption: raw.caption,
359                        caption_entities: raw.caption_entities,
360                    });
361                }
362            };
363        }
364
365        macro_rules! content {
366            ($data:expr, $kind:ident) => {
367                if let Some(c) = $data {
368                    return fill_in_content(MessageContent::$kind { content: c });
369                }
370            };
371        }
372
373        macro_rules! bool_content {
374            ($data:expr, $kind:ident) => {
375                if $data {
376                    return fill_in_content(MessageContent::$kind);
377                }
378            };
379        }
380
381        content_with_captions!(raw.audio, Audio);
382        content_with_captions!(raw.animation, Animation);
383        content_with_captions!(raw.document, Document);
384        content_with_captions!(raw.voice, Voice);
385
386        content!(raw.game, Game);
387        content!(raw.sticker, Sticker);
388        content!(raw.video_note, VideoNote);
389        content!(raw.contact, Contact);
390        content!(raw.location, Location);
391        content!(raw.venue, Venue);
392        content!(raw.poll, Poll);
393        content!(raw.dice, Dice);
394        content!(raw.new_chat_members, NewChatMembers);
395        content!(raw.left_chat_member, LeftChatMember);
396        content!(raw.new_chat_title, NewChatTitle);
397        content!(raw.new_chat_photo, NewChatPhoto);
398        content!(
399            raw.message_auto_delete_timer_changed,
400            MessageAutoDeleteTimerChanged
401        );
402        content!(raw.migrate_to_chat_id, MigrateToChatID);
403        content!(raw.migrate_from_chat_id, MigrateFromChatID);
404        content!(raw.invoice, Invoice);
405        content!(raw.successful_payment, SuccessfulPayment);
406        content!(raw.proximity_alert_triggered, ProximityAlertTriggered);
407        content!(raw.voice_chat_scheduled, VoiceChatScheduled);
408        content!(raw.voice_chat_started, VoiceChatStarted);
409        content!(raw.voice_chat_ended, VoiceChatEnded);
410        content!(
411            raw.voice_chat_participants_invited,
412            VoiceChatParticipantsInvited
413        );
414
415        bool_content!(raw.delete_chat_photo, DeleteChatPhoto);
416        bool_content!(raw.group_chat_created, GroupChatCreated);
417        bool_content!(raw.supergroup_chat_created, SupergroupChatCreated);
418        bool_content!(raw.channel_chat_created, ChannelChatCreated);
419
420        fill_in_content(MessageContent::Unknown)
421    }
422}
423
424impl From<Message> for RawMessage {
425    #[allow(clippy::too_many_lines)]
426    fn from(message: Message) -> RawMessage {
427        let mut ret = Self {
428            message_id: message.message_id,
429            from: message.from,
430            sender_chat: message.sender_chat.map(std::convert::Into::into),
431            date: message.date,
432            chat: message.chat.into(),
433            reply_to_message: message.reply_to_message.map(|r| Box::new((*r).into())),
434            via_bot: message.via_bot,
435            edit_date: message.edit_date,
436            media_group_id: None,
437            author_signature: message.author_signature,
438
439            forward_date: None,
440            forward_sender_name: None,
441            forward_signature: None,
442            forward_from_message_id: None,
443            forward_from: None,
444            forward_from_chat: None,
445
446            text: None,
447            entities: None,
448            caption_entities: None,
449            audio: None,
450            document: None,
451            animation: None,
452            game: None,
453            photo: None,
454            sticker: None,
455            video: None,
456            voice: None,
457            video_note: None,
458            caption: None,
459            contact: None,
460            location: None,
461            venue: None,
462            poll: None,
463            dice: None,
464            new_chat_members: None,
465            left_chat_member: None,
466            new_chat_title: None,
467            new_chat_photo: None,
468            delete_chat_photo: false,
469            group_chat_created: false,
470            supergroup_chat_created: false,
471            channel_chat_created: false,
472            message_auto_delete_timer_changed: None,
473            migrate_to_chat_id: None,
474            migrate_from_chat_id: None,
475            pinned_message: None,
476            invoice: None,
477            successful_payment: None,
478            proximity_alert_triggered: None,
479            voice_chat_scheduled: None,
480            voice_chat_started: None,
481            voice_chat_ended: None,
482            voice_chat_participants_invited: None,
483
484            connected_website: message.connected_website,
485            passport_data: message.passport_data,
486            reply_markup: message.reply_markup,
487        };
488
489        if let Some(d) = message.forward_data {
490            ret.forward_date = Some(d.date);
491            ret.forward_sender_name = d.sender_name;
492            ret.forward_signature = d.signature;
493            ret.forward_from_message_id = d.from_message_id;
494            ret.forward_from = d.from;
495            ret.forward_from_chat = d.from_chat.map(std::convert::Into::into);
496        }
497
498        match message.content {
499            MessageContent::Text { content, entities } => {
500                ret.text = Some(content);
501                ret.entities = Some(entities);
502                ret
503            }
504            MessageContent::Audio {
505                content,
506                caption,
507                caption_entities,
508            } => {
509                ret.audio = Some(content);
510                ret.caption = caption;
511                ret.caption_entities = caption_entities;
512                ret
513            }
514            MessageContent::Document {
515                content,
516                caption,
517                caption_entities,
518            } => {
519                ret.document = Some(content);
520                ret.caption = caption;
521                ret.caption_entities = caption_entities;
522                ret
523            }
524            MessageContent::Animation {
525                content,
526                caption,
527                caption_entities,
528            } => {
529                ret.animation = Some(content);
530                ret.caption = caption;
531                ret.caption_entities = caption_entities;
532                ret
533            }
534            MessageContent::Voice {
535                content,
536                caption,
537                caption_entities,
538            } => {
539                ret.voice = Some(content);
540                ret.caption = caption;
541                ret.caption_entities = caption_entities;
542                ret
543            }
544            MessageContent::Video {
545                content,
546                caption,
547                caption_entities,
548                media_group_id,
549            } => {
550                ret.video = Some(content);
551                ret.caption = caption;
552                ret.caption_entities = caption_entities;
553                ret.media_group_id = media_group_id;
554                ret
555            }
556            MessageContent::Photo {
557                content,
558                caption,
559                caption_entities,
560                media_group_id,
561            } => {
562                ret.photo = Some(content);
563                ret.caption = caption;
564                ret.caption_entities = caption_entities;
565                ret.media_group_id = media_group_id;
566                ret
567            }
568            MessageContent::Game { content } => {
569                ret.game = Some(content);
570                ret
571            }
572            MessageContent::Sticker { content } => {
573                ret.sticker = Some(content);
574                ret
575            }
576            MessageContent::VideoNote { content } => {
577                ret.video_note = Some(content);
578                ret
579            }
580            MessageContent::Contact { content } => {
581                ret.contact = Some(content);
582                ret
583            }
584            MessageContent::Location { content } => {
585                ret.location = Some(content);
586                ret
587            }
588            MessageContent::Venue { content } => {
589                ret.venue = Some(content);
590                ret
591            }
592            MessageContent::Poll { content } => {
593                ret.poll = Some(content);
594                ret
595            }
596            MessageContent::Dice { content } => {
597                ret.dice = Some(content);
598                ret
599            }
600            MessageContent::NewChatMembers { content } => {
601                ret.new_chat_members = Some(content);
602                ret
603            }
604            MessageContent::LeftChatMember { content } => {
605                ret.left_chat_member = Some(content);
606                ret
607            }
608            MessageContent::NewChatTitle { content } => {
609                ret.new_chat_title = Some(content);
610                ret
611            }
612            MessageContent::NewChatPhoto { content } => {
613                ret.new_chat_photo = Some(content);
614                ret
615            }
616            MessageContent::MessageAutoDeleteTimerChanged { content } => {
617                ret.message_auto_delete_timer_changed = Some(content);
618                ret
619            }
620            MessageContent::MigrateToChatID { content } => {
621                ret.migrate_to_chat_id = Some(content);
622                ret
623            }
624            MessageContent::MigrateFromChatID { content } => {
625                ret.migrate_from_chat_id = Some(content);
626                ret
627            }
628            MessageContent::Invoice { content } => {
629                ret.invoice = Some(content);
630                ret
631            }
632            MessageContent::SuccessfulPayment { content } => {
633                ret.successful_payment = Some(content);
634                ret
635            }
636            MessageContent::PinnedMessage { content } => {
637                ret.pinned_message = Some(Box::new((*content).into()));
638                ret
639            }
640            MessageContent::ProximityAlertTriggered { content } => {
641                ret.proximity_alert_triggered = Some(content);
642                ret
643            }
644            MessageContent::VoiceChatScheduled { content } => {
645                ret.voice_chat_scheduled = Some(content);
646                ret
647            }
648            MessageContent::VoiceChatStarted { content } => {
649                ret.voice_chat_started = Some(content);
650                ret
651            }
652            MessageContent::VoiceChatEnded { content } => {
653                ret.voice_chat_ended = Some(content);
654                ret
655            }
656            MessageContent::VoiceChatParticipantsInvited { content } => {
657                ret.voice_chat_participants_invited = Some(content);
658                ret
659            }
660            MessageContent::DeleteChatPhoto => {
661                ret.delete_chat_photo = true;
662                ret
663            }
664            MessageContent::GroupChatCreated => {
665                ret.group_chat_created = true;
666                ret
667            }
668            MessageContent::SupergroupChatCreated => {
669                ret.supergroup_chat_created = true;
670                ret
671            }
672            MessageContent::ChannelChatCreated => {
673                ret.channel_chat_created = true;
674                ret
675            }
676            MessageContent::Unknown => ret,
677        }
678    }
679}
680
681impl<'de> Deserialize<'de> for Message {
682    fn deserialize<D>(deserializer: D) -> Result<Message, D::Error>
683    where
684        D: Deserializer<'de>,
685    {
686        let raw: RawMessage = Deserialize::deserialize(deserializer)?;
687
688        Ok(raw.into())
689    }
690}
691
692impl Serialize for Message {
693    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
694    where
695        S: Serializer,
696    {
697        RawMessage::from(self.clone()).serialize(serializer)
698    }
699}
700
701/// This object represents a unique message identifier.
702#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
703pub struct MessageId {
704    /// Unique message identifier
705    pub message_id: i64,
706}