Команда /cancel в моём демо предусмотрена, хотя при запуске программа не добавляет её в список подсказок Telegram. То же самое с /menu. В исходнике для них есть обработчик, а в публикуемом перечне стоят только /start с описанием «Все демо» и /paysupport — «Вопрос по оплате». Получается любопытное устройство: действие есть, надписи нет. По отсутствующей надписи нельзя судить, заперта ли дверь.
Я бы сравнил этот список с указателем в холле. Названия отделов нужны посетителю, чтобы не искать кабинет наугад, — из этого ещё не следует, что человек с улицы, разглядевший надпись «Бухгалтерия» и добравшийся до кассы, получил право забрать выручку. Можно перевести указатель на другой язык или вовсе снять со стены; кабинеты останутся на месте. В боте между табличкой и дверью примерно такое же расстояние. Только обе вещи помещаются на маленьком экране, отчего их особенно легко принять за одну.
У Telegram есть подсказки команд: человек вводит знак /, приложение предлагает подготовленный список с описаниями. Выбор пункта сразу отправляет соответствующую команду. Это избавляет от запоминания коротких служебных слов. Но напечатать их можно и без подсказки. Программа получает сообщение, а затем уже решает, существует ли такое действие и разрешено ли оно отправителю. Красивый перечень перед полем ввода этой работы за неё не делает.
Табличку разработчик передаёт отдельно. Для этого в Bot API предусмотрен setMyCommands, принимающий список объектов BotCommand. У каждого есть имя и описание. Имя в этом объекте занимает от 1 до 32 символов: строчные английские буквы, цифры, подчёркивание. Поэтому в коде моего демо записано `start`, без косой черты, а посетителю знакомо /start. Подпись «Все демо» лежит рядом отдельным полем. Ни это поле, ни латинское слово не содержат программы, которая покажет демонстрацию.
Обработчик приходится писать.
В демо это разделение видно буквально по разным местам исходника. При запуске вызывается регистрация списка, а выше описана функция с фильтром CommandStart — она определяет реакцию на стартовое сообщение. Если разработчик дописал красивую строку к BotCommand, но не подготовил обработчик, у него получится табличка «Отдел доставки», аккуратно прикрученная к стене здания, в котором никто доставкой не занимается и принимать посылку некому. Telegram получил название. Достраивать помещение по надписи ему не поручали.
Есть и обратный случай — мои /menu и /cancel. Они не включены в перечень при запуске, зато фильтр `Command("menu", "cancel")` направляет обе команды в одну функцию. По коду она убирает ожидание текстового ответа этого пользователя и показывает общий экран. Имена разные — действие здесь одинаковое. Это незаявленные входы, а не секретные слова: любой, кто знает название, может набрать его сам. Получается, системный перечень описывает лишь часть предусмотренного в программе, и его вполне можно прочитать целиком, так и не узнав об отмене ввода.
Тут само слово «меню» начинает мешать. Кнопка рядом с полем сообщения по умолчанию открывает перечень Telegram; вместо него она может запускать Mini App. Команда /menu — сообщение программе. А главный экран моего демо — уже содержимое ответа, собранное самой программой. При запуске для системной кнопки отдельно указан режим MenuButtonCommands. Это говорит о намерении в исходнике; текущий вид кнопки на вашем телефоне по одному исходнику я не знаю.
На общем экране предусмотрены шесть демонстраций, среди них сбор заявок, запись на услуги, магазин. Рядом — «Выполненные проекты» и «Написать Владиславу». Это устройство выставки, а не полный список ботов, которые можно заказать. Обычный /start без аргумента приводит сюда же. Системная подсказка «Все демо» и экран с выбором связаны через обработчик; внешне короткая строка раскрывается в целый холл. Сами кнопки под сообщениями я разбирал в отдельной статье. Здесь меня занимает, почему вход в этот холл не следует путать с его планом.
Особенно хорошо разница заметна у /cancel. Английское слово обещает отмену, но предмет отмены в нём не указан. По коду демо прекращается ожидание текста. Например, в сценарии заявки после выбора работы и времени звонка появляется вопрос «Как к вам обращаться?». Программа запоминает, что следующий ответ относится к имени. Обработчик /cancel удаляет именно это ожидание. Сохранение новой заявки находится в другой функции, до которой такой выход из анкеты не доходит.
Готовые записи этим не отменяются.
В общей функции для /menu и /cancel нет удаления заявок, записей на услуги или корзин. Она возвращает человека к выбору демонстрации. Поэтому я бы не принимал наличие слова cancel в интерфейсе за доказательство, что можно снять уже сделанную запись. Это отдельное действие со своим предметом. В воображаемом здании возвращение в холл тоже не расторгает договор, подписанный этажом выше. Хоть табличку над выходом напишите самыми убедительными буквами.
С правами доступа у указателя ещё меньше полномочий. Telegram позволяет готовить разные списки для разных пользователей и групп, отдельно для администраторов, учитывать язык — так посетителю можно показать только относящиеся к нему пункты. Но в описании областей действия команд есть прямое предупреждение Telegram: входящее обновление не сообщает, из какой области видимости взялась команда. В нём вообще может оказаться слово, которого у бота нет. Проверять допустимость действия и полномочия отправителя должна программа, даже если её автор заранее составил безупречные перечни для каждой категории посетителей и перевёл подписи на все нужные языки.
Допустим, в другом боте предусмотрена служебная выгрузка заявок. Убрать её название из гостевого списка разумно — посетителю незачем видеть чужую работу. Защитой это станет лишь в воображении разработчика, поскольку набранная руками команда не несёт справку о том, что её выбрали из правильного перечня. Если обработчик отдаёт данные любому отправителю — отсутствие подсказки ничего не исправляет. Это мысленный пример, не рассказ об утечке у заказчика. Мне здесь достаточно разделить две вещи, которые на экране выглядят почти одинаково, — человеку не предложили действие и человеку запретили его выполнять.
В моём исходнике всё ещё стоят рядом два коротких имени, menu и cancel. Одна функция ведёт из них в общий холл. На системной табличке их нет. Проход предусмотрен; замок по-прежнему надо искать на двери.