diff --git a/src/types/chat.rs b/src/types/chat.rs index 8f8a8cc3..0fccb5e7 100644 --- a/src/types/chat.rs +++ b/src/types/chat.rs @@ -28,54 +28,62 @@ pub struct Chat { #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] #[serde(untagged)] pub enum ChatKind { - NonPrivate { - /// A title, for supergroups, channels and group chats. - title: Option, + NonPrivate(ChatNonPrivate), + Private(ChatPrivate), +} - #[serde(flatten)] - kind: NonPrivateChatKind, +#[serde_with_macros::skip_serializing_none] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct ChatNonPrivate { + /// A title, for supergroups, channels and group chats. + pub title: Option, - /// A description, for groups, supergroups and channel chats. Returned - /// only in [`Bot::get_chat`]. - /// - /// [`Bot::get_chat`]: crate::Bot::get_chat - description: Option, + #[serde(flatten)] + pub kind: NonPrivateChatKind, - /// A chat invite link, for groups, supergroups and channel chats. Each - /// administrator in a chat generates their own invite links, so the - /// bot must first generate the link using - /// [`Bot::export_chat_invite_link`]. Returned only in - /// [`Bot::get_chat`]. - /// - /// [`Bot::export_chat_invite_link`]: - /// crate::Bot::export_chat_invite_link - /// - /// [`Bot::get_chat`]: crate::Bot::get_chat - invite_link: Option, + /// A description, for groups, supergroups and channel chats. Returned + /// only in [`Bot::get_chat`]. + /// + /// [`Bot::get_chat`]: crate::Bot::get_chat + pub description: Option, - /// Pinned message, for groups, supergroups and channels. Returned only - /// in [`Bot::get_chat`]. - /// - /// [`Bot::get_chat`]: crate::Bot::get_chat - pinned_message: Option>, - }, - Private { - /// A dummy field. Used to ensure that the `type` field is equal to - /// `private`. - #[serde(rename = "type")] - #[serde(deserialize_with = "assert_private_field")] - type_: (), + /// A chat invite link, for groups, supergroups and channel chats. Each + /// administrator in a chat generates their own invite links, so the + /// bot must first generate the link using + /// [`Bot::export_chat_invite_link`]. Returned only in + /// [`Bot::get_chat`]. + /// + /// [`Bot::export_chat_invite_link`]: + /// crate::Bot::export_chat_invite_link + /// + /// [`Bot::get_chat`]: crate::Bot::get_chat + pub invite_link: Option, - /// A username, for private chats, supergroups and channels if - /// available. - username: Option, + /// Pinned message, for groups, supergroups and channels. Returned only + /// in [`Bot::get_chat`]. + /// + /// [`Bot::get_chat`]: crate::Bot::get_chat + pub pinned_message: Option>, +} - /// A first name of the other party in a private chat. - first_name: Option, +#[serde_with_macros::skip_serializing_none] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct ChatPrivate { + /// A dummy field. Used to ensure that the `type` field is equal to + /// `private`. + #[serde(rename = "type")] + #[serde(deserialize_with = "assert_private_field")] + pub type_: (), - /// A last name of the other party in a private chat. - last_name: Option, - }, + /// A username, for private chats, supergroups and channels if + /// available. + pub username: Option, + + /// A first name of the other party in a private chat. + pub first_name: Option, + + /// A last name of the other party in a private chat. + pub last_name: Option, } #[serde_with_macros::skip_serializing_none] @@ -83,47 +91,58 @@ pub enum ChatKind { #[serde(rename_all = "snake_case")] #[serde(tag = "type")] pub enum NonPrivateChatKind { - Channel { - /// A username, for private chats, supergroups and channels if - /// available. - username: Option, - }, - Group { - /// A default chat member permissions, for groups and supergroups. - /// Returned only in [`Bot::get_chat`]. - /// - /// [`Bot::get_chat`]: crate::Bot::get_chat - permissions: Option, - }, - Supergroup { - /// A username, for private chats, supergroups and channels if - /// available. - username: Option, + Channel(NonPrivateChatChannel), + Group(NonPrivateChatGroup), + Supergroup(NonPrivateChatSupergroup), +} - /// For supergroups, name of group sticker set. Returned only in - /// [`Bot::get_chat`]. - /// - /// [`Bot::get_chat`]: crate::Bot::get_chat - sticker_set_name: Option, +#[serde_with_macros::skip_serializing_none] +#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] +pub struct NonPrivateChatChannel { + /// A username, for private chats, supergroups and channels if available. + pub username: Option, +} - /// `true`, if the bot can change the group sticker set. Returned only - /// in [`Bot::get_chat`]. - /// - /// [`Bot::get_chat`]: crate::Bot::get_chat - can_set_sticker_set: Option, +#[serde_with_macros::skip_serializing_none] +#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] +pub struct NonPrivateChatGroup { + /// A default chat member permissions, for groups and supergroups. Returned + /// only from [`Bot::get_chat`]. + /// + /// [`Bot::get_chat`]: crate::Bot::get_chat + pub permissions: Option, +} - /// A default chat member permissions, for groups and supergroups. - /// Returned only in [`Bot::get_chat`]. - /// - /// [`Bot::get_chat`]: crate::Bot::get_chat - permissions: Option, +#[serde_with_macros::skip_serializing_none] +#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] +pub struct NonPrivateChatSupergroup { + /// A username, for private chats, supergroups and channels if + /// available. + pub username: Option, - /// The minimum allowed delay between consecutive messages sent by each - /// unpriviledged user. Returned only in [`Bot::get_chat`]. - /// - /// [`Bot::get_chat`]: crate::Bot::get_chat - slow_mode_delay: Option, - }, + /// For supergroups, name of group sticker set. Returned only from + /// [`Bot::get_chat`]. + /// + /// [`Bot::get_chat`]: crate::Bot::get_chat + pub sticker_set_name: Option, + + /// `true`, if the bot can change the group sticker set. Returned only + /// from [`Bot::get_chat`]. + /// + /// [`Bot::get_chat`]: crate::Bot::get_chat + pub can_set_sticker_set: Option, + + /// A default chat member permissions, for groups and supergroups. + /// Returned only from [`Bot::get_chat`]. + /// + /// [`Bot::get_chat`]: crate::Bot::get_chat + pub permissions: Option, + + /// The minimum allowed delay between consecutive messages sent by each + /// unpriviledged user. Returned only from [`Bot::get_chat`]. + /// + /// [`Bot::get_chat`]: crate::Bot::get_chat + pub slow_mode_delay: Option, } struct PrivateChatKindVisitor; @@ -158,38 +177,36 @@ where impl Chat { pub fn is_private(&self) -> bool { - match self.kind { - ChatKind::Private { .. } => true, - _ => false, - } + matches!(self.kind, ChatKind::Private(_)) } pub fn is_group(&self) -> bool { - match self.kind { - ChatKind::NonPrivate { - kind: NonPrivateChatKind::Group { .. }, + matches!( + self.kind, + ChatKind::NonPrivate(ChatNonPrivate { + kind: NonPrivateChatKind::Group(_), .. - } => true, - _ => false, - } + }) + ) } pub fn is_supergroup(&self) -> bool { - match self.kind { - ChatKind::NonPrivate { - kind: NonPrivateChatKind::Supergroup { .. }, + matches!( + self.kind, + ChatKind::NonPrivate(ChatNonPrivate { + kind: NonPrivateChatKind::Supergroup(_), .. - } => true, - _ => false, - } + }) + ) } pub fn is_channel(&self) -> bool { - match self.kind { - ChatKind::NonPrivate { - kind: NonPrivateChatKind::Channel { .. }, + matches!( + self.kind, + ChatKind::NonPrivate(ChatNonPrivate { + kind: NonPrivateChatKind::Channel(_), .. - } => true, - _ => false, - } + }) + ) } + pub fn is_chat(&self) -> bool { self.is_private() || self.is_group() || self.is_supergroup() } @@ -205,15 +222,15 @@ mod tests { fn channel_de() { let expected = Chat { id: -1, - kind: ChatKind::NonPrivate { + kind: ChatKind::NonPrivate(ChatNonPrivate { title: None, - kind: NonPrivateChatKind::Channel { + kind: NonPrivateChatKind::Channel(NonPrivateChatChannel { username: Some("channelname".into()), - }, + }), description: None, invite_link: None, pinned_message: None, - }, + }), photo: None, }; let actual = @@ -227,12 +244,12 @@ mod tests { assert_eq!( Chat { id: 0, - kind: ChatKind::Private { + kind: ChatKind::Private(ChatPrivate { type_: (), username: Some("username".into()), first_name: Some("Anon".into()), last_name: None, - }, + }), photo: None, }, from_str( diff --git a/src/types/encrypted_passport_element.rs b/src/types/encrypted_passport_element.rs index 6b52f67b..634d9da1 100644 --- a/src/types/encrypted_passport_element.rs +++ b/src/types/encrypted_passport_element.rs @@ -19,337 +19,391 @@ pub struct EncryptedPassportElement { pub kind: EncryptedPassportElementKind, } -#[serde_with_macros::skip_serializing_none] #[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "snake_case")] -#[allow(clippy::large_enum_variant)] pub enum EncryptedPassportElementKind { - PersonalDetails { - /// Base64-encoded encrypted Telegram Passport element data provided - /// by the user, available for `personal_details`, `passport`, - /// `driver_license`, `identity_card`, `internal_passport` and - /// `address` types. Can be decrypted and verified using the - /// accompanying [`EncryptedCredentials`]. - /// - /// [`EncryptedCredentials`]: - /// crate::types::EncryptedCredentials - data: String, - }, - Passport { - /// Base64-encoded encrypted Telegram Passport element data provided - /// by the user, available for `personal_details`, `passport`, - /// `driver_license`, `identity_card`, `internal_passport` and - /// `address` types. Can be decrypted and verified using the - /// accompanying [`EncryptedCredentials`]. - /// - /// [`EncryptedCredentials`]: - /// crate::types::EncryptedCredentials - data: String, - - /// Encrypted file with the front side of the document, provided by the - /// user. Available for `passport`, `driver_license`, `identity_card` - /// and `internal_passport`. The file can be decrypted and verified - /// using the accompanying [`EncryptedCredentials`]. - /// - /// [`EncryptedCredentials`]: - /// crate::types::EncryptedCredentials - front_side: PassportFile, - - /// Encrypted file with the selfie of the user holding a document, - /// provided by the user; available for `passport`, `driver_license`, - /// `identity_card` and `internal_passport`. The file can be decrypted - /// and verified using the accompanying [`EncryptedCredentials`]. - /// - /// [`EncryptedCredentials`]: - /// crate::types::EncryptedCredentials - selfie: PassportFile, - - /// Array of encrypted files with translated versions of documents - /// provided by the user. Available if requested for `passport`, - /// `driver_license`, `identity_card`, `internal_passport`, - /// `utility_bill`, `bank_statement`, `rental_agreement`, - /// `passport_registration` and `temporary_registration` types. Files - /// can be decrypted and verified using the accompanying - /// [`EncryptedCredentials`]. - /// - /// [`EncryptedCredentials`]: - /// crate::types::EncryptedCredentials - translation: Option>, - }, - DriverLicense { - /// Base64-encoded encrypted Telegram Passport element data provided - /// by the user, available for `personal_details`, `passport`, - /// `driver_license`, `identity_card`, `internal_passport` and - /// `address` types. Can be decrypted and verified using the - /// accompanying [`EncryptedCredentials`]. - /// - /// [`EncryptedCredentials`]: - /// crate::types::EncryptedCredentials - data: String, - - /// Encrypted file with the front side of the document, provided by the - /// user. Available for `passport`, `driver_license`, `identity_card` - /// and `internal_passport`. The file can be decrypted and verified - /// using the accompanying [`EncryptedCredentials`]. - /// - /// [`EncryptedCredentials`]: - /// crate::types::EncryptedCredentials - front_side: PassportFile, - - /// Encrypted file with the reverse side of the document, provided by - /// the user. Available for `driver_license` and `identity_card`. The - /// file can be decrypted and verified using the accompanying - /// [`EncryptedCredentials`]. - /// - /// [`EncryptedCredentials`]: - /// crate::types::EncryptedCredentials - reverse_side: PassportFile, - - /// Encrypted file with the selfie of the user holding a document, - /// provided by the user; available for `passport`, `driver_license`, - /// `identity_card` and `internal_passport`. The file can be decrypted - /// and verified using the accompanying [`EncryptedCredentials`]. - /// - /// [`EncryptedCredentials`]: - /// crate::types::EncryptedCredentials - selfie: PassportFile, - - /// Array of encrypted files with translated versions of documents - /// provided by the user. Available if requested for `passport`, - /// `driver_license`, `identity_card`, `internal_passport`, - /// `utility_bill`, `bank_statement`, `rental_agreement`, - /// `passport_registration` and `temporary_registration` types. Files - /// can be decrypted and verified using the accompanying - /// [`EncryptedCredentials`]. - /// - /// [`EncryptedCredentials`]: - /// crate::types::EncryptedCredentials - translation: Option>, - }, - IdentityCard { - /// Base64-encoded encrypted Telegram Passport element data provided - /// by the user, available for `personal_details`, `passport`, - /// `driver_license`, `identity_card`, `internal_passport` and - /// `address` types. Can be decrypted and verified using the - /// accompanying [`EncryptedCredentials`]. - /// - /// [`EncryptedCredentials`]: - /// crate::types::EncryptedCredentials - data: String, - - /// Encrypted file with the front side of the document, provided by the - /// user. Available for `passport`, `driver_license`, `identity_card` - /// and `internal_passport`. The file can be decrypted and verified - /// using the accompanying [`EncryptedCredentials`]. - /// - /// [`EncryptedCredentials`]: - /// crate::types::EncryptedCredentials - front_side: PassportFile, - - /// Encrypted file with the reverse side of the document, provided by - /// the user. Available for `driver_license` and `identity_card`. The - /// file can be decrypted and verified using the accompanying - /// [`EncryptedCredentials`]. - /// - /// [`EncryptedCredentials`]: - /// crate::types::EncryptedCredentials - reverse_side: PassportFile, - - /// Encrypted file with the selfie of the user holding a document, - /// provided by the user; available for `passport`, `driver_license`, - /// `identity_card` and `internal_passport`. The file can be decrypted - /// and verified using the accompanying [`EncryptedCredentials`]. - /// - /// [`EncryptedCredentials`]: - /// crate::types::EncryptedCredentials - selfie: PassportFile, - - /// Array of encrypted files with translated versions of documents - /// provided by the user. Available if requested for `passport`, - /// `driver_license`, `identity_card`, `internal_passport`, - /// `utility_bill`, `bank_statement`, `rental_agreement`, - /// `passport_registration` and `temporary_registration` types. Files - /// can be decrypted and verified using the accompanying - /// [`EncryptedCredentials`]. - /// - /// [`EncryptedCredentials`]: - /// crate::types::EncryptedCredentials - translation: Option>, - }, - InternalPassport { - /// Base64-encoded encrypted Telegram Passport element data provided - /// by the user, available for `personal_details`, `passport`, - /// `driver_license`, `identity_card`, `internal_passport` and - /// `address` types. Can be decrypted and verified using the - /// accompanying [`EncryptedCredentials`]. - /// - /// [`EncryptedCredentials`]: - /// crate::types::EncryptedCredentials - data: String, - - /// Encrypted file with the front side of the document, provided by the - /// user. Available for `passport`, `driver_license`, `identity_card` - /// and `internal_passport`. The file can be decrypted and verified - /// using the accompanying [`EncryptedCredentials`]. - /// - /// [`EncryptedCredentials`]: - /// crate::types::EncryptedCredentials - front_side: PassportFile, - - /// Encrypted file with the selfie of the user holding a document, - /// provided by the user; available for `passport`, `driver_license`, - /// `identity_card` and `internal_passport`. The file can be decrypted - /// and verified using the accompanying [`EncryptedCredentials`]. - /// - /// [`EncryptedCredentials`]: - /// crate::types::EncryptedCredentials - selfie: PassportFile, - - /// Array of encrypted files with translated versions of documents - /// provided by the user. Available if requested for `passport`, - /// `driver_license`, `identity_card`, `internal_passport`, - /// `utility_bill`, `bank_statement`, `rental_agreement`, - /// `passport_registration` and `temporary_registration` types. Files - /// can be decrypted and verified using the accompanying - /// [`EncryptedCredentials`]. - /// - /// [`EncryptedCredentials`]: - /// crate::types::EncryptedCredentials - translation: Option>, - }, - Address { - /// Base64-encoded encrypted Telegram Passport element data provided - /// by the user, available for `personal_details`, `passport`, - /// `driver_license`, `identity_card`, `internal_passport` and - /// `address` types. Can be decrypted and verified using the - /// accompanying [`EncryptedCredentials`]. - /// - /// [`EncryptedCredentials`]: - /// crate::types::EncryptedCredentials - data: String, - }, - UtilityBill { - /// Array of encrypted files with documents provided by the user, - /// available for `utility_bill`, `bank_statement`, `rental_agreement`, - /// `passport_registration` and `temporary_registration` types. Files - /// can be decrypted and verified using the accompanying - /// [`EncryptedCredentials`]. - /// - /// [`EncryptedCredentials`]: - /// crate::types::EncryptedCredentials - files: Vec, - - /// Array of encrypted files with translated versions of documents - /// provided by the user. Available if requested for `passport`, - /// `driver_license`, `identity_card`, `internal_passport`, - /// `utility_bill`, `bank_statement`, `rental_agreement`, - /// `passport_registration` and `temporary_registration` types. Files - /// can be decrypted and verified using the accompanying - /// [`EncryptedCredentials`]. - /// - /// [`EncryptedCredentials`]: - /// crate::types::EncryptedCredentials - translation: Option>, - }, - BankStatement { - /// Array of encrypted files with documents provided by the user, - /// available for `utility_bill`, `bank_statement`, `rental_agreement`, - /// `passport_registration` and `temporary_registration` types. Files - /// can be decrypted and verified using the accompanying - /// [`EncryptedCredentials`]. - /// - /// [`EncryptedCredentials`]: - /// crate::types::EncryptedCredentials - files: Vec, - - /// Array of encrypted files with translated versions of documents - /// provided by the user. Available if requested for `passport`, - /// `driver_license`, `identity_card`, `internal_passport`, - /// `utility_bill`, `bank_statement`, `rental_agreement`, - /// `passport_registration` and `temporary_registration` types. Files - /// can be decrypted and verified using the accompanying - /// [`EncryptedCredentials`]. - /// - /// [`EncryptedCredentials`]: - /// crate::types::EncryptedCredentials - translation: Option>, - }, - RentalAgreement { - /// Array of encrypted files with documents provided by the user, - /// available for `utility_bill`, `bank_statement`, `rental_agreement`, - /// `passport_registration` and `temporary_registration` types. Files - /// can be decrypted and verified using the accompanying - /// [`EncryptedCredentials`]. - /// - /// [`EncryptedCredentials`]: - /// crate::types::EncryptedCredentials - files: Vec, - - /// Array of encrypted files with translated versions of documents - /// provided by the user. Available if requested for `passport`, - /// `driver_license`, `identity_card`, `internal_passport`, - /// `utility_bill`, `bank_statement`, `rental_agreement`, - /// `passport_registration` and `temporary_registration` types. Files - /// can be decrypted and verified using the accompanying - /// [`EncryptedCredentials`]. - /// - /// [`EncryptedCredentials`]: - /// crate::types::EncryptedCredentials - translation: Option>, - }, - PassportRegistration { - /// Array of encrypted files with documents provided by the user, - /// available for `utility_bill`, `bank_statement`, `rental_agreement`, - /// `passport_registration` and `temporary_registration` types. Files - /// can be decrypted and verified using the accompanying - /// [`EncryptedCredentials`]. - /// - /// [`EncryptedCredentials`]: - /// crate::types::EncryptedCredentials - files: Vec, - - /// Array of encrypted files with translated versions of documents - /// provided by the user. Available if requested for `passport`, - /// `driver_license`, `identity_card`, `internal_passport`, - /// `utility_bill`, `bank_statement`, `rental_agreement`, - /// `passport_registration` and `temporary_registration` types. Files - /// can be decrypted and verified using the accompanying - /// [`EncryptedCredentials`]. - /// - /// [`EncryptedCredentials`]: - /// crate::types::EncryptedCredentials - translation: Option>, - }, - TemporaryRegistration { - /// Array of encrypted files with documents provided by the user, - /// available for `utility_bill`, `bank_statement`, `rental_agreement`, - /// `passport_registration` and `temporary_registration` types. Files - /// can be decrypted and verified using the accompanying - /// [`EncryptedCredentials`]. - /// - /// [`EncryptedCredentials`]: - /// crate::types::EncryptedCredentials - files: Vec, - - /// Array of encrypted files with translated versions of documents - /// provided by the user. Available if requested for `passport`, - /// `driver_license`, `identity_card`, `internal_passport`, - /// `utility_bill`, `bank_statement`, `rental_agreement`, - /// `passport_registration` and `temporary_registration` types. Files - /// can be decrypted and verified using the accompanying - /// [`EncryptedCredentials`]. - /// - /// [`EncryptedCredentials`]: - /// crate::types::EncryptedCredentials - translation: Option>, - }, - PhoneNumber { - /// User's verified phone number, available only for `phone_number` - /// type. - phone_number: String, - }, - Email { - /// User's verified email address, available only for `email` type. - email: String, - }, + PersonalDetails(EncryptedPassportElementPersonalDetails), + Passport(EncryptedPassportElementPassport), + DriverLicense(EncryptedPassportElementDriverLicense), + IdentityCard(EncryptedPassportElementIdentityCard), + InternalPassport(EncryptedPassportElementInternalPassport), + Address(EncryptedPassportElementAddress), + UtilityBill(EncryptedPassportElementUtilityBill), + BankStatement(EncryptedPassportElementBankStatement), + RentalAgreement(EncryptedPassportElementRentalAgreement), + PassportRegistration(EncryptedPassportElementPassportRegistration), + EncryptedPassportElement(EncryptedPassportElementTemporaryRegistration), + PhoneNumber(EncryptedPassportElementPhoneNumber), + Email(EncryptedPassportElementEmail), +} + +#[serde_with_macros::skip_serializing_none] +#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] +pub struct EncryptedPassportElementPersonalDetails { + /// Base64-encoded encrypted Telegram Passport element data provided + /// by the user, available for `personal_details`, `passport`, + /// `driver_license`, `identity_card`, `internal_passport` and + /// `address` types. Can be decrypted and verified using the + /// accompanying [`EncryptedCredentials`]. + /// + /// [`EncryptedCredentials`]: + /// crate::types::EncryptedCredentials + pub data: String, +} + +#[serde_with_macros::skip_serializing_none] +#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] +pub struct EncryptedPassportElementPassport { + /// Base64-encoded encrypted Telegram Passport element data provided + /// by the user, available for `personal_details`, `passport`, + /// `driver_license`, `identity_card`, `internal_passport` and + /// `address` types. Can be decrypted and verified using the + /// accompanying [`EncryptedCredentials`]. + /// + /// [`EncryptedCredentials`]: + /// crate::types::EncryptedCredentials + pub data: String, + + /// Encrypted file with the front side of the document, provided by the + /// user. Available for `passport`, `driver_license`, `identity_card` + /// and `internal_passport`. The file can be decrypted and verified + /// using the accompanying [`EncryptedCredentials`]. + /// + /// [`EncryptedCredentials`]: + /// crate::types::EncryptedCredentials + pub front_side: PassportFile, + + /// Encrypted file with the selfie of the user holding a document, + /// provided by the user; available for `passport`, `driver_license`, + /// `identity_card` and `internal_passport`. The file can be decrypted + /// and verified using the accompanying [`EncryptedCredentials`]. + /// + /// [`EncryptedCredentials`]: + /// crate::types::EncryptedCredentials + pub selfie: PassportFile, + + /// Array of encrypted files with translated versions of documents + /// provided by the user. Available if requested for `passport`, + /// `driver_license`, `identity_card`, `internal_passport`, + /// `utility_bill`, `bank_statement`, `rental_agreement`, + /// `passport_registration` and `temporary_registration` types. Files + /// can be decrypted and verified using the accompanying + /// [`EncryptedCredentials`]. + /// + /// [`EncryptedCredentials`]: + /// crate::types::EncryptedCredentials + pub translation: Option>, +} + +#[serde_with_macros::skip_serializing_none] +#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] +pub struct EncryptedPassportElementDriverLicense { + /// Base64-encoded encrypted Telegram Passport element data provided + /// by the user, available for `personal_details`, `passport`, + /// `driver_license`, `identity_card`, `internal_passport` and + /// `address` types. Can be decrypted and verified using the + /// accompanying [`EncryptedCredentials`]. + /// + /// [`EncryptedCredentials`]: + /// crate::types::EncryptedCredentials + pub data: String, + + /// Encrypted file with the front side of the document, provided by the + /// user. Available for `passport`, `driver_license`, `identity_card` + /// and `internal_passport`. The file can be decrypted and verified + /// using the accompanying [`EncryptedCredentials`]. + /// + /// [`EncryptedCredentials`]: + /// crate::types::EncryptedCredentials + pub front_side: PassportFile, + + /// Encrypted file with the reverse side of the document, provided by + /// the user. Available for `driver_license` and `identity_card`. The + /// file can be decrypted and verified using the accompanying + /// [`EncryptedCredentials`]. + /// + /// [`EncryptedCredentials`]: + /// crate::types::EncryptedCredentials + pub reverse_side: PassportFile, + + /// Encrypted file with the selfie of the user holding a document, + /// provided by the user; available for `passport`, `driver_license`, + /// `identity_card` and `internal_passport`. The file can be decrypted + /// and verified using the accompanying [`EncryptedCredentials`]. + /// + /// [`EncryptedCredentials`]: + /// crate::types::EncryptedCredentials + pub selfie: PassportFile, + + /// Array of encrypted files with translated versions of documents + /// provided by the user. Available if requested for `passport`, + /// `driver_license`, `identity_card`, `internal_passport`, + /// `utility_bill`, `bank_statement`, `rental_agreement`, + /// `passport_registration` and `temporary_registration` types. Files + /// can be decrypted and verified using the accompanying + /// [`EncryptedCredentials`]. + /// + /// [`EncryptedCredentials`]: + /// crate::types::EncryptedCredentials + pub translation: Option>, +} + +#[serde_with_macros::skip_serializing_none] +#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] +pub struct EncryptedPassportElementIdentityCard { + /// Base64-encoded encrypted Telegram Passport element data provided + /// by the user, available for `personal_details`, `passport`, + /// `driver_license`, `identity_card`, `internal_passport` and + /// `address` types. Can be decrypted and verified using the + /// accompanying [`EncryptedCredentials`]. + /// + /// [`EncryptedCredentials`]: + /// crate::types::EncryptedCredentials + pub data: String, + + /// Encrypted file with the front side of the document, provided by the + /// user. Available for `passport`, `driver_license`, `identity_card` + /// and `internal_passport`. The file can be decrypted and verified + /// using the accompanying [`EncryptedCredentials`]. + /// + /// [`EncryptedCredentials`]: + /// crate::types::EncryptedCredentials + pub front_side: PassportFile, + + /// Encrypted file with the reverse side of the document, provided by + /// the user. Available for `driver_license` and `identity_card`. The + /// file can be decrypted and verified using the accompanying + /// [`EncryptedCredentials`]. + /// + /// [`EncryptedCredentials`]: + /// crate::types::EncryptedCredentials + pub reverse_side: PassportFile, + + /// Encrypted file with the selfie of the user holding a document, + /// provided by the user; available for `passport`, `driver_license`, + /// `identity_card` and `internal_passport`. The file can be decrypted + /// and verified using the accompanying [`EncryptedCredentials`]. + /// + /// [`EncryptedCredentials`]: + /// crate::types::EncryptedCredentials + pub selfie: PassportFile, + + /// Array of encrypted files with translated versions of documents + /// provided by the user. Available if requested for `passport`, + /// `driver_license`, `identity_card`, `internal_passport`, + /// `utility_bill`, `bank_statement`, `rental_agreement`, + /// `passport_registration` and `temporary_registration` types. Files + /// can be decrypted and verified using the accompanying + /// [`EncryptedCredentials`]. + /// + /// [`EncryptedCredentials`]: + /// crate::types::EncryptedCredentials + pub translation: Option>, +} + +#[serde_with_macros::skip_serializing_none] +#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] + +pub struct EncryptedPassportElementInternalPassport { + /// Base64-encoded encrypted Telegram Passport element data provided + /// by the user, available for `personal_details`, `passport`, + /// `driver_license`, `identity_card`, `internal_passport` and + /// `address` types. Can be decrypted and verified using the + /// accompanying [`EncryptedCredentials`]. + /// + /// [`EncryptedCredentials`]: + /// crate::types::EncryptedCredentials + pub data: String, + + /// Encrypted file with the front side of the document, provided by the + /// user. Available for `passport`, `driver_license`, `identity_card` + /// and `internal_passport`. The file can be decrypted and verified + /// using the accompanying [`EncryptedCredentials`]. + /// + /// [`EncryptedCredentials`]: + /// crate::types::EncryptedCredentials + pub front_side: PassportFile, + + /// Encrypted file with the selfie of the user holding a document, + /// provided by the user; available for `passport`, `driver_license`, + /// `identity_card` and `internal_passport`. The file can be decrypted + /// and verified using the accompanying [`EncryptedCredentials`]. + /// + /// [`EncryptedCredentials`]: + /// crate::types::EncryptedCredentials + pub selfie: PassportFile, + + /// Array of encrypted files with translated versions of documents + /// provided by the user. Available if requested for `passport`, + /// `driver_license`, `identity_card`, `internal_passport`, + /// `utility_bill`, `bank_statement`, `rental_agreement`, + /// `passport_registration` and `temporary_registration` types. Files + /// can be decrypted and verified using the accompanying + /// [`EncryptedCredentials`]. + /// + /// [`EncryptedCredentials`]: + /// crate::types::EncryptedCredentials + pub translation: Option>, +} + +#[serde_with_macros::skip_serializing_none] +#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] +pub struct EncryptedPassportElementAddress { + /// Base64-encoded encrypted Telegram Passport element data provided + /// by the user, available for `personal_details`, `passport`, + /// `driver_license`, `identity_card`, `internal_passport` and + /// `address` types. Can be decrypted and verified using the + /// accompanying [`EncryptedCredentials`]. + /// + /// [`EncryptedCredentials`]: + /// crate::types::EncryptedCredentials + pub data: String, +} + +#[serde_with_macros::skip_serializing_none] +#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] +pub struct EncryptedPassportElementUtilityBill { + /// Array of encrypted files with documents provided by the user, + /// available for `utility_bill`, `bank_statement`, `rental_agreement`, + /// `passport_registration` and `temporary_registration` types. Files + /// can be decrypted and verified using the accompanying + /// [`EncryptedCredentials`]. + /// + /// [`EncryptedCredentials`]: + /// crate::types::EncryptedCredentials + pub files: Vec, + + /// Array of encrypted files with translated versions of documents + /// provided by the user. Available if requested for `passport`, + /// `driver_license`, `identity_card`, `internal_passport`, + /// `utility_bill`, `bank_statement`, `rental_agreement`, + /// `passport_registration` and `temporary_registration` types. Files + /// can be decrypted and verified using the accompanying + /// [`EncryptedCredentials`]. + /// + /// [`EncryptedCredentials`]: + /// crate::types::EncryptedCredentials + pub translation: Option>, +} + +#[serde_with_macros::skip_serializing_none] +#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] + +pub struct EncryptedPassportElementBankStatement { + /// Array of encrypted files with documents provided by the user, + /// available for `utility_bill`, `bank_statement`, `rental_agreement`, + /// `passport_registration` and `temporary_registration` types. Files + /// can be decrypted and verified using the accompanying + /// [`EncryptedCredentials`]. + /// + /// [`EncryptedCredentials`]: + /// crate::types::EncryptedCredentials + pub files: Vec, + + /// Array of encrypted files with translated versions of documents + /// provided by the user. Available if requested for `passport`, + /// `driver_license`, `identity_card`, `internal_passport`, + /// `utility_bill`, `bank_statement`, `rental_agreement`, + /// `passport_registration` and `temporary_registration` types. Files + /// can be decrypted and verified using the accompanying + /// [`EncryptedCredentials`]. + /// + /// [`EncryptedCredentials`]: + /// crate::types::EncryptedCredentials + pub translation: Option>, +} + +#[serde_with_macros::skip_serializing_none] +#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] +pub struct EncryptedPassportElementRentalAgreement { + /// Array of encrypted files with documents provided by the user, + /// available for `utility_bill`, `bank_statement`, `rental_agreement`, + /// `passport_registration` and `temporary_registration` types. Files + /// can be decrypted and verified using the accompanying + /// [`EncryptedCredentials`]. + /// + /// [`EncryptedCredentials`]: + /// crate::types::EncryptedCredentials + pub files: Vec, + + /// Array of encrypted files with translated versions of documents + /// provided by the user. Available if requested for `passport`, + /// `driver_license`, `identity_card`, `internal_passport`, + /// `utility_bill`, `bank_statement`, `rental_agreement`, + /// `passport_registration` and `temporary_registration` types. Files + /// can be decrypted and verified using the accompanying + /// [`EncryptedCredentials`]. + /// + /// [`EncryptedCredentials`]: + /// crate::types::EncryptedCredentials + pub translation: Option>, +} + +#[serde_with_macros::skip_serializing_none] +#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] + +pub struct EncryptedPassportElementPassportRegistration { + /// Array of encrypted files with documents provided by the user, + /// available for `utility_bill`, `bank_statement`, `rental_agreement`, + /// `passport_registration` and `temporary_registration` types. Files + /// can be decrypted and verified using the accompanying + /// [`EncryptedCredentials`]. + /// + /// [`EncryptedCredentials`]: + /// crate::types::EncryptedCredentials + pub files: Vec, + + /// Array of encrypted files with translated versions of documents + /// provided by the user. Available if requested for `passport`, + /// `driver_license`, `identity_card`, `internal_passport`, + /// `utility_bill`, `bank_statement`, `rental_agreement`, + /// `passport_registration` and `temporary_registration` types. Files + /// can be decrypted and verified using the accompanying + /// [`EncryptedCredentials`]. + /// + /// [`EncryptedCredentials`]: + /// crate::types::EncryptedCredentials + pub translation: Option>, +} + +#[serde_with_macros::skip_serializing_none] +#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] +pub struct EncryptedPassportElementTemporaryRegistration { + /// Array of encrypted files with documents provided by the user, + /// available for `utility_bill`, `bank_statement`, `rental_agreement`, + /// `passport_registration` and `temporary_registration` types. Files + /// can be decrypted and verified using the accompanying + /// [`EncryptedCredentials`]. + /// + /// [`EncryptedCredentials`]: + /// crate::types::EncryptedCredentials + pub files: Vec, + + /// Array of encrypted files with translated versions of documents + /// provided by the user. Available if requested for `passport`, + /// `driver_license`, `identity_card`, `internal_passport`, + /// `utility_bill`, `bank_statement`, `rental_agreement`, + /// `passport_registration` and `temporary_registration` types. Files + /// can be decrypted and verified using the accompanying + /// [`EncryptedCredentials`]. + /// + /// [`EncryptedCredentials`]: + /// crate::types::EncryptedCredentials + pub translation: Option>, +} + +#[serde_with_macros::skip_serializing_none] +#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] +pub struct EncryptedPassportElementPhoneNumber { + /// User's verified phone number, available only for `phone_number` + /// type. + pub phone_number: String, +} + +#[serde_with_macros::skip_serializing_none] +#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] + +pub struct EncryptedPassportElementEmail { + /// User's verified email address, available only for `email` type. + pub email: String, } diff --git a/src/types/inline_query_result.rs b/src/types/inline_query_result.rs index b4273dce..de3b28e8 100644 --- a/src/types/inline_query_result.rs +++ b/src/types/inline_query_result.rs @@ -59,6 +59,7 @@ mod tests { use crate::types::{ inline_keyboard_markup::InlineKeyboardMarkup, parse_mode::ParseMode, InlineQueryResult, InlineQueryResultCachedAudio, InputMessageContent, + InputMessageContentText, }; #[test] @@ -89,11 +90,13 @@ mod tests { caption: Some(String::from("caption")), parse_mode: Some(ParseMode::HTML), reply_markup: Some(InlineKeyboardMarkup::default()), - input_message_content: Some(InputMessageContent::Text { - message_text: String::from("message_text"), - parse_mode: Some(ParseMode::MarkdownV2), - disable_web_page_preview: Some(true), - }), + input_message_content: Some(InputMessageContent::Text( + InputMessageContentText { + message_text: String::from("message_text"), + parse_mode: Some(ParseMode::MarkdownV2), + disable_web_page_preview: Some(true), + }, + )), }); let expected_json = r#"{"type":"audio","id":"id","audio_file_id":"audio_file_id","caption":"caption","parse_mode":"HTML","reply_markup":{"inline_keyboard":[]},"input_message_content":{"message_text":"message_text","parse_mode":"MarkdownV2","disable_web_page_preview":true}}"#; diff --git a/src/types/input_media.rs b/src/types/input_media.rs index 365597d7..a7b8daa8 100644 --- a/src/types/input_media.rs +++ b/src/types/input_media.rs @@ -3,7 +3,6 @@ use serde::{Deserialize, Serialize}; use crate::types::{InputFile, ParseMode}; // TODO: should variants use new-type? -#[serde_with_macros::skip_serializing_none] #[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] #[serde(tag = "type")] #[serde(rename_all = "snake_case")] @@ -11,169 +10,185 @@ use crate::types::{InputFile, ParseMode}; /// /// [The official docs](https://core.telegram.org/bots/api#inputmedia). pub enum InputMedia { - /// Represents a photo to be sent. + Photo(InputMediaPhoto), + Video(InputMediaVideo), + Animation(InputMediaAnimation), + Audio(InputMediaAudio), + Document(InputMediaDocument), +} + +/// Represents a photo to be sent. +/// +/// [The official docs](https://core.telegram.org/bots/api#inputmediaphoto). +#[serde_with_macros::skip_serializing_none] +#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] +pub struct InputMediaPhoto { + /// File to send. + pub media: InputFile, + + /// Caption of the photo to be sent, 0-1024 characters. + pub caption: Option, + + /// Send [Markdown] or [HTML], if you want Telegram apps to show [bold, + /// italic, fixed-width text or inline URLs] in the media caption. /// - /// [The official docs](https://core.telegram.org/bots/api#inputmediaphoto). - Photo { - /// File to send. - media: InputFile, + /// [Markdown]: https://core.telegram.org/bots/api#markdown-style + /// [HTML]: https://core.telegram.org/bots/api#html-style + /// [bold, italic, fixed-width text or inline URLs]: https://core.telegram.org/bots/api#formatting-options + pub parse_mode: Option, +} - /// Caption of the photo to be sent, 0-1024 characters. - caption: Option, +/// Represents a video to be sent. +/// +/// [The official docs](https://core.telegram.org/bots/api#inputmediavideo). +#[serde_with_macros::skip_serializing_none] +#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] +pub struct InputMediaVideo { + // File to send. + pub media: InputFile, - /// Send [Markdown] or [HTML], if you want Telegram apps to show [bold, - /// italic, fixed-width text or inline URLs] in the media caption. - /// - /// [Markdown]: https://core.telegram.org/bots/api#markdown-style - /// [HTML]: https://core.telegram.org/bots/api#html-style - /// [bold, italic, fixed-width text or inline URLs]: https://core.telegram.org/bots/api#formatting-options - parse_mode: Option, - }, + /// Thumbnail of the file sent; can be ignored if thumbnail generation + /// for the file is supported server-side. The thumbnail should be in + /// JPEG format and less than 200 kB in size. A thumbnail‘s width and + /// height should not exceed 320. Ignored if the file is not uploaded + /// using multipart/form-data. + pub thumb: Option, - /// Represents a video to be sent. + /// Caption of the video to be sent, 0-1024 characters. + pub caption: Option, + + /// Send [Markdown] or [HTML], if you want Telegram apps to show [bold, + /// italic, fixed-width text or inline URLs] in the media caption. /// - /// [The official docs](https://core.telegram.org/bots/api#inputmediavideo). - Video { - // File to send. - media: InputFile, + /// [Markdown]: https://core.telegram.org/bots/api#markdown-style + /// [HTML]: https://core.telegram.org/bots/api#html-style + /// [bold, italic, fixed-width text or inline URLs]: https://core.telegram.org/bots/api#formatting-options + pub parse_mode: Option, - /// Thumbnail of the file sent; can be ignored if thumbnail generation - /// for the file is supported server-side. The thumbnail should be in - /// JPEG format and less than 200 kB in size. A thumbnail‘s width and - /// height should not exceed 320. Ignored if the file is not uploaded - /// using multipart/form-data. - thumb: Option, + /// Video width. + pub width: Option, - /// Caption of the video to be sent, 0-1024 characters. - caption: Option, + /// Video height. + pub height: Option, - /// Send [Markdown] or [HTML], if you want Telegram apps to show [bold, - /// italic, fixed-width text or inline URLs] in the media caption. - /// - /// [Markdown]: https://core.telegram.org/bots/api#markdown-style - /// [HTML]: https://core.telegram.org/bots/api#html-style - /// [bold, italic, fixed-width text or inline URLs]: https://core.telegram.org/bots/api#formatting-options - parse_mode: Option, + /// Video duration. + pub duration: Option, - /// Video width. - width: Option, + /// Pass `true`, if the uploaded video is suitable for streaming. + pub supports_streaming: Option, +} - /// Video height. - height: Option, +/// Represents an animation file (GIF or H.264/MPEG-4 AVC video without +/// sound) to be sent. +/// +/// [The official docs](https://core.telegram.org/bots/api#inputmediaanimation). +#[serde_with_macros::skip_serializing_none] +#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] +pub struct InputMediaAnimation { + /// File to send. + pub media: InputFile, - /// Video duration. - duration: Option, + /// Thumbnail of the file sent; can be ignored if thumbnail generation + /// for the file is supported server-side. The thumbnail should be in + /// JPEG format and less than 200 kB in size. A thumbnail‘s width and + /// height should not exceed 320. Ignored if the file is not uploaded + /// using multipart/form-data. + pub thumb: Option, - /// Pass `true`, if the uploaded video is suitable for streaming. - supports_streaming: Option, - }, + /// Caption of the animation to be sent, 0-1024 characters. + pub caption: Option, - /// Represents an animation file (GIF or H.264/MPEG-4 AVC video without - /// sound) to be sent. + /// Send [Markdown] or [HTML], if you want Telegram apps to show [bold, + /// italic, fixed-width text or inline URLs] in the media caption. /// - /// [The official docs](https://core.telegram.org/bots/api#inputmediaanimation). - Animation { - /// File to send. - media: InputFile, + /// [Markdown]: https://core.telegram.org/bots/api#markdown-style + /// [HTML]: https://core.telegram.org/bots/api#html-style + /// [bold, italic, fixed-width text or inline URLs]: https://core.telegram.org/bots/api#formatting-options + pub parse_mode: Option, - /// Thumbnail of the file sent; can be ignored if thumbnail generation - /// for the file is supported server-side. The thumbnail should be in - /// JPEG format and less than 200 kB in size. A thumbnail‘s width and - /// height should not exceed 320. Ignored if the file is not uploaded - /// using multipart/form-data. - thumb: Option, + /// Animation width. + pub width: Option, - /// Caption of the animation to be sent, 0-1024 characters. - caption: Option, + /// Animation height. + pub height: Option, - /// Send [Markdown] or [HTML], if you want Telegram apps to show [bold, - /// italic, fixed-width text or inline URLs] in the media caption. - /// - /// [Markdown]: https://core.telegram.org/bots/api#markdown-style - /// [HTML]: https://core.telegram.org/bots/api#html-style - /// [bold, italic, fixed-width text or inline URLs]: https://core.telegram.org/bots/api#formatting-options - parse_mode: Option, + /// Animation duration. + pub duration: Option, +} - /// Animation width. - width: Option, +/// Represents an audio file to be treated as music to be sent. +/// +/// [The official docs](https://core.telegram.org/bots/api#inputmediaaudio). +#[serde_with_macros::skip_serializing_none] +#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] +pub struct InputMediaAudio { + /// File to send. + pub media: InputFile, - /// Animation height. - height: Option, + /// Thumbnail of the file sent; can be ignored if thumbnail generation + /// for the file is supported server-side. The thumbnail should be in + /// JPEG format and less than 200 kB in size. A thumbnail‘s width and + /// height should not exceed 320. Ignored if the file is not uploaded + /// using multipart/form-data. + pub thumb: Option, - /// Animation duration. - duration: Option, - }, + /// Caption of the audio to be sent, 0-1024 characters. + pub caption: Option, - /// Represents an audio file to be treated as music to be sent. + /// Send [Markdown] or [HTML], if you want Telegram apps to show [bold, + /// italic, fixed-width text or inline URLs] in the media caption. /// - /// [The official docs](https://core.telegram.org/bots/api#inputmediaaudio). - Audio { - /// File to send. - media: InputFile, + /// [Markdown]: https://core.telegram.org/bots/api#markdown-style + /// [HTML]: https://core.telegram.org/bots/api#html-style + /// [bold, italic, fixed-width text or inline URLs]: https://core.telegram.org/bots/api#formatting-options + pub parse_mode: Option, - /// Thumbnail of the file sent; can be ignored if thumbnail generation - /// for the file is supported server-side. The thumbnail should be in - /// JPEG format and less than 200 kB in size. A thumbnail‘s width and - /// height should not exceed 320. Ignored if the file is not uploaded - /// using multipart/form-data. - thumb: Option, + /// Duration of the audio in seconds. + pub duration: Option, - /// Caption of the audio to be sent, 0-1024 characters. - caption: Option, + /// Performer of the audio. + pub performer: Option, - /// Send [Markdown] or [HTML], if you want Telegram apps to show [bold, - /// italic, fixed-width text or inline URLs] in the media caption. - /// - /// [Markdown]: https://core.telegram.org/bots/api#markdown-style - /// [HTML]: https://core.telegram.org/bots/api#html-style - /// [bold, italic, fixed-width text or inline URLs]: https://core.telegram.org/bots/api#formatting-options - parse_mode: Option, + /// Title of the audio. + pub title: Option, +} - /// Duration of the audio in seconds. - duration: Option, +/// Represents a general file to be sent. +/// +/// [The official docs](https://core.telegram.org/bots/api#inputmediadocument). +#[serde_with_macros::skip_serializing_none] +#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] +pub struct InputMediaDocument { + /// File to send. + pub media: InputFile, - /// Performer of the audio. - performer: Option, + /// Thumbnail of the file sent; can be ignored if thumbnail generation + /// for the file is supported server-side. The thumbnail should be in + /// JPEG format and less than 200 kB in size. A thumbnail‘s width and + /// height should not exceed 320. Ignored if the file is not uploaded + /// using multipart/form-data. + pub thumb: Option, - /// Title of the audio. - title: Option, - }, + /// Caption of the document to be sent, 0-1024 charactersю + pub caption: Option, - /// Represents a general file to be sent. + /// Send [Markdown] or [HTML], if you want Telegram apps to show [bold, + /// italic, fixed-width text or inline URLs] in the media caption. /// - /// [The official docs](https://core.telegram.org/bots/api#inputmediadocument). - Document { - /// File to send. - media: InputFile, - - /// Thumbnail of the file sent; can be ignored if thumbnail generation - /// for the file is supported server-side. The thumbnail should be in - /// JPEG format and less than 200 kB in size. A thumbnail‘s width and - /// height should not exceed 320. Ignored if the file is not uploaded - /// using multipart/form-data. - thumb: Option, - - /// Caption of the document to be sent, 0-1024 charactersю - caption: Option, - - /// Send [Markdown] or [HTML], if you want Telegram apps to show [bold, - /// italic, fixed-width text or inline URLs] in the media caption. - /// - /// [Markdown]: https://core.telegram.org/bots/api#markdown-style - /// [HTML]: https://core.telegram.org/bots/api#html-style - /// [bold, italic, fixed-width text or inline URLs]: https://core.telegram.org/bots/api#formatting-options - parse_mode: Option, - }, + /// [Markdown]: https://core.telegram.org/bots/api#markdown-style + /// [HTML]: https://core.telegram.org/bots/api#html-style + /// [bold, italic, fixed-width text or inline URLs]: https://core.telegram.org/bots/api#formatting-options + pub parse_mode: Option, } impl InputMedia { pub fn media(&self) -> &InputFile { match self { - InputMedia::Photo { media, .. } - | InputMedia::Document { media, .. } - | InputMedia::Audio { media, .. } - | InputMedia::Animation { media, .. } - | InputMedia::Video { media, .. } => media, + InputMedia::Photo(InputMediaPhoto { media, .. }) + | InputMedia::Document(InputMediaDocument { media, .. }) + | InputMedia::Audio(InputMediaAudio { media, .. }) + | InputMedia::Animation(InputMediaAnimation { media, .. }) + | InputMedia::Video(InputMediaVideo { media, .. }) => media, } } } @@ -181,11 +196,11 @@ impl InputMedia { impl From for InputFile { fn from(media: InputMedia) -> InputFile { match media { - InputMedia::Photo { media, .. } - | InputMedia::Document { media, .. } - | InputMedia::Audio { media, .. } - | InputMedia::Animation { media, .. } - | InputMedia::Video { media, .. } => media, + InputMedia::Photo(InputMediaPhoto { media, .. }) + | InputMedia::Document(InputMediaDocument { media, .. }) + | InputMedia::Audio(InputMediaAudio { media, .. }) + | InputMedia::Animation(InputMediaAnimation { media, .. }) + | InputMedia::Video(InputMediaVideo { media, .. }) => media, } } } @@ -197,11 +212,11 @@ mod tests { #[test] fn photo_serialize() { let expected_json = r#"{"type":"photo","media":"123456"}"#; - let photo = InputMedia::Photo { + let photo = InputMedia::Photo(InputMediaPhoto { media: InputFile::FileId(String::from("123456")), caption: None, parse_mode: None, - }; + }); let actual_json = serde_json::to_string(&photo).unwrap(); assert_eq!(expected_json, actual_json); @@ -210,7 +225,7 @@ mod tests { #[test] fn video_serialize() { let expected_json = r#"{"type":"video","media":"123456"}"#; - let video = InputMedia::Video { + let video = InputMedia::Video(InputMediaVideo { media: InputFile::FileId(String::from("123456")), thumb: None, caption: None, @@ -219,7 +234,7 @@ mod tests { height: None, duration: None, supports_streaming: None, - }; + }); let actual_json = serde_json::to_string(&video).unwrap(); assert_eq!(expected_json, actual_json); @@ -228,7 +243,7 @@ mod tests { #[test] fn animation_serialize() { let expected_json = r#"{"type":"animation","media":"123456"}"#; - let video = InputMedia::Animation { + let video = InputMedia::Animation(InputMediaAnimation { media: InputFile::FileId(String::from("123456")), thumb: None, caption: None, @@ -236,7 +251,7 @@ mod tests { width: None, height: None, duration: None, - }; + }); let actual_json = serde_json::to_string(&video).unwrap(); assert_eq!(expected_json, actual_json); @@ -245,7 +260,7 @@ mod tests { #[test] fn audio_serialize() { let expected_json = r#"{"type":"audio","media":"123456"}"#; - let video = InputMedia::Audio { + let video = InputMedia::Audio(InputMediaAudio { media: InputFile::FileId(String::from("123456")), thumb: None, caption: None, @@ -253,7 +268,7 @@ mod tests { duration: None, performer: None, title: None, - }; + }); let actual_json = serde_json::to_string(&video).unwrap(); assert_eq!(expected_json, actual_json); @@ -262,12 +277,12 @@ mod tests { #[test] fn document_serialize() { let expected_json = r#"{"type":"document","media":"123456"}"#; - let video = InputMedia::Document { + let video = InputMedia::Document(InputMediaDocument { media: InputFile::FileId(String::from("123456")), thumb: None, caption: None, parse_mode: None, - }; + }); let actual_json = serde_json::to_string(&video).unwrap(); assert_eq!(expected_json, actual_json); diff --git a/src/types/input_message_content.rs b/src/types/input_message_content.rs index a9563211..79444de4 100644 --- a/src/types/input_message_content.rs +++ b/src/types/input_message_content.rs @@ -2,88 +2,100 @@ use serde::{Deserialize, Serialize}; use crate::types::ParseMode; -#[serde_with_macros::skip_serializing_none] -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] -#[serde(untagged)] /// This object represents the content of a message to be sent as a result of an /// inline query. /// /// [The official docs](https://core.telegram.org/bots/api#inputmessagecontent). +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +#[serde(untagged)] pub enum InputMessageContent { - /// Represents the content of a text message to be sent as the result of an - /// inline query. - Text { - /// Text of the message to be sent, 1-4096 characters. - message_text: String, + Text(InputMessageContentText), + Location(InputMessageContentLocation), + Venue(InputMessageContentVenue), + Contact(InputMessageContentContact), +} +/// Represents the content of a text message to be sent as the result of an +/// inline query. +#[serde_with_macros::skip_serializing_none] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct InputMessageContentText { + /// Text of the message to be sent, 1-4096 characters. + pub message_text: String, - /// Send [Markdown] or [HTML], if you want Telegram apps to show [bold, - /// italic, fixed-width text or inline URLs] in the media caption. - /// - /// [Markdown]: https://core.telegram.org/bots/api#markdown-style - /// [HTML]: https://core.telegram.org/bots/api#html-style - /// [bold, italic, fixed-width text or inline URLs]: https://core.telegram.org/bots/api#formatting-options - parse_mode: Option, + /// Send [Markdown] or [HTML], if you want Telegram apps to show [bold, + /// italic, fixed-width text or inline URLs] in the media caption. + /// + /// [Markdown]: https://core.telegram.org/bots/api#markdown-style + /// [HTML]: https://core.telegram.org/bots/api#html-style + /// [bold, italic, fixed-width text or inline URLs]: https://core.telegram.org/bots/api#formatting-options + pub parse_mode: Option, - /// Disables link previews for links in the sent message. - disable_web_page_preview: Option, - }, + /// Disables link previews for links in the sent message. + pub disable_web_page_preview: Option, +} - /// Represents the content of a location message to be sent as the result - /// of an inline query. - Location { - /// Latitude of the location in degrees. - latitude: f64, +/// Represents the content of a location message to be sent as the result of an +/// inline query. +#[serde_with_macros::skip_serializing_none] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct InputMessageContentLocation { + /// Latitude of the location in degrees. + pub latitude: f64, - /// Longitude of the location in degrees. - longitude: f64, + /// Longitude of the location in degrees. + pub longitude: f64, - /// Period in seconds for which the location can be updated, should be - /// between 60 and 86400. - live_period: Option, - }, + /// Period in seconds for which the location can be updated, should be + /// between 60 and 86400. + pub live_period: Option, +} - /// Represents the content of a venue message to be sent as the result of - /// an inline query. - Venue { - /// Latitude of the venue in degrees. - latitude: f64, +/// Represents the content of a venue message to be sent as the result of +/// an inline query. +#[serde_with_macros::skip_serializing_none] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] - /// Longitude of the venue in degrees. - longitude: f64, +pub struct InputMessageContentVenue { + /// Latitude of the venue in degrees. + pub latitude: f64, - /// Name of the venue. - title: String, + /// Longitude of the venue in degrees. + pub longitude: f64, - /// Address of the venue. - address: String, + /// Name of the venue. + pub title: String, - /// Foursquare identifier of the venue, if known. - foursquare_id: Option, + /// Address of the venue. + pub address: String, - /// Foursquare type of the venue, if known. (For example, - /// `arts_entertainment/default`, `arts_entertainment/aquarium` - /// or `food/icecream`.) - foursquare_type: Option, - }, + /// Foursquare identifier of the venue, if known. + pub foursquare_id: Option, - /// Represents the content of a contact message to be sent as the result of - /// an inline query. - Contact { - /// Contact's phone number. - phone_number: String, + /// Foursquare type of the venue, if known. (For example, + /// `arts_entertainment/default`, `arts_entertainment/aquarium` + /// or `food/icecream`.) + pub foursquare_type: Option, +} - /// Contact's first name. - first_name: String, +/// Represents the content of a contact message to be sent as the result of +/// an inline query. +#[serde_with_macros::skip_serializing_none] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct InputMessageContentContact { + /// Contact's phone number. + pub phone_number: String, - /// Contact's last name. - last_name: Option, + /// Contact's first name. + pub first_name: String, - /// Additional data about the contact in the form of a [vCard], 0-2048 - /// bytes. - /// - /// [vCard]: https://en.wikipedia.org/wiki/VCard - vcard: Option, - }, + /// Contact's last name. + pub last_name: Option, + + /// Additional data about the contact in the form of a [vCard], 0-2048 + /// bytes. + /// + /// [vCard]: https://en.wikipedia.org/wiki/VCard + pub vcard: Option, } #[cfg(test)] @@ -93,11 +105,11 @@ mod tests { #[test] fn text_serialize() { let expected_json = r#"{"message_text":"text"}"#; - let text_content = InputMessageContent::Text { + let text_content = InputMessageContent::Text(InputMessageContentText { message_text: String::from("text"), parse_mode: None, disable_web_page_preview: None, - }; + }); let actual_json = serde_json::to_string(&text_content).unwrap(); assert_eq!(expected_json, actual_json); @@ -106,11 +118,12 @@ mod tests { #[test] fn location_serialize() { let expected_json = r#"{"latitude":59.08,"longitude":38.4326}"#; - let location_content = InputMessageContent::Location { - latitude: 59.08, - longitude: 38.4326, - live_period: None, - }; + let location_content = + InputMessageContent::Location(InputMessageContentLocation { + latitude: 59.08, + longitude: 38.4326, + live_period: None, + }); let actual_json = serde_json::to_string(&location_content).unwrap(); assert_eq!(expected_json, actual_json); @@ -119,14 +132,15 @@ mod tests { #[test] fn venue_serialize() { let expected_json = r#"{"latitude":59.08,"longitude":38.4326,"title":"some title","address":"some address"}"#; - let venue_content = InputMessageContent::Venue { - latitude: 59.08, - longitude: 38.4326, - title: String::from("some title"), - address: String::from("some address"), - foursquare_id: None, - foursquare_type: None, - }; + let venue_content = + InputMessageContent::Venue(InputMessageContentVenue { + latitude: 59.08, + longitude: 38.4326, + title: String::from("some title"), + address: String::from("some address"), + foursquare_id: None, + foursquare_type: None, + }); let actual_json = serde_json::to_string(&venue_content).unwrap(); assert_eq!(expected_json, actual_json); @@ -136,12 +150,13 @@ mod tests { fn contact_serialize() { let expected_json = r#"{"phone_number":"+3800000000","first_name":"jhon"}"#; - let contact_content = InputMessageContent::Contact { - phone_number: String::from("+3800000000"), - first_name: String::from("jhon"), - last_name: None, - vcard: None, - }; + let contact_content = + InputMessageContent::Contact(InputMessageContentContact { + phone_number: String::from("+3800000000"), + first_name: String::from("jhon"), + last_name: None, + vcard: None, + }); let actual_json = serde_json::to_string(&contact_content).unwrap(); assert_eq!(expected_json, actual_json); diff --git a/src/types/message.rs b/src/types/message.rs index 2e5cffe7..4e7722d9 100644 --- a/src/types/message.rs +++ b/src/types/message.rs @@ -4,9 +4,11 @@ use serde::{Deserialize, Serialize}; use crate::types::{ chat::{ChatKind, NonPrivateChatKind}, - Animation, Audio, Chat, Contact, Document, Game, InlineKeyboardMarkup, - Invoice, Location, MessageEntity, PassportData, PhotoSize, Poll, Sticker, - SuccessfulPayment, True, User, Venue, Video, VideoNote, Voice, + Animation, Audio, Chat, ChatNonPrivate, Contact, Document, Game, + InlineKeyboardMarkup, Invoice, Location, MessageEntity, + NonPrivateChatChannel, NonPrivateChatSupergroup, PassportData, PhotoSize, + Poll, Sticker, SuccessfulPayment, True, User, Venue, Video, VideoNote, + Voice, }; /// This object represents a message. @@ -28,120 +30,165 @@ pub struct Message { pub kind: MessageKind, } -#[serde_with_macros::skip_serializing_none] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] #[serde(untagged)] pub enum MessageKind { - Common { - /// Sender, empty for messages sent to channels. - from: Option, + Common(MessageCommon), + NewChatMembers(MessageNewChatMembers), + LeftChatMember(MessageLeftChatMember), + NewChatTitle(MessageNewChatTitle), + NewChatPhoto(MessageNewChatPhoto), + DeleteChatPhoto(MessageDeleteChatPhoto), + GroupChatCreated(MessageGroupChatCreated), + SupergroupChatCreated(MessageSupergroupChatCreated), + ChannelChatCreated(MessageChannelChatCreated), + Migrate(MessageMigrate), + Pinned(MessagePinned), + Invoice(MessageInvoice), + SuccessfulPayment(MessageSuccessfulPayment), + ConnectedWebsite(MessageConnectedWebsite), + PassportData(MessagePassportData), +} - #[serde(flatten)] - forward_kind: ForwardKind, +#[serde_with_macros::skip_serializing_none] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct MessageCommon { + /// Sender, empty for messages sent to channels. + pub from: Option, - /// Date the message was last edited in Unix time. - edit_date: Option, + #[serde(flatten)] + pub forward_kind: ForwardKind, - #[serde(flatten)] - media_kind: MediaKind, + /// Date the message was last edited in Unix time. + pub edit_date: Option, - /// Inline keyboard attached to the message. `login_url` buttons are - /// represented as ordinary `url` buttons. - reply_markup: Option, - }, - NewChatMembers { - /// New members that were added to the group or supergroup and - /// information about them (the bot itself may be one of these - /// members). - new_chat_members: Vec, - }, - LeftChatMember { - /// A member was removed from the group, information about them (this - /// member may be the bot itself). - left_chat_member: User, - }, - NewChatTitle { - /// A chat title was changed to this value. - new_chat_title: String, - }, - NewChatPhoto { - /// A chat photo was change to this value. - new_chat_photo: Vec, - }, - DeleteChatPhoto { - /// Service message: the chat photo was deleted. - delete_chat_photo: True, - }, - GroupChatCreated { - /// Service message: the group has been created. - group_chat_created: True, - }, - SupergroupChatCreated { - /// Service message: the supergroup has been created. This field can‘t - /// be received in a message coming through updates, because bot can’t - /// be a member of a supergroup when it is created. It can only be - /// found in `reply_to_message` if someone replies to a very first - /// message in a directly created supergroup. - supergroup_chat_created: True, - }, - ChannelChatCreated { - /// Service message: the channel has been created. This field can‘t be - /// received in a message coming through updates, because bot can’t be - /// a member of a channel when it is created. It can only be found in - /// `reply_to_message` if someone replies to a very first message in a - /// channel. - channel_chat_created: True, - }, - Migrate { - /// The group has been migrated to a supergroup with the specified - /// identifier. This number may be greater than 32 bits and some - /// programming languages may have difficulty/silent defects in - /// interpreting it. But it is smaller than 52 bits, so a signed 64 bit - /// integer or double-precision float type are safe for storing this - /// identifier. - migrate_to_chat_id: i64, + #[serde(flatten)] + pub media_kind: MediaKind, - /// The supergroup has been migrated from a group with the specified - /// identifier. This number may be greater than 32 bits and some - /// programming languages may have difficulty/silent defects in - /// interpreting it. But it is smaller than 52 bits, so a signed 64 bit - /// integer or double-precision float type are safe for storing this - /// identifier. - migrate_from_chat_id: i64, - }, - Pinned { - /// Specified message was pinned. Note that the Message object in this - /// field will not contain further `reply_to_message` fields even if it - /// is itself a reply. - #[serde(rename = "pinned_message")] - pinned: Box, - }, - Invoice { - /// Message is an invoice for a [payment], information about the - /// invoice. [More about payments »]. - /// - /// [payment]: https://core.telegram.org/bots/api#payments - /// [More about payments »]: https://core.telegram.org/bots/api#payments - invoice: Invoice, - }, - SuccessfulPayment { - /// Message is a service message about a successful payment, - /// information about the payment. [More about payments »]. - /// - /// [More about payments »]: https://core.telegram.org/bots/api#payments - successful_payment: SuccessfulPayment, - }, - ConnectedWebsite { - /// The domain name of the website on which the user has logged in. - /// [More about Telegram Login »]. - /// - /// [More about Telegram Login »]: https://core.telegram.org/widgets/login - connected_website: String, - }, - PassportData { - /// Telegram Passport data. - passport_data: PassportData, - }, + /// Inline keyboard attached to the message. `login_url` buttons are + /// represented as ordinary `url` buttons. + pub reply_markup: Option, +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct MessageNewChatMembers { + /// New members that were added to the group or supergroup and + /// information about them (the bot itself may be one of these + /// members). + pub new_chat_members: Vec, +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct MessageLeftChatMember { + /// A member was removed from the group, information about them (this + /// member may be the bot itself). + pub left_chat_member: User, +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct MessageNewChatTitle { + /// A chat title was changed to this value. + pub new_chat_title: String, +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct MessageNewChatPhoto { + /// A chat photo was change to this value. + pub new_chat_photo: Vec, +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct MessageDeleteChatPhoto { + /// Service message: the chat photo was deleted. + pub delete_chat_photo: True, +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct MessageGroupChatCreated { + /// Service message: the group has been created. + pub group_chat_created: True, +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct MessageSupergroupChatCreated { + /// Service message: the supergroup has been created. This field can‘t + /// be received in a message coming through updates, because bot can’t + /// be a member of a supergroup when it is created. It can only be + /// found in `reply_to_message` if someone replies to a very first + /// message in a directly created supergroup. + pub supergroup_chat_created: True, +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct MessageChannelChatCreated { + /// Service message: the channel has been created. This field can‘t be + /// received in a message coming through updates, because bot can’t be + /// a member of a channel when it is created. It can only be found in + /// `reply_to_message` if someone replies to a very first message in a + /// channel. + pub channel_chat_created: True, +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct MessageMigrate { + /// The group has been migrated to a supergroup with the specified + /// identifier. This number may be greater than 32 bits and some + /// programming languages may have difficulty/silent defects in + /// interpreting it. But it is smaller than 52 bits, so a signed 64 bit + /// integer or double-precision float type are safe for storing this + /// identifier. + pub migrate_to_chat_id: i64, + + /// The supergroup has been migrated from a group with the specified + /// identifier. This number may be greater than 32 bits and some + /// programming languages may have difficulty/silent defects in + /// interpreting it. But it is smaller than 52 bits, so a signed 64 bit + /// integer or double-precision float type are safe for storing this + /// identifier. + pub migrate_from_chat_id: i64, +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct MessagePinned { + /// Specified message was pinned. Note that the Message object in this + /// field will not contain further `reply_to_message` fields even if it + /// is itself a reply. + #[serde(rename = "pinned_message")] + pub pinned: Box, +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct MessageInvoice { + /// Message is an invoice for a [payment], information about the + /// invoice. [More about payments »]. + /// + /// [payment]: https://core.telegram.org/bots/api#payments + /// [More about payments »]: https://core.telegram.org/bots/api#payments + pub invoice: Invoice, +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct MessageSuccessfulPayment { + /// Message is a service message about a successful payment, + /// information about the payment. [More about payments »]. + /// + /// [More about payments »]: https://core.telegram.org/bots/api#payments + pub successful_payment: SuccessfulPayment, +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct MessageConnectedWebsite { + /// The domain name of the website on which the user has logged in. + /// [More about Telegram Login »]. + /// + /// [More about Telegram Login »]: https://core.telegram.org/widgets/login + pub connected_website: String, +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct MessagePassportData { + /// Telegram Passport data. + pub passport_data: PassportData, } #[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] @@ -155,160 +202,220 @@ pub enum ForwardedFrom { #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] #[serde(untagged)] pub enum ForwardKind { - ChannelForward { - #[serde(rename = "forward_date")] - date: i32, - #[serde(rename = "forward_from_chat")] - chat: Chat, - #[serde(rename = "forward_from_message_id")] - message_id: i32, - #[serde(rename = "forward_signature")] - signature: Option, - }, - NonChannelForward { - #[serde(rename = "forward_date")] - date: i32, - #[serde(flatten)] - from: ForwardedFrom, - }, - Origin { - reply_to_message: Option>, - }, + Channel(ForwardChannel), + NonChannel(ForwardNonChannel), + Origin(ForwardOrigin), +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct ForwardChannel { + #[serde(rename = "forward_date")] + pub date: i32, + + #[serde(rename = "forward_from_chat")] + pub chat: Chat, + + #[serde(rename = "forward_from_message_id")] + pub message_id: i32, + + #[serde(rename = "forward_signature")] + pub signature: Option, +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct ForwardNonChannel { + #[serde(rename = "forward_date")] + pub date: i32, + + #[serde(flatten)] + pub from: ForwardedFrom, +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct ForwardOrigin { + pub reply_to_message: Option>, } #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] #[serde(untagged)] pub enum MediaKind { - Animation { - /// Message is an animation, information about the animation. For - /// backward compatibility, when this field is set, the document field - /// will also be set. - animation: Animation, + Animation(MediaAnimation), + Audio(MediaAudio), + Contact(MediaContact), + Document(MediaDocument), + Game(MediaGame), + Location(MediaLocation), + Photo(MediaPhoto), + Poll(MediaPoll), + Sticker(MediaSticker), + Text(MediaText), + Video(MediaVideo), + VideoNote(MediaVideoNote), + Voice(MediaVoice), + Venue(MediaVenue), +} - #[doc(hidden)] - /// "For backward compatibility" (c) Telegram Docs. - #[serde(skip)] - document: (), +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct MediaAnimation { + /// Message is an animation, information about the animation. For + /// backward compatibility, when this field is set, the document field + /// will also be set. + pub animation: Animation, - /// Caption for the animation, 0-1024 characters. - caption: Option, + #[doc(hidden)] + /// "For backward compatibility" (c) Telegram Docs. + #[serde(skip)] + pub document: (), - /// For messages with a caption, special entities like usernames, URLs, - /// bot commands, etc. that appear in the caption. - #[serde(default = "Vec::new")] - caption_entities: Vec, - }, - Audio { - /// Message is an audio file, information about the file. - audio: Audio, + /// Caption for the animation, 0-1024 characters. + pub caption: Option, - /// Caption for the audio, 0-1024 characters. - caption: Option, + /// For messages with a caption, special entities like usernames, URLs, + /// bot commands, etc. that appear in the caption. + #[serde(default = "Vec::new")] + pub caption_entities: Vec, +} - /// For messages with a caption, special entities like usernames, URLs, - /// bot commands, etc. that appear in the caption. - #[serde(default = "Vec::new")] - caption_entities: Vec, - }, - Contact { - /// Message is a shared contact, information about the contact. - contact: Contact, - }, - Document { - /// Message is a general file, information about the file. - document: Document, +#[serde_with_macros::skip_serializing_none] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct MediaAudio { + /// Message is an audio file, information about the file. + pub audio: Audio, - /// Caption for the document, 0-1024 characters. - caption: Option, + /// Caption for the audio, 0-1024 characters. + pub caption: Option, - /// For messages with a caption, special entities like usernames, URLs, - /// bot commands, etc. that appear in the caption. - #[serde(default = "Vec::new")] - caption_entities: Vec, - }, - Game { - /// Message is a game, information about the game. [More - /// about games »]. - /// - /// [More about games »]: https://core.telegram.org/bots/api#games - game: Game, - }, - Location { - /// Message is a shared location, information about the location. - location: Location, - }, - Photo { - /// Message is a photo, available sizes of the photo. - photo: Vec, + /// For messages with a caption, special entities like usernames, URLs, + /// bot commands, etc. that appear in the caption. + #[serde(default = "Vec::new")] + pub caption_entities: Vec, +} - /// Caption for the photo, 0-1024 characters. - caption: Option, +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct MediaContact { + /// Message is a shared contact, information about the contact. + contact: Contact, +} - /// For messages with a caption, special entities like usernames, URLs, - /// bot commands, etc. that appear in the caption. - #[serde(default = "Vec::new")] - caption_entities: Vec, +#[serde_with_macros::skip_serializing_none] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct MediaDocument { + /// Message is a general file, information about the file. + pub document: Document, - /// The unique identifier of a media message group this message belongs - /// to. - media_group_id: Option, - }, - Poll { - /// Message is a native poll, information about the poll. - poll: Poll, - }, - Sticker { - /// Message is a sticker, information about the sticker. - sticker: Sticker, - }, - Text { - /// For text messages, the actual UTF-8 text of the message, 0-4096 - /// characters. - text: String, + /// Caption for the document, 0-1024 characters. + pub caption: Option, - /// For text messages, special entities like usernames, URLs, bot - /// commands, etc. that appear in the text. - #[serde(default = "Vec::new")] - entities: Vec, - }, - Video { - /// Message is a video, information about the video. - video: Video, + /// For messages with a caption, special entities like usernames, URLs, + /// bot commands, etc. that appear in the caption. + #[serde(default = "Vec::new")] + pub caption_entities: Vec, +} - /// Caption for the video, 0-1024 characters. - caption: Option, +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct MediaGame { + /// Message is a game, information about the game. [More + /// about games »]. + /// + /// [More about games »]: https://core.telegram.org/bots/api#games + pub game: Game, +} - /// For messages with a caption, special entities like usernames, URLs, - /// bot commands, etc. that appear in the caption. - #[serde(default = "Vec::new")] - caption_entities: Vec, +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct MediaLocation { + /// Message is a shared location, information about the location. + pub location: Location, +} - /// The unique identifier of a media message group this message belongs - /// to. - media_group_id: Option, - }, - VideoNote { - /// Message is a [video note], information about the video message. - /// - /// [video note]: https://telegram.org/blog/video-messages-and-telescope - video_note: VideoNote, - }, - Voice { - /// Message is a voice message, information about the file. - voice: Voice, +#[serde_with_macros::skip_serializing_none] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct MediaPhoto { + /// Message is a photo, available sizes of the photo. + pub photo: Vec, - /// Caption for the voice, 0-1024 characters. - caption: Option, + /// Caption for the photo, 0-1024 characters. + pub caption: Option, - /// For messages with a caption, special entities like usernames, URLs, - /// bot commands, etc. that appear in the caption. - #[serde(default = "Vec::new")] - caption_entities: Vec, - }, - Venue { - /// Message is a venue, information about the venue. - venue: Venue, - }, + /// For messages with a caption, special entities like usernames, URLs, + /// bot commands, etc. that appear in the caption. + #[serde(default = "Vec::new")] + pub caption_entities: Vec, + + /// The unique identifier of a media message group this message belongs + /// to. + pub media_group_id: Option, +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct MediaPoll { + /// Message is a native poll, information about the poll. + pub poll: Poll, +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct MediaSticker { + /// Message is a sticker, information about the sticker. + pub sticker: Sticker, +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct MediaText { + /// For text messages, the actual UTF-8 text of the message, 0-4096 + /// characters. + pub text: String, + + /// For text messages, special entities like usernames, URLs, bot + /// commands, etc. that appear in the text. + #[serde(default = "Vec::new")] + pub entities: Vec, +} + +#[serde_with_macros::skip_serializing_none] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct MediaVideo { + /// Message is a video, information about the video. + pub video: Video, + + /// Caption for the video, 0-1024 characters. + pub caption: Option, + + /// For messages with a caption, special entities like usernames, URLs, + /// bot commands, etc. that appear in the caption. + #[serde(default = "Vec::new")] + pub caption_entities: Vec, + + /// The unique identifier of a media message group this message belongs + /// to. + pub media_group_id: Option, +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct MediaVideoNote { + /// Message is a [video note], information about the video message. + /// + /// [video note]: https://telegram.org/blog/video-messages-and-telescope + pub video_note: VideoNote, +} + +#[serde_with_macros::skip_serializing_none] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct MediaVoice { + /// Message is a voice message, information about the file. + pub voice: Voice, + + /// Caption for the voice, 0-1024 characters. + pub caption: Option, + + /// For messages with a caption, special entities like usernames, URLs, + /// bot commands, etc. that appear in the caption. + #[serde(default = "Vec::new")] + pub caption_entities: Vec, +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct MediaVenue { + /// Message is a venue, information about the venue. + pub venue: Venue, } mod getters { @@ -317,11 +424,7 @@ mod getters { use crate::types::{ self, message::{ - ForwardKind::{ChannelForward, NonChannelForward, Origin}, - MediaKind::{ - Animation, Audio, Contact, Document, Game, Location, Photo, - Poll, Sticker, Text, Venue, Video, VideoNote, Voice, - }, + ForwardKind::NonChannel, MessageKind::{ ChannelChatCreated, Common, ConnectedWebsite, DeleteChatPhoto, GroupChatCreated, Invoice, LeftChatMember, Migrate, @@ -329,7 +432,17 @@ mod getters { Pinned, SuccessfulPayment, SupergroupChatCreated, }, }, - Chat, ForwardedFrom, Message, MessageEntity, PhotoSize, True, User, + Chat, ForwardChannel, ForwardKind, ForwardNonChannel, ForwardOrigin, + ForwardedFrom, MediaAnimation, MediaAudio, MediaContact, MediaDocument, + MediaGame, MediaKind, MediaLocation, MediaPhoto, MediaPoll, + MediaSticker, MediaText, MediaVenue, MediaVideo, MediaVideoNote, + MediaVoice, Message, MessageChannelChatCreated, MessageCommon, + MessageConnectedWebsite, MessageDeleteChatPhoto, MessageEntity, + MessageGroupChatCreated, MessageInvoice, MessageLeftChatMember, + MessageMigrate, MessageNewChatMembers, MessageNewChatPhoto, + MessageNewChatTitle, MessagePassportData, MessagePinned, + MessageSuccessfulPayment, MessageSupergroupChatCreated, PhotoSize, + True, User, }; /// Getters for [Message] fields from [telegram docs]. @@ -340,7 +453,7 @@ mod getters { /// NOTE: this is getter for both `from` and `author_signature` pub fn from(&self) -> Option<&User> { match &self.kind { - Common { from, .. } => from.as_ref(), + Common(MessageCommon { from, .. }) => from.as_ref(), _ => None, } } @@ -353,84 +466,105 @@ mod getters { /// `forward_sender_name` pub fn forward_from(&self) -> Option<&ForwardedFrom> { match &self.kind { - Common { - forward_kind: NonChannelForward { from, .. }, .. - } => Some(from), + Common(MessageCommon { + forward_kind: NonChannel(ForwardNonChannel { from, .. }), + .. + }) => Some(from), _ => None, } } pub fn forward_from_chat(&self) -> Option<&Chat> { match &self.kind { - Common { - forward_kind: ChannelForward { chat, .. }, .. - } => Some(chat), + Common(MessageCommon { + forward_kind: + ForwardKind::Channel(ForwardChannel { chat, .. }), + .. + }) => Some(chat), _ => None, } } pub fn forward_from_message_id(&self) -> Option<&i32> { match &self.kind { - Common { - forward_kind: ChannelForward { message_id, .. }, + Common(MessageCommon { + forward_kind: + ForwardKind::Channel(ForwardChannel { message_id, .. }), .. - } => Some(message_id), + }) => Some(message_id), _ => None, } } pub fn forward_signature(&self) -> Option<&str> { match &self.kind { - Common { - forward_kind: ChannelForward { signature, .. }, + Common(MessageCommon { + forward_kind: + ForwardKind::Channel(ForwardChannel { signature, .. }), .. - } => signature.as_ref().map(Deref::deref), + }) => signature.as_ref().map(Deref::deref), _ => None, } } pub fn forward_date(&self) -> Option<&i32> { match &self.kind { - Common { - forward_kind: ChannelForward { date, .. }, .. - } - | Common { - forward_kind: NonChannelForward { date, .. }, .. - } => Some(date), + Common(MessageCommon { + forward_kind: + ForwardKind::Channel(ForwardChannel { date, .. }), + .. + }) + | Common(MessageCommon { + forward_kind: + ForwardKind::NonChannel(ForwardNonChannel { date, .. }), + .. + }) => Some(date), _ => None, } } pub fn reply_to_message(&self) -> Option<&Message> { match &self.kind { - Common { - forward_kind: Origin { reply_to_message, .. }, + Common(MessageCommon { + forward_kind: + ForwardKind::Origin(ForwardOrigin { + reply_to_message, .. + }), .. - } => reply_to_message.as_ref().map(Deref::deref), + }) => reply_to_message.as_ref().map(Deref::deref), _ => None, } } pub fn edit_date(&self) -> Option<&i32> { match &self.kind { - Common { edit_date, .. } => edit_date.as_ref(), + Common(MessageCommon { edit_date, .. }) => edit_date.as_ref(), _ => None, } } pub fn media_group_id(&self) -> Option<&str> { match &self.kind { - Common { media_kind: Video { media_group_id, .. }, .. } - | Common { media_kind: Photo { media_group_id, .. }, .. } => { - media_group_id.as_ref().map(Deref::deref) - } + Common(MessageCommon { + media_kind: + MediaKind::Video(MediaVideo { media_group_id, .. }), + .. + }) + | Common(MessageCommon { + media_kind: + MediaKind::Photo(MediaPhoto { media_group_id, .. }), + .. + }) => media_group_id.as_ref().map(Deref::deref), _ => None, } } pub fn text(&self) -> Option<&str> { match &self.kind { - Common { media_kind: Text { text, .. }, .. } => Some(text), + Common(MessageCommon { + media_kind: MediaKind::Text(MediaText { text, .. }), + .. + }) => Some(text), _ => None, } } @@ -441,119 +575,159 @@ mod getters { pub fn entities(&self) -> Option<&[MessageEntity]> { match &self.kind { - Common { media_kind: Text { entities, .. }, .. } => { - Some(entities) - } + Common(MessageCommon { + media_kind: MediaKind::Text(MediaText { entities, .. }), + .. + }) => Some(entities), _ => None, } } pub fn caption_entities(&self) -> Option<&[MessageEntity]> { match &self.kind { - Common { - media_kind: Animation { caption_entities, .. }, + Common(MessageCommon { + media_kind: + MediaKind::Animation(MediaAnimation { + caption_entities, + .. + }), .. - } - | Common { - media_kind: Audio { caption_entities, .. }, .. - } - | Common { - media_kind: Document { caption_entities, .. }, + }) + | Common(MessageCommon { + media_kind: + MediaKind::Audio(MediaAudio { caption_entities, .. }), .. - } - | Common { - media_kind: Photo { caption_entities, .. }, .. - } - | Common { - media_kind: Video { caption_entities, .. }, .. - } - | Common { - media_kind: Voice { caption_entities, .. }, .. - } => Some(caption_entities), + }) + | Common(MessageCommon { + media_kind: + MediaKind::Document(MediaDocument { + caption_entities, .. + }), + .. + }) + | Common(MessageCommon { + media_kind: + MediaKind::Photo(MediaPhoto { caption_entities, .. }), + .. + }) + | Common(MessageCommon { + media_kind: + MediaKind::Video(MediaVideo { caption_entities, .. }), + .. + }) + | Common(MessageCommon { + media_kind: + MediaKind::Voice(MediaVoice { caption_entities, .. }), + .. + }) => Some(caption_entities), _ => None, } } pub fn audio(&self) -> Option<&types::Audio> { match &self.kind { - Common { media_kind: Audio { audio, .. }, .. } => Some(audio), + Common(MessageCommon { + media_kind: MediaKind::Audio(MediaAudio { audio, .. }), + .. + }) => Some(audio), _ => None, } } pub fn document(&self) -> Option<&types::Document> { match &self.kind { - Common { media_kind: Document { document, .. }, .. } => { - Some(document) - } + Common(MessageCommon { + media_kind: + MediaKind::Document(MediaDocument { document, .. }), + .. + }) => Some(document), _ => None, } } pub fn animation(&self) -> Option<&types::Animation> { match &self.kind { - Common { media_kind: Animation { animation, .. }, .. } => { - Some(animation) - } + Common(MessageCommon { + media_kind: + MediaKind::Animation(MediaAnimation { animation, .. }), + .. + }) => Some(animation), _ => None, } } pub fn game(&self) -> Option<&types::Game> { match &self.kind { - Common { media_kind: Game { game, .. }, .. } => Some(game), + Common(MessageCommon { + media_kind: MediaKind::Game(MediaGame { game, .. }), + .. + }) => Some(game), _ => None, } } pub fn photo(&self) -> Option<&[PhotoSize]> { match &self.kind { - Common { media_kind: Photo { photo, .. }, .. } => Some(photo), + Common(MessageCommon { + media_kind: MediaKind::Photo(MediaPhoto { photo, .. }), + .. + }) => Some(photo), _ => None, } } pub fn sticker(&self) -> Option<&types::Sticker> { match &self.kind { - Common { media_kind: Sticker { sticker, .. }, .. } => { - Some(sticker) - } + Common(MessageCommon { + media_kind: MediaKind::Sticker(MediaSticker { sticker, .. }), + .. + }) => Some(sticker), _ => None, } } pub fn video(&self) -> Option<&types::Video> { match &self.kind { - Common { media_kind: Video { video, .. }, .. } => Some(video), + Common(MessageCommon { + media_kind: MediaKind::Video(MediaVideo { video, .. }), + .. + }) => Some(video), _ => None, } } pub fn voice(&self) -> Option<&types::Voice> { match &self.kind { - Common { media_kind: Voice { voice, .. }, .. } => Some(voice), + Common(MessageCommon { + media_kind: MediaKind::Voice(MediaVoice { voice, .. }), + .. + }) => Some(voice), _ => None, } } pub fn video_note(&self) -> Option<&types::VideoNote> { match &self.kind { - Common { media_kind: VideoNote { video_note, .. }, .. } => { - Some(video_note) - } + Common(MessageCommon { + media_kind: + MediaKind::VideoNote(MediaVideoNote { video_note, .. }), + .. + }) => Some(video_note), _ => None, } } pub fn caption(&self) -> Option<&str> { match &self.kind { - Common { media_kind, .. } => match media_kind { - Animation { caption, .. } - | Audio { caption, .. } - | Document { caption, .. } - | Photo { caption, .. } - | Video { caption, .. } - | Voice { caption, .. } => { + Common(MessageCommon { media_kind, .. }) => match media_kind { + MediaKind::Animation(MediaAnimation { + caption, .. + }) + | MediaKind::Audio(MediaAudio { caption, .. }) + | MediaKind::Document(MediaDocument { caption, .. }) + | MediaKind::Photo(MediaPhoto { caption, .. }) + | MediaKind::Video(MediaVideo { caption, .. }) + | MediaKind::Voice(MediaVoice { caption, .. }) => { caption.as_ref().map(Deref::deref) } _ => None, @@ -564,58 +738,77 @@ mod getters { pub fn contact(&self) -> Option<&types::Contact> { match &self.kind { - Common { media_kind: Contact { contact }, .. } => Some(contact), + Common(MessageCommon { + media_kind: MediaKind::Contact(MediaContact { contact, .. }), + .. + }) => Some(contact), _ => None, } } pub fn location(&self) -> Option<&types::Location> { match &self.kind { - Common { media_kind: Location { location, .. }, .. } => { - Some(location) - } + Common(MessageCommon { + media_kind: + MediaKind::Location(MediaLocation { location, .. }), + .. + }) => Some(location), _ => None, } } pub fn venue(&self) -> Option<&types::Venue> { match &self.kind { - Common { media_kind: Venue { venue, .. }, .. } => Some(venue), + Common(MessageCommon { + media_kind: MediaKind::Venue(MediaVenue { venue, .. }), + .. + }) => Some(venue), _ => None, } } pub fn poll(&self) -> Option<&types::Poll> { match &self.kind { - Common { media_kind: Poll { poll, .. }, .. } => Some(poll), + Common(MessageCommon { + media_kind: MediaKind::Poll(MediaPoll { poll, .. }), + .. + }) => Some(poll), _ => None, } } pub fn new_chat_members(&self) -> Option<&[User]> { match &self.kind { - NewChatMembers { new_chat_members } => Some(new_chat_members), + NewChatMembers(MessageNewChatMembers { new_chat_members }) => { + Some(new_chat_members.as_ref()) + } _ => None, } } pub fn left_chat_member(&self) -> Option<&User> { match &self.kind { - LeftChatMember { left_chat_member } => Some(left_chat_member), + LeftChatMember(MessageLeftChatMember { left_chat_member }) => { + Some(left_chat_member) + } _ => None, } } pub fn new_chat_title(&self) -> Option<&str> { match &self.kind { - NewChatTitle { new_chat_title } => Some(new_chat_title), + NewChatTitle(MessageNewChatTitle { new_chat_title }) => { + Some(new_chat_title) + } _ => None, } } pub fn new_chat_photo(&self) -> Option<&[PhotoSize]> { match &self.kind { - NewChatPhoto { new_chat_photo } => Some(new_chat_photo), + NewChatPhoto(MessageNewChatPhoto { new_chat_photo }) => { + Some(new_chat_photo) + } _ => None, } } @@ -624,50 +817,52 @@ mod getters { // mb smt like `is_delete_chat_photo(&self) -> bool`? pub fn delete_chat_photo(&self) -> Option { match &self.kind { - DeleteChatPhoto { delete_chat_photo } => { - Some(*delete_chat_photo) - } + DeleteChatPhoto(MessageDeleteChatPhoto { + delete_chat_photo, + }) => Some(*delete_chat_photo), _ => None, } } pub fn group_chat_created(&self) -> Option { match &self.kind { - GroupChatCreated { group_chat_created } => { - Some(*group_chat_created) - } + GroupChatCreated(MessageGroupChatCreated { + group_chat_created, + }) => Some(*group_chat_created), _ => None, } } pub fn super_group_chat_created(&self) -> Option { match &self.kind { - SupergroupChatCreated { supergroup_chat_created } => { - Some(*supergroup_chat_created) - } + SupergroupChatCreated(MessageSupergroupChatCreated { + supergroup_chat_created, + }) => Some(*supergroup_chat_created), _ => None, } } pub fn channel_chat_created(&self) -> Option { match &self.kind { - ChannelChatCreated { channel_chat_created } => { - Some(*channel_chat_created) - } + ChannelChatCreated(MessageChannelChatCreated { + channel_chat_created, + }) => Some(*channel_chat_created), _ => None, } } pub fn migrate_to_chat_id(&self) -> Option { match &self.kind { - Migrate { migrate_to_chat_id, .. } => Some(*migrate_to_chat_id), + Migrate(MessageMigrate { migrate_to_chat_id, .. }) => { + Some(*migrate_to_chat_id) + } _ => None, } } pub fn migrate_from_chat_id(&self) -> Option { match &self.kind { - Migrate { migrate_from_chat_id, .. } => { + Migrate(MessageMigrate { migrate_from_chat_id, .. }) => { Some(*migrate_from_chat_id) } _ => None, @@ -676,46 +871,50 @@ mod getters { pub fn pinned_message(&self) -> Option<&Message> { match &self.kind { - Pinned { pinned } => Some(pinned), + Pinned(MessagePinned { pinned }) => Some(pinned), _ => None, } } pub fn invoice(&self) -> Option<&types::Invoice> { match &self.kind { - Invoice { invoice } => Some(invoice), + Invoice(MessageInvoice { invoice }) => Some(invoice), _ => None, } } pub fn successful_payment(&self) -> Option<&types::SuccessfulPayment> { match &self.kind { - SuccessfulPayment { successful_payment } => { - Some(successful_payment) - } + SuccessfulPayment(MessageSuccessfulPayment { + successful_payment, + }) => Some(successful_payment), _ => None, } } pub fn connected_website(&self) -> Option<&str> { match &self.kind { - ConnectedWebsite { connected_website } => { - Some(connected_website) - } + ConnectedWebsite(MessageConnectedWebsite { + connected_website, + }) => Some(connected_website), _ => None, } } pub fn passport_data(&self) -> Option<&types::PassportData> { match &self.kind { - PassportData { passport_data } => Some(passport_data), + PassportData(MessagePassportData { passport_data }) => { + Some(passport_data) + } _ => None, } } pub fn reply_markup(&self) -> Option<&types::InlineKeyboardMarkup> { match &self.kind { - Common { reply_markup, .. } => reply_markup.as_ref(), + Common(MessageCommon { reply_markup, .. }) => { + reply_markup.as_ref() + } _ => None, } } @@ -725,17 +924,21 @@ mod getters { impl Message { pub fn url(&self) -> Option { match &self.chat.kind { - ChatKind::NonPrivate { - kind: NonPrivateChatKind::Channel { username: Some(username) }, - .. - } - | ChatKind::NonPrivate { + ChatKind::NonPrivate(ChatNonPrivate { kind: - NonPrivateChatKind::Supergroup { - username: Some(username), .. - }, + NonPrivateChatKind::Channel(NonPrivateChatChannel { + username: Some(username), + }), .. - } => Some( + }) + | ChatKind::NonPrivate(ChatNonPrivate { + kind: + NonPrivateChatKind::Supergroup(NonPrivateChatSupergroup { + username: Some(username), + .. + }), + .. + }) => Some( reqwest::Url::parse( format!("https://t.me/{0}/{1}/", username, self.id) .as_str(), diff --git a/src/types/message_entity.rs b/src/types/message_entity.rs index b5f45327..39cc32b9 100644 --- a/src/types/message_entity.rs +++ b/src/types/message_entity.rs @@ -50,7 +50,10 @@ impl MessageEntity { #[cfg(test)] mod tests { use super::*; - use crate::types::{Chat, ChatKind, ForwardKind, MediaKind, MessageKind}; + use crate::types::{ + Chat, ChatKind, ChatPrivate, ForwardKind, ForwardOrigin, MediaKind, + MediaText, MessageCommon, MessageKind, + }; #[test] fn recursive_kind() { @@ -103,15 +106,15 @@ mod tests { date: 0, chat: Chat { id: 0, - kind: ChatKind::Private { + kind: ChatKind::Private(ChatPrivate { type_: (), username: None, first_name: None, last_name: None, - }, + }), photo: None, }, - kind: MessageKind::Common { + kind: MessageKind::Common(MessageCommon { from: Some(User { id: 0, is_bot: false, @@ -120,18 +123,20 @@ mod tests { username: None, language_code: None, }), - forward_kind: ForwardKind::Origin { reply_to_message: None }, + forward_kind: ForwardKind::Origin(ForwardOrigin { + reply_to_message: None, + }), edit_date: None, - media_kind: MediaKind::Text { + media_kind: MediaKind::Text(MediaText { text: "no yes no".to_string(), entities: vec![MessageEntity { kind: MessageEntityKind::Mention, offset: 3, length: 3, }], - }, + }), reply_markup: None, - }, + }), } } } diff --git a/src/types/passport_element_error.rs b/src/types/passport_element_error.rs index 9657969f..21e47ee7 100644 --- a/src/types/passport_element_error.rs +++ b/src/types/passport_element_error.rs @@ -17,133 +17,160 @@ pub struct PassportElementError { #[serde(tag = "source")] #[derive(Clone, Debug, Hash, Eq, PartialEq, Serialize, Deserialize)] pub enum PassportElementErrorKind { - /// Represents an issue in one of the data fields that was provided by the - /// user. The error is considered resolved when the field's value changes. - /// - /// [The official docs](https://core.telegram.org/bots/api#passportelementerrordatafield). #[serde(rename = "data")] - DataField { - /// The section of the user's Telegram Passport which has the error. - r#type: PassportElementErrorDataFieldType, + DataField(PassportElementErrorDataField), - /// Name of the data field which has the error. - field_name: String, - - /// Base64-encoded data hash. - data_hash: String, - }, - - /// Represents an issue with the front side of a document. The error is - /// considered resolved when the file with the front side of the document - /// changes. - /// - /// [The official docs](https://core.telegram.org/bots/api#passportelementerrorfrontside). #[serde(rename = "snake_case")] - FrontSide { - /// The section of the user's Telegram Passport which has the issue. - r#type: PassportElementErrorFrontSideType, + FrontSide(PassportElementErrorFrontSide), - /// Base64-encoded hash of the file with the front side of the - /// document. - file_hash: String, - }, - - /// Represents an issue with the reverse side of a document. The error is - /// considered resolved when the file with reverse side of the document - /// changes. - /// - /// [The official docs](https://core.telegram.org/bots/api#passportelementerrorreverseside). #[serde(rename = "snake_case")] - ReverseSide { - /// The section of the user's Telegram Passport which has the issue. - r#type: PassportElementErrorReverseSideType, + ReverseSide(PassportElementErrorReverseSide), - //// Base64-encoded hash of the file with the reverse side of the - //// document. - file_hash: String, - }, - - //// Represents an issue with the selfie with a document. The error is - //// considered resolved when the file with the selfie changes. - /// - /// [The official docs](https://core.telegram.org/bots/api#passportelementerrorselfie). #[serde(rename = "snake_case")] - Selfie { - /// The section of the user's Telegram Passport which has the issue. - r#type: PassportElementErrorSelfieType, + Selfie(PassportElementErrorSelfie), - /// Base64-encoded hash of the file with the selfie. - file_hash: String, - }, - - /// Represents an issue with a document scan. The error is considered - /// resolved when the file with the document scan changes. - /// - /// [The official docs](https://core.telegram.org/bots/api#passportelementerrorfile). #[serde(rename = "snake_case")] - File { - /// The section of the user's Telegram Passport which has the issue. - r#type: PassportElementErrorFileType, + File(PassportElementErrorFile), - /// Base64-encoded file hash. - file_hash: String, - }, - - /// Represents an issue with a list of scans. The error is considered - /// resolved when the list of files containing the scans changes. - /// - /// [The official docs](https://core.telegram.org/bots/api#passportelementerrorfiles). #[serde(rename = "snake_case")] - Files { - /// The section of the user's Telegram Passport which has the issue. - r#type: PassportElementErrorFilesType, + Files(PassportElementErrorFiles), - /// List of base64-encoded file hashes. - file_hashes: Vec, - }, - - /// Represents an issue with one of the files that constitute the - /// translation of a document. The error is considered resolved when the - /// file changes. - /// - /// [The official docs](https://core.telegram.org/bots/api#passportelementerrortranslationfile). #[serde(rename = "snake_case")] - TranslationFile { - /// Type of element of the user's Telegram Passport which has the - /// issue. - r#type: PassportElementErrorTranslationFileType, + TranslationFile(PassportElementErrorTranslationFile), - /// Base64-encoded file hash. - file_hash: String, - }, - - /// Represents an issue with the translated version of a document. The - /// error is considered resolved when a file with the document translation - /// change. - /// - /// [The official docs](https://core.telegram.org/bots/api#passportelementerrortranslationfiles). #[serde(rename = "snake_case")] - TranslationFiles { - /// Type of element of the user's Telegram Passport which has the issue - r#type: PassportElementErrorTranslationFilesType, + TranslationFiles(PassportElementErrorTranslationFiles), - /// List of base64-encoded file hashes - file_hashes: Vec, - }, - - /// Represents an issue in an unspecified place. The error is considered - /// resolved when new data is added. - /// - /// [The official docs](https://core.telegram.org/bots/api#passportelementerrorunspecified). #[serde(rename = "snake_case")] - Unspecified { - /// Type of element of the user's Telegram Passport which has the - /// issue. - r#type: PassportElementErrorUnspecifiedType, + Unspecified(PassportElementErrorUnspecified), +} - /// Base64-encoded element hash. - element_hash: String, - }, +/// Represents an issue in one of the data fields that was provided by the +/// user. The error is considered resolved when the field's value changes. +/// +/// [The official docs](https://core.telegram.org/bots/api#passportelementerrordatafield). +#[derive(Clone, Debug, Hash, Eq, PartialEq, Serialize, Deserialize)] +pub struct PassportElementErrorDataField { + /// The section of the user's Telegram Passport which has the error. + pub r#type: PassportElementErrorDataFieldType, + + /// Name of the data field which has the error. + pub field_name: String, + + /// Base64-encoded data hash. + pub data_hash: String, +} + +/// Represents an issue with the front side of a document. The error is +/// considered resolved when the file with the front side of the document +/// changes. +/// +/// [The official docs](https://core.telegram.org/bots/api#passportelementerrorfrontside). +#[derive(Clone, Debug, Hash, Eq, PartialEq, Serialize, Deserialize)] +pub struct PassportElementErrorFrontSide { + /// The section of the user's Telegram Passport which has the issue. + pub r#type: PassportElementErrorFrontSideType, + + /// Base64-encoded hash of the file with the front side of the + /// document. + pub file_hash: String, +} + +/// Represents an issue with the reverse side of a document. The error is +/// considered resolved when the file with reverse side of the document +/// changes. +/// +/// [The official docs](https://core.telegram.org/bots/api#passportelementerrorreverseside). +#[derive(Clone, Debug, Hash, Eq, PartialEq, Serialize, Deserialize)] +pub struct PassportElementErrorReverseSide { + /// The section of the user's Telegram Passport which has the issue. + pub r#type: PassportElementErrorReverseSideType, + + //// Base64-encoded hash of the file with the reverse side of the + //// document. + pub file_hash: String, +} + +//// Represents an issue with the selfie with a document. The error is +//// considered resolved when the file with the selfie changes. +/// +/// [The official docs](https://core.telegram.org/bots/api#passportelementerrorselfie). +#[derive(Clone, Debug, Hash, Eq, PartialEq, Serialize, Deserialize)] +pub struct PassportElementErrorSelfie { + /// The section of the user's Telegram Passport which has the issue. + pub r#type: PassportElementErrorSelfieType, + + /// Base64-encoded hash of the file with the selfie. + pub file_hash: String, +} + +/// Represents an issue with a document scan. The error is considered +/// resolved when the file with the document scan changes. +/// +/// [The official docs](https://core.telegram.org/bots/api#passportelementerrorfile). +#[derive(Clone, Debug, Hash, Eq, PartialEq, Serialize, Deserialize)] +pub struct PassportElementErrorFile { + /// The section of the user's Telegram Passport which has the issue. + pub r#type: PassportElementErrorFileType, + + /// Base64-encoded file hash. + pub file_hash: String, +} + +/// Represents an issue with a list of scans. The error is considered +/// resolved when the list of files containing the scans changes. +/// +/// [The official docs](https://core.telegram.org/bots/api#passportelementerrorfiles). +#[derive(Clone, Debug, Hash, Eq, PartialEq, Serialize, Deserialize)] +pub struct PassportElementErrorFiles { + /// The section of the user's Telegram Passport which has the issue. + pub r#type: PassportElementErrorFilesType, + + /// List of base64-encoded file hashes. + pub file_hashes: Vec, +} + +/// Represents an issue with one of the files that constitute the +/// translation of a document. The error is considered resolved when the +/// file changes. +/// +/// [The official docs](https://core.telegram.org/bots/api#passportelementerrortranslationfile). +#[derive(Clone, Debug, Hash, Eq, PartialEq, Serialize, Deserialize)] +pub struct PassportElementErrorTranslationFile { + /// Type of element of the user's Telegram Passport which has the + /// issue. + pub r#type: PassportElementErrorTranslationFileType, + + /// Base64-encoded file hash. + pub file_hash: String, +} + +/// Represents an issue with the translated version of a document. The +/// error is considered resolved when a file with the document translation +/// change. +/// +/// [The official docs](https://core.telegram.org/bots/api#passportelementerrortranslationfiles). +#[derive(Clone, Debug, Hash, Eq, PartialEq, Serialize, Deserialize)] +pub struct PassportElementErrorTranslationFiles { + /// Type of element of the user's Telegram Passport which has the issue + pub r#type: PassportElementErrorTranslationFilesType, + + /// List of base64-encoded file hashes + pub file_hashes: Vec, +} + +/// Represents an issue in an unspecified place. The error is considered +/// resolved when new data is added. +/// +/// [The official docs](https://core.telegram.org/bots/api#passportelementerrorunspecified). +#[derive(Clone, Debug, Hash, Eq, PartialEq, Serialize, Deserialize)] +pub struct PassportElementErrorUnspecified { + /// Type of element of the user's Telegram Passport which has the + /// issue. + pub r#type: PassportElementErrorUnspecifiedType, + + /// Base64-encoded element hash. + pub element_hash: String, } #[derive(Clone, Copy, Debug, Hash, Eq, PartialEq, Serialize, Deserialize)] @@ -252,11 +279,13 @@ mod tests { fn serialize_data_field() { let data = PassportElementError { message: "This is an error message!".to_owned(), - kind: PassportElementErrorKind::DataField { - r#type: PassportElementErrorDataFieldType::InternalPassport, - field_name: "The field name".to_owned(), - data_hash: "This is a data hash".to_owned(), - }, + kind: PassportElementErrorKind::DataField( + PassportElementErrorDataField { + r#type: PassportElementErrorDataFieldType::InternalPassport, + field_name: "The field name".to_owned(), + data_hash: "This is a data hash".to_owned(), + }, + ), }; assert_eq!( diff --git a/src/types/poll.rs b/src/types/poll.rs index 11248714..085a4c19 100644 --- a/src/types/poll.rs +++ b/src/types/poll.rs @@ -4,6 +4,7 @@ use serde::{Deserialize, Serialize}; /// This object contains information about a poll. /// /// [The official docs](https://core.telegram.org/bots/api#poll). +#[serde_with_macros::skip_serializing_none] #[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] pub struct Poll { /// Unique poll identifier. diff --git a/src/types/update.rs b/src/types/update.rs index 2b3a3e44..31aa9a8c 100644 --- a/src/types/update.rs +++ b/src/types/update.rs @@ -125,8 +125,9 @@ impl Update { #[cfg(test)] mod test { use crate::types::{ - Chat, ChatKind, ForwardKind, MediaKind, Message, MessageKind, Update, - UpdateKind, User, + Chat, ChatKind, ChatPrivate, ForwardKind, ForwardOrigin, MediaKind, + MediaText, Message, MessageCommon, MessageKind, Update, UpdateKind, + User, }; // TODO: more tests for deserialization @@ -161,15 +162,15 @@ mod test { date: 1_569_518_342, chat: Chat { id: 218_485_655, - kind: ChatKind::Private { + kind: ChatKind::Private(ChatPrivate { type_: (), username: Some(String::from("WaffleLapkin")), first_name: Some(String::from("Waffle")), last_name: None, - }, + }), photo: None, }, - kind: MessageKind::Common { + kind: MessageKind::Common(MessageCommon { from: Some(User { id: 218_485_655, is_bot: false, @@ -178,16 +179,16 @@ mod test { username: Some(String::from("WaffleLapkin")), language_code: Some(String::from("en")), }), - forward_kind: ForwardKind::Origin { + forward_kind: ForwardKind::Origin(ForwardOrigin { reply_to_message: None, - }, + }), edit_date: None, - media_kind: MediaKind::Text { + media_kind: MediaKind::Text(MediaText { text: String::from("hello there"), entities: vec![], - }, + }), reply_markup: None, - }, + }), }), };