diff --git a/.gitignore b/.gitignore index 4473662..b3d2ae7 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ *.bak +*.ospx diff --git a/installlocalhost.bat b/installlocalhost.bat new file mode 100644 index 0000000..12a4e29 --- /dev/null +++ b/installlocalhost.bat @@ -0,0 +1,12 @@ +@echo off +call del "*.ospx" + +for /f %%i in ('"oscript -version"') do set result=%%i + +if %result%==1.0.19.105 ( + call opm build . -mf ./packagedef -out . +) else ( + call opm build -m ./packagedef -o . +) + +call opm install -f *.ospx \ No newline at end of file diff --git a/installlocalhost.sh b/installlocalhost.sh new file mode 100644 index 0000000..80cb5d1 --- /dev/null +++ b/installlocalhost.sh @@ -0,0 +1,12 @@ +#!/bin/bash +rm "*.ospx" + +result=$(oscript -version) + +if [[ $result = "1.0.19.105" ]]; then + opm build . -mf ./packagedef -out . +else + opm build -m ./packagedef -o . +fi + +opm install -f *.ospx diff --git a/packagedef b/packagedef index 615753c..9b05dfe 100644 --- a/packagedef +++ b/packagedef @@ -1,6 +1,6 @@  Описание.Имя("confluence") - .Версия("1.0.5") + .Версия("1.1.0") .ЗависитОт("json") .ВерсияСреды("1.0.14") .ВключитьФайл("readme.md") diff --git a/readme.md b/readme.md index 2403a4f..324e068 100644 --- a/readme.md +++ b/readme.md @@ -32,3 +32,37 @@ #### Установка метки странице `Confluence.ПрикрепитьМеткуКСтранице(ПараметрыПодключения, ИдентификаторСтраницы, "Моя метка")` + +### Примеры нового API + +```bsl + +// Настройки подключения +Подключение = Confluence.ОписаниеПодключения("https://confluence.myserver.ru", "user", "password") + +// Получение идентификатора страницы +ИдентификаторРодителя = Confluence.НайтиСтраницуПоИмени(Подключение, "SpaceKey", "Корневая страница"); + +// Структура адреса страницы (Пространство, Наименование, Идентификатор, Родитель) +АдресСтраницы = Confluence.АдресСтраницы("SpaceKey", "Новая страница", , ИдентификаторРодителя); + +// Создадим новую страницу +Confluence.Создать(Подключение, АдресСтраницы, "Содержимое страницы"); +Сообщить("Идентификатор новой страницы: " + АдресСтраницы.Идентификатор) + +// Обновим содержимое +Confluence.Обновить(Подключение, АдресСтраницы, "Новое содержимое страницы", Истина); + +// Адрес второй страницы +АдресСтраницы = Confluence.АдресСтраницы("SpaceKey", "Вторая страница", , ИдентификаторРодителя); + +// Обновим если содержимое отличается, либо создадим если отсутствует +Confluence.СоздатьИлиОбновить(Подключение, АдресСтраницы, "Содержимое второй страницы"); + +// Опубликуем страницу в формате Markdown +АдресСтраницы = Confluence.АдресСтраницы("SpaceKey", "Третья страница Markdown", , ИдентификаторРодителя); +Содержимое = Новый Структура("Значение, Формат", "# Содержимое третьей страницы", confluence.ФорматыСодержимого.MarkDown); +Confluence.СоздатьИлиОбновить(Подключение, АдресСтраницы, Содержимое); + + +``` diff --git "a/src/\321\201onfluence.os" "b/src/\321\201onfluence.os" index 586b8d3..dd64c3a 100644 --- "a/src/\321\201onfluence.os" +++ "b/src/\321\201onfluence.os" @@ -10,13 +10,15 @@ /////////////////////////////////////////////////////////////////// +Перем ФорматыСодержимого Экспорт; + // ОписаниеПодключения // Создает структуру с набором параметров подключения. // Созданная структура в дальнейшем используется для всех операций // // Параметры: // АдресСервера - Строка - Адрес (URL) сервера confluence. Например "https://conflunece.mydomain.ru" -// Пользователь - Строка - Имя пользователя для покдлючения +// Пользователь - Строка - Имя пользователя для подключения // Пароль - Строка - Пароль пользователя для подключения // // Возвращаемое значение: @@ -60,7 +62,7 @@ URL = ПолучитьURLОперации(КодПространства, ИмяСтраницы); РезультатЗапроса = ВыполнитьHTTPЗапрос(ПараметрыПодключения, "GET", URL); - Если РезультатЗапроса.КодСостояния = 200 Тогда + Если УспешныйЗапрос(РезультатЗапроса) Тогда ПарсерJSON = Новый ПарсерJSON; Ответ = ПарсерJSON.ПрочитатьJSON(РезультатЗапроса.Ответ); @@ -74,11 +76,8 @@ Иначе - ВызватьИсключение "Ошибка поиска страницы: " + КодПространства + "." + ИмяСтраницы + - "Запрос: " + URL + " - |КодСостояния: " + РезультатЗапроса.КодСостояния + " - |Ответ: " + РезультатЗапроса.Ответ; - + ВызватьИсключение "Ошибка поиска страницы: " + КодПространства + "." + ИмяСтраницы + ТекстОшибки(РезультатЗапроса, URL, "GET"); + КонецЕсли; Возврат Идентификатор; @@ -101,7 +100,7 @@ URL = ПолучитьURLОперации(,, Идентификатор); РезультатЗапроса = ВыполнитьHTTPЗапрос(ПараметрыПодключения, "GET", URL); - Если РезультатЗапроса.КодСостояния = 200 Тогда + Если УспешныйЗапрос(РезультатЗапроса) Тогда ПарсерJSON = Новый ПарсерJSON; @@ -115,10 +114,7 @@ Иначе - ВызватьИсключение "Ошибка получения версии страницы:" + Идентификатор + - "Запрос: " + URL + " - |КодСостояния: " + РезультатЗапроса.КодСостояния + " - |Ответ: " + РезультатЗапроса.Ответ; + ВызватьИсключение "Ошибка получения версии страницы:" + Идентификатор + ТекстОшибки(РезультатЗапроса, URL, "GET"); КонецЕсли; @@ -142,23 +138,15 @@ URL = ПолучитьURLОперации(,, Идентификатор) + "&expand=body.storage"; РезультатЗапроса = ВыполнитьHTTPЗапрос(ПараметрыПодключения, "GET", URL); - Если РезультатЗапроса.КодСостояния = 200 Тогда + Если УспешныйЗапрос(РезультатЗапроса) Тогда - Регексп = Новый РегулярноеВыражение("""body"":{""storage"":{""value"":""([\w\W]*?)"",""representation"":""storage"); - Регексп.Многострочный = ИСТИНА; - Ответ = Регексп.НайтиСовпадения(РезультатЗапроса.Ответ); - Если Ответ.Количество() Тогда - - Тело = Ответ[0].Группы[1].Значение; - - КонецЕсли; + Данные = ДесериализоватьJSON(РезультатЗапроса.Ответ); + + Возврат Данные.body.storage.value; Иначе - ВызватьИсключение "Ошибка получения версии страницы:" + Идентификатор + - "Запрос: " + URL + " - |КодСостояния: " + РезультатЗапроса.КодСостояния + " - |Ответ: " + РезультатЗапроса.Ответ; + ВызватьИсключение "Ошибка получения версии страницы:" + Идентификатор + ТекстОшибки(РезультатЗапроса, URL, "GET"); КонецЕсли; @@ -189,7 +177,7 @@ URL = ПолучитьURLОперации(,, Идентификатор, "child/page"); РезультатЗапроса = ВыполнитьHTTPЗапрос(ПараметрыПодключения, "GET", URL); - Если РезультатЗапроса.КодСостояния = 200 Тогда + Если УспешныйЗапрос(РезультатЗапроса) Тогда ПарсерJSON = Новый ПарсерJSON; Ответ = ПарсерJSON.ПрочитатьJSON(РезультатЗапроса.Ответ); @@ -208,10 +196,7 @@ Иначе - ВызватьИсключение "Ошибка получения подчиненных страниц: " + Идентификатор + - "Запрос: " + URL + " - |КодСостояния: " + РезультатЗапроса.КодСостояния + " - |Ответ: " + РезультатЗапроса.Ответ; + ВызватьИсключение "Ошибка получения подчиненных страниц: " + Идентификатор + ТекстОшибки(РезультатЗапроса, URL, "GET"); КонецЕсли; @@ -261,16 +246,13 @@ ИдентификаторСтраницы = ""; РезультатЗапроса = ВыполнитьHTTPЗапрос(ПараметрыПодключения, "POST", URL, ТелоЗапроса); - Если РезультатЗапроса.КодСостояния = 200 Тогда + Если УспешныйЗапрос(РезультатЗапроса) Тогда ИдентификаторСтраницы = НайтиСтраницуПоИмени(ПараметрыПодключения, КодПространства, ИмяСтраницы); Иначе - ВызватьИсключение "Ошибка создания страницы:" + КодПространства + "." + ИмяСтраницы + "" - "Запрос: " + URL + " - |КодСостояния: " + РезультатЗапроса.КодСостояния + " - |Ответ: " + РезультатЗапроса.Ответ; + ВызватьИсключение "Ошибка создания страницы:" + КодПространства + "." + ИмяСтраницы + ТекстОшибки(РезультатЗапроса, URL, "POST"); КонецЕсли; @@ -356,12 +338,9 @@ РезультатЗапроса = ВыполнитьHTTPЗапрос(ПараметрыПодключения, "PUT", URL, ТелоЗапроса); - Если РезультатЗапроса.КодСостояния <> 200 Тогда + Если НЕ УспешныйЗапрос(РезультатЗапроса) Тогда - ВызватьИсключение "Ошибка обновления страницы:" + КодПространства + "." + ИмяСтраницы + - "Запрос: " + URL + " - |КодСостояния: " + РезультатЗапроса.КодСостояния + " - |Ответ: " + РезультатЗапроса.Ответ; + ВызватьИсключение "Ошибка обновления страницы:" + КодПространства + "." + ИмяСтраницы + ТекстОшибки(РезультатЗапроса, URL, "PUT"); КонецЕсли; @@ -409,7 +388,7 @@ // КодПространства - Строка - Код пространства confluence // ИмяСтраницы - Строка - Наименование страницы (заголовок) // Идентификатор - Строка - Идентификатор страницы -// УдалятьПодчиненные - Булево - признак необходимости удаления подчиненых страниц. +// УдалятьПодчиненные - Булево - признак необходимости удаления подчиненных страниц. // Если данный параметр = ЛОЖЬ и есть подчиненные страницы, то удаление не будет выполнено // и будет вызвано исключение // @@ -445,12 +424,9 @@ URL = ПолучитьURLОперации(,, Идентификатор); РезультатЗапроса = ВыполнитьHTTPЗапрос(ПараметрыПодключения, "DELETE", URL); - Если НЕ (РезультатЗапроса.КодСостояния = 200 И РезультатЗапроса.КодСостояния = 204) Тогда + Если НЕ (УспешныйЗапрос(РезультатЗапроса) ИЛИ РезультатЗапроса.КодСостояния = 204) Тогда - ВызватьИсключение "Ошибка обновления страницы:" + КодПространства + "." + ИмяСтраницы + - "Запрос: " + URL + " - |КодСостояния: " + РезультатЗапроса.КодСостояния + " - |Ответ: " + РезультатЗапроса.Ответ; + ВызватьИсключение "Ошибка удаления страницы:" + КодПространства + "." + ИмяСтраницы + ТекстОшибки(РезультатЗапроса, URL, "DELETE"); КонецЕсли; @@ -474,29 +450,369 @@ РезультатЗапроса = ВыполнитьHTTPЗапрос(ПараметрыПодключения, "POST", URL, ТелоЗапроса); - Если РезультатЗапроса.КодСостояния = 200 Тогда + Если УспешныйЗапрос(РезультатЗапроса) Тогда Результат = Истина; Иначе - ВызватьИсключение "Ошибка прикрепления метки: - |Запрос: " + URL + " - |КодСостояния: " + РезультатЗапроса.КодСостояния + " - |Ответ: " + РезультатЗапроса.Ответ; + ВызватьИсключение "Ошибка прикрепления метки:" + ТекстОшибки(РезультатЗапроса, URL, "POST"); + + КонецЕсли; + + Возврат Результат; + +КонецФункции + +#Область НовоеAPI + +// АдресСтраницы +// Описание расположения страницы +// +// Параметры: +// КодПространства - Строка - Код пространства confluence +// ИмяСтраницы - Строка - имя страницы, должно быть уникально в пределах пространства +// Идентификатор - Строка - Идентификатор страницы confluence, может быть получен только поиском +// ИдентификаторРодителя - Строка - Идентификатор родителя страницы confluence, может быть получен только поиском +// +// Возвращаемое значение: +// Структура - Описание расположения страницы +// +Функция АдресСтраницы(КодПространства, ИмяСтраницы = "", Идентификатор = "", ИдентификаторРодителя = "") Экспорт + + Адрес = Новый Структура; + + Адрес.Вставить("КодПространства", КодПространства); + Адрес.Вставить("ИмяСтраницы", ИмяСтраницы); + Адрес.Вставить("Идентификатор", Идентификатор); + Адрес.Вставить("ИдентификаторРодителя", ИдентификаторРодителя); + + Возврат Адрес; + +КонецФункции + +// Создать +// Создает новую страницу в confluence и возвращает идентификатор новой страницы, также установив его в "АдресСтраницы" +// +// Параметры: +// ПараметрыПодключения - Структура - Описание подключения, см. confluence.ОписаниеПодключения +// АдресСтраницы - Структура - Описание расположения страницы, см. confluence.АдресСтраницы +// Содержимое - Строка, Структура - Содержимое новой страницы. +// либо строка содержимого в формате confluence +// либо структура с ключами Значение и Формат (Confluence, Markdown, HTML) +// +// Возвращаемое значение: +// Строка - Идентификатор созданной страницы +// +Функция Создать(ПараметрыПодключения, АдресСтраницы, Содержимое = Неопределено) Экспорт + + HTTPМетод = "POST"; + + ОписаниеСодержимого = ПодготовитьСодержимое(ПараметрыПодключения, Содержимое); + ПараметрыКоманды = ПараметрыСозданияОбновления(АдресСтраницы, ОписаниеСодержимого); + + URL = ПолучитьURLОперации(); + + РезультатЗапроса = ВыполнитьHTTPЗапрос(ПараметрыПодключения, HTTPМетод, URL, СериализоватьJSON(ПараметрыКоманды)); + + Если УспешныйЗапрос(РезультатЗапроса) Тогда + + АдресСтраницы.Идентификатор = НайтиСтраницуПоИмени(ПараметрыПодключения, АдресСтраницы.КодПространства, АдресСтраницы.ИмяСтраницы); + + Иначе + + ВызватьИсключение СтрШаблон("Ошибка создания страницы: %1.%2%3", + АдресСтраницы.КодПространства, + АдресСтраницы.ИмяСтраницы, + ТекстОшибки(РезультатЗапроса, URL, HTTPМетод)); + + КонецЕсли; + + Возврат АдресСтраницы.Идентификатор; + +КонецФункции + +// Обновить +// Выполняет обновление существующей страницы +// +// Параметры: +// ПараметрыПодключения - Структура - Описание подключения, см. confluence.ОписаниеПодключения +// АдресСтраницы - Структура - Описание расположения страницы, см. confluence.АдресСтраницы +// Содержимое - Строка, Структура - Содержимое новой страницы. +// либо строка содержимого в формате confluence +// либо структура с ключами Значение и Формат (Confluence, Markdown, HTML) +// +// ОбновитьПриИзмененииСодержимого - Булево - Выполнять только если содержимое изменено, +// Если установлено в Истина, но меняется только родитель или имя страницы - изменения не будут применены +// +// Возвращаемое значение: +// Неопределено, Строка - Когда обновление не требуется будет возвращено Неопределено, +// в других случаях - идентификатор страницы +// +Функция Обновить(ПараметрыПодключения, АдресСтраницы, Содержимое = Неопределено, ОбновитьПриИзмененииСодержимого = Ложь) Экспорт + + Если ПустаяСтрока(АдресСтраницы.ИмяСтраницы) И ПустаяСтрока(АдресСтраницы.Идентификатор) Тогда + + ВызватьИсключение "Ошибка обновления страницы: " + АдресСтраницы.КодПространства + "." + АдресСтраницы.ИмяСтраницы + + "Ответ: не указаны имя страницы и идентификатор"; + + КонецЕсли; + + Если ПустаяСтрока(АдресСтраницы.Идентификатор) Тогда + + АдресСтраницы.Идентификатор = НайтиСтраницуПоИмени(ПараметрыПодключения, АдресСтраницы.КодПространства, АдресСтраницы.ИмяСтраницы); + + Если ПустаяСтрока(АдресСтраницы.Идентификатор) Тогда + + ВызватьИсключение "Ошибка обновления страницы: " + АдресСтраницы.КодПространства + "." + АдресСтраницы.ИмяСтраницы + + "Ответ: не найдена страница"; + + КонецЕсли; + + КонецЕсли; + + ОписаниеСодержимого = ПодготовитьСодержимое(ПараметрыПодключения, Содержимое); + + Если ОбновитьПриИзмененииСодержимого Тогда + + СодержимоеConfluence = СодержимоеСтраницыПоИдентификатору(ПараметрыПодключения, АдресСтраницы.Идентификатор); + Регексп = Новый РегулярноеВыражение("ac\:macro-id=""[a-z0-9-]{36}"""); // идентификаторы плагинов меняются + Регексп.Многострочный = Истина; + СодержимоеConfluence = Регексп.Заменить(СодержимоеConfluence, "NONE"); + ВрСодержимое = Регексп.Заменить(ОписаниеСодержимого.Значение, "NONE"); + + Если ОписаниеСодержимого.Формат = ФорматыСодержимого.MarkDown Тогда + + // TODO: Известные проблемы при сравнении MarkDown + // 1. Если в исходном файле есть "/", то для публикации его необходимо экранировать + // но до сравнения, тк от confluence он приходит в норм виде + // 2. Картинки (img) при конвертации тэк не закрытый, в confluence - закрытый + СодержимоеConfluence = СтрЗаменить(СодержимоеConfluence, "", ""); // Особенность конвертера Markdown → Confluence + + КонецЕсли; + + + Если СтрСравнить(СокрЛП(СодержимоеConfluence), СокрЛП(ВрСодержимое)) = 0 Тогда + + Возврат Неопределено; + + КонецЕсли; + + КонецЕсли; + + URL = ПолучитьURLОперации(, , АдресСтраницы.Идентификатор); + Версия = ВерсияСтраницыПоИдентификатору(ПараметрыПодключения, АдресСтраницы.Идентификатор); + Версия = Формат(Число(Версия) + 1, "ЧГ="); + + HTTPМетод = "PUT"; + + ПараметрыКоманды = ПараметрыСозданияОбновления(АдресСтраницы, ОписаниеСодержимого, Версия); + + ТелоЗапроса = СериализоватьJSON(ПараметрыКоманды); + + РезультатЗапроса = ВыполнитьHTTPЗапрос(ПараметрыПодключения, HTTPМетод, URL, ТелоЗапроса); + + Если НЕ УспешныйЗапрос(РезультатЗапроса) Тогда + + ВызватьИсключение "Ошибка обновления страницы:" + АдресСтраницы.КодПространства + "." + АдресСтраницы.ИмяСтраницы + ТекстОшибки(РезультатЗапроса, URL, HTTPМетод); + + КонецЕсли; + + Возврат АдресСтраницы.Идентификатор; + +КонецФункции + +// СоздатьИлиОбновить +// Создает новую страницу, либо обновление существующую +// +// Параметры: +// ПараметрыПодключения - Структура - Описание подключения, см. confluence.ОписаниеПодключения +// АдресСтраницы - Структура - Описание расположения страницы, см. confluence.АдресСтраницы +// Содержимое - Строка, Структура - Содержимое новой страницы. +// либо строка содержимого в формате confluence +// либо структура с ключами Значение и Формат (Confluence, Markdown, HTML) +// ОбновитьПриИзмененииСодержимого - Булево - Выполнять только если содержимое изменено, +// Если установлено в Истина, но меняется только родитель или имя страницы - изменения не будут применены +// +// Возвращаемое значение: +// Структура - Ключи: +// Успешно - Булево - не было ошибок +// Действие - Строка - "Создание", "Обновление", Неопределено +// +Функция СоздатьИлиОбновить(ПараметрыПодключения, АдресСтраницы, Содержимое, ОбновитьПриИзмененииСодержимого) Экспорт + + Результат = Новый Структура("Успешно, Действие"); + Если ПустаяСтрока(АдресСтраницы.Идентификатор) Тогда + + АдресСтраницы.Идентификатор = НайтиСтраницуПоИмени(ПараметрыПодключения, АдресСтраницы.КодПространства, АдресСтраницы.ИмяСтраницы); + + КонецЕсли; + + Если Не ПустаяСтрока(АдресСтраницы.Идентификатор) Тогда + + РезультатОбновления = Обновить( + ПараметрыПодключения, + АдресСтраницы, + Содержимое, + ОбновитьПриИзмененииСодержимого); + + Если РезультатОбновления <> Неопределено Тогда + Результат.Действие = "Обновление"; + КонецЕсли; - Результат = Ложь; + Иначе + АдресСтраницы.Идентификатор = Создать(ПараметрыПодключения, АдресСтраницы, Содержимое); + Результат.Действие = "Создание"; + КонецЕсли; + Результат.Успешно = Истина; + Возврат Результат; КонецФункции +#КонецОбласти + /////////////////////////////////////////////////////////////////// // СЛУЖЕБНЫЙ ФУНКЦИОНАЛ /////////////////////////////////////////////////////////////////// +#Область СлужебныеМетоды + +Функция ПараметрыСозданияОбновления(Адрес, ОписаниеСодержимого, Версия = Неопределено) + + ПараметрыКоманды = Новый Структура(); + ПараметрыКоманды.Вставить("type", "page"); + ПараметрыКоманды.Вставить("title", Адрес.ИмяСтраницы); + ПараметрыКоманды.Вставить("space", Новый Структура("key", Адрес.КодПространства)); + + Если Версия <> Неопределено Тогда + + ПараметрыКоманды.Вставить("version", Новый Структура("number", Версия)); + + КонецЕсли; + + Если Не ПустаяСтрока(Адрес.ИдентификаторРодителя) Тогда + Родители = Новый Массив(); + Родители.Добавить(Новый Структура("id", Адрес.ИдентификаторРодителя)); + ПараметрыКоманды.Вставить("ancestors", Родители); + КонецЕсли; + + ФорматПоУмолчанию = confluence.ФорматыСодержимого.Confluence; + Значение = ""; + Формат = ФорматПоУмолчанию; + + Если ТипЗнч(ОписаниеСодержимого) <> Тип("Структура") + ИЛИ НЕ ОписаниеСодержимого.Свойство("Формат") + ИЛИ НЕ ОписаниеСодержимого.Свойство("Значение") Тогда + + ВызватьИсключение "Передано не корректное описание содержимого"; + + КонецЕсли; + + Если ЗначениеЗаполнено(ОписаниеСодержимого.Значение) Тогда + + Если ОписаниеСодержимого.Формат = ФорматыСодержимого.MarkDown Тогда + + Значение = СтрЗаменить(ОписаниеСодержимого.Значение, "\", "\\"); + + Хранение = Новый Структура("value, representation", Значение, "editor"); + ТелоСтраницы = Новый Структура("editor", Хранение); + + Иначе + + Хранение = Новый Структура("value, representation", ОписаниеСодержимого.Значение, "storage"); + ТелоСтраницы = Новый Структура("storage", Хранение); + + КонецЕсли; + + ПараметрыКоманды.Вставить("body", ТелоСтраницы); + + КонецЕсли; + + Возврат ПараметрыКоманды; + +КонецФункции + +Функция ПодготовитьСодержимое(ПараметрыПодключения, Содержимое) + + ОписаниеСодержимого = Новый Структура("Значение, Формат"); + + ФорматПоУмолчанию = "confluence"; + Значение = ""; + Формат = ФорматПоУмолчанию; + + Если ТипЗнч(Содержимое) = Тип("Структура") Тогда + + Если Содержимое.Свойство("Значение") Тогда + + Значение = Содержимое.Значение; + + ИначеЕсли Содержимое.Свойство("ИмяФайла") Тогда + + Значение = ТекстФайла(Содержимое.ИмяФайла); + + КонецЕсли; + + Если Содержимое.Свойство("Формат") Тогда + + Формат = Содержимое.Формат; + + КонецЕсли; + + ИначеЕсли ЗначениеЗаполнено(Содержимое) Тогда + + Значение = Содержимое; + + КонецЕсли; + + Если ПустаяСтрока(Формат) Тогда + + Формат = ФорматПоУмолчанию; + + КонецЕсли; + + Если ЗначениеЗаполнено(Значение) И Формат = ФорматыСодержимого.MarkDown Тогда + + Значение = ПреобразоватьMarkdownToConfluence(ПараметрыПодключения, Значение); + + КонецЕсли; + + ОписаниеСодержимого.Формат = Формат; + ОписаниеСодержимого.Значение = Значение; + + Возврат ОписаниеСодержимого; + +КонецФункции + +Функция ПреобразоватьMarkdownToConfluence(ПараметрыПодключения, СодержимоеMarkdown) + + Идентификатор = ""; + + URLОперации = "rest/tinymce/1/markdownxhtmlconverter"; + + ПараметрыОперации = Новый Структура(); + ПараметрыОперации.Вставить("wiki", СодержимоеMarkdown); + + Тело = СериализоватьJSON(ПараметрыОперации); + РезультатЗапроса = ВыполнитьHTTPЗапрос(ПараметрыПодключения, "POST", URLОперации, Тело, "text/html; charset=UTF-8"); + + Если УспешныйЗапрос(РезультатЗапроса) Тогда + + Возврат РезультатЗапроса.Ответ; + + Иначе + + ВызватьИсключение "Ошибка преобразования markdown → html" + ТекстОшибки(РезультатЗапроса, URLОперации, "POST"); + + КонецЕсли; + + Возврат Идентификатор; + +КонецФункции + Функция ПолучитьURLОперации(КодПространства = "", ИмяСтраницы = "", Идентификатор = "", Операция = "") URLОперации = "rest/api/content/"; @@ -526,20 +842,24 @@ КонецФункции // ПолучитьURLОперации() -Функция ВыполнитьHTTPЗапрос(ПараметрыПодключения, Метод, URL, ТелоЗапроса = "") +Функция ВыполнитьHTTPЗапрос(ПараметрыПодключения, Метод, URL, ТелоЗапроса = "", Accept = "application/json; charset=UTF-8") HTTPЗапрос = Новый HTTPЗапрос; - HTTPЗапрос.Заголовки.Вставить("Content-Type", "application/json"); - HTTPЗапрос.Заголовки.Вставить("Accept", "application/json"); + HTTPЗапрос.Заголовки.Вставить("Content-Type", "application/json; charset=UTF-8"); + HTTPЗапрос.Заголовки.Вставить("Accept", Accept); HTTPЗапрос.АдресРесурса = URL; + Если Не ПустаяСтрока(ТелоЗапроса) Тогда - HTTPЗапрос.УстановитьТелоИзСтроки(ТелоЗапроса); + HTTPЗапрос.УстановитьТелоИзСтроки(ТелоЗапроса, КодировкаТекста.UTF8); КонецЕсли; - HTTP = Новый HTTPСоединение(ПараметрыПодключения.АдресСервера,, ПараметрыПодключения.Пользователь, ПараметрыПодключения.Пароль); + HTTP = Новый HTTPСоединение(ПараметрыПодключения.АдресСервера, , + ПараметрыПодключения.Пользователь, + ПараметрыПодключения.Пароль); + Если СтрСравнить(Метод, "GET") = 0 Тогда Ответ = HTTP.Получить(HTTPЗапрос); @@ -558,10 +878,66 @@ Иначе - ВызватьИсключение "Неизвестный метод: '" + Метод + "'" + ВызватьИсключение СтрШаблон("Неизвестный метод: '%1'", Метод); КонецЕсли; - Возврат Новый Структура("Ответ, КодСостояния", Ответ.ПолучитьТелоКакСтроку(), Ответ.КодСостояния); + Возврат Новый Структура("Ответ, КодСостояния", Ответ.ПолучитьТелоКакСтроку(КодировкаТекста.UTF8), Ответ.КодСостояния); КонецФункции // ВыполнитьHTTPЗапрос() + +Функция УспешныйЗапрос(РезультатЗапроса) + + КодОтветаУспешно = 200; + Возврат РезультатЗапроса.КодСостояния = КодОтветаУспешно; + +КонецФункции + +Функция СериализоватьJSON(Значение) + + ПараметрыЗаписи = Новый ПараметрыЗаписиJSON(Ложь, , Истина, , , , , , Истина); + Запись = Новый ЗаписьJSON(ПараметрыЗаписи); + Запись.УстановитьСтроку(); + + ЗаписатьJSON(Запись, Значение); + + Возврат Запись.Закрыть(); + +КонецФункции + +Функция ДесериализоватьJSON(СтрокаJSON) + Чтение = Новый ЧтениеJSON(); + Чтение.УстановитьСтроку(СтрокаJSON); + Данные = ПрочитатьJSON(Чтение); + Чтение.Закрыть(); + + Возврат Данные; + +КонецФункции + +Функция ТекстОшибки(РезультатЗапроса, URL, HTTМетод) + + Возврат СтрШаблон( + " + |Запрос: [%4] %1 + |КодСостояния: %2 + |Ответ: %3", URL, РезультатЗапроса.КодСостояния, РезультатЗапроса.Ответ, HTTМетод); + +КонецФункции + +Функция ТекстФайла(ИмяФайла) + + Чтение = Новый ЧтениеТекста(ИмяФайла, КодировкаТекста.UTF8); + Содержимое = Чтение.Прочитать(); + Чтение.Закрыть(); + + Возврат Содержимое; + +КонецФункции + +#КонецОбласти + +ФорматыСодержимого = Новый Структура(); +ФорматыСодержимого.Вставить("Markdown", "markdown"); +ФорматыСодержимого.Вставить("Confluence", "confluence"); +ФорматыСодержимого.Вставить("HTML", "html"); \ No newline at end of file