mirror of
https://github.com/teloxide/teloxide.git
synced 2024-12-22 14:35:36 +01:00
Merge branch 'dev' of github.com:async-telegram-bot/async-telegram-bot into dev
This commit is contained in:
commit
1f50a87daf
3 changed files with 297 additions and 111 deletions
|
@ -1,18 +1,60 @@
|
|||
use crate::core::types::{ChatPermissions, ChatPhoto, Message};
|
||||
|
||||
#[derive(Debug, Deserialize, Eq, Hash, PartialEq, Serialize, Clone)]
|
||||
|
||||
#[derive(Debug, Deserialize, Eq, Hash, PartialEq, Clone)]
|
||||
pub struct Chat {
|
||||
#[serde(rename = "chat_id")]
|
||||
pub id: i32,
|
||||
pub id: i64,
|
||||
#[serde(flatten)]
|
||||
pub type_: ChatType,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub kind: ChatKind,
|
||||
pub photo: Option<ChatPhoto>,
|
||||
}
|
||||
|
||||
struct PrivateChatTypeVisitor;
|
||||
|
||||
impl<'de> serde::de::Visitor<'de> for PrivateChatTypeVisitor {
|
||||
#[derive(Debug, Deserialize, Eq, Hash, PartialEq, Clone)]
|
||||
#[serde(untagged)]
|
||||
pub enum ChatKind {
|
||||
NonPrivate {
|
||||
title: Option<String>,
|
||||
#[serde(flatten)]
|
||||
kind: NonPrivateChatKind,
|
||||
description: Option<String>,
|
||||
invite_link: Option<String>,
|
||||
pinned_message: Option<Box<Message>>,
|
||||
},
|
||||
Private {
|
||||
/// Dummy field. Used to ensure that "type" field is equal to "private"
|
||||
#[serde(rename = "type")]
|
||||
#[serde(deserialize_with = "assert_private_field")]
|
||||
type_: (),
|
||||
username: Option<String>,
|
||||
first_name: Option<String>,
|
||||
last_name: Option<String>,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug, Deserialize, Eq, Hash, PartialEq, Clone)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
#[serde(tag = "type")]
|
||||
pub enum NonPrivateChatKind {
|
||||
Channel {
|
||||
username: Option<String>,
|
||||
},
|
||||
Group {
|
||||
permissions: Option<ChatPermissions>,
|
||||
},
|
||||
Supergroup {
|
||||
username: Option<String>,
|
||||
sticker_set_name: Option<String>,
|
||||
can_set_sticker_set: Option<bool>,
|
||||
permissions: Option<ChatPermissions>,
|
||||
},
|
||||
}
|
||||
|
||||
struct PrivateChatKindVisitor;
|
||||
|
||||
impl<'de> serde::de::Visitor<'de> for PrivateChatKindVisitor {
|
||||
type Value = ();
|
||||
|
||||
fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
|
@ -33,94 +75,38 @@ impl<'de> serde::de::Visitor<'de> for PrivateChatTypeVisitor {
|
|||
}
|
||||
}
|
||||
|
||||
fn assert_private_field<'de, D: serde::Deserializer<'de>>(
|
||||
des: D,
|
||||
) -> Result<(), D::Error> {
|
||||
des.deserialize_str(PrivateChatTypeVisitor)
|
||||
}
|
||||
|
||||
fn serialize_private_field<S: serde::Serializer>(
|
||||
_: &(),
|
||||
ser: S,
|
||||
) -> Result<S::Ok, S::Error> {
|
||||
ser.serialize_str("private")
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Eq, Hash, PartialEq, Serialize, Clone)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
#[serde(untagged)]
|
||||
pub enum ChatType {
|
||||
NotPrivate {
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
title: Option<String>,
|
||||
#[serde(flatten)]
|
||||
type_: NotPrivateChatType,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
description: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
invite_link: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pinned_message: Option<Box<Message>>,
|
||||
},
|
||||
Private {
|
||||
/// Dummy field. Used to ensure that "type" field is equal to "private"
|
||||
#[serde(rename = "type")]
|
||||
#[serde(deserialize_with = "assert_private_field")]
|
||||
#[serde(serialize_with = "serialize_private_field")]
|
||||
type_: (),
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
username: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
first_name: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
last_name: Option<String>,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Eq, Hash, PartialEq, Serialize, Clone)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
#[serde(tag = "type")]
|
||||
pub enum NotPrivateChatType {
|
||||
Channel {
|
||||
username: Option<String>,
|
||||
},
|
||||
Group {
|
||||
permissions: Option<ChatPermissions>,
|
||||
},
|
||||
Supergroup {
|
||||
username: Option<String>,
|
||||
sticker_set_name: Option<String>,
|
||||
can_set_sticker_set: Option<bool>,
|
||||
permissions: Option<ChatPermissions>,
|
||||
},
|
||||
fn assert_private_field<'de, D>(des: D) -> Result<(), D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
{
|
||||
des.deserialize_str(PrivateChatKindVisitor)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::core::types::*;
|
||||
use serde_json::{from_str, to_string};
|
||||
use serde_json::from_str;
|
||||
|
||||
#[test]
|
||||
fn channel_de() {
|
||||
assert_eq!(
|
||||
Chat {
|
||||
id: -1,
|
||||
type_: ChatType::NotPrivate {
|
||||
title: None,
|
||||
type_: NotPrivateChatType::Channel {
|
||||
username: Some("channelname".into())
|
||||
},
|
||||
description: None,
|
||||
invite_link: None,
|
||||
pinned_message: None
|
||||
let expected = Chat {
|
||||
id: -1,
|
||||
kind: ChatKind::NonPrivate {
|
||||
title: None,
|
||||
kind: NonPrivateChatKind::Channel {
|
||||
username: Some("channelname".into()),
|
||||
},
|
||||
photo: None,
|
||||
description: None,
|
||||
invite_link: None,
|
||||
pinned_message: None,
|
||||
},
|
||||
from_str(
|
||||
r#"{"chat_id":-1,"type":"channel","username":"channelname"}"#
|
||||
)
|
||||
.unwrap()
|
||||
);
|
||||
photo: None,
|
||||
};
|
||||
let actual = from_str(
|
||||
r#"{"chat_id":-1,"type":"channel","username":"channelname"}"#,
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(expected, actual);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -128,7 +114,7 @@ mod tests {
|
|||
assert_eq!(
|
||||
Chat {
|
||||
id: 0,
|
||||
type_: ChatType::Private {
|
||||
kind: ChatKind::Private {
|
||||
type_: (),
|
||||
username: Some("username".into()),
|
||||
first_name: Some("Anon".into()),
|
||||
|
@ -145,22 +131,4 @@ mod tests {
|
|||
fn private_chat_de_wrong_type_field() {
|
||||
assert!(from_str::<Chat>(r#"{"chat_id":0,"type":"WRONG"}"#).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn private_chat_ser() {
|
||||
assert_eq!(
|
||||
to_string(&Chat {
|
||||
id: 0,
|
||||
type_: ChatType::Private {
|
||||
type_: (),
|
||||
username: None,
|
||||
first_name: None,
|
||||
last_name: None
|
||||
},
|
||||
photo: None
|
||||
})
|
||||
.unwrap(),
|
||||
r#"{"chat_id":0,"type":"private"}"#.to_owned()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,17 +4,235 @@ use crate::core::types::{
|
|||
SuccessfulPayment, User, Venue, Video, VideoNote, Voice,
|
||||
};
|
||||
|
||||
#[derive(Debug, Deserialize, Eq, Hash, PartialEq, Serialize, Clone)]
|
||||
|
||||
#[derive(Debug, Deserialize, Eq, Hash, PartialEq, Clone)]
|
||||
pub struct Message {
|
||||
#[serde(rename = "message_id")]
|
||||
pub id: i32,
|
||||
pub id: i64,
|
||||
pub date: i32,
|
||||
pub chat: Chat,
|
||||
#[serde(flatten)]
|
||||
pub type_: MessageType,
|
||||
pub message_kind: MessageKind,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Eq, Hash, PartialEq, Serialize, Clone)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
|
||||
#[derive(Debug, Deserialize, Eq, Hash, PartialEq, Clone)]
|
||||
#[serde(untagged)]
|
||||
pub enum MessageType {}
|
||||
pub enum MessageKind {
|
||||
IncomingMessage {
|
||||
#[serde(flatten)]
|
||||
forward_kind: ForwardKind,
|
||||
edit_date: Option<i32>,
|
||||
#[serde(flatten)]
|
||||
media_kind: MediaKind,
|
||||
reply_markup: Option<InlineKeyboardMarkup>,
|
||||
},
|
||||
NewChatMembers {
|
||||
new_chat_members: Vec<User>,
|
||||
},
|
||||
LeftChatMember {
|
||||
left_chat_member: User,
|
||||
},
|
||||
NewChatTitle {
|
||||
new_chat_title: String,
|
||||
},
|
||||
NewChatPhoto {
|
||||
new_chat_photo: Vec<PhotoSize>,
|
||||
},
|
||||
DeleteChatPhoto {
|
||||
delete_chat_photo: bool,
|
||||
},
|
||||
GroupChatCreated {
|
||||
group_chat_created: bool,
|
||||
},
|
||||
SupergroupChatCreated {
|
||||
supergroup_chat_created: bool,
|
||||
},
|
||||
ChannelChatCreated {
|
||||
channel_chat_created: bool,
|
||||
},
|
||||
Migrate {
|
||||
migrate_to_chat_id: i64,
|
||||
migrate_from_chat_id: i64,
|
||||
},
|
||||
PinnedMessage {
|
||||
pinned_message: Box<Message>,
|
||||
},
|
||||
Invoice {
|
||||
invoice: Invoice,
|
||||
},
|
||||
SuccessfulPayment {
|
||||
successful_payment: SuccessfulPayment,
|
||||
},
|
||||
ConnectedWebsite {
|
||||
connected_website: String,
|
||||
},
|
||||
PassportData {
|
||||
passport_data: PassportData,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Eq, Hash, PartialEq, Clone)]
|
||||
#[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: i64,
|
||||
#[serde(rename = "forward_signature")]
|
||||
signature: Option<String>,
|
||||
},
|
||||
NonChannelForward {
|
||||
#[serde(rename = "forward_date")]
|
||||
date: i32,
|
||||
#[serde(flatten)]
|
||||
from: ForwardedFrom,
|
||||
},
|
||||
Origin {
|
||||
reply_to_message: Option<Box<Message>>,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Eq, Hash, PartialEq, Clone)]
|
||||
pub enum ForwardedFrom {
|
||||
#[serde(rename = "forward_from")]
|
||||
User(User),
|
||||
#[serde(rename = "forward_sender_name")]
|
||||
SenderName(String),
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Eq, Hash, PartialEq, Clone)]
|
||||
#[serde(untagged)]
|
||||
pub enum MediaKind {
|
||||
Animation {
|
||||
animation: Animation,
|
||||
caption: Option<String>,
|
||||
},
|
||||
Audio {
|
||||
audio: Audio,
|
||||
caption: Option<String>,
|
||||
},
|
||||
Contact {
|
||||
contact: Contact,
|
||||
},
|
||||
Document {
|
||||
document: Document,
|
||||
caption: Option<String>,
|
||||
},
|
||||
Game {
|
||||
game: Game,
|
||||
},
|
||||
Location {
|
||||
location: Location,
|
||||
},
|
||||
Photo {
|
||||
sizes: Vec<PhotoSize>,
|
||||
caption: Option<String>,
|
||||
},
|
||||
Poll {
|
||||
poll: Poll,
|
||||
},
|
||||
Sticker {
|
||||
sticker: Sticker,
|
||||
},
|
||||
Text {
|
||||
text: String,
|
||||
entities: Vec<MessageEntity>,
|
||||
},
|
||||
Video {
|
||||
video: Video,
|
||||
caption: Option<String>,
|
||||
},
|
||||
VideoNote {
|
||||
video_note: VideoNote,
|
||||
},
|
||||
Voice {
|
||||
voice: Voice,
|
||||
caption: Option<String>,
|
||||
},
|
||||
Venue {
|
||||
venue: Venue,
|
||||
},
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::core::types::*;
|
||||
use serde_json::from_str;
|
||||
|
||||
#[test]
|
||||
fn origin_de() {
|
||||
let expected = Message {
|
||||
id: 0,
|
||||
date: 0,
|
||||
chat: Chat {
|
||||
id: 0,
|
||||
kind: ChatKind::Private {
|
||||
type_: (),
|
||||
username: None,
|
||||
first_name: None,
|
||||
last_name: None,
|
||||
},
|
||||
photo: None,
|
||||
},
|
||||
message_kind: MessageKind::IncomingMessage {
|
||||
forward_kind: ForwardKind::Origin {
|
||||
reply_to_message: None,
|
||||
},
|
||||
edit_date: None,
|
||||
media_kind: MediaKind::Text {
|
||||
text: "Hello".to_string(),
|
||||
entities: vec![],
|
||||
},
|
||||
reply_markup: None,
|
||||
},
|
||||
};
|
||||
let actual = from_str::<Message>(r#"{"message_id":0,"date":0,"chat":{"chat_id":0,"type":"private"},"text":"Hello","entities":[]}"#).unwrap();
|
||||
assert_eq!(expected, actual);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn forward_de() {
|
||||
let expected = Message {
|
||||
id: 1,
|
||||
date: 1,
|
||||
chat: Chat {
|
||||
id: 1,
|
||||
kind: ChatKind::Private {
|
||||
type_: (),
|
||||
username: None,
|
||||
first_name: None,
|
||||
last_name: None,
|
||||
},
|
||||
photo: None,
|
||||
},
|
||||
message_kind: MessageKind::IncomingMessage {
|
||||
forward_kind: ForwardKind::NonChannelForward {
|
||||
date: 1,
|
||||
from: ForwardedFrom::User(User {
|
||||
id: 123,
|
||||
is_bot: false,
|
||||
first_name: "Name".to_string(),
|
||||
last_name: None,
|
||||
username: None,
|
||||
language_code: None,
|
||||
}),
|
||||
},
|
||||
edit_date: None,
|
||||
media_kind: MediaKind::Text {
|
||||
text: "Message".into(),
|
||||
entities: vec![],
|
||||
},
|
||||
reply_markup: None,
|
||||
},
|
||||
};
|
||||
let actual = from_str::<Message>(
|
||||
r#"{"message_id":1,"date":1,"chat":{"chat_id":1,"type":"private"},"forward_date":1,"forward_from":{"id":123,"is_bot":false,"first_name":"Name"},"text":"Message","entities":[]}"#,
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(expected, actual);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ pub use self::{
|
|||
answer_pre_checkout_query::AnswerPreCheckoutQuery,
|
||||
answer_shipping_query::AnswerShippingQuery,
|
||||
audio::Audio,
|
||||
chat::{Chat, ChatType, NotPrivateChatType},
|
||||
chat::{Chat, ChatKind, NonPrivateChatKind},
|
||||
chat_member::ChatMember,
|
||||
chat_permissions::ChatPermissions,
|
||||
chat_photo::ChatPhoto,
|
||||
|
@ -12,7 +12,7 @@ pub use self::{
|
|||
input_media::InputMedia,
|
||||
invoice::Invoice,
|
||||
label_price::LabeledPrice,
|
||||
message::Message,
|
||||
message::{ForwardKind, ForwardedFrom, MediaKind, Message, MessageKind},
|
||||
message_entity::MessageEntity,
|
||||
order_info::OrderInfo,
|
||||
parse_mode::ParseMode,
|
||||
|
|
Loading…
Reference in a new issue