Commit Graph
5 Commits
Author SHA1 Message Date
hermes 3dd2924d5e fix: вход в любой режим закрывает обращение поддержки
Деактивация была только в /start и «Главное меню». После перехода в
«Обучение» флаг is_active оставался, и текст уезжал оператору, а не в
обучение — сообщение уходило не туда.

Правило теперь: ушёл из контекста поддержки — обращение неактивно.
_close_support_case() вызывается из enter_mode() (любой режим),
show_main_menu() и start(). «🆘 Поддержка» — не режим, флаг не снимает.
Топик и история сохраняются, следующее обращение продолжает переписку.

Три точки вызова сведены в один helper вместо трёх копий try/except.

Тесты: 230 OK (3 новых). Регрессия проверена на старом коде: после входа
в «Обучение» is_active=True и relay=1 (текст ушёл оператору); с фиксом
is_active=False, relay=0 (текст обработал бот).

VERSION: 0.1.0+55 -> 0.1.0+56
2026-10-11 19:48:57 +02:00
hermes 12ef2c6b44 fix: /start закрывает обращение в поддержку
/start возвращает в лобби, но не снимал is_active в support_topics: FSM
сбрасывался, а обращение в БД оставалось открытым. Пользователь оказывался
в лобби, а следующее сообщение всё равно уходило оператору. Дополнительно
enter_mode() блокировал вход в режим сообщением «Идёт обращение в поддержку»
— после /start это выглядело как необъяснимый отказ.

- start() вызывает support.deactivate() перед сбросом FSM.
- Блокировка из enter_mode() удалена: выход в любой режим из открытого
  обращения разрешён — пользователя нельзя запирать. Проверка дублировала
  middleware иConflictовала с /start.

Тесты: 227 OK (3 новых). Регрессия проверена на старом коде: /start оставляет
is_active=True (баг), с фиксом — False. Топик при этом сохраняется, поэтому
следующее обращение продолжает ту же переписку.

VERSION: 0.1.0+54 -> 0.1.0+55
2026-10-11 18:34:14 +02:00
hermes 562442b979 fix: развести приватные и групповые чаты по роутерам
Сообщение оператора в топике поддержки не доходило до пользователя: бот
отвечал прямо в группу «Выбери режим работы кнопкой ниже». Причина — порядок
регистрации роутеров: основной router с catch-all @router.message() (без
фильтра по чату) включался ПЕРВЫМ, а support.router — вторым. У aiogram
побеждает первый подходящий, поэтому до поддержки очередь не доходила.
Комментарий в main() утверждал обратное.

- support.router регистрируется до основного router.
- Основной роутер отфильтрован на F.chat.type == "private" (роль «работник»);
  групповые сценарии обслуживаются своими роутерами. Это первый шаг к ролям:
  работник / помощник поддержки / аналитик / почтальон.
- Роутер поддержки дополнительно отсекает сообщения от ботов.

Вторая поломка того же корня: при активном обращении «📖 Помощь» и
«🎓 Обучение» уезжали оператору как обычный текст, режим не переключался и
бот в личке молчал — пользователь был заперт в обращении. Middleware теперь
пропускает все команды и все кнопки reply-клавиатуры через _is_bot_control(),
а не только «Поддержка» и «Главное меню».

Тесты: 224 OK (10 новых). Регрессия проверена: на старой логике «Помощь»
уходит оператору (relay=1), на новой обрабатывается ботом (relay=0).
Заглушки заменены на настоящие Message — middleware проверяет
isinstance(event, Message), поэтому SimpleNamespace проходил вхолостую.
is_support_active вызывается через to_thread — AsyncMock-заглушка возвращала
truthy-корутину и делала проверку фиктивной.

VERSION: 0.1.0+53 -> 0.1.0+54
2026-10-11 18:16:11 +02:00
hermes 4076765618 fix: показывать причину сбоя поддержки в development
Создание топика падало с «not enough rights to create a topic» (бот был
обычным участником группы, а не администратором), но пользователь видел
только «Поддержка временно недоступна. Попробуй позже» — по такому сообщению
невозможно понять, что чинить.

- ensure_topic возвращает (thread_id, причина) вместо одного thread_id.
- Текст Telegram логируется на ERROR: по типу исключения причина нечитаема.
- В DEPLOY_ENV=development причина добавляется в сообщение пользователю;
  в production остаётся общая заглушка. HTML экранируется.

Проверено: 214 тестов OK (7 новых на причину и её выдачу).
Живая проверка на dev: после выдачи боту прав администратора с «Управление
темами» create_forum_topic создал топик (thread_id 18, пробный удалён).

VERSION: 0.1.0+52 -> 0.1.0+53
2026-10-11 17:04:33 +02:00
hermes 21db563f28 feat: поддержка в боте — топик, сводка профиля, приветствие оператора
Обращение открывается кнопкой «🆘 Поддержка» или /support в режиме «Помощь».
Отдельного FSM-режима нет: пока обращение активно, внизу остаётся только
«Главное меню», а переключение режимов отклоняется.

- support.py: личка пользователя ↔ персональный топик группы SUPPORT_GROUP_ID.
  Топик создаётся один раз на пользователя и переиспользуется, поэтому
  повторные обращения продолжают ту же переписку. Пересылаются все типы
  контента через copy_message; ответ оператора из топика уходит в личку;
  сообщение с префиксом // остаётся внутренней заметкой. Функция выключена
  без SUPPORT_GROUP_ID.
- Карточка профиля уходит первым сообщением топика: аватарка, имя, username,
  id и сводка — сколько дней пользуется ботом, сколько продлений подписки,
  сколько дней осталось, обучен ли бот (user_store.support_profile_summary).
- Бот не объясняет пользователю, что «передаёт оператору»: в ответ приходит
  случайная фраза из пула SUPPORT_GREETINGS (activity_phrases.support_greeting).
  Формулировки безличные, без «я/бот/оператор»; пул переопределяется через
  SUPPORT_GREETINGS без деплоя.

Проверено: 207 тестов OK (30 новых в tests/test_support.py).
VERSION: 0.1.0+51 -> 0.1.0+52
2026-10-11 16:48:04 +02:00