mirror of
https://github.com/teloxide/teloxide.git
synced 2024-12-23 15:01:45 +01:00
Split big enumerations' variants into new types
This commit is contained in:
parent
157d571251
commit
65e210fff1
10 changed files with 1507 additions and 1164 deletions
|
@ -28,18 +28,24 @@ pub struct Chat {
|
|||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum ChatKind {
|
||||
NonPrivate {
|
||||
NonPrivate(ChatNonPrivate),
|
||||
Private(ChatPrivate),
|
||||
}
|
||||
|
||||
#[serde_with_macros::skip_serializing_none]
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub struct ChatNonPrivate {
|
||||
/// A title, for supergroups, channels and group chats.
|
||||
title: Option<String>,
|
||||
pub title: Option<String>,
|
||||
|
||||
#[serde(flatten)]
|
||||
kind: NonPrivateChatKind,
|
||||
pub kind: NonPrivateChatKind,
|
||||
|
||||
/// A description, for groups, supergroups and channel chats. Returned
|
||||
/// only in [`Bot::get_chat`].
|
||||
///
|
||||
/// [`Bot::get_chat`]: crate::Bot::get_chat
|
||||
description: Option<String>,
|
||||
pub description: Option<String>,
|
||||
|
||||
/// A chat invite link, for groups, supergroups and channel chats. Each
|
||||
/// administrator in a chat generates their own invite links, so the
|
||||
|
@ -51,31 +57,33 @@ pub enum ChatKind {
|
|||
/// crate::Bot::export_chat_invite_link
|
||||
///
|
||||
/// [`Bot::get_chat`]: crate::Bot::get_chat
|
||||
invite_link: Option<String>,
|
||||
pub invite_link: Option<String>,
|
||||
|
||||
/// Pinned message, for groups, supergroups and channels. Returned only
|
||||
/// in [`Bot::get_chat`].
|
||||
///
|
||||
/// [`Bot::get_chat`]: crate::Bot::get_chat
|
||||
pinned_message: Option<Box<Message>>,
|
||||
},
|
||||
Private {
|
||||
pub pinned_message: Option<Box<Message>>,
|
||||
}
|
||||
|
||||
#[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")]
|
||||
type_: (),
|
||||
pub type_: (),
|
||||
|
||||
/// A username, for private chats, supergroups and channels if
|
||||
/// available.
|
||||
username: Option<String>,
|
||||
pub username: Option<String>,
|
||||
|
||||
/// A first name of the other party in a private chat.
|
||||
first_name: Option<String>,
|
||||
pub first_name: Option<String>,
|
||||
|
||||
/// A last name of the other party in a private chat.
|
||||
last_name: Option<String>,
|
||||
},
|
||||
pub last_name: Option<String>,
|
||||
}
|
||||
|
||||
#[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<String>,
|
||||
},
|
||||
Group {
|
||||
/// A default chat member permissions, for groups and supergroups.
|
||||
/// Returned only in [`Bot::get_chat`].
|
||||
Channel(NonPrivateChatChannel),
|
||||
Group(NonPrivateChatGroup),
|
||||
Supergroup(NonPrivateChatSupergroup),
|
||||
}
|
||||
|
||||
#[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<String>,
|
||||
}
|
||||
|
||||
#[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
|
||||
permissions: Option<ChatPermissions>,
|
||||
},
|
||||
Supergroup {
|
||||
pub permissions: Option<ChatPermissions>,
|
||||
}
|
||||
|
||||
#[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.
|
||||
username: Option<String>,
|
||||
pub username: Option<String>,
|
||||
|
||||
/// For supergroups, name of group sticker set. Returned only in
|
||||
/// For supergroups, name of group sticker set. Returned only from
|
||||
/// [`Bot::get_chat`].
|
||||
///
|
||||
/// [`Bot::get_chat`]: crate::Bot::get_chat
|
||||
sticker_set_name: Option<String>,
|
||||
pub sticker_set_name: Option<String>,
|
||||
|
||||
/// `true`, if the bot can change the group sticker set. Returned only
|
||||
/// in [`Bot::get_chat`].
|
||||
/// from [`Bot::get_chat`].
|
||||
///
|
||||
/// [`Bot::get_chat`]: crate::Bot::get_chat
|
||||
can_set_sticker_set: Option<bool>,
|
||||
pub can_set_sticker_set: Option<bool>,
|
||||
|
||||
/// A default chat member permissions, for groups and supergroups.
|
||||
/// Returned only in [`Bot::get_chat`].
|
||||
/// Returned only from [`Bot::get_chat`].
|
||||
///
|
||||
/// [`Bot::get_chat`]: crate::Bot::get_chat
|
||||
permissions: Option<ChatPermissions>,
|
||||
pub permissions: Option<ChatPermissions>,
|
||||
|
||||
/// The minimum allowed delay between consecutive messages sent by each
|
||||
/// unpriviledged user. Returned only in [`Bot::get_chat`].
|
||||
/// unpriviledged user. Returned only from [`Bot::get_chat`].
|
||||
///
|
||||
/// [`Bot::get_chat`]: crate::Bot::get_chat
|
||||
slow_mode_delay: Option<i32>,
|
||||
},
|
||||
pub slow_mode_delay: Option<i32>,
|
||||
}
|
||||
|
||||
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(
|
||||
|
|
|
@ -19,12 +19,27 @@ 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 {
|
||||
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
|
||||
|
@ -33,9 +48,12 @@ pub enum EncryptedPassportElementKind {
|
|||
///
|
||||
/// [`EncryptedCredentials`]:
|
||||
/// crate::types::EncryptedCredentials
|
||||
data: String,
|
||||
},
|
||||
Passport {
|
||||
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
|
||||
|
@ -44,7 +62,7 @@ pub enum EncryptedPassportElementKind {
|
|||
///
|
||||
/// [`EncryptedCredentials`]:
|
||||
/// crate::types::EncryptedCredentials
|
||||
data: String,
|
||||
pub data: String,
|
||||
|
||||
/// Encrypted file with the front side of the document, provided by the
|
||||
/// user. Available for `passport`, `driver_license`, `identity_card`
|
||||
|
@ -53,7 +71,7 @@ pub enum EncryptedPassportElementKind {
|
|||
///
|
||||
/// [`EncryptedCredentials`]:
|
||||
/// crate::types::EncryptedCredentials
|
||||
front_side: PassportFile,
|
||||
pub front_side: PassportFile,
|
||||
|
||||
/// Encrypted file with the selfie of the user holding a document,
|
||||
/// provided by the user; available for `passport`, `driver_license`,
|
||||
|
@ -62,7 +80,7 @@ pub enum EncryptedPassportElementKind {
|
|||
///
|
||||
/// [`EncryptedCredentials`]:
|
||||
/// crate::types::EncryptedCredentials
|
||||
selfie: PassportFile,
|
||||
pub selfie: PassportFile,
|
||||
|
||||
/// Array of encrypted files with translated versions of documents
|
||||
/// provided by the user. Available if requested for `passport`,
|
||||
|
@ -74,9 +92,12 @@ pub enum EncryptedPassportElementKind {
|
|||
///
|
||||
/// [`EncryptedCredentials`]:
|
||||
/// crate::types::EncryptedCredentials
|
||||
translation: Option<Vec<PassportFile>>,
|
||||
},
|
||||
DriverLicense {
|
||||
pub translation: Option<Vec<PassportFile>>,
|
||||
}
|
||||
|
||||
#[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
|
||||
|
@ -85,7 +106,7 @@ pub enum EncryptedPassportElementKind {
|
|||
///
|
||||
/// [`EncryptedCredentials`]:
|
||||
/// crate::types::EncryptedCredentials
|
||||
data: String,
|
||||
pub data: String,
|
||||
|
||||
/// Encrypted file with the front side of the document, provided by the
|
||||
/// user. Available for `passport`, `driver_license`, `identity_card`
|
||||
|
@ -94,7 +115,7 @@ pub enum EncryptedPassportElementKind {
|
|||
///
|
||||
/// [`EncryptedCredentials`]:
|
||||
/// crate::types::EncryptedCredentials
|
||||
front_side: PassportFile,
|
||||
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
|
||||
|
@ -103,7 +124,7 @@ pub enum EncryptedPassportElementKind {
|
|||
///
|
||||
/// [`EncryptedCredentials`]:
|
||||
/// crate::types::EncryptedCredentials
|
||||
reverse_side: PassportFile,
|
||||
pub reverse_side: PassportFile,
|
||||
|
||||
/// Encrypted file with the selfie of the user holding a document,
|
||||
/// provided by the user; available for `passport`, `driver_license`,
|
||||
|
@ -112,7 +133,7 @@ pub enum EncryptedPassportElementKind {
|
|||
///
|
||||
/// [`EncryptedCredentials`]:
|
||||
/// crate::types::EncryptedCredentials
|
||||
selfie: PassportFile,
|
||||
pub selfie: PassportFile,
|
||||
|
||||
/// Array of encrypted files with translated versions of documents
|
||||
/// provided by the user. Available if requested for `passport`,
|
||||
|
@ -124,9 +145,12 @@ pub enum EncryptedPassportElementKind {
|
|||
///
|
||||
/// [`EncryptedCredentials`]:
|
||||
/// crate::types::EncryptedCredentials
|
||||
translation: Option<Vec<PassportFile>>,
|
||||
},
|
||||
IdentityCard {
|
||||
pub translation: Option<Vec<PassportFile>>,
|
||||
}
|
||||
|
||||
#[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
|
||||
|
@ -135,7 +159,7 @@ pub enum EncryptedPassportElementKind {
|
|||
///
|
||||
/// [`EncryptedCredentials`]:
|
||||
/// crate::types::EncryptedCredentials
|
||||
data: String,
|
||||
pub data: String,
|
||||
|
||||
/// Encrypted file with the front side of the document, provided by the
|
||||
/// user. Available for `passport`, `driver_license`, `identity_card`
|
||||
|
@ -144,7 +168,7 @@ pub enum EncryptedPassportElementKind {
|
|||
///
|
||||
/// [`EncryptedCredentials`]:
|
||||
/// crate::types::EncryptedCredentials
|
||||
front_side: PassportFile,
|
||||
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
|
||||
|
@ -153,7 +177,7 @@ pub enum EncryptedPassportElementKind {
|
|||
///
|
||||
/// [`EncryptedCredentials`]:
|
||||
/// crate::types::EncryptedCredentials
|
||||
reverse_side: PassportFile,
|
||||
pub reverse_side: PassportFile,
|
||||
|
||||
/// Encrypted file with the selfie of the user holding a document,
|
||||
/// provided by the user; available for `passport`, `driver_license`,
|
||||
|
@ -162,7 +186,7 @@ pub enum EncryptedPassportElementKind {
|
|||
///
|
||||
/// [`EncryptedCredentials`]:
|
||||
/// crate::types::EncryptedCredentials
|
||||
selfie: PassportFile,
|
||||
pub selfie: PassportFile,
|
||||
|
||||
/// Array of encrypted files with translated versions of documents
|
||||
/// provided by the user. Available if requested for `passport`,
|
||||
|
@ -174,9 +198,13 @@ pub enum EncryptedPassportElementKind {
|
|||
///
|
||||
/// [`EncryptedCredentials`]:
|
||||
/// crate::types::EncryptedCredentials
|
||||
translation: Option<Vec<PassportFile>>,
|
||||
},
|
||||
InternalPassport {
|
||||
pub translation: Option<Vec<PassportFile>>,
|
||||
}
|
||||
|
||||
#[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
|
||||
|
@ -185,7 +213,7 @@ pub enum EncryptedPassportElementKind {
|
|||
///
|
||||
/// [`EncryptedCredentials`]:
|
||||
/// crate::types::EncryptedCredentials
|
||||
data: String,
|
||||
pub data: String,
|
||||
|
||||
/// Encrypted file with the front side of the document, provided by the
|
||||
/// user. Available for `passport`, `driver_license`, `identity_card`
|
||||
|
@ -194,7 +222,7 @@ pub enum EncryptedPassportElementKind {
|
|||
///
|
||||
/// [`EncryptedCredentials`]:
|
||||
/// crate::types::EncryptedCredentials
|
||||
front_side: PassportFile,
|
||||
pub front_side: PassportFile,
|
||||
|
||||
/// Encrypted file with the selfie of the user holding a document,
|
||||
/// provided by the user; available for `passport`, `driver_license`,
|
||||
|
@ -203,7 +231,7 @@ pub enum EncryptedPassportElementKind {
|
|||
///
|
||||
/// [`EncryptedCredentials`]:
|
||||
/// crate::types::EncryptedCredentials
|
||||
selfie: PassportFile,
|
||||
pub selfie: PassportFile,
|
||||
|
||||
/// Array of encrypted files with translated versions of documents
|
||||
/// provided by the user. Available if requested for `passport`,
|
||||
|
@ -215,9 +243,12 @@ pub enum EncryptedPassportElementKind {
|
|||
///
|
||||
/// [`EncryptedCredentials`]:
|
||||
/// crate::types::EncryptedCredentials
|
||||
translation: Option<Vec<PassportFile>>,
|
||||
},
|
||||
Address {
|
||||
pub translation: Option<Vec<PassportFile>>,
|
||||
}
|
||||
|
||||
#[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
|
||||
|
@ -226,9 +257,12 @@ pub enum EncryptedPassportElementKind {
|
|||
///
|
||||
/// [`EncryptedCredentials`]:
|
||||
/// crate::types::EncryptedCredentials
|
||||
data: String,
|
||||
},
|
||||
UtilityBill {
|
||||
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
|
||||
|
@ -237,7 +271,7 @@ pub enum EncryptedPassportElementKind {
|
|||
///
|
||||
/// [`EncryptedCredentials`]:
|
||||
/// crate::types::EncryptedCredentials
|
||||
files: Vec<PassportFile>,
|
||||
pub files: Vec<PassportFile>,
|
||||
|
||||
/// Array of encrypted files with translated versions of documents
|
||||
/// provided by the user. Available if requested for `passport`,
|
||||
|
@ -249,9 +283,13 @@ pub enum EncryptedPassportElementKind {
|
|||
///
|
||||
/// [`EncryptedCredentials`]:
|
||||
/// crate::types::EncryptedCredentials
|
||||
translation: Option<Vec<PassportFile>>,
|
||||
},
|
||||
BankStatement {
|
||||
pub translation: Option<Vec<PassportFile>>,
|
||||
}
|
||||
|
||||
#[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
|
||||
|
@ -260,7 +298,7 @@ pub enum EncryptedPassportElementKind {
|
|||
///
|
||||
/// [`EncryptedCredentials`]:
|
||||
/// crate::types::EncryptedCredentials
|
||||
files: Vec<PassportFile>,
|
||||
pub files: Vec<PassportFile>,
|
||||
|
||||
/// Array of encrypted files with translated versions of documents
|
||||
/// provided by the user. Available if requested for `passport`,
|
||||
|
@ -272,9 +310,12 @@ pub enum EncryptedPassportElementKind {
|
|||
///
|
||||
/// [`EncryptedCredentials`]:
|
||||
/// crate::types::EncryptedCredentials
|
||||
translation: Option<Vec<PassportFile>>,
|
||||
},
|
||||
RentalAgreement {
|
||||
pub translation: Option<Vec<PassportFile>>,
|
||||
}
|
||||
|
||||
#[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
|
||||
|
@ -283,7 +324,7 @@ pub enum EncryptedPassportElementKind {
|
|||
///
|
||||
/// [`EncryptedCredentials`]:
|
||||
/// crate::types::EncryptedCredentials
|
||||
files: Vec<PassportFile>,
|
||||
pub files: Vec<PassportFile>,
|
||||
|
||||
/// Array of encrypted files with translated versions of documents
|
||||
/// provided by the user. Available if requested for `passport`,
|
||||
|
@ -295,9 +336,13 @@ pub enum EncryptedPassportElementKind {
|
|||
///
|
||||
/// [`EncryptedCredentials`]:
|
||||
/// crate::types::EncryptedCredentials
|
||||
translation: Option<Vec<PassportFile>>,
|
||||
},
|
||||
PassportRegistration {
|
||||
pub translation: Option<Vec<PassportFile>>,
|
||||
}
|
||||
|
||||
#[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
|
||||
|
@ -306,7 +351,7 @@ pub enum EncryptedPassportElementKind {
|
|||
///
|
||||
/// [`EncryptedCredentials`]:
|
||||
/// crate::types::EncryptedCredentials
|
||||
files: Vec<PassportFile>,
|
||||
pub files: Vec<PassportFile>,
|
||||
|
||||
/// Array of encrypted files with translated versions of documents
|
||||
/// provided by the user. Available if requested for `passport`,
|
||||
|
@ -318,9 +363,12 @@ pub enum EncryptedPassportElementKind {
|
|||
///
|
||||
/// [`EncryptedCredentials`]:
|
||||
/// crate::types::EncryptedCredentials
|
||||
translation: Option<Vec<PassportFile>>,
|
||||
},
|
||||
TemporaryRegistration {
|
||||
pub translation: Option<Vec<PassportFile>>,
|
||||
}
|
||||
|
||||
#[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
|
||||
|
@ -329,7 +377,7 @@ pub enum EncryptedPassportElementKind {
|
|||
///
|
||||
/// [`EncryptedCredentials`]:
|
||||
/// crate::types::EncryptedCredentials
|
||||
files: Vec<PassportFile>,
|
||||
pub files: Vec<PassportFile>,
|
||||
|
||||
/// Array of encrypted files with translated versions of documents
|
||||
/// provided by the user. Available if requested for `passport`,
|
||||
|
@ -341,15 +389,21 @@ pub enum EncryptedPassportElementKind {
|
|||
///
|
||||
/// [`EncryptedCredentials`]:
|
||||
/// crate::types::EncryptedCredentials
|
||||
translation: Option<Vec<PassportFile>>,
|
||||
},
|
||||
PhoneNumber {
|
||||
pub translation: Option<Vec<PassportFile>>,
|
||||
}
|
||||
|
||||
#[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.
|
||||
phone_number: String,
|
||||
},
|
||||
Email {
|
||||
/// User's verified email address, available only for `email` type.
|
||||
email: String,
|
||||
},
|
||||
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,
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
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}}"#;
|
||||
|
|
|
@ -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,15 +10,24 @@ use crate::types::{InputFile, ParseMode};
|
|||
///
|
||||
/// [The official docs](https://core.telegram.org/bots/api#inputmedia).
|
||||
pub enum InputMedia {
|
||||
/// Represents a photo to be sent.
|
||||
///
|
||||
/// [The official docs](https://core.telegram.org/bots/api#inputmediaphoto).
|
||||
Photo {
|
||||
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.
|
||||
media: InputFile,
|
||||
pub media: InputFile,
|
||||
|
||||
/// Caption of the photo to be sent, 0-1024 characters.
|
||||
caption: Option<String>,
|
||||
pub caption: Option<String>,
|
||||
|
||||
/// Send [Markdown] or [HTML], if you want Telegram apps to show [bold,
|
||||
/// italic, fixed-width text or inline URLs] in the media caption.
|
||||
|
@ -27,25 +35,27 @@ pub enum InputMedia {
|
|||
/// [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<ParseMode>,
|
||||
},
|
||||
pub parse_mode: Option<ParseMode>,
|
||||
}
|
||||
|
||||
/// Represents a video to be sent.
|
||||
///
|
||||
/// [The official docs](https://core.telegram.org/bots/api#inputmediavideo).
|
||||
Video {
|
||||
/// 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.
|
||||
media: InputFile,
|
||||
pub 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<InputFile>,
|
||||
pub thumb: Option<InputFile>,
|
||||
|
||||
/// Caption of the video to be sent, 0-1024 characters.
|
||||
caption: Option<String>,
|
||||
pub caption: Option<String>,
|
||||
|
||||
/// Send [Markdown] or [HTML], if you want Telegram apps to show [bold,
|
||||
/// italic, fixed-width text or inline URLs] in the media caption.
|
||||
|
@ -53,38 +63,40 @@ pub enum InputMedia {
|
|||
/// [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<ParseMode>,
|
||||
pub parse_mode: Option<ParseMode>,
|
||||
|
||||
/// Video width.
|
||||
width: Option<u16>,
|
||||
pub width: Option<u16>,
|
||||
|
||||
/// Video height.
|
||||
height: Option<u16>,
|
||||
pub height: Option<u16>,
|
||||
|
||||
/// Video duration.
|
||||
duration: Option<u16>,
|
||||
pub duration: Option<u16>,
|
||||
|
||||
/// Pass `true`, if the uploaded video is suitable for streaming.
|
||||
supports_streaming: Option<bool>,
|
||||
},
|
||||
pub supports_streaming: Option<bool>,
|
||||
}
|
||||
|
||||
/// 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).
|
||||
Animation {
|
||||
/// 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.
|
||||
media: InputFile,
|
||||
pub 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<InputFile>,
|
||||
pub thumb: Option<InputFile>,
|
||||
|
||||
/// Caption of the animation to be sent, 0-1024 characters.
|
||||
caption: Option<String>,
|
||||
pub caption: Option<String>,
|
||||
|
||||
/// Send [Markdown] or [HTML], if you want Telegram apps to show [bold,
|
||||
/// italic, fixed-width text or inline URLs] in the media caption.
|
||||
|
@ -92,34 +104,36 @@ pub enum InputMedia {
|
|||
/// [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<ParseMode>,
|
||||
pub parse_mode: Option<ParseMode>,
|
||||
|
||||
/// Animation width.
|
||||
width: Option<u16>,
|
||||
pub width: Option<u16>,
|
||||
|
||||
/// Animation height.
|
||||
height: Option<u16>,
|
||||
pub height: Option<u16>,
|
||||
|
||||
/// Animation duration.
|
||||
duration: Option<u16>,
|
||||
},
|
||||
pub duration: Option<u16>,
|
||||
}
|
||||
|
||||
/// Represents an audio file to be treated as music to be sent.
|
||||
///
|
||||
/// [The official docs](https://core.telegram.org/bots/api#inputmediaaudio).
|
||||
Audio {
|
||||
/// 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.
|
||||
media: InputFile,
|
||||
pub 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<InputFile>,
|
||||
pub thumb: Option<InputFile>,
|
||||
|
||||
/// Caption of the audio to be sent, 0-1024 characters.
|
||||
caption: Option<String>,
|
||||
pub caption: Option<String>,
|
||||
|
||||
/// Send [Markdown] or [HTML], if you want Telegram apps to show [bold,
|
||||
/// italic, fixed-width text or inline URLs] in the media caption.
|
||||
|
@ -127,34 +141,36 @@ pub enum InputMedia {
|
|||
/// [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<String>,
|
||||
pub parse_mode: Option<String>,
|
||||
|
||||
/// Duration of the audio in seconds.
|
||||
duration: Option<u16>,
|
||||
pub duration: Option<u16>,
|
||||
|
||||
/// Performer of the audio.
|
||||
performer: Option<String>,
|
||||
pub performer: Option<String>,
|
||||
|
||||
/// Title of the audio.
|
||||
title: Option<String>,
|
||||
},
|
||||
pub title: Option<String>,
|
||||
}
|
||||
|
||||
/// Represents a general file to be sent.
|
||||
///
|
||||
/// [The official docs](https://core.telegram.org/bots/api#inputmediadocument).
|
||||
Document {
|
||||
/// 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.
|
||||
media: InputFile,
|
||||
pub 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<InputFile>,
|
||||
pub thumb: Option<InputFile>,
|
||||
|
||||
/// Caption of the document to be sent, 0-1024 charactersю
|
||||
caption: Option<String>,
|
||||
pub caption: Option<String>,
|
||||
|
||||
/// Send [Markdown] or [HTML], if you want Telegram apps to show [bold,
|
||||
/// italic, fixed-width text or inline URLs] in the media caption.
|
||||
|
@ -162,18 +178,17 @@ pub enum InputMedia {
|
|||
/// [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<ParseMode>,
|
||||
},
|
||||
pub parse_mode: Option<ParseMode>,
|
||||
}
|
||||
|
||||
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<InputMedia> 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);
|
||||
|
|
|
@ -2,19 +2,25 @@ 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(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.
|
||||
message_text: String,
|
||||
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.
|
||||
|
@ -22,68 +28,74 @@ pub enum InputMessageContent {
|
|||
/// [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<ParseMode>,
|
||||
pub parse_mode: Option<ParseMode>,
|
||||
|
||||
/// Disables link previews for links in the sent message.
|
||||
disable_web_page_preview: Option<bool>,
|
||||
},
|
||||
pub disable_web_page_preview: Option<bool>,
|
||||
}
|
||||
|
||||
/// Represents the content of a location message to be sent as the result
|
||||
/// of an inline query.
|
||||
Location {
|
||||
/// 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.
|
||||
latitude: f64,
|
||||
pub latitude: f64,
|
||||
|
||||
/// Longitude of the location in degrees.
|
||||
longitude: f64,
|
||||
pub longitude: f64,
|
||||
|
||||
/// Period in seconds for which the location can be updated, should be
|
||||
/// between 60 and 86400.
|
||||
live_period: Option<u32>,
|
||||
},
|
||||
pub live_period: Option<u32>,
|
||||
}
|
||||
|
||||
/// Represents the content of a venue message to be sent as the result of
|
||||
/// an inline query.
|
||||
Venue {
|
||||
/// 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)]
|
||||
|
||||
pub struct InputMessageContentVenue {
|
||||
/// Latitude of the venue in degrees.
|
||||
latitude: f64,
|
||||
pub latitude: f64,
|
||||
|
||||
/// Longitude of the venue in degrees.
|
||||
longitude: f64,
|
||||
pub longitude: f64,
|
||||
|
||||
/// Name of the venue.
|
||||
title: String,
|
||||
pub title: String,
|
||||
|
||||
/// Address of the venue.
|
||||
address: String,
|
||||
pub address: String,
|
||||
|
||||
/// Foursquare identifier of the venue, if known.
|
||||
foursquare_id: Option<String>,
|
||||
pub foursquare_id: Option<String>,
|
||||
|
||||
/// Foursquare type of the venue, if known. (For example,
|
||||
/// `arts_entertainment/default`, `arts_entertainment/aquarium`
|
||||
/// or `food/icecream`.)
|
||||
foursquare_type: Option<String>,
|
||||
},
|
||||
pub foursquare_type: Option<String>,
|
||||
}
|
||||
|
||||
/// Represents the content of a contact message to be sent as the result of
|
||||
/// an inline query.
|
||||
Contact {
|
||||
/// 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.
|
||||
phone_number: String,
|
||||
pub phone_number: String,
|
||||
|
||||
/// Contact's first name.
|
||||
first_name: String,
|
||||
pub first_name: String,
|
||||
|
||||
/// Contact's last name.
|
||||
last_name: Option<String>,
|
||||
pub last_name: Option<String>,
|
||||
|
||||
/// Additional data about the contact in the form of a [vCard], 0-2048
|
||||
/// bytes.
|
||||
///
|
||||
/// [vCard]: https://en.wikipedia.org/wiki/VCard
|
||||
vcard: Option<String>,
|
||||
},
|
||||
pub vcard: Option<String>,
|
||||
}
|
||||
|
||||
#[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 {
|
||||
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 {
|
||||
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 {
|
||||
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);
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -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,
|
||||
},
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
DataField(PassportElementErrorDataField),
|
||||
|
||||
#[serde(rename = "snake_case")]
|
||||
FrontSide(PassportElementErrorFrontSide),
|
||||
|
||||
#[serde(rename = "snake_case")]
|
||||
ReverseSide(PassportElementErrorReverseSide),
|
||||
|
||||
#[serde(rename = "snake_case")]
|
||||
Selfie(PassportElementErrorSelfie),
|
||||
|
||||
#[serde(rename = "snake_case")]
|
||||
File(PassportElementErrorFile),
|
||||
|
||||
#[serde(rename = "snake_case")]
|
||||
Files(PassportElementErrorFiles),
|
||||
|
||||
#[serde(rename = "snake_case")]
|
||||
TranslationFile(PassportElementErrorTranslationFile),
|
||||
|
||||
#[serde(rename = "snake_case")]
|
||||
TranslationFiles(PassportElementErrorTranslationFiles),
|
||||
|
||||
#[serde(rename = "snake_case")]
|
||||
Unspecified(PassportElementErrorUnspecified),
|
||||
}
|
||||
|
||||
/// 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.
|
||||
r#type: PassportElementErrorDataFieldType,
|
||||
pub r#type: PassportElementErrorDataFieldType,
|
||||
|
||||
/// Name of the data field which has the error.
|
||||
field_name: String,
|
||||
pub field_name: String,
|
||||
|
||||
/// Base64-encoded data hash.
|
||||
data_hash: String,
|
||||
},
|
||||
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).
|
||||
#[serde(rename = "snake_case")]
|
||||
FrontSide {
|
||||
/// 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.
|
||||
r#type: PassportElementErrorFrontSideType,
|
||||
pub r#type: PassportElementErrorFrontSideType,
|
||||
|
||||
/// Base64-encoded hash of the file with the front side of the
|
||||
/// document.
|
||||
file_hash: String,
|
||||
},
|
||||
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).
|
||||
#[serde(rename = "snake_case")]
|
||||
ReverseSide {
|
||||
/// 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.
|
||||
r#type: PassportElementErrorReverseSideType,
|
||||
pub r#type: PassportElementErrorReverseSideType,
|
||||
|
||||
//// Base64-encoded hash of the file with the reverse side of the
|
||||
//// document.
|
||||
file_hash: String,
|
||||
},
|
||||
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).
|
||||
#[serde(rename = "snake_case")]
|
||||
Selfie {
|
||||
//// 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.
|
||||
r#type: PassportElementErrorSelfieType,
|
||||
pub r#type: PassportElementErrorSelfieType,
|
||||
|
||||
/// Base64-encoded hash of the file with the selfie.
|
||||
file_hash: String,
|
||||
},
|
||||
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).
|
||||
#[serde(rename = "snake_case")]
|
||||
File {
|
||||
/// 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.
|
||||
r#type: PassportElementErrorFileType,
|
||||
pub r#type: PassportElementErrorFileType,
|
||||
|
||||
/// Base64-encoded file hash.
|
||||
file_hash: String,
|
||||
},
|
||||
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).
|
||||
#[serde(rename = "snake_case")]
|
||||
Files {
|
||||
/// 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.
|
||||
r#type: PassportElementErrorFilesType,
|
||||
pub r#type: PassportElementErrorFilesType,
|
||||
|
||||
/// List of base64-encoded file hashes.
|
||||
file_hashes: Vec<String>,
|
||||
},
|
||||
pub file_hashes: Vec<String>,
|
||||
}
|
||||
|
||||
/// 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 {
|
||||
/// 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.
|
||||
r#type: PassportElementErrorTranslationFileType,
|
||||
pub r#type: PassportElementErrorTranslationFileType,
|
||||
|
||||
/// Base64-encoded file hash.
|
||||
file_hash: String,
|
||||
},
|
||||
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).
|
||||
#[serde(rename = "snake_case")]
|
||||
TranslationFiles {
|
||||
/// 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
|
||||
r#type: PassportElementErrorTranslationFilesType,
|
||||
pub r#type: PassportElementErrorTranslationFilesType,
|
||||
|
||||
/// List of base64-encoded file hashes
|
||||
file_hashes: Vec<String>,
|
||||
},
|
||||
pub file_hashes: Vec<String>,
|
||||
}
|
||||
|
||||
/// 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 {
|
||||
/// 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.
|
||||
r#type: PassportElementErrorUnspecifiedType,
|
||||
pub r#type: PassportElementErrorUnspecifiedType,
|
||||
|
||||
/// Base64-encoded element hash.
|
||||
element_hash: String,
|
||||
},
|
||||
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 {
|
||||
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!(
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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,
|
||||
},
|
||||
}),
|
||||
}),
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in a new issue