Switched to inline buttons when getting the account name, finished decrypt and delete Callback commands
This commit is contained in:
		
							
								
								
									
										68
									
								
								src/callbacks/decrypt.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								src/callbacks/decrypt.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,68 @@
 | 
			
		||||
use crate::{change_state, prelude::*};
 | 
			
		||||
use teloxide::types::ParseMode;
 | 
			
		||||
use tokio::task::spawn_blocking;
 | 
			
		||||
 | 
			
		||||
async fn get_master_pass(
 | 
			
		||||
    bot: Throttle<Bot>,
 | 
			
		||||
    msg: Message,
 | 
			
		||||
    db: DatabaseConnection,
 | 
			
		||||
    dialogue: MainDialogue,
 | 
			
		||||
    mut ids: MessageIds,
 | 
			
		||||
    name: String,
 | 
			
		||||
    master_pass: String,
 | 
			
		||||
) -> crate::Result<()> {
 | 
			
		||||
    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 => {
 | 
			
		||||
            bot.send_message(msg.chat.id, "Account not found")
 | 
			
		||||
                .reply_markup(deletion_markup())
 | 
			
		||||
                .await?;
 | 
			
		||||
            return Ok(());
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    let (login, password) = spawn_blocking(move || account.decrypt(&master_pass)).await??;
 | 
			
		||||
    let text = format!("Name:\n`{name}`\nLogin:\n`{login}`\nPassword:\n`{password}`");
 | 
			
		||||
 | 
			
		||||
    ids.alter_message(
 | 
			
		||||
        &bot,
 | 
			
		||||
        text,
 | 
			
		||||
        account_markup(&name, false),
 | 
			
		||||
        ParseMode::MarkdownV2,
 | 
			
		||||
    )
 | 
			
		||||
    .await?;
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub async fn decrypt(
 | 
			
		||||
    bot: Throttle<Bot>,
 | 
			
		||||
    q: CallbackQuery,
 | 
			
		||||
    db: DatabaseConnection,
 | 
			
		||||
    dialogue: MainDialogue,
 | 
			
		||||
    hash: super::NameHash,
 | 
			
		||||
) -> crate::Result<()> {
 | 
			
		||||
    let mut msg: MessageIds = q.message.as_ref().unwrap().into();
 | 
			
		||||
    let user_id = q.from.id.0;
 | 
			
		||||
    let name = match name_from_hash(&db, user_id, &hash).await? {
 | 
			
		||||
        Some(name) => name,
 | 
			
		||||
        None => {
 | 
			
		||||
            msg.alter_message(
 | 
			
		||||
                &bot,
 | 
			
		||||
                "Account wan't found. Select another one",
 | 
			
		||||
                menu_markup("decrypt", user_id, &db).await?,
 | 
			
		||||
                None,
 | 
			
		||||
            )
 | 
			
		||||
            .await?;
 | 
			
		||||
            return Ok(());
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    msg.alter_message(&bot, "Send master password", None, None)
 | 
			
		||||
        .await?;
 | 
			
		||||
 | 
			
		||||
    change_state!(dialogue, msg, (name), State::GetMasterPass, get_master_pass)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										63
									
								
								src/callbacks/delete.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								src/callbacks/delete.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,63 @@
 | 
			
		||||
use crate::{change_state, prelude::*};
 | 
			
		||||
 | 
			
		||||
async fn get_master_pass(
 | 
			
		||||
    bot: Throttle<Bot>,
 | 
			
		||||
    msg: Message,
 | 
			
		||||
    db: DatabaseConnection,
 | 
			
		||||
    dialogue: MainDialogue,
 | 
			
		||||
    mut ids: MessageIds,
 | 
			
		||||
    name: String,
 | 
			
		||||
    _: String,
 | 
			
		||||
) -> crate::Result<()> {
 | 
			
		||||
    dialogue.exit().await?;
 | 
			
		||||
 | 
			
		||||
    let user_id = msg.from().ok_or(NoUserInfo)?.id.0;
 | 
			
		||||
    Account::delete_by_id((user_id, name)).exec(&db).await?;
 | 
			
		||||
 | 
			
		||||
    ids.alter_message(
 | 
			
		||||
        &bot,
 | 
			
		||||
        "The account is successfully deleted",
 | 
			
		||||
        deletion_markup(),
 | 
			
		||||
        None,
 | 
			
		||||
    )
 | 
			
		||||
    .await?;
 | 
			
		||||
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub async fn delete(
 | 
			
		||||
    bot: Throttle<Bot>,
 | 
			
		||||
    q: CallbackQuery,
 | 
			
		||||
    db: DatabaseConnection,
 | 
			
		||||
    dialogue: MainDialogue,
 | 
			
		||||
    hash: super::NameHash,
 | 
			
		||||
) -> crate::Result<()> {
 | 
			
		||||
    let mut msg: MessageIds = q.message.as_ref().unwrap().into();
 | 
			
		||||
    let user_id = q.from.id.0;
 | 
			
		||||
    let name = match name_from_hash(&db, user_id, &hash).await? {
 | 
			
		||||
        Some(name) => name,
 | 
			
		||||
        None => {
 | 
			
		||||
            msg.alter_message(
 | 
			
		||||
                &bot,
 | 
			
		||||
                "Account wan't found. Select another one",
 | 
			
		||||
                menu_markup("delete", user_id, &db).await?,
 | 
			
		||||
                None,
 | 
			
		||||
            )
 | 
			
		||||
            .await?;
 | 
			
		||||
            return Ok(());
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    let previous = bot.send_message(
 | 
			
		||||
        msg.0,
 | 
			
		||||
        "Send master password. Once you send correct master password the account is unrecoverable"
 | 
			
		||||
    ).await?;
 | 
			
		||||
 | 
			
		||||
    change_state!(
 | 
			
		||||
        dialogue,
 | 
			
		||||
        &previous,
 | 
			
		||||
        (name),
 | 
			
		||||
        State::GetMasterPass,
 | 
			
		||||
        get_master_pass
 | 
			
		||||
    )
 | 
			
		||||
}
 | 
			
		||||
@@ -10,8 +10,7 @@ pub async fn get(
 | 
			
		||||
    let user_id = q.from.id.0;
 | 
			
		||||
    let msg = q.message.as_ref().unwrap();
 | 
			
		||||
 | 
			
		||||
    let hash = hex::encode(hash);
 | 
			
		||||
    let name = match Account::get_name_by_hash(user_id, hash, &db).await? {
 | 
			
		||||
    let name = match name_from_hash(&db, user_id, &hash).await? {
 | 
			
		||||
        Some(name) => name,
 | 
			
		||||
        None => {
 | 
			
		||||
            bot.edit_message_text(
 | 
			
		||||
@@ -19,13 +18,13 @@ pub async fn get(
 | 
			
		||||
                msg.id,
 | 
			
		||||
                "Account wan't found. Select another one",
 | 
			
		||||
            )
 | 
			
		||||
            .reply_markup(menu_markup(user_id, &db).await?)
 | 
			
		||||
            .reply_markup(menu_markup("get", user_id, &db).await?)
 | 
			
		||||
            .await?;
 | 
			
		||||
            return Ok(());
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    let text = format!("Name:\n`{name}`\nLogin:\n***\nPassword:\n***");
 | 
			
		||||
    let text = format!("Name:\n`{name}`\nLogin:\n\\*\\*\\*\nPassword:\n\\*\\*\\*");
 | 
			
		||||
    bot.send_message(msg.chat.id, text)
 | 
			
		||||
        .reply_markup(account_markup(&name, true))
 | 
			
		||||
        .parse_mode(ParseMode::MarkdownV2)
 | 
			
		||||
 
 | 
			
		||||
@@ -18,9 +18,10 @@ pub async fn get_menu(
 | 
			
		||||
        bot.edit_message_text(msg.chat.id, msg.id, "You don't have any accounts")
 | 
			
		||||
            .reply_markup(deletion_markup())
 | 
			
		||||
            .await?;
 | 
			
		||||
        return Ok(());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let markup = spawn_blocking(|| menu_markup_sync(names)).await?;
 | 
			
		||||
    let markup = spawn_blocking(|| menu_markup_sync("get", names)).await?;
 | 
			
		||||
    bot.edit_message_text(msg.chat.id, msg.id, "Choose your account")
 | 
			
		||||
        .reply_markup(markup)
 | 
			
		||||
        .await?;
 | 
			
		||||
 
 | 
			
		||||
@@ -1,9 +1,13 @@
 | 
			
		||||
//! This module consists of endpoints to handle callbacks
 | 
			
		||||
 | 
			
		||||
mod decrypt;
 | 
			
		||||
mod delete;
 | 
			
		||||
mod delete_message;
 | 
			
		||||
mod get;
 | 
			
		||||
mod get_menu;
 | 
			
		||||
 | 
			
		||||
pub use decrypt::decrypt;
 | 
			
		||||
pub use delete::delete;
 | 
			
		||||
pub use delete_message::delete_message;
 | 
			
		||||
pub use get::get;
 | 
			
		||||
pub use get_menu::get_menu;
 | 
			
		||||
@@ -36,7 +40,7 @@ pub enum CallbackCommand {
 | 
			
		||||
impl CallbackCommand {
 | 
			
		||||
    pub fn from_query(q: CallbackQuery) -> Option<Self> {
 | 
			
		||||
        q.message.as_ref()?;
 | 
			
		||||
        q.data.and_then(|text| dbg!(text.parse()).ok())
 | 
			
		||||
        q.data.and_then(|data| data.parse().ok())
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -47,8 +51,6 @@ impl FromStr for CallbackCommand {
 | 
			
		||||
        use AlterableField::*;
 | 
			
		||||
        use CallbackCommand::*;
 | 
			
		||||
 | 
			
		||||
        println!("{s}");
 | 
			
		||||
 | 
			
		||||
        match s {
 | 
			
		||||
            "delete_message" => return Ok(DeleteMessage),
 | 
			
		||||
            "get_menu" => return Ok(GetMenu),
 | 
			
		||||
 
 | 
			
		||||
@@ -1,40 +1,11 @@
 | 
			
		||||
use crate::prelude::*;
 | 
			
		||||
 | 
			
		||||
/// Gets the master password and deletes the account.
 | 
			
		||||
/// Although it doesn't use the master password, we get it to be sure that it's the user who used that command
 | 
			
		||||
async fn get_master_pass(
 | 
			
		||||
    bot: Throttle<Bot>,
 | 
			
		||||
    msg: Message,
 | 
			
		||||
    db: DatabaseConnection,
 | 
			
		||||
    dialogue: MainDialogue,
 | 
			
		||||
    mut ids: MessageIds,
 | 
			
		||||
    name: String,
 | 
			
		||||
    _: String,
 | 
			
		||||
) -> crate::Result<()> {
 | 
			
		||||
    dialogue.exit().await?;
 | 
			
		||||
 | 
			
		||||
pub async fn delete(bot: Throttle<Bot>, msg: Message, db: DatabaseConnection) -> crate::Result<()> {
 | 
			
		||||
    let user_id = msg.from().ok_or(NoUserInfo)?.id.0;
 | 
			
		||||
    Account::delete_by_id((user_id, name)).exec(&db).await?;
 | 
			
		||||
 | 
			
		||||
    ids.alter_message(
 | 
			
		||||
        &bot,
 | 
			
		||||
        "The account is successfully deleted",
 | 
			
		||||
        deletion_markup(),
 | 
			
		||||
        None,
 | 
			
		||||
    )
 | 
			
		||||
    .await?;
 | 
			
		||||
    bot.send_message(msg.chat.id, "Choose the account to delete")
 | 
			
		||||
        .reply_markup(menu_markup("delete", user_id, &db).await?)
 | 
			
		||||
        .await?;
 | 
			
		||||
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
handler!(
 | 
			
		||||
    get_account_name(name: String),
 | 
			
		||||
    "Send master password. Once you send correct master password the account is unrecoverable",
 | 
			
		||||
    State::GetMasterPass,
 | 
			
		||||
    get_master_pass
 | 
			
		||||
);
 | 
			
		||||
ask_name_handler!(
 | 
			
		||||
    delete,
 | 
			
		||||
    "Send the name of the account to delete",
 | 
			
		||||
    get_account_name
 | 
			
		||||
);
 | 
			
		||||
 
 | 
			
		||||
@@ -1,42 +1,15 @@
 | 
			
		||||
use crate::prelude::*;
 | 
			
		||||
use teloxide::types::ParseMode;
 | 
			
		||||
use tokio::task::spawn_blocking;
 | 
			
		||||
 | 
			
		||||
/// Gets the master password, decryptes the account and sends it to the user with copyable fields
 | 
			
		||||
async fn get_master_pass(
 | 
			
		||||
pub async fn get_account(
 | 
			
		||||
    bot: Throttle<Bot>,
 | 
			
		||||
    msg: Message,
 | 
			
		||||
    db: DatabaseConnection,
 | 
			
		||||
    dialogue: MainDialogue,
 | 
			
		||||
    mut ids: MessageIds,
 | 
			
		||||
    name: String,
 | 
			
		||||
    master_pass: String,
 | 
			
		||||
) -> crate::Result<()> {
 | 
			
		||||
    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 => {
 | 
			
		||||
            bot.send_message(msg.chat.id, "Account not found")
 | 
			
		||||
                .reply_markup(deletion_markup())
 | 
			
		||||
                .await?;
 | 
			
		||||
            return Ok(());
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    let (login, password) = spawn_blocking(move || account.decrypt(&master_pass)).await??;
 | 
			
		||||
    let text = format!("Name:\n`{name}`\nLogin:\n`{login}`\nPassword:\n`{password}`");
 | 
			
		||||
 | 
			
		||||
    ids.alter_message(&bot, text, deletion_markup(), ParseMode::MarkdownV2)
 | 
			
		||||
    bot.send_message(msg.chat.id, "Choose the account to get")
 | 
			
		||||
        .reply_markup(menu_markup("decrypt", user_id, &db).await?)
 | 
			
		||||
        .await?;
 | 
			
		||||
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
handler!(get_account_name(name:String), "Send master password", State::GetMasterPass, get_master_pass);
 | 
			
		||||
ask_name_handler!(
 | 
			
		||||
    get_account,
 | 
			
		||||
    "Send the name of the account to get",
 | 
			
		||||
    get_account_name
 | 
			
		||||
);
 | 
			
		||||
 
 | 
			
		||||
@@ -15,7 +15,7 @@ pub async fn menu(bot: Throttle<Bot>, msg: Message, db: DatabaseConnection) -> c
 | 
			
		||||
            .await?;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let markup = spawn_blocking(|| menu_markup_sync(names)).await?;
 | 
			
		||||
    let markup = spawn_blocking(|| menu_markup_sync("get", names)).await?;
 | 
			
		||||
    bot.send_message(msg.chat.id, "Choose your account")
 | 
			
		||||
        .reply_markup(markup)
 | 
			
		||||
        .await?;
 | 
			
		||||
 
 | 
			
		||||
@@ -34,7 +34,7 @@ macro_rules! handler {
 | 
			
		||||
        #[inline]
 | 
			
		||||
        async fn $function_name(
 | 
			
		||||
            bot: Throttle<Bot>,
 | 
			
		||||
            msg: Message,
 | 
			
		||||
            _: Message,
 | 
			
		||||
            _: DatabaseConnection,
 | 
			
		||||
            dialogue: MainDialogue,
 | 
			
		||||
            mut ids: MessageIds,
 | 
			
		||||
@@ -47,34 +47,6 @@ macro_rules! handler {
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[macro_export]
 | 
			
		||||
macro_rules! ask_name_handler {
 | 
			
		||||
    ($function_name: ident, $message: literal, $next_func: ident) => {
 | 
			
		||||
        #[inline]
 | 
			
		||||
        pub async fn $function_name(
 | 
			
		||||
            bot: Throttle<Bot>,
 | 
			
		||||
            msg: Message,
 | 
			
		||||
            dialogue: MainDialogue,
 | 
			
		||||
            db: DatabaseConnection,
 | 
			
		||||
        ) -> $crate::Result<()> {
 | 
			
		||||
            let user_id = msg.from().ok_or(NoUserInfo)?.id.0;
 | 
			
		||||
            let markup = account_list_markup(user_id, &db).await?;
 | 
			
		||||
            if markup.keyboard.is_empty() {
 | 
			
		||||
                bot.send_message(msg.chat.id, "No accounts found")
 | 
			
		||||
                    .reply_markup(deletion_markup())
 | 
			
		||||
                    .await?;
 | 
			
		||||
                return Ok(());
 | 
			
		||||
            }
 | 
			
		||||
            let previous = bot
 | 
			
		||||
                .send_message(msg.chat.id, $message)
 | 
			
		||||
                .reply_markup(markup)
 | 
			
		||||
                .await?;
 | 
			
		||||
 | 
			
		||||
            $crate::change_state!(dialogue, &previous, (), State::GetExistingName, $next_func)
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[macro_export]
 | 
			
		||||
macro_rules! simple_state_handler {
 | 
			
		||||
    ($function_name: ident, $check: ident, $no_text_message: literal) => {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,3 @@
 | 
			
		||||
#![allow(unused)]
 | 
			
		||||
 | 
			
		||||
mod callbacks;
 | 
			
		||||
mod commands;
 | 
			
		||||
mod default;
 | 
			
		||||
@@ -49,8 +47,6 @@ fn get_dispatcher(
 | 
			
		||||
 | 
			
		||||
    let message_handler = Update::filter_message()
 | 
			
		||||
        .map_async(utils::delete_message)
 | 
			
		||||
        .enter_dialogue::<Update, InMemStorage<State>, State>()
 | 
			
		||||
        .branch(case![State::GetExistingName(next)].endpoint(state::get_existing_name))
 | 
			
		||||
        .branch(case![State::GetNewName(next)].endpoint(state::get_new_name))
 | 
			
		||||
        .branch(case![State::GetMasterPass(next)].endpoint(state::get_master_pass))
 | 
			
		||||
        .branch(case![State::GetNewMasterPass(next)].endpoint(state::get_new_master_pass))
 | 
			
		||||
@@ -64,9 +60,12 @@ fn get_dispatcher(
 | 
			
		||||
        .filter_map(CallbackCommand::from_query)
 | 
			
		||||
        .branch(case![CallbackCommand::GetMenu].endpoint(callbacks::get_menu))
 | 
			
		||||
        .branch(case![CallbackCommand::DeleteMessage].endpoint(callbacks::delete_message))
 | 
			
		||||
        .branch(case![CallbackCommand::Get(hash)].endpoint(callbacks::get));
 | 
			
		||||
        .branch(case![CallbackCommand::Get(hash)].endpoint(callbacks::get))
 | 
			
		||||
        .branch(case![CallbackCommand::Decrypt(hash)].endpoint(callbacks::decrypt))
 | 
			
		||||
        .branch(case![CallbackCommand::DeleteAccount(hash)].endpoint(callbacks::delete));
 | 
			
		||||
 | 
			
		||||
    let handler = dptree::entry()
 | 
			
		||||
        .enter_dialogue::<Update, InMemStorage<State>, State>()
 | 
			
		||||
        .branch(message_handler)
 | 
			
		||||
        .branch(callback_handler);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -2,36 +2,21 @@ use crate::prelude::*;
 | 
			
		||||
use base64::{engine::general_purpose::STANDARD_NO_PAD as B64_ENGINE, Engine as _};
 | 
			
		||||
use itertools::Itertools;
 | 
			
		||||
use sha2::{Digest, Sha256};
 | 
			
		||||
use teloxide::types::{InlineKeyboardButton, InlineKeyboardMarkup, KeyboardButton, KeyboardMarkup};
 | 
			
		||||
use teloxide::types::{InlineKeyboardButton, InlineKeyboardMarkup};
 | 
			
		||||
use tokio::task::spawn_blocking;
 | 
			
		||||
 | 
			
		||||
/// Creates a markup of all user's account names
 | 
			
		||||
#[inline]
 | 
			
		||||
pub async fn account_list_markup(
 | 
			
		||||
    user_id: u64,
 | 
			
		||||
    db: &DatabaseConnection,
 | 
			
		||||
) -> crate::Result<KeyboardMarkup> {
 | 
			
		||||
    let account_names: Vec<Vec<KeyboardButton>> = Account::get_names(user_id, db)
 | 
			
		||||
        .await?
 | 
			
		||||
        .map_ok(KeyboardButton::new)
 | 
			
		||||
        .try_chunks(3)
 | 
			
		||||
        .map_err(|err| err.1)
 | 
			
		||||
        .try_collect()
 | 
			
		||||
        .await?;
 | 
			
		||||
    let markup = KeyboardMarkup::new(account_names)
 | 
			
		||||
        .resize_keyboard(true)
 | 
			
		||||
        .one_time_keyboard(true);
 | 
			
		||||
    Ok(markup)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[inline]
 | 
			
		||||
pub fn menu_markup_sync(names: impl IntoIterator<Item = String>) -> InlineKeyboardMarkup {
 | 
			
		||||
pub fn menu_markup_sync(
 | 
			
		||||
    command: &str,
 | 
			
		||||
    names: impl IntoIterator<Item = String>,
 | 
			
		||||
) -> InlineKeyboardMarkup {
 | 
			
		||||
    let names = names
 | 
			
		||||
        .into_iter()
 | 
			
		||||
        .map(|name| {
 | 
			
		||||
            let hash = <Sha256 as Digest>::digest(name.as_bytes());
 | 
			
		||||
            let mut data = "get ".to_owned();
 | 
			
		||||
            data.reserve(43);
 | 
			
		||||
            let mut data = command.to_owned();
 | 
			
		||||
            data.reserve(44);
 | 
			
		||||
            data.push(' ');
 | 
			
		||||
            B64_ENGINE.encode_string(hash, &mut data);
 | 
			
		||||
            InlineKeyboardButton::callback(name, data)
 | 
			
		||||
        })
 | 
			
		||||
@@ -42,12 +27,14 @@ pub fn menu_markup_sync(names: impl IntoIterator<Item = String>) -> InlineKeyboa
 | 
			
		||||
 | 
			
		||||
#[inline]
 | 
			
		||||
pub async fn menu_markup(
 | 
			
		||||
    command: impl Into<String>,
 | 
			
		||||
    user_id: u64,
 | 
			
		||||
    db: &DatabaseConnection,
 | 
			
		||||
) -> crate::Result<InlineKeyboardMarkup> {
 | 
			
		||||
    let command: String = command.into();
 | 
			
		||||
    let names: Vec<String> = Account::get_names(user_id, db).await?.try_collect().await?;
 | 
			
		||||
 | 
			
		||||
    spawn_blocking(|| menu_markup_sync(names))
 | 
			
		||||
    spawn_blocking(move || menu_markup_sync(&command, names))
 | 
			
		||||
        .await
 | 
			
		||||
        .map_err(Into::into)
 | 
			
		||||
}
 | 
			
		||||
@@ -69,26 +56,26 @@ pub fn account_markup(name: &str, is_encrypted: bool) -> InlineKeyboardMarkup {
 | 
			
		||||
        .unwrap();
 | 
			
		||||
    let hash = std::str::from_utf8(&hash).unwrap();
 | 
			
		||||
 | 
			
		||||
    let alter_buttons = [
 | 
			
		||||
    let encryption_button = if is_encrypted {
 | 
			
		||||
        ("Decrypt", "decrypt")
 | 
			
		||||
    } else {
 | 
			
		||||
        ("Hide", "get")
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    let main_buttons = [
 | 
			
		||||
        ("Alter name", "an"),
 | 
			
		||||
        ("Alter login", "al"),
 | 
			
		||||
        ("Alter password", "ap"),
 | 
			
		||||
        encryption_button,
 | 
			
		||||
        ("Delete account", "delete"),
 | 
			
		||||
    ]
 | 
			
		||||
    .map(|(text, command)| make_button(text, command, hash));
 | 
			
		||||
 | 
			
		||||
    let mut second_raw = Vec::new();
 | 
			
		||||
    if is_encrypted {
 | 
			
		||||
        second_raw.push(make_button("Decrypt", "decrypt", hash))
 | 
			
		||||
    } else {
 | 
			
		||||
        second_raw.push(make_button("Hide", "hide", hash));
 | 
			
		||||
    }
 | 
			
		||||
    second_raw.push(make_button("Delete account", "delete", hash));
 | 
			
		||||
    .into_iter()
 | 
			
		||||
    .map(|(text, command)| make_button(text, command, hash))
 | 
			
		||||
    .chunks(3);
 | 
			
		||||
 | 
			
		||||
    let menu_button = InlineKeyboardButton::callback("Back to the menu", "get_menu");
 | 
			
		||||
 | 
			
		||||
    InlineKeyboardMarkup::new([alter_buttons])
 | 
			
		||||
        .append_row(second_raw)
 | 
			
		||||
        .append_row([menu_button])
 | 
			
		||||
    InlineKeyboardMarkup::new(&main_buttons).append_row([menu_button])
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Creates a markup with a "Delete message" button.
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,4 @@
 | 
			
		||||
pub(crate) use crate::{
 | 
			
		||||
    ask_name_handler,
 | 
			
		||||
    commands::Command,
 | 
			
		||||
    errors::*,
 | 
			
		||||
    first_handler, handler,
 | 
			
		||||
 
 | 
			
		||||
@@ -1,60 +0,0 @@
 | 
			
		||||
use crate::prelude::*;
 | 
			
		||||
 | 
			
		||||
/// Function to handle GetExistingName state
 | 
			
		||||
pub async fn get_existing_name(
 | 
			
		||||
    bot: Throttle<Bot>,
 | 
			
		||||
    msg: Message,
 | 
			
		||||
    db: DatabaseConnection,
 | 
			
		||||
    dialogue: MainDialogue,
 | 
			
		||||
    next: PackagedHandler<String>,
 | 
			
		||||
) -> crate::Result<()> {
 | 
			
		||||
    let user_id = msg.from().ok_or(NoUserInfo)?.id.0;
 | 
			
		||||
 | 
			
		||||
    let mut handler = next.lock().await;
 | 
			
		||||
    if handler.func.is_none() {
 | 
			
		||||
        let _ = dialogue.exit().await;
 | 
			
		||||
        return Err(HandlerUsed.into());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let text = match msg.text() {
 | 
			
		||||
        Some(text) => text.trim(),
 | 
			
		||||
        None => {
 | 
			
		||||
            let msg = bot
 | 
			
		||||
                .send_message(
 | 
			
		||||
                    msg.chat.id,
 | 
			
		||||
                    "Couldn't get the text of the message. Send the name again",
 | 
			
		||||
                )
 | 
			
		||||
                .reply_markup(account_list_markup(user_id, &db).await?)
 | 
			
		||||
                .await?;
 | 
			
		||||
            handler.previous = MessageIds::from(&msg);
 | 
			
		||||
            return Ok(());
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    if text == "/cancel" {
 | 
			
		||||
        dialogue.exit().await?;
 | 
			
		||||
        handler
 | 
			
		||||
            .previous
 | 
			
		||||
            .alter_message(&bot, "Successfully cancelled", deletion_markup(), None)
 | 
			
		||||
            .await?;
 | 
			
		||||
        return Ok(());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if !Account::exists(user_id, text, &db).await? {
 | 
			
		||||
        let msg = bot
 | 
			
		||||
            .send_message(msg.chat.id, "Account doesn't exists. Try again")
 | 
			
		||||
            .reply_markup(account_list_markup(user_id, &db).await?)
 | 
			
		||||
            .await?;
 | 
			
		||||
        handler.previous = MessageIds::from(&msg);
 | 
			
		||||
        return Ok(());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let func = handler.func.take().unwrap();
 | 
			
		||||
    let text = text.to_owned();
 | 
			
		||||
 | 
			
		||||
    if let Err(err) = func(bot, msg, db, dialogue.clone(), handler.previous, text).await {
 | 
			
		||||
        let _ = dialogue.exit().await;
 | 
			
		||||
        return Err(err);
 | 
			
		||||
    }
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
@@ -39,7 +39,7 @@ impl MessageIds {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        match edit.send_ref().await {
 | 
			
		||||
            Ok(msg) => return Ok(()),
 | 
			
		||||
            Ok(_) => return Ok(()),
 | 
			
		||||
            Err(RequestError::Api(_)) => (),
 | 
			
		||||
            Err(err) => return Err(err.into()),
 | 
			
		||||
        };
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,6 @@
 | 
			
		||||
//! This module consists of endpoints to handle the state
 | 
			
		||||
 | 
			
		||||
mod generic;
 | 
			
		||||
mod get_existing_name;
 | 
			
		||||
mod get_login;
 | 
			
		||||
mod get_master_pass;
 | 
			
		||||
mod get_new_master_pass;
 | 
			
		||||
@@ -10,7 +9,6 @@ mod get_password;
 | 
			
		||||
mod get_user;
 | 
			
		||||
mod handler;
 | 
			
		||||
 | 
			
		||||
pub use get_existing_name::get_existing_name;
 | 
			
		||||
pub use get_login::get_login;
 | 
			
		||||
pub use get_master_pass::get_master_pass;
 | 
			
		||||
pub use get_new_master_pass::get_new_master_pass;
 | 
			
		||||
@@ -26,7 +24,6 @@ use teloxide::dispatching::dialogue::InMemStorage;
 | 
			
		||||
pub enum State {
 | 
			
		||||
    #[default]
 | 
			
		||||
    Start,
 | 
			
		||||
    GetExistingName(PackagedHandler<String>),
 | 
			
		||||
    GetNewName(PackagedHandler<String>),
 | 
			
		||||
    GetMasterPass(PackagedHandler<String>),
 | 
			
		||||
    GetNewMasterPass(PackagedHandler<String>),
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										11
									
								
								src/utils.rs
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								src/utils.rs
									
									
									
									
									
								
							@@ -16,3 +16,14 @@ pub fn validate_field(field: &str) -> bool {
 | 
			
		||||
        .chars()
 | 
			
		||||
        .all(|char| !['`', '\\', '\n', '\t'].contains(&char))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub async fn name_from_hash(
 | 
			
		||||
    db: &DatabaseConnection,
 | 
			
		||||
    user_id: u64,
 | 
			
		||||
    hash: &[u8],
 | 
			
		||||
) -> crate::Result<Option<String>> {
 | 
			
		||||
    let hash = hex::encode(hash);
 | 
			
		||||
    Account::get_name_by_hash(user_id, hash, db)
 | 
			
		||||
        .await
 | 
			
		||||
        .map_err(Into::into)
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user