Merge pull request #239 from teloxide/v4.7

v4.7
This commit is contained in:
Temirkhan Myrzamadi 2020-07-30 10:41:05 +06:00 committed by GitHub
commit cf87d72852
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
25 changed files with 571 additions and 122 deletions

View file

@ -53,7 +53,7 @@ jobs:
dialogue_bot,
heroku_ping_pong_bot,
ngrok_ping_pong_bot,
ping_pong_bot,
dices_bot,
shared_state_bot,
simple_commands_bot,
]

View file

@ -15,7 +15,7 @@
<img src="https://img.shields.io/badge/official%20chat-t.me%2Fteloxide-blueviolet">
</a>
<a href="https://core.telegram.org/bots/api">
<img src="https://img.shields.io/badge/API coverage-Up to 0.4.6 (inclusively)-green.svg">
<img src="https://img.shields.io/badge/API coverage-Up to 0.4.7 (inclusively)-green.svg">
</a>
A full-featured framework that empowers you to easily build [Telegram bots](https://telegram.org/blog/bot-revolution) using the [`async`/`.await`](https://rust-lang.github.io/async-book/01_getting_started/01_chapter.html) syntax in [Rust](https://www.rust-lang.org/). It handles all the difficult stuff so you can focus only on your business logic.
@ -25,7 +25,7 @@
- [Highlights](https://github.com/teloxide/teloxide#highlights)
- [Setting up your environment](https://github.com/teloxide/teloxide#setting-up-your-environment)
- [API overview](https://github.com/teloxide/teloxide#api-overview)
- [The ping-pong bot](https://github.com/teloxide/teloxide#the-ping-pong-bot)
- [The dices bot](https://github.com/teloxide/teloxide#the-dices-bot)
- [Commands](https://github.com/teloxide/teloxide#commands)
- [Dialogues management](https://github.com/teloxide/teloxide#dialogues-management)
- [Recommendations](https://github.com/teloxide/teloxide#recommendations)
@ -88,24 +88,24 @@ futures = "0.3.5"
## API overview
### The ping-pong bot
This bot has a single message handler, which answers "pong" to each incoming message:
### The dices bot
This bot throws a dice on each incoming message:
([Full](https://github.com/teloxide/teloxide/blob/master/examples/ping_pong_bot/src/main.rs))
([Full](https://github.com/teloxide/teloxide/blob/master/examples/dices_bot/src/main.rs))
```rust
use teloxide::prelude::*;
#[tokio::main]
async fn main() {
teloxide::enable_logging!();
log::info!("Starting ping_pong_bot...");
log::info!("Starting dices_bot...");
let bot = Bot::from_env();
Dispatcher::new(bot)
.messages_handler(|rx: DispatcherHandlerRx<Message>| {
rx.for_each(|message| async move {
message.answer_str("pong").await.log_on_error().await;
message.send_dice().send().await.log_on_error().await;
})
})
.dispatch()
@ -116,7 +116,7 @@ async fn main() {
<div align="center">
<kbd>
<img src=https://github.com/teloxide/teloxide/raw/master/media/PING_PONG_BOT.gif />
<img src=https://github.com/teloxide/teloxide/raw/master/media/DICES_BOT.gif />
</kbd>
</div>

View file

@ -2,7 +2,7 @@
Just enter the directory (for example, `cd dialogue_bot`) and execute `cargo run` to run an example. Don't forget to initialise the `TELOXIDE_TOKEN` environmental variable.
| Bot | Description |
|---|-----------|
| [ping_pong_bot](ping_pong_bot) | Answers "pong" to each incoming message. |
| [dices_bot](dices_bot) | This bot throws a dice on each incoming message. |
| [ngrok_ping_pong_bot](ngrok_ping_pong_bot) | The ngrok version of ping-pong-bot that uses webhooks. |
| [heroku_ping_pong_bot](heroku_ping_pong_bot) | The Heroku version of ping-pong-bot that uses webhooks. |
| [simple_commands_bot](simple_commands_bot) | Shows how to deal with bot's commands. |

View file

@ -1,5 +1,5 @@
[package]
name = "ping_pong_bot"
name = "dices_bot"
version = "0.1.0"
authors = ["Temirkhan Myrzamadi <hirrolot@gmail.com>"]
edition = "2018"

View file

@ -1,4 +1,4 @@
// This bot just answers "pong" to each incoming UpdateKind::Message.
// This bot throws a dice on each incoming message.
use teloxide::prelude::*;
@ -9,14 +9,14 @@ async fn main() {
async fn run() {
teloxide::enable_logging!();
log::info!("Starting ping_pong_bot...");
log::info!("Starting dices_bot...");
let bot = Bot::from_env();
Dispatcher::new(bot)
.messages_handler(|rx: DispatcherHandlerRx<Message>| {
rx.for_each(|message| async move {
message.answer_str("pong").await.log_on_error().await;
message.send_dice().send().await.log_on_error().await;
})
})
.dispatch()

BIN
media/DICES_BOT.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 169 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

View file

@ -5,19 +5,19 @@ use crate::{
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,
GetChatMembersCount, GetFile, GetGameHighScores, GetMe, GetMyCommands, GetStickerSet,
GetUpdates, GetUserProfilePhotos, GetWebhookInfo, KickChatMember, LeaveChat,
PinChatMessage, PromoteChatMember, RestrictChatMember, SendAnimation, SendAudio,
SendChatAction, SendChatActionKind, SendContact, SendDice, SendDocument, SendGame,
SendInvoice, SendLocation, SendMediaGroup, SendMessage, SendPhoto, SendPoll, SendSticker,
SendVenue, SendVideo, SendVideoNote, SendVoice, SetChatAdministratorCustomTitle,
SetChatDescription, SetChatPermissions, SetChatPhoto, SetChatStickerSet, SetChatTitle,
SetGameScore, SetMyCommands, SetStickerPositionInSet, SetStickerSetThumb, SetWebhook,
StopMessageLiveLocation, StopPoll, UnbanChatMember, UnpinChatMessage, UploadStickerFile,
},
types::{
ChatId, ChatOrInlineMessage, ChatPermissions, InlineQueryResult, InputFile, InputMedia,
LabeledPrice,
BotCommand, ChatId, ChatOrInlineMessage, ChatPermissions, InlineQueryResult, InputFile,
InputMedia, LabeledPrice, StickerType,
},
Bot,
};
@ -1198,25 +1198,12 @@ impl Bot {
/// end in `_by_<bot username>`. `<bot_username>` is case insensitive. 1-64
/// characters.
/// - `title`: Sticker set title, 1-64 characters.
/// - `png_sticker`: **Png** image with the sticker, must be up to 512
/// kilobytes in size, dimensions must not exceed 512px, and either
/// width or height must be exactly 512px.
///
/// Pass [`InputFile::File`] to send a file that exists on the Telegram
/// servers (recommended), pass an [`InputFile::Url`] for Telegram to get a
/// .webp file from the Internet, or upload a new one using
/// [`InputFile::FileId`]. [More info on Sending Files »].
/// - `emojis`: One or more emoji corresponding to the sticker.
///
/// [`InputFile::File`]: crate::types::InputFile::File
/// [`InputFile::Url`]: crate::types::InputFile::Url
/// [`InputFile::FileId`]: crate::types::InputFile::FileId
pub fn create_new_sticker_set<N, T, E>(
&self,
user_id: i32,
name: N,
title: T,
png_sticker: InputFile,
sticker_type: StickerType,
emojis: E,
) -> CreateNewStickerSet
where
@ -1224,7 +1211,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, sticker_type, emojis)
}
/// Use this method to add a new sticker to a set created by the bot.
@ -1234,31 +1221,19 @@ impl Bot {
/// # Params
/// - `user_id`: User identifier of sticker set owner.
/// - `name`: Sticker set name.
/// - `png_sticker`: **Png** image with the sticker, must be up to 512
/// kilobytes in size, dimensions must not exceed 512px, and either
/// width or height must be exactly 512px.
///
/// Pass [`InputFile::File`] to send a file that exists on the Telegram
/// servers (recommended), pass an [`InputFile::Url`] for Telegram to get a
/// .webp file from the Internet, or upload a new one using [`InputFile:
/// :FileId`]. [More info on Sending Files »].
/// - `emojis`: One or more emoji corresponding to the sticker.
///
/// [`InputFile::File`]: crate::types::InputFile::File
/// [`InputFile::Url`]: crate::types::InputFile::Url
/// [`InputFile::FileId`]: crate::types::InputFile::FileId
pub fn add_sticker_to_set<N, E>(
&self,
user_id: i32,
name: N,
png_sticker: InputFile,
sticker_type: StickerType,
emojis: E,
) -> AddStickerToSet
where
N: Into<String>,
E: Into<String>,
{
AddStickerToSet::new(self.clone(), user_id, name, png_sticker, emojis)
AddStickerToSet::new(self.clone(), user_id, name, sticker_type, emojis)
}
/// Use this method to move a sticker in a set created by the bot to a
@ -1501,4 +1476,55 @@ impl Bot {
{
SetChatAdministratorCustomTitle::new(self.clone(), chat_id, user_id, custom_title)
}
/// Use this method to send an animated emoji that will display a random
/// value.
///
/// [The official docs](https://core.telegram.org/bots/api#senddice).
///
/// # Params
/// - `chat_id`: Unique identifier for the target chat or username of the
/// target channel (in the format `@channelusername`).
pub fn send_dice<C>(&self, chat_id: C) -> SendDice
where
C: Into<ChatId>,
{
SendDice::new(self.clone(), chat_id)
}
/// Use this method to get the current list of the bot's commands.
///
/// [The official docs](https://core.telegram.org/bots/api#getmycommands).
pub fn get_my_commands(&self) -> GetMyCommands {
GetMyCommands::new(self.clone())
}
/// Use this method to change the list of the bot's commands.
///
/// [The official docs](https://core.telegram.org/bots/api#setmycommands).
///
/// # Params
/// - `commands`: A JSON-serialized list of bot commands to be set as the
/// list of the bot's commands. At most 100 commands can be specified.
pub fn set_my_commands<C>(&self, commands: C) -> SetMyCommands
where
C: Into<Vec<BotCommand>>,
{
SetMyCommands::new(self.clone(), commands)
}
/// Use this method to set the thumbnail of a sticker set. Animated
/// thumbnails can be set for animated sticker sets only.
///
/// [The official docs](https://core.telegram.org/bots/api#setstickersetthumb).
///
/// # Params
/// - `name`: Sticker set name.
/// - `user_id`: User identifier of the sticker set owner.
pub fn set_sticker_set_thumb<S>(&self, name: S, user_id: i32) -> SetStickerSetThumb
where
S: Into<String>,
{
SetStickerSetThumb::new(self.clone(), name, user_id)
}
}

View file

@ -30,25 +30,24 @@
//!
//! Since they implement [`DispatcherHandler`] too.
//!
//! # The ping-pong bot
//! This bot has a single handler of messages, which answers "pong" to each
//! incoming message:
//! # The dices bot
//! This bot throws a dice on each incoming message:
//!
//! ([Full](https://github.com/teloxide/teloxide/blob/master/examples/ping_pong_bot/src/main.rs))
//! ([Full](https://github.com/teloxide/teloxide/blob/master/examples/dices_bot/src/main.rs))
//! ```no_run
//! use teloxide::prelude::*;
//!
//! # #[tokio::main]
//! # async fn main_() {
//! teloxide::enable_logging!();
//! log::info!("Starting ping_pong_bot...");
//! log::info!("Starting dices_bot...");
//!
//! let bot = Bot::from_env();
//!
//! Dispatcher::new(bot)
//! .messages_handler(|rx: DispatcherHandlerRx<Message>| {
//! rx.for_each(|message| async move {
//! message.answer("pong").send().await.log_on_error().await;
//! message.send_dice().send().await.log_on_error().await;
//! })
//! })
//! .dispatch()
@ -58,7 +57,7 @@
//!
//! <div align="center">
//! <kbd>
//! <img src=https://github.com/teloxide/teloxide/raw/master/media/PING_PONG_BOT.gif />
//! <img src=https://github.com/teloxide/teloxide/raw/master/media/DICES_BOT.gif />
//! </kbd>
//! </div>
//!

View file

@ -2,9 +2,9 @@ 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,
Request, ResponseResult, SendAnimation, SendAudio, SendContact, SendDice, SendDocument,
SendLocation, SendMediaGroup, SendMessage, SendPhoto, SendSticker, SendVenue, SendVideo,
SendVideoNote, SendVoice,
},
types::{ChatId, ChatOrInlineMessage, InputFile, InputMedia, Message},
Bot,
@ -153,4 +153,8 @@ impl UpdateWithCx<Message> {
pub fn pin_message(&self) -> PinChatMessage {
self.bot.pin_chat_message(self.update.chat.id, self.update.id)
}
pub fn send_dice(&self) -> SendDice {
self.bot.send_dice(self.update.chat.id)
}
}

View file

@ -1,11 +1,14 @@
use crate::{
net,
requests::form_builder::FormBuilder,
types::{InputFile, MaskPosition, True},
types::{MaskPosition, True},
Bot,
};
use crate::requests::{RequestWithFile, ResponseResult};
use crate::{
requests::{RequestWithFile, ResponseResult},
types::StickerType,
};
/// Use this method to add a new sticker to a set created by the bot.
///
@ -15,7 +18,7 @@ pub struct AddStickerToSet {
bot: Bot,
user_id: i32,
name: String,
png_sticker: InputFile,
sticker_type: StickerType,
emojis: String,
mask_position: Option<MaskPosition>,
}
@ -25,18 +28,22 @@ impl RequestWithFile for AddStickerToSet {
type Output = True;
async fn send(&self) -> tokio::io::Result<ResponseResult<True>> {
let builder =
FormBuilder::new().add_text("user_id", &self.user_id).add_text("name", &self.name);
let builder = match &self.sticker_type {
StickerType::Png(file) => builder.add_input_file("png_sticker", &file),
StickerType::Tgs(file) => builder.add_input_file("tgs_sticker", &file),
}
.await?
.add_text("emojis", &self.emojis)
.add_text("mask_position", &self.mask_position);
Ok(net::request_multipart(
self.bot.client(),
self.bot.token(),
"addStickerToSet",
FormBuilder::new()
.add_text("user_id", &self.user_id)
.add_text("name", &self.name)
.add_input_file("png_sticker", &self.png_sticker)
.await?
.add_text("emojis", &self.emojis)
.add_text("mask_position", &self.mask_position)
.build(),
builder.build(),
)
.await)
}
@ -47,7 +54,7 @@ impl AddStickerToSet {
bot: Bot,
user_id: i32,
name: N,
png_sticker: InputFile,
sticker_type: StickerType,
emojis: E,
) -> Self
where
@ -58,7 +65,7 @@ impl AddStickerToSet {
bot,
user_id,
name: name.into(),
png_sticker,
sticker_type,
emojis: emojis.into(),
mask_position: None,
}
@ -79,20 +86,8 @@ impl AddStickerToSet {
self
}
/// **Png** image with the sticker, must be up to 512 kilobytes in size,
/// dimensions must not exceed 512px, and either width or height must be
/// exactly 512px.
///
/// Pass [`InputFile::File`] to send a file that exists on
/// the Telegram servers (recommended), pass an [`InputFile::Url`] for
/// Telegram to get a .webp file from the Internet, or upload a new one
/// using [`InputFile::FileId`]. [More info on Sending Files »].
///
/// [`InputFile::File`]: crate::types::InputFile::File
/// [`InputFile::Url`]: crate::types::InputFile::Url
/// [`InputFile::FileId`]: crate::types::InputFile::FileId
pub fn png_sticker(mut self, val: InputFile) -> Self {
self.png_sticker = val;
pub fn sticker_type(mut self, val: StickerType) -> Self {
self.sticker_type = val;
self
}

View file

@ -1,7 +1,7 @@
use crate::{
net,
requests::{form_builder::FormBuilder, RequestWithFile, ResponseResult},
types::{InputFile, MaskPosition, True},
types::{MaskPosition, StickerType, True},
Bot,
};
@ -15,7 +15,7 @@ pub struct CreateNewStickerSet {
user_id: i32,
name: String,
title: String,
png_sticker: InputFile,
sticker_type: StickerType,
emojis: String,
contains_masks: Option<bool>,
mask_position: Option<MaskPosition>,
@ -26,20 +26,25 @@ impl RequestWithFile for CreateNewStickerSet {
type Output = True;
async fn send(&self) -> tokio::io::Result<ResponseResult<True>> {
let builder = FormBuilder::new()
.add_text("user_id", &self.user_id)
.add_text("name", &self.name)
.add_text("title", &self.title);
let builder = match &self.sticker_type {
StickerType::Png(file) => builder.add_input_file("png_sticker", &file),
StickerType::Tgs(file) => builder.add_input_file("tgs_sticker", &file),
}
.await?
.add_text("emojis", &self.emojis)
.add_text("contains_masks", &self.contains_masks)
.add_text("mask_position", &self.mask_position);
Ok(net::request_multipart(
self.bot.client(),
self.bot.token(),
"createNewStickerSet",
FormBuilder::new()
.add_text("user_id", &self.user_id)
.add_text("name", &self.name)
.add_text("title", &self.title)
.add_input_file("png_sticker", &self.png_sticker)
.await?
.add_text("emojis", &self.emojis)
.add_text("contains_masks", &self.contains_masks)
.add_text("mask_position", &self.mask_position)
.build(),
builder.build(),
)
.await)
}
@ -51,7 +56,7 @@ impl CreateNewStickerSet {
user_id: i32,
name: N,
title: T,
png_sticker: InputFile,
sticker_type: StickerType,
emojis: E,
) -> Self
where
@ -64,7 +69,7 @@ impl CreateNewStickerSet {
user_id,
name: name.into(),
title: title.into(),
png_sticker,
sticker_type,
emojis: emojis.into(),
contains_masks: None,
mask_position: None,
@ -100,20 +105,8 @@ impl CreateNewStickerSet {
self
}
/// **Png** image with the sticker, must be up to 512 kilobytes in size,
/// dimensions must not exceed 512px, and either width or height must be
/// exactly 512px.
///
/// Pass [`InputFile::File`] to send a file that exists on
/// the Telegram servers (recommended), pass an [`InputFile::Url`] for
/// Telegram to get a .webp file from the Internet, or upload a new one
/// using [`InputFile::FileId`]. [More info on Sending Files »].
///
/// [`InputFile::File`]: crate::types::InputFile::File
/// [`InputFile::Url`]: crate::types::InputFile::Url
/// [`InputFile::FileId`]: crate::types::InputFile::FileId
pub fn png_sticker(mut self, val: InputFile) -> Self {
self.png_sticker = val;
pub fn sticker_type(mut self, val: StickerType) -> Self {
self.sticker_type = val;
self
}

View file

@ -0,0 +1,33 @@
use serde::Serialize;
use crate::{
net,
requests::{Request, ResponseResult},
types::BotCommand,
Bot,
};
/// Use this method to get the current list of the bot's commands.
///
/// [The official docs](https://core.telegram.org/bots/api#getmycommands).
#[serde_with_macros::skip_serializing_none]
#[derive(Debug, Clone, Serialize)]
pub struct GetMyCommands {
#[serde(skip_serializing)]
bot: Bot,
}
#[async_trait::async_trait]
impl Request for GetMyCommands {
type Output = Vec<BotCommand>;
async fn send(&self) -> ResponseResult<Self::Output> {
net::request_json(self.bot.client(), self.bot.token(), "getMyCommands", &self).await
}
}
impl GetMyCommands {
pub(crate) fn new(bot: Bot) -> Self {
Self { bot }
}
}

View file

@ -23,6 +23,7 @@ mod get_chat_members_count;
mod get_file;
mod get_game_high_scores;
mod get_me;
mod get_my_commands;
mod get_sticker_set;
mod get_updates;
mod get_user_profile_photos;
@ -36,6 +37,7 @@ mod send_animation;
mod send_audio;
mod send_chat_action;
mod send_contact;
mod send_dice;
mod send_document;
mod send_game;
mod send_invoice;
@ -56,7 +58,9 @@ mod set_chat_photo;
mod set_chat_sticker_set;
mod set_chat_title;
mod set_game_score;
mod set_my_commands;
mod set_sticker_position_in_set;
mod set_sticker_set_thumb;
mod set_webhook;
mod stop_message_live_location;
mod stop_poll;
@ -89,6 +93,7 @@ pub use get_chat_members_count::*;
pub use get_file::*;
pub use get_game_high_scores::*;
pub use get_me::*;
pub use get_my_commands::*;
pub use get_sticker_set::*;
pub use get_updates::*;
pub use get_user_profile_photos::*;
@ -102,6 +107,7 @@ pub use send_animation::*;
pub use send_audio::*;
pub use send_chat_action::*;
pub use send_contact::*;
pub use send_dice::*;
pub use send_document::*;
pub use send_game::*;
pub use send_invoice::*;
@ -122,7 +128,9 @@ pub use set_chat_photo::*;
pub use set_chat_sticker_set::*;
pub use set_chat_title::*;
pub use set_game_score::*;
pub use set_my_commands::*;
pub use set_sticker_position_in_set::*;
pub use set_sticker_set_thumb::*;
pub use set_webhook::*;
pub use std::pin::Pin;
pub use stop_message_live_location::*;

View file

@ -0,0 +1,94 @@
use serde::Serialize;
use crate::{
net,
requests::{Request, ResponseResult},
types::{ChatId, DiceEmoji, Message, ReplyMarkup},
Bot,
};
/// Use this method to send an animated emoji that will display a random value.
///
/// [The official docs](https://core.telegram.org/bots/api#senddice).
#[serde_with_macros::skip_serializing_none]
#[derive(Debug, Clone, Serialize)]
pub struct SendDice {
#[serde(skip_serializing)]
bot: Bot,
chat_id: ChatId,
#[serde(flatten)]
emoji: Option<DiceEmoji>,
disable_notification: Option<bool>,
reply_to_message_id: Option<i32>,
reply_markup: Option<ReplyMarkup>,
}
#[async_trait::async_trait]
impl Request for SendDice {
type Output = Message;
async fn send(&self) -> ResponseResult<Message> {
net::request_json(self.bot.client(), self.bot.token(), "sendDice", &self).await
}
}
impl SendDice {
pub(crate) fn new<C>(bot: Bot, chat_id: C) -> Self
where
C: Into<ChatId>,
{
Self {
bot,
chat_id: chat_id.into(),
emoji: None,
disable_notification: None,
reply_to_message_id: None,
reply_markup: None,
}
}
/// Unique identifier for the target chat or username of the target channel
/// (in the format `@channelusername`).
pub fn chat_id<T>(mut self, value: T) -> Self
where
T: Into<ChatId>,
{
self.chat_id = value.into();
self
}
/// Emoji on which the dice throw animation is based.
pub fn emoji(mut self, val: DiceEmoji) -> Self {
self.emoji = Some(val);
self
}
/// Sends the message [silently]. Users will receive a notification with no
/// sound.
///
/// [silently]: https://telegram.org/blog/channels-2-0#silent-messages
pub fn disable_notification(mut self, value: bool) -> Self {
self.disable_notification = Some(value);
self
}
/// If the message is a reply, ID of the original message.
pub fn reply_to_message_id(mut self, value: i32) -> Self {
self.reply_to_message_id = Some(value);
self
}
/// Additional interface options.
///
/// A JSON-serialized object for an [inline keyboard], [custom reply
/// keyboard], instructions to remove reply keyboard or to force a reply
/// from the user.
///
/// [inline keyboard]: https://core.telegram.org/bots#inline-keyboards-and-on-the-fly-updating
/// [custom reply keyboard]: https://core.telegram.org/bots#keyboards
pub fn reply_markup(mut self, val: ReplyMarkup) -> Self {
self.reply_markup = Some(val);
self
}
}

View file

@ -0,0 +1,50 @@
use serde::Serialize;
use crate::{
net,
requests::{Request, ResponseResult},
types::{BotCommand, True},
Bot,
};
/// Use this method to change the list of the bot's commands.
///
/// [The official docs](https://core.telegram.org/bots/api#setmycommands).
#[serde_with_macros::skip_serializing_none]
#[derive(Debug, Clone, Serialize)]
pub struct SetMyCommands {
#[serde(skip_serializing)]
bot: Bot,
commands: Vec<BotCommand>,
}
#[async_trait::async_trait]
impl Request for SetMyCommands {
type Output = True;
async fn send(&self) -> ResponseResult<Self::Output> {
net::request_json(self.bot.client(), self.bot.token(), "setMyCommands", &self).await
}
}
impl SetMyCommands {
pub(crate) fn new<C>(bot: Bot, commands: C) -> Self
where
C: Into<Vec<BotCommand>>,
{
Self { bot, commands: commands.into() }
}
/// A JSON-serialized list of bot commands to be set as the list of the
/// bot's commands.
///
/// At most 100 commands can be specified.
pub fn commands<C>(mut self, commands: C) -> Self
where
C: Into<Vec<BotCommand>>,
{
self.commands = commands.into();
self
}
}

View file

@ -0,0 +1,73 @@
use serde::Serialize;
use crate::{
net,
requests::{Request, ResponseResult},
types::{InputFile, True},
Bot,
};
/// Use this method to set the thumbnail of a sticker set. Animated thumbnails
/// can be set for animated sticker sets only.
///
/// [The official docs](https://core.telegram.org/bots/api#setstickersetthumb).
#[serde_with_macros::skip_serializing_none]
#[derive(Debug, Clone, Serialize)]
pub struct SetStickerSetThumb {
#[serde(skip_serializing)]
bot: Bot,
name: String,
user_id: i32,
thumb: Option<InputFile>,
}
#[async_trait::async_trait]
impl Request for SetStickerSetThumb {
type Output = True;
async fn send(&self) -> ResponseResult<Self::Output> {
net::request_json(self.bot.client(), self.bot.token(), "setStickerSetThumb", &self).await
}
}
impl SetStickerSetThumb {
pub(crate) fn new<S>(bot: Bot, name: S, user_id: i32) -> Self
where
S: Into<String>,
{
Self { bot, name: name.into(), user_id, thumb: None }
}
/// Sticker set name.
pub fn name<T>(mut self, val: T) -> Self
where
T: Into<String>,
{
self.name = val.into();
self
}
/// User identifier of the sticker set owner.
pub fn user_id(mut self, val: i32) -> Self {
self.user_id = val;
self
}
/// A PNG image with the thumbnail, must be up to 128 kilobytes in size and
/// have width and height exactly 100px, or a TGS animation with the
/// thumbnail up to 32 kilobytes in size; see https://core.telegram.org/animated_stickers#technical-requirements
/// for animated sticker technical requirements.
///
/// Pass [`InputFile::FileId`] as a String to send a file that already
/// exists on the Telegram servers, pass [`InputFile::Url`] for Telegram
/// to get a file from the Internet, or upload a new one using
/// multipart/form-data. More info on Sending Files ». Animated sticker
/// set thumbnail can't be uploaded via HTTP URL.
///
/// [`InputFile::FileId`]: crate::types::InputFile::FileId
/// [`InputFile::Url]: crate::types::InputFile::Url
pub fn thumb(mut self, val: InputFile) -> Self {
self.thumb = Some(val);
self
}
}

42
src/types/bot_command.rs Normal file
View file

@ -0,0 +1,42 @@
use serde::{Deserialize, Serialize};
/// This object represents a bot command.
///
/// [The official docs](https://core.telegram.org/bots/api#botcommand).
#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
#[non_exhaustive]
pub struct BotCommand {
/// Text of the command, 1-32 characters.
///
/// Can contain only lowercase English letters, digits and underscores.
pub command: String,
/// Description of the command, 3-256 characters.
pub description: String,
}
impl BotCommand {
pub fn new<S1, S2>(command: S1, description: S2) -> Self
where
S1: Into<String>,
S2: Into<String>,
{
Self { command: command.into(), description: description.into() }
}
pub fn command<S>(mut self, val: S) -> Self
where
S: Into<String>,
{
self.command = val.into();
self
}
pub fn description<S>(mut self, val: S) -> Self
where
S: Into<String>,
{
self.description = val.into();
self
}
}

38
src/types/dice.rs Normal file
View file

@ -0,0 +1,38 @@
use serde::{Deserialize, Serialize};
use crate::types::DiceEmoji;
/// This object represents an animated emoji that displays a random value.
#[serde_with_macros::skip_serializing_none]
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[non_exhaustive]
pub struct Dice {
/// Emoji on which the dice throw animation is based.
emoji: DiceEmoji,
/// Value of the dice.
///
/// 1-6 for [`DiceEmoji::Dice`] and [`DiceEmoji::Darts`], 1-5 for
/// [`DiceEmoji::Basketball`].
///
/// [`DiceEmoji::Dice`]: crate::types::DiceEmoji::Dice
/// [`DiceEmoji::Darts`]:crate::types::DiceEmoji::Darts
/// [`DiceEmoji::Basketball`]:crate::types::DiceEmoji::Basketball
value: i32,
}
impl Dice {
pub fn new(emoji: DiceEmoji, value: i32) -> Self {
Self { emoji, value }
}
pub fn emoji(mut self, val: DiceEmoji) -> Self {
self.emoji = val;
self
}
pub fn value<S>(mut self, val: i32) -> Self {
self.value = val;
self
}
}

16
src/types/dice_emoji.rs Normal file
View file

@ -0,0 +1,16 @@
use serde::{Deserialize, Serialize};
#[derive(Copy, Debug, Clone, PartialEq, Eq, Hash, Deserialize, Serialize)]
pub enum DiceEmoji {
/// Values from 1-6. Defaults to this variant.
#[serde(rename = "🎲")]
Dice,
/// Values from 1-6.
#[serde(rename = "🎯")]
Darts,
/// Values from 1-5.
#[serde(rename = "🏀")]
Basketball,
}

View file

@ -4,8 +4,8 @@ use serde::{Deserialize, Serialize};
use crate::types::{
chat::{ChatKind, PublicChatKind},
Animation, Audio, Chat, ChatPublic, Contact, Document, Game, InlineKeyboardMarkup, Invoice,
Location, MessageEntity, PassportData, PhotoSize, Poll, PublicChatChannel,
Animation, Audio, Chat, ChatPublic, Contact, Dice, Document, Game, InlineKeyboardMarkup,
Invoice, Location, MessageEntity, PassportData, PhotoSize, Poll, PublicChatChannel,
PublicChatSupergroup, Sticker, SuccessfulPayment, True, User, Venue, Video, VideoNote, Voice,
};
@ -74,6 +74,7 @@ pub enum MessageKind {
SuccessfulPayment(MessageSuccessfulPayment),
ConnectedWebsite(MessageConnectedWebsite),
PassportData(MessagePassportData),
Dice(MessageDice),
}
#[serde_with_macros::skip_serializing_none]
@ -1048,6 +1049,13 @@ impl MediaVenue {
}
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[non_exhaustive]
pub struct MessageDice {
/// Message is a dice with random value from 1 to 6.
dice: Dice,
}
mod getters {
use std::ops::Deref;

View file

@ -3,6 +3,7 @@
pub use allowed_update::*;
pub use animation::*;
pub use audio::*;
pub use bot_command::*;
pub use callback_game::*;
pub use callback_query::*;
pub use chat::*;
@ -14,6 +15,8 @@ pub use chat_permissions::*;
pub use chat_photo::*;
pub use chosen_inline_result::*;
pub use contact::*;
pub use dice::*;
pub use dice_emoji::*;
pub use document::*;
pub use encrypted_credentials::*;
pub use encrypted_passport_element::*;
@ -78,6 +81,7 @@ pub use shipping_option::*;
pub use shipping_query::*;
pub use sticker::*;
pub use sticker_set::*;
pub use sticker_type::*;
pub use successful_payment::*;
pub use unit_false::*;
pub use unit_true::*;
@ -93,6 +97,7 @@ pub use webhook_info::*;
mod allowed_update;
mod animation;
mod audio;
mod bot_command;
mod callback_game;
mod callback_query;
mod chat;
@ -104,6 +109,8 @@ mod chat_permissions;
mod chat_photo;
mod chosen_inline_result;
mod contact;
mod dice;
mod dice_emoji;
mod document;
mod file;
mod force_reply;
@ -141,6 +148,7 @@ mod shipping_option;
mod shipping_query;
mod sticker;
mod sticker_set;
mod sticker_type;
mod successful_payment;
mod unit_false;
mod unit_true;

View file

@ -1,6 +1,6 @@
use serde::{Deserialize, Serialize};
use crate::types::Sticker;
use crate::types::{PhotoSize, Sticker};
/// This object represents a sticker set.
///
@ -24,6 +24,9 @@ pub struct StickerSet {
/// List of all set stickers.
pub stickers: Vec<Sticker>,
/// Sticker set thumbnail in the .WEBP or .TGS format.
thumb: Option<PhotoSize>,
}
impl StickerSet {
@ -45,6 +48,7 @@ impl StickerSet {
is_animated,
contains_masks,
stickers: stickers.into(),
thumb: None,
}
}

26
src/types/sticker_type.rs Normal file
View file

@ -0,0 +1,26 @@
use crate::types::InputFile;
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
#[non_exhaustive]
pub enum StickerType {
/// PNG image with the sticker, must be up to 512 kilobytes in size,
/// dimensions must not exceed 512px, and either width or height must be
/// exactly 512px.
///
/// Pass [`InputFile::File`] to send a file that exists on
/// the Telegram servers (recommended), pass an [`InputFile::Url`] for
/// Telegram to get a .webp file from the Internet, or upload a new one
/// using [`InputFile::FileId`]. [More info on Sending Files »].
///
/// [`InputFile::File`]: crate::types::InputFile::File
/// [`InputFile::Url`]: crate::types::InputFile::Url
/// [`InputFile::FileId`]: crate::types::InputFile::FileId
///
/// [More info on Sending Files »]: https://core.telegram.org/bots/api#sending-files
Png(InputFile),
/// TGS animation with the sticker, uploaded using multipart/form-data.
///
/// See https://core.telegram.org/animated_stickers#technical-requirements for technical requirements
Tgs(InputFile),
}

View file

@ -285,4 +285,36 @@ mod test {
serde_json::from_str::<Update>(json).unwrap();
}
#[test]
fn dice_works() {
let json = r#"
{
"message": {
"chat": {
"id": -1001276785818,
"title": "bla bla bla chat",
"type": "supergroup",
"username": "teloxide_dev"
},
"date": 1596014550,
"dice": {
"emoji": "🎲",
"value": 2
},
"from": {
"first_name": "Hirrolot",
"id": 408258968,
"is_bot": false,
"language_code": "en",
"username": "hirrolot"
},
"message_id": 35410
},
"update_id": 573255266
}
"#;
serde_json::from_str::<Update>(json).unwrap();
}
}