surfaces/adapter/telegram/handlers/commands.py
Mikhail Putilovskij 8901e60f6a fix(tg): reviewer fixes — error handling, timeouts, db index
- commands.py: try/except TelegramBadRequest around all Bot API calls (#2);
  /new handles "topics limit" with user-friendly message (#4)
- start.py: isolate _check_and_prune_stale_topics with try/except Exception (#3)
- message.py: asyncio.timeout(30) around stream_message; handle TimeoutError (#6)
- db.py: add idx_chats_user_id index in init_db() (#7)
- settings.py: remove dead active_chat_id variable (#8)
- tests: add test_message.py (stream error/success); add 2 tests in test_commands.py
  (topics limit, /archive in General topic)
2026-04-02 13:44:59 +03:00

91 lines
3.6 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from __future__ import annotations
import structlog
from aiogram import Router
from aiogram.exceptions import TelegramBadRequest
from aiogram.filters import Command
from aiogram.types import Message
from adapter.telegram import db
from adapter.telegram.keyboards.settings import settings_main_keyboard
logger = structlog.get_logger(__name__)
router = Router(name="commands")
@router.message(Command("new"))
async def cmd_new(message: Message) -> None:
"""Create a new topic and register it as a new chat."""
user_id = message.from_user.id
chat_id = message.chat.id
n = db.count_active_chats(user_id) + 1
new_name = f"Чат #{n}"
try:
topic = await message.bot.create_forum_topic(chat_id=chat_id, name=new_name)
except TelegramBadRequest as e:
if "topics limit" in str(e).lower():
await message.answer("Достигнут лимит топиков (1000). Заархивируй неиспользуемые чаты.")
else:
logger.error("cmd_new_failed", error=str(e))
await message.answer("Не удалось создать чат, попробуй позже.")
return
thread_id = topic.message_thread_id
db.create_chat(user_id=user_id, thread_id=thread_id, chat_name=new_name)
await message.bot.send_message(
chat_id=chat_id,
message_thread_id=thread_id,
text=f"Создан {new_name}. Напиши что-нибудь.",
)
logger.info("cmd_new", user_id=user_id, thread_id=thread_id, name=new_name)
@router.message(Command("archive"))
async def cmd_archive(message: Message) -> None:
"""Archive the current topic."""
user_id = message.from_user.id
thread_id = message.message_thread_id
chat = db.get_chat(user_id=user_id, thread_id=thread_id)
if chat is None or chat["archived_at"] is not None:
await message.answer("Этот чат не найден или уже архивирован.")
return
try:
await message.bot.close_forum_topic(chat_id=message.chat.id, message_thread_id=thread_id)
except TelegramBadRequest as e:
logger.warning("cmd_archive_bot_error", error=str(e))
db.archive_chat(user_id=user_id, thread_id=thread_id)
logger.info("cmd_archive", user_id=user_id, thread_id=thread_id)
@router.message(Command("rename"))
async def cmd_rename(message: Message) -> None:
"""Rename the current topic. Usage: /rename New Name"""
user_id = message.from_user.id
thread_id = message.message_thread_id
parts = (message.text or "").split(maxsplit=1)
new_name = parts[1].strip() if len(parts) > 1 else ""
if not new_name:
await message.answer("Использование: /rename Новое название")
return
chat = db.get_chat(user_id=user_id, thread_id=thread_id)
if chat is None:
await message.answer("Этот чат не найден.")
return
try:
await message.bot.edit_forum_topic(
chat_id=message.chat.id,
message_thread_id=thread_id,
name=new_name[:128],
)
except TelegramBadRequest as e:
logger.error("cmd_rename_failed", error=str(e))
await message.answer("Не удалось переименовать топик.")
return
db.rename_chat(user_id=user_id, thread_id=thread_id, new_name=new_name[:128])
logger.info("cmd_rename", user_id=user_id, thread_id=thread_id, new_name=new_name)
@router.message(Command("settings"))
async def cmd_settings(message: Message) -> None:
"""Open settings menu."""
await message.answer("⚙️ Настройки", reply_markup=settings_main_keyboard())