mirror of
https://github.com/teloxide/teloxide.git
synced 2024-10-23 17:36:54 +02:00
Merge branch 'dev' into dispatcher
This commit is contained in:
commit
edeff3305a
44 changed files with 1223 additions and 448 deletions
|
@ -17,4 +17,5 @@ bytes = "0.4.12"
|
|||
log = "0.4.8"
|
||||
futures-preview = "0.3.0-alpha.18"
|
||||
pin-project = "0.4.0-alpha.7"
|
||||
async-trait = "0.1.13"
|
||||
libc = "0.2.62"
|
||||
|
|
|
@ -26,7 +26,8 @@ impl Bot {
|
|||
/// let bot = Bot::new("TOKEN");
|
||||
/// let mut file = File::create("/home/waffle/Pictures/test.png").await?;
|
||||
///
|
||||
/// let TgFile { file_path, .. } = bot.get_file("*file_id*").send().await?;
|
||||
/// let TgFile { file_path, .. } =
|
||||
/// bot.get_file("*file_id*").send_boxed().await?;
|
||||
/// bot.download_file(&file_path, &mut file).await?;
|
||||
/// # Ok(()) }
|
||||
/// ```
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -5,12 +5,12 @@ 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 dispatcher;
|
||||
pub mod requests;
|
||||
pub mod types;
|
||||
|
||||
pub use errors::{DownloadError, RequestError};
|
||||
|
|
|
@ -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())
|
||||
}
|
||||
|
|
|
@ -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].
|
||||
///
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
use async_trait::async_trait;
|
||||
|
||||
use crate::{
|
||||
network,
|
||||
requests::{Request, RequestContext, RequestFuture, ResponseResult},
|
||||
types::True
|
||||
requests::{Request, RequestContext, ResponseResult},
|
||||
types::True,
|
||||
};
|
||||
|
||||
#[derive(Debug, Serialize, Clone)]
|
||||
|
@ -32,19 +34,24 @@ pub struct AnswerPreCheckoutQuery<'a> {
|
|||
pub error_message: Option<String>,
|
||||
}
|
||||
|
||||
impl<'a> Request<'a> for AnswerPreCheckoutQuery<'a> {
|
||||
#[async_trait]
|
||||
impl Request for AnswerPreCheckoutQuery<'_> {
|
||||
type ReturnValue = True;
|
||||
|
||||
fn send(self) -> RequestFuture<'a, ResponseResult<Self::ReturnValue>> {
|
||||
Box::pin(async move {
|
||||
network::request_json(
|
||||
&self.ctx.client,
|
||||
&self.ctx.token,
|
||||
"answerPreCheckoutQuery",
|
||||
&self,
|
||||
)
|
||||
.await
|
||||
})
|
||||
async fn send_boxed(self) -> ResponseResult<Self::ReturnValue> {
|
||||
self.send().await
|
||||
}
|
||||
}
|
||||
|
||||
impl AnswerPreCheckoutQuery<'_> {
|
||||
pub async fn send(self) -> ResponseResult<True> {
|
||||
network::request_json(
|
||||
&self.ctx.client,
|
||||
&self.ctx.token,
|
||||
"answerPreCheckoutQuery",
|
||||
&self,
|
||||
)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
use async_trait::async_trait;
|
||||
|
||||
use crate::{
|
||||
network,
|
||||
requests::{Request, RequestContext, RequestFuture, ResponseResult},
|
||||
requests::{Request, RequestContext, ResponseResult},
|
||||
types::{ShippingOption, True},
|
||||
};
|
||||
|
||||
|
@ -33,19 +35,24 @@ pub struct AnswerShippingQuery<'a> {
|
|||
pub error_message: Option<String>,
|
||||
}
|
||||
|
||||
impl<'a> Request<'a> for AnswerShippingQuery<'a> {
|
||||
#[async_trait]
|
||||
impl Request for AnswerShippingQuery<'_> {
|
||||
type ReturnValue = True;
|
||||
|
||||
fn send(self) -> RequestFuture<'a, ResponseResult<Self::ReturnValue>> {
|
||||
Box::pin(async move {
|
||||
network::request_json(
|
||||
&self.ctx.client,
|
||||
&self.ctx.token,
|
||||
"answerShippingQuery",
|
||||
&self,
|
||||
)
|
||||
.await
|
||||
})
|
||||
async fn send_boxed(self) -> ResponseResult<Self::ReturnValue> {
|
||||
self.send().await
|
||||
}
|
||||
}
|
||||
|
||||
impl AnswerShippingQuery<'_> {
|
||||
pub async fn send(self) -> ResponseResult<True> {
|
||||
network::request_json(
|
||||
&self.ctx.client,
|
||||
&self.ctx.token,
|
||||
"answerShippingQuery",
|
||||
&self,
|
||||
)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
use async_trait::async_trait;
|
||||
|
||||
use crate::{
|
||||
network,
|
||||
requests::{
|
||||
ChatId, Request, RequestContext, RequestFuture, ResponseResult,
|
||||
},
|
||||
requests::{ChatId, Request, RequestContext, ResponseResult},
|
||||
types::{Message, ReplyMarkup},
|
||||
};
|
||||
|
||||
|
@ -38,19 +38,24 @@ pub struct EditMessageLiveLocation<'a> {
|
|||
reply_markup: Option<ReplyMarkup>,
|
||||
}
|
||||
|
||||
impl<'a> Request<'a> for EditMessageLiveLocation<'a> {
|
||||
#[async_trait]
|
||||
impl Request for EditMessageLiveLocation<'_> {
|
||||
type ReturnValue = Message;
|
||||
|
||||
fn send(self) -> RequestFuture<'a, ResponseResult<Self::ReturnValue>> {
|
||||
Box::pin(async move {
|
||||
network::request_json(
|
||||
&self.ctx.client,
|
||||
&self.ctx.token,
|
||||
"editMessageLiveLocation",
|
||||
&self,
|
||||
)
|
||||
.await
|
||||
})
|
||||
async fn send_boxed(self) -> ResponseResult<Self::ReturnValue> {
|
||||
self.send().await
|
||||
}
|
||||
}
|
||||
|
||||
impl EditMessageLiveLocation<'_> {
|
||||
pub async fn send(self) -> ResponseResult<Message> {
|
||||
network::request_json(
|
||||
&self.ctx.client,
|
||||
&self.ctx.token,
|
||||
"editMessageLiveLocation",
|
||||
&self,
|
||||
)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
use async_trait::async_trait;
|
||||
|
||||
use crate::{
|
||||
network,
|
||||
requests::{
|
||||
ChatId, Request, RequestContext, RequestFuture, ResponseResult,
|
||||
},
|
||||
requests::{ChatId, Request, RequestContext, ResponseResult},
|
||||
types::Message,
|
||||
};
|
||||
|
||||
|
@ -28,19 +28,24 @@ pub struct ForwardMessage<'a> {
|
|||
pub disable_notification: Option<bool>,
|
||||
}
|
||||
|
||||
impl<'a> Request<'a> for ForwardMessage<'a> {
|
||||
#[async_trait]
|
||||
impl Request for ForwardMessage<'_> {
|
||||
type ReturnValue = Message;
|
||||
|
||||
fn send(self) -> RequestFuture<'a, ResponseResult<Self::ReturnValue>> {
|
||||
Box::pin(async move {
|
||||
network::request_json(
|
||||
self.ctx.client,
|
||||
self.ctx.token,
|
||||
"forwardMessage",
|
||||
&self,
|
||||
)
|
||||
.await
|
||||
})
|
||||
async fn send_boxed(self) -> ResponseResult<Self::ReturnValue> {
|
||||
self.send().await
|
||||
}
|
||||
}
|
||||
|
||||
impl ForwardMessage<'_> {
|
||||
pub async fn send(self) -> ResponseResult<Message> {
|
||||
network::request_json(
|
||||
self.ctx.client,
|
||||
self.ctx.token,
|
||||
"forwardMessage",
|
||||
&self,
|
||||
)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
use async_trait::async_trait;
|
||||
|
||||
use crate::{
|
||||
network,
|
||||
requests::{
|
||||
ChatId, Request, RequestContext, RequestFuture, ResponseResult,
|
||||
},
|
||||
requests::{ChatId, Request, RequestContext, ResponseResult},
|
||||
types::Chat,
|
||||
};
|
||||
|
||||
|
@ -19,19 +19,24 @@ pub struct GetChat<'a> {
|
|||
chat_id: ChatId,
|
||||
}
|
||||
|
||||
impl<'a> Request<'a> for GetChat<'a> {
|
||||
#[async_trait]
|
||||
impl Request for GetChat<'_> {
|
||||
type ReturnValue = Chat;
|
||||
|
||||
fn send(self) -> RequestFuture<'a, ResponseResult<Self::ReturnValue>> {
|
||||
Box::pin(async move {
|
||||
network::request_json(
|
||||
&self.ctx.client,
|
||||
&self.ctx.token,
|
||||
"getChat",
|
||||
&self,
|
||||
)
|
||||
.await
|
||||
})
|
||||
async fn send_boxed(self) -> ResponseResult<Self::ReturnValue> {
|
||||
self.send().await
|
||||
}
|
||||
}
|
||||
|
||||
impl GetChat<'_> {
|
||||
pub async fn send(self) -> ResponseResult<Chat> {
|
||||
network::request_json(
|
||||
&self.ctx.client,
|
||||
&self.ctx.token,
|
||||
"getChat",
|
||||
&self,
|
||||
)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
use async_trait::async_trait;
|
||||
|
||||
use crate::{
|
||||
network,
|
||||
requests::{Request, RequestContext, RequestFuture, ResponseResult},
|
||||
requests::{Request, RequestContext, ResponseResult},
|
||||
types::File,
|
||||
};
|
||||
|
||||
|
@ -19,19 +21,24 @@ pub struct GetFile<'a> {
|
|||
pub file_id: String,
|
||||
}
|
||||
|
||||
impl<'a> Request<'a> for GetFile<'a> {
|
||||
#[async_trait]
|
||||
impl Request for GetFile<'_> {
|
||||
type ReturnValue = File;
|
||||
|
||||
fn send(self) -> RequestFuture<'a, ResponseResult<Self::ReturnValue>> {
|
||||
Box::pin(async move {
|
||||
network::request_json(
|
||||
&self.ctx.client,
|
||||
&self.ctx.token,
|
||||
"getFile",
|
||||
&self,
|
||||
)
|
||||
.await
|
||||
})
|
||||
async fn send_boxed(self) -> ResponseResult<Self::ReturnValue> {
|
||||
self.send().await
|
||||
}
|
||||
}
|
||||
|
||||
impl GetFile<'_> {
|
||||
pub async fn send(self) -> ResponseResult<File> {
|
||||
network::request_json(
|
||||
&self.ctx.client,
|
||||
&self.ctx.token,
|
||||
"getFile",
|
||||
&self,
|
||||
)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
use async_trait::async_trait;
|
||||
|
||||
use crate::{
|
||||
network,
|
||||
requests::{Request, RequestContext, RequestFuture, ResponseResult},
|
||||
requests::{Request, RequestContext, ResponseResult},
|
||||
types::User,
|
||||
};
|
||||
|
||||
|
@ -11,16 +13,24 @@ pub struct GetMe<'a> {
|
|||
ctx: RequestContext<'a>,
|
||||
}
|
||||
|
||||
impl<'a> Request<'a> for GetMe<'a> {
|
||||
#[async_trait]
|
||||
impl Request for GetMe<'_> {
|
||||
type ReturnValue = User;
|
||||
|
||||
fn send(self) -> RequestFuture<'a, ResponseResult<Self::ReturnValue>> {
|
||||
Box::pin(network::request_multipart(
|
||||
async fn send_boxed(self) -> ResponseResult<Self::ReturnValue> {
|
||||
self.send().await
|
||||
}
|
||||
}
|
||||
|
||||
impl GetMe<'_> {
|
||||
pub async fn send(self) -> ResponseResult<User> {
|
||||
network::request_multipart(
|
||||
self.ctx.client,
|
||||
self.ctx.token,
|
||||
"getMe",
|
||||
None,
|
||||
))
|
||||
)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
use async_trait::async_trait;
|
||||
|
||||
use crate::{
|
||||
network,
|
||||
requests::{Request, RequestContext, RequestFuture, ResponseResult},
|
||||
requests::{Request, RequestContext, ResponseResult},
|
||||
types::Update,
|
||||
};
|
||||
|
||||
|
@ -27,19 +29,24 @@ pub enum AllowedUpdate {
|
|||
CallbackQuery,
|
||||
}
|
||||
|
||||
impl<'a> Request<'a> for GetUpdates<'a> {
|
||||
#[async_trait]
|
||||
impl Request for GetUpdates<'_> {
|
||||
type ReturnValue = Vec<Update>;
|
||||
|
||||
fn send(self) -> RequestFuture<'a, ResponseResult<Self::ReturnValue>> {
|
||||
Box::pin(async move {
|
||||
network::request_json(
|
||||
&self.ctx.client,
|
||||
&self.ctx.token,
|
||||
"getUpdates",
|
||||
&self,
|
||||
)
|
||||
.await
|
||||
})
|
||||
async fn send_boxed(self) -> ResponseResult<Self::ReturnValue> {
|
||||
self.send().await
|
||||
}
|
||||
}
|
||||
|
||||
impl GetUpdates<'_> {
|
||||
pub async fn send(self) -> ResponseResult<Vec<Update>> {
|
||||
network::request_json(
|
||||
&self.ctx.client,
|
||||
&self.ctx.token,
|
||||
"getUpdates",
|
||||
&self,
|
||||
)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
use crate::network;
|
||||
use crate::requests::{Request, RequestContext, RequestFuture, ResponseResult};
|
||||
use crate::types::UserProfilePhotos;
|
||||
use async_trait::async_trait;
|
||||
|
||||
use crate::{
|
||||
network,
|
||||
requests::{Request, RequestContext, ResponseResult},
|
||||
types::UserProfilePhotos,
|
||||
};
|
||||
|
||||
///Use this method to get a list of profile pictures for a user. Returns a
|
||||
/// UserProfilePhotos object.
|
||||
|
@ -20,19 +24,24 @@ pub struct GetUserProfilePhotos<'a> {
|
|||
pub limit: Option<i64>,
|
||||
}
|
||||
|
||||
impl<'a> Request<'a> for GetUserProfilePhotos<'a> {
|
||||
#[async_trait]
|
||||
impl Request for GetUserProfilePhotos<'_> {
|
||||
type ReturnValue = UserProfilePhotos;
|
||||
|
||||
fn send(self) -> RequestFuture<'a, ResponseResult<Self::ReturnValue>> {
|
||||
Box::pin(async move {
|
||||
network::request_json(
|
||||
&self.ctx.client,
|
||||
&self.ctx.token,
|
||||
"getUserProfilePhotos",
|
||||
&self,
|
||||
)
|
||||
.await
|
||||
})
|
||||
async fn send_boxed(self) -> ResponseResult<Self::ReturnValue> {
|
||||
self.send().await
|
||||
}
|
||||
}
|
||||
|
||||
impl GetUserProfilePhotos<'_> {
|
||||
async fn send(self) -> ResponseResult<UserProfilePhotos> {
|
||||
network::request_json(
|
||||
&self.ctx.client,
|
||||
&self.ctx.token,
|
||||
"getUserProfilePhotos",
|
||||
&self,
|
||||
)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -63,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
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
use crate::network;
|
||||
use crate::requests::{
|
||||
ChatId, Request, RequestContext, RequestFuture, ResponseResult,
|
||||
use async_trait::async_trait;
|
||||
|
||||
use crate::{
|
||||
network,
|
||||
requests::{ChatId, Request, RequestContext, ResponseResult},
|
||||
types::True,
|
||||
};
|
||||
use crate::types::True;
|
||||
|
||||
/// 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
|
||||
|
@ -25,19 +27,24 @@ pub struct KickChatMember<'a> {
|
|||
pub until_date: Option<u64>,
|
||||
}
|
||||
|
||||
impl<'a> Request<'a> for KickChatMember<'a> {
|
||||
#[async_trait]
|
||||
impl<'a> Request for KickChatMember<'a> {
|
||||
type ReturnValue = True;
|
||||
|
||||
fn send(self) -> RequestFuture<'a, ResponseResult<Self::ReturnValue>> {
|
||||
Box::pin(async move {
|
||||
network::request_json(
|
||||
self.ctx.client,
|
||||
self.ctx.token,
|
||||
"kickChatMember",
|
||||
&self,
|
||||
)
|
||||
.await
|
||||
})
|
||||
async fn send_boxed(self) -> ResponseResult<Self::ReturnValue> {
|
||||
self.send().await
|
||||
}
|
||||
}
|
||||
|
||||
impl KickChatMember<'_> {
|
||||
async fn send(self) -> ResponseResult<True> {
|
||||
network::request_json(
|
||||
self.ctx.client,
|
||||
self.ctx.token,
|
||||
"kickChatMember",
|
||||
&self,
|
||||
)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
mod form_builder;
|
||||
mod utils;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use reqwest::r#async::Client;
|
||||
use serde::de::DeserializeOwned;
|
||||
use std::{future::Future, pin::Pin};
|
||||
|
||||
use crate::RequestError;
|
||||
|
||||
|
@ -15,28 +12,33 @@ 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,
|
||||
unban_chat_member::UnbanChatMember, unpin_chat_message::UnpinChatMessage,
|
||||
};
|
||||
|
||||
mod form_builder;
|
||||
mod utils;
|
||||
|
||||
pub type ResponseResult<T> = Result<T, RequestError>;
|
||||
|
||||
/// Request that can be sent to telegram.
|
||||
/// `ReturnValue` - a type that will be returned from Telegram.
|
||||
pub trait Request<'a> {
|
||||
#[async_trait]
|
||||
pub trait Request {
|
||||
type ReturnValue: DeserializeOwned;
|
||||
|
||||
/// Send request to telegram
|
||||
fn send(self) -> RequestFuture<'a, ResponseResult<Self::ReturnValue>>;
|
||||
async fn send_boxed(self) -> ResponseResult<Self::ReturnValue>;
|
||||
}
|
||||
|
||||
pub type RequestFuture<'a, T> = Pin<Box<dyn Future<Output = T> + Send + 'a>>;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct RequestContext<'a> {
|
||||
pub client: &'a Client,
|
||||
|
@ -91,15 +93,22 @@ 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;
|
||||
mod unpin_chat_message;
|
||||
|
|
|
@ -1,50 +1,65 @@
|
|||
use crate::{
|
||||
requests::{ChatId, RequestContext, RequestFuture, ResponseResult, Request},
|
||||
types::True
|
||||
};
|
||||
use crate::network;
|
||||
use async_trait::async_trait;
|
||||
|
||||
/// 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 crate::{
|
||||
network,
|
||||
requests::{ChatId, Request, RequestContext, ResponseResult},
|
||||
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.).
|
||||
/// 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
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Request<'a> for PinChatMessage<'a> {
|
||||
#[async_trait]
|
||||
impl<'a> Request for PinChatMessage<'a> {
|
||||
type ReturnValue = True;
|
||||
|
||||
fn send(self) -> RequestFuture<'a, ResponseResult<Self::ReturnValue>> {
|
||||
Box::pin(async move {
|
||||
network::request_json(
|
||||
&self.ctx.client,
|
||||
&self.ctx.token,
|
||||
"pinChatMessage",
|
||||
&self,
|
||||
).await
|
||||
})
|
||||
async fn send_boxed(self) -> ResponseResult<Self::ReturnValue> {
|
||||
self.send().await
|
||||
}
|
||||
}
|
||||
|
||||
impl PinChatMessage<'_> {
|
||||
async fn send(self) -> ResponseResult<True> {
|
||||
network::request_json(
|
||||
&self.ctx.client,
|
||||
&self.ctx.token,
|
||||
"pinChatMessage",
|
||||
&self,
|
||||
)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
|
170
src/requests/promote_chat_member.rs
Normal file
170
src/requests/promote_chat_member.rs
Normal file
|
@ -0,0 +1,170 @@
|
|||
use crate::network;
|
||||
use crate::requests::{ChatId, Request, RequestContext, ResponseResult};
|
||||
use crate::types::True;
|
||||
|
||||
use async_trait::async_trait;
|
||||
|
||||
///Use this method to promote or demote a user in a supergroup or a channel.
|
||||
/// The bot must be an administrator in the chat for this to work and must have
|
||||
/// the appropriate admin rights. Pass False for all boolean parameters to
|
||||
/// demote a user. Returns True on success.
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
pub struct PromoteChatMember<'a> {
|
||||
#[serde(skip_serializing)]
|
||||
ctx: RequestContext<'a>,
|
||||
///Unique identifier for the target chat or username of the target channel
|
||||
/// (in the format @channelusername)
|
||||
pub chat_id: ChatId,
|
||||
///Unique identifier of the target user
|
||||
pub user_id: i32,
|
||||
///Pass True, if the administrator can change chat title, photo and other
|
||||
/// settings
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
can_change_info: Option<bool>,
|
||||
///Pass True, if the administrator can create channel posts, channels only
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub can_post_messages: Option<bool>,
|
||||
///Pass True, if the administrator can edit messages of other users and
|
||||
/// can pin messages, channels only
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub can_edit_messages: Option<bool>,
|
||||
///Pass True, if the administrator can delete messages of other users
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub can_delete_messages: Option<bool>,
|
||||
///Pass True, if the administrator can invite new users to the chat
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub can_invite_users: Option<bool>,
|
||||
///Pass True, if the administrator can restrict, ban or unban chat members
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub can_restrict_members: Option<bool>,
|
||||
///Pass True, if the administrator can pin messages, supergroups only
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub can_pin_messages: Option<bool>,
|
||||
///Pass True, if the administrator can add new administrators with a
|
||||
/// subset of his own privileges or demote administrators that he has
|
||||
/// promoted, directly or indirectly (promoted by administrators that were
|
||||
/// appointed by him)
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub can_promote_members: Option<bool>,
|
||||
}
|
||||
#[async_trait]
|
||||
impl Request for PromoteChatMember<'_> {
|
||||
type ReturnValue = True;
|
||||
|
||||
async fn send_boxed(self) -> ResponseResult<Self::ReturnValue> {
|
||||
self.send().await
|
||||
}
|
||||
}
|
||||
|
||||
impl PromoteChatMember<'_> {
|
||||
pub async fn send(self) -> ResponseResult<True> {
|
||||
network::request_json(
|
||||
&self.ctx.client,
|
||||
&self.ctx.token,
|
||||
"promoteChatMember",
|
||||
&self,
|
||||
)
|
||||
.await
|
||||
}
|
||||
}
|
||||
impl<'a> PromoteChatMember<'a> {
|
||||
pub(crate) fn new(
|
||||
ctx: RequestContext<'a>,
|
||||
chat_id: ChatId,
|
||||
user_id: i32,
|
||||
) -> Self {
|
||||
Self {
|
||||
ctx,
|
||||
chat_id,
|
||||
user_id,
|
||||
can_change_info: None,
|
||||
can_post_messages: None,
|
||||
can_edit_messages: None,
|
||||
can_delete_messages: None,
|
||||
can_invite_users: None,
|
||||
can_restrict_members: None,
|
||||
can_pin_messages: None,
|
||||
can_promote_members: None,
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
pub fn can_change_info<T>(mut self, can_change_info: T) -> Self
|
||||
where
|
||||
T: Into<bool>,
|
||||
{
|
||||
self.can_change_info = Some(can_change_info.into());
|
||||
self
|
||||
}
|
||||
|
||||
pub fn can_post_messages<T>(mut self, can_post_messages: T) -> Self
|
||||
where
|
||||
T: Into<bool>,
|
||||
{
|
||||
self.can_post_messages = Some(can_post_messages.into());
|
||||
self
|
||||
}
|
||||
|
||||
pub fn can_edit_messages<T>(mut self, can_edit_messages: T) -> Self
|
||||
where
|
||||
T: Into<bool>,
|
||||
{
|
||||
self.can_edit_messages = Some(can_edit_messages.into());
|
||||
self
|
||||
}
|
||||
|
||||
pub fn can_delete_messages<T>(mut self, can_delete_messages: T) -> Self
|
||||
where
|
||||
T: Into<bool>,
|
||||
{
|
||||
self.can_delete_messages = Some(can_delete_messages.into());
|
||||
self
|
||||
}
|
||||
|
||||
pub fn can_invite_users<T>(mut self, can_invite_users: T) -> Self
|
||||
where
|
||||
T: Into<bool>,
|
||||
{
|
||||
self.can_invite_users = Some(can_invite_users.into());
|
||||
self
|
||||
}
|
||||
|
||||
pub fn can_restrict_members<T>(mut self, can_restrict_members: T) -> Self
|
||||
where
|
||||
T: Into<bool>,
|
||||
{
|
||||
self.can_restrict_members = Some(can_restrict_members.into());
|
||||
self
|
||||
}
|
||||
|
||||
pub fn can_pin_messages<T>(mut self, can_pin_messages: T) -> Self
|
||||
where
|
||||
T: Into<bool>,
|
||||
{
|
||||
self.can_pin_messages = Some(can_pin_messages.into());
|
||||
self
|
||||
}
|
||||
|
||||
pub fn can_promote_members<T>(mut self, can_promote_members: T) -> Self
|
||||
where
|
||||
T: Into<bool>,
|
||||
{
|
||||
self.can_promote_members = Some(can_promote_members.into());
|
||||
self
|
||||
}
|
||||
}
|
|
@ -1,8 +1,9 @@
|
|||
use crate::network;
|
||||
use crate::requests::{
|
||||
ChatId, Request, RequestContext, RequestFuture, ResponseResult,
|
||||
use crate::{
|
||||
network,
|
||||
requests::{ChatId, Request, RequestContext, ResponseResult},
|
||||
types::{ChatPermissions, True},
|
||||
};
|
||||
use crate::types::{ChatPermissions, True};
|
||||
use async_trait::async_trait;
|
||||
|
||||
/// Use this method to restrict a user in a supergroup. The bot must be an
|
||||
/// administrator in the supergroup for this to work and must have the
|
||||
|
@ -26,19 +27,24 @@ pub struct RestrictChatMember<'a> {
|
|||
pub until_date: Option<u64>,
|
||||
}
|
||||
|
||||
impl<'a> Request<'a> for RestrictChatMember<'a> {
|
||||
#[async_trait]
|
||||
impl<'a> Request for RestrictChatMember<'a> {
|
||||
type ReturnValue = True;
|
||||
|
||||
fn send(self) -> RequestFuture<'a, ResponseResult<Self::ReturnValue>> {
|
||||
Box::pin(async move {
|
||||
network::request_json(
|
||||
&self.ctx.client,
|
||||
&self.ctx.token,
|
||||
"restrictChatMember",
|
||||
&self,
|
||||
)
|
||||
.await
|
||||
})
|
||||
async fn send_boxed(self) -> ResponseResult<Self::ReturnValue> {
|
||||
self.send().await
|
||||
}
|
||||
}
|
||||
|
||||
impl RestrictChatMember<'_> {
|
||||
async fn send(self) -> ResponseResult<True> {
|
||||
network::request_json(
|
||||
&self.ctx.client,
|
||||
&self.ctx.token,
|
||||
"restrictChatMember",
|
||||
&self,
|
||||
)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
|
|
8
src/requests/send_animation.rs
Normal file
8
src/requests/send_animation.rs
Normal 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>,
|
||||
}
|
|
@ -1,8 +1,10 @@
|
|||
use async_trait::async_trait;
|
||||
|
||||
use crate::{
|
||||
network,
|
||||
requests::{
|
||||
form_builder::FormBuilder, ChatId, Request, RequestContext,
|
||||
RequestFuture, ResponseResult,
|
||||
ResponseResult,
|
||||
},
|
||||
types::{InputFile, Message, ParseMode, ReplyMarkup},
|
||||
};
|
||||
|
@ -59,48 +61,53 @@ pub struct SendAudio<'a> {
|
|||
pub reply_markup: Option<ReplyMarkup>,
|
||||
}
|
||||
|
||||
impl<'a> Request<'a> for SendAudio<'a> {
|
||||
#[async_trait]
|
||||
impl Request for SendAudio<'_> {
|
||||
type ReturnValue = Message;
|
||||
|
||||
fn send(self) -> RequestFuture<'a, ResponseResult<Self::ReturnValue>> {
|
||||
Box::pin(async move {
|
||||
let mut params = FormBuilder::new()
|
||||
.add("chat_id", &self.chat_id)
|
||||
.add_if_some("caption", self.caption.as_ref())
|
||||
.add_if_some("parse_mode", self.parse_mode.as_ref())
|
||||
.add_if_some("duration", self.duration.as_ref())
|
||||
.add_if_some("performer", self.performer.as_ref())
|
||||
.add_if_some("title", self.title.as_ref())
|
||||
.add_if_some(
|
||||
"disable_notification",
|
||||
self.disable_notification.as_ref(),
|
||||
)
|
||||
.add_if_some(
|
||||
"reply_to_message_id",
|
||||
self.reply_to_message_id.as_ref(),
|
||||
);
|
||||
params = match self.audio {
|
||||
InputFile::File(file) => params.add_file("audio", &file),
|
||||
InputFile::Url(url) => params.add("audio", &url),
|
||||
InputFile::FileId(file_id) => params.add("audio", &file_id),
|
||||
};
|
||||
if let Some(thumb) = self.thumb {
|
||||
params = match thumb {
|
||||
InputFile::File(file) => params.add_file("thumb", &file),
|
||||
InputFile::Url(url) => params.add("thumb", &url),
|
||||
InputFile::FileId(file_id) => params.add("thumb", &file_id),
|
||||
}
|
||||
}
|
||||
let params = params.build();
|
||||
async fn send_boxed(self) -> ResponseResult<Self::ReturnValue> {
|
||||
self.send().await
|
||||
}
|
||||
}
|
||||
|
||||
network::request_multipart(
|
||||
&self.ctx.client,
|
||||
&self.ctx.token,
|
||||
"sendAudio",
|
||||
Some(params),
|
||||
impl SendAudio<'_> {
|
||||
pub async fn send(self) -> ResponseResult<Message> {
|
||||
let mut params = FormBuilder::new()
|
||||
.add("chat_id", &self.chat_id)
|
||||
.add_if_some("caption", self.caption.as_ref())
|
||||
.add_if_some("parse_mode", self.parse_mode.as_ref())
|
||||
.add_if_some("duration", self.duration.as_ref())
|
||||
.add_if_some("performer", self.performer.as_ref())
|
||||
.add_if_some("title", self.title.as_ref())
|
||||
.add_if_some(
|
||||
"disable_notification",
|
||||
self.disable_notification.as_ref(),
|
||||
)
|
||||
.await
|
||||
})
|
||||
.add_if_some(
|
||||
"reply_to_message_id",
|
||||
self.reply_to_message_id.as_ref(),
|
||||
);
|
||||
params = match self.audio {
|
||||
InputFile::File(file) => params.add_file("audio", &file),
|
||||
InputFile::Url(url) => params.add("audio", &url),
|
||||
InputFile::FileId(file_id) => params.add("audio", &file_id),
|
||||
};
|
||||
if let Some(thumb) = self.thumb {
|
||||
params = match thumb {
|
||||
InputFile::File(file) => params.add_file("thumb", &file),
|
||||
InputFile::Url(url) => params.add("thumb", &url),
|
||||
InputFile::FileId(file_id) => params.add("thumb", &file_id),
|
||||
}
|
||||
}
|
||||
let params = params.build();
|
||||
|
||||
network::request_multipart(
|
||||
&self.ctx.client,
|
||||
&self.ctx.token,
|
||||
"sendAudio",
|
||||
Some(params),
|
||||
)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
use async_trait::async_trait;
|
||||
|
||||
use crate::{
|
||||
network,
|
||||
requests::{
|
||||
ChatId, Request, RequestContext, RequestFuture, ResponseResult,
|
||||
},
|
||||
types::True
|
||||
requests::{ChatId, Request, RequestContext, ResponseResult},
|
||||
types::True,
|
||||
};
|
||||
|
||||
///Use this method when you need to tell the user that something is happening
|
||||
|
@ -40,19 +40,24 @@ pub enum ChatAction {
|
|||
UploadVideoNote,
|
||||
}
|
||||
|
||||
impl<'a> Request<'a> for SendChatAction<'a> {
|
||||
#[async_trait]
|
||||
impl Request for SendChatAction<'_> {
|
||||
type ReturnValue = True;
|
||||
|
||||
fn send(self) -> RequestFuture<'a, ResponseResult<Self::ReturnValue>> {
|
||||
Box::pin(async move {
|
||||
network::request_json(
|
||||
&self.ctx.client,
|
||||
&self.ctx.token,
|
||||
"sendChatAction",
|
||||
&self,
|
||||
)
|
||||
.await
|
||||
})
|
||||
async fn send_boxed(self) -> ResponseResult<Self::ReturnValue> {
|
||||
self.send().await
|
||||
}
|
||||
}
|
||||
|
||||
impl SendChatAction<'_> {
|
||||
pub async fn send(self) -> ResponseResult<True> {
|
||||
network::request_json(
|
||||
&self.ctx.client,
|
||||
&self.ctx.token,
|
||||
"sendChatAction",
|
||||
&self,
|
||||
)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
use async_trait::async_trait;
|
||||
|
||||
use crate::{
|
||||
network,
|
||||
requests::{
|
||||
ChatId, Request, RequestContext, RequestFuture, ResponseResult,
|
||||
},
|
||||
requests::{ChatId, Request, RequestContext, ResponseResult},
|
||||
types::{Message, ReplyMarkup},
|
||||
};
|
||||
|
||||
|
@ -42,19 +42,24 @@ pub struct SendContact<'a> {
|
|||
pub reply_markup: Option<ReplyMarkup>,
|
||||
}
|
||||
|
||||
impl<'a> Request<'a> for SendContact<'a> {
|
||||
#[async_trait]
|
||||
impl Request for SendContact<'_> {
|
||||
type ReturnValue = Message;
|
||||
|
||||
fn send(self) -> RequestFuture<'a, ResponseResult<Self::ReturnValue>> {
|
||||
Box::pin(async move {
|
||||
network::request_json(
|
||||
&self.ctx.client,
|
||||
&self.ctx.token,
|
||||
"sendContact",
|
||||
&self,
|
||||
)
|
||||
.await
|
||||
})
|
||||
async fn send_boxed(self) -> ResponseResult<Self::ReturnValue> {
|
||||
self.send().await
|
||||
}
|
||||
}
|
||||
|
||||
impl SendContact<'_> {
|
||||
pub async fn send(self) -> ResponseResult<Message> {
|
||||
network::request_json(
|
||||
&self.ctx.client,
|
||||
&self.ctx.token,
|
||||
"sendContact",
|
||||
&self,
|
||||
)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
|
|
8
src/requests/send_document.rs
Normal file
8
src/requests/send_document.rs
Normal 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>,
|
||||
}
|
|
@ -1,13 +1,12 @@
|
|||
use async_trait::async_trait;
|
||||
use serde::Serialize;
|
||||
|
||||
use crate::{
|
||||
network,
|
||||
requests::{
|
||||
ChatId, Request, RequestContext, RequestFuture, ResponseResult,
|
||||
},
|
||||
requests::{ChatId, Request, RequestContext, ResponseResult},
|
||||
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.
|
||||
|
@ -38,19 +37,24 @@ pub struct SendLocation<'a> {
|
|||
reply_markup: Option<ReplyMarkup>,
|
||||
}
|
||||
|
||||
impl<'a> Request<'a> for SendLocation<'a> {
|
||||
#[async_trait]
|
||||
impl Request for SendLocation<'_> {
|
||||
type ReturnValue = Message;
|
||||
|
||||
fn send(self) -> RequestFuture<'a, ResponseResult<Self::ReturnValue>> {
|
||||
Box::pin(async move {
|
||||
network::request_json(
|
||||
&self.ctx.client,
|
||||
&self.ctx.token,
|
||||
"sendLocation",
|
||||
&self,
|
||||
)
|
||||
.await
|
||||
})
|
||||
async fn send_boxed(self) -> ResponseResult<Self::ReturnValue> {
|
||||
self.send().await
|
||||
}
|
||||
}
|
||||
|
||||
impl SendLocation<'_> {
|
||||
pub async fn send(self) -> ResponseResult<Message> {
|
||||
network::request_json(
|
||||
&self.ctx.client,
|
||||
&self.ctx.token,
|
||||
"sendLocation",
|
||||
&self,
|
||||
)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
use apply::Apply;
|
||||
use async_trait::async_trait;
|
||||
|
||||
use crate::{
|
||||
network::request_multipart,
|
||||
requests::{
|
||||
form_builder::FormBuilder, ChatId, Request, RequestContext,
|
||||
RequestFuture, ResponseResult,
|
||||
ResponseResult,
|
||||
},
|
||||
types::{InputFile, InputMedia, Message},
|
||||
};
|
||||
|
@ -21,49 +22,51 @@ pub struct SendMediaGroup<'a> {
|
|||
pub reply_to_message_id: Option<i32>,
|
||||
}
|
||||
|
||||
impl<'a> Request<'a> for SendMediaGroup<'a> {
|
||||
#[async_trait]
|
||||
impl Request for SendMediaGroup<'_> {
|
||||
type ReturnValue = Vec<Message>;
|
||||
|
||||
fn send(self) -> RequestFuture<'a, ResponseResult<Self::ReturnValue>> {
|
||||
Box::pin(async move {
|
||||
let params = FormBuilder::new()
|
||||
.add("chat_id", &self.chat_id)
|
||||
.apply(|form| {
|
||||
self.media.iter().map(|e| e.media()).fold(
|
||||
form,
|
||||
|acc, file| {
|
||||
if let InputFile::File(path) = file {
|
||||
acc.add_file(
|
||||
&path
|
||||
.file_name()
|
||||
.unwrap()
|
||||
.to_string_lossy(),
|
||||
path,
|
||||
)
|
||||
} else {
|
||||
acc
|
||||
}
|
||||
},
|
||||
)
|
||||
})
|
||||
.add("media", &self.media)
|
||||
.add_if_some(
|
||||
"disable_notification",
|
||||
self.disable_notification.as_ref(),
|
||||
)
|
||||
.add_if_some(
|
||||
"reply_to_message_id",
|
||||
self.reply_to_message_id.as_ref(),
|
||||
)
|
||||
.build();
|
||||
request_multipart(
|
||||
&self.ctx.client,
|
||||
&self.ctx.token,
|
||||
"sendMediaGroup",
|
||||
Some(params),
|
||||
async fn send_boxed(self) -> ResponseResult<Self::ReturnValue> {
|
||||
self.send().await
|
||||
}
|
||||
}
|
||||
|
||||
impl SendMediaGroup<'_> {
|
||||
pub async fn send(self) -> ResponseResult<Vec<Message>> {
|
||||
let params = FormBuilder::new()
|
||||
.add("chat_id", &self.chat_id)
|
||||
.apply(|form| {
|
||||
self.media
|
||||
.iter()
|
||||
.map(|e| e.media())
|
||||
.fold(form, |acc, file| {
|
||||
if let InputFile::File(path) = file {
|
||||
acc.add_file(
|
||||
&path.file_name().unwrap().to_string_lossy(),
|
||||
path,
|
||||
)
|
||||
} else {
|
||||
acc
|
||||
}
|
||||
})
|
||||
})
|
||||
.add("media", &self.media)
|
||||
.add_if_some(
|
||||
"disable_notification",
|
||||
self.disable_notification.as_ref(),
|
||||
)
|
||||
.await
|
||||
})
|
||||
.add_if_some(
|
||||
"reply_to_message_id",
|
||||
self.reply_to_message_id.as_ref(),
|
||||
)
|
||||
.build();
|
||||
request_multipart(
|
||||
&self.ctx.client,
|
||||
&self.ctx.token,
|
||||
"sendMediaGroup",
|
||||
Some(params),
|
||||
)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
use async_trait::async_trait;
|
||||
|
||||
use crate::{
|
||||
network,
|
||||
requests::{
|
||||
ChatId, Request, RequestContext, RequestFuture, ResponseResult,
|
||||
},
|
||||
requests::{ChatId, Request, RequestContext, ResponseResult},
|
||||
types::{Message, ParseMode, ReplyMarkup},
|
||||
};
|
||||
|
||||
|
@ -43,19 +43,24 @@ pub struct SendMessage<'a> {
|
|||
pub reply_markup: Option<ReplyMarkup>,
|
||||
}
|
||||
|
||||
impl<'a> Request<'a> for SendMessage<'a> {
|
||||
#[async_trait]
|
||||
impl Request for SendMessage<'_> {
|
||||
type ReturnValue = Message;
|
||||
|
||||
fn send(self) -> RequestFuture<'a, ResponseResult<Self::ReturnValue>> {
|
||||
Box::pin(async move {
|
||||
network::request_json(
|
||||
self.ctx.client,
|
||||
self.ctx.token,
|
||||
"sendMessage",
|
||||
&self,
|
||||
)
|
||||
.await
|
||||
})
|
||||
async fn send_boxed(self) -> ResponseResult<Self::ReturnValue> {
|
||||
self.send().await
|
||||
}
|
||||
}
|
||||
|
||||
impl SendMessage<'_> {
|
||||
pub async fn send(self) -> ResponseResult<Message> {
|
||||
network::request_json(
|
||||
self.ctx.client,
|
||||
self.ctx.token,
|
||||
"sendMessage",
|
||||
&self,
|
||||
)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
use async_trait::async_trait;
|
||||
|
||||
use crate::{
|
||||
network,
|
||||
requests::{
|
||||
form_builder::FormBuilder, ChatId, Request, RequestContext,
|
||||
RequestFuture, ResponseResult,
|
||||
ResponseResult,
|
||||
},
|
||||
types::{InputFile, Message, ParseMode, ReplyMarkup},
|
||||
};
|
||||
|
@ -43,39 +45,44 @@ pub struct SendPhoto<'a> {
|
|||
pub reply_markup: Option<ReplyMarkup>,
|
||||
}
|
||||
|
||||
impl<'a> Request<'a> for SendPhoto<'a> {
|
||||
#[async_trait]
|
||||
impl Request for SendPhoto<'_> {
|
||||
type ReturnValue = Message;
|
||||
|
||||
fn send(self) -> RequestFuture<'a, ResponseResult<Self::ReturnValue>> {
|
||||
Box::pin(async move {
|
||||
let mut params = FormBuilder::new()
|
||||
.add("chat_id", &self.chat_id)
|
||||
.add_if_some("caption", self.caption.as_ref())
|
||||
.add_if_some("parse_mode", self.parse_mode.as_ref())
|
||||
.add_if_some(
|
||||
"disable_notification",
|
||||
self.disable_notification.as_ref(),
|
||||
)
|
||||
.add_if_some(
|
||||
"reply_to_message_id",
|
||||
self.reply_to_message_id.as_ref(),
|
||||
);
|
||||
async fn send_boxed(self) -> ResponseResult<Self::ReturnValue> {
|
||||
self.send().await
|
||||
}
|
||||
}
|
||||
|
||||
params = match self.photo {
|
||||
InputFile::File(path) => params.add_file("photo", &path),
|
||||
InputFile::Url(url) => params.add("photo", &url),
|
||||
InputFile::FileId(file_id) => params.add("photo", &file_id),
|
||||
};
|
||||
let params = params.build();
|
||||
|
||||
network::request_multipart(
|
||||
&self.ctx.client,
|
||||
&self.ctx.token,
|
||||
"sendPhoto",
|
||||
Some(params),
|
||||
impl SendPhoto<'_> {
|
||||
pub async fn send(self) -> ResponseResult<Message> {
|
||||
let mut params = FormBuilder::new()
|
||||
.add("chat_id", &self.chat_id)
|
||||
.add_if_some("caption", self.caption.as_ref())
|
||||
.add_if_some("parse_mode", self.parse_mode.as_ref())
|
||||
.add_if_some(
|
||||
"disable_notification",
|
||||
self.disable_notification.as_ref(),
|
||||
)
|
||||
.await
|
||||
})
|
||||
.add_if_some(
|
||||
"reply_to_message_id",
|
||||
self.reply_to_message_id.as_ref(),
|
||||
);
|
||||
|
||||
params = match self.photo {
|
||||
InputFile::File(path) => params.add_file("photo", &path),
|
||||
InputFile::Url(url) => params.add("photo", &url),
|
||||
InputFile::FileId(file_id) => params.add("photo", &file_id),
|
||||
};
|
||||
let params = params.build();
|
||||
|
||||
network::request_multipart(
|
||||
&self.ctx.client,
|
||||
&self.ctx.token,
|
||||
"sendPhoto",
|
||||
Some(params),
|
||||
)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
use async_trait::async_trait;
|
||||
|
||||
use crate::{
|
||||
network,
|
||||
requests::{
|
||||
ChatId, Request, RequestContext, RequestFuture, ResponseResult,
|
||||
},
|
||||
requests::{ChatId, Request, RequestContext, ResponseResult},
|
||||
types::{Message, ReplyMarkup},
|
||||
};
|
||||
|
||||
|
@ -32,19 +32,24 @@ pub struct SendPoll<'a> {
|
|||
reply_markup: Option<ReplyMarkup>,
|
||||
}
|
||||
|
||||
impl<'a> Request<'a> for SendPoll<'a> {
|
||||
#[async_trait]
|
||||
impl Request for SendPoll<'_> {
|
||||
type ReturnValue = Message;
|
||||
|
||||
fn send(self) -> RequestFuture<'a, ResponseResult<Self::ReturnValue>> {
|
||||
Box::pin(async move {
|
||||
network::request_json(
|
||||
&self.ctx.client,
|
||||
&self.ctx.token,
|
||||
"sendPoll",
|
||||
&self,
|
||||
)
|
||||
.await
|
||||
})
|
||||
async fn send_boxed(self) -> ResponseResult<Self::ReturnValue> {
|
||||
self.send().await
|
||||
}
|
||||
}
|
||||
|
||||
impl SendPoll<'_> {
|
||||
pub async fn send(self) -> ResponseResult<Message> {
|
||||
network::request_json(
|
||||
&self.ctx.client,
|
||||
&self.ctx.token,
|
||||
"sendPoll",
|
||||
&self,
|
||||
)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
use async_trait::async_trait;
|
||||
|
||||
use crate::{
|
||||
network,
|
||||
requests::{
|
||||
ChatId, Request, RequestContext, RequestFuture, ResponseResult,
|
||||
},
|
||||
requests::{ChatId, Request, RequestContext, ResponseResult},
|
||||
types::{Message, ReplyMarkup},
|
||||
};
|
||||
|
||||
|
@ -47,19 +47,24 @@ pub struct SendVenue<'a> {
|
|||
pub reply_markup: Option<ReplyMarkup>,
|
||||
}
|
||||
|
||||
impl<'a> Request<'a> for SendVenue<'a> {
|
||||
#[async_trait]
|
||||
impl Request for SendVenue<'_> {
|
||||
type ReturnValue = Message;
|
||||
|
||||
fn send(self) -> RequestFuture<'a, ResponseResult<Self::ReturnValue>> {
|
||||
Box::pin(async move {
|
||||
network::request_json(
|
||||
&self.ctx.client,
|
||||
&self.ctx.token,
|
||||
"sendVenue",
|
||||
&self,
|
||||
)
|
||||
.await
|
||||
})
|
||||
async fn send_boxed(self) -> ResponseResult<Self::ReturnValue> {
|
||||
self.send().await
|
||||
}
|
||||
}
|
||||
|
||||
impl SendVenue<'_> {
|
||||
pub async fn send(self) -> ResponseResult<Message> {
|
||||
network::request_json(
|
||||
&self.ctx.client,
|
||||
&self.ctx.token,
|
||||
"sendVenue",
|
||||
&self,
|
||||
)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
|
|
8
src/requests/send_video.rs
Normal file
8
src/requests/send_video.rs
Normal 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>,
|
||||
}
|
154
src/requests/send_video_note.rs
Normal file
154
src/requests/send_video_note.rs
Normal file
|
@ -0,0 +1,154 @@
|
|||
use crate::network;
|
||||
use crate::requests::{ChatId, Request, RequestContext, ResponseResult};
|
||||
use crate::types::{Message, ReplyMarkup};
|
||||
use async_trait::async_trait;
|
||||
|
||||
///As of v.4.0, Telegram clients support rounded square mp4 videos of up to 1
|
||||
/// minute long. Use this method to send video messages. On success, the sent
|
||||
/// Message is returned.
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
pub struct SendVideoNote<'a> {
|
||||
#[serde(skip_serializing)]
|
||||
ctx: RequestContext<'a>,
|
||||
///Unique identifier for the target chat or username of the target channel
|
||||
/// (in the format @channelusername)
|
||||
pub chat_id: ChatId,
|
||||
///Video note to send. Pass a file_id as String to send a video note that
|
||||
/// exists on the Telegram servers (recommended) or upload a new video
|
||||
/// using multipart/form-data. More info on Sending Files ». Sending video
|
||||
/// notes by a URL is currently unsupported
|
||||
pub video_note: String, // InputFile or String
|
||||
///Duration of sent video in seconds
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub duration: Option<u64>,
|
||||
/// Video width and height, i.e. diameter of the video message
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub length: Option<u64>,
|
||||
///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. Thumbnails can’t be reused and can be only
|
||||
/// uploaded as a new file, so you can pass “attach://<file_attach_name>”
|
||||
/// if the thumbnail was uploaded using multipart/form-data under
|
||||
/// <file_attach_name>. More info on Sending Files »
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub thumb: Option<String>, // InputFile or String
|
||||
///Sends the message silently. Users will receive a notification with no
|
||||
/// sound.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub disable_notification: Option<bool>,
|
||||
///If the message is a reply, ID of the original message
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub reply_to_message_id: Option<i32>,
|
||||
/// Additional interface options. A JSON-serialized object for an inline
|
||||
/// keyboard, custom reply keyboard, instructions to remove reply keyboard
|
||||
/// or to force a reply from the user.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub reply_markup: Option<ReplyMarkup>,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl Request for SendVideoNote<'_> {
|
||||
type ReturnValue = Message;
|
||||
|
||||
async fn send_boxed(self) -> ResponseResult<Self::ReturnValue> {
|
||||
self.send().await
|
||||
}
|
||||
}
|
||||
|
||||
impl SendVideoNote<'_> {
|
||||
pub async fn send(self) -> ResponseResult<Message> {
|
||||
network::request_json(
|
||||
&self.ctx.client,
|
||||
&self.ctx.token,
|
||||
"sendVideoNote",
|
||||
&self,
|
||||
)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> SendVideoNote<'a> {
|
||||
pub(crate) fn new(
|
||||
ctx: RequestContext<'a>,
|
||||
chat_id: ChatId,
|
||||
video_note: String,
|
||||
) -> Self {
|
||||
Self {
|
||||
ctx,
|
||||
chat_id,
|
||||
video_note,
|
||||
duration: None,
|
||||
length: None,
|
||||
thumb: None,
|
||||
disable_notification: None,
|
||||
reply_to_message_id: None,
|
||||
reply_markup: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn chat_id<T>(mut self, chat_id: T) -> Self
|
||||
where
|
||||
T: Into<ChatId>,
|
||||
{
|
||||
self.chat_id = chat_id.into();
|
||||
self
|
||||
}
|
||||
|
||||
pub fn video_note<T>(mut self, video_note: T) -> Self
|
||||
where
|
||||
T: Into<String>,
|
||||
{
|
||||
self.video_note = video_note.into();
|
||||
self
|
||||
}
|
||||
|
||||
pub fn duration<T>(mut self, duration: T) -> Self
|
||||
where
|
||||
T: Into<u64>,
|
||||
{
|
||||
self.duration = Some(duration.into());
|
||||
self
|
||||
}
|
||||
|
||||
pub fn length<T>(mut self, length: T) -> Self
|
||||
where
|
||||
T: Into<u64>,
|
||||
{
|
||||
self.length = Some(length.into());
|
||||
self
|
||||
}
|
||||
|
||||
pub fn thumb<T>(mut self, thumb: T) -> Self
|
||||
where
|
||||
T: Into<String>,
|
||||
{
|
||||
self.thumb = Some(thumb.into());
|
||||
self
|
||||
}
|
||||
|
||||
pub fn disable_notification<T>(mut self, disable_notification: T) -> Self
|
||||
where
|
||||
T: Into<bool>,
|
||||
{
|
||||
self.disable_notification = Some(disable_notification.into());
|
||||
self
|
||||
}
|
||||
|
||||
pub fn reply_to_message_id<T>(mut self, reply_to_message_id: T) -> Self
|
||||
where
|
||||
T: Into<i32>,
|
||||
{
|
||||
self.reply_to_message_id = Some(reply_to_message_id.into());
|
||||
self
|
||||
}
|
||||
|
||||
pub fn reply_markup<T>(mut self, reply_markup: T) -> Self
|
||||
where
|
||||
T: Into<ReplyMarkup>,
|
||||
{
|
||||
self.reply_markup = Some(reply_markup.into());
|
||||
self
|
||||
}
|
||||
}
|
155
src/requests/send_voice.rs
Normal file
155
src/requests/send_voice.rs
Normal file
|
@ -0,0 +1,155 @@
|
|||
use crate::network;
|
||||
use crate::requests::{ChatId, Request, RequestContext, ResponseResult};
|
||||
use crate::types::{Message, ReplyMarkup, ParseMode};
|
||||
use async_trait::async_trait;
|
||||
|
||||
///Use this method to send audio files, if you want Telegram clients to display
|
||||
/// the file as a playable voice message. For this to work, your audio must be
|
||||
/// in an .ogg file encoded with OPUS (other formats may be sent as Audio or
|
||||
/// Document). On success, the sent Message is returned. Bots can currently send
|
||||
/// voice messages of up to 50 MB in size, this limit may be changed in the
|
||||
/// future.
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
pub struct SendVoice<'a> {
|
||||
#[serde(skip_serializing)]
|
||||
ctx: RequestContext<'a>,
|
||||
/// Unique identifier for the target chat or username of the target channel
|
||||
/// (in the format @channelusername)
|
||||
pub chat_id: ChatId,
|
||||
/// Audio file to send. Pass a file_id as String to send a file that exists
|
||||
/// on the Telegram servers (recommended), pass an HTTP URL as a String for
|
||||
/// Telegram to get a file from the Internet, or upload a new one using
|
||||
/// multipart/form-data. More info on Sending Files »
|
||||
pub voice: String, //InputFile or String
|
||||
/// Voice message caption, 0-1024 characters
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
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.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub parse_mode: Option<ParseMode>,
|
||||
///Duration of the voice message in seconds
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub duration: Option<u64>,
|
||||
/// Sends the message silently. Users will receive a notification with
|
||||
/// no sound.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub disable_notification: Option<bool>,
|
||||
/// If the message is a reply, ID of the original message
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub reply_to_message_id: Option<i32>,
|
||||
/// InlineKeyboardMarkup or ReplyKeyboardMarkup or ReplyKeyboardRemove or
|
||||
/// ForceReply Optional Additional interface options. A JSON-serialized
|
||||
/// object for an inline keyboard, custom reply keyboard, instructions to
|
||||
/// remove reply keyboard or to force a reply from the user.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub reply_markup: Option<ReplyMarkup>,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl Request for SendVoice<'_> {
|
||||
type ReturnValue = Message;
|
||||
|
||||
async fn send_boxed(self) -> ResponseResult<Self::ReturnValue> {
|
||||
self.send().await
|
||||
}
|
||||
}
|
||||
|
||||
impl SendVoice<'_> {
|
||||
pub async fn send(self) -> ResponseResult<Message> {
|
||||
network::request_json(
|
||||
&self.ctx.client,
|
||||
&self.ctx.token,
|
||||
"sendVoice",
|
||||
&self,
|
||||
)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> SendVoice<'a> {
|
||||
pub(crate) fn new(
|
||||
ctx: RequestContext<'a>,
|
||||
chat_id: ChatId,
|
||||
voice: String,
|
||||
) -> Self {
|
||||
Self {
|
||||
ctx,
|
||||
chat_id,
|
||||
voice,
|
||||
caption: None,
|
||||
parse_mode: None,
|
||||
duration: None,
|
||||
disable_notification: None,
|
||||
reply_to_message_id: None,
|
||||
reply_markup: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn chat_id<T>(mut self, chat_id: T) -> Self
|
||||
where
|
||||
T: Into<ChatId>,
|
||||
{
|
||||
self.chat_id = chat_id.into();
|
||||
self
|
||||
}
|
||||
|
||||
pub fn voice<T>(mut self, voice: T) -> Self
|
||||
where
|
||||
T: Into<String>,
|
||||
{
|
||||
self.voice = voice.into();
|
||||
self
|
||||
}
|
||||
|
||||
pub fn caption<T>(mut self, caption: T) -> Self
|
||||
where
|
||||
T: Into<String>,
|
||||
{
|
||||
self.caption = Some(caption.into());
|
||||
self
|
||||
}
|
||||
|
||||
pub fn parse_mode<T>(mut self, parse_mode: T) -> Self
|
||||
where
|
||||
T: Into<ParseMode>,
|
||||
{
|
||||
self.parse_mode = Some(parse_mode.into());
|
||||
self
|
||||
}
|
||||
|
||||
|
||||
pub fn duration<T>(mut self, duration: T) -> Self
|
||||
where
|
||||
T: Into<u64>,
|
||||
{
|
||||
self.duration = Some(duration.into());
|
||||
self
|
||||
}
|
||||
|
||||
pub fn disable_notification<T>(mut self, disable_notification: T) -> Self
|
||||
where
|
||||
T: Into<bool>,
|
||||
{
|
||||
self.disable_notification = Some(disable_notification.into());
|
||||
self
|
||||
}
|
||||
|
||||
pub fn reply_to_message_id<T>(mut self, reply_to_message_id: T) -> Self
|
||||
where
|
||||
T: Into<i32>,
|
||||
{
|
||||
self.reply_to_message_id = Some(reply_to_message_id.into());
|
||||
self
|
||||
}
|
||||
|
||||
|
||||
pub fn reply_markup<T>(mut self, reply_markup: T) -> Self
|
||||
where
|
||||
T: Into<ReplyMarkup>,
|
||||
{
|
||||
self.reply_markup = Some(reply_markup.into());
|
||||
self
|
||||
}
|
||||
|
||||
}
|
|
@ -1,8 +1,8 @@
|
|||
use async_trait::async_trait;
|
||||
|
||||
use crate::{
|
||||
network,
|
||||
requests::{
|
||||
ChatId, Request, RequestContext, RequestFuture, ResponseResult,
|
||||
},
|
||||
requests::{ChatId, Request, RequestContext, ResponseResult},
|
||||
types::{InlineKeyboardMarkup, Message},
|
||||
};
|
||||
|
||||
|
@ -32,19 +32,24 @@ pub struct StopMessageLiveLocation<'a> {
|
|||
pub reply_markup: Option<InlineKeyboardMarkup>,
|
||||
}
|
||||
|
||||
impl<'a> Request<'a> for StopMessageLiveLocation<'a> {
|
||||
#[async_trait]
|
||||
impl Request for StopMessageLiveLocation<'_> {
|
||||
type ReturnValue = Message;
|
||||
|
||||
fn send(self) -> RequestFuture<'a, ResponseResult<Self::ReturnValue>> {
|
||||
Box::pin(async move {
|
||||
network::request_json(
|
||||
&self.ctx.client,
|
||||
&self.ctx.token,
|
||||
"stopMessageLiveLocation",
|
||||
&self,
|
||||
)
|
||||
.await
|
||||
})
|
||||
async fn send_boxed(self) -> ResponseResult<Self::ReturnValue> {
|
||||
self.send().await
|
||||
}
|
||||
}
|
||||
|
||||
impl StopMessageLiveLocation<'_> {
|
||||
pub async fn send(self) -> ResponseResult<Message> {
|
||||
network::request_json(
|
||||
&self.ctx.client,
|
||||
&self.ctx.token,
|
||||
"stopMessageLiveLocation",
|
||||
&self,
|
||||
)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,8 +1,70 @@
|
|||
use crate::requests::RequestContext;
|
||||
//TODO:: need implementation
|
||||
use async_trait::async_trait;
|
||||
|
||||
use crate::network;
|
||||
use crate::requests::{ChatId, Request, RequestContext, 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,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl Request for UnbanChatMember<'_> {
|
||||
type ReturnValue = bool;
|
||||
|
||||
async fn send_boxed(self) -> ResponseResult<Self::ReturnValue> {
|
||||
self.send().await
|
||||
}
|
||||
}
|
||||
|
||||
impl UnbanChatMember<'_> {
|
||||
pub async fn send(self) -> ResponseResult<bool> {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
|
50
src/requests/unpin_chat_message.rs
Normal file
50
src/requests/unpin_chat_message.rs
Normal file
|
@ -0,0 +1,50 @@
|
|||
use async_trait::async_trait;
|
||||
|
||||
use crate::{
|
||||
network,
|
||||
requests::{ChatId, Request, RequestContext, ResponseResult},
|
||||
types::True,
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
pub struct UnpinChatMessage<'a> {
|
||||
#[serde(skip_serializing)]
|
||||
pub ctx: RequestContext<'a>,
|
||||
|
||||
pub chat_id: ChatId,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl Request for UnpinChatMessage<'_> {
|
||||
type ReturnValue = True;
|
||||
|
||||
async fn send_boxed(self) -> ResponseResult<Self::ReturnValue> {
|
||||
self.send().await
|
||||
}
|
||||
}
|
||||
|
||||
impl UnpinChatMessage<'_> {
|
||||
pub async fn send(self) -> ResponseResult<True> {
|
||||
network::request_json(
|
||||
&self.ctx.client,
|
||||
&self.ctx.token,
|
||||
"unpinChatMessage",
|
||||
&self,
|
||||
)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> UnpinChatMessage<'a> {
|
||||
pub(crate) fn new(ctx: RequestContext<'a>, chat_id: ChatId) -> Self {
|
||||
Self { ctx, chat_id }
|
||||
}
|
||||
|
||||
pub fn chat_id<T>(mut self, chat_id: T) -> Self
|
||||
where
|
||||
T: Into<ChatId>,
|
||||
{
|
||||
self.chat_id = chat_id.into();
|
||||
self
|
||||
}
|
||||
}
|
|
@ -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"}"#
|
||||
|
|
|
@ -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 }
|
||||
}
|
||||
|
|
|
@ -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#"{
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -15,7 +15,8 @@ pub enum UpdateKind {
|
|||
EditedMessage(Message),
|
||||
ChannelPost(Message),
|
||||
EditedChannelPost(Message),
|
||||
InlineQuery(()), // TODO
|
||||
InlineQuery(()),
|
||||
// TODO
|
||||
ChosenInlineResult(ChosenInlineResult),
|
||||
CallbackQuery(CallbackQuery),
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue