Fix text dialog routing and club card registration recovery
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
@@ -14,6 +14,7 @@
|
||||
## Работа с пользователями
|
||||
|
||||
1. Попросите клиента выполнить `/start`, затем пройти «Регистрация»: указать данные, которые запрашивает бот.
|
||||
Карта вводится цифрами; допустимы и три, и четыре цифры, ведущие нули сохраняются. Если карта заранее привязана к этому же клиенту, он может завершить регистрацию с ней. При ошибке номера или телефона можно повторить ввод на текущем шаге.
|
||||
2. Откройте «Пользователи» и найдите клиента по точному Telegram ID, клубной карте или username. При нескольких совпадениях сверяйте профиль и карту.
|
||||
3. Проверьте регистрацию, клубную карту, связанные счета и участия. Введённая пользователем карта сама по себе не доказывает право владения: сверяйте её по принятой в вашей организации процедуре.
|
||||
4. Для привязки счёта используйте `/add_account КАРТА СЧЁТ`, например `/add_account 2223 11-22-33-44-55-66-77`. Затем выберите розыгрыш, если нужно добавить участие.
|
||||
|
||||
61
docs/TEXT_INPUT_AUDIT.md
Normal file
61
docs/TEXT_INPUT_AUDIT.md
Normal file
@@ -0,0 +1,61 @@
|
||||
# Проверка текстового ввода
|
||||
|
||||
Проверены зарегистрированные обработчики личных диалогов: регистрация, админка, касса, роли, каналы, эмодзи, общий и личный чат, команды и резервная обработка ввода. Демонстрационные `test_handlers.py` в рабочий диспетчер не подключены.
|
||||
|
||||
## Клубная карта: три и четыре цифры
|
||||
|
||||
Ограничения «не более трёх цифр» в текущем коде нет. В рабочей базе есть карты из четырёх цифр. Проверка полного диалога через диспетчер подтверждает приём `123`, `1234`, `0007` и сохранение ведущих нулей. Номер остаётся строкой; допустимы 1–50 цифр, как и до исправления.
|
||||
|
||||
Исторический отказ именно на четырёх цифрах без текста ответа воспроизвести не удалось. Найдены и исправлены причины потери/остановки диалога:
|
||||
|
||||
- Занятая карта сбрасывала регистрацию. Теперь остаётся шаг карты, можно исправить номер.
|
||||
- Карта, заранее записанная в профиле самого клиента, тоже считалась чужой занятой картой. Теперь клиент может завершить регистрацию со своей картой; карту другого пользователя присвоить нельзя.
|
||||
- Формат карты проверялся только после телефона. Теперь ошибка показывается сразу, на шаге карты.
|
||||
- Неправильный телефон приводил к потере введённых данных. Теперь сохраняются карта и никнейм.
|
||||
- Никнейм записывался второй транзакцией. Теперь никнейм, карта, телефон и регистрация сохраняются вместе.
|
||||
- Сбой ответа Telegram после успешного сохранения оставлял старое состояние. Завершённая регистрация теперь закрывает диалог до отправки подтверждения.
|
||||
- Если диалог уже истёк/отменён, обычное число могло поглощаться обработчиком счетов без ответа. Теперь бот предлагает `/register` или `/start`.
|
||||
|
||||
## Остальные исправления
|
||||
|
||||
| Область | Исправление |
|
||||
|---|---|
|
||||
| Команды во время ввода | Формы не сохраняют и не пересылают `/команды` как данные; известные команды доходят до своих обработчиков, неизвестные получают ответ. `/skip` оставлен только там, где он предусмотрен. |
|
||||
| Регистр команд | Зарегистрированные команды принимаются без учёта регистра. |
|
||||
| Текстовые формы | Добавлены проверки типа сообщения; неподходящее вложение не вызывает обращение к отсутствующему `message.text`. Состояние сохраняется, бот объясняет дальнейшее действие. |
|
||||
| Перехват текста | Слово «регистрация» не перезапускает активную форму. Быстрое удаление по ответу работает по точному триггеру и не перехватывает никнеймы или поля форм. |
|
||||
| Редактирование розыгрыша | Убран выдуманный callback и попытка редактировать сообщение человека. Розыгрыш без описания открывается корректно. Отмена и новое создание не сохраняют ID прежнего редактирования. |
|
||||
| Название, описание, призы | Проверяются пустые/слишком длинные значения, длина названия и каждого приза соответствует базе. Длинное подтверждение разбивается на сообщения, кнопки остаются на последнем. |
|
||||
| Массовые ID | Перенос строки равнозначен запятой. Некорректные ID не превращаются в молчаливую операцию с нулевым результатом. |
|
||||
| Массовые счета | Обрабатываются все строки, табуляция, пара «карта счёт», счёт и карта на отдельных строках, блоки Viposnova. Сохраняется принадлежность карты к счёту. |
|
||||
| Сохранение кассового диалога | Объект SQLAlchemy исключён из данных FSM: структура пригодна для JSON и Redis. При ошибочном вводе можно повторить попытку. |
|
||||
| Числовые ID | Границы чисел проверяются до SQL/Telegram; длинный номер карты в поиске не трактуется как выходящий за диапазон Telegram ID. |
|
||||
| Каналы и модерация | Проверяется ID; экранируются введённые значения в HTML. Ответ `/ban`/`/unban` на копию сообщения определяется по исходному автору в текущем диалоге. |
|
||||
| Чат | Команды не уходят получателю как текст. Выход словами «start»/«старт» использует действующий обработчик главного меню. |
|
||||
|
||||
## Проверки
|
||||
|
||||
`tests/test_text_inputs.py` проверяет полный цикл регистрации, дубликаты карт, конкурентную регистрацию двух клиентов, ошибку отправки подтверждения, ведущие нули, команды и неверный тип сообщения в текстовых формах, отмену/редактирование розыгрыша, длинные подтверждения, многострочный ввод счетов и ID, JSON-сериализацию состояния и команды модерации.
|
||||
|
||||
Проверки выполняются на изолированных SQLite/PostgreSQL с подставным Telegram API. Рабочие карты, телефоны и роли пользователей для тестирования не изменяются. Отдельно проверяются CI, успешный деплой и здоровье работающего бота.
|
||||
|
||||
## Handler inventory
|
||||
|
||||
| Module | Text-capable handlers |
|
||||
|---|---|
|
||||
| [main.py](../main.py) | `cancel_dialog`, `cmd_start`, `btn_lotteries`, `btn_chat`, `btn_registration`, `cmd_register`, `text_registration`, `btn_my_code`, `btn_my_accounts`, `btn_help`, `btn_admin`, `btn_exit_chat`, `btn_main_menu`, `cmd_admin` |
|
||||
| [src/handlers/account_handlers.py](../src/handlers/account_handlers.py) | `detect_account_input` |
|
||||
| [src/handlers/admin_account_handlers.py](../src/handlers/admin_account_handlers.py) | `cancel_command`, `add_account_command`, `process_accounts_data`, `remove_account_command`, `verify_winner_command`, `winner_status_command`, `user_info_command` |
|
||||
| [src/handlers/admin_chat_handlers.py](../src/handlers/admin_chat_handlers.py) | `cmd_chat_mode`, `cmd_set_forward`, `cmd_global_ban`, `cmd_ban`, `cmd_unban`, `cmd_banlist`, `cmd_delete_message`, `cmd_chat_stats` |
|
||||
| [src/handlers/admin_emoji_handlers.py](../src/handlers/admin_emoji_handlers.py) | `add_emoji_start`, `receive_emoji`, `receive_emoji_description`, `list_my_emojis`, `list_all_emojis`, `delete_emoji_start` |
|
||||
| [src/handlers/admin_panel.py](../src/handlers/admin_panel.py) | `process_lottery_title`, `process_lottery_description`, `process_lottery_prizes`, `process_add_participant`, `process_remove_participant`, `process_search_participants`, `process_bulk_add_participant`, `process_bulk_remove_participant`, `process_add_to_lottery`, `process_remove_from_lottery`, `process_bulk_add_accounts`, `process_bulk_remove_accounts`, `process_winner_place`, `process_winner_user`, `admin_broadcast_send`, `admin_broadcast_add_channel_id`, `admin_broadcast_add_channel_description`, `admin_users_search_process` |
|
||||
| [src/handlers/cashier_handlers.py](../src/handlers/cashier_handlers.py) | `cashier_menu`, `add_accounts` |
|
||||
| [src/handlers/chat_handlers.py](../src/handlers/chat_handlers.py) | `enter_chat_command`, `exit_chat_command`, `check_exit_keywords` |
|
||||
| [src/handlers/help_handlers.py](../src/handlers/help_handlers.py) | `help_command` |
|
||||
| [src/handlers/input_fallback.py](../src/handlers/input_fallback.py) | `unknown_command`, `unmatched_input` |
|
||||
| [src/handlers/message_management.py](../src/handlers/message_management.py) | `delete_replied_message`, `quick_delete_replied_message` |
|
||||
| [src/handlers/operator_help.py](../src/handlers/operator_help.py) | `own_id`, `help_command` |
|
||||
| [src/handlers/p2p_chat.py](../src/handlers/p2p_chat.py) | `show_chat_menu`, `handle_p2p_message` |
|
||||
| [src/handlers/redraw_handlers.py](../src/handlers/redraw_handlers.py) | `check_unclaimed_winners`, `redraw_lottery` |
|
||||
| [src/handlers/registration_handlers.py](../src/handlers/registration_handlers.py) | `process_nickname`, `process_club_card`, `process_phone`, `show_verification_code`, `show_user_accounts` |
|
||||
| [src/handlers/staff_handlers.py](../src/handlers/staff_handlers.py) | `staff_menu`, `staff_command`, `staff_target`, `confirmation_pending`, `staff_list_command` |
|
||||
Reference in New Issue
Block a user