Add per-user default search setting

This commit is contained in:
2026-02-16 22:00:19 +01:00
parent a3ab5e9508
commit fb4ef7e952
6 changed files with 359 additions and 20 deletions

View File

@@ -3,12 +3,14 @@ pub mod commands;
use std::collections::HashSet;
use smallvec::SmallVec;
use smartstring::alias::String as SmartString;
use crate::bots::{
approved_bot::{
services::user_settings::{
create_or_update_user_settings, get_langs, get_user_or_default_lang_codes, Lang,
create_or_update_user_settings, get_langs, get_user_or_default_lang_codes,
get_user_settings, DefaultSearchType, Lang,
},
tools::filter_callback_query,
},
@@ -23,18 +25,28 @@ use teloxide::{
use self::{callback_data::SettingsCallbackData, commands::SettingsCommand};
async fn settings_handler(message: Message, bot: CacheMe<Throttle<Bot>>) -> BotHandlerInternal {
let keyboard = InlineKeyboardMarkup {
inline_keyboard: vec![vec![InlineKeyboardButton {
text: "Языки".to_string(),
kind: teloxide::types::InlineKeyboardButtonKind::CallbackData(
SettingsCallbackData::Settings.to_string(),
),
}]],
};
fn get_main_settings_keyboard() -> InlineKeyboardMarkup {
InlineKeyboardMarkup {
inline_keyboard: vec![
vec![InlineKeyboardButton {
text: "Языки".to_string(),
kind: teloxide::types::InlineKeyboardButtonKind::CallbackData(
SettingsCallbackData::Settings.to_string(),
),
}],
vec![InlineKeyboardButton {
text: "Поиск по умолчанию".to_string(),
kind: teloxide::types::InlineKeyboardButtonKind::CallbackData(
SettingsCallbackData::DefaultSearchMenu.to_string(),
),
}],
],
}
}
async fn settings_handler(message: Message, bot: CacheMe<Throttle<Bot>>) -> BotHandlerInternal {
bot.send_message(message.chat.id, "Настройки")
.reply_markup(keyboard)
.reply_markup(get_main_settings_keyboard())
.send()
.await?;
@@ -71,6 +83,65 @@ fn get_lang_keyboard(
}
}
fn get_default_search_keyboard(current: Option<DefaultSearchType>) -> InlineKeyboardMarkup {
let check = |v: DefaultSearchType| if current == Some(v) { "" } else { "" };
InlineKeyboardMarkup {
inline_keyboard: vec![
vec![InlineKeyboardButton {
text: format!("Книга{}", check(DefaultSearchType::Book)),
kind: teloxide::types::InlineKeyboardButtonKind::CallbackData(
SettingsCallbackData::DefaultSearch {
value: "book".into(),
}
.to_string(),
),
}],
vec![InlineKeyboardButton {
text: format!("Автор{}", check(DefaultSearchType::Author)),
kind: teloxide::types::InlineKeyboardButtonKind::CallbackData(
SettingsCallbackData::DefaultSearch {
value: "author".into(),
}
.to_string(),
),
}],
vec![InlineKeyboardButton {
text: format!("Серия{}", check(DefaultSearchType::Series)),
kind: teloxide::types::InlineKeyboardButtonKind::CallbackData(
SettingsCallbackData::DefaultSearch {
value: "series".into(),
}
.to_string(),
),
}],
vec![InlineKeyboardButton {
text: format!("Переводчик{}", check(DefaultSearchType::Translator)),
kind: teloxide::types::InlineKeyboardButtonKind::CallbackData(
SettingsCallbackData::DefaultSearch {
value: "translator".into(),
}
.to_string(),
),
}],
vec![InlineKeyboardButton {
text: format!("Не выбрано{}", if current.is_none() { "" } else { "" }),
kind: teloxide::types::InlineKeyboardButtonKind::CallbackData(
SettingsCallbackData::DefaultSearch {
value: "none".into(),
}
.to_string(),
),
}],
vec![InlineKeyboardButton {
text: "← Назад".to_string(),
kind: teloxide::types::InlineKeyboardButtonKind::CallbackData(
SettingsCallbackData::DefaultSearchBack.to_string(),
),
}],
],
}
}
async fn settings_callback_handler(
cq: CallbackQuery,
bot: CacheMe<Throttle<Bot>>,
@@ -89,6 +160,72 @@ async fn settings_callback_handler(
let user = cq.from;
match &callback_data {
SettingsCallbackData::DefaultSearchMenu => {
let current = get_user_settings(user.id).await.ok().flatten();
let current_default = current.as_ref().and_then(|s| s.default_search);
let keyboard = get_default_search_keyboard(current_default);
bot.edit_message_text(message.chat().id, message.id(), "Поиск по умолчанию")
.reply_markup(keyboard)
.send()
.await?;
bot.answer_callback_query(cq.id).send().await?;
return Ok(());
}
SettingsCallbackData::DefaultSearchBack => {
bot.edit_message_text(message.chat().id, message.id(), "Настройки")
.reply_markup(get_main_settings_keyboard())
.send()
.await?;
bot.answer_callback_query(cq.id).send().await?;
return Ok(());
}
SettingsCallbackData::DefaultSearch { value } => {
let current = get_user_settings(user.id).await.ok().flatten();
let allowed_langs: SmallVec<[SmartString; 3]> = match current {
Some(s) => s.allowed_langs.into_iter().map(|l| l.code).collect(),
None => get_user_or_default_lang_codes(user.id).await,
};
let default_search = if value.as_str() == "none" {
None
} else if let Some(t) = DefaultSearchType::from_api_str(value.as_str()) {
Some(t)
} else {
bot.answer_callback_query(cq.id).send().await?;
return Ok(());
};
if create_or_update_user_settings(
user.id,
&user.last_name.unwrap_or("".to_string()),
&user.first_name,
user.username.as_deref().unwrap_or(""),
&me.username.clone().unwrap(),
allowed_langs,
default_search,
)
.await
.is_err()
{
bot.answer_callback_query(cq.id)
.text("Ошибка! Попробуйте заново(")
.show_alert(true)
.send()
.await?;
return Ok(());
}
bot.edit_message_text(message.chat().id, message.id(), "Настройки")
.reply_markup(get_main_settings_keyboard())
.send()
.await?;
bot.answer_callback_query(cq.id)
.text("Готово")
.send()
.await?;
return Ok(());
}
_ => {}
}
let allowed_langs = get_user_or_default_lang_codes(user.id).await;
let mut allowed_langs_set: HashSet<SmartString> = HashSet::new();
@@ -104,6 +241,7 @@ async fn settings_callback_handler(
SettingsCallbackData::Off { code } => {
allowed_langs_set.remove(&code);
}
_ => {}
};
if allowed_langs_set.is_empty() {
@@ -116,6 +254,9 @@ async fn settings_callback_handler(
return Ok(());
}
let current_settings = get_user_settings(user.id).await.ok().flatten();
let default_search = current_settings.as_ref().and_then(|s| s.default_search);
if let Err(err) = create_or_update_user_settings(
user.id,
&user.last_name.unwrap_or("".to_string()),
@@ -123,6 +264,7 @@ async fn settings_callback_handler(
&user.username.unwrap_or("".to_string()),
&me.username.clone().unwrap(),
allowed_langs_set.clone().into_iter().collect(),
default_search,
)
.await
{