Merge branch 'dev' into file_download

This commit is contained in:
Waffle Lapkin 2019-09-20 23:36:49 +03:00 committed by GitHub
commit d5adf4701b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 244 additions and 55 deletions

View file

@ -9,7 +9,7 @@ use bytes::Buf;
use futures::StreamExt;
use reqwest::r#async::Chunk;
use reqwest::{
r#async::{multipart::Form, Client},
r#async::{multipart::Form, Client, Response},
StatusCode,
};
use serde::{de::DeserializeOwned, Serialize};
@ -49,7 +49,8 @@ pub async fn request_multipart<T: DeserializeOwned>(
method_name: &str,
params: Option<Form>,
) -> ResponseResult<T> {
let mut response = client
process_response(
client
.post(&method_url(TELEGRAM_API_URL, token, method_name))
.apply(|request_builder| match params {
Some(params) => request_builder.multipart(params),
@ -57,14 +58,9 @@ pub async fn request_multipart<T: DeserializeOwned>(
})
.send()
.await
.map_err(RequestError::NetworkError)?;
let response = serde_json::from_str::<TelegramResponse<T>>(
&response.text().await.map_err(RequestError::NetworkError)?,
.map_err(RequestError::NetworkError)?,
)
.map_err(RequestError::InvalidJson)?;
response.into()
.await
}
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,
params: &P,
) -> ResponseResult<T> {
let mut response = client
process_response(
client
.post(&method_url(TELEGRAM_API_URL, token, method_name))
.json(params)
.send()
.await
.map_err(RequestError::NetworkError)?;
.map_err(RequestError::NetworkError)?,
)
.await
}
async fn process_response<T: DeserializeOwned>(
mut response: Response,
) -> ResponseResult<T> {
let response = serde_json::from_str::<TelegramResponse<T>>(
&response.text().await.map_err(RequestError::NetworkError)?,
)
@ -92,14 +95,14 @@ pub async fn request_json<T: DeserializeOwned, P: Serialize>(
#[serde(untagged)]
enum TelegramResponse<R> {
Ok {
/// Dummy field. Used for deserialization.
/// A dummy field. Used only for deserialization.
#[allow(dead_code)]
ok: bool, // TODO: True type
result: R,
},
Err {
/// Dummy field. Used for deserialization.
/// A dummy field. Used only for deserialization.
#[allow(dead_code)]
ok: bool, // TODO: False type

View file

@ -1,8 +1,19 @@
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)]
struct GetUserProfilePhotos<'a> {
#[serde(skip_serializing)]
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>,
}

View file

@ -1,6 +1,10 @@
use crate::core::requests::RequestContext;
//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)]
struct KickChatMember<'a> {
#[serde(skip_serializing)]

View file

@ -1,17 +1,51 @@
use crate::core::types::PhotoSize;
#[derive(Debug, Deserialize, Eq, Hash, PartialEq, Serialize, Clone)]
#[derive(Debug, Deserialize, Eq, Hash, PartialEq, Clone)]
pub struct Audio {
pub file_id: String,
pub duration: u32,
#[serde(skip_serializing_if = "Option::is_none")]
pub performer: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub title: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub mime_type: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub file_size: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
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)
}
}

View file

@ -1,22 +1,51 @@
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)]
pub struct CallbackQuery {
/// Unique identifier for this query
pub id: String,
/// Sender
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,
/// Data associated with the callback button. Be aware that a bad client
/// can send arbitrary data in this field.
pub data: String,
pub message: Option<Message>,
pub inline_message_id: Option<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);
}
}

View file

@ -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.
#[derive(Debug, Deserialize, Hash, PartialEq, Eq, Clone)]
@ -54,3 +54,74 @@ pub struct ChatMember {
/// his messages, implies can_send_media_messages
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)
}
}

View file

@ -11,13 +11,26 @@ pub struct Message {
pub date: i32,
pub chat: Chat,
#[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)]
#[serde(untagged)]
pub enum MessageKind {
IncomingMessage {
Common {
#[serde(flatten)]
from: Sender,
#[serde(flatten)]
@ -55,8 +68,8 @@ pub enum MessageKind {
migrate_to_chat_id: i64,
migrate_from_chat_id: i64,
},
PinnedMessage {
pinned_message: Box<Message>,
Pinned {
pinned: Box<Message>,
},
Invoice {
invoice: Invoice,

View file

@ -4,7 +4,7 @@ pub use self::{
audio::Audio,
callback_query::CallbackQuery,
chat::{Chat, ChatKind, NonPrivateChatKind},
chat_member::ChatMember,
chat_member::{ChatMember, ChatMemberStatus},
chat_permissions::ChatPermissions,
chat_photo::ChatPhoto,
chosen_inline_result::ChosenInlineResult,

View file

@ -1,5 +1,2 @@
#[derive(Debug, Deserialize, Eq, Hash, PartialEq, Serialize, Clone)]
pub struct PassportData;
#[derive(Debug, Deserialize, Eq, Hash, PartialEq, Serialize, Clone)]
pub struct ChatMemberStatus;

View file

@ -7,3 +7,30 @@ pub struct User {
pub username: 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)
}
}