Use the default characters per line limit

This commit is contained in:
Temirkhan Myrzamadi 2020-07-26 23:47:02 +06:00
parent f9c192aad0
commit 38a1f470ad
121 changed files with 521 additions and 1580 deletions

View file

@ -100,7 +100,7 @@ async fn main() {
Dispatcher::new(bot)
.messages_handler(|rx: DispatcherHandlerRx<Message>| {
rx.for_each(|message| async move {
message.answer("pong").send().await.log_on_error().await;
message.answer_str("pong").await.log_on_error().await;
})
})
.dispatch()
@ -136,28 +136,18 @@ enum Command {
Help,
#[command(description = "handle a username.")]
Username(String),
#[command(
description = "handle a username and an age.",
parse_with = "split"
)]
#[command(description = "handle a username and an age.", parse_with = "split")]
UsernameAndAge { username: String, age: u8 },
}
async fn answer(
cx: UpdateWithCx<Message>,
command: Command,
) -> ResponseResult<()> {
async fn answer(cx: UpdateWithCx<Message>, command: Command) -> ResponseResult<()> {
match command {
Command::Help => cx.answer(Command::descriptions()).send().await?,
Command::Username(username) => {
cx.answer_str(format!("Your username is @{}.", username)).await?
}
Command::UsernameAndAge { username, age } => {
cx.answer_str(format!(
"Your username is @{} and age is {}.",
username, age
))
.await?
cx.answer_str(format!("Your username is @{} and age is {}.", username, age)).await?
}
};
@ -176,6 +166,7 @@ async fn handle_commands(rx: DispatcherHandlerRx<Message>) {
async fn main() {
// Setup is omitted...
}
```
<div align="center">
@ -195,9 +186,8 @@ Below is a bot, which asks you three questions and then sends the answers back t
```rust
// Imports are omitted...
#[derive(Transition, SmartDefault, From)]
#[derive(Transition, From)]
pub enum Dialogue {
#[default]
Start(StartState),
ReceiveFullName(ReceiveFullNameState),
ReceiveAge(ReceiveAgeState),
@ -219,11 +209,7 @@ impl Default for Dialogue {
pub struct StartState;
#[teloxide(transition)]
async fn start(
_state: StartState,
cx: TransitionIn,
_ans: String,
) -> TransitionOut<Dialogue> {
async fn start(_state: StartState, cx: TransitionIn, _ans: String) -> TransitionOut<Dialogue> {
cx.answer_str("Let's start! What's your full name?").await?;
next(ReceiveFullNameState)
}
@ -291,11 +277,8 @@ async fn receive_location(
cx: TransitionIn,
ans: String,
) -> TransitionOut<Dialogue> {
cx.answer_str(format!(
"Full name: {}\nAge: {}\nLocation: {}",
state.full_name, state.age, ans
))
.await?;
cx.answer_str(format!("Full name: {}\nAge: {}\nLocation: {}", state.full_name, state.age, ans))
.await?;
exit()
}
```
@ -320,19 +303,14 @@ async fn main() {
|DialogueWithCx { cx, dialogue }: In| async move {
// No panic because of std::convert::Infallible.
let dialogue = dialogue.unwrap();
handle_message(cx, dialogue)
.await
.expect("Something wrong with the bot!")
handle_message(cx, dialogue).await.expect("Something wrong with the bot!")
},
))
.dispatch()
.await;
}
async fn handle_message(
cx: UpdateWithCx<Message>,
dialogue: Dialogue,
) -> TransitionOut<Dialogue> {
async fn handle_message(cx: UpdateWithCx<Message>, dialogue: Dialogue) -> TransitionOut<Dialogue> {
match cx.update.text_owned() {
None => {
cx.answer_str("Send me a text message.").await?;
@ -341,6 +319,7 @@ async fn handle_message(
Some(ans) => dialogue.react(cx, ans).await,
}
}
```
<div align="center">

View file

@ -1,8 +1,6 @@
use std::str::FromStr;
use teloxide::{
prelude::*, types::ChatPermissions, utils::command::BotCommand
};
use teloxide::{prelude::*, types::ChatPermissions, utils::command::BotCommand};
use futures::future;
@ -81,9 +79,7 @@ async fn mute_user(cx: &Cx, time: u32) -> ResponseResult<()> {
.await?;
}
None => {
cx.reply_to("Use this command in reply to another message")
.send()
.await?;
cx.reply_to("Use this command in reply to another message").send().await?;
}
}
Ok(())
@ -94,15 +90,10 @@ async fn kick_user(cx: &Cx) -> ResponseResult<()> {
match cx.update.reply_to_message() {
Some(mes) => {
// bot.unban_chat_member can also kicks a user from a group chat.
cx.bot
.unban_chat_member(cx.update.chat_id(), mes.from().unwrap().id)
.send()
.await?;
cx.bot.unban_chat_member(cx.update.chat_id(), mes.from().unwrap().id).send().await?;
}
None => {
cx.reply_to("Use this command in reply to another message")
.send()
.await?;
cx.reply_to("Use this command in reply to another message").send().await?;
}
}
Ok(())
@ -122,29 +113,18 @@ async fn ban_user(cx: &Cx, time: u32) -> ResponseResult<()> {
.await?;
}
None => {
cx.reply_to("Use this command in a reply to another message!")
.send()
.await?;
cx.reply_to("Use this command in a reply to another message!").send().await?;
}
}
Ok(())
}
async fn action(
cx: UpdateWithCx<Message>,
command: Command,
) -> ResponseResult<()> {
async fn action(cx: UpdateWithCx<Message>, command: Command) -> ResponseResult<()> {
match command {
Command::Help => {
cx.answer(Command::descriptions()).send().await.map(|_| ())?
}
Command::Help => cx.answer(Command::descriptions()).send().await.map(|_| ())?,
Command::Kick => kick_user(&cx).await?,
Command::Ban { time, unit } => {
ban_user(&cx, calc_restrict_time(time, unit)).await?
}
Command::Mute { time, unit } => {
mute_user(&cx, calc_restrict_time(time, unit)).await?
}
Command::Ban { time, unit } => ban_user(&cx, calc_restrict_time(time, unit)).await?,
Command::Mute { time, unit } => mute_user(&cx, calc_restrict_time(time, unit)).await?,
};
Ok(())

View file

@ -1,6 +1,4 @@
use crate::dialogue::{
states::receive_location::ReceiveLocationState, Dialogue,
};
use crate::dialogue::{states::receive_location::ReceiveLocationState, Dialogue};
use teloxide::prelude::*;
use teloxide_macros::teloxide;

View file

@ -14,10 +14,7 @@ async fn receive_location(
cx: TransitionIn,
ans: String,
) -> TransitionOut<Dialogue> {
cx.answer_str(format!(
"Full name: {}\nAge: {}\nLocation: {}",
state.full_name, state.age, ans
))
.await?;
cx.answer_str(format!("Full name: {}\nAge: {}\nLocation: {}", state.full_name, state.age, ans))
.await?;
exit()
}

View file

@ -6,11 +6,7 @@ use teloxide_macros::teloxide;
pub struct StartState;
#[teloxide(transition)]
async fn start(
_state: StartState,
cx: TransitionIn,
_ans: String,
) -> TransitionOut<Dialogue> {
async fn start(_state: StartState, cx: TransitionIn, _ans: String) -> TransitionOut<Dialogue> {
cx.answer_str("Let's start! What's your full name?").await?;
next(ReceiveFullNameState)
}

View file

@ -44,19 +44,14 @@ async fn run() {
|DialogueWithCx { cx, dialogue }: In| async move {
// No panic because of std::convert::Infallible.
let dialogue = dialogue.unwrap();
handle_message(cx, dialogue)
.await
.expect("Something wrong with the bot!")
handle_message(cx, dialogue).await.expect("Something wrong with the bot!")
},
))
.dispatch()
.await;
}
async fn handle_message(
cx: UpdateWithCx<Message>,
dialogue: Dialogue,
) -> TransitionOut<Dialogue> {
async fn handle_message(cx: UpdateWithCx<Message>, dialogue: Dialogue) -> TransitionOut<Dialogue> {
match cx.update.text_owned() {
None => {
cx.answer_str("Send me a text message.").await?;

View file

@ -14,19 +14,14 @@ async fn main() {
run().await;
}
async fn handle_rejection(
error: warp::Rejection,
) -> Result<impl warp::Reply, Infallible> {
async fn handle_rejection(error: warp::Rejection) -> Result<impl warp::Reply, Infallible> {
log::error!("Cannot process the request due to: {:?}", error);
Ok(StatusCode::INTERNAL_SERVER_ERROR)
}
pub async fn webhook<'a>(
bot: Bot,
) -> impl update_listeners::UpdateListener<Infallible> {
pub async fn webhook<'a>(bot: Bot) -> impl update_listeners::UpdateListener<Infallible> {
// Heroku defines auto defines a port value
let teloxide_token = env::var("TELOXIDE_TOKEN")
.expect("TELOXIDE_TOKEN env variable missing");
let teloxide_token = env::var("TELOXIDE_TOKEN").expect("TELOXIDE_TOKEN env variable missing");
let port: u16 = env::var("PORT")
.expect("PORT env variable missing")
.parse()
@ -58,8 +53,7 @@ pub async fn webhook<'a>(
}
};
if let Ok(update) = try_parse {
tx.send(Ok(update))
.expect("Cannot send an incoming update from the webhook")
tx.send(Ok(update)).expect("Cannot send an incoming update from the webhook")
}
StatusCode::OK
@ -87,9 +81,7 @@ async fn run() {
})
.dispatch_with_listener(
webhook(bot).await,
LoggingErrorHandler::with_custom_text(
"An error from the update listener",
),
LoggingErrorHandler::with_custom_text("An error from the update listener"),
)
.await;
}

View file

@ -1,5 +1,5 @@
// The version of ngrok ping-pong-bot, which uses a webhook to receive updates from
// Telegram, instead of long polling.
// The version of ngrok ping-pong-bot, which uses a webhook to receive updates
// from Telegram, instead of long polling.
use teloxide::{dispatching::update_listeners, prelude::*};
@ -14,16 +14,12 @@ async fn main() {
run().await;
}
async fn handle_rejection(
error: warp::Rejection,
) -> Result<impl warp::Reply, Infallible> {
async fn handle_rejection(error: warp::Rejection) -> Result<impl warp::Reply, Infallible> {
log::error!("Cannot process the request due to: {:?}", error);
Ok(StatusCode::INTERNAL_SERVER_ERROR)
}
pub async fn webhook<'a>(
bot: Bot,
) -> impl update_listeners::UpdateListener<Infallible> {
pub async fn webhook<'a>(bot: Bot) -> impl update_listeners::UpdateListener<Infallible> {
// You might want to specify a self-signed certificate via .certificate
// method on SetWebhook.
bot.set_webhook("Your HTTPS ngrok URL here. Get it by 'ngrok http 80'")
@ -37,8 +33,7 @@ pub async fn webhook<'a>(
.and(warp::body::json())
.map(move |json: serde_json::Value| {
if let Ok(update) = Update::try_parse(&json) {
tx.send(Ok(update))
.expect("Cannot send an incoming update from the webhook")
tx.send(Ok(update)).expect("Cannot send an incoming update from the webhook")
}
StatusCode::OK
@ -68,9 +63,7 @@ async fn run() {
})
.dispatch_with_listener(
webhook(bot).await,
LoggingErrorHandler::with_custom_text(
"An error from the update listener",
),
LoggingErrorHandler::with_custom_text("An error from the update listener"),
)
.await;
}

View file

@ -38,26 +38,19 @@ async fn run() {
|DialogueWithCx { cx, dialogue }: In| async move {
// No panic because of std::convert::Infallible.
let dialogue = dialogue.unwrap();
handle_message(cx, dialogue)
.await
.expect("Something wrong with the bot!")
handle_message(cx, dialogue).await.expect("Something wrong with the bot!")
},
// You can also choose serializer::JSON or serializer::CBOR
// All serializers but JSON require enabling feature
// "serializer-<name>", e. g. "serializer-cbor"
// or "serializer-bincode"
RedisStorage::open("redis://127.0.0.1:6379", Bincode)
.await
.unwrap(),
RedisStorage::open("redis://127.0.0.1:6379", Bincode).await.unwrap(),
))
.dispatch()
.await;
}
async fn handle_message(
cx: UpdateWithCx<Message>,
dialogue: Dialogue,
) -> TransitionOut<Dialogue> {
async fn handle_message(cx: UpdateWithCx<Message>, dialogue: Dialogue) -> TransitionOut<Dialogue> {
match cx.update.text_owned() {
None => {
cx.answer_str("Send me a text message.").await?;

View file

@ -4,17 +4,9 @@ use teloxide_macros::teloxide;
use super::states::*;
#[teloxide(transition)]
async fn start(
state: StartState,
cx: TransitionIn,
ans: String,
) -> TransitionOut<Dialogue> {
async fn start(state: StartState, cx: TransitionIn, ans: String) -> TransitionOut<Dialogue> {
if let Ok(number) = ans.parse() {
cx.answer_str(format!(
"Remembered number {}. Now use /get or /reset",
number
))
.await?;
cx.answer_str(format!("Remembered number {}. Now use /get or /reset", number)).await?;
next(HaveNumberState { number })
} else {
cx.answer_str("Please, send me a number").await?;

View file

@ -26,10 +26,7 @@ async fn run() {
let previous = MESSAGES_TOTAL.fetch_add(1, Ordering::Relaxed);
message
.answer_str(format!(
"I received {} messages in total.",
previous
))
.answer_str(format!("I received {} messages in total.", previous))
.await
.log_on_error()
.await;

View file

@ -7,28 +7,18 @@ enum Command {
Help,
#[command(description = "handle a username.")]
Username(String),
#[command(
description = "handle a username and an age.",
parse_with = "split"
)]
#[command(description = "handle a username and an age.", parse_with = "split")]
UsernameAndAge { username: String, age: u8 },
}
async fn answer(
cx: UpdateWithCx<Message>,
command: Command,
) -> ResponseResult<()> {
async fn answer(cx: UpdateWithCx<Message>, command: Command) -> ResponseResult<()> {
match command {
Command::Help => cx.answer(Command::descriptions()).send().await?,
Command::Username(username) => {
cx.answer_str(format!("Your username is @{}.", username)).await?
}
Command::UsernameAndAge { username, age } => {
cx.answer_str(format!(
"Your username is @{} and age is {}.",
username, age
))
.await?
cx.answer_str(format!("Your username is @{} and age is {}.", username, age)).await?
}
};

View file

@ -1,7 +1,6 @@
format_code_in_doc_comments = true
wrap_comments = true
format_strings = true
max_width = 80
merge_imports = true
use_small_heuristics = "Max"
use_field_init_shorthand = true

View file

@ -1,27 +1,23 @@
use crate::{
requests::{
AddStickerToSet, AnswerCallbackQuery, AnswerInlineQuery,
AnswerPreCheckoutQuery, AnswerShippingQuery, CreateNewStickerSet,
DeleteChatPhoto, DeleteChatStickerSet, DeleteMessage,
DeleteStickerFromSet, DeleteWebhook, EditMessageCaption,
EditMessageLiveLocation, EditMessageMedia, EditMessageReplyMarkup,
EditMessageText, ExportChatInviteLink, ForwardMessage, GetChat,
GetChatAdministrators, GetChatMember, GetChatMembersCount, GetFile,
GetGameHighScores, GetMe, GetStickerSet, GetUpdates,
GetUserProfilePhotos, GetWebhookInfo, KickChatMember, LeaveChat,
PinChatMessage, PromoteChatMember, RestrictChatMember, SendAnimation,
SendAudio, SendChatAction, SendChatActionKind, SendContact,
SendDocument, SendGame, SendInvoice, SendLocation, SendMediaGroup,
SendMessage, SendPhoto, SendPoll, SendSticker, SendVenue, SendVideo,
SendVideoNote, SendVoice, SetChatAdministratorCustomTitle,
SetChatDescription, SetChatPermissions, SetChatPhoto,
SetChatStickerSet, SetChatTitle, SetGameScore, SetStickerPositionInSet,
SetWebhook, StopMessageLiveLocation, StopPoll, UnbanChatMember,
AddStickerToSet, AnswerCallbackQuery, AnswerInlineQuery, AnswerPreCheckoutQuery,
AnswerShippingQuery, CreateNewStickerSet, DeleteChatPhoto, DeleteChatStickerSet,
DeleteMessage, DeleteStickerFromSet, DeleteWebhook, EditMessageCaption,
EditMessageLiveLocation, EditMessageMedia, EditMessageReplyMarkup, EditMessageText,
ExportChatInviteLink, ForwardMessage, GetChat, GetChatAdministrators, GetChatMember,
GetChatMembersCount, GetFile, GetGameHighScores, GetMe, GetStickerSet, GetUpdates,
GetUserProfilePhotos, GetWebhookInfo, KickChatMember, LeaveChat, PinChatMessage,
PromoteChatMember, RestrictChatMember, SendAnimation, SendAudio, SendChatAction,
SendChatActionKind, SendContact, SendDocument, SendGame, SendInvoice, SendLocation,
SendMediaGroup, SendMessage, SendPhoto, SendPoll, SendSticker, SendVenue, SendVideo,
SendVideoNote, SendVoice, SetChatAdministratorCustomTitle, SetChatDescription,
SetChatPermissions, SetChatPhoto, SetChatStickerSet, SetChatTitle, SetGameScore,
SetStickerPositionInSet, SetWebhook, StopMessageLiveLocation, StopPoll, UnbanChatMember,
UnpinChatMessage, UploadStickerFile,
},
types::{
ChatId, ChatOrInlineMessage, ChatPermissions, InlineQueryResult,
InputFile, InputMedia, LabeledPrice,
ChatId, ChatOrInlineMessage, ChatPermissions, InlineQueryResult, InputFile, InputMedia,
LabeledPrice,
},
Bot,
};
@ -121,8 +117,9 @@ impl Bot {
{
match self.parse_mode.deref() {
None => SendMessage::new(self.clone(), chat_id, text),
Some(parse_mode) => SendMessage::new(self.clone(), chat_id, text)
.parse_mode(*parse_mode.deref()),
Some(parse_mode) => {
SendMessage::new(self.clone(), chat_id, text).parse_mode(*parse_mode.deref())
}
}
}
@ -184,8 +181,9 @@ impl Bot {
{
match self.parse_mode.deref() {
None => SendPhoto::new(self.clone(), chat_id, photo),
Some(parse_mode) => SendPhoto::new(self.clone(), chat_id, photo)
.parse_mode(*parse_mode.deref()),
Some(parse_mode) => {
SendPhoto::new(self.clone(), chat_id, photo).parse_mode(*parse_mode.deref())
}
}
}
@ -206,8 +204,9 @@ impl Bot {
{
match self.parse_mode.deref() {
None => SendAudio::new(self.clone(), chat_id, audio),
Some(parse_mode) => SendAudio::new(self.clone(), chat_id, audio)
.parse_mode(*parse_mode.deref()),
Some(parse_mode) => {
SendAudio::new(self.clone(), chat_id, audio).parse_mode(*parse_mode.deref())
}
}
}
@ -235,19 +234,14 @@ impl Bot {
///
/// [a default parse mode]: crate::BotBuilder::parse_mode
/// [`BotBuilder`]: crate::BotBuilder
pub fn send_document<C>(
&self,
chat_id: C,
document: InputFile,
) -> SendDocument
pub fn send_document<C>(&self, chat_id: C, document: InputFile) -> SendDocument
where
C: Into<ChatId>,
{
match self.parse_mode.deref() {
None => SendDocument::new(self.clone(), chat_id, document),
Some(parse_mode) => {
SendDocument::new(self.clone(), chat_id, document)
.parse_mode(*parse_mode.deref())
SendDocument::new(self.clone(), chat_id, document).parse_mode(*parse_mode.deref())
}
}
}
@ -285,8 +279,9 @@ impl Bot {
{
match self.parse_mode.deref() {
None => SendVideo::new(self.clone(), chat_id, video),
Some(parse_mode) => SendVideo::new(self.clone(), chat_id, video)
.parse_mode(*parse_mode.deref()),
Some(parse_mode) => {
SendVideo::new(self.clone(), chat_id, video).parse_mode(*parse_mode.deref())
}
}
}
@ -308,19 +303,14 @@ impl Bot {
///
/// [a default parse mode]: crate::BotBuilder::parse_mode
/// [`BotBuilder`]: crate::BotBuilder
pub fn send_animation<C>(
&self,
chat_id: C,
animation: InputFile,
) -> SendAnimation
pub fn send_animation<C>(&self, chat_id: C, animation: InputFile) -> SendAnimation
where
C: Into<ChatId>,
{
match self.parse_mode.deref() {
None => SendAnimation::new(self.clone(), chat_id, animation),
Some(parse_mode) => {
SendAnimation::new(self.clone(), chat_id, animation)
.parse_mode(*parse_mode.deref())
SendAnimation::new(self.clone(), chat_id, animation).parse_mode(*parse_mode.deref())
}
}
}
@ -364,8 +354,9 @@ impl Bot {
{
match self.parse_mode.deref() {
None => SendVoice::new(self.clone(), chat_id, voice),
Some(parse_mode) => SendVoice::new(self.clone(), chat_id, voice)
.parse_mode(*parse_mode.deref()),
Some(parse_mode) => {
SendVoice::new(self.clone(), chat_id, voice).parse_mode(*parse_mode.deref())
}
}
}
@ -390,11 +381,7 @@ impl Bot {
/// [`InputFile::FileId`]: crate::types::InputFile::FileId
/// [More info on Sending Files »]: https://core.telegram.org/bots/api#sending-files
pub fn send_video_note<C>(
&self,
chat_id: C,
video_note: InputFile,
) -> SendVideoNote
pub fn send_video_note<C>(&self, chat_id: C, video_note: InputFile) -> SendVideoNote
where
C: Into<ChatId>,
{
@ -427,12 +414,7 @@ impl Bot {
/// target supergroup or channel (in the format `@channelusername`).
/// - `latitude`: Latitude of the location.
/// - `longitude`: Latitude of the location.
pub fn send_location<C>(
&self,
chat_id: C,
latitude: f32,
longitude: f32,
) -> SendLocation
pub fn send_location<C>(&self, chat_id: C, latitude: f32, longitude: f32) -> SendLocation
where
C: Into<ChatId>,
{
@ -460,12 +442,7 @@ impl Bot {
latitude: f32,
longitude: f32,
) -> EditMessageLiveLocation {
EditMessageLiveLocation::new(
self.clone(),
chat_or_inline_message,
latitude,
longitude,
)
EditMessageLiveLocation::new(self.clone(), chat_or_inline_message, latitude, longitude)
}
/// Use this method to stop updating a live location message before
@ -509,14 +486,7 @@ impl Bot {
T: Into<String>,
A: Into<String>,
{
SendVenue::new(
self.clone(),
chat_id,
latitude,
longitude,
title,
address,
)
SendVenue::new(self.clone(), chat_id, latitude, longitude, title, address)
}
/// Use this method to send phone contacts.
@ -529,12 +499,7 @@ impl Bot {
/// target supergroup or channel (in the format `@channelusername`).
/// - `phone_number`: Contact's phone number.
/// - `first_name`: Contact's first name.
pub fn send_contact<C, P, F>(
&self,
chat_id: C,
phone_number: P,
first_name: F,
) -> SendContact
pub fn send_contact<C, P, F>(&self, chat_id: C, phone_number: P, first_name: F) -> SendContact
where
C: Into<ChatId>,
P: Into<String>,
@ -555,12 +520,7 @@ impl Bot {
/// - `question`: Poll question, 1-255 characters.
/// - `options`: List of answer options, 2-10 strings 1-100 characters
/// each.
pub fn send_poll<C, Q, O>(
&self,
chat_id: C,
question: Q,
options: O,
) -> SendPoll
pub fn send_poll<C, Q, O>(&self, chat_id: C, question: Q, options: O) -> SendPoll
where
C: Into<ChatId>,
Q: Into<String>,
@ -592,11 +552,7 @@ impl Bot {
///
/// [ImageBot]: https://t.me/imagebot
/// [`Bot::send_chat_action`]: crate::Bot::send_chat_action
pub fn send_chat_action<C>(
&self,
chat_id: C,
action: SendChatActionKind,
) -> SendChatAction
pub fn send_chat_action<C>(&self, chat_id: C, action: SendChatActionKind) -> SendChatAction
where
C: Into<ChatId>,
{
@ -609,10 +565,7 @@ impl Bot {
///
/// # Params
/// - `user_id`: Unique identifier of the target user.
pub fn get_user_profile_photos(
&self,
user_id: i32,
) -> GetUserProfilePhotos {
pub fn get_user_profile_photos(&self, user_id: i32) -> GetUserProfilePhotos {
GetUserProfilePhotos::new(self.clone(), user_id)
}
@ -660,11 +613,7 @@ impl Bot {
/// - `user_id`: Unique identifier of the target user.
///
/// [unbanned]: crate::Bot::unban_chat_member
pub fn kick_chat_member<C>(
&self,
chat_id: C,
user_id: i32,
) -> KickChatMember
pub fn kick_chat_member<C>(&self, chat_id: C, user_id: i32) -> KickChatMember
where
C: Into<ChatId>,
{
@ -682,11 +631,7 @@ impl Bot {
/// - `chat_id`: Unique identifier for the target chat or username of the
/// target supergroup or channel (in the format `@channelusername`).
/// - `user_id`: Unique identifier of the target user.
pub fn unban_chat_member<C>(
&self,
chat_id: C,
user_id: i32,
) -> UnbanChatMember
pub fn unban_chat_member<C>(&self, chat_id: C, user_id: i32) -> UnbanChatMember
where
C: Into<ChatId>,
{
@ -731,11 +676,7 @@ impl Bot {
/// - `chat_id`: Unique identifier for the target chat or username of the
/// target supergroup or channel (in the format `@channelusername`).
/// - `user_id`: Unique identifier of the target user.
pub fn promote_chat_member<C>(
&self,
chat_id: C,
user_id: i32,
) -> PromoteChatMember
pub fn promote_chat_member<C>(&self, chat_id: C, user_id: i32) -> PromoteChatMember
where
C: Into<ChatId>,
{
@ -806,11 +747,7 @@ impl Bot {
/// - `chat_id`: Unique identifier for the target chat or username of the
/// target supergroup or channel (in the format `@channelusername`).
/// - `photo`: New chat photo, uploaded using `multipart/form-data`.
pub fn set_chat_photo<C>(
&self,
chat_id: C,
photo: InputFile,
) -> SetChatPhoto
pub fn set_chat_photo<C>(&self, chat_id: C, photo: InputFile) -> SetChatPhoto
where
C: Into<ChatId>,
{
@ -883,11 +820,7 @@ impl Bot {
/// - `chat_id`: Unique identifier for the target chat or username of the
/// target supergroup or channel (in the format `@channelusername`).
/// - `message_id`: Identifier of a message to pin.
pub fn pin_chat_message<C>(
&self,
chat_id: C,
message_id: i32,
) -> PinChatMessage
pub fn pin_chat_message<C>(&self, chat_id: C, message_id: i32) -> PinChatMessage
where
C: Into<ChatId>,
{
@ -953,10 +886,7 @@ impl Bot {
/// # Params
/// - `chat_id`: Unique identifier for the target chat or username of the
/// target supergroup or channel (in the format `@channelusername`).
pub fn get_chat_administrators<C>(
&self,
chat_id: C,
) -> GetChatAdministrators
pub fn get_chat_administrators<C>(&self, chat_id: C) -> GetChatAdministrators
where
C: Into<ChatId>,
{
@ -1006,11 +936,7 @@ impl Bot {
/// target supergroup (in the format `@supergroupusername`).
/// - `sticker_set_name`: Name of the sticker set to be set as the group
/// sticker set.
pub fn set_chat_sticker_set<C, S>(
&self,
chat_id: C,
sticker_set_name: S,
) -> SetChatStickerSet
pub fn set_chat_sticker_set<C, S>(&self, chat_id: C, sticker_set_name: S) -> SetChatStickerSet
where
C: Into<ChatId>,
S: Into<String>,
@ -1051,10 +977,7 @@ impl Bot {
/// - `callback_query_id`: Unique identifier for the query to be answered.
///
/// [inline keyboards]: https://core.telegram.org/bots#inline-keyboards-and-on-the-fly-updating
pub fn answer_callback_query<C>(
&self,
callback_query_id: C,
) -> AnswerCallbackQuery
pub fn answer_callback_query<C>(&self, callback_query_id: C) -> AnswerCallbackQuery
where
C: Into<String>,
{
@ -1088,13 +1011,9 @@ impl Bot {
T: Into<String>,
{
match self.parse_mode.deref() {
None => {
EditMessageText::new(self.clone(), chat_or_inline_message, text)
}
Some(parse_mode) => {
EditMessageText::new(self.clone(), chat_or_inline_message, text)
.parse_mode(*parse_mode.deref())
}
None => EditMessageText::new(self.clone(), chat_or_inline_message, text),
Some(parse_mode) => EditMessageText::new(self.clone(), chat_or_inline_message, text)
.parse_mode(*parse_mode.deref()),
}
}
@ -1118,13 +1037,9 @@ impl Bot {
chat_or_inline_message: ChatOrInlineMessage,
) -> EditMessageCaption {
match self.parse_mode.deref() {
None => {
EditMessageCaption::new(self.clone(), chat_or_inline_message)
}
Some(parse_mode) => {
EditMessageCaption::new(self.clone(), chat_or_inline_message)
.parse_mode(*parse_mode.deref())
}
None => EditMessageCaption::new(self.clone(), chat_or_inline_message),
Some(parse_mode) => EditMessageCaption::new(self.clone(), chat_or_inline_message)
.parse_mode(*parse_mode.deref()),
}
}
@ -1202,11 +1117,7 @@ impl Bot {
/// - `chat_id`: Unique identifier for the target chat or username of the
/// target channel (in the format `@channelusername`).
/// - `message_id`: Identifier of the message to delete.
pub fn delete_message<C>(
&self,
chat_id: C,
message_id: i32,
) -> DeleteMessage
pub fn delete_message<C>(&self, chat_id: C, message_id: i32) -> DeleteMessage
where
C: Into<ChatId>,
{
@ -1268,11 +1179,7 @@ impl Bot {
/// [More info on Sending Files »]: https://core.telegram.org/bots/api#sending-files
/// [`Bot::create_new_sticker_set`]: crate::Bot::create_new_sticker_set
/// [`Bot::add_sticker_to_set`]: crate::Bot::add_sticker_to_set
pub fn upload_sticker_file(
&self,
user_id: i32,
png_sticker: InputFile,
) -> UploadStickerFile {
pub fn upload_sticker_file(&self, user_id: i32, png_sticker: InputFile) -> UploadStickerFile {
UploadStickerFile::new(self.clone(), user_id, png_sticker)
}
@ -1317,14 +1224,7 @@ impl Bot {
T: Into<String>,
E: Into<String>,
{
CreateNewStickerSet::new(
self.clone(),
user_id,
name,
title,
png_sticker,
emojis,
)
CreateNewStickerSet::new(self.clone(), user_id, name, title, png_sticker, emojis)
}
/// Use this method to add a new sticker to a set created by the bot.
@ -1402,11 +1302,7 @@ impl Bot {
/// # Params
/// - `inline_query_id`: Unique identifier for the answered query.
/// - `results`: A JSON-serialized array of results for the inline query.
pub fn answer_inline_query<I, R>(
&self,
inline_query_id: I,
results: R,
) -> AnswerInlineQuery
pub fn answer_inline_query<I, R>(&self, inline_query_id: I, results: R) -> AnswerInlineQuery
where
I: Into<String>,
R: Into<Vec<InlineQueryResult>>,
@ -1484,11 +1380,7 @@ impl Bot {
/// delivery to the specified address is not possible).
///
/// [`Update`]: crate::types::Update
pub fn answer_shipping_query<S>(
&self,
shipping_query_id: S,
ok: bool,
) -> AnswerShippingQuery
pub fn answer_shipping_query<S>(&self, shipping_query_id: S, ok: bool) -> AnswerShippingQuery
where
S: Into<String>,
{
@ -1607,11 +1499,6 @@ impl Bot {
C: Into<ChatId>,
CT: Into<String>,
{
SetChatAdministratorCustomTitle::new(
self.clone(),
chat_id,
user_id,
custom_title,
)
SetChatAdministratorCustomTitle::new(self.clone(), chat_id, user_id, custom_title)
}
}

View file

@ -59,8 +59,7 @@ impl Bot {
pub async fn download_file_stream(
&self,
path: &str,
) -> Result<impl Stream<Item = Result<Bytes, reqwest::Error>>, reqwest::Error>
{
) -> Result<impl Stream<Item = Result<Bytes, reqwest::Error>>, reqwest::Error> {
download_file_stream(&self.client, &self.token, path).await
}
}

View file

@ -116,8 +116,7 @@ pub(crate) fn build_sound_bot() -> Client {
}
fn get_token_from_env() -> String {
std::env::var("TELOXIDE_TOKEN")
.expect("Cannot get the TELOXIDE_TOKEN env variable")
std::env::var("TELOXIDE_TOKEN").expect("Cannot get the TELOXIDE_TOKEN env variable")
}
impl Bot {

View file

@ -1,7 +1,6 @@
use crate::dispatching::{
dialogue::{
DialogueDispatcherHandler, DialogueStage, DialogueWithCx, GetChatId,
InMemStorage, Storage,
DialogueDispatcherHandler, DialogueStage, DialogueWithCx, GetChatId, InMemStorage, Storage,
},
DispatcherHandler, UpdateWithCx,
};
@ -100,13 +99,10 @@ where
match handler.handle(DialogueWithCx { cx, dialogue }).await {
DialogueStage::Next(new_dialogue) => {
if let Ok(Some(_)) =
storage.update_dialogue(chat_id, new_dialogue).await
{
if let Ok(Some(_)) = storage.update_dialogue(chat_id, new_dialogue).await {
panic!(
"Oops, you have an bug in your Storage: \
update_dialogue returns Some after \
remove_dialogue"
"Oops, you have an bug in your Storage: update_dialogue returns \
Some after remove_dialogue"
);
}
}
@ -135,10 +131,7 @@ where
S: Storage<D> + Send + Sync + 'static,
S::Error: Send + 'static,
{
fn handle(
self,
updates: mpsc::UnboundedReceiver<UpdateWithCx<Upd>>,
) -> BoxFuture<'static, ()>
fn handle(self, updates: mpsc::UnboundedReceiver<UpdateWithCx<Upd>>) -> BoxFuture<'static, ()>
where
UpdateWithCx<Upd>: 'static,
{
@ -152,19 +145,13 @@ where
// An old dialogue
Some(tx) => {
if tx.1.send(cx).is_err() {
panic!(
"We are not dropping a receiver or call .close() \
on it",
);
panic!("We are not dropping a receiver or call .close() on it",);
}
}
None => {
let tx = this.new_tx();
if tx.send(cx).is_err() {
panic!(
"We are not dropping a receiver or call .close() \
on it",
);
panic!("We are not dropping a receiver or call .close() on it",);
}
this.senders.insert(chat_id, tx);
}
@ -214,8 +201,8 @@ mod tests {
static ref SEQ3: Mutex<Vec<u32>> = Mutex::new(Vec::new());
}
let dispatcher = DialogueDispatcher::new(
|cx: DialogueWithCx<MyUpdate, (), Infallible>| async move {
let dispatcher =
DialogueDispatcher::new(|cx: DialogueWithCx<MyUpdate, (), Infallible>| async move {
delay_for(Duration::from_millis(300)).await;
match cx.cx.update {
@ -232,8 +219,7 @@ mod tests {
}
DialogueStage::Next(())
},
);
});
let updates = stream::iter(
vec![
@ -260,10 +246,7 @@ mod tests {
MyUpdate::new(3, 1611),
]
.into_iter()
.map(|update| UpdateWithCx {
update,
bot: Bot::new("Doesn't matter here"),
})
.map(|update| UpdateWithCx { update, bot: Bot::new("Doesn't matter here") })
.collect::<Vec<UpdateWithCx<MyUpdate>>>(),
);
@ -287,13 +270,7 @@ mod tests {
delay_for(Duration::from_millis(3000)).await;
assert_eq!(*SEQ1.lock().await, vec![174, 125, 2, 193, 104, 7, 7778]);
assert_eq!(
*SEQ2.lock().await,
vec![411, 515, 623, 2222, 737, 10, 55456]
);
assert_eq!(
*SEQ3.lock().await,
vec![72782, 2737, 5475, 1096, 872, 5665, 1611]
);
assert_eq!(*SEQ2.lock().await, vec![411, 515, 623, 2222, 737, 10, 55456]);
assert_eq!(*SEQ3.lock().await, vec![72782, 2737, 5475, 1096, 872, 5665, 1611]);
}
}

View file

@ -23,10 +23,7 @@ where
F: Fn(DialogueWithCx<Upd, D, E>) -> Fut + Send + Sync + 'static,
Fut: Future<Output = DialogueStage<D>> + Send + 'static,
{
fn handle(
self: Arc<Self>,
cx: DialogueWithCx<Upd, D, E>,
) -> BoxFuture<'static, Fut::Output>
fn handle(self: Arc<Self>, cx: DialogueWithCx<Upd, D, E>) -> BoxFuture<'static, Fut::Output>
where
DialogueWithCx<Upd, D, E>: Send + 'static,
{

View file

@ -153,8 +153,7 @@ pub use dialogue_stage::{exit, next, DialogueStage};
pub use dialogue_with_cx::DialogueWithCx;
pub use get_chat_id::GetChatId;
pub use transition::{
SubTransition, SubTransitionOutputType, Transition, TransitionIn,
TransitionOut,
SubTransition, SubTransitionOutputType, Transition, TransitionIn, TransitionOut,
};
#[cfg(feature = "redis-storage")]

View file

@ -43,8 +43,6 @@ impl<D> Storage<D> for InMemStorage<D> {
where
D: Send + 'static,
{
Box::pin(
async move { Ok(self.map.lock().await.insert(chat_id, dialogue)) },
)
Box::pin(async move { Ok(self.map.lock().await.insert(chat_id, dialogue)) })
}
}

View file

@ -37,9 +37,7 @@ impl<S> RedisStorage<S> {
serializer: S,
) -> Result<Arc<Self>, RedisStorageError<Infallible>> {
Ok(Arc::new(Self {
conn: Mutex::new(
redis::Client::open(url)?.get_async_connection().await?,
),
conn: Mutex::new(redis::Client::open(url)?.get_async_connection().await?),
serializer,
}))
}
@ -91,21 +89,15 @@ where
dialogue: D,
) -> BoxFuture<'static, Result<Option<D>, Self::Error>> {
Box::pin(async move {
let dialogue = self
.serializer
.serialize(&dialogue)
.map_err(RedisStorageError::SerdeError)?;
let dialogue =
self.serializer.serialize(&dialogue).map_err(RedisStorageError::SerdeError)?;
Ok(self
.conn
.lock()
.await
.getset::<_, Vec<u8>, Option<Vec<u8>>>(chat_id, dialogue)
.await?
.map(|d| {
self.serializer
.deserialize(&d)
.map_err(RedisStorageError::SerdeError)
})
.map(|d| self.serializer.deserialize(&d).map_err(RedisStorageError::SerdeError))
.transpose()?)
})
}

View file

@ -10,11 +10,7 @@ pub trait Transition<T>: Sized {
/// Turns itself into another state, depending on the input message.
///
/// `aux` will be passed to each subtransition function.
fn react(
self,
cx: TransitionIn,
aux: T,
) -> BoxFuture<'static, TransitionOut<Self>>;
fn react(self, cx: TransitionIn, aux: T) -> BoxFuture<'static, TransitionOut<Self>>;
}
/// Like [`Transition`], but from `StateN` -> `Dialogue`.

View file

@ -1,12 +1,11 @@
use crate::{
dispatching::{
update_listeners, update_listeners::UpdateListener, DispatcherHandler,
UpdateWithCx,
update_listeners, update_listeners::UpdateListener, DispatcherHandler, UpdateWithCx,
},
error_handlers::{ErrorHandler, LoggingErrorHandler},
types::{
CallbackQuery, ChosenInlineResult, InlineQuery, Message, Poll,
PollAnswer, PreCheckoutQuery, ShippingQuery, UpdateKind,
CallbackQuery, ChosenInlineResult, InlineQuery, Message, Poll, PollAnswer,
PreCheckoutQuery, ShippingQuery, UpdateKind,
},
Bot,
};
@ -26,19 +25,14 @@ mod macros {
}
}
fn send<'a, Upd>(
bot: &'a Bot,
tx: &'a Tx<Upd>,
update: Upd,
variant: &'static str,
) where
fn send<'a, Upd>(bot: &'a Bot, tx: &'a Tx<Upd>, update: Upd, variant: &'static str)
where
Upd: Debug,
{
if let Some(tx) = tx {
if let Err(error) = tx.send(UpdateWithCx { bot: bot.clone(), update }) {
log::error!(
"The RX part of the {} channel is closed, but an update is \
received.\nError:{}\n",
"The RX part of the {} channel is closed, but an update is received.\nError:{}\n",
variant,
error
);
@ -206,9 +200,7 @@ impl Dispatcher {
pub async fn dispatch(&self) {
self.dispatch_with_listener(
update_listeners::polling_default(self.bot.clone()),
LoggingErrorHandler::with_custom_text(
"An error from the update listener",
),
LoggingErrorHandler::with_custom_text("An error from the update listener"),
)
.await;
}
@ -228,8 +220,7 @@ impl Dispatcher {
update_listener
.for_each(move |update| {
let update_listener_error_handler =
Arc::clone(&update_listener_error_handler);
let update_listener_error_handler = Arc::clone(&update_listener_error_handler);
async move {
log::trace!("Dispatcher received an update: {:?}", update);
@ -237,21 +228,14 @@ impl Dispatcher {
let update = match update {
Ok(update) => update,
Err(error) => {
Arc::clone(&update_listener_error_handler)
.handle_error(error)
.await;
Arc::clone(&update_listener_error_handler).handle_error(error).await;
return;
}
};
match update.kind {
UpdateKind::Message(message) => {
send!(
&self.bot,
&self.messages_queue,
message,
UpdateKind::Message
);
send!(&self.bot, &self.messages_queue, message, UpdateKind::Message);
}
UpdateKind::EditedMessage(message) => {
send!(
@ -318,12 +302,7 @@ impl Dispatcher {
);
}
UpdateKind::Poll(poll) => {
send!(
&self.bot,
&self.polls_queue,
poll,
UpdateKind::Poll
);
send!(&self.bot, &self.polls_queue, poll, UpdateKind::Poll);
}
UpdateKind::PollAnswer(answer) => {
send!(

View file

@ -11,10 +11,7 @@ use futures::future::BoxFuture;
/// [`Dispatcher`]: crate::dispatching::Dispatcher
pub trait DispatcherHandler<Upd> {
#[must_use]
fn handle(
self,
updates: DispatcherHandlerRx<Upd>,
) -> BoxFuture<'static, ()>
fn handle(self, updates: DispatcherHandlerRx<Upd>) -> BoxFuture<'static, ()>
where
UpdateWithCx<Upd>: Send + 'static;
}

View file

@ -1,6 +1,4 @@
use crate::{
prelude::UpdateWithCx, types::Message, utils::command::BotCommand,
};
use crate::{prelude::UpdateWithCx, types::Message, utils::command::BotCommand};
use futures::{stream::BoxStream, Stream, StreamExt};
/// An extension trait to be used with [`DispatcherHandlerRx`].
@ -11,18 +9,13 @@ use futures::{stream::BoxStream, Stream, StreamExt};
/// [`DispatcherHandlerRx`]: crate::dispatching::DispatcherHandlerRx
pub trait DispatcherHandlerRxExt {
/// Extracts only text messages from this stream of arbitrary messages.
fn text_messages(
self,
) -> BoxStream<'static, (UpdateWithCx<Message>, String)>
fn text_messages(self) -> BoxStream<'static, (UpdateWithCx<Message>, String)>
where
Self: Stream<Item = UpdateWithCx<Message>>;
/// Extracts only commands with their arguments from this stream of
/// arbitrary messages.
fn commands<C, N>(
self,
bot_name: N,
) -> BoxStream<'static, (UpdateWithCx<Message>, C)>
fn commands<C, N>(self, bot_name: N) -> BoxStream<'static, (UpdateWithCx<Message>, C)>
where
Self: Stream<Item = UpdateWithCx<Message>>,
C: BotCommand,
@ -33,21 +26,14 @@ impl<T> DispatcherHandlerRxExt for T
where
T: Send + 'static,
{
fn text_messages(
self,
) -> BoxStream<'static, (UpdateWithCx<Message>, String)>
fn text_messages(self) -> BoxStream<'static, (UpdateWithCx<Message>, String)>
where
Self: Stream<Item = UpdateWithCx<Message>>,
{
Box::pin(self.filter_map(|cx| async move {
cx.update.text_owned().map(|text| (cx, text))
}))
Box::pin(self.filter_map(|cx| async move { cx.update.text_owned().map(|text| (cx, text)) }))
}
fn commands<C, N>(
self,
bot_name: N,
) -> BoxStream<'static, (UpdateWithCx<Message>, C)>
fn commands<C, N>(self, bot_name: N) -> BoxStream<'static, (UpdateWithCx<Message>, C)>
where
Self: Stream<Item = UpdateWithCx<Message>>,
C: BotCommand,
@ -58,9 +44,7 @@ where
Box::pin(self.text_messages().filter_map(move |(cx, text)| {
let bot_name = bot_name.clone();
async move {
C::parse(&text, &bot_name).map(|command| (cx, command)).ok()
}
async move { C::parse(&text, &bot_name).map(|command| (cx, command)).ok() }
}))
}
}

View file

@ -145,8 +145,7 @@ pub fn polling(
limit: Option<u8>,
allowed_updates: Option<Vec<AllowedUpdate>>,
) -> impl UpdateListener<RequestError> {
let timeout =
timeout.map(|t| t.as_secs().try_into().expect("timeout is too big"));
let timeout = timeout.map(|t| t.as_secs().try_into().expect("timeout is too big"));
stream::unfold(
(allowed_updates, bot, 0),
@ -165,10 +164,7 @@ pub fn polling(
Ok(ok) => ok.id,
Err((value, _)) => value["update_id"]
.as_i64()
.expect(
"The 'update_id' field must always exist \
in Update",
)
.expect("The 'update_id' field must always exist in Update")
.try_into()
.expect("update_id must be i32"),
};
@ -176,10 +172,8 @@ pub fn polling(
offset = id + 1;
}
let updates = updates
.into_iter()
.filter_map(Result::ok)
.collect::<Vec<Update>>();
let updates =
updates.into_iter().filter_map(Result::ok).collect::<Vec<Update>>();
updates.into_iter().map(Ok).collect::<Vec<_>>()
}

View file

@ -1,10 +1,10 @@
use crate::{
dispatching::dialogue::GetChatId,
requests::{
DeleteMessage, EditMessageCaption, EditMessageText, ForwardMessage,
PinChatMessage, Request, ResponseResult, SendAnimation, SendAudio,
SendContact, SendDocument, SendLocation, SendMediaGroup, SendMessage,
SendPhoto, SendSticker, SendVenue, SendVideo, SendVideoNote, SendVoice,
DeleteMessage, EditMessageCaption, EditMessageText, ForwardMessage, PinChatMessage,
Request, ResponseResult, SendAnimation, SendAudio, SendContact, SendDocument, SendLocation,
SendMediaGroup, SendMessage, SendPhoto, SendSticker, SendVenue, SendVideo, SendVideoNote,
SendVoice,
},
types::{ChatId, ChatOrInlineMessage, InputFile, InputMedia, Message},
Bot,
@ -51,9 +51,7 @@ impl UpdateWithCx<Message> {
where
T: Into<String>,
{
self.bot
.send_message(self.chat_id(), text)
.reply_to_message_id(self.update.id)
self.bot.send_message(self.chat_id(), text).reply_to_message_id(self.update.id)
}
pub fn answer_photo(&self, photo: InputFile) -> SendPhoto {
@ -87,11 +85,7 @@ impl UpdateWithCx<Message> {
self.bot.send_media_group(self.update.chat.id, media_group)
}
pub fn answer_location(
&self,
latitude: f32,
longitude: f32,
) -> SendLocation {
pub fn answer_location(&self, latitude: f32, longitude: f32) -> SendLocation {
self.bot.send_location(self.update.chat.id, latitude, longitude)
}
@ -106,24 +100,14 @@ impl UpdateWithCx<Message> {
T: Into<String>,
U: Into<String>,
{
self.bot.send_venue(
self.update.chat.id,
latitude,
longitude,
title,
address,
)
self.bot.send_venue(self.update.chat.id, latitude, longitude, title, address)
}
pub fn answer_video_note(&self, video_note: InputFile) -> SendVideoNote {
self.bot.send_video_note(self.update.chat.id, video_note)
}
pub fn answer_contact<T, U>(
&self,
phone_number: T,
first_name: U,
) -> SendContact
pub fn answer_contact<T, U>(&self, phone_number: T, first_name: U) -> SendContact
where
T: Into<String>,
U: Into<String>,

View file

@ -174,9 +174,7 @@ impl ErrorHandler<Infallible> for IgnoringErrorHandlerSafe {
///
/// LoggingErrorHandler::new().handle_error(()).await;
/// LoggingErrorHandler::with_custom_text("Omg1").handle_error(404).await;
/// LoggingErrorHandler::with_custom_text("Omg2")
/// .handle_error("Invalid data type!")
/// .await;
/// LoggingErrorHandler::with_custom_text("Omg2").handle_error("Invalid data type!").await;
/// # }
/// ```
pub struct LoggingErrorHandler {

View file

@ -63,9 +63,9 @@ pub enum KnownApiErrorKind {
/// 1. [`EditMessageText`]
///
/// [`EditMessageText`]: crate::requests::EditMessageText
#[serde(rename = "Bad Request: message is not modified: specified new \
message content and reply markup are exactly the same \
as a current content and reply markup of the message")]
#[serde(rename = "Bad Request: message is not modified: specified new message content and \
reply markup are exactly the same as a current content and reply markup \
of the message")]
MessageNotModified,
/// Occurs when bot tries to forward or delete a message which was deleted.
@ -285,8 +285,8 @@ pub enum KnownApiErrorKind {
/// 1. [`AnswerCallbackQuery`]
///
/// [`AnswerCallbackQuery`]: crate::requests::AnswerCallbackQuery
#[serde(rename = "Bad Request: query is too old and response timeout \
expired or query id is invalid")]
#[serde(rename = "Bad Request: query is too old and response timeout expired or query id is \
invalid")]
InvalidQueryID,
/// Occurs when bot tries to send InlineKeyboardMarkup with invalid button
@ -314,8 +314,8 @@ pub enum KnownApiErrorKind {
/// 1. [`SendMessage`]
///
/// [`SendMessage`]: crate::requests::SendMessage
#[serde(rename = "Bad Request: can't parse inline keyboard button: Text \
buttons are unallowed in the inline keyboard")]
#[serde(rename = "Bad Request: can't parse inline keyboard button: Text buttons are \
unallowed in the inline keyboard")]
TextButtonsAreUnallowed,
/// Occurs when bot tries to get file by wrong file id.
@ -361,8 +361,7 @@ pub enum KnownApiErrorKind {
/// Occurs when bot tries to use method in group which is allowed only in a
/// supergroup or channel.
#[serde(rename = "Bad Request: method is available only for supergroups \
and channel")]
#[serde(rename = "Bad Request: method is available only for supergroups and channel")]
MethodNotAvailableInPrivateChats,
/// Occurs when bot tries to demote chat creator.
@ -390,8 +389,7 @@ pub enum KnownApiErrorKind {
/// 1. [`RestrictChatMember`]
///
/// [`RestrictChatMember`]: crate::requests::RestrictChatMember
#[serde(rename = "Bad Request: not enough rights to restrict/unrestrict \
chat member")]
#[serde(rename = "Bad Request: not enough rights to restrict/unrestrict chat member")]
NotEnoughRightsToRestrict,
/// Occurs when bot tries set webhook to protocol other than HTTPS.
@ -400,8 +398,7 @@ pub enum KnownApiErrorKind {
/// 1. [`SetWebhook`]
///
/// [`SetWebhook`]: crate::requests::SetWebhook
#[serde(rename = "Bad Request: bad webhook: HTTPS url must be provided \
for webhook")]
#[serde(rename = "Bad Request: bad webhook: HTTPS url must be provided for webhook")]
WebhookRequireHTTPS,
/// Occurs when bot tries to set webhook to port other than 80, 88, 443 or
@ -411,8 +408,8 @@ pub enum KnownApiErrorKind {
/// 1. [`SetWebhook`]
///
/// [`SetWebhook`]: crate::requests::SetWebhook
#[serde(rename = "Bad Request: bad webhook: Webhook can be set up only \
on ports 80, 88, 443 or 8443")]
#[serde(rename = "Bad Request: bad webhook: Webhook can be set up only on ports 80, 88, 443 \
or 8443")]
BadWebhookPort,
/// Occurs when bot tries to set webhook to unknown host.
@ -421,8 +418,7 @@ pub enum KnownApiErrorKind {
/// 1. [`SetWebhook`]
///
/// [`SetWebhook`]: crate::requests::SetWebhook
#[serde(rename = "Bad Request: bad webhook: Failed to resolve host: \
Name or service not known")]
#[serde(rename = "Bad Request: bad webhook: Failed to resolve host: Name or service not known")]
UnknownHost,
/// Occurs when bot tries to set webhook to invalid URL.
@ -476,9 +472,7 @@ pub enum KnownApiErrorKind {
/// 1. [`SendMessage`]
///
/// [`SendMessage`]: crate::requests::SendMessage
#[serde(
rename = "Unauthorized: bot can't initiate conversation with a user"
)]
#[serde(rename = "Unauthorized: bot can't initiate conversation with a user")]
CantInitiateConversation,
/// Occurs when you tries to send message to bot.
@ -506,8 +500,8 @@ pub enum KnownApiErrorKind {
/// 1. [`GetUpdates`]
///
/// [`GetUpdates`]: crate::requests::GetUpdates
#[serde(rename = "Conflict: terminated by other getUpdates request; \
make sure that only one bot instance is running")]
#[serde(rename = "Conflict: terminated by other getUpdates request; make sure that only one \
bot instance is running")]
TerminatedByOtherGetUpdates,
/// Occurs when bot tries to get file by invalid file id.

View file

@ -17,9 +17,7 @@
#![forbid(unsafe_code)]
pub use bot::{Bot, BotBuilder};
pub use errors::{
ApiErrorKind, DownloadError, KnownApiErrorKind, RequestError,
};
pub use errors::{ApiErrorKind, DownloadError, KnownApiErrorKind, RequestError};
mod errors;
mod net;

View file

@ -17,24 +17,14 @@ const TELEGRAM_API_URL: &str = "https://api.telegram.org";
///
/// [Telegram documentation]: https://core.telegram.org/bots/api#making-requests
fn method_url(base: &str, token: &str, method_name: &str) -> String {
format!(
"{url}/bot{token}/{method}",
url = base,
token = token,
method = method_name,
)
format!("{url}/bot{token}/{method}", url = base, token = token, method = method_name,)
}
/// Creates URL for downloading a file. See the [Telegram documentation].
///
/// [Telegram documentation]: https://core.telegram.org/bots/api#file
fn file_url(base: &str, token: &str, file_path: &str) -> String {
format!(
"{url}/file/bot{token}/{file}",
url = base,
token = token,
file = file_path,
)
format!("{url}/file/bot{token}/{file}", url = base, token = token, file = file_path,)
}
#[cfg(test)]

View file

@ -33,17 +33,10 @@ impl<R> Into<ResponseResult<R>> for TelegramResponse<R> {
fn into(self) -> Result<R, RequestError> {
match self {
TelegramResponse::Ok { result, .. } => Ok(result),
TelegramResponse::Err {
kind,
error_code,
response_parameters,
..
} => {
TelegramResponse::Err { kind, error_code, response_parameters, .. } => {
if let Some(params) = response_parameters {
match params {
ResponseParameters::RetryAfter(i) => {
Err(RequestError::RetryAfter(i))
}
ResponseParameters::RetryAfter(i) => Err(RequestError::RetryAfter(i)),
ResponseParameters::MigrateToChatId(to) => {
Err(RequestError::MigrateToChatId(to))
}
@ -66,8 +59,7 @@ mod tests {
#[test]
fn terminated_by_other_get_updates() {
let expected =
ApiErrorKind::Known(KnownApiErrorKind::TerminatedByOtherGetUpdates);
let expected = ApiErrorKind::Known(KnownApiErrorKind::TerminatedByOtherGetUpdates);
if let TelegramResponse::Err{ kind, .. } = serde_json::from_str::<TelegramResponse<Update>>(r#"{"ok":false,"error_code":409,"description":"Conflict: terminated by other getUpdates request; make sure that only one bot instance is running"}"#).unwrap() {
assert_eq!(expected, kind);
}

View file

@ -3,8 +3,8 @@
pub use crate::{
dispatching::{
dialogue::{
exit, next, DialogueDispatcher, DialogueStage, DialogueWithCx,
GetChatId, Transition, TransitionIn, TransitionOut,
exit, next, DialogueDispatcher, DialogueStage, DialogueWithCx, GetChatId, Transition,
TransitionIn, TransitionOut,
},
Dispatcher, DispatcherHandlerRx, DispatcherHandlerRxExt, UpdateWithCx,
},

View file

@ -33,13 +33,7 @@ impl Request for AnswerCallbackQuery {
type Output = True;
async fn send(&self) -> ResponseResult<True> {
net::request_json(
self.bot.client(),
self.bot.token(),
"answerCallbackQuery",
&self,
)
.await
net::request_json(self.bot.client(), self.bot.token(), "answerCallbackQuery", &self).await
}
}
@ -49,14 +43,7 @@ impl AnswerCallbackQuery {
C: Into<String>,
{
let callback_query_id = callback_query_id.into();
Self {
bot,
callback_query_id,
text: None,
show_alert: None,
url: None,
cache_time: None,
}
Self { bot, callback_query_id, text: None, show_alert: None, url: None, cache_time: None }
}
/// Unique identifier for the query to be answered.

View file

@ -31,13 +31,7 @@ impl Request for AnswerInlineQuery {
type Output = True;
async fn send(&self) -> ResponseResult<True> {
net::request_json(
self.bot.client(),
self.bot.token(),
"answerInlineQuery",
&self,
)
.await
net::request_json(self.bot.client(), self.bot.token(), "answerInlineQuery", &self).await
}
}

View file

@ -34,13 +34,8 @@ impl Request for AnswerPreCheckoutQuery {
type Output = True;
async fn send(&self) -> ResponseResult<True> {
net::request_json(
self.bot.client(),
self.bot.token(),
"answerPreCheckoutQuery",
&self,
)
.await
net::request_json(self.bot.client(), self.bot.token(), "answerPreCheckoutQuery", &self)
.await
}
}

View file

@ -31,13 +31,7 @@ impl Request for AnswerShippingQuery {
type Output = True;
async fn send(&self) -> ResponseResult<True> {
net::request_json(
self.bot.client(),
self.bot.token(),
"answerShippingQuery",
&self,
)
.await
net::request_json(self.bot.client(), self.bot.token(), "answerShippingQuery", &self).await
}
}
@ -47,13 +41,7 @@ impl AnswerShippingQuery {
S: Into<String>,
{
let shipping_query_id = shipping_query_id.into();
Self {
bot,
shipping_query_id,
ok,
shipping_options: None,
error_message: None,
}
Self { bot, shipping_query_id, ok, shipping_options: None, error_message: None }
}
/// Unique identifier for the query to be answered.

View file

@ -25,13 +25,7 @@ impl Request for DeleteChatPhoto {
type Output = True;
async fn send(&self) -> ResponseResult<True> {
net::request_json(
self.bot.client(),
self.bot.token(),
"deleteChatPhoto",
&self,
)
.await
net::request_json(self.bot.client(), self.bot.token(), "deleteChatPhoto", &self).await
}
}

View file

@ -30,13 +30,7 @@ impl Request for DeleteChatStickerSet {
type Output = True;
async fn send(&self) -> ResponseResult<True> {
net::request_json(
self.bot.client(),
self.bot.token(),
"deleteChatStickerSet",
&self,
)
.await
net::request_json(self.bot.client(), self.bot.token(), "deleteChatStickerSet", &self).await
}
}

View file

@ -36,13 +36,7 @@ impl Request for DeleteMessage {
type Output = True;
async fn send(&self) -> ResponseResult<True> {
net::request_json(
self.bot.client(),
self.bot.token(),
"deleteMessage",
&self,
)
.await
net::request_json(self.bot.client(), self.bot.token(), "deleteMessage", &self).await
}
}

View file

@ -23,13 +23,7 @@ impl Request for DeleteStickerFromSet {
type Output = True;
async fn send(&self) -> ResponseResult<True> {
net::request_json(
self.bot.client(),
self.bot.token(),
"deleteStickerFromSet",
&self,
)
.await
net::request_json(self.bot.client(), self.bot.token(), "deleteStickerFromSet", &self).await
}
}

View file

@ -26,13 +26,7 @@ impl Request for DeleteWebhook {
#[allow(clippy::trivially_copy_pass_by_ref)]
async fn send(&self) -> ResponseResult<True> {
net::request_json(
self.bot.client(),
self.bot.token(),
"deleteWebhook",
&self,
)
.await
net::request_json(self.bot.client(), self.bot.token(), "deleteWebhook", &self).await
}
}

View file

@ -33,28 +33,13 @@ impl Request for EditMessageCaption {
type Output = Message;
async fn send(&self) -> ResponseResult<Message> {
net::request_json(
self.bot.client(),
self.bot.token(),
"editMessageCaption",
&self,
)
.await
net::request_json(self.bot.client(), self.bot.token(), "editMessageCaption", &self).await
}
}
impl EditMessageCaption {
pub(crate) fn new(
bot: Bot,
chat_or_inline_message: ChatOrInlineMessage,
) -> Self {
Self {
bot,
chat_or_inline_message,
caption: None,
parse_mode: None,
reply_markup: None,
}
pub(crate) fn new(bot: Bot, chat_or_inline_message: ChatOrInlineMessage) -> Self {
Self { bot, chat_or_inline_message, caption: None, parse_mode: None, reply_markup: None }
}
pub fn chat_or_inline_message(mut self, val: ChatOrInlineMessage) -> Self {

View file

@ -35,13 +35,8 @@ impl Request for EditMessageLiveLocation {
type Output = Message;
async fn send(&self) -> ResponseResult<Message> {
net::request_json(
self.bot.client(),
self.bot.token(),
"editMessageLiveLocation",
&self,
)
.await
net::request_json(self.bot.client(), self.bot.token(), "editMessageLiveLocation", &self)
.await
}
}
@ -52,13 +47,7 @@ impl EditMessageLiveLocation {
latitude: f32,
longitude: f32,
) -> Self {
Self {
bot,
chat_or_inline_message,
latitude,
longitude,
reply_markup: None,
}
Self { bot, chat_or_inline_message, latitude, longitude, reply_markup: None }
}
pub fn chat_or_inline_message(mut self, val: ChatOrInlineMessage) -> Self {

View file

@ -36,13 +36,10 @@ impl Request for EditMessageMedia {
match &self.chat_or_inline_message {
ChatOrInlineMessage::Chat { chat_id, message_id } => {
params = params
.add_text("chat_id", chat_id)
.add_text("message_id", message_id);
params = params.add_text("chat_id", chat_id).add_text("message_id", message_id);
}
ChatOrInlineMessage::Inline { inline_message_id } => {
params =
params.add_text("inline_message_id", inline_message_id);
params = params.add_text("inline_message_id", inline_message_id);
}
}

View file

@ -31,21 +31,13 @@ impl Request for EditMessageReplyMarkup {
type Output = Message;
async fn send(&self) -> ResponseResult<Message> {
net::request_json(
self.bot.client(),
self.bot.token(),
"editMessageReplyMarkup",
&self,
)
.await
net::request_json(self.bot.client(), self.bot.token(), "editMessageReplyMarkup", &self)
.await
}
}
impl EditMessageReplyMarkup {
pub(crate) fn new(
bot: Bot,
chat_or_inline_message: ChatOrInlineMessage,
) -> Self {
pub(crate) fn new(bot: Bot, chat_or_inline_message: ChatOrInlineMessage) -> Self {
Self { bot, chat_or_inline_message, reply_markup: None }
}

View file

@ -34,22 +34,12 @@ impl Request for EditMessageText {
type Output = Message;
async fn send(&self) -> ResponseResult<Message> {
net::request_json(
self.bot.client(),
self.bot.token(),
"editMessageText",
&self,
)
.await
net::request_json(self.bot.client(), self.bot.token(), "editMessageText", &self).await
}
}
impl EditMessageText {
pub(crate) fn new<T>(
bot: Bot,
chat_or_inline_message: ChatOrInlineMessage,
text: T,
) -> Self
pub(crate) fn new<T>(bot: Bot, chat_or_inline_message: ChatOrInlineMessage, text: T) -> Self
where
T: Into<String>,
{

View file

@ -40,13 +40,7 @@ impl Request for ExportChatInviteLink {
/// Returns the new invite link as `String` on success.
async fn send(&self) -> ResponseResult<String> {
net::request_json(
self.bot.client(),
self.bot.token(),
"exportChatInviteLink",
&self,
)
.await
net::request_json(self.bot.client(), self.bot.token(), "exportChatInviteLink", &self).await
}
}

View file

@ -26,36 +26,19 @@ impl Request for ForwardMessage {
type Output = Message;
async fn send(&self) -> ResponseResult<Message> {
net::request_json(
self.bot.client(),
self.bot.token(),
"forwardMessage",
&self,
)
.await
net::request_json(self.bot.client(), self.bot.token(), "forwardMessage", &self).await
}
}
impl ForwardMessage {
pub(crate) fn new<C, F>(
bot: Bot,
chat_id: C,
from_chat_id: F,
message_id: i32,
) -> Self
pub(crate) fn new<C, F>(bot: Bot, chat_id: C, from_chat_id: F, message_id: i32) -> Self
where
C: Into<ChatId>,
F: Into<ChatId>,
{
let chat_id = chat_id.into();
let from_chat_id = from_chat_id.into();
Self {
bot,
chat_id,
from_chat_id,
message_id,
disable_notification: None,
}
Self { bot, chat_id, from_chat_id, message_id, disable_notification: None }
}
/// Unique identifier for the target chat or username of the target channel

View file

@ -25,8 +25,7 @@ impl Request for GetChat {
type Output = Chat;
async fn send(&self) -> ResponseResult<Chat> {
net::request_json(self.bot.client(), self.bot.token(), "getChat", &self)
.await
net::request_json(self.bot.client(), self.bot.token(), "getChat", &self).await
}
}

View file

@ -28,13 +28,7 @@ impl Request for GetChatAdministrators {
/// On success, returns an array that contains information about all chat
/// administrators except other bots.
async fn send(&self) -> ResponseResult<Vec<ChatMember>> {
net::request_json(
self.bot.client(),
self.bot.token(),
"getChatAdministrators",
&self,
)
.await
net::request_json(self.bot.client(), self.bot.token(), "getChatAdministrators", &self).await
}
}

View file

@ -24,13 +24,7 @@ impl Request for GetChatMember {
type Output = ChatMember;
async fn send(&self) -> ResponseResult<ChatMember> {
net::request_json(
self.bot.client(),
self.bot.token(),
"getChatMember",
&self,
)
.await
net::request_json(self.bot.client(), self.bot.token(), "getChatMember", &self).await
}
}

View file

@ -23,13 +23,7 @@ impl Request for GetChatMembersCount {
type Output = i32;
async fn send(&self) -> ResponseResult<i32> {
net::request_json(
self.bot.client(),
self.bot.token(),
"getChatMembersCount",
&self,
)
.await
net::request_json(self.bot.client(), self.bot.token(), "getChatMembersCount", &self).await
}
}

View file

@ -39,8 +39,7 @@ impl Request for GetFile {
type Output = File;
async fn send(&self) -> ResponseResult<File> {
net::request_json(self.bot.client(), self.bot.token(), "getFile", &self)
.await
net::request_json(self.bot.client(), self.bot.token(), "getFile", &self).await
}
}

View file

@ -34,22 +34,12 @@ impl Request for GetGameHighScores {
type Output = Vec<GameHighScore>;
async fn send(&self) -> ResponseResult<Vec<GameHighScore>> {
net::request_json(
self.bot.client(),
self.bot.token(),
"getGameHighScores",
&self,
)
.await
net::request_json(self.bot.client(), self.bot.token(), "getGameHighScores", &self).await
}
}
impl GetGameHighScores {
pub(crate) fn new(
bot: Bot,
chat_or_inline_message: ChatOrInlineMessage,
user_id: i32,
) -> Self {
pub(crate) fn new(bot: Bot, chat_or_inline_message: ChatOrInlineMessage, user_id: i32) -> Self {
Self { bot, chat_or_inline_message, user_id }
}

View file

@ -22,8 +22,7 @@ impl Request for GetMe {
/// Returns basic information about the bot.
#[allow(clippy::trivially_copy_pass_by_ref)]
async fn send(&self) -> ResponseResult<Me> {
net::request_json(self.bot.client(), self.bot.token(), "getMe", &self)
.await
net::request_json(self.bot.client(), self.bot.token(), "getMe", &self).await
}
}

View file

@ -23,13 +23,7 @@ impl Request for GetStickerSet {
type Output = StickerSet;
async fn send(&self) -> ResponseResult<StickerSet> {
net::request_json(
self.bot.client(),
self.bot.token(),
"getStickerSet",
&self,
)
.await
net::request_json(self.bot.client(), self.bot.token(), "getStickerSet", &self).await
}
}

View file

@ -36,23 +36,14 @@ impl Request for GetUpdates {
/// Deserialize to `Vec<serde_json::Result<Update>>` instead of
/// `Vec<Update>`, because we want to parse the rest of updates even if our
/// library hasn't parsed one.
async fn send(
&self,
) -> ResponseResult<Vec<Result<Update, (Value, serde_json::Error)>>> {
let value: Value = net::request_json(
self.bot.client(),
self.bot.token(),
"getUpdates",
&self,
)
.await?;
async fn send(&self) -> ResponseResult<Vec<Result<Update, (Value, serde_json::Error)>>> {
let value: Value =
net::request_json(self.bot.client(), self.bot.token(), "getUpdates", &self).await?;
match value {
Value::Array(array) => Ok(array
.into_iter()
.map(|value| {
Update::try_parse(&value).map_err(|error| (value, error))
})
.map(|value| Update::try_parse(&value).map_err(|error| (value, error)))
.collect()),
_ => Err(RequestError::InvalidJson(
serde_json::from_value::<Vec<Update>>(value)
@ -64,13 +55,7 @@ impl Request for GetUpdates {
impl GetUpdates {
pub(crate) fn new(bot: Bot) -> Self {
Self {
bot,
offset: None,
limit: None,
timeout: None,
allowed_updates: None,
}
Self { bot, offset: None, limit: None, timeout: None, allowed_updates: None }
}
/// Identifier of the first update to be returned.

View file

@ -25,13 +25,7 @@ impl Request for GetUserProfilePhotos {
type Output = UserProfilePhotos;
async fn send(&self) -> ResponseResult<UserProfilePhotos> {
net::request_json(
self.bot.client(),
self.bot.token(),
"getUserProfilePhotos",
&self,
)
.await
net::request_json(self.bot.client(), self.bot.token(), "getUserProfilePhotos", &self).await
}
}

View file

@ -27,13 +27,7 @@ impl Request for GetWebhookInfo {
#[allow(clippy::trivially_copy_pass_by_ref)]
async fn send(&self) -> ResponseResult<WebhookInfo> {
net::request_json(
self.bot.client(),
self.bot.token(),
"getWebhookInfo",
&self,
)
.await
net::request_json(self.bot.client(), self.bot.token(), "getWebhookInfo", &self).await
}
}

View file

@ -32,13 +32,7 @@ impl Request for KickChatMember {
type Output = True;
async fn send(&self) -> ResponseResult<True> {
net::request_json(
self.bot.client(),
self.bot.token(),
"kickChatMember",
&self,
)
.await
net::request_json(self.bot.client(), self.bot.token(), "kickChatMember", &self).await
}
}

View file

@ -23,13 +23,7 @@ impl Request for LeaveChat {
type Output = True;
async fn send(&self) -> ResponseResult<True> {
net::request_json(
self.bot.client(),
self.bot.token(),
"leaveChat",
&self,
)
.await
net::request_json(self.bot.client(), self.bot.token(), "leaveChat", &self).await
}
}

View file

@ -29,13 +29,7 @@ impl Request for PinChatMessage {
type Output = True;
async fn send(&self) -> ResponseResult<True> {
net::request_json(
self.bot.client(),
self.bot.token(),
"pinChatMessage",
&self,
)
.await
net::request_json(self.bot.client(), self.bot.token(), "pinChatMessage", &self).await
}
}

View file

@ -36,13 +36,7 @@ impl Request for PromoteChatMember {
type Output = True;
async fn send(&self) -> ResponseResult<True> {
net::request_json(
self.bot.client(),
self.bot.token(),
"promoteChatMember",
&self,
)
.await
net::request_json(self.bot.client(), self.bot.token(), "promoteChatMember", &self).await
}
}

View file

@ -30,23 +30,12 @@ impl Request for RestrictChatMember {
type Output = True;
async fn send(&self) -> ResponseResult<True> {
net::request_json(
self.bot.client(),
self.bot.token(),
"restrictChatMember",
&self,
)
.await
net::request_json(self.bot.client(), self.bot.token(), "restrictChatMember", &self).await
}
}
impl RestrictChatMember {
pub(crate) fn new<C>(
bot: Bot,
chat_id: C,
user_id: i32,
permissions: ChatPermissions,
) -> Self
pub(crate) fn new<C>(bot: Bot, chat_id: C, user_id: i32, permissions: ChatPermissions) -> Self
where
C: Into<ChatId>,
{

View file

@ -75,22 +75,12 @@ impl Request for SendChatAction {
type Output = True;
async fn send(&self) -> ResponseResult<True> {
net::request_json(
self.bot.client(),
self.bot.token(),
"sendChatAction",
&self,
)
.await
net::request_json(self.bot.client(), self.bot.token(), "sendChatAction", &self).await
}
}
impl SendChatAction {
pub(crate) fn new<C>(
bot: Bot,
chat_id: C,
action: SendChatActionKind,
) -> Self
pub(crate) fn new<C>(bot: Bot, chat_id: C, action: SendChatActionKind) -> Self
where
C: Into<ChatId>,
{

View file

@ -30,23 +30,12 @@ impl Request for SendContact {
type Output = Message;
async fn send(&self) -> ResponseResult<Message> {
net::request_json(
self.bot.client(),
self.bot.token(),
"sendContact",
&self,
)
.await
net::request_json(self.bot.client(), self.bot.token(), "sendContact", &self).await
}
}
impl SendContact {
pub(crate) fn new<C, P, F>(
bot: Bot,
chat_id: C,
phone_number: P,
first_name: F,
) -> Self
pub(crate) fn new<C, P, F>(bot: Bot, chat_id: C, phone_number: P, first_name: F) -> Self
where
C: Into<ChatId>,
P: Into<String>,

View file

@ -27,13 +27,7 @@ impl Request for SendGame {
type Output = Message;
async fn send(&self) -> ResponseResult<Message> {
net::request_json(
self.bot.client(),
self.bot.token(),
"sendGame",
&self,
)
.await
net::request_json(self.bot.client(), self.bot.token(), "sendGame", &self).await
}
}

View file

@ -45,13 +45,7 @@ impl Request for SendInvoice {
type Output = Message;
async fn send(&self) -> ResponseResult<Message> {
net::request_json(
self.bot.client(),
self.bot.token(),
"sendInvoice",
&self,
)
.await
net::request_json(self.bot.client(), self.bot.token(), "sendInvoice", &self).await
}
}

View file

@ -29,23 +29,12 @@ impl Request for SendLocation {
type Output = Message;
async fn send(&self) -> ResponseResult<Message> {
net::request_json(
self.bot.client(),
self.bot.token(),
"sendLocation",
&self,
)
.await
net::request_json(self.bot.client(), self.bot.token(), "sendLocation", &self).await
}
}
impl SendLocation {
pub(crate) fn new<C>(
bot: Bot,
chat_id: C,
latitude: f32,
longitude: f32,
) -> Self
pub(crate) fn new<C>(bot: Bot, chat_id: C, latitude: f32, longitude: f32) -> Self
where
C: Into<ChatId>,
{

View file

@ -45,13 +45,7 @@ impl SendMediaGroup {
{
let chat_id = chat_id.into();
let media = media.into();
Self {
bot,
chat_id,
media,
disable_notification: None,
reply_to_message_id: None,
}
Self { bot, chat_id, media, disable_notification: None, reply_to_message_id: None }
}
/// Unique identifier for the target chat or username of the target channel

View file

@ -29,13 +29,7 @@ impl Request for SendMessage {
type Output = Message;
async fn send(&self) -> ResponseResult<Message> {
net::request_json(
self.bot.client(),
self.bot.token(),
"sendMessage",
&self,
)
.await
net::request_json(self.bot.client(), self.bot.token(), "sendMessage", &self).await
}
}

View file

@ -33,23 +33,12 @@ impl Request for SendPoll {
type Output = Message;
async fn send(&self) -> ResponseResult<Message> {
net::request_json(
self.bot.client(),
self.bot.token(),
"sendPoll",
&self,
)
.await
net::request_json(self.bot.client(), self.bot.token(), "sendPoll", &self).await
}
}
impl SendPoll {
pub(crate) fn new<C, Q, O>(
bot: Bot,
chat_id: C,
question: Q,
options: O,
) -> Self
pub(crate) fn new<C, Q, O>(bot: Bot, chat_id: C, question: Q, options: O) -> Self
where
C: Into<ChatId>,
Q: Into<String>,

View file

@ -32,13 +32,7 @@ impl Request for SendVenue {
type Output = Message;
async fn send(&self) -> ResponseResult<Message> {
net::request_json(
self.bot.client(),
self.bot.token(),
"sendVenue",
&self,
)
.await
net::request_json(self.bot.client(), self.bot.token(), "sendVenue", &self).await
}
}

View file

@ -37,12 +37,7 @@ impl Request for SetChatAdministratorCustomTitle {
}
impl SetChatAdministratorCustomTitle {
pub(crate) fn new<C, CT>(
bot: Bot,
chat_id: C,
user_id: i32,
custom_title: CT,
) -> Self
pub(crate) fn new<C, CT>(bot: Bot, chat_id: C, user_id: i32, custom_title: CT) -> Self
where
C: Into<ChatId>,
CT: Into<String>,

View file

@ -28,13 +28,7 @@ impl Request for SetChatDescription {
type Output = True;
async fn send(&self) -> ResponseResult<True> {
net::request_json(
self.bot.client(),
self.bot.token(),
"setChatDescription",
&self,
)
.await
net::request_json(self.bot.client(), self.bot.token(), "setChatDescription", &self).await
}
}

View file

@ -27,22 +27,12 @@ impl Request for SetChatPermissions {
type Output = True;
async fn send(&self) -> ResponseResult<True> {
net::request_json(
self.bot.client(),
self.bot.token(),
"sendChatPermissions",
&self,
)
.await
net::request_json(self.bot.client(), self.bot.token(), "sendChatPermissions", &self).await
}
}
impl SetChatPermissions {
pub(crate) fn new<C>(
bot: Bot,
chat_id: C,
permissions: ChatPermissions,
) -> Self
pub(crate) fn new<C>(bot: Bot, chat_id: C, permissions: ChatPermissions) -> Self
where
C: Into<ChatId>,
{

View file

@ -27,13 +27,7 @@ impl Request for SetChatPhoto {
type Output = True;
async fn send(&self) -> ResponseResult<True> {
net::request_json(
self.bot.client(),
self.bot.token(),
"setChatPhoto",
&self,
)
.await
net::request_json(self.bot.client(), self.bot.token(), "setChatPhoto", &self).await
}
}

View file

@ -28,13 +28,7 @@ impl Request for SetChatStickerSet {
type Output = True;
async fn send(&self) -> ResponseResult<True> {
net::request_json(
self.bot.client(),
self.bot.token(),
"setChatStickerSet",
&self,
)
.await
net::request_json(self.bot.client(), self.bot.token(), "setChatStickerSet", &self).await
}
}

View file

@ -27,13 +27,7 @@ impl Request for SetChatTitle {
type Output = True;
async fn send(&self) -> ResponseResult<True> {
net::request_json(
self.bot.client(),
self.bot.token(),
"setChatTitle",
&self,
)
.await
net::request_json(self.bot.client(), self.bot.token(), "setChatTitle", &self).await
}
}

View file

@ -36,13 +36,7 @@ impl Request for SetGameScore {
type Output = Message;
async fn send(&self) -> ResponseResult<Message> {
net::request_json(
self.bot.client(),
self.bot.token(),
"setGameScore",
&self,
)
.await
net::request_json(self.bot.client(), self.bot.token(), "setGameScore", &self).await
}
}

View file

@ -25,13 +25,8 @@ impl Request for SetStickerPositionInSet {
type Output = True;
async fn send(&self) -> ResponseResult<True> {
net::request_json(
self.bot.client(),
self.bot.token(),
"setStickerPositionInSet",
&self,
)
.await
net::request_json(self.bot.client(), self.bot.token(), "setStickerPositionInSet", &self)
.await
}
}

View file

@ -39,13 +39,7 @@ impl Request for SetWebhook {
type Output = True;
async fn send(&self) -> ResponseResult<True> {
net::request_json(
self.bot.client(),
self.bot.token(),
"setWebhook",
&self,
)
.await
net::request_json(self.bot.client(), self.bot.token(), "setWebhook", &self).await
}
}
@ -55,13 +49,7 @@ impl SetWebhook {
U: Into<String>,
{
let url = url.into();
Self {
bot,
url,
certificate: None,
max_connections: None,
allowed_updates: None,
}
Self { bot, url, certificate: None, max_connections: None, allowed_updates: None }
}
/// HTTPS url to send updates to.

View file

@ -32,21 +32,13 @@ impl Request for StopMessageLiveLocation {
type Output = Message;
async fn send(&self) -> ResponseResult<Message> {
net::request_json(
self.bot.client(),
self.bot.token(),
"stopMessageLiveLocation",
&self,
)
.await
net::request_json(self.bot.client(), self.bot.token(), "stopMessageLiveLocation", &self)
.await
}
}
impl StopMessageLiveLocation {
pub(crate) fn new(
bot: Bot,
chat_or_inline_message: ChatOrInlineMessage,
) -> Self {
pub(crate) fn new(bot: Bot, chat_or_inline_message: ChatOrInlineMessage) -> Self {
Self { bot, chat_or_inline_message, reply_markup: None }
}

View file

@ -28,13 +28,7 @@ impl Request for StopPoll {
///
/// [`Poll`]: crate::types::Poll
async fn send(&self) -> ResponseResult<Poll> {
net::request_json(
self.bot.client(),
self.bot.token(),
"stopPoll",
&self,
)
.await
net::request_json(self.bot.client(), self.bot.token(), "stopPoll", &self).await
}
}
impl StopPoll {

View file

@ -27,13 +27,7 @@ impl Request for UnbanChatMember {
type Output = True;
async fn send(&self) -> ResponseResult<True> {
net::request_json(
self.bot.client(),
self.bot.token(),
"unbanChatMember",
&self,
)
.await
net::request_json(self.bot.client(), self.bot.token(), "unbanChatMember", &self).await
}
}

View file

@ -27,13 +27,7 @@ impl Request for UnpinChatMessage {
type Output = True;
async fn send(&self) -> ResponseResult<True> {
net::request_json(
self.bot.client(),
self.bot.token(),
"unpinChatMessage",
&self,
)
.await
net::request_json(self.bot.client(), self.bot.token(), "unpinChatMessage", &self).await
}
}

View file

@ -28,13 +28,7 @@ impl Request for UploadStickerFile {
type Output = File;
async fn send(&self) -> ResponseResult<File> {
net::request_json(
self.bot.client(),
self.bot.token(),
"uploadStickerFile",
&self,
)
.await
net::request_json(self.bot.client(), self.bot.token(), "uploadStickerFile", &self).await
}
}

View file

@ -5,8 +5,7 @@ use reqwest::multipart::Form;
use crate::{
requests::utils::{file_from_memory_to_part, file_to_part},
types::{
ChatId, InlineKeyboardMarkup, InputFile, InputMedia, MaskPosition,
ParseMode, ReplyMarkup,
ChatId, InlineKeyboardMarkup, InputFile, InputMedia, MaskPosition, ParseMode, ReplyMarkup,
},
};
@ -27,18 +26,12 @@ impl FormBuilder {
T: IntoFormText,
{
match value.into_form_text() {
Some(val) => {
Self { form: self.form.text(name.into().into_owned(), val) }
}
Some(val) => Self { form: self.form.text(name.into().into_owned(), val) },
None => self,
}
}
pub async fn add_input_file<'a, N>(
self,
name: N,
value: &InputFile,
) -> tokio::io::Result<Self>
pub async fn add_input_file<'a, N>(self, name: N, value: &InputFile) -> tokio::io::Result<Self>
where
N: Into<Cow<'a, str>>,
{
@ -53,19 +46,12 @@ impl FormBuilder {
}
// used in SendMediaGroup
pub async fn add_file<'a, N>(
self,
name: N,
path_to_file: PathBuf,
) -> tokio::io::Result<Self>
pub async fn add_file<'a, N>(self, name: N, path_to_file: PathBuf) -> tokio::io::Result<Self>
where
N: Into<Cow<'a, str>>,
{
Ok(Self {
form: self.form.part(
name.into().into_owned(),
file_to_part(path_to_file).await?,
),
form: self.form.part(name.into().into_owned(), file_to_part(path_to_file).await?),
})
}
@ -79,10 +65,9 @@ impl FormBuilder {
N: Into<Cow<'a, str>>,
{
Self {
form: self.form.part(
name.into().into_owned(),
file_from_memory_to_part(data, file_name),
),
form: self
.form
.part(name.into().into_owned(), file_from_memory_to_part(data, file_name)),
}
}
@ -109,15 +94,7 @@ macro_rules! impl_for_struct {
};
}
impl_for_struct!(
bool,
i32,
i64,
u32,
ReplyMarkup,
InlineKeyboardMarkup,
MaskPosition
);
impl_for_struct!(bool, i32, i64, u32, ReplyMarkup, InlineKeyboardMarkup, MaskPosition);
impl<T> IntoFormText for Option<T>
where
@ -132,16 +109,14 @@ where
// encode files :|)
impl IntoFormText for Vec<InputMedia> {
fn into_form_text(&self) -> Option<String> {
let json =
serde_json::to_string(self).expect("serde_json::to_string failed");
let json = serde_json::to_string(self).expect("serde_json::to_string failed");
Some(json)
}
}
impl IntoFormText for InputMedia {
fn into_form_text(&self) -> Option<String> {
let json =
serde_json::to_string(self).expect("serde_json::to_string failed");
let json = serde_json::to_string(self).expect("serde_json::to_string failed");
Some(json)
}
}

View file

@ -10,10 +10,7 @@ impl Decoder for FileDecoder {
type Item = Bytes;
type Error = std::io::Error;
fn decode(
&mut self,
src: &mut BytesMut,
) -> Result<Option<Self::Item>, Self::Error> {
fn decode(&mut self, src: &mut BytesMut) -> Result<Option<Self::Item>, Self::Error> {
if src.is_empty() {
return Ok(None);
}
@ -22,20 +19,13 @@ impl Decoder for FileDecoder {
}
pub async fn file_to_part(path_to_file: PathBuf) -> std::io::Result<Part> {
let file_name =
path_to_file.file_name().unwrap().to_string_lossy().into_owned();
let file_name = path_to_file.file_name().unwrap().to_string_lossy().into_owned();
let file = FramedRead::new(
tokio::fs::File::open(path_to_file).await?,
FileDecoder,
);
let file = FramedRead::new(tokio::fs::File::open(path_to_file).await?, FileDecoder);
Ok(Part::stream(Body::wrap_stream(file)).file_name(file_name))
}
pub fn file_from_memory_to_part(
data: Cow<'static, [u8]>,
name: String,
) -> Part {
pub fn file_from_memory_to_part(data: Cow<'static, [u8]>, name: String) -> Part {
Part::bytes(data).file_name(name)
}

View file

@ -64,9 +64,7 @@ mod tests {
duration: 60,
performer: Some("Performer".to_string()),
title: Some("Title".to_string()),
mime_type: Some(
serde_json::from_str("\"application/zip\"").unwrap(),
),
mime_type: Some(serde_json::from_str("\"application/zip\"").unwrap()),
file_size: Some(123_456),
thumb: Some(PhotoSize {
file_id: "id".to_string(),

View file

@ -154,16 +154,10 @@ impl<'de> serde::de::Visitor<'de> for PrivateChatKindVisitor {
write!(f, r#"field equal to "private""#)
}
fn visit_borrowed_str<E: serde::de::Error>(
self,
v: &'de str,
) -> Result<Self::Value, E> {
fn visit_borrowed_str<E: serde::de::Error>(self, v: &'de str) -> Result<Self::Value, E> {
match v {
"private" => Ok(()),
_ => Err(E::invalid_value(
serde::de::Unexpected::Str(v),
&r#""private""#,
)),
_ => Err(E::invalid_value(serde::de::Unexpected::Str(v), &r#""private""#)),
}
}
}
@ -180,30 +174,16 @@ impl Chat {
matches!(self.kind, ChatKind::Private(_))
}
pub fn is_group(&self) -> bool {
matches!(
self.kind,
ChatKind::Public(ChatPublic {
kind: PublicChatKind::Group(_), ..
})
)
matches!(self.kind, ChatKind::Public(ChatPublic { kind: PublicChatKind::Group(_), .. }))
}
pub fn is_supergroup(&self) -> bool {
matches!(
self.kind,
ChatKind::Public(ChatPublic {
kind: PublicChatKind::Supergroup(_),
..
})
ChatKind::Public(ChatPublic { kind: PublicChatKind::Supergroup(_), .. })
)
}
pub fn is_channel(&self) -> bool {
matches!(
self.kind,
ChatKind::Public(ChatPublic {
kind: PublicChatKind::Channel(_),
..
})
)
matches!(self.kind, ChatKind::Public(ChatPublic { kind: PublicChatKind::Channel(_), .. }))
}
pub fn is_chat(&self) -> bool {
@ -232,9 +212,7 @@ mod tests {
}),
photo: None,
};
let actual =
from_str(r#"{"id":-1,"type":"channel","username":"channelname"}"#)
.unwrap();
let actual = from_str(r#"{"id":-1,"type":"channel","username":"channelname"}"#).unwrap();
assert_eq!(expected, actual);
}
@ -251,9 +229,9 @@ mod tests {
}),
photo: None,
},
from_str(
r#"{"id":0,"type":"private","username":"username","first_name":"Anon"}"#
).unwrap());
from_str(r#"{"id":0,"type":"private","username":"username","first_name":"Anon"}"#)
.unwrap()
);
}
#[test]

View file

@ -3,9 +3,7 @@ use serde::{Deserialize, Serialize};
/// A unique identifier for the target chat or username of the target channel
/// (in the format `@channelusername`).
#[derive(
Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize, Display, From,
)]
#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize, Display, From)]
#[serde(untagged)]
pub enum ChatId {
/// A chat identifier.
@ -32,10 +30,8 @@ mod tests {
#[test]
fn chat_id_channel_username_serialization() {
let expected_json = String::from(r#""@username""#);
let actual_json = serde_json::to_string(&ChatId::ChannelUsername(
String::from("@username"),
))
.unwrap();
let actual_json =
serde_json::to_string(&ChatId::ChannelUsername(String::from("@username"))).unwrap();
assert_eq!(expected_json, actual_json)
}

View file

@ -51,8 +51,7 @@ mod tests {
secret: "secret".to_string(),
};
// when
let actual_json =
serde_json::to_string(&encrypted_credentials).unwrap();
let actual_json = serde_json::to_string(&encrypted_credentials).unwrap();
//then
assert_eq!(actual_json, expected_json)
}

View file

@ -79,35 +79,21 @@ pub enum InlineKeyboardButtonKind {
/// ```
/// use teloxide::types::InlineKeyboardButton;
///
/// let url_button = InlineKeyboardButton::url(
/// "Text".to_string(),
/// "http://url.com".to_string(),
/// );
/// let url_button = InlineKeyboardButton::url("Text".to_string(), "http://url.com".to_string());
/// ```
impl InlineKeyboardButton {
pub fn url(text: String, url: String) -> InlineKeyboardButton {
InlineKeyboardButton { text, kind: InlineKeyboardButtonKind::Url(url) }
}
pub fn callback(
text: String,
callback_data: String,
) -> InlineKeyboardButton {
InlineKeyboardButton {
text,
kind: InlineKeyboardButtonKind::CallbackData(callback_data),
}
pub fn callback(text: String, callback_data: String) -> InlineKeyboardButton {
InlineKeyboardButton { text, kind: InlineKeyboardButtonKind::CallbackData(callback_data) }
}
pub fn switch_inline_query(
text: String,
switch_inline_query: String,
) -> InlineKeyboardButton {
pub fn switch_inline_query(text: String, switch_inline_query: String) -> InlineKeyboardButton {
InlineKeyboardButton {
text,
kind: InlineKeyboardButtonKind::SwitchInlineQuery(
switch_inline_query,
),
kind: InlineKeyboardButtonKind::SwitchInlineQuery(switch_inline_query),
}
}

View file

@ -26,10 +26,7 @@ pub struct InlineKeyboardMarkup {
/// ```
/// use teloxide::types::{InlineKeyboardButton, InlineKeyboardMarkup};
///
/// let url_button = InlineKeyboardButton::url(
/// "text".to_string(),
/// "http://url.com".to_string(),
/// );
/// let url_button = InlineKeyboardButton::url("text".to_string(), "http://url.com".to_string());
/// let keyboard = InlineKeyboardMarkup::default().append_row(vec![url_button]);
/// ```
impl InlineKeyboardMarkup {
@ -38,11 +35,7 @@ impl InlineKeyboardMarkup {
self
}
pub fn append_to_row(
mut self,
button: InlineKeyboardButton,
index: usize,
) -> Self {
pub fn append_to_row(mut self, button: InlineKeyboardButton, index: usize) -> Self {
match self.inline_keyboard.get_mut(index) {
Some(buttons) => buttons.push(button),
None => self.inline_keyboard.push(vec![button]),
@ -57,65 +50,41 @@ mod tests {
#[test]
fn append_row() {
let button1 = InlineKeyboardButton::url(
"text 1".to_string(),
"url 1".to_string(),
);
let button2 = InlineKeyboardButton::url(
"text 2".to_string(),
"url 2".to_string(),
);
let button1 = InlineKeyboardButton::url("text 1".to_string(), "url 1".to_string());
let button2 = InlineKeyboardButton::url("text 2".to_string(), "url 2".to_string());
let markup = InlineKeyboardMarkup::default()
.append_row(vec![button1.clone(), button2.clone()]);
let markup =
InlineKeyboardMarkup::default().append_row(vec![button1.clone(), button2.clone()]);
let expected = InlineKeyboardMarkup {
inline_keyboard: vec![vec![button1, button2]],
};
let expected = InlineKeyboardMarkup { inline_keyboard: vec![vec![button1, button2]] };
assert_eq!(markup, expected);
}
#[test]
fn append_to_row_existent_row() {
let button1 = InlineKeyboardButton::url(
"text 1".to_string(),
"url 1".to_string(),
);
let button2 = InlineKeyboardButton::url(
"text 2".to_string(),
"url 2".to_string(),
);
let button1 = InlineKeyboardButton::url("text 1".to_string(), "url 1".to_string());
let button2 = InlineKeyboardButton::url("text 2".to_string(), "url 2".to_string());
let markup = InlineKeyboardMarkup::default()
.append_row(vec![button1.clone()])
.append_to_row(button2.clone(), 0);
let expected = InlineKeyboardMarkup {
inline_keyboard: vec![vec![button1, button2]],
};
let expected = InlineKeyboardMarkup { inline_keyboard: vec![vec![button1, button2]] };
assert_eq!(markup, expected);
}
#[test]
fn append_to_row_nonexistent_row() {
let button1 = InlineKeyboardButton::url(
"text 1".to_string(),
"url 1".to_string(),
);
let button2 = InlineKeyboardButton::url(
"text 2".to_string(),
"url 2".to_string(),
);
let button1 = InlineKeyboardButton::url("text 1".to_string(), "url 1".to_string());
let button2 = InlineKeyboardButton::url("text 2".to_string(), "url 2".to_string());
let markup = InlineKeyboardMarkup::default()
.append_row(vec![button1.clone()])
.append_to_row(button2.clone(), 1);
let expected = InlineKeyboardMarkup {
inline_keyboard: vec![vec![button1], vec![button2]],
};
let expected = InlineKeyboardMarkup { inline_keyboard: vec![vec![button1], vec![button2]] };
assert_eq!(markup, expected);
}

View file

@ -4,15 +4,13 @@ use derive_more::From;
use serde::{Deserialize, Serialize};
use crate::types::{
InlineQueryResultArticle, InlineQueryResultAudio,
InlineQueryResultCachedAudio, InlineQueryResultCachedDocument,
InlineQueryResultCachedGif, InlineQueryResultCachedMpeg4Gif,
InlineQueryResultCachedPhoto, InlineQueryResultCachedSticker,
InlineQueryResultCachedVideo, InlineQueryResultCachedVoice,
InlineQueryResultContact, InlineQueryResultDocument, InlineQueryResultGame,
InlineQueryResultGif, InlineQueryResultLocation, InlineQueryResultMpeg4Gif,
InlineQueryResultPhoto, InlineQueryResultVenue, InlineQueryResultVideo,
InlineQueryResultVoice,
InlineQueryResultArticle, InlineQueryResultAudio, InlineQueryResultCachedAudio,
InlineQueryResultCachedDocument, InlineQueryResultCachedGif, InlineQueryResultCachedMpeg4Gif,
InlineQueryResultCachedPhoto, InlineQueryResultCachedSticker, InlineQueryResultCachedVideo,
InlineQueryResultCachedVoice, InlineQueryResultContact, InlineQueryResultDocument,
InlineQueryResultGame, InlineQueryResultGif, InlineQueryResultLocation,
InlineQueryResultMpeg4Gif, InlineQueryResultPhoto, InlineQueryResultVenue,
InlineQueryResultVideo, InlineQueryResultVoice,
};
/// This object represents one result of an inline query.
@ -57,25 +55,22 @@ pub enum InlineQueryResult {
#[cfg(test)]
mod tests {
use crate::types::{
inline_keyboard_markup::InlineKeyboardMarkup, parse_mode::ParseMode,
InlineQueryResult, InlineQueryResultCachedAudio, InputMessageContent,
InputMessageContentText,
inline_keyboard_markup::InlineKeyboardMarkup, parse_mode::ParseMode, InlineQueryResult,
InlineQueryResultCachedAudio, InputMessageContent, InputMessageContentText,
};
#[test]
fn cached_audio_min_serialize() {
let structure =
InlineQueryResult::CachedAudio(InlineQueryResultCachedAudio {
id: String::from("id"),
audio_file_id: String::from("audio_file_id"),
caption: None,
parse_mode: None,
reply_markup: None,
input_message_content: None,
});
let structure = InlineQueryResult::CachedAudio(InlineQueryResultCachedAudio {
id: String::from("id"),
audio_file_id: String::from("audio_file_id"),
caption: None,
parse_mode: None,
reply_markup: None,
input_message_content: None,
});
let expected_json =
r#"{"type":"audio","id":"id","audio_file_id":"audio_file_id"}"#;
let expected_json = r#"{"type":"audio","id":"id","audio_file_id":"audio_file_id"}"#;
let actual_json = serde_json::to_string(&structure).unwrap();
assert_eq!(expected_json, actual_json);
@ -83,21 +78,18 @@ mod tests {
#[test]
fn cached_audio_full_serialize() {
let structure =
InlineQueryResult::CachedAudio(InlineQueryResultCachedAudio {
id: String::from("id"),
audio_file_id: String::from("audio_file_id"),
caption: Some(String::from("caption")),
parse_mode: Some(ParseMode::HTML),
reply_markup: Some(InlineKeyboardMarkup::default()),
input_message_content: Some(InputMessageContent::Text(
InputMessageContentText {
message_text: String::from("message_text"),
parse_mode: Some(ParseMode::MarkdownV2),
disable_web_page_preview: Some(true),
},
)),
});
let structure = InlineQueryResult::CachedAudio(InlineQueryResultCachedAudio {
id: String::from("id"),
audio_file_id: String::from("audio_file_id"),
caption: Some(String::from("caption")),
parse_mode: Some(ParseMode::HTML),
reply_markup: Some(InlineKeyboardMarkup::default()),
input_message_content: Some(InputMessageContent::Text(InputMessageContentText {
message_text: String::from("message_text"),
parse_mode: Some(ParseMode::MarkdownV2),
disable_web_page_preview: Some(true),
})),
});
let expected_json = r#"{"type":"audio","id":"id","audio_file_id":"audio_file_id","caption":"caption","parse_mode":"HTML","reply_markup":{"inline_keyboard":[]},"input_message_content":{"message_text":"message_text","parse_mode":"MarkdownV2","disable_web_page_preview":true}}"#;
let actual_json = serde_json::to_string(&structure).unwrap();

View file

@ -1,8 +1,6 @@
use serde::{Deserialize, Serialize};
use crate::types::{
InlineKeyboardMarkup, InputMessageContent, MimeWrapper, ParseMode,
};
use crate::types::{InlineKeyboardMarkup, InputMessageContent, MimeWrapper, ParseMode};
/// Represents a link to a file.
///

View file

@ -1,8 +1,6 @@
use serde::{Deserialize, Serialize};
use crate::types::{
InlineKeyboardMarkup, InputMessageContent, MimeWrapper, ParseMode,
};
use crate::types::{InlineKeyboardMarkup, InputMessageContent, MimeWrapper, ParseMode};
/// Represents a link to a page containing an embedded video player or a video
/// file.

View file

@ -85,19 +85,13 @@ impl Serialize for InputFile {
// multipart/form-data
serializer.serialize_str(
// TODO: remove unwrap (?)
&format!(
"attach://{}",
path.file_name().unwrap().to_string_lossy()
),
&format!("attach://{}", path.file_name().unwrap().to_string_lossy()),
)
}
InputFile::Memory { data, .. } => {
// NOTE: file should be actually attached with
// multipart/form-data
serializer.serialize_str(&format!(
"attach://{}",
String::from_utf8_lossy(data)
))
serializer.serialize_str(&format!("attach://{}", String::from_utf8_lossy(data)))
}
InputFile::Url(url) => serializer.serialize_str(url),
InputFile::FileId(id) => serializer.serialize_str(id),

Some files were not shown because too many files have changed in this diff Show more