Интерактивный бот
Здесь собран бот, который ведёт задачи прямо в чате. Сотрудник пишет в канале /task Обновить прайс, и бот отвечает тредом с кнопкой «Взять задачу». По нажатию бот открывает форму со сроком и комментарием, а после отправки пишет итог в тред и меняет кнопку на «Готово». Нажатие «Готово» убирает кнопки и закрывает задачу.
Бот — один обработчик исходящего вебхука, код на TypeScript (Express) и Python (Flask). Как бот получает сообщение и отвечает на него без кнопок и форм, показано в разделе Первый бот.
Что настроить
Создайте бота
Откройте Интеграции > Боты и нажмите Создать бота. Подробнее — в разделе Создание бота.
Выпустите токен
На вкладке API в карточке бота нажмите Создать токен и выберите права из набора для интерактивного бота в разделе Наборы прав под типовые задачи. Коду на этой странице из набора нужны messages:create и threads:create для ответа тредом, views:write для формы и messages:update для замены кнопок. Если права не хватает, метод отвечает 403 с кодом insufficient_scope. Подробнее о выпуске — в разделе Токены бота.
Включите исходящий вебхук
На вкладке Исходящий вебхук нажмите Включить и укажите в Webhook URL адрес обработчика, например https://tasks.example.com/pachca/events. Для разработки на своей машине подойдёт адрес туннеля, подробнее в разделе Запуск. Отметьте Новые сообщения в режиме Начинающиеся с команд с командой /task и событие Нажатие кнопок: с ним приходят и нажатия, и отправленные формы. Включите Игнорировать свои сообщения и скопируйте Signing secret для проверки подписи. Остальные настройки вкладки — в разделе Общие настройки.
Добавьте бота в чат
Добавьте бота участником беседы или канала, где сотрудники будут писать команду. Команда работает и в тредах этого чата, и в личных сообщениях с ботом.
Режим «Начинающиеся с команд» с командой /task и событие «Нажатие кнопок»
Код бота
Обработчик проверяет подпись и время отправки, как в разделе Безопасность, и разбирает три события: новое сообщение с командой, нажатие кнопки и отправку формы. Методы API он вызывает обычными HTTP-запросами с телами из справочника API.
TypeScript
Нужен Node.js 18 или новее.
Python
Нужен Python 3.9 или новее.
Запуск
Задайте переменные окружения и запустите обработчик. Он слушает порт 3000 и принимает события по пути /pachca/events.
Пачка доставляет события на публичный адрес. На своей машине его даёт туннель, например ngrok или Cloudflare Tunnel, подробнее в разделе Разработка с туннелем. Адрес обработчика с путём /pachca/events укажите в Webhook URL, затем напишите в беседе или канале с ботом /task Обновить прайс: бот ответит в треде сообщением с кнопкой.
Этот код принимает события вебхуком. Бот без публичного адреса получает их потоком событий, а на отправку формы отвечает отдельным методом, подробнее в разделах Разработка без публичного адреса и Ответ через журнал событий.
Как это работает
Команда и ответ тредом
В режиме Начинающиеся с команд бот получает только сообщения, первое слово которых /task. Как Пачка сравнивает первое слово с командой, сказано в разделе Команды настроек вебхука. Текст задачи — остальная часть content, а пример разбора команды с упоминанием бота перед ней есть на странице Общение с ботом.
На событие о сообщении Пачка ждёт ответа 5 секунд, поэтому обработчик отвечает 200 сразу, а методы API вызывает после ответа. Все сроки — в разделе Сроки ответа.
В беседе или канале бот отвечает тредом. Метод POSTНовый тред с id сообщения возвращает новый тред или тот, что у сообщения уже есть, а ответ уходит в тред методом POSTНовое сообщение с entity_type: "thread" и id треда. Если команду написали в треде или в личных сообщениях, бот отвечает туда же, с entity_type и entity_id из события. Для треда другого пути нет: у сообщения в треде свой тред не заводится. Подробнее — в разделе Куда отвечать.
Кнопка и форма
Нажатие кнопки с полем data приходит событием тому боту, который отправил сообщение, подробнее в разделе Кнопки в сообщениях. В событии есть data кнопки, message_id сообщения, chat_id чата, user_id сотрудника и trigger_id.
Форму открывает метод POSTОткрытие представления с этим trigger_id. Он действует 3 секунды, поэтому обработчик открывает форму первым делом и только потом отвечает на вебхук. Опоздавший вызов получит 410 с кодом trigger_expired, все сроки — в разделе Сроки ответа. В serverless часть этих секунд может уйти на холодный старт, подробнее в разделе Serverless и холодный старт.
Два поля запроса вернутся к боту вместе с отправленной формой:
callback_id— имя формы, по нему бот узнаёт, какую форму отправилиprivate_metadata— строка для своих данных, здесьidсообщения с кнопкой: в событии об отправке формы его нет, а кнопки в этом сообщении бот потом меняет
Поля формы задают блоки, здесь это дата date и многострочное поле input. Остальные блоки — в разделе Блоки представления.
Отправка формы
Отправленная форма приходит событием view тому боту, который её открыл. Ключи в data — значения name у блоков формы. Ответить на событие нужно за 3 секунды: кодом 200, чтобы закрыть форму, или кодом 400 с объектом errors, чтобы показать ошибку под полем. Так бот отклоняет срок в прошлом, а сотрудник исправляет дату и отправляет форму снова. Подробнее — в разделе Закрытие и отображение ошибок.
Сообщения в чат бот отправляет уже после ответа: ответ закрывает форму, и тратить на них эти 3 секунды не нужно.
Итог в чат и замена кнопок
chat_id в событии об отправке формы — чат, где нажали кнопку. Сообщение с этим chat_id в entity_id и без entity_type попадает туда же, в том числе в тред. Так же бот отвечает и на нажатие «Готово». Подробнее — в разделе Ответ в чат.
Кнопки меняет метод PUTРедактирование сообщения. Поле buttons заменяет набор кнопок целиком, пустой массив убирает их все, а текст сообщения без поля content остаётся прежним. Править бот может только свои сообщения.
Упоминание <@user_id> в тексте Пачка заменяет ником сотрудника, подробнее в разделе Что учесть в ответе.
Что доработать
- Хранилище. Бот не запоминает, кто взял задачу, поэтому «Готово» может нажать любой участник чата. Сохраните исполнителя у себя или передайте его в
dataкнопки, напримерdone:3456, и сравнивайте сuser_idиз события. Если задачу уже взяли, ответьте на отправку формы кодом400с ошибкой под полем. - Повторы. Одно и то же событие изредка приходит дважды. Отсекайте повторы по
trigger_idнажатия,submit_idотправки формы иidсообщения, подробнее в разделе Идемпотентная обработка. - Очередь. Работу после ответа код делает в том же процессе. В рабочем боте её выносят в очередь задач, а остальное для запуска на сервере собрано в разделе Чек-лист перед запуском в работу.
- SDK. Те же методы с типами запросов и тел событий есть в SDK для TypeScript и Python.