From fd31cba6d73899d969debd26694cf0845a907e5d Mon Sep 17 00:00:00 2001 From: Hirrolot Date: Sun, 24 Apr 2022 23:30:22 +0600 Subject: [PATCH 1/5] Restrict all purchase bot's commands by `State::Start` --- examples/purchase.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/examples/purchase.rs b/examples/purchase.rs index 50201fec..ea81b303 100644 --- a/examples/purchase.rs +++ b/examples/purchase.rs @@ -56,8 +56,12 @@ async fn main() { dialogue::enter::, State, _>() .branch( Update::filter_message() + .branch( + teloxide::handler![State::Start] + .filter_command::() + .endpoint(handle_command), + ) .branch(teloxide::handler![State::ReceiveFullName].endpoint(receive_full_name)) - .branch(dptree::entry().filter_command::().endpoint(handle_command)) .branch(dptree::endpoint(invalid_state)), ) .branch( From c3d5ed9fb70ec8cc5fd670504ef0d711257cdc86 Mon Sep 17 00:00:00 2001 From: Hirrolot Date: Mon, 25 Apr 2022 01:23:05 +0600 Subject: [PATCH 2/5] Use `teloxide::handler!` for command handling too --- examples/purchase.rs | 51 ++++++++++++++++++++++++-------------------- 1 file changed, 28 insertions(+), 23 deletions(-) diff --git a/examples/purchase.rs b/examples/purchase.rs index ea81b303..034441bf 100644 --- a/examples/purchase.rs +++ b/examples/purchase.rs @@ -42,6 +42,8 @@ enum Command { Help, #[command(description = "start the purchase procedure.")] Start, + #[command(description = "cancel the purchase procedure.")] + Cancel, } #[tokio::main] @@ -57,9 +59,14 @@ async fn main() { .branch( Update::filter_message() .branch( - teloxide::handler![State::Start] + dptree::entry() .filter_command::() - .endpoint(handle_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)), ) .branch(teloxide::handler![State::ReceiveFullName].endpoint(receive_full_name)) .branch(dptree::endpoint(invalid_state)), @@ -78,22 +85,26 @@ async fn main() { .await; } -async fn handle_command( - bot: AutoSend, - msg: Message, - cmd: Command, - 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 start(bot: AutoSend, msg: Message, dialogue: MyDialogue) -> HandlerResult { + bot.send_message(msg.chat.id, "Let's start! What's your full name?").await?; + dialogue.update(State::ReceiveFullName).await?; + Ok(()) +} +async fn help(bot: AutoSend, msg: Message) -> HandlerResult { + bot.send_message(msg.chat.id, Command::descriptions().to_string()).await?; + Ok(()) +} + +async fn cancel(bot: AutoSend, 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, msg: Message) -> HandlerResult { + bot.send_message(msg.chat.id, "Unable to handle the message. Type /help to see the usage.") + .await?; Ok(()) } @@ -138,9 +149,3 @@ async fn receive_product_selection( Ok(()) } - -async fn invalid_state(bot: AutoSend, msg: Message) -> HandlerResult { - bot.send_message(msg.chat.id, "Unable to handle the message. Type /help to see the usage.") - .await?; - Ok(()) -} From f555d1d2d3ea28b23cebe60a372e425b13b5904f Mon Sep 17 00:00:00 2001 From: Hirrolot Date: Mon, 25 Apr 2022 01:30:01 +0600 Subject: [PATCH 3/5] Prettify `examples/purchase.rs` by a separate command handler --- examples/purchase.rs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/examples/purchase.rs b/examples/purchase.rs index 034441bf..621a6bf3 100644 --- a/examples/purchase.rs +++ b/examples/purchase.rs @@ -53,21 +53,21 @@ async fn main() { let bot = Bot::from_env().auto_send(); + let command_handler = dptree::entry() + .filter_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)); + Dispatcher::builder( bot, dialogue::enter::, State, _>() .branch( Update::filter_message() - .branch( - dptree::entry() - .filter_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)), - ) + .branch(command_handler) .branch(teloxide::handler![State::ReceiveFullName].endpoint(receive_full_name)) .branch(dptree::endpoint(invalid_state)), ) From 52678b187cbe1f4962c9253e7ec3cf5da6e06d6e Mon Sep 17 00:00:00 2001 From: Hirrolot Date: Mon, 25 Apr 2022 01:38:55 +0600 Subject: [PATCH 4/5] Simplify `InlineKeyboardButton` construction --- examples/purchase.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/purchase.rs b/examples/purchase.rs index 621a6bf3..72088c10 100644 --- a/examples/purchase.rs +++ b/examples/purchase.rs @@ -115,13 +115,13 @@ async fn receive_full_name( ) -> HandlerResult { match msg.text().map(ToOwned::to_owned) { Some(full_name) => { - let products = InlineKeyboardMarkup::default().append_row( - vec!["Apple", "Banana", "Orange", "Potato"].into_iter().map(|product| { - InlineKeyboardButton::callback(product.to_owned(), product.to_owned()) - }), - ); + let products = ["Apple", "Banana", "Orange", "Potato"].map(|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?; } None => { From 4ad7dfac49f7888262a03892b271ccdbb9e85838 Mon Sep 17 00:00:00 2001 From: Hirrolot Date: Mon, 25 Apr 2022 01:46:03 +0600 Subject: [PATCH 5/5] Update the docs of `teloxide::handler!` --- src/dispatching/dialogue/mod.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/dispatching/dialogue/mod.rs b/src/dispatching/dialogue/mod.rs index 98f2887d..c558d991 100644 --- a/src/dispatching/dialogue/mod.rs +++ b/src/dispatching/dialogue/mod.rs @@ -214,11 +214,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 -/// state: if the state enumeration is of a certain variant, the execution -/// continues; otherwise, `dptree` will try the next branch. +/// This macro expands to a [`dptree::Handler`] that acts on your enumeration +/// type: if the enumeration is of a certain variant, the execution continues; +/// 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: /// @@ -243,6 +245,8 @@ where /// ## Dependency requirements /// /// - Your dialogue state enumeration `State`. +/// +/// [`examples/purchase.rs`]: https://github.com/teloxide/teloxide/blob/master/examples/purchase.rs #[macro_export] macro_rules! handler { ($($variant:ident)::+) => {