- sdk/mock.py: stream_message was async def (coroutine), must be async generator with yield — caused TypeError on every user message - topic_events.py: on_topic_created now skips bot-created topics (from_user.id == bot.id); cmd_new already registers them under the correct human user_id - commands.py: cmd_archive now sends "Чат архивирован." confirmation - test_topic_events.py: add bot=SimpleNamespace(id=BOT_ID) to fixture
92 lines
3.7 KiB
Python
92 lines
3.7 KiB
Python
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)
|
||
await message.answer("Чат архивирован.")
|
||
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())
|