Сегодня у меня на разборе еще одна задачка, которая внешне кажется довольно простой. Но практика показала, что придется нырнуть поглубже и использовать HTTP-запросы с блока конструктора к серверу конструктора. Если кто найдет способ попроще — напишите в Telegram @alexdevop.
Итак, идея следующая. Всем известно, что для отправки сообщения пользователю в боте этот пользователь должен инициировать диалог самостоятельно путем нажатия кнопки начать или start. Но в этом правиле есть одно исключение: если бот администратор закрытого Telegram канала, в котором есть ссылка на вступление с включенной премодерацией (Запрос на подписку), то при подаче такой заявки бот может самостоятельно инициировать диалог с пользователем.
В документации к SaleBot есть функции калькулятор для управления запросами: tg_approve_chat_join_request (принятие запроса) и tg_decline_chat_join_request (для отклонения)
Попутно, можно использовать tg_send_message для отправки пользователю сообщения о том, что заявка принята или, наоборот, мы отклонили заявку.
Но все становится чуточку «веселее», если после подписки нужно отправить более одного сообщения, или соорудить нечто подобное САРТСНА-боту, в котором прием заявки на вступление в Telegram-канал происходил бы после нажатия на кнопку в боте или вводе контрольного числа.
Немного матчасти теории
Конструктор SaleBot в процессе своей работы оперирует одновременно двумя сущностями. Это client_id и platform_id.
Сразу оговорюсь, что эту пару мы будем рассматривать для работы с Telegram-ботами, с другими каналами (мессенджерами) SaleBot будут небольшие расхождения.
client_id в нашем случае это идентификатор клиента внутри конструктора, в то время как platform_id — идентификатор внутри мессенджера, проще говоря это идентификатор пользователя в Telegram. Когда пользователь нажимает кнопку «начать», срабатывает команда start, конструктор реагирует на эту команду и регистрирует нового пользователя в базе. Назначает ему внутренний идентификатор (client_id) и закрепляет за этим client_id идентификатор внутри мессенджера (platform_id). Дальше — интереснее. Помимо идентификации пользователя client_id внутри конструктора также является носителем контекста (терминологию придумал я только что), это означает, что если мы собираем какую-то цепочку сообщений и запускаем пользователя по этой цепочке, то SaleBot будет ориентироваться на client_id, и лишь перед непосредственно отправкой будет извлекать ID Telegram и выполнять запрос на отправку сообщения на сервера Telegram. Пока что всё выглядит логично.
Первые приключения начинаются тогда, когда мы добавляем пользователя в канал или чат Telegram. Дело всё в том, что Telegram-канал (дальше по тексту я буду писать канал подразумевая и каналы и чаты) с точки зрения SaleBot тоже пользователь (внезапно!). После добавления канала так же происходит присваивание client_id каналу и подвязка ID Telegram канала к переменной platofrm_id. Именно по этой причине, если сделать рассылку по всей базе в SaleBot, то сообщение попадет не только людям но и в канал. Так вот, до поры до времени эта конструкция работает как следует.
Далее начинается самое интересное. У Telegram-каналов есть служебные сигналы, они же более известны под названием колбэки (callback). Это внутренние системные уведомления которые Telegram канал посылает боту. Не путайте только их с сообщениями.
Интересное здесь вот что: когда приходят подобный callback’и (подписка, отписка, заявка на вступление и т.п), эти уведомления действуют в контексте Telegram канала источника (с тем же client_id, что и у канала) но при этом являются самостоятельными носителями контекста, так как внутри себя подтягивают переменные подписчика.
Когда нам нужно принять заявку на подписку или отправить новому подписчику сообщение, то в целом проблем никаких не возникает. Мы просто используем функцию tg_approve_chat_join_request(platform_id, chat_member_id) для подтверждения или tg_send_message(chat_member_id, text)
Но, что делать, если нужно отправить нашему новому подписчику цепочку сообщений? На всякий случай я заглянул в документацию SaleBot. Но в описании функции tg_send_message() есть много параметров, но ни одного, который бы отвечал за тайминги. Штатно мы не сможем отправить одно сообщение сразу, а затем следующее сообщение через 15 минут. Если на этом этапе вы подметите, что можно же сделать условный зеленый блок с условием chat_join_request, в его калькуляторе прописать tg_send_message(), а затем с этого блока протянуть стрелку с таймером в другой блок в котором в калькуляторе та же функция но с другим текстом — то так не получится. Точнее получится, но максимальный тайминг в стрелке будет равен интервалу между запросами на подписку(!).
Всё дело в том, что цепочка сообщений будет работать в контексте Telegram-канала, а не в контексте системного уведомления. И соответственно, если новый пользователь оставит заявку на подписку, то уведомление получит client_id Telegram-канала и цепочка запустится заново и для нового пользователя. А предыдущий подписчик уже ничего не получит.
А еще более интересный эффект будет заключатся в том, что наши подписчики с включенным ботом, не будут пополнять базу в SaleBot. Так как сущность этих подписчиков будет сокрыта в контексте client_id Telegram-канала, а у канала в свою очередь client_id уже есть и повторно регистрировать в базе конструктора его не нужно. Как итог, у нас есть какое-то определенное кол-во пользователей у кого бот запустился автоматически, кому потенциально мы можем отправлять сообщения и рассылки, но эти люди утекают мимо базы и им не получится полноценно отправлять цепочки сообщений.
Такая вот невесёлая история получается. Но решение этой задачи в целом достаточно очевидное. При получении уведомления (колбэка) с запросом на подписку нам необходимо извлечь из контекста системного уведомления максимум данных о пользователе, зарегистрировать пользователя в базе принудительно и получить пару client_id и platform_id уже для клиента в базе. Затем, получив client_id нашего пользователя, мы можем поместить этот идентификатор в цепочку сообщений (запустить цепочку сообщений по client_id). Таким образом мы сразу разрешаем все проблемы, связанные и с добавлением подписчиков в базу, превращаем в полноценного клиента и можем штатно использовать все те же возможности конструктора так, будто этот пользовать запустил бота по команде старт или пришел с минилендинга (прокси-ссылки).
Решение задачи
На этом этапе нам уже понятно, с какой задачей мы столкнулись и общий вектор того, что делать. Остается только ответить на вопрос: А как?
В общем виде, нам необходимо сделать два шага:
- Принудительно зарегистрировать клиента
- Запустить цепочку сообщений по этому клиенту после регистрации (добавления в базу)
А поможет в этом нам два узла HTTP API SaleBot. Первый узел это load_clients
Используя этот метод API мы можем создавать клиентов внутри SaleBot. Второй метод (узел) API это send_callback_by_platform_id Текущий метод API не единственный, позволяющий запустить цепочку. Но мне он приглянулся и показался более удобным и точечным.
Ну и соответственно собираем две цепочки сообщений. Первая цепочка сообщений будет работать в контексте канала. Её задача среагировать на запрос на подписку. Зарегистрировать клиента и запустить уже штатную цепочку сообщений.
Для того, чтобы сделать всё чуть более компактно, я решил использовать не блок с POST-запросом, а аналогичную функцию в калькуляторе requests_post()
В зеленом блоке chat_join_request который работает в контексте канала происходит прием заявки функцией tg_approve_chat_join_request(), далее двигаясь в контексте канала мы попадаем в блок регистрации клиента. В этом блоке в разделе калькулятор указан следующий код
1 2 3 4 5 6 7 8 |
/*РЕГИСТРИУРЕМ ПОЛЬЗОВАТЕЛЯ*/ url = "https://chatter.salebot.pro/api/#{api_key}/load_clients" headers = {"Content-Type":"application/json"} json_data = '[{"platform_id":"#{chat_member_id}","client_type":1,"group_id":"НИКНЕЙМ_БОТА","name":"#{chat_member_name}","variables": { "tg_username": "#{message_from_username}"}}]' requests_post(url, 'json', headers , None, json_data) new_client_id = get(custom_answer, 'items|0|id') |
При использовании этого кода не забудьте заменить НИКНЕЙМ_БОТА на свой, и именно на тот бот, который назначен администратором канала и который принимает заявки.
В блоке запуска цепочки код калькулятора проще
1 2 3 4 5 6 7 |
/*ЗАПУСКАЕМ ЦЕПОЧКУ*/ url = "https://chatter.salebot.pro/api/#{api_key}/send_callback_by_platform_id" headers = {"Content-Type":"application/json"} json_data = '{"platform_ids": ["#{chat_member_id}"],"callback_text":"test_callback","group_id":"НИКНЕЙМ_БОТА"}' requests_post(url, 'json', headers , None, json_data) |
Отдельно обращаю внимание на значение callback_text, в моем случае это test_callback. Когда этот код выполнится, пользователю по заданному ID Telegram (в контексте канала это chat_member_id) будет вызван системный callback внутри конструктора. Этот callback нужно будет установить в условия запуска цепочки сообщений в зеленом блоке.
На этом решение нашей задачи завершено. Бывает и такие задачи, которые на первый взгляд кажутся простыми и понятными, но таят в себе разного рода тонкости и нюансы реализации. В моем случае это вполне реальная задача с одного из моих проектов. Благо я заранее почувствовал подвох и запросил дополнительное время на разработку метода реализации. Однако эта задача в очередной раз раскрыла SaleBot как конструктор с уникальными возможностями и практически абсолютным контролем над любым параметром функционала бота.
На скриншоте выше можно увидеть, что в служебной цепочке принудительной регистрации кол-во пользователей в боте всегда равно единице. Единственное, что там может изменится это только перемещение этой единички между блоками. В тоже время вполне исправно работает цепочка после подписки. Как видите 9 человек дошло до финала, а 3 человека ждут срабатывания таймера в первой стрелке.
Как итог всей моей статьи задача решена, база пополняется новыми людьми с подписки на Telegram-канал, автоматически сегментируется, и дальше я могу учитывать этих пользователей в статистике, а наши пользователи спокойно получают цепочки рассылок-знакомством с экспертом и его Telegram каналом.