mirror of
https://github.com/teloxide/teloxide.git
synced 2025-01-05 10:24:32 +01:00
Merge branch 'dev' into master-copy
This commit is contained in:
commit
6c5bb1932d
8 changed files with 105 additions and 60 deletions
10
CHANGELOG.md
10
CHANGELOG.md
|
@ -6,6 +6,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
|
|
||||||
## unreleased
|
## unreleased
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- The `dispatching::filter_command` function (also accessible as `teloxide::filter_command`) as a shortcut for `dptree::entry().filter_command()`.
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Update teloxide-core to v0.6.0 with [Bot API 6.0] support [**BC**].
|
||||||
|
|
||||||
|
[Bot API 6.0]: https://core.telegram.org/bots/api#april-16-2022
|
||||||
|
|
||||||
## 0.8.2 - 2022-04-26
|
## 0.8.2 - 2022-04-26
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
|
@ -56,7 +56,7 @@ full = [
|
||||||
]
|
]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
teloxide-core = { version = "0.5.1", default-features = false }
|
teloxide-core = { version = "0.6.0", default-features = false }
|
||||||
teloxide-macros = { version = "0.6.1", optional = true }
|
teloxide-macros = { version = "0.6.1", optional = true }
|
||||||
|
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
|
|
|
@ -363,6 +363,7 @@ Feel free to propose your own bot to our collection!
|
||||||
- [wa7sa34cx/the-black-box-bot](https://github.com/wa7sa34cx/the-black-box-bot) -- This is the Black Box Telegram bot. You can hold any items in it.
|
- [wa7sa34cx/the-black-box-bot](https://github.com/wa7sa34cx/the-black-box-bot) -- This is the Black Box Telegram bot. You can hold any items in it.
|
||||||
- [crapstone/hsctt](https://codeberg.org/crapstones-bots/hsctt) -- A Telegram bot that searches for HTTP status codes in all messages and replies with the text form.
|
- [crapstone/hsctt](https://codeberg.org/crapstones-bots/hsctt) -- A Telegram bot that searches for HTTP status codes in all messages and replies with the text form.
|
||||||
- [alenpaul2001/AurSearchBot](https://gitlab.com/alenpaul2001/aursearchbot) -- Telegram bot for searching AUR in inline mode.
|
- [alenpaul2001/AurSearchBot](https://gitlab.com/alenpaul2001/aursearchbot) -- Telegram bot for searching AUR in inline mode.
|
||||||
|
- [studiedlist/EddieBot](https://gitlab.com/studiedlist/eddie-bot) -- Chatting bot with several entertainment features
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
// ```
|
// ```
|
||||||
|
|
||||||
use teloxide::{
|
use teloxide::{
|
||||||
dispatching::dialogue::{self, GetChatId, InMemStorage},
|
dispatching::dialogue::{self, InMemStorage},
|
||||||
prelude::*,
|
prelude::*,
|
||||||
types::{InlineKeyboardButton, InlineKeyboardMarkup},
|
types::{InlineKeyboardButton, InlineKeyboardMarkup},
|
||||||
utils::command::BotCommands,
|
utils::command::BotCommands,
|
||||||
|
@ -42,30 +42,40 @@ enum Command {
|
||||||
Help,
|
Help,
|
||||||
#[command(description = "start the purchase procedure.")]
|
#[command(description = "start the purchase procedure.")]
|
||||||
Start,
|
Start,
|
||||||
|
#[command(description = "cancel the purchase procedure.")]
|
||||||
|
Cancel,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() {
|
async fn main() {
|
||||||
pretty_env_logger::init();
|
pretty_env_logger::init();
|
||||||
log::info!("Starting dialogue_bot...");
|
log::info!("Starting purchase bot...");
|
||||||
|
|
||||||
let bot = Bot::from_env().auto_send();
|
let bot = Bot::from_env().auto_send();
|
||||||
|
|
||||||
|
let command_handler = teloxide::filter_command::<Command, _>()
|
||||||
|
.branch(
|
||||||
|
teloxide::handler![State::Start]
|
||||||
|
.branch(teloxide::handler![Command::Help].endpoint(help))
|
||||||
|
.branch(teloxide::handler![Command::Start].endpoint(start)),
|
||||||
|
)
|
||||||
|
.branch(teloxide::handler![Command::Cancel].endpoint(cancel));
|
||||||
|
|
||||||
|
let message_handler = Update::filter_message()
|
||||||
|
.branch(command_handler)
|
||||||
|
.branch(teloxide::handler![State::ReceiveFullName].endpoint(receive_full_name))
|
||||||
|
.branch(dptree::endpoint(invalid_state));
|
||||||
|
|
||||||
|
let callback_query_handler = Update::filter_callback_query().chain(
|
||||||
|
teloxide::handler![State::ReceiveProductChoice { full_name }]
|
||||||
|
.endpoint(receive_product_selection),
|
||||||
|
);
|
||||||
|
|
||||||
Dispatcher::builder(
|
Dispatcher::builder(
|
||||||
bot,
|
bot,
|
||||||
dialogue::enter::<Update, InMemStorage<State>, State, _>()
|
dialogue::enter::<Update, InMemStorage<State>, State, _>()
|
||||||
.branch(
|
.branch(message_handler)
|
||||||
Update::filter_message()
|
.branch(callback_query_handler),
|
||||||
.branch(teloxide::handler![State::ReceiveFullName].endpoint(receive_full_name))
|
|
||||||
.branch(dptree::entry().filter_command::<Command>().endpoint(handle_command))
|
|
||||||
.branch(dptree::endpoint(invalid_state)),
|
|
||||||
)
|
|
||||||
.branch(
|
|
||||||
Update::filter_callback_query().chain(
|
|
||||||
teloxide::handler![State::ReceiveProductChoice { full_name }]
|
|
||||||
.endpoint(receive_product_selection),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
.dependencies(dptree::deps![InMemStorage::<State>::new()])
|
.dependencies(dptree::deps![InMemStorage::<State>::new()])
|
||||||
.build()
|
.build()
|
||||||
|
@ -74,22 +84,26 @@ async fn main() {
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn handle_command(
|
async fn start(bot: AutoSend<Bot>, msg: Message, dialogue: MyDialogue) -> HandlerResult {
|
||||||
bot: AutoSend<Bot>,
|
bot.send_message(msg.chat.id, "Let's start! What's your full name?").await?;
|
||||||
msg: Message,
|
dialogue.update(State::ReceiveFullName).await?;
|
||||||
cmd: Command,
|
Ok(())
|
||||||
dialogue: MyDialogue,
|
}
|
||||||
) -> HandlerResult {
|
|
||||||
match cmd {
|
|
||||||
Command::Help => {
|
|
||||||
bot.send_message(msg.chat.id, Command::descriptions().to_string()).await?;
|
|
||||||
}
|
|
||||||
Command::Start => {
|
|
||||||
bot.send_message(msg.chat.id, "Let's start! What's your full name?").await?;
|
|
||||||
dialogue.update(State::ReceiveFullName).await?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
async fn help(bot: AutoSend<Bot>, msg: Message) -> HandlerResult {
|
||||||
|
bot.send_message(msg.chat.id, Command::descriptions().to_string()).await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn cancel(bot: AutoSend<Bot>, msg: Message, dialogue: MyDialogue) -> HandlerResult {
|
||||||
|
bot.send_message(msg.chat.id, "Cancelling the dialogue.").await?;
|
||||||
|
dialogue.exit().await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn invalid_state(bot: AutoSend<Bot>, msg: Message) -> HandlerResult {
|
||||||
|
bot.send_message(msg.chat.id, "Unable to handle the message. Type /help to see the usage.")
|
||||||
|
.await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,13 +114,12 @@ async fn receive_full_name(
|
||||||
) -> HandlerResult {
|
) -> HandlerResult {
|
||||||
match msg.text().map(ToOwned::to_owned) {
|
match msg.text().map(ToOwned::to_owned) {
|
||||||
Some(full_name) => {
|
Some(full_name) => {
|
||||||
let products = InlineKeyboardMarkup::default().append_row(
|
let products = ["Apple", "Banana", "Orange", "Potato"]
|
||||||
vec!["Apple", "Banana", "Orange", "Potato"].into_iter().map(|product| {
|
.map(|product| InlineKeyboardButton::callback(product, product));
|
||||||
InlineKeyboardButton::callback(product.to_owned(), product.to_owned())
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
bot.send_message(msg.chat.id, "Select a product:").reply_markup(products).await?;
|
bot.send_message(msg.chat.id, "Select a product:")
|
||||||
|
.reply_markup(InlineKeyboardMarkup::new([products]))
|
||||||
|
.await?;
|
||||||
dialogue.update(State::ReceiveProductChoice { full_name }).await?;
|
dialogue.update(State::ReceiveProductChoice { full_name }).await?;
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
|
@ -124,21 +137,13 @@ async fn receive_product_selection(
|
||||||
full_name: String,
|
full_name: String,
|
||||||
) -> HandlerResult {
|
) -> HandlerResult {
|
||||||
if let Some(product) = &q.data {
|
if let Some(product) = &q.data {
|
||||||
if let Some(chat_id) = q.chat_id() {
|
bot.send_message(
|
||||||
bot.send_message(
|
dialogue.chat_id(),
|
||||||
chat_id,
|
format!("{full_name}, product '{product}' has been purchased successfully!"),
|
||||||
format!("{full_name}, product '{product}' has been purchased successfully!"),
|
)
|
||||||
)
|
.await?;
|
||||||
.await?;
|
dialogue.exit().await?;
|
||||||
dialogue.exit().await?;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn invalid_state(bot: AutoSend<Bot>, msg: Message) -> HandlerResult {
|
|
||||||
bot.send_message(msg.chat.id, "Unable to handle the message. Type /help to see the usage.")
|
|
||||||
.await?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
|
@ -189,6 +189,11 @@ where
|
||||||
///
|
///
|
||||||
/// See [`HandlerExt::enter_dialogue`].
|
/// See [`HandlerExt::enter_dialogue`].
|
||||||
///
|
///
|
||||||
|
/// ## Dependency requirements
|
||||||
|
///
|
||||||
|
/// - `Arc<S>`
|
||||||
|
/// - `Upd`
|
||||||
|
///
|
||||||
/// [`HandlerExt::enter_dialogue`]: super::HandlerExt::enter_dialogue
|
/// [`HandlerExt::enter_dialogue`]: super::HandlerExt::enter_dialogue
|
||||||
pub fn enter<Upd, S, D, Output>() -> Handler<'static, DependencyMap, Output, DpHandlerDescription>
|
pub fn enter<Upd, S, D, Output>() -> Handler<'static, DependencyMap, Output, DpHandlerDescription>
|
||||||
where
|
where
|
||||||
|
@ -214,11 +219,13 @@ where
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Perform a dialogue FSM transition.
|
/// Filters an enumeration, passing its payload forwards.
|
||||||
///
|
///
|
||||||
/// This macro expands to a [`dptree::Handler`] that filters your dialogue
|
/// This macro expands to a [`dptree::Handler`] that acts on your enumeration
|
||||||
/// state: if the state enumeration is of a certain variant, the execution
|
/// type: if the enumeration is of a certain variant, the execution continues;
|
||||||
/// continues; otherwise, `dptree` will try the next branch.
|
/// otherwise, `dptree` will try the next branch. This is very useful for
|
||||||
|
/// dialogue FSM transitions and Telegram command filtering; for a complete
|
||||||
|
/// example, please see [`examples/purchase.rs`].
|
||||||
///
|
///
|
||||||
/// Variants can take the following forms:
|
/// Variants can take the following forms:
|
||||||
///
|
///
|
||||||
|
@ -243,6 +250,8 @@ where
|
||||||
/// ## Dependency requirements
|
/// ## Dependency requirements
|
||||||
///
|
///
|
||||||
/// - Your dialogue state enumeration `State`.
|
/// - Your dialogue state enumeration `State`.
|
||||||
|
///
|
||||||
|
/// [`examples/purchase.rs`]: https://github.com/teloxide/teloxide/blob/master/examples/purchase.rs
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! handler {
|
macro_rules! handler {
|
||||||
($($variant:ident)::+) => {
|
($($variant:ident)::+) => {
|
||||||
|
|
|
@ -42,7 +42,8 @@ pub trait HandlerExt<Output> {
|
||||||
/// - `Arc<S>`
|
/// - `Arc<S>`
|
||||||
/// - `Upd`
|
/// - `Upd`
|
||||||
///
|
///
|
||||||
/// [`Dialogue<D, S>`]: Dialogue
|
/// [`Dialogue<D, S>`]: super::dialogue::Dialogue
|
||||||
|
/// [`Dialogue::get_or_default`]: super::dialogue::Dialogue::get_or_default
|
||||||
#[must_use]
|
#[must_use]
|
||||||
fn enter_dialogue<Upd, S, D>(self) -> Self
|
fn enter_dialogue<Upd, S, D>(self) -> Self
|
||||||
where
|
where
|
||||||
|
@ -67,10 +68,7 @@ where
|
||||||
where
|
where
|
||||||
C: BotCommands + Send + Sync + 'static,
|
C: BotCommands + Send + Sync + 'static,
|
||||||
{
|
{
|
||||||
self.chain(dptree::filter_map(move |message: Message, me: Me| {
|
self.chain(filter_command::<C, Output>())
|
||||||
let bot_name = me.user.username.expect("Bots must have a username");
|
|
||||||
message.text().and_then(|text| C::parse(text, bot_name).ok())
|
|
||||||
}))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn enter_dialogue<Upd, S, D>(self) -> Self
|
fn enter_dialogue<Upd, S, D>(self) -> Self
|
||||||
|
@ -91,3 +89,24 @@ where
|
||||||
self.chain(F::handler())
|
self.chain(F::handler())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns a handler that accepts a parsed command `C`.
|
||||||
|
///
|
||||||
|
/// A call to this function is the same as `dptree::entry().filter_command()`.
|
||||||
|
///
|
||||||
|
/// See [`HandlerExt::filter_command`].
|
||||||
|
///
|
||||||
|
/// ## Dependency requirements
|
||||||
|
///
|
||||||
|
/// - [`crate::types::Message`]
|
||||||
|
/// - [`crate::types::Me`]
|
||||||
|
pub fn filter_command<C, Output>() -> Handler<'static, DependencyMap, Output, DpHandlerDescription>
|
||||||
|
where
|
||||||
|
C: BotCommands + Send + Sync + 'static,
|
||||||
|
Output: Send + Sync + 'static,
|
||||||
|
{
|
||||||
|
dptree::entry().chain(dptree::filter_map(move |message: Message, me: Me| {
|
||||||
|
let bot_name = me.user.username.expect("Bots must have a username");
|
||||||
|
message.text().and_then(|text| C::parse(text, bot_name).ok())
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
|
@ -113,6 +113,6 @@ pub use dispatcher::{Dispatcher, DispatcherBuilder, UpdateHandler};
|
||||||
pub use distribution::DefaultKey;
|
pub use distribution::DefaultKey;
|
||||||
pub use filter_ext::{MessageFilterExt, UpdateFilterExt};
|
pub use filter_ext::{MessageFilterExt, UpdateFilterExt};
|
||||||
pub use handler_description::DpHandlerDescription;
|
pub use handler_description::DpHandlerDescription;
|
||||||
pub use handler_ext::HandlerExt;
|
pub use handler_ext::{filter_command, HandlerExt};
|
||||||
#[allow(deprecated)]
|
#[allow(deprecated)]
|
||||||
pub use handler_factory::HandlerFactory;
|
pub use handler_factory::HandlerFactory;
|
||||||
|
|
|
@ -79,6 +79,7 @@ pub use teloxide_core::*;
|
||||||
#[cfg(feature = "macros")]
|
#[cfg(feature = "macros")]
|
||||||
pub use teloxide_macros as macros;
|
pub use teloxide_macros as macros;
|
||||||
|
|
||||||
|
pub use dispatching::filter_command;
|
||||||
pub use dptree;
|
pub use dptree;
|
||||||
|
|
||||||
#[cfg(all(feature = "nightly", doctest))]
|
#[cfg(all(feature = "nightly", doctest))]
|
||||||
|
|
Loading…
Reference in a new issue