use crate::prelude::*; use base64::{Engine as _, engine::general_purpose::STANDARD_NO_PAD as B64_ENGINE}; use itertools::Itertools; use sha2::{Digest, Sha256}; use teloxide::types::{InlineKeyboardButton, InlineKeyboardMarkup}; use tokio::task::spawn_blocking; pub fn menu_markup_sync( command: &str, names: impl IntoIterator, ) -> InlineKeyboardMarkup { let names = names .into_iter() .map(|name| { let hash = ::digest(name.as_bytes()); let mut data = command.to_owned(); data.reserve(44); data.push(' '); B64_ENGINE.encode_string(hash, &mut data); InlineKeyboardButton::callback(name, data) }) .chunks(3); InlineKeyboardMarkup::new(&names) } pub async fn menu_markup( command: impl Into + Send, user_id: u64, db: &Pool, ) -> crate::Result { let command: String = command.into(); let names: Vec = Account::get_names(user_id, db).try_collect().await?; spawn_blocking(move || menu_markup_sync(&command, names)) .await .map_err(Into::into) } fn make_button(text: &str, command: &str, param: &str) -> InlineKeyboardButton { let mut data = command.to_owned(); data.reserve(param.len() + 1); data.push(' '); data.push_str(param); InlineKeyboardButton::callback(text, data) } pub fn account_markup(name: &str, is_encrypted: bool, locale: LocaleRef) -> InlineKeyboardMarkup { let mut hash = [0; 43]; B64_ENGINE .encode_slice(::digest(name), &mut hash) .unwrap(); let hash = std::str::from_utf8(&hash).unwrap(); let encryption_button = if is_encrypted { (&locale.decrypt_button, "decrypt") } else { (&locale.hide_button, "get") }; let main_buttons = [ (&locale.change_name_button, "an"), (&locale.change_login_button, "al"), (&locale.change_password_button, "ap"), (&locale.delete_account_button, "delete0"), encryption_button, ] .into_iter() .map(|(text, command)| make_button(text, command, hash)) .chunks(2); let menu_button = InlineKeyboardButton::callback(&locale.menu_button, "get_menu"); InlineKeyboardMarkup::new(&main_buttons).append_row([menu_button]) } pub fn language_markup() -> InlineKeyboardMarkup { let languages = [("🇷🇺 Русский", "ru"), ("🇬🇧 English", "en")] .into_iter() .map(|(text, param)| make_button(text, "change_locale", param)) .chunks(2); InlineKeyboardMarkup::new(&languages) } /// Creates a markup with a "Delete message" button. /// This markup should be added for all messages that won't be deleted afterwards pub fn deletion_markup(locale: LocaleRef) -> InlineKeyboardMarkup { let button = InlineKeyboardButton::callback(&locale.delete_message_button, "delete_message"); InlineKeyboardMarkup::new([[button]]) }