Merge branch 'dev' into unbox_send_future

This commit is contained in:
Temirkhan Myrzamadi 2019-10-01 13:31:19 +06:00 committed by GitHub
commit 816d2bad2f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
22 changed files with 206 additions and 76 deletions

View file

@ -1,10 +1,10 @@
mod api;
mod download;
use reqwest::r#async::Client;
use crate::requests::RequestContext;
mod api;
mod download;
pub struct Bot {
token: String,
client: Client,

View file

@ -5,11 +5,11 @@ extern crate derive_more;
#[macro_use]
extern crate serde;
mod network;
pub use errors::{DownloadError, RequestError};
mod errors;
mod network;
pub mod bot;
pub mod requests;
pub mod types;
pub use errors::{DownloadError, RequestError};

View file

@ -6,10 +6,9 @@ use tokio::{
stream::Stream,
};
use crate::{
network::{file_url, TELEGRAM_API_URL},
DownloadError,
};
use crate::DownloadError;
use super::TELEGRAM_API_URL;
pub async fn download_file<D>(
client: &Client,
@ -35,7 +34,10 @@ pub async fn download_file_stream(
token: &str,
path: &str,
) -> Result<impl Stream<Item = Result<Chunk, reqwest::Error>>, reqwest::Error> {
let url = file_url(TELEGRAM_API_URL, token, path);
let resp = client.get(&url).send().await?.error_for_status()?;
Ok(resp.into_body())
Ok(client
.get(&super::file_url(TELEGRAM_API_URL, token, path))
.send()
.await?
.error_for_status()?
.into_body())
}

View file

@ -1,12 +1,12 @@
mod download;
mod request;
mod telegram_response;
pub use download::{download_file, download_file_stream};
pub use request::{request_json, request_multipart};
pub use telegram_response::TelegramResponse;
pub const TELEGRAM_API_URL: &str = "https://api.telegram.org";
mod download;
mod request;
mod telegram_response;
const TELEGRAM_API_URL: &str = "https://api.telegram.org";
/// Creates URL for making HTTPS requests. See the [Telegram documentation].
///

View file

@ -2,11 +2,9 @@ use apply::Apply;
use reqwest::r#async::{multipart::Form, Client, Response};
use serde::{de::DeserializeOwned, Serialize};
use crate::{
network::{method_url, TelegramResponse, TELEGRAM_API_URL},
requests::ResponseResult,
RequestError,
};
use crate::{requests::ResponseResult, RequestError};
use super::{TelegramResponse, TELEGRAM_API_URL};
pub async fn request_multipart<T>(
client: &Client,
@ -19,7 +17,7 @@ where
{
process_response(
client
.post(&method_url(TELEGRAM_API_URL, token, method_name))
.post(&super::method_url(TELEGRAM_API_URL, token, method_name))
.apply(|request_builder| match params {
Some(params) => request_builder.multipart(params),
None => request_builder,
@ -39,7 +37,7 @@ pub async fn request_json<T: DeserializeOwned, P: Serialize>(
) -> ResponseResult<T> {
process_response(
client
.post(&method_url(TELEGRAM_API_URL, token, method_name))
.post(&super::method_url(TELEGRAM_API_URL, token, method_name))
.json(params)
.send()
.await
@ -51,10 +49,9 @@ pub async fn request_json<T: DeserializeOwned, P: Serialize>(
async fn process_response<T: DeserializeOwned>(
mut response: Response,
) -> ResponseResult<T> {
let response = serde_json::from_str::<TelegramResponse<T>>(
serde_json::from_str::<TelegramResponse<T>>(
&response.text().await.map_err(RequestError::NetworkError)?,
)
.map_err(RequestError::InvalidJson)?;
response.into()
.map_err(RequestError::InvalidJson)?
.into()
}

View file

@ -72,11 +72,10 @@ impl<'a> GetUserProfilePhotos<'a> {
}
pub fn limit<T>(mut self, limit: T) -> Self
where
T: Into<i64>,
where
T: Into<i64>,
{
self.limit = Some(limit.into());
self
}
}

View file

@ -1,5 +1,4 @@
mod form_builder;
mod utils;
use std::{future::Future, pin::Pin};
use async_trait::async_trait;
use reqwest::r#async::Client;
@ -15,15 +14,21 @@ pub use self::{
get_me::GetMe, get_updates::GetUpdates,
get_user_profile_photos::GetUserProfilePhotos,
kick_chat_member::KickChatMember, pin_chat_message::PinChatMessage,
restrict_chat_member::RestrictChatMember,
promote_chat_member::PromoteChatMember,
restrict_chat_member::RestrictChatMember, send_animation::SendAnimation,
send_audio::SendAudio, send_chat_action::SendChatAction,
send_contact::SendContact, send_location::SendLocation,
send_media_group::SendMediaGroup, send_message::SendMessage,
send_photo::SendPhoto, send_poll::SendPoll, send_venue::SendVenue,
send_contact::SendContact, send_document::SendDocument,
send_location::SendLocation, send_media_group::SendMediaGroup,
send_message::SendMessage, send_photo::SendPhoto, send_poll::SendPoll,
send_venue::SendVenue, send_video::SendVideo,
send_video_note::SendVideoNote, send_voice::SendVoice,
stop_message_live_location::StopMessageLiveLocation,
unban_chat_member::UnbanChatMember,
};
mod form_builder;
mod utils;
pub type ResponseResult<T> = Result<T, RequestError>;
/// Request that can be sent to telegram.
@ -90,15 +95,21 @@ mod get_updates;
mod get_user_profile_photos;
mod kick_chat_member;
mod pin_chat_message;
mod promote_chat_member;
mod restrict_chat_member;
mod send_animation;
mod send_audio;
mod send_chat_action;
mod send_contact;
mod send_document;
mod send_location;
mod send_media_group;
mod send_message;
mod send_photo;
mod send_poll;
mod send_venue;
mod send_video;
mod send_video_note;
mod send_voice;
mod stop_message_live_location;
mod unban_chat_member;

View file

@ -6,30 +6,38 @@ use crate::{
types::True
};
/// Use this method to get up to date information about the chat
/// (current name of the user for one-on-one conversations,
/// current username of a user, group or channel, etc.).
/// Use this method to get up to date information about the chat
/// (current name of the user for one-on-one conversations,
/// current username of a user, group or channel, etc.).
/// Returns a Chat object on success.
#[derive(Debug, Clone, Serialize)]
pub struct PinChatMessage<'a> {
#[serde(skip_serializing)]
ctx: RequestContext<'a>,
/// Unique identifier for the target chat or username
/// Unique identifier for the target chat or username
/// of the target supergroup or channel (in the format @channelusername)
pub chat_id: ChatId,
pub message_id: i32,
pub disable_notification: Option<bool>
pub disable_notification: Option<bool>,
}
impl<'a> PinChatMessage<'a> {
pub(crate) fn new(
ctx: RequestContext<'a>, chat_id: ChatId, message_id: i32
ctx: RequestContext<'a>,
chat_id: ChatId,
message_id: i32,
) -> Self {
Self { ctx, chat_id, message_id, disable_notification: None }
Self {
ctx,
chat_id,
message_id,
disable_notification: None,
}
}
pub fn disable_notification<T>(mut self, val: T) -> Self
where T: Into<bool>
where
T: Into<bool>,
{
self.disable_notification = Some(val.into());
self
@ -39,7 +47,6 @@ impl<'a> PinChatMessage<'a> {
#[async_trait]
impl<'a> Request for PinChatMessage<'a> {
type ReturnValue = True;
async fn send_boxed(self) -> ResponseResult<Self::ReturnValue> {
self.send().await
}

View file

@ -0,0 +1,8 @@
use crate::requests::RequestContext;
///TODO: add implementation
#[derive(Debug, Clone, Serialize)]
pub struct PromoteChatMember<'a> {
#[serde(skip_serializing)]
ctx: RequestContext<'a>,
}

View file

@ -0,0 +1,8 @@
use crate::requests::RequestContext;
///TODO: add implementation
#[derive(Debug, Clone, Serialize)]
pub struct SendAnimation<'a> {
#[serde(skip_serializing)]
ctx: RequestContext<'a>,
}

View file

@ -0,0 +1,8 @@
use crate::requests::RequestContext;
///TODO: add implementation
#[derive(Debug, Clone, Serialize)]
pub struct SendDocument<'a> {
#[serde(skip_serializing)]
ctx: RequestContext<'a>,
}

View file

@ -1,4 +1,5 @@
use async_trait::async_trait;
use serde::Serialize;
use crate::{
network,
@ -6,8 +7,6 @@ use crate::{
types::{Message, ReplyMarkup},
};
use serde::Serialize;
#[derive(Debug, Clone, Serialize)]
/// Use this method to send point on the map. On success, the sent [`Message`]
/// is returned.

View file

@ -0,0 +1,8 @@
use crate::requests::RequestContext;
///TODO: add implementation
#[derive(Debug, Clone, Serialize)]
pub struct SendVideo<'a> {
#[serde(skip_serializing)]
ctx: RequestContext<'a>,
}

View file

@ -0,0 +1,8 @@
use crate::requests::RequestContext;
///TODO: add implementation
#[derive(Debug, Clone, Serialize)]
pub struct SendVideoNote<'a> {
#[serde(skip_serializing)]
ctx: RequestContext<'a>,
}

View file

@ -0,0 +1,8 @@
use crate::requests::RequestContext;
///TODO: add implementation
#[derive(Debug, Clone, Serialize)]
pub struct SendVoice<'a> {
#[serde(skip_serializing)]
ctx: RequestContext<'a>,
}

View file

@ -1,8 +1,65 @@
use crate::requests::RequestContext;
//TODO:: need implementation
use crate::network;
use crate::requests::{
ChatId, Request, RequestContext, RequestFuture, ResponseResult,
};
/// Use this method to unban a previously kicked user in a supergroup or
/// channel. The user will not return to the group or channel automatically, but
/// will be able to join via link, etc. The bot must be an administrator for
/// this to work. Returns True on success.
#[derive(Debug, Clone, Serialize)]
pub struct UnbanChatMember<'a> {
#[serde(skip_serializing)]
ctx: RequestContext<'a>,
///Unique identifier for the target group or username of the target
/// supergroup or channel (in the format @channelusername)
pub chat_id: ChatId,
/// Unique identifier of the target user
pub user_id: i32,
}
impl<'a> Request<'a> for UnbanChatMember<'a> {
type ReturnValue = bool;
fn send(self) -> RequestFuture<'a, ResponseResult<Self::ReturnValue>> {
Box::pin(async move {
network::request_json(
&self.ctx.client,
&self.ctx.token,
"unbanChatMember",
&self,
)
.await
})
}
}
impl<'a> UnbanChatMember<'a> {
pub(crate) fn new(
ctx: RequestContext<'a>,
chat_id: ChatId,
user_id: i32,
) -> Self {
Self {
ctx,
chat_id,
user_id,
}
}
pub fn chat_id<T>(mut self, chat_id: T) -> Self
where
T: Into<ChatId>,
{
self.chat_id = chat_id.into();
self
}
pub fn user_id<T>(mut self, user_id: T) -> Self
where
T: Into<i32>,
{
self.user_id = user_id.into();
self
}
}

View file

@ -80,9 +80,10 @@ where
#[cfg(test)]
mod tests {
use crate::types::*;
use serde_json::from_str;
use crate::types::*;
#[test]
fn channel_de() {
let expected = Chat {
@ -113,9 +114,9 @@ mod tests {
type_: (),
username: Some("username".into()),
first_name: Some("Anon".into()),
last_name: None
last_name: None,
},
photo: None
photo: None,
},
from_str(
r#"{"id":0,"type":"private","username":"username","first_name":"Anon"}"#

View file

@ -4,64 +4,68 @@ use super::passport_file::PassportFile;
pub struct EncryptedPassportElement {
pub hash: String,
#[serde(flatten)]
pub kind: EncryptedPassportElementKind
pub kind: EncryptedPassportElementKind,
}
#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum EncryptedPassportElementKind {
PersonalDetails {
data: String
data: String,
},
Passport {
data: String,
front_side: PassportFile,
selfie: PassportFile,
translation: Option<Vec<PassportFile>>
translation: Option<Vec<PassportFile>>,
},
DriverLicense {
data: String,
front_side: PassportFile,
reverse_side: PassportFile,
selfie: PassportFile,
translation: Option<Vec<PassportFile>>
translation: Option<Vec<PassportFile>>,
},
IdentityCard {
data: String,
front_side: PassportFile,
reverse_side: PassportFile,
selfie: PassportFile,
translation: Option<Vec<PassportFile>>
translation: Option<Vec<PassportFile>>,
},
InternalPassport {
data: String,
front_side: PassportFile,
selfie: PassportFile,
translation: Option<Vec<PassportFile>>
translation: Option<Vec<PassportFile>>,
},
Address {
data: String
data: String,
},
UtilityBill {
files: Vec<PassportFile>,
translation: Option<Vec<PassportFile>>
translation: Option<Vec<PassportFile>>,
},
BankStatement {
files: Vec<PassportFile>,
translation: Option<Vec<PassportFile>>
translation: Option<Vec<PassportFile>>,
},
RentalAgreement {
files: Vec<PassportFile>,
translation: Option<Vec<PassportFile>>
translation: Option<Vec<PassportFile>>,
},
PassportRegistration {
files: Vec<PassportFile>,
translation: Option<Vec<PassportFile>>
translation: Option<Vec<PassportFile>>,
},
TemporaryRegistration {
files: Vec<PassportFile>,
translation: Option<Vec<PassportFile>>
translation: Option<Vec<PassportFile>>,
},
PhoneNumber {
phone_number: String,
},
Email {
email: String,
},
PhoneNumber { phone_number: String },
Email { email: String }
}

View file

@ -203,9 +203,10 @@ pub enum MediaKind {
#[cfg(test)]
mod tests {
use crate::types::*;
use serde_json::from_str;
use crate::types::*;
#[test]
fn de_media_forwarded() {
let json = r#"{

View file

@ -12,7 +12,9 @@ pub use self::{
contact::Contact,
document::Document,
encrypted_credintials::EncryptedCredentials,
encrypted_passport_element::{EncryptedPassportElement, EncryptedPassportElementKind},
encrypted_passport_element::{
EncryptedPassportElement, EncryptedPassportElementKind,
},
file::File,
force_reply::ForceReply,
game::Game,

View file

@ -16,7 +16,7 @@ impl std::convert::TryFrom<bool> for True {
fn try_from(value: bool) -> Result<Self, Self::Error> {
match value {
true => Ok(True),
false => Err(())
false => Err(()),
}
}
}
@ -24,7 +24,7 @@ impl std::convert::TryFrom<bool> for True {
impl<'de> Deserialize<'de> for True {
fn deserialize<D>(des: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>
D: Deserializer<'de>,
{
des.deserialize_bool(TrueVisitor)
}
@ -41,11 +41,11 @@ impl<'de> Visitor<'de> for TrueVisitor {
fn visit_bool<E>(self, value: bool) -> Result<Self::Value, E>
where
E: de::Error
E: de::Error,
{
match value {
true => Ok(True),
false => Err(E::custom("expected `true`, found `false`"))
false => Err(E::custom("expected `true`, found `false`")),
}
}
}
@ -61,9 +61,10 @@ impl Serialize for True {
#[cfg(test)]
mod tests {
use super::True;
use serde_json::{from_str, to_string};
use super::True;
#[test]
fn unit_true_de() {
let json = "true";

View file

@ -16,7 +16,8 @@ pub enum UpdateKind {
EditedMessage(Message),
ChannelPost(Message),
EditedChannelPost(Message),
InlineQuery(()), // TODO
InlineQuery(()),
// TODO
ChosenInlineResult(ChosenInlineResult),
CallbackQuery(CallbackQuery),
}