Пишем систему омниканальной рассылки оповещений в Telegram
Рассказали, как устроена система омниканальной рассылки без сложной персонализации и как реализовать что-то похожее с отправкой в Telegram
4К открытий7К показов
Все мы знаем о рассылках, где нас приглашают что-то купить или дарят бонусные рубли. Они не пишутся и не отправляются в ручном режиме — это долго, дорого и непрактично (особенно, если вы вдруг решили порадовать скидкой сразу миллионы клиентов). Такими сообщениями занимаются системы, которые на основе правил собирают «уникальные» предложения и отправляют их по SMS, на почту или в пуш-уведомлениях.
В статье постараемся разобраться, как устроена система омниканальной рассылки без сложной персонализации и большой базы данных клиентов. Обсудим вводные и посмотрим, как реализовать что-то похожее с отправкой в Telegram (в нашем случае, в банке, мы отправляем информацию по инцидентам). И даже организуем простенькую систему защиты каналов от незваных гостей.
Немного о системе
Для своего, узкого, пользования мы разработали систему омниканальной отправки сообщений. И научили её собирать сообщения в raw-, markdown- и html-форматах для отправки по разным каналам: hpsm, Ivanti, email, Mattermost и Telegram.
Сервис помогает удобно и быстро встраивать уведомления для разных каналов связи в другие системы. Что позволяет в режиме реального времени менять шаблоны сообщений, а также учетные записи и, например, адреса smtp-серверов. Единственная проблема — ещё одна точка отказа для других систем.
Углубляться в систему не будем — лишь выделим интересующий нас API-метод /interact, и назовём его точкой входа. В этот метод мы будем передавать инструкции по сборке и отправке сообщений. Ключевыми параметрами для выполнения запроса будут: список каналов и получателей, набор параметров и «фич», а также нагрузка. Например, такие:
В системе мы объявляем несколько уровней:
- Система. В нём мы определяем токены для интеграции API, указываем пути доставки с адресами, пароли, триггеры и все необходимое.
- Триггеры. В них указываются базовые характеристики: имя, ключ доступа, поля, которые необходимо указать в инструкции, их характеристики и модификаторы; способы доставки, которые описывают, по какому каналу, объявленному на уровне системы, необходимо отправить сообщение, и как будет выглядеть само сообщение. Например, поле name имеет тип string, модификатор toUpperCase и так далее.
Финальный API-метод исполнения инструкции отправки выглядит так: /api/v1/trigger_name_or_uid/interact
.
Тут может возникнуть вопрос: куда делся первый уровень? Всё просто. Определение системы вшито в токен интеграции API.
Маршрут до оповещения выглядит так: system→ trigger → transport → template
. Где transport
— канал, по которым мы будем отправлять сообщения, а template
— шаблон сообщения по транспорту. На этом моменте мы оставим дальнейшую работу системы под капотом.
Шаблоны и параметры заполнения сообщения
Триггер может включать в себя большой набор каналов доставки. Но не хватает самого сообщения, для которого, в свою очередь, нужны шаблон и параметры заполнения.
Шаблон вручную заполняет оператор системы — для каждого выбранного транспортного узла в триггере. То есть описывает инструмент и параметры отправки сообщения по каналу: Telegram, email, Mattermost и прочим.
Далее мы совмещаем шаблон с параметрами. Для этого используется движок Razor. Упрощенно, код инициализации экземпляра выглядит так:
А метод компиляции сообщения — так
Telegram
Телеграм предоставляет разработчикам несколько способов создать чат-бот и готовые библиотеки для работы с API. Нам понадобится способ Bot API. Это REST, поэтому много новой информации по взаимодействию искать не придётся.
Разработчики Bot API придумали интересный метод организации методов. Они разделили запрос на два части: токен доступа и название метода. Запрос на получение информации о боте в Telegram выглядит так: https://api.telegram.org/bot/getMe
. Во всех адресах обращения к API будут меняться лишь названия методов:
- /getMe;
- /sendMessage;
- /getFile и так далее.
Всю информацию по доступным методам можно найти здесь: https://core.telegram.org/bots/api#available-methods.
Регистрация бота в Telegram
Для начала необходимо создать бота:
- заходим в приложение и запускаем чат с @BotFather;
- отправляем команду /newbot и следуем инструкциям:пишем имя бота;вводим username, который обязательно должен заканчиваться на bot.
Выполнив все шаги, мы получим сообщение об успешном создании бота и токен для работы с ним.
Храните токен в защищённом месте и не публикуйте его вместе с кодом в репозиторий. Если вдруг всё пошло не так, и секретность токена под угрозой, вы можете перевыпустить токен или отключить бота до момента решения вопросов с безопасностью.
Учимся отправлять сообщения в чаты
Для теста подойдёт любой канал, в котором вы являетесь администратором. Для отправки сообщений нам понадобится метод sendMessage.
Объявляем структуру сообщения:
Передаём идентификатор канала и сообщение:
Почти все запросы к Bot API будут с типом POST, так как это самый удачный метод для передачи большого набора данных (но можно и GET). Тело запроса на отправку сообщения в канал будет выглядеть так:
Поле parse_mode нужно, чтобы регулировать формат текста, выбрать html или markdown-разметку.
В модели Message поле parse_mode не указано для упрощения, но вы можете его добавить и поиграться с html или markdown-разметкой.
Отправлять сообщения пользователям тоже можно, но вот начать переписку с ботом в Telegram должен человек. Дальше надо научиться слушать события.
Слушаем чаты
Чтобы бот умел реагировать на команды, понадобится «сканирование» на обновления. Есть два метода прослушивания обновлений: регулярно ходить в Telegram или предоставлять ему адрес прослушивания на вашем сервере, то есть webhook.
Для реализации веб-хуков в корпоративном контуре нужно обосновать необходимость доступа и согласовать изменения. Это долго и сложно, поэтому мы используем первый вариант и будем получать обновления по методу getUpdates
.
В теле запроса мы будем отправлять следующие данные: offset
, limit
, allowed_updates
.
offset
Поле offset самое интересное. Оно обеспечивает последовательное чтение обновлений с сервера. Его магия в том, что если мы не будем указывать его в каждом последующем запросе, то будем всегда получать одни и те же обновления раз за разом. Назовём это поле «ластиком», который стирает все полученные ранее обновления, и предоставляет свежие.
Важно! Для корректного функционирования системы, в запросах getUpdates всегда необходимо указывать — идентификатор последнего полученного обновления. При первом вызове метода у нас его не будет — мы получим его после первого запроса getUpdates. При каждом последующем запуске приложения, что логично, идентификатора обновления снова не будет, вы получите его после первого запроса, конечно же, если в потоке будет хоть одно обновление.
limit
Это лимит обновлений, которые мы можем получить в одном запросе getUpdates
. Получать можно от 1 до 100 обновлений за раз. По умолчанию стоит значение 100, поэтому поле можно не указывать, если вы хотите получать максимальное количество обновлений.
allowed_updates
Это поле — массив строк, то есть список типов обновлений, которые мы хотим получить в ответ. Для полного охвата нам будет достаточно: chat_member
, message
и my_chat_member
. Полный список можно посмотреть тут: https://core.telegram.org/bots/api#update.
Вы получите ровно те объекты обновлений, типы которых были указаны в поле allowed_updates
. В нашем случае объект может выглядеть так:
Каждый объект обновления в массиве результата будет включать в себя набор данных, к которому относится обновление. Исходя из них, мы сможем реагировать на сообщения пользователей, получать информацию о вступивших и вышедших пользователях канала.
Верифицируем пользователей
Нам нужно подтверждать легитимность присутствия пользователей в чате. Для этого используем:
- таблицу сопоставления логина телеграмм с логином в AD;
- статус верификации;
- кодовое слово — случайно сгенерированную строку в 1024 символа.
Процесс выглядит так:
- Заводим заявку на подключение пользователя к Telegram.
- В заявке генерируются необходимые данные: запись сопоставления логинов, ключ верификации и так далее.
- На корпоративную почту отправляется сообщение с инструкцией, как пройти верификацию.
- Пользователь отправляет секретный ключ через команду /verify в чат с ботом.
- Мы обрабатываем все обновления с объектом message в ответе. То есть ищем поля message.chat.type, которым эквивалентно значение private.
- Определяем команду /verify.
- Подтверждаем верификацию в системе, сохраняем ID пользователя в таблицу сопоставления и отправляем ему письмо об успешной верификации.
Мы решили обойтись без усложнений и не стали регистрировать команды в боте. Но вы можете зарегистрировать их для удобства ваших клиентов.
Приглашаем пользователей в чаты
Сперва нам нужно запросить разблокировку пользователя, даже если он не был заблокирован ранее. Для этого воспользуемся командой unbanChatMember
. Как тело запроса передаём поля: chat_id
и user_id
— и проверяем в поле в коде OK 200.
Далее генерируем ссылку на приглашение методом createChatInviteLink. В теле передаём поля chat_id
, expire_date
, member_limit = 1
. Лимит нужен, чтобы ограничить количество вошедших по ней пользователей. (все равно неавторизованного пользователя мы забаним????).
Дата «протухания» приглашения передаётся в формате unix (seconds).
Далее отправляем сообщение пользователю со ссылкой на приглашение. Например, «Вам отправлено приглашение на вступление в группу ‘{chat.FriendlyName}’.\n{inviteLink.Link}\n Приглашение активно до {invite.ExpireDate.ToUniversalTime():dd.MM.yyyy H:mm:ss zzz».
Блокировка неверифицированных пользователей
Для определения нового вошедшего в канал пользователя получаем значение из поля chat_member.member.status
. Оно должно быть эквивалентно значению member. Если пользователь есть в системе, и он помечен как верифицированный, то мы игнорируем сообщение. Иначе смотрим на него с презрением и выписываем перманентный бан.
Для блокировки в чате используем метод banChatMember
. В тело запроса передаём 2 поля: chat_id
и user_id
. И пишем пользователю в личку информацию о блокировке c инструкцией, как выйти и зайти правильно.
Что в итоге
Так, мы научили бота Telegram отправлять сообщения, получать обновления, верифицировать, приглашать в чаты и блокировать пользователей. Благодаря этому, нам не нужен оператор Telegram-чатов, который добавлял бы пользователей и сообщения в канал вручную. За все отвечает автоматизированная система, для которой достаточно указать обязательные поля, чтобы она собрала все необходимые варианты сообщений и отправила их в соответствующие каналы.
4К открытий7К показов