diff --git a/Cargo.lock b/Cargo.lock index 8b58b7d..52116a7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2118,18 +2118,18 @@ checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918" [[package]] name = "serde" -version = "1.0.176" +version = "1.0.177" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76dc28c9523c5d70816e393136b86d48909cfb27cecaa902d338c19ed47164dc" +checksum = "63ba2516aa6bf82e0b19ca8b50019d52df58455d3cf9bdaf6315225fdd0c560a" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.176" +version = "1.0.177" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4e7b8c5dc823e3b90651ff1d3808419cd14e5ad76de04feaf37da114e7a306f" +checksum = "401797fe7833d72109fedec6bfcbe67c0eed9b99772f26eb8afd261f0abc6fd3" dependencies = [ "proc-macro2", "quote", diff --git a/src/commands/add_account.rs b/src/commands/add_account.rs index abe5bbf..d258ad5 100644 --- a/src/commands/add_account.rs +++ b/src/commands/add_account.rs @@ -8,22 +8,23 @@ async fn get_master_pass( msg: Message, db: DatabaseConnection, dialogue: MainDialogue, - ids: MessageIds, + mut ids: MessageIds, name: String, login: String, password: String, master_pass: String, ) -> crate::Result<()> { - ids.delete(&bot).await; - let user_id = msg.from().ok_or(NoUserInfo)?.id.0; dialogue.exit().await?; + + let user_id = msg.from().ok_or(NoUserInfo)?.id.0; + let account = spawn_blocking(move || { account::ActiveModel::from_unencrypted(user_id, name, &login, &password, &master_pass) }) .await??; account.insert(&db).await?; - bot.send_message(msg.chat.id, "Success") - .reply_markup(deletion_markup()) + + ids.alter_message(&bot, "Success", deletion_markup(), None) .await?; Ok(()) } diff --git a/src/commands/delete.rs b/src/commands/delete.rs index 03fb5f2..39715da 100644 --- a/src/commands/delete.rs +++ b/src/commands/delete.rs @@ -7,18 +7,23 @@ async fn get_master_pass( msg: Message, db: DatabaseConnection, dialogue: MainDialogue, - ids: MessageIds, + mut ids: MessageIds, name: String, _: String, ) -> crate::Result<()> { - ids.delete(&bot).await; dialogue.exit().await?; let user_id = msg.from().ok_or(NoUserInfo)?.id.0; Account::delete_by_id((user_id, name)).exec(&db).await?; - bot.send_message(msg.chat.id, "The account is successfully deleted") - .reply_markup(deletion_markup()) - .await?; + + ids.alter_message( + &bot, + "The account is successfully deleted", + deletion_markup(), + None, + ) + .await?; + Ok(()) } diff --git a/src/commands/delete_all.rs b/src/commands/delete_all.rs index 7abf40d..3ec159a 100644 --- a/src/commands/delete_all.rs +++ b/src/commands/delete_all.rs @@ -10,10 +10,9 @@ async fn get_master_pass( msg: Message, db: DatabaseConnection, dialogue: MainDialogue, - ids: MessageIds, + mut ids: MessageIds, _: String, ) -> crate::Result<()> { - ids.delete(&bot).await; dialogue.exit().await?; let user_id = msg.from().ok_or(NoUserInfo)?.id.0; let txn = db.begin().await?; @@ -32,8 +31,7 @@ async fn get_master_pass( "Something went wrong. Try again later" } }; - bot.send_message(msg.chat.id, text) - .reply_markup(deletion_markup()) + ids.alter_message(&bot, text, deletion_markup(), None) .await?; Ok(()) } diff --git a/src/commands/export.rs b/src/commands/export.rs index 50cc2bf..1adb39d 100644 --- a/src/commands/export.rs +++ b/src/commands/export.rs @@ -26,6 +26,8 @@ async fn get_master_pass( ids: MessageIds, master_pass: String, ) -> crate::Result<()> { + dialogue.exit().await?; + ids.delete(&bot).await; let user_id = msg.from().ok_or(NoUserInfo)?.id.0; let mut accounts = Vec::new(); @@ -51,7 +53,6 @@ async fn get_master_pass( bot.send_document(msg.chat.id, file) .reply_markup(deletion_markup()) .await?; - dialogue.exit().await?; Ok(()) } diff --git a/src/commands/get_account.rs b/src/commands/get_account.rs index 7253913..84e7f54 100644 --- a/src/commands/get_account.rs +++ b/src/commands/get_account.rs @@ -8,14 +8,14 @@ async fn get_master_pass( msg: Message, db: DatabaseConnection, dialogue: MainDialogue, - ids: MessageIds, + mut ids: MessageIds, name: String, master_pass: String, ) -> crate::Result<()> { - ids.delete(&bot).await; dialogue.exit().await?; let user_id = msg.from().ok_or(NoUserInfo)?.id.0; + let account = match Account::get(user_id, &name, &db).await? { Some(account) => account, None => { @@ -25,11 +25,11 @@ async fn get_master_pass( return Ok(()); } }; + let (login, password) = spawn_blocking(move || account.decrypt(&master_pass)).await??; - let message = format!("Name:\n`{name}`\nLogin:\n`{login}`\nPassword:\n`{password}`"); - bot.send_message(msg.chat.id, message) - .reply_markup(deletion_markup()) - .parse_mode(ParseMode::MarkdownV2) + let text = format!("Name:\n`{name}`\nLogin:\n`{login}`\nPassword:\n`{password}`"); + + ids.alter_message(&bot, text, deletion_markup(), ParseMode::MarkdownV2) .await?; Ok(()) } diff --git a/src/commands/import.rs b/src/commands/import.rs index 923cd5b..d55f2ec 100644 --- a/src/commands/import.rs +++ b/src/commands/import.rs @@ -31,11 +31,12 @@ async fn get_master_pass( msg: Message, db: DatabaseConnection, dialogue: MainDialogue, - ids: MessageIds, + mut ids: MessageIds, user: User, master_pass: String, ) -> crate::Result<()> { - ids.delete(&bot).await; + dialogue.exit().await?; + let user_id = msg.from().ok_or(NoUserInfo)?.id.0; let mut failed = Vec::new(); @@ -50,7 +51,7 @@ async fn get_master_pass( .await; } - let message = if failed.is_empty() { + let text = if failed.is_empty() { "Success".to_owned() } else { format!( @@ -58,10 +59,8 @@ async fn get_master_pass( failed.into_iter().format("\n") ) }; - bot.send_message(msg.chat.id, message) - .reply_markup(deletion_markup()) + ids.alter_message(&bot, text, deletion_markup(), None) .await?; - dialogue.exit().await?; Ok(()) } diff --git a/src/commands/set_master_pass.rs b/src/commands/set_master_pass.rs index da1575b..70114a0 100644 --- a/src/commands/set_master_pass.rs +++ b/src/commands/set_master_pass.rs @@ -7,10 +7,9 @@ async fn get_master_pass( msg: Message, db: DatabaseConnection, dialogue: MainDialogue, - ids: MessageIds, + mut ids: MessageIds, master_pass: String, ) -> crate::Result<()> { - ids.delete(&bot).await; dialogue.exit().await?; let user_id = msg.from().ok_or(NoUserInfo)?.id.0; @@ -18,8 +17,7 @@ async fn get_master_pass( spawn_blocking(move || master_pass::ActiveModel::from_unencrypted(user_id, &master_pass)) .await?; model.insert(&db).await?; - bot.send_message(msg.chat.id, "Success") - .reply_markup(deletion_markup()) + ids.alter_message(&bot, "Success", deletion_markup(), None) .await?; Ok(()) } @@ -44,7 +42,7 @@ pub async fn set_master_pass( change_state!( dialogue, - previous, + &previous, (), State::GetNewMasterPass, get_master_pass diff --git a/src/macros.rs b/src/macros.rs index 922e342..05e55bb 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -4,7 +4,7 @@ macro_rules! change_state { $dialogue .update($next_state(Handler::new( move |bot, msg, db, dialogue, ids, param| Box::pin($next_func(bot, msg, db, dialogue, ids, $($param,)* param)), - &$previous, + $previous, ))) .await?; Ok(()) @@ -22,7 +22,7 @@ macro_rules! first_handler { ) -> $crate::Result<()> { let previous = bot.send_message(msg.chat.id, $message).await?; - $crate::change_state!(dialogue, previous, (), $next_state, $next_func) + $crate::change_state!(dialogue, &previous, (), $next_state, $next_func) } }; } @@ -37,14 +37,12 @@ macro_rules! handler { msg: Message, _: DatabaseConnection, dialogue: MainDialogue, - ids: MessageIds, + mut ids: MessageIds, $($param: $type),* ) -> $crate::Result<()> { - ids.delete(&bot).await; + ids.alter_message(&bot, $message, None, None).await?; - let previous = bot.send_message(msg.chat.id, $message).await?; - - $crate::change_state!(dialogue, previous, ($($param),*), $next_state, $next_func) + $crate::change_state!(dialogue, ids, ($($param),*), $next_state, $next_func) } }; } @@ -72,7 +70,7 @@ macro_rules! ask_name_handler { .reply_markup(markup) .await?; - $crate::change_state!(dialogue, previous, (), State::GetExistingName, $next_func) + $crate::change_state!(dialogue, &previous, (), State::GetExistingName, $next_func) } }; } diff --git a/src/state/generic.rs b/src/state/generic.rs index d0569dc..713f454 100644 --- a/src/state/generic.rs +++ b/src/state/generic.rs @@ -28,23 +28,28 @@ where let text = match msg.text() { Some(text) => text.trim(), None => { - let msg = bot.send_message(msg.chat.id, no_text_message).await?; - handler.previous = MessageIds::from(&msg); + handler + .previous + .alter_message(&bot, no_text_message, None, None) + .await?; return Ok(()); } }; if text == "/cancel" { dialogue.exit().await?; - bot.send_message(msg.chat.id, "Successfully cancelled") - .reply_markup(deletion_markup()) + handler + .previous + .alter_message(&bot, "Successfully cancelled", deletion_markup(), None) .await?; return Ok(()); } if let Some(text) = check(&msg, &db, text).await? { - let failure_message = bot.send_message(msg.chat.id, text).await?; - handler.previous = MessageIds::from(&failure_message); + handler + .previous + .alter_message(&bot, text, None, None) + .await?; return Ok(()); } diff --git a/src/state/get_existing_name.rs b/src/state/get_existing_name.rs index 2c8293b..ed4d88f 100644 --- a/src/state/get_existing_name.rs +++ b/src/state/get_existing_name.rs @@ -33,8 +33,9 @@ pub async fn get_existing_name( if text == "/cancel" { dialogue.exit().await?; - bot.send_message(msg.chat.id, "Successfully cancelled") - .reply_markup(deletion_markup()) + handler + .previous + .alter_message(&bot, "Successfully cancelled", deletion_markup(), None) .await?; return Ok(()); } @@ -48,12 +49,10 @@ pub async fn get_existing_name( return Ok(()); } - let previous = handler.previous; let func = handler.func.take().unwrap(); - drop(handler); let text = text.to_owned(); - if let Err(err) = func(bot, msg, db, dialogue.clone(), previous, text).await { + if let Err(err) = func(bot, msg, db, dialogue.clone(), handler.previous, text).await { let _ = dialogue.exit().await; return Err(err); } diff --git a/src/state/get_user.rs b/src/state/get_user.rs index ae286c0..8b0a372 100644 --- a/src/state/get_user.rs +++ b/src/state/get_user.rs @@ -147,8 +147,9 @@ pub async fn get_user( if let Some("/cancel") = msg.text().map(str::trim) { dialogue.exit().await?; - bot.send_message(msg.chat.id, "Successfully cancelled") - .reply_markup(deletion_markup()) + handler + .previous + .alter_message(&bot, "Successfully cancelled", deletion_markup(), None) .await?; return Ok(()); } @@ -156,8 +157,10 @@ pub async fn get_user( let file = match validate_document(msg.document()) { Ok(document) => &document.file, Err(text) => { - let msg = bot.send_message(msg.chat.id, text).await?; - handler.previous = MessageIds::from(&msg); + handler + .previous + .alter_message(&bot, text, None, None) + .await?; return Ok(()); } }; @@ -175,15 +178,17 @@ pub async fn get_user( let user = match spawn_blocking(move || user_from_vec(data, existing_names)).await? { Ok(Ok(user)) => user, Ok(Err(error_text)) => { - let msg = bot.send_message(msg.chat.id, error_text).await?; - handler.previous = MessageIds::from(&msg); + handler + .previous + .alter_message(&bot, error_text, None, None) + .await?; return Ok(()); } Err(_) => { - let msg = bot - .send_message(msg.chat.id, "Error parsing the json file. Try again") + handler + .previous + .alter_message(&bot, "Error parsing the json file. Try again", None, None) .await?; - handler.previous = MessageIds::from(&msg); return Ok(()); } }; diff --git a/src/state/handler.rs b/src/state/handler.rs index 36f713f..c1ee2b7 100644 --- a/src/state/handler.rs +++ b/src/state/handler.rs @@ -1,17 +1,62 @@ use crate::prelude::*; use futures::future::BoxFuture; -use std::sync::Arc; -use teloxide::types::{InlineKeyboardMarkup, MessageId}; -use tokio::sync::Mutex; +use std::{mem, sync::Arc}; +use teloxide::{ + requests::HasPayload, + types::{InlineKeyboardMarkup, MessageId, ParseMode}, + RequestError, +}; +use tokio::{join, sync::Mutex}; #[derive(Clone, Copy)] pub struct MessageIds(pub ChatId, pub MessageId); impl MessageIds { #[inline] - pub async fn delete(&self, bot: &Throttle) { + pub async fn delete(self, bot: &Throttle) { let _ = bot.delete_message(self.0, self.1).await; } + + /// Tries to alter the message or sends a new one + /// + /// # Returns + /// + /// Returns true if the message was edited successfully. Returns false otherwise + #[inline] + pub async fn alter_message( + &mut self, + bot: &Throttle, + text: impl Into, + markup: impl Into>, + parse_mode: impl Into> + Copy, + ) -> crate::Result<()> { + let mut edit = bot.edit_message_text(self.0, self.1, text); + edit.parse_mode = parse_mode.into(); + + let mut markup = markup.into(); + if let Some(markup) = markup { + edit = edit.reply_markup(markup) + } + + match edit.send_ref().await { + Ok(msg) => return Ok(()), + Err(RequestError::Api(_)) => (), + Err(err) => return Err(err.into()), + }; + + let text = mem::take(&mut edit.text); + markup = mem::take(&mut edit.reply_markup); + + let mut send = bot.send_message(self.0, text); + send.payload_mut().parse_mode = parse_mode.into(); + if let Some(markup) = markup { + send = send.reply_markup(markup); + } + + let msg = join!(self.delete(bot), send.send()).1?; + *self = Self::from(&msg); + Ok(()) + } } impl From<&Message> for MessageIds {