mirror of
https://github.com/teloxide/teloxide.git
synced 2025-01-18 15:20:15 +01:00
Merge branch 'dev' into file_download
This commit is contained in:
commit
d5adf4701b
10 changed files with 244 additions and 55 deletions
|
@ -9,7 +9,7 @@ use bytes::Buf;
|
||||||
use futures::StreamExt;
|
use futures::StreamExt;
|
||||||
use reqwest::r#async::Chunk;
|
use reqwest::r#async::Chunk;
|
||||||
use reqwest::{
|
use reqwest::{
|
||||||
r#async::{multipart::Form, Client},
|
r#async::{multipart::Form, Client, Response},
|
||||||
StatusCode,
|
StatusCode,
|
||||||
};
|
};
|
||||||
use serde::{de::DeserializeOwned, Serialize};
|
use serde::{de::DeserializeOwned, Serialize};
|
||||||
|
@ -49,22 +49,18 @@ pub async fn request_multipart<T: DeserializeOwned>(
|
||||||
method_name: &str,
|
method_name: &str,
|
||||||
params: Option<Form>,
|
params: Option<Form>,
|
||||||
) -> ResponseResult<T> {
|
) -> ResponseResult<T> {
|
||||||
let mut response = client
|
process_response(
|
||||||
.post(&method_url(TELEGRAM_API_URL, token, method_name))
|
client
|
||||||
.apply(|request_builder| match params {
|
.post(&method_url(TELEGRAM_API_URL, token, method_name))
|
||||||
Some(params) => request_builder.multipart(params),
|
.apply(|request_builder| match params {
|
||||||
None => request_builder,
|
Some(params) => request_builder.multipart(params),
|
||||||
})
|
None => request_builder,
|
||||||
.send()
|
})
|
||||||
.await
|
.send()
|
||||||
.map_err(RequestError::NetworkError)?;
|
.await
|
||||||
|
.map_err(RequestError::NetworkError)?,
|
||||||
let response = serde_json::from_str::<TelegramResponse<T>>(
|
|
||||||
&response.text().await.map_err(RequestError::NetworkError)?,
|
|
||||||
)
|
)
|
||||||
.map_err(RequestError::InvalidJson)?;
|
.await
|
||||||
|
|
||||||
response.into()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn request_json<T: DeserializeOwned, P: Serialize>(
|
pub async fn request_json<T: DeserializeOwned, P: Serialize>(
|
||||||
|
@ -73,13 +69,20 @@ pub async fn request_json<T: DeserializeOwned, P: Serialize>(
|
||||||
method_name: &str,
|
method_name: &str,
|
||||||
params: &P,
|
params: &P,
|
||||||
) -> ResponseResult<T> {
|
) -> ResponseResult<T> {
|
||||||
let mut response = client
|
process_response(
|
||||||
.post(&method_url(TELEGRAM_API_URL, token, method_name))
|
client
|
||||||
.json(params)
|
.post(&method_url(TELEGRAM_API_URL, token, method_name))
|
||||||
.send()
|
.json(params)
|
||||||
.await
|
.send()
|
||||||
.map_err(RequestError::NetworkError)?;
|
.await
|
||||||
|
.map_err(RequestError::NetworkError)?,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn process_response<T: DeserializeOwned>(
|
||||||
|
mut response: Response,
|
||||||
|
) -> ResponseResult<T> {
|
||||||
let response = serde_json::from_str::<TelegramResponse<T>>(
|
let response = serde_json::from_str::<TelegramResponse<T>>(
|
||||||
&response.text().await.map_err(RequestError::NetworkError)?,
|
&response.text().await.map_err(RequestError::NetworkError)?,
|
||||||
)
|
)
|
||||||
|
@ -92,14 +95,14 @@ pub async fn request_json<T: DeserializeOwned, P: Serialize>(
|
||||||
#[serde(untagged)]
|
#[serde(untagged)]
|
||||||
enum TelegramResponse<R> {
|
enum TelegramResponse<R> {
|
||||||
Ok {
|
Ok {
|
||||||
/// Dummy field. Used for deserialization.
|
/// A dummy field. Used only for deserialization.
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
ok: bool, // TODO: True type
|
ok: bool, // TODO: True type
|
||||||
|
|
||||||
result: R,
|
result: R,
|
||||||
},
|
},
|
||||||
Err {
|
Err {
|
||||||
/// Dummy field. Used for deserialization.
|
/// A dummy field. Used only for deserialization.
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
ok: bool, // TODO: False type
|
ok: bool, // TODO: False type
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,19 @@
|
||||||
use crate::core::requests::RequestContext;
|
use crate::core::requests::RequestContext;
|
||||||
//TODO:: need implementation
|
|
||||||
|
|
||||||
|
//TODO: complete implementation after user_profile_fotos will be added to
|
||||||
|
// types/mod.rs
|
||||||
|
///Use this method to get a list of profile pictures for a user. Returns a
|
||||||
|
/// UserProfilePhotos object.
|
||||||
#[derive(Debug, Clone, Serialize)]
|
#[derive(Debug, Clone, Serialize)]
|
||||||
struct GetUserProfilePhotos<'a> {
|
struct GetUserProfilePhotos<'a> {
|
||||||
#[serde(skip_serializing)]
|
#[serde(skip_serializing)]
|
||||||
ctx: RequestContext<'a>,
|
ctx: RequestContext<'a>,
|
||||||
|
/// Unique identifier of the target user
|
||||||
|
user_id: i32,
|
||||||
|
/// Sequential number of the first photo to be returned. By default, all
|
||||||
|
/// photos are returned.
|
||||||
|
offset: Option<i64>,
|
||||||
|
///Limits the number of photos to be retrieved. Values between 1—100 are
|
||||||
|
/// accepted. Defaults to 100.
|
||||||
|
limit: Option<i64>,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
use crate::core::requests::RequestContext;
|
use crate::core::requests::RequestContext;
|
||||||
//TODO:: need implementation
|
//TODO:: need implementation
|
||||||
|
/// Use this method to kick a user from a group, a supergroup or a channel. In
|
||||||
|
/// the case of supergroups and channels, the user will not be able to return to
|
||||||
|
/// the group on their own using invite links, etc., unless unbanned first. The
|
||||||
|
/// bot must be an administrator in the chat for this to work and must have the
|
||||||
|
/// appropriate admin rights. Returns True on success.
|
||||||
#[derive(Debug, Clone, Serialize)]
|
#[derive(Debug, Clone, Serialize)]
|
||||||
struct KickChatMember<'a> {
|
struct KickChatMember<'a> {
|
||||||
#[serde(skip_serializing)]
|
#[serde(skip_serializing)]
|
||||||
|
|
|
@ -1,17 +1,51 @@
|
||||||
use crate::core::types::PhotoSize;
|
use crate::core::types::PhotoSize;
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, Eq, Hash, PartialEq, Serialize, Clone)]
|
#[derive(Debug, Deserialize, Eq, Hash, PartialEq, Clone)]
|
||||||
pub struct Audio {
|
pub struct Audio {
|
||||||
pub file_id: String,
|
pub file_id: String,
|
||||||
pub duration: u32,
|
pub duration: u32,
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
|
||||||
pub performer: Option<String>,
|
pub performer: Option<String>,
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
|
||||||
pub title: Option<String>,
|
pub title: Option<String>,
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
|
||||||
pub mime_type: Option<String>,
|
pub mime_type: Option<String>,
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
|
||||||
pub file_size: Option<u32>,
|
pub file_size: Option<u32>,
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
|
||||||
pub thumb: Option<PhotoSize>,
|
pub thumb: Option<PhotoSize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn deserialize() {
|
||||||
|
let json = r#"{
|
||||||
|
"file_id":"id",
|
||||||
|
"duration":60,
|
||||||
|
"performer":"Performer",
|
||||||
|
"title":"Title",
|
||||||
|
"mime_type":"MimeType",
|
||||||
|
"file_size":123456,
|
||||||
|
"thumb":{
|
||||||
|
"file_id":"id",
|
||||||
|
"width":320,
|
||||||
|
"height":320,
|
||||||
|
"file_size":3452
|
||||||
|
}
|
||||||
|
}"#;
|
||||||
|
let expected = Audio {
|
||||||
|
file_id: "id".to_string(),
|
||||||
|
duration: 60,
|
||||||
|
performer: Some("Performer".to_string()),
|
||||||
|
title: Some("Title".to_string()),
|
||||||
|
mime_type: Some("MimeType".to_string()),
|
||||||
|
file_size: Some(123456),
|
||||||
|
thumb: Some(PhotoSize {
|
||||||
|
file_id: "id".to_string(),
|
||||||
|
width: 320,
|
||||||
|
height: 320,
|
||||||
|
file_size: Some(3452)
|
||||||
|
})
|
||||||
|
};
|
||||||
|
let actual = serde_json::from_str::<Audio>(&json).unwrap();
|
||||||
|
assert_eq!(actual, expected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,22 +1,51 @@
|
||||||
use crate::core::types::{Message, User};
|
use crate::core::types::{Message, User};
|
||||||
|
|
||||||
/// This object represents an incoming callback query from a callback button in
|
|
||||||
/// an inline keyboard.
|
|
||||||
#[derive(Debug, Deserialize, PartialEq, Clone)]
|
#[derive(Debug, Deserialize, PartialEq, Clone)]
|
||||||
pub struct CallbackQuery {
|
pub struct CallbackQuery {
|
||||||
/// Unique identifier for this query
|
|
||||||
pub id: String,
|
pub id: String,
|
||||||
/// Sender
|
|
||||||
pub from: User,
|
pub from: User,
|
||||||
/// Message with the callback button that originated the query.
|
|
||||||
/// Note that message content and message date will not be available if the
|
|
||||||
/// message is too old
|
|
||||||
pub message: Message,
|
|
||||||
/// Global identifier, uniquely corresponding to the chat to which the
|
|
||||||
/// message with the callback button was sent. Useful for high scores
|
|
||||||
/// in games.
|
|
||||||
pub chat_instance: String,
|
pub chat_instance: String,
|
||||||
/// Data associated with the callback button. Be aware that a bad client
|
pub message: Option<Message>,
|
||||||
/// can send arbitrary data in this field.
|
pub inline_message_id: Option<String>,
|
||||||
pub data: String,
|
pub data: Option<String>,
|
||||||
|
pub game_short_name: Option<String>
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn deserialize() {
|
||||||
|
let json = r#"{
|
||||||
|
"id":"id",
|
||||||
|
"from":{
|
||||||
|
"id":12345,
|
||||||
|
"is_bot":false,
|
||||||
|
"first_name":"firstName"
|
||||||
|
},
|
||||||
|
"inline_message_id":"i_m_id",
|
||||||
|
"chat_instance":"123456",
|
||||||
|
"data":"some_data",
|
||||||
|
"game_short_name":"game_name"
|
||||||
|
}"#;
|
||||||
|
let expected = CallbackQuery {
|
||||||
|
id: "id".to_string(),
|
||||||
|
from: User {
|
||||||
|
id: 12345,
|
||||||
|
is_bot: false,
|
||||||
|
first_name: "firstName".to_string(),
|
||||||
|
last_name: None,
|
||||||
|
username: None,
|
||||||
|
language_code: None
|
||||||
|
},
|
||||||
|
chat_instance: "123456".to_string(),
|
||||||
|
message: None,
|
||||||
|
inline_message_id: Some("i_m_id".to_string()),
|
||||||
|
data: Some("some_data".to_string()),
|
||||||
|
game_short_name: Some("game_name".to_string())
|
||||||
|
};
|
||||||
|
let actual = serde_json::from_str::<CallbackQuery>(json).unwrap();
|
||||||
|
assert_eq!(actual, expected);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::core::types::{ChatMemberStatus, User};
|
use crate::core::types::User;
|
||||||
|
|
||||||
/// This object contains information about one member of the chat.
|
/// This object contains information about one member of the chat.
|
||||||
#[derive(Debug, Deserialize, Hash, PartialEq, Eq, Clone)]
|
#[derive(Debug, Deserialize, Hash, PartialEq, Eq, Clone)]
|
||||||
|
@ -54,3 +54,74 @@ pub struct ChatMember {
|
||||||
/// his messages, implies can_send_media_messages
|
/// his messages, implies can_send_media_messages
|
||||||
pub can_add_web_page_previews: Option<bool>,
|
pub can_add_web_page_previews: Option<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Debug, Hash, PartialEq, Eq, Clone)]
|
||||||
|
#[serde(rename_all = "snake_case")]
|
||||||
|
pub enum ChatMemberStatus {
|
||||||
|
Creator,
|
||||||
|
Administrator,
|
||||||
|
Member,
|
||||||
|
Restricted,
|
||||||
|
Left,
|
||||||
|
Kicked
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn deserialize() {
|
||||||
|
let json = r#"{
|
||||||
|
"user":{
|
||||||
|
"id":12345,
|
||||||
|
"is_bot":false,
|
||||||
|
"first_name":"firstName"
|
||||||
|
},
|
||||||
|
"status":"creator",
|
||||||
|
"until_date":123456,
|
||||||
|
"can_be_edited":true,
|
||||||
|
"can_post_messages":true,
|
||||||
|
"can_edit_messages":true,
|
||||||
|
"can_delete_messages":true,
|
||||||
|
"can_restrict_members":true,
|
||||||
|
"can_promote_members":true,
|
||||||
|
"can_change_info":true,
|
||||||
|
"can_invite_users":true,
|
||||||
|
"can_pin_messages":true,
|
||||||
|
"is_member":true,
|
||||||
|
"can_send_messages":true,
|
||||||
|
"can_send_media_messages":true,
|
||||||
|
"can_send_polls":true,
|
||||||
|
"can_send_other_messages":true,
|
||||||
|
"can_add_web_page_previews":true
|
||||||
|
}"#;
|
||||||
|
let expected = ChatMember {
|
||||||
|
user: User {
|
||||||
|
id: 12345,
|
||||||
|
is_bot: false,
|
||||||
|
first_name: "firstName".to_string(),
|
||||||
|
last_name: None,
|
||||||
|
username: None,
|
||||||
|
language_code: None
|
||||||
|
},
|
||||||
|
status: ChatMemberStatus::Creator,
|
||||||
|
until_date: Some(123456),
|
||||||
|
can_be_edited: Some(true),
|
||||||
|
can_change_info: Some(true),
|
||||||
|
can_post_messages: Some(true),
|
||||||
|
can_edit_messages: Some(true),
|
||||||
|
can_delete_messages: Some(true),
|
||||||
|
can_invite_users: Some(true),
|
||||||
|
can_restrict_members: Some(true),
|
||||||
|
can_pin_messages: Some(true),
|
||||||
|
can_promote_members: Some(true),
|
||||||
|
can_send_messages: Some(true),
|
||||||
|
can_send_media_messages: Some(true),
|
||||||
|
can_send_other_messages: Some(true),
|
||||||
|
can_add_web_page_previews: Some(true)
|
||||||
|
};
|
||||||
|
let actual = serde_json::from_str::<ChatMember>(&json).unwrap();
|
||||||
|
assert_eq!(actual, expected)
|
||||||
|
}
|
||||||
|
}
|
|
@ -11,13 +11,26 @@ pub struct Message {
|
||||||
pub date: i32,
|
pub date: i32,
|
||||||
pub chat: Chat,
|
pub chat: Chat,
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
pub message_kind: MessageKind,
|
pub kind: MessageKind,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Message {
|
||||||
|
fn text(&self) -> Option<&str> {
|
||||||
|
if let MessageKind::Common {
|
||||||
|
media_kind: MediaKind::Text {
|
||||||
|
ref text, ..
|
||||||
|
}, .. } = self.kind {
|
||||||
|
Some(text)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, PartialEq, Clone)]
|
#[derive(Debug, Deserialize, PartialEq, Clone)]
|
||||||
#[serde(untagged)]
|
#[serde(untagged)]
|
||||||
pub enum MessageKind {
|
pub enum MessageKind {
|
||||||
IncomingMessage {
|
Common {
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
from: Sender,
|
from: Sender,
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
|
@ -55,8 +68,8 @@ pub enum MessageKind {
|
||||||
migrate_to_chat_id: i64,
|
migrate_to_chat_id: i64,
|
||||||
migrate_from_chat_id: i64,
|
migrate_from_chat_id: i64,
|
||||||
},
|
},
|
||||||
PinnedMessage {
|
Pinned {
|
||||||
pinned_message: Box<Message>,
|
pinned: Box<Message>,
|
||||||
},
|
},
|
||||||
Invoice {
|
Invoice {
|
||||||
invoice: Invoice,
|
invoice: Invoice,
|
||||||
|
|
|
@ -4,7 +4,7 @@ pub use self::{
|
||||||
audio::Audio,
|
audio::Audio,
|
||||||
callback_query::CallbackQuery,
|
callback_query::CallbackQuery,
|
||||||
chat::{Chat, ChatKind, NonPrivateChatKind},
|
chat::{Chat, ChatKind, NonPrivateChatKind},
|
||||||
chat_member::ChatMember,
|
chat_member::{ChatMember, ChatMemberStatus},
|
||||||
chat_permissions::ChatPermissions,
|
chat_permissions::ChatPermissions,
|
||||||
chat_photo::ChatPhoto,
|
chat_photo::ChatPhoto,
|
||||||
chosen_inline_result::ChosenInlineResult,
|
chosen_inline_result::ChosenInlineResult,
|
||||||
|
|
|
@ -1,5 +1,2 @@
|
||||||
#[derive(Debug, Deserialize, Eq, Hash, PartialEq, Serialize, Clone)]
|
#[derive(Debug, Deserialize, Eq, Hash, PartialEq, Serialize, Clone)]
|
||||||
pub struct PassportData;
|
pub struct PassportData;
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, Eq, Hash, PartialEq, Serialize, Clone)]
|
|
||||||
pub struct ChatMemberStatus;
|
|
||||||
|
|
|
@ -7,3 +7,30 @@ pub struct User {
|
||||||
pub username: Option<String>,
|
pub username: Option<String>,
|
||||||
pub language_code: Option<String>,
|
pub language_code: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn deserialize() {
|
||||||
|
let json = r#"{
|
||||||
|
"id":12345,
|
||||||
|
"is_bot":false,
|
||||||
|
"first_name":"firstName",
|
||||||
|
"last_name":"lastName",
|
||||||
|
"username":"Username",
|
||||||
|
"language_code":"languageCode"
|
||||||
|
}"#;
|
||||||
|
let expected = User {
|
||||||
|
id: 12345,
|
||||||
|
is_bot: false,
|
||||||
|
first_name: "firstName".to_string(),
|
||||||
|
last_name: Some("lastName".to_string()),
|
||||||
|
username: Some("Username".to_string()),
|
||||||
|
language_code: Some("languageCode".to_string())
|
||||||
|
};
|
||||||
|
let actual = serde_json::from_str::<User>(&json).unwrap();
|
||||||
|
assert_eq!(actual, expected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue