diff --git a/.gitignore b/.gitignore index 4aefd7c..ff0f10a 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ src/entity.example /target .env .env.deploy +.claude diff --git a/Justfile b/Justfile index 4fa035f..d02ce9a 100644 --- a/Justfile +++ b/Justfile @@ -59,3 +59,6 @@ run: watch: cargo watch -s 'just run' + +lazysql: + lazysql 'postgresql://postgres:example@localhost:5432/postgres?sslmode=disable' diff --git a/src/telegram/actions/admin_users/details.rs b/src/telegram/actions/admin_users/details.rs index 3e8937d..5871fd8 100644 --- a/src/telegram/actions/admin_users/details.rs +++ b/src/telegram/actions/admin_users/details.rs @@ -19,7 +19,6 @@ use crate::telegram::inline_buttons_admin::{ }; use crate::user::UserState; use crate::utils::DurationPrettyFormat as _; -use crate::utils::teloxide::CallbackQueryExt as _; #[tracing::instrument(skip_all, fields(user_id = %state.user_id(), target_user_id = %user_id))] pub async fn handle_command( @@ -53,21 +52,14 @@ pub async fn handle_command( pub async fn handle_inline( app: &'static App, state: &UserState, - q: CallbackQuery, + _q: CallbackQuery, + m: Message, user_id: String, page: u64, sort_by: AdminUsersSortBy, sort_order: AdminUsersSortOrder, status_filter: Option, ) -> anyhow::Result<()> { - let Some(message) = q.get_message() else { - app.bot() - .answer_callback_query(q.id.clone()) - .text("Inaccessible Message") - .await?; - return Ok(()); - }; - let text = format_user_details(app, &user_id).await?; let keyboard = InlineKeyboardMarkup::new(vec![vec![ @@ -80,10 +72,7 @@ pub async fn handle_inline( .into_inline_keyboard_button(state.locale()), ]]); - app.bot() - .edit_text(&message, text) - .reply_markup(keyboard) - .await?; + app.bot().edit_text(&m, text).reply_markup(keyboard).await?; Ok(()) } diff --git a/src/telegram/actions/admin_users/list.rs b/src/telegram/actions/admin_users/list.rs index 76c4aae..c84bb68 100644 --- a/src/telegram/actions/admin_users/list.rs +++ b/src/telegram/actions/admin_users/list.rs @@ -16,7 +16,6 @@ use crate::telegram::inline_buttons_admin::{ AdminUsersSortOrder, }; use crate::user::UserState; -use crate::utils::teloxide::CallbackQueryExt as _; const USERS_PER_PAGE: u64 = 10; @@ -45,31 +44,21 @@ pub async fn handle_command( } #[tracing::instrument(skip_all, fields(user_id = %state.user_id(), %page, ?sort_by, ?sort_order, ?status_filter))] +#[allow(clippy::too_many_arguments)] pub async fn handle_inline( app: &'static App, state: &UserState, - q: CallbackQuery, + _q: CallbackQuery, + m: Message, page: u64, sort_by: AdminUsersSortBy, sort_order: AdminUsersSortOrder, status_filter: Option, ) -> anyhow::Result<()> { - let Some(message) = q.get_message() else { - app.bot() - .answer_callback_query(q.id.clone()) - .text("Inaccessible Message") - .await?; - - return Ok(()); - }; - let (text, keyboard) = build_users_page(app, state, page, sort_by, sort_order, status_filter).await?; - app.bot() - .edit_text(&message, text) - .reply_markup(keyboard) - .await?; + app.bot().edit_text(&m, text).reply_markup(keyboard).await?; Ok(()) } diff --git a/src/telegram/actions/ai_slop_detection.rs b/src/telegram/actions/ai_slop_detection.rs index 9174b0d..22bf3d7 100644 --- a/src/telegram/actions/ai_slop_detection.rs +++ b/src/telegram/actions/ai_slop_detection.rs @@ -1,9 +1,5 @@ use sea_orm::Iterable as _; -use teloxide::payloads::{ - AnswerCallbackQuerySetters as _, - EditMessageReplyMarkupSetters as _, - SendMessageSetters as _, -}; +use teloxide::payloads::{EditMessageReplyMarkupSetters as _, SendMessageSetters as _}; use teloxide::prelude::Requester as _; use teloxide::sugar::bot::BotMessagesExt as _; use teloxide::types::{ @@ -11,6 +7,7 @@ use teloxide::types::{ ChatId, InlineKeyboardButton, InlineKeyboardMarkup, + Message, ReplyMarkup, }; @@ -20,31 +17,22 @@ use crate::services::UserService; use crate::telegram::handlers::HandleStatus; use crate::telegram::inline_buttons::InlineButtons; use crate::user::UserState; -use crate::utils::teloxide::CallbackQueryExt as _; #[tracing::instrument(skip_all, fields(user_id = %state.user_id()))] pub async fn handle_inline( app: &'static App, state: &UserState, q: CallbackQuery, + m: Message, status: UserAISlopDetection, ) -> anyhow::Result<()> { - let Some(message) = q.get_message() else { - app.bot() - .answer_callback_query(q.id.clone()) - .text("Inaccessible Message") - .await?; - - return Ok(()); - }; - app.bot().answer_callback_query(q.id).await?; if status != state.user().cfg_ai_slop_detection { UserService::set_cfg_ai_slop_detection(app.db(), state.user_id(), status).await?; app.bot() - .edit_reply_markup(&message) + .edit_reply_markup(&m) .reply_markup(InlineKeyboardMarkup::new(get_keyboard( status, state.locale(), diff --git a/src/telegram/actions/analyze.rs b/src/telegram/actions/analyze.rs index fdd4a22..18aaf83 100644 --- a/src/telegram/actions/analyze.rs +++ b/src/telegram/actions/analyze.rs @@ -12,7 +12,7 @@ use teloxide::payloads::{ }; use teloxide::prelude::Requester as _; use teloxide::sugar::bot::BotMessagesExt as _; -use teloxide::types::{CallbackQuery, InlineKeyboardMarkup}; +use teloxide::types::{CallbackQuery, InlineKeyboardMarkup, Message}; use crate::app::{AIConfig, App}; use crate::lyrics::SearchResult as _; @@ -31,7 +31,6 @@ use crate::telegram::MESSAGE_MAX_LEN; use crate::telegram::inline_buttons::InlineButtons; use crate::telegram::utils::link_preview_small_top; use crate::user::UserState; -use crate::utils::teloxide::CallbackQueryExt as _; use crate::utils::{DurationPrettyFormat as _, StringUtils as _}; #[tracing::instrument(skip_all, fields(user_id = %state.user_id(), %track_id))] @@ -39,17 +38,9 @@ pub async fn handle_inline( app: &'static App, state: &UserState, q: CallbackQuery, + m: Message, track_id: &str, ) -> anyhow::Result<()> { - let Some(message) = q.get_message() else { - app.bot() - .answer_callback_query(q.id.clone()) - .text("Inaccessible Message") - .await?; - - return Ok(()); - }; - let Some(config) = app.ai() else { app.bot() .answer_callback_query(q.id) @@ -91,10 +82,7 @@ pub async fn handle_inline( .await? else { app.bot() - .edit_text( - &message, - t!("analysis.lyrics-not-found", locale = state.locale()), - ) + .edit_text(&m, t!("analysis.lyrics-not-found", locale = state.locale())) .await?; return Ok(()); @@ -102,7 +90,7 @@ pub async fn handle_inline( app.bot() .edit_text( - &message, + &m, t!( "analysis.waiting", locale = state.locale(), @@ -116,7 +104,7 @@ pub async fn handle_inline( let res = perform(app, state, config, &track, &hit.lyrics()).await; // I don't care about error - app.bot().delete(&message).await.ok(); + app.bot().delete(&m).await.ok(); match res { Ok(()) => { diff --git a/src/telegram/actions/dislike.rs b/src/telegram/actions/dislike.rs index c2ffee3..75429f4 100644 --- a/src/telegram/actions/dislike.rs +++ b/src/telegram/actions/dislike.rs @@ -13,7 +13,6 @@ use crate::telegram::handlers::HandleStatus; use crate::telegram::utils::link_preview_small_top; use crate::user::UserState; use crate::utils::DurationPrettyFormat as _; -use crate::utils::teloxide::CallbackQueryExt as _; #[tracing::instrument(skip_all, fields(user_id = %state.user_id()))] pub async fn handle( @@ -80,7 +79,8 @@ pub async fn handle( pub async fn handle_inline( app: &'static App, state: &UserState, - q: CallbackQuery, + _q: CallbackQuery, + m: Message, track_id: &str, ) -> anyhow::Result<()> { let track = state @@ -95,17 +95,8 @@ pub async fn handle_inline( let keyboard = InlineButtons::from_track_status(TrackStatus::Disliked, track.id(), state.locale()); - let Some(message) = q.get_message() else { - app.bot() - .answer_callback_query(q.id.clone()) - .text("Inaccessible Message") - .await?; - - return Ok(()); - }; - app.bot() - .edit_text(&message, compose_message_text(&track, state.locale())) + .edit_text(&m, compose_message_text(&track, state.locale())) .link_preview_options(link_preview_small_top(track.url())) .reply_markup(InlineKeyboardMarkup::new(keyboard)) .await?; diff --git a/src/telegram/actions/ignore.rs b/src/telegram/actions/ignore.rs index 136ef31..a53d374 100644 --- a/src/telegram/actions/ignore.rs +++ b/src/telegram/actions/ignore.rs @@ -9,24 +9,15 @@ use crate::entity::prelude::*; use crate::services::TrackStatusService; use crate::telegram::utils::link_preview_small_top; use crate::user::UserState; -use crate::utils::teloxide::CallbackQueryExt as _; #[tracing::instrument(skip_all, fields(user_id = %state.user_id(), %track_id))] pub async fn handle_inline( app: &'static App, state: &UserState, - q: CallbackQuery, + _q: CallbackQuery, + m: Message, track_id: &str, ) -> anyhow::Result<()> { - let Some(message) = q.get_message() else { - app.bot() - .answer_callback_query(q.id.clone()) - .text("Inaccessible Message") - .await?; - - return Ok(()); - }; - let track = state .spotify() .await @@ -41,7 +32,7 @@ pub async fn handle_inline( app.bot() .edit_text( - &message, + &m, t!( "actions.ignore", track_link = track.track_tg_link(), diff --git a/src/telegram/actions/magic.rs b/src/telegram/actions/magic.rs index 526036b..8dd678c 100644 --- a/src/telegram/actions/magic.rs +++ b/src/telegram/actions/magic.rs @@ -9,7 +9,7 @@ use teloxide::payloads::{ }; use teloxide::prelude::Requester as _; use teloxide::sugar::bot::BotMessagesExt as _; -use teloxide::types::{CallbackQuery, ChatId, InlineKeyboardMarkup, ReplyMarkup}; +use teloxide::types::{CallbackQuery, ChatId, InlineKeyboardMarkup, Message, ReplyMarkup}; use crate::app::App; use crate::services::{RateLimitAction, RateLimitOutput, RateLimitService, UserService}; @@ -20,7 +20,6 @@ use crate::telegram::inline_buttons::InlineButtons; use crate::telegram::utils::link_preview_small_top; use crate::user::UserState; use crate::utils::DurationPrettyFormat as _; -use crate::utils::teloxide::CallbackQueryExt as _; #[allow(clippy::significant_drop_tightening)] #[tracing::instrument(skip_all, fields(user_id = %state.user_id()))] @@ -66,16 +65,8 @@ pub async fn handle_inline( app: &'static App, state: &UserState, q: CallbackQuery, + m: Message, ) -> anyhow::Result<()> { - let Some(message) = q.get_message() else { - app.bot() - .answer_callback_query(q.id.clone()) - .text("Inaccessible Message") - .await?; - - return Ok(()); - }; - if !state.is_spotify_authed().await { actions::login::send_login_invite(app, state).await?; @@ -109,7 +100,7 @@ pub async fn handle_inline( app.bot() .edit_text( - &message, + &m, t!("magic.generating", header = header, locale = state.locale()), ) .await?; @@ -120,7 +111,7 @@ pub async fn handle_inline( Ok(playlist) => { app.bot() .edit_text( - &message, + &m, t!( "magic.generated", header = header, @@ -137,7 +128,7 @@ pub async fn handle_inline( Err(err) => { app.bot() .edit_text( - &message, + &m, t!("magic.failed", header = header, locale = state.locale()), ) .await?; diff --git a/src/telegram/actions/recommendasion.rs b/src/telegram/actions/recommendasion.rs index 0fda9b0..ed923eb 100644 --- a/src/telegram/actions/recommendasion.rs +++ b/src/telegram/actions/recommendasion.rs @@ -27,7 +27,7 @@ use teloxide::payloads::{ use teloxide::prelude::Requester as _; use teloxide::sugar::bot::BotMessagesExt as _; use teloxide::sugar::request::RequestLinkPreviewExt as _; -use teloxide::types::{CallbackQuery, ChatId, InlineKeyboardMarkup, ReplyMarkup}; +use teloxide::types::{CallbackQuery, ChatId, InlineKeyboardMarkup, Message, ReplyMarkup}; use crate::app::{AIConfig, App}; use crate::entity::prelude::TrackStatus; @@ -43,7 +43,6 @@ use crate::telegram::actions; use crate::telegram::handlers::HandleStatus; use crate::telegram::inline_buttons::InlineButtons; use crate::user::{SpotifyWrapperType, UserState}; -use crate::utils::teloxide::CallbackQueryExt as _; use crate::utils::{DurationPrettyFormat as _, StringUtils as _}; #[derive(Default, Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] @@ -152,16 +151,8 @@ pub async fn handle_inline( app: &'static App, state: &UserState, q: CallbackQuery, + m: Message, ) -> anyhow::Result<()> { - let Some(message) = q.get_message() else { - app.bot() - .answer_callback_query(q.id.clone()) - .text("Inaccessible Message") - .await?; - - return Ok(()); - }; - if !state.is_spotify_authed().await { actions::login::send_login_invite(app, state).await?; @@ -170,10 +161,7 @@ pub async fn handle_inline( let Some(config) = app.ai() else { app.bot() - .edit_text( - &message, - t!("recommendasion.disabled", locale = state.locale()), - ) + .edit_text(&m, t!("recommendasion.disabled", locale = state.locale())) .await?; return Ok(()); @@ -191,7 +179,7 @@ pub async fn handle_inline( else { app.bot() .edit_text( - &message, + &m, t!("recommendasion.device-not-found", locale = state.locale()), ) .reply_markup(InlineKeyboardMarkup::new(vec![vec![ @@ -224,7 +212,7 @@ pub async fn handle_inline( app.bot() .edit_text( - &message, + &m, t!( "recommendasion.collecting-favorites", locale = state.locale() @@ -243,10 +231,7 @@ pub async fn handle_inline( }; app.bot() - .edit_text( - &message, - t!("recommendasion.ask-ai", locale = state.locale()), - ) + .edit_text(&m, t!("recommendasion.ask-ai", locale = state.locale())) .await?; let recommendations = get_recommendations(app, state, config, &mut user_data).await?; @@ -255,10 +240,7 @@ pub async fn handle_inline( / (recommendations.slop.len() + recommendations.recommended.len() + 1); app.bot() - .edit_text( - &message, - t!("recommendasion.queue", locale = state.locale()), - ) + .edit_text(&m, t!("recommendasion.queue", locale = state.locale())) .await?; let mut recommendation_links = vec![]; @@ -294,7 +276,7 @@ pub async fn handle_inline( ); app.bot() - .edit_text(&message, text) + .edit_text(&m, text) .disable_link_preview(true) .reply_markup(InlineKeyboardMarkup::new(vec![vec![ InlineButtons::Recommendasion.into_inline_keyboard_button(state.locale()), diff --git a/src/telegram/actions/skippage.rs b/src/telegram/actions/skippage.rs index bb24a4b..1b7217d 100644 --- a/src/telegram/actions/skippage.rs +++ b/src/telegram/actions/skippage.rs @@ -1,12 +1,8 @@ use chrono::Duration; -use teloxide::payloads::{ - AnswerCallbackQuerySetters as _, - EditMessageTextSetters as _, - SendMessageSetters as _, -}; +use teloxide::payloads::{EditMessageTextSetters as _, SendMessageSetters as _}; use teloxide::prelude::Requester as _; use teloxide::sugar::bot::BotMessagesExt as _; -use teloxide::types::{CallbackQuery, ChatId, InlineKeyboardMarkup, ReplyMarkup}; +use teloxide::types::{CallbackQuery, ChatId, InlineKeyboardMarkup, Message, ReplyMarkup}; use crate::app::App; use crate::services::{SkippageService, UserService}; @@ -15,24 +11,15 @@ use crate::telegram::commands::UserCommandDisplay; use crate::telegram::handlers::HandleStatus; use crate::telegram::inline_buttons::InlineButtons; use crate::user::UserState; -use crate::utils::teloxide::CallbackQueryExt as _; #[tracing::instrument(skip_all, fields(user_id = %state.user_id()))] pub async fn handle_inline( app: &'static App, state: &UserState, - q: CallbackQuery, + _q: CallbackQuery, + m: Message, to_enable: bool, ) -> anyhow::Result<()> { - let Some(message) = q.get_message() else { - app.bot() - .answer_callback_query(q.id.clone()) - .text("Inaccessible Message") - .await?; - - return Ok(()); - }; - UserService::set_cfg_skippage_enabled(app.db(), state.user_id(), to_enable).await?; let days = Duration::seconds(state.user().cfg_skippage_secs).num_days(); @@ -48,7 +35,7 @@ pub async fn handle_inline( app.bot() .edit_text( - &message, + &m, t!( "skippage.main", locale = state.locale(), diff --git a/src/telegram/actions/song_links.rs b/src/telegram/actions/song_links.rs index b42a702..987120f 100644 --- a/src/telegram/actions/song_links.rs +++ b/src/telegram/actions/song_links.rs @@ -1,31 +1,21 @@ use itertools::Itertools as _; use rspotify::model::TrackId; -use teloxide::payloads::{AnswerCallbackQuerySetters as _, EditMessageTextSetters as _}; -use teloxide::prelude::Requester as _; +use teloxide::payloads::EditMessageTextSetters as _; use teloxide::sugar::bot::BotMessagesExt as _; -use teloxide::types::CallbackQuery; +use teloxide::types::{CallbackQuery, Message}; use crate::app::App; use crate::telegram::utils::link_preview_small_top; use crate::user::UserState; -use crate::utils::teloxide::CallbackQueryExt as _; #[tracing::instrument(skip_all, fields(user_id = %state.user_id(), %track_id))] pub async fn handle_inline( app: &'static App, state: &UserState, - q: CallbackQuery, + _q: CallbackQuery, + m: Message, track_id: &str, ) -> anyhow::Result<()> { - let Some(message) = q.get_message() else { - app.bot() - .answer_callback_query(q.id.clone()) - .text("Inaccessible Message") - .await?; - - return Ok(()); - }; - let mut redis_conn = app.redis_conn().await?; let track = state @@ -36,7 +26,7 @@ pub async fn handle_inline( app.bot() .edit_text( - &message, + &m, t!( "song-links.fetch", track_name = track.track_tg_link(), @@ -58,7 +48,7 @@ pub async fn handle_inline( app.bot() .edit_text( - &message, + &m, t!( "song-links.result", track_name = track.track_tg_link(), diff --git a/src/telegram/actions/word_definition.rs b/src/telegram/actions/word_definition.rs index 2b0ad60..cb5e74e 100644 --- a/src/telegram/actions/word_definition.rs +++ b/src/telegram/actions/word_definition.rs @@ -9,7 +9,6 @@ use crate::services::{WordDefinitionService, WordStatsService}; use crate::telegram::commands_admin::AdminCommandDisplay; use crate::telegram::handlers::HandleStatus; use crate::telegram::inline_buttons_admin::AdminInlineButtons; -use crate::utils::teloxide::CallbackQueryExt as _; #[tracing::instrument(skip_all, fields(%locale, %word))] async fn generate_and_send_definition( @@ -100,20 +99,12 @@ pub async fn handle_definition( #[tracing::instrument(skip_all, fields(%locale, %word))] pub async fn handle_inline_regenerate( app: &'static App, - q: CallbackQuery, + _q: CallbackQuery, + m: Message, locale: String, word: String, ) -> anyhow::Result<()> { - let Some(message) = q.get_message() else { - app.bot() - .answer_callback_query(q.id.clone()) - .text("Inaccessible Message") - .await?; - - return Ok(()); - }; - - generate_and_send_definition(app, &message, locale, word, true).await?; + generate_and_send_definition(app, &m, locale, word, true).await?; Ok(()) } @@ -133,21 +124,13 @@ pub async fn handle_list( pub async fn handle_inline_list( app: &'static App, q: CallbackQuery, + m: Message, locale_filter: String, page: usize, ) -> anyhow::Result<()> { app.bot().answer_callback_query(q.id.clone()).await?; - let Some(message) = q.get_message() else { - app.bot() - .answer_callback_query(q.id.clone()) - .text("Inaccessible Message") - .await?; - - return Ok(()); - }; - - send_definitions_page(app, message.chat.id, Some(message), locale_filter, page).await?; + send_definitions_page(app, m.chat.id, Some(m), locale_filter, page).await?; Ok(()) } diff --git a/src/telegram/handlers/inline_buttons.rs b/src/telegram/handlers/inline_buttons.rs index 5e871a7..e68a443 100644 --- a/src/telegram/handlers/inline_buttons.rs +++ b/src/telegram/handlers/inline_buttons.rs @@ -13,7 +13,12 @@ use crate::user::UserState; user_id = %state.user_id(), ) )] -pub async fn handle(app: &'static App, state: &UserState, q: CallbackQuery) -> anyhow::Result<()> { +pub async fn handle( + app: &'static App, + state: &UserState, + q: CallbackQuery, + m: Message, +) -> anyhow::Result<()> { let data = q.data.as_ref().context("Callback needs data")?; let admin_button: Result = data.parse(); @@ -31,10 +36,10 @@ pub async fn handle(app: &'static App, state: &UserState, q: CallbackQuery) -> a match button { AdminInlineButtons::RegenerateWordDefinition { locale, word } => { - actions::word_definition::handle_inline_regenerate(app, q, locale, word).await?; + actions::word_definition::handle_inline_regenerate(app, q, m, locale, word).await?; }, AdminInlineButtons::WordDefinitionsPage { locale, page, .. } => { - actions::word_definition::handle_inline_list(app, q, locale, page).await?; + actions::word_definition::handle_inline_list(app, q, m, locale, page).await?; }, AdminInlineButtons::AdminUserSelect { user_id, @@ -48,6 +53,7 @@ pub async fn handle(app: &'static App, state: &UserState, q: CallbackQuery) -> a app, state, q, + m, user_id, page, sort_by, @@ -66,6 +72,7 @@ pub async fn handle(app: &'static App, state: &UserState, q: CallbackQuery) -> a app, state, q, + m, page, sort_by, sort_order, @@ -88,6 +95,7 @@ pub async fn handle(app: &'static App, state: &UserState, q: CallbackQuery) -> a app, state, q, + m, page, sort_by, sort_order, @@ -131,28 +139,28 @@ pub async fn handle(app: &'static App, state: &UserState, q: CallbackQuery) -> a match button { InlineButtons::Dislike(id) => { - actions::dislike::handle_inline(app, state, q, &id).await?; + actions::dislike::handle_inline(app, state, q, m, &id).await?; }, InlineButtons::Ignore(id) => { - actions::ignore::handle_inline(app, state, q, &id).await?; + actions::ignore::handle_inline(app, state, q, m, &id).await?; }, InlineButtons::Analyze(id) => { - actions::analyze::handle_inline(app, state, q, &id).await?; + actions::analyze::handle_inline(app, state, q, m, &id).await?; }, InlineButtons::SongLinks(id) => { - actions::song_links::handle_inline(app, state, q, &id).await?; + actions::song_links::handle_inline(app, state, q, m, &id).await?; }, InlineButtons::Magic => { - actions::magic::handle_inline(app, state, q).await?; + actions::magic::handle_inline(app, state, q, m).await?; }, InlineButtons::Recommendasion => { - actions::recommendasion::handle_inline(app, state, q).await?; + actions::recommendasion::handle_inline(app, state, q, m).await?; }, InlineButtons::SkippageEnable(to_enable) => { - actions::skippage::handle_inline(app, state, q, to_enable).await?; + actions::skippage::handle_inline(app, state, q, m, to_enable).await?; }, InlineButtons::AISlopDetection(status, _) => { - actions::ai_slop_detection::handle_inline(app, state, q, status).await?; + actions::ai_slop_detection::handle_inline(app, state, q, m, status).await?; }, } diff --git a/src/workers/bot.rs b/src/workers/bot.rs index 9cf043d..7f30915 100644 --- a/src/workers/bot.rs +++ b/src/workers/bot.rs @@ -1,4 +1,3 @@ -use indoc::formatdoc; use sea_orm::Iterable as _; use teloxide::prelude::*; use teloxide::sugar::request::RequestLinkPreviewExt as _; @@ -10,6 +9,7 @@ use crate::infrastructure::error_handler; use crate::services::UserService; use crate::telegram::commands::UserCommand; use crate::user::UserState; +use crate::utils::teloxide::CallbackQueryExt as _; use crate::{self as rustify}; #[tracing::instrument(skip_all, fields(user_id = %state.user_id()))] @@ -92,27 +92,49 @@ pub async fn work() { if !res.user_notified { app.bot().send_message( m.chat.id, - formatdoc!( - r#" - Sorry, error has happened :( - - Report an issue on GitHub - "# - ) + t!("error.general", locale = state.locale()) ) .disable_link_preview(true) .await?; } } - Ok(()) + anyhow::Ok(()) }), ) .branch(Update::filter_callback_query().endpoint( move |q: CallbackQuery| async { - let state = app.user_state(&q.from.id.to_string()).await?; + // Message can be None for: inline mode results, old messages (48+ hours), + // deleted messages, or inaccessible channels + let Some(m) = q.get_message() else { + app.bot() + .answer_callback_query(q.id.clone()) + .text("This message is too old or no longer accessible") + .show_alert(true) + .await?; + + return Ok(()); + }; + + let chat_id = m.chat.id; + + let state = app.user_state(&chat_id.to_string()).await?; - rustify::telegram::handlers::inline_buttons::handle(app, &state, q).await + let result = Box::pin(rustify::telegram::handlers::inline_buttons::handle(app, &state, q, m)).await; + + if let Err(mut err) = result { + let res = error_handler::handle(&mut err, app, state.user_id(), state.locale()).await; + if !res.user_notified { + app.bot().send_message( + chat_id, + t!("error.general", locale = state.locale()) + ) + .disable_link_preview(true) + .await?; + } + } + + Ok(()) }, ));