reminder-bot/bot/handlers/callbacks.py

261 lines
7.9 KiB
Python
Raw Permalink Normal View History

2025-12-19 11:19:54 +01:00
"""Handlers for inline button callbacks (done, snooze, pause, delete)."""
from aiogram import Router, F
from aiogram.types import CallbackQuery, Message
from sqlalchemy.ext.asyncio import AsyncSession
from bot.keyboards.reminders import (
ReminderActionCallback,
SnoozeDelayCallback,
ConfirmCallback,
get_snooze_delay_keyboard,
get_confirmation_keyboard,
)
from bot.keyboards.main_menu import get_main_menu_keyboard
from bot.services.reminders_service import RemindersService
from bot.services.time_service import get_time_service
from bot.logging_config import get_logger
logger = get_logger(__name__)
router = Router(name="callbacks")
reminders_service = RemindersService()
time_service = get_time_service()
# ==================== Done Action ====================
@router.callback_query(ReminderActionCallback.filter(F.action == "done"))
async def handle_done(
callback: CallbackQuery,
callback_data: ReminderActionCallback,
session: AsyncSession,
) -> None:
"""
Handle 'Done' button - mark reminder as completed.
Args:
callback: Callback query
callback_data: Parsed callback data
session: Database session
"""
reminder = await reminders_service.mark_as_done(session, callback_data.reminder_id)
if not reminder:
await callback.answer("Напоминание не найдено", show_alert=True)
return
next_run_str = time_service.format_next_run(reminder.next_run_at)
await callback.message.edit_text(
f"✅ Отлично! Отметил как выполненное.\n\n"
f"Следующее напоминание будет {next_run_str}."
)
await callback.answer("Выполнено!")
logger.info(f"Reminder {reminder.id} marked as done by user {callback.from_user.id}")
# ==================== Snooze Action ====================
@router.callback_query(ReminderActionCallback.filter(F.action == "snooze"))
async def handle_snooze_select(
callback: CallbackQuery,
callback_data: ReminderActionCallback,
) -> None:
"""
Handle 'Snooze' button - show delay options.
Args:
callback: Callback query
callback_data: Parsed callback data
"""
await callback.message.edit_text(
"На сколько отложить напоминание?",
reply_markup=get_snooze_delay_keyboard(callback_data.reminder_id),
)
await callback.answer()
@router.callback_query(SnoozeDelayCallback.filter())
async def handle_snooze_delay(
callback: CallbackQuery,
callback_data: SnoozeDelayCallback,
session: AsyncSession,
) -> None:
"""
Handle snooze delay selection.
Args:
callback: Callback query
callback_data: Parsed callback data
session: Database session
"""
reminder = await reminders_service.snooze(
session, callback_data.reminder_id, callback_data.hours
)
if not reminder:
await callback.answer("Напоминание не найдено", show_alert=True)
return
next_run_str = time_service.format_next_run(reminder.next_run_at)
await callback.message.edit_text(
f"⏰ Напоминание отложено.\n\n"
f"Напомню {next_run_str}."
)
await callback.answer("Отложено!")
logger.info(
f"Reminder {reminder.id} snoozed for {callback_data.hours}h "
f"by user {callback.from_user.id}"
)
# ==================== Pause/Resume Actions ====================
@router.callback_query(ReminderActionCallback.filter(F.action == "pause"))
async def handle_pause(
callback: CallbackQuery,
callback_data: ReminderActionCallback,
session: AsyncSession,
) -> None:
"""
Handle 'Pause' button - deactivate reminder.
Args:
callback: Callback query
callback_data: Parsed callback data
session: Database session
"""
reminder = await reminders_service.pause_reminder(session, callback_data.reminder_id)
if not reminder:
await callback.answer("Напоминание не найдено", show_alert=True)
return
await callback.message.edit_text(
"⏸ Напоминание поставлено на паузу.\n\n"
"Можешь возобновить его в любое время через «📋 Мои напоминания»."
)
await callback.answer("Поставлено на паузу")
logger.info(f"Reminder {reminder.id} paused by user {callback.from_user.id}")
@router.callback_query(ReminderActionCallback.filter(F.action == "resume"))
async def handle_resume(
callback: CallbackQuery,
callback_data: ReminderActionCallback,
session: AsyncSession,
) -> None:
"""
Handle 'Resume' button - reactivate reminder.
Args:
callback: Callback query
callback_data: Parsed callback data
session: Database session
"""
reminder = await reminders_service.resume_reminder(session, callback_data.reminder_id)
if not reminder:
await callback.answer("Напоминание не найдено", show_alert=True)
return
next_run_str = time_service.format_next_run(reminder.next_run_at)
await callback.message.edit_text(
f"▶️ Напоминание возобновлено!\n\n"
f"Следующее напоминание будет {next_run_str}."
)
await callback.answer("Возобновлено!")
logger.info(f"Reminder {reminder.id} resumed by user {callback.from_user.id}")
# ==================== Delete Action ====================
@router.callback_query(ReminderActionCallback.filter(F.action == "delete"))
async def handle_delete_confirm(
callback: CallbackQuery,
callback_data: ReminderActionCallback,
) -> None:
"""
Handle 'Delete' button - ask for confirmation.
Args:
callback: Callback query
callback_data: Parsed callback data
"""
await callback.message.edit_text(
"Точно удалить напоминание?",
reply_markup=get_confirmation_keyboard(
entity="delete",
entity_id=callback_data.reminder_id
),
)
await callback.answer()
@router.callback_query(ConfirmCallback.filter(F.entity == "delete"))
async def handle_delete_execute(
callback: CallbackQuery,
callback_data: ConfirmCallback,
session: AsyncSession,
) -> None:
"""
Execute reminder deletion after confirmation.
Args:
callback: Callback query
callback_data: Parsed callback data
session: Database session
"""
if callback_data.action == "no":
await callback.message.edit_text("Удаление отменено.")
await callback.answer()
return
deleted = await reminders_service.delete_reminder_by_id(
session, callback_data.entity_id
)
if not deleted:
await callback.answer("Напоминание не найдено", show_alert=True)
return
await callback.message.edit_text("🗑 Напоминание удалено.")
await callback.answer("Удалено")
logger.info(
f"Reminder {callback_data.entity_id} deleted by user {callback.from_user.id}"
)
# ==================== Settings Placeholder ====================
@router.message(F.text == "⚙️ Настройки")
async def handle_settings(message: Message) -> None:
"""
Handle settings button (placeholder).
Args:
message: Telegram message
"""
await message.answer(
"⚙️ Настройки\n\n"
"Функционал настроек будет добавлен в следующих версиях.\n\n"
"Пока доступны основные функции:\n"
"• Создание напоминаний\n"
"• Просмотр и управление\n"
"• Редактирование параметров",
reply_markup=get_main_menu_keyboard(),
)