Получить консультацию

Интеграция 1С и MS Teams – два примера использования

Уф, давненько я не писал чего-то сугубо практического! В этом материале мы рассмотрим интеграцию корпоративного мессенджера MS Teams и 1С, и разберем два варианта взаимодействия – отправка сообщений из 1С в каналы MS Teams через вебхуки, и отправка личных сообщений в чат пользователю.

Содержание

Преамбула

В работе любой информационной системы есть события, которые крайне нежелательно упускать, и которые хотелось бы мониторить. Для мониторинга сетевых ресурсов и “железа” есть Zabbix, оповещения о задачах исполнителя из СЭД можно настроить на электронную почту, как и многое другое. Но иногда этого бывает недостаточно, и нужны дополнительные каналы информирования пользователей.
Сперва идея, как водится, родилась для внутреннего использования самими разработчиками – создать канал MS Teams, куда присылать уведомления о важных изменениях в учетных системах. Как правило, такие изменения требуют дополнительного контроля, настроек, или еще каких-то действий.  А потому надеяться на то, что пользователи сообщат, например, что они поменяли структуру предприятия в справочнике – не только неразумно, но и опасно. Поэтому было решено ловить такие триггеры-изменения НСИ, и присылать уведомления в MS Teams.
Почему именно Тимс? Во-первых, это основной корпоративный месенджер и основной канал взаимодействия всех пользователей в компании. Во вторых, потому что совместный чат в канале продуктивнее и быстрее чем отслеживание цепочки электронных писем.
Поизучали документацию, форумы, и пришли к выводу, что эта задача вполне решаема.
Но аппетит приходит во время еды, и вскоре возникло уже новое пожелание – автоматизировать поздравления с днями рождения, которые ранее практически каждый день формировались вручную (в компании около 700 сотрудников, и дней рождения действительно много 🙂 ).  Это тоже было решено делать через вебхуки в канал MS Teams.
А вот третья задача оказалась самой сложной – возникло пожелание присылать уведомления руководителям проектов о необходимости актуализации данных, и уведомление это присылать в виде личных сообщений. Собственно это второй способ интеграции, который рассмотрен в данной статье.

По сути, все взаимодействие с API Тимс сводится к формированию правильного JSONа и передаче его правильным http запросом 🙂

Вариант первый - использование входящих вебхуков

Чем хорош MS Teams – так это обширными средствами интеграции с другими системами. В русском переводе они называются Соединители. Можно настроить соединители с Гугл Аналитикс, С Jira, Jenkins, с тем же Заббиксом. Соединителей многие десятки. В том числе есть и универсальный соединитель, который можно использовать для практически любой системы – входящий веб-перехватчик. В английской версии Incomming Webhook.

Со стороны Teams настраивается все очень просто.
Заходим в нужный канал, жмем Соединители.

Вебхуки MS Teams в 1С

Выбираем Входящий веб-перехватчик. Задаем имя перехватчика, картинку, и сохраняем. Копируем URL-адрес вебхука, и на этом в общем-то все. Нужно учесть, что иконка вебхука отличается от иконки пользователя. У пользователей она круглая, а у вебхуков она в форме шестиугольника.

Настройка входящего вебхука в MS TEams

Дальше можно этот вебхук использовать где угодно – например, проверить его работу через Postman. В нашем же случае, код на языке 1С будет обычным использованием HTTP-запроса. В качестве тела сообщения можно использовать разметку URL, тогда сообщение будет соответствующим образом оформлено – например, сделать маркированный список, табуляцию, оформление цветом и т.п. очень удобно встроить в сообщение ссылку на нужный элемент в 1С, чтобы из Teams можно было сразу запустить 1С и открыть нужный справочник или документ.
Ссылку, полученную на этапе настройки вебхука, надо разделить на две части – первая будет адрес сервера, и указывается в HTTPСоединение,  а все что после “… office.com” – пойдет уже в HTTPЗапрос.

HTTPСоединение = Новый HTTPСоединение("ИмяСервера.webhook.office.com",,,,,,Новый ЗащищенноеСоединениеOpenSSL()); 

СтруктураСообщения = Новый Структура("text","Ваше сообщение");
	
ЗаписьJSON = Новый ЗаписьJSON;
ПараметрыJSON = Новый ПараметрыЗаписиJSON();
ЗаписьJSON.УстановитьСтроку(ПараметрыJSON);
ЗаписатьJSON(ЗаписьJSON, СтруктураСообщения);
ДанныеJSON = ЗаписьJSON.Закрыть();
		
Заголовки = Новый Соответствие();
Заголовки.Вставить("Content-Type", "application/json");
	
HTTPЗапрос = Новый HTTPЗапрос("/webhookb2/GUID1@GUID2/IncomingWebhook/GUID3/GUID4", Заголовки); 
HTTPЗапрос.УстановитьТелоИзСтроки(ДанныеJSON, КодировкаТекста.UTF8);
Попытка		
	HTTPОтвет =  HTTPСоединение.ОтправитьДляОбработки(HTTPЗапрос);		
Исключение
	Сообщить(ОписаниеОшибки());
КонецПопытки;

Чтобы не хардкодить имя сервера и адрес вебхука, было принято решение создать регистр сведений и ряд справочников, чтобы можно было в пользовательском режиме настраивать на стороне 1С новые вебхуки. Для хранения самих сообщений был создан справочник Уведомления, который в момент записи создает хеш MD5, и записывает контрольную сумму в наименование. Это позволило организовать быстрый поиск по текстам большого размера, чтобы не дублировать одинаковые сообщения. Для хранения настроек вебхуков был создан справочник Каналы, где хранятся адреса веб-серверов и адреса веб-хуков. А в регистр сведений пишется очередь сообщений на отправку.

Трудности и подводные камни

Проблема 1. Для того, чтобы в общем чате именинники не пропустили свои поздравления, необходимо их упоминать в сообщении. Обычно в тимс мы просто пишем “@username” и упоминание автоматически подставляется. Но при программном создании сообщений упоминания нужно формировать особым образом.

Решение. Формируем текст сообщения, воспользовавшись документацией Microsoft. Нам понадобится создать массив entities, в котором должны быть элементы с типом mention. В каждом элементе мы указываем id пользователя и его имя. Кроме того, нам нужен текст-маска, по которому будет сопоставляться упоминание.

{
    "type": "message",
    "text": "Hey Ivanov Ivan check out this message",
    "entities": [
        {
            "type":"mention",
            "mentioned":{
                "id":"29:08q2j2o3jc09au90eucae",
                "name":"Ivanov Ivan"
            },
            "text": "@Ivanov Ivan"
        }
    ]
}

Но увы, такое решение не универсальное – см. следующую проблему.

Проблема 2. Следующая беда, с которой столкнулись – упоминания видны на android и на ПК, а вот на iPhone сообщения отображаются с текстом “отправлена карточка”.
Решение. Долгие поиски в документации и на Stackoverflow привели меня к понятию адаптивных карточек (AdaptiveCards). Начать можно со странички https://adaptivecards.io/ , там можно найти и документацию, и примеры, и конструктор карточек – чтобы можно было сразу посмотреть превью, как оно будет выглядеть. Еще один конструктор тут: https://dev.teams.microsoft.com/cards – но тут нужна учетная запись Майкрософт.
Хороший пример упоминания пользователя в адаптивной карточке – тут. Правда, он на английском. Как впрочем и почти вся годная информация по MS Teams.
Важный момент – с адаптивными карточками нужно работать внимательно, чтобы они корректно отображались на узких экранах. Обратите внимание на свойства wrap и width.

Проблема 3. Новым вызовом стало желание отображать смайлики в поздравлениях. 1С забавная платформа. Смайлики, – они же эмодзи, emoji и др – в табличном документе она отображать может. При работе через браузер в веб-клиенте – может отображать и в текстовом документе. А вот в тонком клиенте и в конфигураторе – не умеет.
А раз в коде эти эмодзи прописать нельзя, в текстовом поле шаблона – тоже нельзя, выход один – искать альтернативу. И альтернатива нашлась в виде суррогатных пар. подробнее написано в замечательной статье на Инфостарте.

Для хранения информации об используемых эмодзи и тегировании (упоминании) сотрудников в справочнике сообщений были добавлены табличные части Упоминания(Колонки id, text, name) и Эмодзи (Колонка Code). В момент формирования запроса к API из этих табличных частей и основного шаблона формируется JSON всего сообщения, при этом код эмодзи разбивается на суррогатные пары. Список эмодзи можно найти например здесь.

Вариант второй - отправка сообщений в чат пользователю

Принцип формирования сообщения точно такой же – собираем нужный нам JSON и отправляем http запросом POST. Сообщения могут быть оформлены как обычный текст, либо же можно использовать HTML разметку – например, вставлять ссылки, маркированные списки и т.д.

Но вся сложность заключается в том, что сообщения в чат можно писать только от имени другого пользователя (у нас не было цели создавать полноценного чат-бота, поэтому работу с ботами в данной статье мы не рассматриваем). При этом для отправки сообщения от имени пользователя нам нужен JWT токен этого пользователя. Если бы мы реализовывали какую-то автоматизацию для реального пользователя, нам понадобилось бы обеспечить его авторизацию, в том числе учитывая возможности двухфакторной авторизации на разных устройствах.
Но так как у нас стоит задача отправлять сообщения от имени служебного пользователя (технической учетки Teams), можно поступить немного проще.

Сперва нужно зарегистрировать приложение в Azure Active Directory, и получить нужные разрешения. Проверить и потестировать, как это все работает, можно в веб-приложении Graph explorer.
Для отправки сообщений нужны права Chat.ReadWrite, ChatMessage.Send, DelagatedPermissionGrant.ReadWrite.All, Directory.Read.All.
Если вы являетесь админом вашего тенанта MS Teams – вам проще, вы можете сами выдать эти права. В противном случае понадобится запросить разрешение у администратора.
Важно: права делятся на два вида – Delegated и Application. Нужны именно Delegated, т.к. мы работаем от имени конкретного пользователя.
После того, как права получены, мы можем получить токен.
Прежде чем двигаться дальше – несколько полезных ссылок по этой теме.

Статья про Microsoft Graph, в которой рассказывается как зарегистрировать свое приложение и получить токен: https://itproblog.ru/%D1%87%D1%82%D0%BE-%D1%82%D0%B0%D0%BA%D0%BE%D0%B5-microsoft-graph/
Статья про права и доступы в Azure AD: https://learn.microsoft.com/en-us/azure/active-directory/develop/permissions-consent-overview

Теперь у нас есть приложение, мы даже можем получить токен, и казалось бы – вот оно счастье. Но нет. Токен живет 24 часа, и каждые сутки обновляется. Поэтому задача разбивается на следующие этапы:
1. Получить токен от имени пользователя
2. Получить идентификатор того пользователя, кому мы собираемся написать и идентификатор текущей служебной учетки
3. Создать чат и получить его ID
4. Сформировать сообщение и отправить его в чат

Классический подход к получению токена – создать специальную страничку авторизации для пользователя, запомнить токен, и дальше с ним работать. Например, если мы хотим встроить какую-то функциональность в корпоративный портал, такое  решение подойдет. Но для служебного технического пользователя нужно обеспечить фоновую авторизацию.
Для других систем (.net, NodeJS) есть отдельные библиотеки для неинтерактивной (фоновой) аутентификации. 1С тут не повезло. Изучая документацию и форумы, я пришел к выводу, что токен можно получить используя авторизацию OAuth 2.0 с указанием логина и пароля. Это не самый популярный и не рекомендуемый способ, но другого мне не попалось.

Статья о том, как авторизоваться от имени пользователя: https://learn.microsoft.com/en-us/graph/auth-v2-user
Собственно сам стандарт, где описано как получить токен через логин и пароль: https://www.rfc-editor.org/rfc/rfc6749#section-4.3

Идентификаторы пользователей можно получить из данных учетной записи ActiveDirectory, из поля msDS-ExternalDirectoryObjectId. Зная идентификаторы, мы можем создать чат. API для создания чата описано тут. В ответ мы получим ID чата, который используем для отправки сообщения.

API формирования сообщения описано по этой ссылке. С чем можно столкнуться при формировании текста сообщения, рассмотрено выше в первой части статьи.

Теперь немного о том, как это реализовано на стороне 1С.

В справочнике сервисных учетных записей хранится информация о ClientID, TenantID, адресе сервера и ID служебной учетки, а также логин и пароль – все что нужно для получения токена и создания чатов.
Формируем сообщения и записываем их в регистр сведений. В момент формирования сообщения мы получаем идентификатор пользователя-получателя, и на основании его и данных сервисной учетки получаем токен и формируем чат. В сообщении храним шаблон, на основании которого потом сформируем JSON сообщения.
Регламентной обработкой по расписанию считываем данные из регистра очереди сообщений на отправку. Снова получаем токен и создаем http-запрос на отправку сообщения.

В случае, если по какой-то причине не удалось отправить сообщение, ошибка логируется в том же журнале очереди сообщений. Например, по какой-то причине у нас один раз отвалился коннектор для одного канала. Помогло удаление коннектора и повторное создание.
И еще один подводный камень напоследок. API MS Teams очень специфичное. Даже  в случае ошибки оно возвращает код 200, а вот сама ошибка будет скрываться в теле ответа, в JSON объекте error.

Надеюсь, эта статья сэкономит кому-нибудь хождение по граблям и поможет настроить интеграцию 1С с MS Teams через MS Graph API.

Оставьте комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

двенадцать − три =

К НАЧАЛУ