mirror of
https://github.com/teloxide/teloxide.git
synced 2024-12-22 22:46:39 +01:00
Merge branch 'dev' into unbox_send_future
This commit is contained in:
commit
8b1a032b55
21 changed files with 529 additions and 52 deletions
|
@ -16,3 +16,4 @@ tokio = "0.2.0-alpha.4"
|
|||
bytes = "0.4.12"
|
||||
futures-preview = "0.3.0-alpha.18"
|
||||
async-trait = "0.1.13"
|
||||
libc = "0.2.62"
|
||||
|
|
|
@ -1,12 +1,9 @@
|
|||
use crate::{
|
||||
bot::Bot,
|
||||
requests::{
|
||||
edit_message_live_location::EditMessageLiveLocation,
|
||||
forward_message::ForwardMessage, get_file::GetFile, get_me::GetMe,
|
||||
send_audio::SendAudio, send_location::SendLocation,
|
||||
send_media_group::SendMediaGroup, send_message::SendMessage,
|
||||
send_photo::SendPhoto,
|
||||
stop_message_live_location::StopMessageLiveLocation, ChatId,
|
||||
ChatId, EditMessageLiveLocation, ForwardMessage, GetFile, GetMe,
|
||||
SendAudio, SendLocation, SendMediaGroup, SendMessage, SendPhoto,
|
||||
StopMessageLiveLocation,
|
||||
},
|
||||
types::{InputFile, InputMedia},
|
||||
};
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
#![feature(termination_trait_lib)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate derive_more;
|
||||
#[macro_use]
|
||||
extern crate serde;
|
||||
|
||||
mod network;
|
||||
mod errors;
|
||||
|
||||
pub mod bot;
|
||||
pub mod errors;
|
||||
pub mod requests;
|
||||
pub mod types;
|
||||
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
use bytes::Buf;
|
||||
use futures::StreamExt;
|
||||
use reqwest::r#async::{Chunk, Client};
|
||||
use tokio::{
|
||||
io::{AsyncWrite, AsyncWriteExt},
|
||||
stream::Stream,
|
||||
};
|
||||
use bytes::Buf;
|
||||
|
||||
use crate::{
|
||||
network::{file_url, TELEGRAM_API_URL},
|
||||
|
@ -23,7 +23,8 @@ where
|
|||
let mut stream = download_file_stream(client, token, path).await?;
|
||||
|
||||
while let Some(chunk) = stream.next().await {
|
||||
destination.write_all(chunk?.bytes()).await?;
|
||||
let chunk = chunk?;
|
||||
destination.write_all(chunk.bytes()).await?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
|
|
@ -3,7 +3,7 @@ use reqwest::r#async::{multipart::Form, Client, Response};
|
|||
use serde::{de::DeserializeOwned, Serialize};
|
||||
|
||||
use crate::{
|
||||
network::{method_url, TELEGRAM_API_URL, TelegramResponse},
|
||||
network::{method_url, TelegramResponse, TELEGRAM_API_URL},
|
||||
requests::ResponseResult,
|
||||
RequestError,
|
||||
};
|
||||
|
|
|
@ -3,6 +3,7 @@ use async_trait::async_trait;
|
|||
use crate::{
|
||||
network,
|
||||
requests::{Request, RequestContext, ResponseResult},
|
||||
types::True
|
||||
};
|
||||
|
||||
#[derive(Debug, Serialize, Clone)]
|
||||
|
@ -35,7 +36,7 @@ pub struct AnswerPreCheckoutQuery<'a> {
|
|||
|
||||
#[async_trait]
|
||||
impl Request for AnswerPreCheckoutQuery<'_> {
|
||||
type ReturnValue = bool;
|
||||
type ReturnValue = True;
|
||||
|
||||
async fn send_boxed(self) -> ResponseResult<Self::ReturnValue> {
|
||||
self.send().await
|
||||
|
@ -43,7 +44,7 @@ impl Request for AnswerPreCheckoutQuery<'_> {
|
|||
}
|
||||
|
||||
impl AnswerPreCheckoutQuery<'_> {
|
||||
pub async fn send(self) -> ResponseResult<bool> {
|
||||
pub async fn send(self) -> ResponseResult<True> {
|
||||
network::request_json(
|
||||
&self.ctx.client,
|
||||
&self.ctx.token,
|
||||
|
|
|
@ -3,7 +3,7 @@ use async_trait::async_trait;
|
|||
use crate::{
|
||||
network,
|
||||
requests::{Request, RequestContext, ResponseResult},
|
||||
types::ShippingOption,
|
||||
types::{ShippingOption, True},
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
|
@ -37,7 +37,7 @@ pub struct AnswerShippingQuery<'a> {
|
|||
|
||||
#[async_trait]
|
||||
impl Request for AnswerShippingQuery<'_> {
|
||||
type ReturnValue = bool;
|
||||
type ReturnValue = True;
|
||||
|
||||
async fn send_boxed(self) -> ResponseResult<Self::ReturnValue> {
|
||||
self.send().await
|
||||
|
|
|
@ -1,19 +1,73 @@
|
|||
use crate::requests::RequestContext;
|
||||
use crate::network;
|
||||
use crate::requests::{Request, RequestContext, RequestFuture, ResponseResult};
|
||||
use crate::types::UserProfilePhotos;
|
||||
|
||||
//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> {
|
||||
pub struct GetUserProfilePhotos<'a> {
|
||||
#[serde(skip_serializing)]
|
||||
ctx: RequestContext<'a>,
|
||||
/// Unique identifier of the target user
|
||||
user_id: i32,
|
||||
pub user_id: i32,
|
||||
/// Sequential number of the first photo to be returned. By default, all
|
||||
/// photos are returned.
|
||||
offset: Option<i64>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub offset: Option<i64>,
|
||||
///Limits the number of photos to be retrieved. Values between 1—100 are
|
||||
/// accepted. Defaults to 100.
|
||||
limit: Option<i64>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub limit: Option<i64>,
|
||||
}
|
||||
|
||||
impl<'a> Request<'a> for GetUserProfilePhotos<'a> {
|
||||
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
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> GetUserProfilePhotos<'a> {
|
||||
pub fn new(ctx: RequestContext<'a>, user_id: i32) -> Self {
|
||||
Self {
|
||||
ctx,
|
||||
user_id,
|
||||
offset: None,
|
||||
limit: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn user_id<T>(mut self, user_id: T) -> Self
|
||||
where
|
||||
T: Into<i32>,
|
||||
{
|
||||
self.user_id = user_id.into();
|
||||
self
|
||||
}
|
||||
|
||||
pub fn offset<T>(mut self, offset: T) -> Self
|
||||
where
|
||||
T: Into<i64>,
|
||||
{
|
||||
self.offset = Some(offset.into());
|
||||
self
|
||||
}
|
||||
|
||||
pub fn limit<T>(mut self, limit: T) -> Self
|
||||
where
|
||||
T: Into<i64>,
|
||||
{
|
||||
self.limit = Some(limit.into());
|
||||
self
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,12 +1,72 @@
|
|||
use crate::requests::RequestContext;
|
||||
//TODO:: need implementation
|
||||
use crate::network;
|
||||
use crate::requests::{
|
||||
ChatId, Request, RequestContext, RequestFuture, ResponseResult,
|
||||
};
|
||||
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
|
||||
/// 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> {
|
||||
pub struct KickChatMember<'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,
|
||||
///Date when the user will be unbanned, unix time. If user is banned for
|
||||
/// more than 366 days or less than 30 seconds from the current time they
|
||||
/// are considered to be banned forever
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub until_date: Option<u64>,
|
||||
}
|
||||
|
||||
impl<'a> Request<'a> 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
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> KickChatMember<'a> {
|
||||
pub(crate) fn new(
|
||||
ctx: RequestContext<'a>,
|
||||
chat_id: ChatId,
|
||||
user_id: i32,
|
||||
) -> Self {
|
||||
Self {
|
||||
ctx,
|
||||
chat_id,
|
||||
user_id,
|
||||
until_date: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn chat_id<T: Into<ChatId>>(mut self, chat_id: T) -> Self {
|
||||
self.chat_id = chat_id.into();
|
||||
self
|
||||
}
|
||||
|
||||
pub fn user_id<T: Into<i32>>(mut self, user_id: T) -> Self {
|
||||
self.user_id = user_id.into();
|
||||
self
|
||||
}
|
||||
|
||||
pub fn until_date<T: Into<u64>>(mut self, until_date: T) -> Self {
|
||||
self.until_date = Some(until_date.into());
|
||||
self
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,23 @@ use serde::de::DeserializeOwned;
|
|||
|
||||
use crate::RequestError;
|
||||
|
||||
pub use self::{
|
||||
answer_pre_checkout_query::AnswerPreCheckoutQuery,
|
||||
answer_shipping_query::AnswerShippingQuery,
|
||||
edit_message_live_location::EditMessageLiveLocation,
|
||||
forward_message::ForwardMessage, get_chat::GetChat, get_file::GetFile,
|
||||
get_me::GetMe, get_updates::GetUpdates,
|
||||
get_user_profile_photos::GetUserProfilePhotos,
|
||||
kick_chat_member::KickChatMember, pin_chat_message::PinChatMessage,
|
||||
restrict_chat_member::RestrictChatMember,
|
||||
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,
|
||||
stop_message_live_location::StopMessageLiveLocation,
|
||||
unban_chat_member::UnbanChatMember,
|
||||
};
|
||||
|
||||
pub type ResponseResult<T> = Result<T, RequestError>;
|
||||
|
||||
/// Request that can be sent to telegram.
|
||||
|
@ -62,25 +79,26 @@ mod tests {
|
|||
}
|
||||
}
|
||||
|
||||
pub mod answer_pre_checkout_query;
|
||||
pub mod answer_shipping_query;
|
||||
pub mod edit_message_live_location;
|
||||
pub mod forward_message;
|
||||
pub mod get_chat;
|
||||
pub mod get_file;
|
||||
pub mod get_me;
|
||||
pub mod get_updates;
|
||||
pub mod get_user_profile_photos;
|
||||
pub mod kick_chat_member;
|
||||
pub mod restrict_chat_member;
|
||||
pub mod send_audio;
|
||||
pub mod send_chat_action;
|
||||
pub mod send_contact;
|
||||
pub mod send_location;
|
||||
pub mod send_media_group;
|
||||
pub mod send_message;
|
||||
pub mod send_photo;
|
||||
pub mod send_poll;
|
||||
pub mod send_venue;
|
||||
pub mod stop_message_live_location;
|
||||
pub mod unban_chat_member;
|
||||
mod answer_pre_checkout_query;
|
||||
mod answer_shipping_query;
|
||||
mod edit_message_live_location;
|
||||
mod forward_message;
|
||||
mod get_chat;
|
||||
mod get_file;
|
||||
mod get_me;
|
||||
mod get_updates;
|
||||
mod get_user_profile_photos;
|
||||
mod kick_chat_member;
|
||||
mod pin_chat_message;
|
||||
mod restrict_chat_member;
|
||||
mod send_audio;
|
||||
mod send_chat_action;
|
||||
mod send_contact;
|
||||
mod send_location;
|
||||
mod send_media_group;
|
||||
mod send_message;
|
||||
mod send_photo;
|
||||
mod send_poll;
|
||||
mod send_venue;
|
||||
mod stop_message_live_location;
|
||||
mod unban_chat_member;
|
||||
|
|
50
src/requests/pin_chat_message.rs
Normal file
50
src/requests/pin_chat_message.rs
Normal file
|
@ -0,0 +1,50 @@
|
|||
use crate::{
|
||||
requests::{ChatId, RequestContext, RequestFuture, ResponseResult, Request},
|
||||
types::True
|
||||
};
|
||||
use crate::network;
|
||||
|
||||
/// 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
|
||||
/// of the target supergroup or channel (in the format @channelusername)
|
||||
pub chat_id: ChatId,
|
||||
pub message_id: i32,
|
||||
pub disable_notification: Option<bool>
|
||||
}
|
||||
|
||||
impl<'a> PinChatMessage<'a> {
|
||||
pub(crate) fn new(
|
||||
ctx: RequestContext<'a>, chat_id: ChatId, message_id: i32
|
||||
) -> Self {
|
||||
Self { ctx, chat_id, message_id, disable_notification: None }
|
||||
}
|
||||
|
||||
pub fn disable_notification<T>(mut self, val: T) -> Self
|
||||
where T: Into<bool>
|
||||
{
|
||||
self.disable_notification = Some(val.into());
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Request<'a> 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
|
||||
})
|
||||
}
|
||||
}
|
|
@ -1,8 +1,92 @@
|
|||
use crate::requests::RequestContext;
|
||||
//TODO:: need implementation
|
||||
use crate::network;
|
||||
use crate::requests::{
|
||||
ChatId, Request, RequestContext, RequestFuture, ResponseResult,
|
||||
};
|
||||
use crate::types::{ChatPermissions, True};
|
||||
|
||||
/// 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
|
||||
/// appropriate admin rights. Pass True for all permissions to lift restrictions
|
||||
/// from a user. Returns True on success.
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
struct RestrictChatMember<'a> {
|
||||
pub struct RestrictChatMember<'a> {
|
||||
#[serde(skip_serializing)]
|
||||
ctx: RequestContext<'a>,
|
||||
///Unique identifier for the target chat or username of the target
|
||||
/// supergroup (in the format @supergroupusername)
|
||||
pub chat_id: ChatId,
|
||||
///Unique identifier of the target user
|
||||
pub user_id: i32,
|
||||
///New user permissions
|
||||
pub permissions: ChatPermissions,
|
||||
///Date when restrictions will be lifted for the user, unix time. If user
|
||||
/// is restricted for more than 366 days or less than 30 seconds from the
|
||||
/// current time, they are considered to be restricted forever
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub until_date: Option<u64>,
|
||||
}
|
||||
|
||||
impl<'a> Request<'a> 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
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> RestrictChatMember<'a> {
|
||||
pub(crate) fn new(
|
||||
ctx: RequestContext<'a>,
|
||||
chat_id: ChatId,
|
||||
user_id: i32,
|
||||
permissions: ChatPermissions,
|
||||
) -> Self {
|
||||
Self {
|
||||
ctx,
|
||||
chat_id,
|
||||
user_id,
|
||||
permissions,
|
||||
until_date: 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 permissions<T>(mut self, permissions: T) -> Self
|
||||
where
|
||||
T: Into<ChatPermissions>,
|
||||
{
|
||||
self.permissions = permissions.into();
|
||||
self
|
||||
}
|
||||
|
||||
pub fn until_date<T>(mut self, until_date: T) -> Self
|
||||
where
|
||||
T: Into<u64>,
|
||||
{
|
||||
self.until_date = Some(until_date.into());
|
||||
self
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ use async_trait::async_trait;
|
|||
use crate::{
|
||||
network,
|
||||
requests::{ChatId, Request, RequestContext, ResponseResult},
|
||||
types::True
|
||||
};
|
||||
|
||||
///Use this method when you need to tell the user that something is happening
|
||||
|
@ -41,7 +42,7 @@ pub enum ChatAction {
|
|||
|
||||
#[async_trait]
|
||||
impl Request for SendChatAction<'_> {
|
||||
type ReturnValue = bool;
|
||||
type ReturnValue = True;
|
||||
|
||||
async fn send_boxed(self) -> ResponseResult<Self::ReturnValue> {
|
||||
self.send().await
|
||||
|
|
|
@ -2,7 +2,7 @@ use crate::requests::RequestContext;
|
|||
//TODO:: need implementation
|
||||
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
struct UnbanChatMember<'a> {
|
||||
pub struct UnbanChatMember<'a> {
|
||||
#[serde(skip_serializing)]
|
||||
ctx: RequestContext<'a>,
|
||||
}
|
||||
|
|
35
src/types/encrypted_credintials.rs
Normal file
35
src/types/encrypted_credintials.rs
Normal file
|
@ -0,0 +1,35 @@
|
|||
#[derive(Debug, Deserialize, Eq, Hash, PartialEq, Clone, Serialize)]
|
||||
pub struct EncryptedCredentials {
|
||||
// TODO: check base64 type
|
||||
pub data: String,
|
||||
pub hash: String,
|
||||
pub secret: String,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn must_serialize_encrypted_credentials_to_json() {
|
||||
// given
|
||||
let expected_json = r#"
|
||||
{
|
||||
"data":"someData",
|
||||
"hash":"1122",
|
||||
"secret":"secret"
|
||||
}"#
|
||||
.replace("\n", "")
|
||||
.replace(" ", "");
|
||||
let encrypted_credentials = EncryptedCredentials {
|
||||
data: "someData".to_string(),
|
||||
hash: "1122".to_string(),
|
||||
secret: "secret".to_string(),
|
||||
};
|
||||
// when
|
||||
let actual_json =
|
||||
serde_json::to_string(&encrypted_credentials).unwrap();
|
||||
//then
|
||||
assert_eq!(actual_json, expected_json)
|
||||
}
|
||||
}
|
67
src/types/encrypted_passport_element.rs
Normal file
67
src/types/encrypted_passport_element.rs
Normal file
|
@ -0,0 +1,67 @@
|
|||
use super::passport_file::PassportFile;
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
|
||||
pub struct EncryptedPassportElement {
|
||||
pub hash: String,
|
||||
#[serde(flatten)]
|
||||
pub kind: EncryptedPassportElementKind
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum EncryptedPassportElementKind {
|
||||
PersonalDetails {
|
||||
data: String
|
||||
},
|
||||
Passport {
|
||||
data: String,
|
||||
front_side: PassportFile,
|
||||
selfie: PassportFile,
|
||||
translation: Option<Vec<PassportFile>>
|
||||
},
|
||||
DriverLicense {
|
||||
data: String,
|
||||
front_side: PassportFile,
|
||||
reverse_side: PassportFile,
|
||||
selfie: PassportFile,
|
||||
translation: Option<Vec<PassportFile>>
|
||||
},
|
||||
IdentityCard {
|
||||
data: String,
|
||||
front_side: PassportFile,
|
||||
reverse_side: PassportFile,
|
||||
selfie: PassportFile,
|
||||
translation: Option<Vec<PassportFile>>
|
||||
},
|
||||
InternalPassport {
|
||||
data: String,
|
||||
front_side: PassportFile,
|
||||
selfie: PassportFile,
|
||||
translation: Option<Vec<PassportFile>>
|
||||
},
|
||||
Address {
|
||||
data: String
|
||||
},
|
||||
UtilityBill {
|
||||
files: Vec<PassportFile>,
|
||||
translation: Option<Vec<PassportFile>>
|
||||
},
|
||||
BankStatement {
|
||||
files: Vec<PassportFile>,
|
||||
translation: Option<Vec<PassportFile>>
|
||||
},
|
||||
RentalAgreement {
|
||||
files: Vec<PassportFile>,
|
||||
translation: Option<Vec<PassportFile>>
|
||||
},
|
||||
PassportRegistration {
|
||||
files: Vec<PassportFile>,
|
||||
translation: Option<Vec<PassportFile>>
|
||||
},
|
||||
TemporaryRegistration {
|
||||
files: Vec<PassportFile>,
|
||||
translation: Option<Vec<PassportFile>>
|
||||
},
|
||||
PhoneNumber { phone_number: String },
|
||||
Email { email: String }
|
||||
}
|
|
@ -15,7 +15,7 @@ pub struct Message {
|
|||
}
|
||||
|
||||
impl Message {
|
||||
fn text(&self) -> Option<&str> {
|
||||
pub fn text(&self) -> Option<&str> {
|
||||
if let MessageKind::Common {
|
||||
media_kind: MediaKind::Text { ref text, .. },
|
||||
..
|
||||
|
|
|
@ -11,6 +11,8 @@ pub use self::{
|
|||
chosen_inline_result::ChosenInlineResult,
|
||||
contact::Contact,
|
||||
document::Document,
|
||||
encrypted_credintials::EncryptedCredentials,
|
||||
encrypted_passport_element::{EncryptedPassportElement, EncryptedPassportElementKind},
|
||||
file::File,
|
||||
force_reply::ForceReply,
|
||||
game::Game,
|
||||
|
@ -54,6 +56,8 @@ pub use self::{
|
|||
message_entity::MessageEntity,
|
||||
order_info::OrderInfo,
|
||||
parse_mode::ParseMode,
|
||||
passport_data::PassportData,
|
||||
passport_file::PassportFile,
|
||||
photo_size::PhotoSize,
|
||||
poll::{Poll, PollOption},
|
||||
pre_checkout_query::PreCheckoutQuery,
|
||||
|
@ -68,6 +72,7 @@ pub use self::{
|
|||
sticker::Sticker,
|
||||
sticker_set::StickerSet,
|
||||
successful_payment::SuccessfulPayment,
|
||||
unit_true::True,
|
||||
update::{Update, UpdateKind},
|
||||
user::User,
|
||||
user_profile_photos::UserProfilePhotos,
|
||||
|
@ -123,6 +128,7 @@ mod shipping_query;
|
|||
mod sticker;
|
||||
mod sticker_set;
|
||||
mod successful_payment;
|
||||
mod unit_true;
|
||||
mod update;
|
||||
mod user;
|
||||
mod user_profile_photos;
|
||||
|
@ -154,3 +160,8 @@ mod inline_query_result_photo;
|
|||
mod inline_query_result_venue;
|
||||
mod inline_query_result_video;
|
||||
mod inline_query_result_voice;
|
||||
|
||||
mod encrypted_credintials;
|
||||
mod encrypted_passport_element;
|
||||
mod passport_data;
|
||||
mod passport_file;
|
||||
|
|
8
src/types/passport_data.rs
Normal file
8
src/types/passport_data.rs
Normal file
|
@ -0,0 +1,8 @@
|
|||
use super::encrypted_credintials::EncryptedCredentials;
|
||||
use super::encrypted_passport_element::EncryptedPassportElement;
|
||||
|
||||
#[derive(Debug, Deserialize, Eq, Hash, PartialEq, Clone, Serialize)]
|
||||
pub struct PassportData {
|
||||
pub data: Vec<EncryptedPassportElement>,
|
||||
pub credentials: EncryptedCredentials,
|
||||
}
|
6
src/types/passport_file.rs
Normal file
6
src/types/passport_file.rs
Normal file
|
@ -0,0 +1,6 @@
|
|||
#[derive(Debug, Deserialize, Eq, Hash, PartialEq, Clone, Serialize)]
|
||||
pub struct PassportFile {
|
||||
pub file_id: String,
|
||||
pub file_size: u64,
|
||||
pub file_date: u64,
|
||||
}
|
81
src/types/unit_true.rs
Normal file
81
src/types/unit_true.rs
Normal file
|
@ -0,0 +1,81 @@
|
|||
use serde::de::{self, Deserialize, Deserializer, Visitor};
|
||||
use serde::ser::{Serialize, Serializer};
|
||||
|
||||
#[derive(Copy, Clone, Debug, Default, Eq, Hash, PartialEq, PartialOrd, Ord)]
|
||||
pub struct True;
|
||||
|
||||
impl std::process::Termination for True {
|
||||
fn report(self) -> i32 {
|
||||
libc::EXIT_SUCCESS
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::TryFrom<bool> for True {
|
||||
type Error = ();
|
||||
|
||||
fn try_from(value: bool) -> Result<Self, Self::Error> {
|
||||
match value {
|
||||
true => Ok(True),
|
||||
false => Err(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for True {
|
||||
fn deserialize<D>(des: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>
|
||||
{
|
||||
des.deserialize_bool(TrueVisitor)
|
||||
}
|
||||
}
|
||||
|
||||
struct TrueVisitor;
|
||||
|
||||
impl<'de> Visitor<'de> for TrueVisitor {
|
||||
type Value = True;
|
||||
|
||||
fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
write!(f, "bool, equal to `true`")
|
||||
}
|
||||
|
||||
fn visit_bool<E>(self, value: bool) -> Result<Self::Value, E>
|
||||
where
|
||||
E: de::Error
|
||||
{
|
||||
match value {
|
||||
true => Ok(True),
|
||||
false => Err(E::custom("expected `true`, found `false`"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for True {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
serializer.serialize_bool(true)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::True;
|
||||
use serde_json::{from_str, to_string};
|
||||
|
||||
#[test]
|
||||
fn unit_true_de() {
|
||||
let json = "true";
|
||||
let expected = True;
|
||||
let actual = from_str(json).unwrap();
|
||||
assert_eq!(expected, actual);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unit_true_se() {
|
||||
let actual = to_string(&True).unwrap();
|
||||
let expected = "true";
|
||||
assert_eq!(expected, actual);
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue