mirror of
https://github.com/teloxide/teloxide.git
synced 2025-01-03 09:49:07 +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
|
||||
|
||||
### 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
|
||||
|
||||
### Fixed
|
||||
|
|
|
@ -56,7 +56,7 @@ full = [
|
|||
]
|
||||
|
||||
[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 }
|
||||
|
||||
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.
|
||||
- [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.
|
||||
- [studiedlist/EddieBot](https://gitlab.com/studiedlist/eddie-bot) -- Chatting bot with several entertainment features
|
||||
|
||||
## Contributing
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
// ```
|
||||
|
||||
use teloxide::{
|
||||
dispatching::dialogue::{self, GetChatId, InMemStorage},
|
||||
dispatching::dialogue::{self, InMemStorage},
|
||||
prelude::*,
|
||||
types::{InlineKeyboardButton, InlineKeyboardMarkup},
|
||||
utils::command::BotCommands,
|
||||
|
@ -42,30 +42,40 @@ enum Command {
|
|||
Help,
|
||||
#[command(description = "start the purchase procedure.")]
|
||||
Start,
|
||||
#[command(description = "cancel the purchase procedure.")]
|
||||
Cancel,
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
pretty_env_logger::init();
|
||||
log::info!("Starting dialogue_bot...");
|
||||
log::info!("Starting purchase bot...");
|
||||
|
||||
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(
|
||||
bot,
|
||||
dialogue::enter::<Update, InMemStorage<State>, State, _>()
|
||||
.branch(
|
||||
Update::filter_message()
|
||||
.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),
|
||||
),
|
||||
),
|
||||
.branch(message_handler)
|
||||
.branch(callback_query_handler),
|
||||
)
|
||||
.dependencies(dptree::deps![InMemStorage::<State>::new()])
|
||||
.build()
|
||||
|
@ -74,22 +84,26 @@ async fn main() {
|
|||
.await;
|
||||
}
|
||||
|
||||
async fn handle_command(
|
||||
bot: AutoSend<Bot>,
|
||||
msg: Message,
|
||||
cmd: Command,
|
||||
dialogue: MyDialogue,
|
||||
) -> HandlerResult {
|
||||
match cmd {
|
||||
Command::Help => {
|
||||
bot.send_message(msg.chat.id, Command::descriptions().to_string()).await?;
|
||||
}
|
||||
Command::Start => {
|
||||
async fn start(bot: AutoSend<Bot>, 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<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(())
|
||||
}
|
||||
|
||||
|
@ -100,13 +114,12 @@ 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, product));
|
||||
|
||||
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 => {
|
||||
|
@ -124,21 +137,13 @@ async fn receive_product_selection(
|
|||
full_name: String,
|
||||
) -> HandlerResult {
|
||||
if let Some(product) = &q.data {
|
||||
if let Some(chat_id) = q.chat_id() {
|
||||
bot.send_message(
|
||||
chat_id,
|
||||
dialogue.chat_id(),
|
||||
format!("{full_name}, product '{product}' has been purchased successfully!"),
|
||||
)
|
||||
.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(())
|
||||
}
|
||||
|
|
|
@ -189,6 +189,11 @@ where
|
|||
///
|
||||
/// See [`HandlerExt::enter_dialogue`].
|
||||
///
|
||||
/// ## Dependency requirements
|
||||
///
|
||||
/// - `Arc<S>`
|
||||
/// - `Upd`
|
||||
///
|
||||
/// [`HandlerExt::enter_dialogue`]: super::HandlerExt::enter_dialogue
|
||||
pub fn enter<Upd, S, D, Output>() -> Handler<'static, DependencyMap, Output, DpHandlerDescription>
|
||||
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
|
||||
/// 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 +250,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)::+) => {
|
||||
|
|
|
@ -42,7 +42,8 @@ pub trait HandlerExt<Output> {
|
|||
/// - `Arc<S>`
|
||||
/// - `Upd`
|
||||
///
|
||||
/// [`Dialogue<D, S>`]: Dialogue
|
||||
/// [`Dialogue<D, S>`]: super::dialogue::Dialogue
|
||||
/// [`Dialogue::get_or_default`]: super::dialogue::Dialogue::get_or_default
|
||||
#[must_use]
|
||||
fn enter_dialogue<Upd, S, D>(self) -> Self
|
||||
where
|
||||
|
@ -67,10 +68,7 @@ where
|
|||
where
|
||||
C: BotCommands + Send + Sync + 'static,
|
||||
{
|
||||
self.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())
|
||||
}))
|
||||
self.chain(filter_command::<C, Output>())
|
||||
}
|
||||
|
||||
fn enter_dialogue<Upd, S, D>(self) -> Self
|
||||
|
@ -91,3 +89,24 @@ where
|
|||
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 filter_ext::{MessageFilterExt, UpdateFilterExt};
|
||||
pub use handler_description::DpHandlerDescription;
|
||||
pub use handler_ext::HandlerExt;
|
||||
pub use handler_ext::{filter_command, HandlerExt};
|
||||
#[allow(deprecated)]
|
||||
pub use handler_factory::HandlerFactory;
|
||||
|
|
|
@ -79,6 +79,7 @@ pub use teloxide_core::*;
|
|||
#[cfg(feature = "macros")]
|
||||
pub use teloxide_macros as macros;
|
||||
|
||||
pub use dispatching::filter_command;
|
||||
pub use dptree;
|
||||
|
||||
#[cfg(all(feature = "nightly", doctest))]
|
||||
|
|
Loading…
Reference in a new issue