Skip to content
This repository was archived by the owner on Sep 29, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "fulturate"
version = "0.13.0"
version = "0.13.1"
edition = "2024"

[dependencies]
Expand Down
215 changes: 155 additions & 60 deletions src/bot/callbacks/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,21 @@ use crate::{
whisper::handle_whisper_callback,
},
commands::settings::update_settings_message,
modules::{registry::MOD_MANAGER, Owner},
modules::{Owner, registry::MOD_MANAGER},
},
core::{
config::Config,
services::speech_recognition::{back_handler, pagination_handler, summarization_handler},
},
errors::MyError,
};
use log::info;
use std::sync::Arc;
use teloxide::{
payloads::EditMessageTextSetters,
prelude::{CallbackQuery, Requester},
Bot,
payloads::{AnswerCallbackQuerySetters, EditMessageTextSetters},
prelude::{CallbackQuery, Requester},
};
use teloxide::payloads::AnswerCallbackQuerySetters;

pub mod cobalt_pagination;
pub mod delete;
Expand Down Expand Up @@ -71,115 +71,210 @@ fn parse_callback_data(data: &'_ str) -> Option<CallbackAction<'_>> {
if let Some(rest) = data.strip_prefix("module_select:") {
let parts: Vec<_> = rest.split(':').collect();
if parts.len() == 4
&& let Ok(commander_id) = parts[3].parse() {
return Some(CallbackAction::ModuleSelect {
owner_type: parts[0],
owner_id: parts[1],
module_key: parts[2],
commander_id,
});
}
&& let Ok(commander_id) = parts[3].parse()
{
return Some(CallbackAction::ModuleSelect {
owner_type: parts[0],
owner_id: parts[1],
module_key: parts[2],
commander_id,
});
}
}

if let Some(rest) = data.strip_prefix("settings_back:") {
let parts: Vec<_> = rest.split(':').collect();
if parts.len() == 3
&& let Ok(commander_id) = parts[2].parse() {
return Some(CallbackAction::SettingsBack {
owner_type: parts[0],
owner_id: parts[1],
commander_id,
});
}
&& let Ok(commander_id) = parts[2].parse()
{
return Some(CallbackAction::SettingsBack {
owner_type: parts[0],
owner_id: parts[1],
commander_id,
});
}
}

if let Some(module_key) = MOD_MANAGER.get_all_modules().iter().find_map(|m| {
data.starts_with(&format!("{}:settings:", m.key())).then_some(m.key())
data.starts_with(&format!("{}:settings:", m.key()))
.then_some(m.key())
}) {
let rest_with_id = data.strip_prefix(&format!("{}:settings:", module_key)).unwrap_or("");
let parts: Vec<_> = rest_with_id.rsplitn(2, ':').collect();
if parts.len() == 2
&& let Ok(commander_id) = parts[0].parse() {
let rest = parts[1];
return Some(CallbackAction::ModuleSettings {
module_key,
rest,
commander_id,
});
}
let full_rest = data
.strip_prefix(&format!("{}:settings:", module_key))
.unwrap_or_default();

if let Some((rest, id_str)) = full_rest.rsplit_once(':')
&& let Ok(commander_id) = id_str.parse()
{
return Some(CallbackAction::ModuleSettings {
module_key,
rest,
commander_id,
});
}

return Some(CallbackAction::ModuleSettings {
module_key,
rest: full_rest,
commander_id: 0,
});
}

if let Some(commander_id_str) = data.strip_prefix("delete_data:")
&& let Ok(commander_id) = commander_id_str.parse() {
return Some(CallbackAction::DeleteData { commander_id });
}
&& let Ok(commander_id) = commander_id_str.parse()
{
return Some(CallbackAction::DeleteData { commander_id });
}

if data.starts_with("delete_data_confirm:") { return Some(CallbackAction::DeleteDataConfirmation); }
if data.starts_with("delete_msg") { return Some(CallbackAction::DeleteMessage); }
if data.starts_with("delete_confirm:") { return Some(CallbackAction::DeleteConfirmation); }
if data.starts_with("summarize") { return Some(CallbackAction::Summarize); }
if data.starts_with("speech:page:") { return Some(CallbackAction::SpeechPage); }
if data.starts_with("back_to_full") { return Some(CallbackAction::BackToFull); }
if data.starts_with("whisper") { return Some(CallbackAction::Whisper); }
if data.starts_with("tr_") || data.starts_with("tr:") { return Some(CallbackAction::Translate); }
if data.starts_with("cobalt:") { return Some(CallbackAction::CobaltPagination); }
if data.starts_with("delete_data_confirm:") {
return Some(CallbackAction::DeleteDataConfirmation);
}
if data.starts_with("delete_msg") {
return Some(CallbackAction::DeleteMessage);
}
if data.starts_with("delete_confirm:") {
return Some(CallbackAction::DeleteConfirmation);
}
if data.starts_with("summarize") {
return Some(CallbackAction::Summarize);
}
if data.starts_with("speech:page:") {
return Some(CallbackAction::SpeechPage);
}
if data.starts_with("back_to_full") {
return Some(CallbackAction::BackToFull);
}
if data.starts_with("whisper") {
return Some(CallbackAction::Whisper);
}
if data.starts_with("tr_") || data.starts_with("tr:") {
return Some(CallbackAction::Translate);
}
if data.starts_with("cobalt:") {
return Some(CallbackAction::CobaltPagination);
}

None
}

pub async fn callback_query_handlers(bot: Bot, q: CallbackQuery) -> Result<(), MyError> {
let config = Arc::new(Config::new().await);

let Some(data) = &q.data else { return Ok(()); };
let Some(data) = &q.data else {
return Ok(());
};

match parse_callback_data(data) {
Some(CallbackAction::ModuleSelect { owner_type, owner_id, module_key, commander_id }) => {
Some(CallbackAction::ModuleSelect {
owner_type,
owner_id,
module_key,
commander_id,
}) => {
info!(
"module_select: id: {} | commander_id: {}",
q.from.clone().id.0,
commander_id
);
if q.from.id.0 != commander_id {
bot.answer_callback_query(q.id).text("❌ Вы не можете управлять этими настройками.").show_alert(true).await?;
bot.answer_callback_query(q.id)
.text("❌ Вы не можете управлять этими настройками.")
.show_alert(true)
.await?;
return Ok(());
}
if let (Some(module), Some(message)) = (MOD_MANAGER.get_module(module_key), &q.message) {
let owner = Owner { id: owner_id.to_string(), r#type: owner_type.to_string() };
if let (Some(module), Some(message)) = (MOD_MANAGER.get_module(module_key), &q.message)
{
let owner = Owner {
id: owner_id.to_string(),
r#type: owner_type.to_string(),
};
let (text, keyboard) = module.get_settings_ui(&owner, commander_id).await?;
bot.edit_message_text(message.chat().id, message.id(), text)
.reply_markup(keyboard)
.parse_mode(teloxide::types::ParseMode::Html)
.await?;
}
}
Some(CallbackAction::SettingsBack { owner_type, owner_id, commander_id }) => {
Some(CallbackAction::SettingsBack {
owner_type,
owner_id,
commander_id,
}) => {
info!(
"settings_back: id: {} | commander_id: {}",
q.from.clone().id.0,
commander_id
);
if q.from.id.0 != commander_id {
bot.answer_callback_query(q.id).text("❌ Вы не можете управлять этими настройками.").show_alert(true).await?;
bot.answer_callback_query(q.id)
.text("❌ Вы не можете управлять этими настройками.")
.show_alert(true)
.await?;
return Ok(());
}
if let Some(message) = q.message {
update_settings_message(bot, message, owner_id.to_string(), owner_type.to_string(), commander_id).await?;
update_settings_message(
bot,
message,
owner_id.to_string(),
owner_type.to_string(),
commander_id,
)
.await?;
}
}
Some(CallbackAction::ModuleSettings { module_key, rest, commander_id }) => {
Some(CallbackAction::ModuleSettings {
module_key,
rest,
commander_id,
}) => {
info!(
"module_settings: id: {} | commander_id: {}",
q.from.clone().id.0,
commander_id
);
if q.from.id.0 != commander_id {
bot.answer_callback_query(q.id).text("❌ Вы не можете управлять этими настройками.").show_alert(true).await?;
bot.answer_callback_query(q.id)
.text("❌ Вы не можете управлять этими настройками.")
.show_alert(true)
.await?;
return Ok(());
}
if let (Some(module), Some(message)) = (MOD_MANAGER.get_module(module_key), &q.message) {
if let (Some(module), Some(message)) = (MOD_MANAGER.get_module(module_key), &q.message)
{
let owner = Owner {
id: message.chat().id.to_string(),
r#type: (if message.chat().is_private() { "user" } else { "group" }).to_string(),
r#type: (if message.chat().is_private() {
"user"
} else {
"group"
})
.to_string(),
};
module.handle_callback(bot, &q, &owner, rest, commander_id).await?;
module
.handle_callback(bot, &q, &owner, rest, commander_id)
.await?;
}
}
Some(CallbackAction::DeleteData { commander_id }) => {
if q.from.id.0 != commander_id {
bot.answer_callback_query(q.id).text("❌ Вы не можете управлять этими настройками.").show_alert(true).await?;
bot.answer_callback_query(q.id)
.text("❌ Вы не можете управлять этими настройками.")
.show_alert(true)
.await?;
return Ok(());
}
handle_delete_data(bot, q).await?
}
Some(CallbackAction::CobaltPagination) => handle_cobalt_pagination(bot, q, config).await?,
Some(CallbackAction::DeleteDataConfirmation) => handle_delete_data_confirmation(bot, q).await?,
Some(CallbackAction::DeleteDataConfirmation) => {
handle_delete_data_confirmation(bot, q).await?
}
Some(CallbackAction::DeleteMessage) => handle_delete_request(bot, q).await?,
Some(CallbackAction::DeleteConfirmation) => handle_delete_confirmation(bot, q, &config).await?,
Some(CallbackAction::DeleteConfirmation) => {
handle_delete_confirmation(bot, q, &config).await?
}
Some(CallbackAction::Summarize) => summarization_handler(bot, q, &config).await?,
Some(CallbackAction::SpeechPage) => pagination_handler(bot, q, &config).await?,
Some(CallbackAction::BackToFull) => back_handler(bot, q, &config).await?,
Expand All @@ -195,4 +290,4 @@ pub async fn callback_query_handlers(bot: Bot, q: CallbackQuery) -> Result<(), M
}

Ok(())
}
}
2 changes: 1 addition & 1 deletion src/bot/inlines/cobalter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use teloxide::{
prelude::*,
types::{
InlineQuery, InlineQueryResult, InlineQueryResultArticle, InlineQueryResultPhoto,
InputMessageContent, InputMessageContentText, InputFile, InputMedia, InputMediaVideo
InputFile, InputMedia, InputMediaVideo, InputMessageContent, InputMessageContentText,
},
};
use url::Url;
Expand Down
5 changes: 3 additions & 2 deletions src/bot/modules/currency.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ impl Module for CurrencyModule {
return Ok(());
}

if parts.len() == 2 && parts[0] == "page" {
if parts.len() >= 2 && parts[0] == "page" {
let page = parts[1].parse::<usize>().unwrap_or(0);
let (text, keyboard) = self.get_paged_settings_ui(owner, page, commander_id).await?;
bot.edit_message_text(message.chat.id, message.id, text)
Expand All @@ -105,7 +105,7 @@ impl Module for CurrencyModule {
return Ok(());
}

if parts.len() == 2 && parts[0] == "toggle" {
if parts.len() >= 2 && parts[0] == "toggle" {
let currency_code = parts[1].to_string();
let mut settings: CurrencySettings =
Settings::get_module_settings(owner, self.key()).await?;
Expand Down Expand Up @@ -183,6 +183,7 @@ impl CurrencyModule {
.current_page(page)
.add_bottom_row(vec![back_button])
.set_callback_prefix(format!("{}:settings", self.key()))
.set_callback_formatter(move |p| format!("{}:settings:page:{}:{}", self.key(), p, commander_id))
.build(|currency| {
let is_selected = settings.selected_codes.contains(&currency.code);
let icon = if is_selected { "✅" } else { "❌" };
Expand Down