From 6dc7f70813e526a888d1de8283e1fd1f7c84c75a Mon Sep 17 00:00:00 2001 From: Ilya Bizyaev Date: Sat, 11 Jan 2025 16:00:39 +0100 Subject: [PATCH] Implement deleteMessages It's the batch version of deleteMessage that does not return errors for messages that were not found. Docs: https://core.telegram.org/bots/api#deletemessages --- teloxide_tests/src/lib.rs | 1 + teloxide_tests/src/server/messages.rs | 44 +++++++++++++++++- teloxide_tests/src/server/mod.rs | 19 ++++---- .../src/server/routes/delete_messages.rs | 46 +++++++++++++++++++ teloxide_tests/src/server/routes/mod.rs | 5 +- teloxide_tests/src/tests.rs | 19 ++++++++ 6 files changed, 122 insertions(+), 12 deletions(-) create mode 100644 teloxide_tests/src/server/routes/delete_messages.rs diff --git a/teloxide_tests/src/lib.rs b/teloxide_tests/src/lib.rs index ec46a33..da0d76e 100644 --- a/teloxide_tests/src/lib.rs +++ b/teloxide_tests/src/lib.rs @@ -58,6 +58,7 @@ //! //! - /AnswerCallbackQuery //! - /DeleteMessage +//! - /DeleteMessages //! - /EditMessageText //! - /EditMessageReplyMarkup //! - /EditMessageCaption diff --git a/teloxide_tests/src/server/messages.rs b/teloxide_tests/src/server/messages.rs index 564573f..2a6677e 100644 --- a/teloxide_tests/src/server/messages.rs +++ b/teloxide_tests/src/server/messages.rs @@ -1,3 +1,5 @@ +use std::collections::HashSet; + use serde::Serialize; use teloxide::types::{Message, ReplyMarkup}; @@ -61,12 +63,24 @@ impl Messages { self.messages.retain(|m| m.id.0 != message_id); Some(message) } + + pub fn delete_messages(&mut self, message_ids: &[i32]) -> Vec { + let message_ids: HashSet = message_ids.iter().cloned().collect(); + let deleted = self + .messages + .iter() + .filter(|m| message_ids.contains(&m.id.0)) + .cloned() + .collect(); + self.messages.retain(|m| !message_ids.contains(&m.id.0)); + deleted + } } #[cfg(test)] mod tests { use serial_test::serial; - use teloxide::types::{InlineKeyboardButton, InlineKeyboardMarkup}; + use teloxide::types::{InlineKeyboardButton, InlineKeyboardMarkup, MessageId}; use super::*; use crate::dataset::*; @@ -125,7 +139,7 @@ mod tests { #[test] #[serial] - fn test_delete_messages() { + fn test_delete_message() { let mut messages = Messages::default(); messages.add_message( message_common::MockMessageText::new() @@ -137,6 +151,32 @@ mod tests { assert_eq!(messages.get_message(1), None); } + #[test] + #[serial] + fn test_delete_messages() { + let mut messages = Messages::default(); + for id in 1..=5 { + messages.add_message( + message_common::MockMessageText::new() + .text(format!("Message {}", id)) + .id(id) + .build(), + ); + } + + let deleted = messages.delete_messages(&[2, 3]); + + assert_eq!(deleted.len(), 2); + assert_eq!(deleted[0].id, MessageId(2)); + assert_eq!(deleted[1].id, MessageId(3)); + + assert!(messages.get_message(1).is_some()); + assert_eq!(messages.get_message(2), None); + assert_eq!(messages.get_message(3), None); + assert!(messages.get_message(4).is_some()); + assert!(messages.get_message(5).is_some()); + } + #[test] #[serial] fn test_edit_message_reply_markup() { diff --git a/teloxide_tests/src/server/mod.rs b/teloxide_tests/src/server/mod.rs index a1c7ad3..3bffee3 100644 --- a/teloxide_tests/src/server/mod.rs +++ b/teloxide_tests/src/server/mod.rs @@ -14,18 +14,18 @@ use actix_web::{ pub use responses::*; use routes::{ answer_callback_query::*, ban_chat_member::*, copy_message::*, delete_message::*, - download_file::download_file, edit_message_caption::*, edit_message_reply_markup::*, - edit_message_text::*, forward_message::*, get_file::*, get_me::*, get_updates::*, - get_webhook_info::*, pin_chat_message::*, restrict_chat_member::*, send_animation::*, - send_audio::*, send_chat_action::*, send_contact::*, send_dice::*, send_document::*, - send_invoice::*, send_location::*, send_media_group::*, send_message::*, send_photo::*, - send_poll::*, send_sticker::*, send_venue::*, send_video::*, send_video_note::*, send_voice::*, - set_message_reaction::*, set_my_commands::*, unban_chat_member::*, unpin_all_chat_messages::*, - unpin_chat_message::*, + delete_messages::*, download_file::download_file, edit_message_caption::*, + edit_message_reply_markup::*, edit_message_text::*, forward_message::*, get_file::*, get_me::*, + get_updates::*, get_webhook_info::*, pin_chat_message::*, restrict_chat_member::*, + send_animation::*, send_audio::*, send_chat_action::*, send_contact::*, send_dice::*, + send_document::*, send_invoice::*, send_location::*, send_media_group::*, send_message::*, + send_photo::*, send_poll::*, send_sticker::*, send_venue::*, send_video::*, send_video_note::*, + send_voice::*, set_message_reaction::*, set_my_commands::*, unban_chat_member::*, + unpin_all_chat_messages::*, unpin_chat_message::*, }; pub use routes::{ copy_message::CopyMessageBody, delete_message::DeleteMessageBody, - edit_message_caption::EditMessageCaptionBody, + delete_messages::DeleteMessagesBody, edit_message_caption::EditMessageCaptionBody, edit_message_reply_markup::EditMessageReplyMarkupBody, edit_message_text::EditMessageTextBody, forward_message::ForwardMessageBody, send_animation::SendMessageAnimationBody, send_audio::SendMessageAudioBody, send_contact::SendMessageContactBody, @@ -154,6 +154,7 @@ fn set_bot_routes(cfg: &mut ServiceConfig) { post().to(edit_message_reply_markup), ) .route("/DeleteMessage", post().to(delete_message)) + .route("/DeleteMessages", post().to(delete_messages)) .route("/ForwardMessage", post().to(forward_message)) .route("/CopyMessage", post().to(copy_message)) .route("/AnswerCallbackQuery", post().to(answer_callback_query)) diff --git a/teloxide_tests/src/server/routes/delete_messages.rs b/teloxide_tests/src/server/routes/delete_messages.rs new file mode 100644 index 0000000..b5f80ab --- /dev/null +++ b/teloxide_tests/src/server/routes/delete_messages.rs @@ -0,0 +1,46 @@ +use std::sync::Mutex; + +use actix_web::{web, Responder}; +use serde::Deserialize; + +use super::BodyChatId; +use crate::{ + server::{ + routes::{delete_message::DeleteMessageBody, make_telegram_result}, + DeletedMessage, + }, + state::State, +}; + +#[derive(Debug, Deserialize, Clone)] +pub struct DeleteMessagesBody { + pub chat_id: BodyChatId, + pub message_ids: Vec, +} + +pub async fn delete_messages( + state: web::Data>, + body: web::Json, +) -> impl Responder { + let mut lock = state.lock().unwrap(); + let bot_request = body.into_inner(); + // deleteMessages skips messages that are not found, no error is returned. + let mut deleted_messages = lock + .messages + .delete_messages(&bot_request.message_ids) + .into_iter() + .map(|m| DeletedMessage { + message: m.clone(), + bot_request: DeleteMessageBody { + chat_id: bot_request.chat_id.clone(), + message_id: m.id.0, + }, + }) + .collect(); + + lock.responses + .deleted_messages + .append(&mut deleted_messages); + + make_telegram_result(true) +} diff --git a/teloxide_tests/src/server/routes/mod.rs b/teloxide_tests/src/server/routes/mod.rs index 9479cc7..574aa41 100644 --- a/teloxide_tests/src/server/routes/mod.rs +++ b/teloxide_tests/src/server/routes/mod.rs @@ -13,6 +13,7 @@ pub mod answer_callback_query; pub mod ban_chat_member; pub mod copy_message; pub mod delete_message; +pub mod delete_messages; pub mod download_file; pub mod edit_message_caption; pub mod edit_message_reply_markup; @@ -237,7 +238,9 @@ pub async fn get_raw_multipart_fields( Attachment { raw_name: data.0.to_string(), file_name: filename.to_string(), - file_data: from_utf8(&data.1).unwrap_or("error_getting_data").to_string(), + file_data: from_utf8(&data.1) + .unwrap_or("error_getting_data") + .to_string(), }, ); } diff --git a/teloxide_tests/src/tests.rs b/teloxide_tests/src/tests.rs index ee92ad4..baf51ab 100644 --- a/teloxide_tests/src/tests.rs +++ b/teloxide_tests/src/tests.rs @@ -186,6 +186,8 @@ pub enum AllCommands { #[command()] Delete, #[command()] + DeleteBatch, + #[command()] EditReplyMarkup, #[command()] Photo, @@ -264,6 +266,10 @@ async fn handler( AllCommands::Delete => { bot.delete_message(msg.chat.id, sent_message.id).await?; } + AllCommands::DeleteBatch => { + bot.delete_messages(msg.chat.id, vec![sent_message.id, MessageId(404)]) + .await?; + } AllCommands::EditReplyMarkup => { bot.edit_message_reply_markup(msg.chat.id, sent_message.id) .reply_markup(InlineKeyboardMarkup::new(vec![vec![ @@ -1024,6 +1030,19 @@ async fn test_delete_message() { assert_eq!(last_deleted_response.message.id, last_sent_message.id); } +#[tokio::test] +async fn test_delete_messages() { + let mut bot = MockBot::new(MockMessageText::new().text("/deletebatch"), get_schema()); + + bot.dispatch().await; + + let last_sent_message = bot.get_responses().sent_messages.pop().unwrap(); + let last_deleted_response = bot.get_responses().deleted_messages.pop().unwrap(); + + assert_eq!(last_sent_message.text(), Some("/deletebatch")); + assert_eq!(last_deleted_response.message.id, last_sent_message.id); +} + #[tokio::test] async fn test_answer_callback_query() { let mut bot = MockBot::new(MockCallbackQuery::new().data("test"), get_schema());