Если вы не слышали ранее об Открытом Пакете Интеграций (что вполне вероятно), то небольшая вводная часть ниже, под катом. Для тех, кто уже знаком с ОПИ, данный раздел можно пропустить.
Открытый Пакет Интеграций (ОПИ) - это open-source набор методов для простой и быстрой интеграции с различными популярными API. Он состоит из аналогичных по функционалу 1С-расширения (CFE), OS-пакета и программы для Windows и Linux, которые предоставляют готовые функции для работы с целым набором различных онлайн-сервисов.
- ОПИ бесплатен и имеет открытый исходный код на GitHub. Вы всегда можете получить последнюю версию библиотеки на странице репозитория, а подписавшись - узнавать о выходе обновлений. Все релизы сопровождаются статьями на Инфостарт и разделами единой документации. На Инфостарт вы можете подписаться уже хоть сейчас, а про документацию я расскажу далее.
- Удобная единая документация. Она расположена на сайте opi.neocities.org и содержит в себе всю информацию, необходимую для работы: инструкции по предварительным действиям для начала интеграции, описания всех методов с параметрами и возвращаемыми значениями, примеры кода и т.д. Каждый API имеет там свой раздел.
- Простая установка. ОПИ распространяется во множестве вариантах: как XML файлы расширения, как EDT проект расширения, как файл расширения формата .cfe (версия 1С 8.3.9), как файл пакета для OneScript и еще в целом наборе пакетов и файлов для Windows и Linux. Из этого набора вы всегда сможете выбрать тот способ установки, который лучше подойдет для вашей конкретной задачи
На момент последнего обновления данной статьи, доступны следующие API:
Наиболее актуальную информацию можно посмотреть в репозитории или на вводной странице документации.
Telegram - отличная штука, думаю большинство из нас его использует - причем не только по прямому назначению, для общения, но и в качестве удобной площадки организации разнообразных рассылок.
В 1С это крайне актуально - идея отправлять уведомления о статусах документов или даже присылать PDF формы заинтересованным лицам звучит свежо и интересно. Не говоря уже про вопросы обслуживания: автоматическими сообщениями об ошибках, завершении обновления и выгрузках уже никого не удивишь. Однако, чем больше идей - тем больше чатов и каналов: тут чат для новостей, а тут - для объявлений, тут бот под ошибки определенного механизма, а тут - для другого, тут вообще 10 админских чатов для разных видов выгрузок - неплохо было бы хотя бы некоторые из них как-то сгруппировать, а в идеале - не плодить по 10 штук на каждый чих. И такой способ есть - сегодня мы поговорим про один небольшой механизм мессенджера Telegram - механизм Форума (он же темы или topics)
Что такое форум?
Форум (режим тем) - это параметр супергруппы в Телеграм, при активации которого стандартный одиночный чат превращается в набор отдельных диалогов (тем), существующих как отдельные ветки.
Для создания подобного чата необходимо, в первую очередь, создать обычную группу
А затем включить Темы в её настройках
В принципе, наш форум уже готов к работе. Но это, конечно же, было бы слишком просто. Сейчас мы рассмотрим более продвинутый способ взаимодействия с данным режимом - способ взаимодействия посредством API. С чем нам и поможет сегодняшнее обновление Открытого пакета интеграций
В этом обновлении были добавлены методы:
- Получения списка иконок-аватаров для тем
- Создания темы форума
- Изменения темы форума
- Закрытия темы форума
- Повторного открытия темы форума
- Удаления темы форума
- Скрытия главной темы
- Показа главной темы
- Изменения имени главной темы
- Очистки списка закрепленных сообщений
А также изменены старые методы отправки сообщений так, чтобы в них можно было указывать не только номер чата, но и номер конечной темы.
Эти, как и все остальные, методы с описанием параметров, возвращаемых значений и примерами кода есть в документации. А сейчас, для наглядности, мы сделаем что-нибудь незатейливое - посмотрим на новые и освежим в памяти старые методы работы с Телеграм через ОПИ.
Самый настоящий форум
Пришло время механизму оправдывать свое название. Что отличает настоящий форум от ненастоящего? Правильно - возможностью пользователей создавать свои темы.
Для реализации подобного функционала, в первую очередь, нам нужен бот. У меня он уже есть - вам необходимо его создать (если еще нет). Думаю, многие уже и так умеют, но, если что, в документации и про данный процесс есть.
После создания останется лишь добавить его в свою супергруппу - я это сделал при создании последней
А также дать боту права на управление темами. Для этого необходимо добавить его в список администраторов и включить соответствующую настройку
Для разогрева создадим оснастку управления нашими темами - заодно вспомним, как делать кнопки у ботов. Идея такова - бот должен уметь принимать сигнал о том, что пользователь хочет создать новую тему, принимать её имя и уметь пинговать пользователя, если тот её потерял.
Создадим http-сервис и установим Webhook. Установить его можно функцией OPI_Telegram.УстановитьWebhook(Токен, URL), или в браузере
https://api.telegram.org/bot[Ваш токен]/setWebhook?url=[Ваш URL]
Если публиковать базу на сервере нельзя или невозможно создать http-сервис, то можно использовать poll режим и получать обновления в цикле/фоне при помощи функции OPI_Telegram.ПолучитьОбновления(Токен). Подробно останавливаться на Webhook/Polling не будем.
Помимо http-сервиса, я еще создал вот такую очень простую структуру.
Тут рассказывать особо нечего:
Токен - токен бота
IDГруппы - собственно, ID нашего форума (его можно получить на Webhook или обновлением, если написать что-нибудь в чат форума)
Статус у пользователя - 0 - стандартный, 1 - бот ждет имя после нажатия кнопки "Создать тему", 2 - бот ждет номер группы, при нажатии "Позови меня" для пинга
Теперь создадим механизм реакции на события в модуле нашего http-сервиса (POST). Основа выглядит так:
Функция maingetMessages(Запрос)
// Достаем из ответа Telegram JSON и преобразуем его в Соответствие
ТелоСтрока = Запрос.ПолучитьТелоКакСтроку();
ЧтениеJSON = Новый ЧтениеJSON;
ЧтениеJSON.УстановитьСтроку(ТелоСтрока);
Запрос = ПрочитатьJSON(ЧтениеJSON);
Токен = Константы.Токен.Получить();
ДанныеЗапроса = ПолучитьСтруктуруПараметровИзСообщения(Запрос);
ТекстСообщения = ДанныеЗапроса["ТекстСообщения"];
IDПользователя = ДанныеЗапроса["ИдентификаторПользователя"];
Статус = ДанныеЗапроса["Статус"];
Никнейм = ДанныеЗапроса["Никнейм"];
// Если сообщение - начало диалога
Если СтрНайти(ТекстСообщения, "/start") > 0 Тогда
ОбработатьНачало(IDПользователя);
// Если предварительно была нажата кнопка Создать тему
ИначеЕсли Статус = 1 Тогда
СоздатьТему(ТестСообщения);
// Если предварительно была нажата кнопка Позови меня!
ИначеЕсли Статус = 2 Тогда
ПозватьПользователя(Никнейм);
// Все остальное: кнопки и необрабатываемые сообщения
Иначе
ОбработатьСообщение(Пользователь, IDПользователя, ТекстСообщения);
КонецЕсли;
КонецФункции
Функция ПолучитьСтруктуруПараметровИзСообщения(Знач Запрос)
СтруктураПараметров = Новый Структура;
// Получаем данные о нике, сообщении и ID из Telegram запроса
Никнейм = ?(Запрос.message.from.Свойство("username"), Запрос.message.from.username, "");
ТекстСообщения = ?(Запрос.message.Свойство("text"), Запрос.message.text, "");
ИдентификаторПользователя = Запрос.message.from.id;
ИдентификаторПользователя = OPI_Инструменты.ЧислоВСтроку(ИдентификаторПользователя);
// Ищем существующего пользователя
СуществующийПользователь = Справочники.Пользователи.НайтиПоРеквизиту("TelegramID", ИдентификаторПользователя);
// Создаем пользователя, если его нет
Если Не ЗначениеЗаполнено(СуществующийПользователь) Тогда
ОбъектПользователь = Справочники.Пользователи.СоздатьЭлемент();
ОбъектПользователь.Наименование = Никнейм;
ОбъектПользователь.TelegramID = ИдентификаторПользователя;
ОбъектПользователь.Записать();
СуществующийПользователь = ОбъектПользователь.Ссылка;
КонецЕсли;
Статус = СуществующийПользователь.Статус;
// Заполняем структуру
СтруктураПараметров.Вставить("Пользователь" , СуществующийПользователь);
СтруктураПараметров.Вставить("ИдентификаторПользователя", ИдентификаторПользователя);
СтруктураПараметров.Вставить("ТекстСообщения" , ТекстСообщения);
СтруктураПараметров.Вставить("Никнейм" , Никнейм);
СтруктураПараметров.Вставить("Статус" , Статус);
Возврат СтруктураПараметров;
КонецФункции
Первая часть функции сервиса, а также функция ПолучитьСтруктуруПараметровИзСообщения() служат лишь для определения данных, полученных от ответа Telegram при получении нового сообщения. Вторая часть определяет, что было прислано и, исходя из этого, пускает обработку по одной из 4-х веток: начало чата с ботом, создание темы по имени, упоминание пользователя в теме, чтобы он мог её найти и все остальное - нажатие на кнопки или просто сообщение с ботом. Разберем все ветки отдельно
Начало чата
Тут ничего сложного нет - просто здороваемся с пользователем и отправляем ему клавиатуру с кнопками. Для создание клавиатуры есть отдельный метод СофрмироватьКлавиатуруПоМассивуКнопок, а для отправки - ОтправитьТекстовоеСообщение. Это старые методы - одни из первых, появившихся в ОПИ. Делают то, что написано
Процедура ОбработатьНачало(IDПользователя)
Токен = Константы.Токен.Получить();
ТекстОтвета = "Добро пожаловать! Выберите действие, которое хотите совершить";
//Формируем клавиатуру
Кнопки = Новый Массив;
Кнопки.Добавить("Новая тема");
Кнопки.Добавить("Позови меня!");
// Кнопки - массив кнопок
// Ложь - не под сообщением, а на панели
// Истина - кнопки одна под одной, а не в ряд
Клавиатура = OPI_Telegram.СформироватьКлавиатуруПоМассивуКнопок(Кнопки, Ложь, Истина);
OPI_Telegram.ОтправитьТекстовоеСообщение(Токен, IDПользователя, ТекстОтвета, Клавиатура);
КонецПроцедуры
Обработка кнопок и сообщений
Наш бот должен воспринимать команды кнопок, а простые сообщения - нет. Определим процедуру ОбработатьСообщение()
Процедура ОбработатьСообщение(Знач Пользователь, Знач IDПользователя, Знач ТекстСообщения)
Токен = Константы.Токен.Получить();
// Если Новая тема - ожидаем ввода названия
Если ТекстСообщения = "Новая тема" Тогда
ПользовательОбъект = Пользователь.ПолучитьОбъект();
ПользовательОбъект.Статус = 1;
ПользовательОбъект.Записать();
ТекстОтвета = "Введите имя темы";
// Если Позови меня! - ожидаем ввода номера темы
ИначеЕсли ТекстСообщения = "Позови меня!" Тогда
ПользовательОбъект = Пользователь.ПолучитьОбъект();
ПользовательОбъект.Статус = 2;
ПользовательОбъект.Записать();
ТекстОтвета = "Введите номер темы";
// Если нечто дургое
Иначе
ТекстОтвета = "Я не знаю такой команды. Выберите что-нибудь на панели ниже";
КонецЕсли;
OPI_Telegram.ОтправитьТекстовоеСообщение(Токен, IDПользователя, ТекстОтвета);
КонецПроцедуры
Создание новой темы
Перейдем к непосредственно созданию темы. За это отвечает функция СоздатьТемуФорума()
Процедура СоздатьТему(Знач Имя, Знач Пользователь, Знач IDПользователя)
Токен = Константы.Токен.Получить();
Форум = Константы.IDГруппы.Получить();
// Создаем тему
Ответ = OPI_Telegram.СоздатьТемуФорума(Токен, Форум, Имя, "5357419403325481346");
// Получаем номер и приводим Число к строку
Номер = Ответ["result"]["message_thread_id"];
Номер = OPI_Инструменты.ЧислоВСтроку(Номер);
// Отправляем ответ
Сообщение = "Тема создана! Её номер - " + Номер;
OPI_Telegram.ОтправитьТекстовоеСообщение(Токен, IDПользователя, Сообщение);
// Сбрасываем статус
ПользовательОбъект = Пользователь.ПолучитьОбъект();
ПользовательОбъект.Статус = 0;
ПользовательОбъект.Записать();
КонецПроцедуры
При создании темы последним параметром идет длинный числовой код - 5357419403325481346. Это - номер ID иконки темы. Я вставил его руками, но вообще в библиотеке есть метод ПолучитьСписокИконокАватаров(), который позволяет получить список всех иконок с их ID. Также полный список есть и в документации
Позвать пользователя
Осталось дело за малым - позвать пользователя в диалоге. Позвать - именно что позвать, окликнуть. Доступ ко всем темам есть у всех пользователей, но нужная тема может просто потеряться если их количество станет достаточно большим. При создании темы мы отправляем пользователю номер - по нему и будем определять целевой чат для пинга.
Изначально, метод отправки сообщений не предусматривал параметр номера темы (возможно, их тогда еще и не было), поэтому, для сохранения обратной совместимости, номер темы указывается не как отдельный параметр, а через * в параметре ID Чата
Процедура ПозватьПользователя(Знач Никнейм, Знач НомерТемы, Пользователь)
Токен = Константы.Токен.Получить();
Форум = Константы.IDГруппы.Получить();
// Прибаляем номер темы к ID чата через *
Чат = Форум + "*" + НомерТемы;
// Отправляем @Никнейм для упоминания пользователя
OPI_Telegram.ОтправитьТекстовоеСообщение(Токен, Чат, "@" + Никнейм);
// Сбрасываем статус
ПользовательОбъект = Пользователь.ПолучитьОбъект();
ПользовательОбъект.Статус = 0;
ПользовательОбъект.Записать();
КонецПроцедуры
Вот такой вот небольшой бот по управлению форумом у нас получился. Помимо создания темы, как уже было указано ранее, есть методы и для изменения и для удаления тем, но в них также нет ничего сложного - думаю, суть работы понятна. Еще проще, чем через бота, эти методы можно использовать и просто изнутри кода - например, создавать тему при отклонении какого-нибудь документа или в случае возникновения ошибки (а потом закрывать - типо как тикет).
Ну а пока все. Забирайте ОПИ на Github, изучайте документацию - там есть еще много разных методов для работы все с тем же Telegram (а еще с VK, Viber, Twitter, Notion, Yandex.Disk и Google Calendar)
Спасибо за внимание!
Репозиторий ОПИ: github.com/Bayselonarrend/OpenIntegrations
Последний релиз: github.com/Bayselonarrend/OpenIntegrations/releases/latest
Другие статьи про Открытый пакет интеграций на Инфостарт:
Мой GitHub: https://gitub.com/Bayselonarrend Лицензия MIT: https://mit-license.org