# Проверка текстового ввода Проверены зарегистрированные обработчики личных диалогов: регистрация, админка, касса, роли, каналы, эмодзи, общий и личный чат, команды и резервная обработка ввода. Демонстрационные `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` |