diff --git a/CHANGELOG.md b/CHANGELOG.md index 3b993d45..deae0c9a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Add `filter_boost_added` and `filter_reply_to_story` filters to `MessageFilterExt` trait +- Add `filter_mention_command` filter to `HandlerExt` trait ([issue #494](https://github.com/teloxide/teloxide/issues/494)) ## 0.13.0 - 2024-08-16 diff --git a/crates/teloxide/src/dispatching.rs b/crates/teloxide/src/dispatching.rs index 1caa197b..1d16b35a 100644 --- a/crates/teloxide/src/dispatching.rs +++ b/crates/teloxide/src/dispatching.rs @@ -227,4 +227,4 @@ pub use dispatcher::{Dispatcher, DispatcherBuilder, UpdateHandler}; pub use distribution::DefaultKey; pub use filter_ext::{MessageFilterExt, UpdateFilterExt}; pub use handler_description::DpHandlerDescription; -pub use handler_ext::{filter_command, HandlerExt}; +pub use handler_ext::{filter_command, filter_mention_command, HandlerExt}; diff --git a/crates/teloxide/src/dispatching/handler_ext.rs b/crates/teloxide/src/dispatching/handler_ext.rs index f5f3236d..df808e29 100644 --- a/crates/teloxide/src/dispatching/handler_ext.rs +++ b/crates/teloxide/src/dispatching/handler_ext.rs @@ -23,6 +23,18 @@ pub trait HandlerExt { where C: BotCommands + Send + Sync + 'static; + /// Returns a handler that accepts a parsed command `C` if the command + /// contains a bot mention, for example `/start@my_bot`. + /// + /// ## Dependency requirements + /// + /// - [`crate::types::Message`] + /// - [`crate::types::Me`] + #[must_use] + fn filter_mention_command(self) -> Self + where + C: BotCommands + Send + Sync + 'static; + /// Passes [`Dialogue`] and `D` as handler dependencies. /// /// It does so by the following steps: @@ -61,6 +73,13 @@ where self.chain(filter_command::()) } + fn filter_mention_command(self) -> Self + where + C: BotCommands + Send + Sync + 'static, + { + self.chain(filter_mention_command::()) + } + fn enter_dialogue(self) -> Self where S: Storage + ?Sized + Send + Sync + 'static, @@ -93,3 +112,38 @@ where message.text().and_then(|text| C::parse(text, &bot_name).ok()) }) } + +/// Returns a handler that accepts a parsed command `C` if the command +/// contains a bot mention, for example `/start@my_bot`. +/// +/// A call to this function is the same as +/// `dptree::entry().filter_mention_command()`. +/// +/// See [`HandlerExt::filter_mention_command`]. +/// +/// ## Dependency requirements +/// +/// - [`crate::types::Message`] +/// - [`crate::types::Me`] +#[must_use] +pub fn filter_mention_command( +) -> Handler<'static, DependencyMap, Output, DpHandlerDescription> +where + C: BotCommands + Send + Sync + 'static, + Output: Send + Sync + 'static, +{ + dptree::filter_map(move |message: Message, me: Me| { + let bot_name = me.user.username.expect("Bots must have a username"); + + let command = message.text().and_then(|text| C::parse(text, &bot_name).ok()); + // If the parsing succeeds with a bot_name, + // but fails without - there is a mention + let is_username_required = + message.text().and_then(|text| C::parse(text, "").ok()).is_none(); + + if !is_username_required { + return None; + } + command + }) +} diff --git a/crates/teloxide/src/lib.rs b/crates/teloxide/src/lib.rs index f4c9995c..7a789398 100644 --- a/crates/teloxide/src/lib.rs +++ b/crates/teloxide/src/lib.rs @@ -149,7 +149,7 @@ pub use teloxide_core::*; #[cfg(feature = "macros")] pub use teloxide_macros as macros; -pub use dispatching::filter_command; +pub use dispatching::{filter_command, filter_mention_command}; pub use dptree::{self, case as handler}; #[cfg(all(feature = "nightly", doctest))]