Initial SFERA platform baseline
This commit is contained in:
@@ -0,0 +1,45 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<MetaDataObject xmlns="http://v8.1c.ru/8.3/MDClasses" xmlns:app="http://v8.1c.ru/8.2/managed-application/core" xmlns:cfg="http://v8.1c.ru/8.1/data/enterprise/current-config" xmlns:cmi="http://v8.1c.ru/8.2/managed-application/cmi" xmlns:ent="http://v8.1c.ru/8.1/data/enterprise" xmlns:lf="http://v8.1c.ru/8.2/managed-application/logform" xmlns:pal="http://v8.1c.ru/8.1/data/ui/colors/palette" xmlns:style="http://v8.1c.ru/8.1/data/ui/style" xmlns:sys="http://v8.1c.ru/8.1/data/ui/fonts/system" xmlns:v8="http://v8.1c.ru/8.1/data/core" xmlns:v8ui="http://v8.1c.ru/8.1/data/ui" xmlns:web="http://v8.1c.ru/8.1/data/ui/colors/web" xmlns:win="http://v8.1c.ru/8.1/data/ui/colors/windows" xmlns:xen="http://v8.1c.ru/8.3/xcf/enums" xmlns:xpr="http://v8.1c.ru/8.3/xcf/predef" xmlns:xr="http://v8.1c.ru/8.3/xcf/readable" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.21">
|
||||
<HTTPService uuid="f8df0ad1-f152-49df-aebb-9b2ff8db4580">
|
||||
<Properties>
|
||||
<ObjectBelonging>Native</ObjectBelonging>
|
||||
<Name>BridgeHTTP</Name>
|
||||
<Synonym>
|
||||
<v8:item>
|
||||
<v8:lang>ru</v8:lang>
|
||||
<v8:content>SFERA</v8:content>
|
||||
</v8:item>
|
||||
</Synonym>
|
||||
<Comment/>
|
||||
<RootURL>sfera</RootURL>
|
||||
<ReuseSessions>AutoUse</ReuseSessions>
|
||||
<SessionMaxAge>20</SessionMaxAge>
|
||||
</Properties>
|
||||
<ChildObjects>
|
||||
<URLTemplate uuid="1872224d-87e7-4c12-bf6f-1af0520d346f">
|
||||
<Properties><Name>health</Name><Synonym/><Comment/><Template>/health</Template></Properties>
|
||||
<ChildObjects><Method uuid="499209a4-9b88-46bb-9c13-5d88dff15ead"><Properties><Name>GET</Name><Synonym/><Comment/><HTTPMethod>GET</HTTPMethod><Handler>Health</Handler></Properties></Method></ChildObjects>
|
||||
</URLTemplate>
|
||||
<URLTemplate uuid="d00d9ff8-5357-406c-9f0d-1e0ff5a8d02a">
|
||||
<Properties><Name>v1_metadata</Name><Synonym/><Comment/><Template>/v1/metadata</Template></Properties>
|
||||
<ChildObjects><Method uuid="ec0d5d95-bfe9-4389-8f95-fe2369c67e69"><Properties><Name>POST</Name><Synonym/><Comment/><HTTPMethod>POST</HTTPMethod><Handler>MetadataSnapshot</Handler></Properties></Method></ChildObjects>
|
||||
</URLTemplate>
|
||||
<URLTemplate uuid="746ca047-7cad-4ce0-b7e3-8bfdb60e900e">
|
||||
<Properties><Name>v1_query</Name><Synonym/><Comment/><Template>/v1/query</Template></Properties>
|
||||
<ChildObjects><Method uuid="1172f149-8cb9-4f57-bb56-9a887bd5f1d6"><Properties><Name>POST</Name><Synonym/><Comment/><HTTPMethod>POST</HTTPMethod><Handler>Query</Handler></Properties></Method></ChildObjects>
|
||||
</URLTemplate>
|
||||
<URLTemplate uuid="d308d5a0-58e6-49ce-8e26-6336d78c756e">
|
||||
<Properties><Name>v1_data_read</Name><Synonym/><Comment/><Template>/v1/data/read</Template></Properties>
|
||||
<ChildObjects><Method uuid="49505f43-68dd-4ee2-ad77-f5f2a41fd93d"><Properties><Name>POST</Name><Synonym/><Comment/><HTTPMethod>POST</HTTPMethod><Handler>DataRead</Handler></Properties></Method></ChildObjects>
|
||||
</URLTemplate>
|
||||
<URLTemplate uuid="2a5a4ac1-2a21-40d2-90d9-11f52578d6bb">
|
||||
<Properties><Name>v1_data_write</Name><Synonym/><Comment/><Template>/v1/data/write</Template></Properties>
|
||||
<ChildObjects><Method uuid="3dac1d67-6371-4d92-9b9a-de2652e6a7b5"><Properties><Name>POST</Name><Synonym/><Comment/><HTTPMethod>POST</HTTPMethod><Handler>DataWrite</Handler></Properties></Method></ChildObjects>
|
||||
</URLTemplate>
|
||||
<URLTemplate uuid="e7b07595-572f-4f2c-8b92-737072bf9e5b">
|
||||
<Properties><Name>v1_metadata_apply</Name><Synonym/><Comment/><Template>/v1/metadata/apply</Template></Properties>
|
||||
<ChildObjects><Method uuid="efcc63f3-c2f5-4729-8656-3b83112f7299"><Properties><Name>POST</Name><Synonym/><Comment/><HTTPMethod>POST</HTTPMethod><Handler>MetadataApply</Handler></Properties></Method></ChildObjects>
|
||||
</URLTemplate>
|
||||
</ChildObjects>
|
||||
</HTTPService>
|
||||
</MetaDataObject>
|
||||
@@ -0,0 +1,268 @@
|
||||
#Область ОбработчикиHTTPСервиса
|
||||
|
||||
Функция Health(Запрос) Экспорт
|
||||
Возврат ОтветJSON(BridgeHealth());
|
||||
КонецФункции
|
||||
|
||||
Функция MetadataSnapshot(Запрос) Экспорт
|
||||
Контекст = ПрочитатьКонтекст(Запрос);
|
||||
Если Не Авторизован(Запрос, Контекст) Тогда
|
||||
Возврат ОтветОшибка(401, "Unauthorized");
|
||||
КонецЕсли;
|
||||
Возврат ОтветJSON(BridgeMetadataSnapshot());
|
||||
КонецФункции
|
||||
|
||||
Функция Query(Запрос) Экспорт
|
||||
Контекст = ПрочитатьКонтекст(Запрос);
|
||||
Если Не Авторизован(Запрос, Контекст) Тогда
|
||||
Возврат ОтветОшибка(401, "Unauthorized");
|
||||
КонецЕсли;
|
||||
Возврат ОтветJSON(BridgeExecuteQuery(
|
||||
ПолучитьПоле(Контекст, "payload", Новый Структура),
|
||||
ПолучитьПоле(Контекст, "dry_run", Истина),
|
||||
ПолучитьПоле(Контекст, "allow_mutation", Ложь)));
|
||||
КонецФункции
|
||||
|
||||
Функция DataRead(Запрос) Экспорт
|
||||
Контекст = ПрочитатьКонтекст(Запрос);
|
||||
Если Не Авторизован(Запрос, Контекст) Тогда
|
||||
Возврат ОтветОшибка(401, "Unauthorized");
|
||||
КонецЕсли;
|
||||
Возврат ОтветJSON(BridgeReadData(ПолучитьПоле(Контекст, "payload", Новый Структура)));
|
||||
КонецФункции
|
||||
|
||||
Функция DataWrite(Запрос) Экспорт
|
||||
Контекст = ПрочитатьКонтекст(Запрос);
|
||||
Если Не Авторизован(Запрос, Контекст) Тогда
|
||||
Возврат ОтветОшибка(401, "Unauthorized");
|
||||
КонецЕсли;
|
||||
Возврат ОтветJSON(BridgeWriteData(
|
||||
ПолучитьПоле(Контекст, "payload", Новый Структура),
|
||||
ПолучитьПоле(Контекст, "dry_run", Истина),
|
||||
ПолучитьПоле(Контекст, "allow_mutation", Ложь)));
|
||||
КонецФункции
|
||||
|
||||
Функция MetadataApply(Запрос) Экспорт
|
||||
Контекст = ПрочитатьКонтекст(Запрос);
|
||||
Если Не Авторизован(Запрос, Контекст) Тогда
|
||||
Возврат ОтветОшибка(401, "Unauthorized");
|
||||
КонецЕсли;
|
||||
Возврат ОтветJSON(BridgeMetadataApply(
|
||||
ПолучитьПоле(Контекст, "payload", Новый Структура),
|
||||
ПолучитьПоле(Контекст, "dry_run", Истина)));
|
||||
КонецФункции
|
||||
|
||||
#КонецОбласти
|
||||
|
||||
#Область ЛогикаSFERA
|
||||
|
||||
Функция BridgeHealth()
|
||||
Результат = Новый Структура;
|
||||
Результат.Вставить("status", "ok");
|
||||
Результат.Вставить("extension", "SFERA");
|
||||
Результат.Вставить("version", "0.1.0");
|
||||
Результат.Вставить("timestamp", ТекущаяДата());
|
||||
Результат.Вставить("mutation_supported", Истина);
|
||||
Результат.Вставить("metadata_apply_supported", Ложь);
|
||||
Возврат Результат;
|
||||
КонецФункции
|
||||
|
||||
Функция BridgeMetadataSnapshot()
|
||||
Коллекции = Новый Массив;
|
||||
ДобавитьКоллекциюМетаданных(Коллекции, "Справочники", Метаданные.Справочники);
|
||||
ДобавитьКоллекциюМетаданных(Коллекции, "Документы", Метаданные.Документы);
|
||||
ДобавитьКоллекциюМетаданных(Коллекции, "Перечисления", Метаданные.Перечисления);
|
||||
ДобавитьКоллекциюМетаданных(Коллекции, "Отчеты", Метаданные.Отчеты);
|
||||
ДобавитьКоллекциюМетаданных(Коллекции, "Обработки", Метаданные.Обработки);
|
||||
ДобавитьКоллекциюМетаданных(Коллекции, "ПланыОбмена", Метаданные.ПланыОбмена);
|
||||
ДобавитьКоллекциюМетаданных(Коллекции, "ПланыВидовХарактеристик", Метаданные.ПланыВидовХарактеристик);
|
||||
ДобавитьКоллекциюМетаданных(Коллекции, "ПланыСчетов", Метаданные.ПланыСчетов);
|
||||
ДобавитьКоллекциюМетаданных(Коллекции, "ПланыВидовРасчета", Метаданные.ПланыВидовРасчета);
|
||||
ДобавитьКоллекциюМетаданных(Коллекции, "РегистрыСведений", Метаданные.РегистрыСведений);
|
||||
ДобавитьКоллекциюМетаданных(Коллекции, "РегистрыНакопления", Метаданные.РегистрыНакопления);
|
||||
ДобавитьКоллекциюМетаданных(Коллекции, "РегистрыБухгалтерии", Метаданные.РегистрыБухгалтерии);
|
||||
ДобавитьКоллекциюМетаданных(Коллекции, "РегистрыРасчета", Метаданные.РегистрыРасчета);
|
||||
ДобавитьКоллекциюМетаданных(Коллекции, "БизнесПроцессы", Метаданные.БизнесПроцессы);
|
||||
ДобавитьКоллекциюМетаданных(Коллекции, "Задачи", Метаданные.Задачи);
|
||||
ДобавитьКоллекциюМетаданных(Коллекции, "ОбщиеМодули", Метаданные.ОбщиеМодули);
|
||||
ДобавитьКоллекциюМетаданных(Коллекции, "Роли", Метаданные.Роли);
|
||||
ДобавитьКоллекциюМетаданных(Коллекции, "Подсистемы", Метаданные.Подсистемы);
|
||||
ДобавитьКоллекциюМетаданных(Коллекции, "HTTPСервисы", Метаданные.HTTPСервисы);
|
||||
ДобавитьКоллекциюМетаданных(Коллекции, "WebСервисы", Метаданные.WebСервисы);
|
||||
Результат = Новый Структура;
|
||||
Результат.Вставить("status", "ok");
|
||||
Результат.Вставить("collections", Коллекции);
|
||||
Возврат Результат;
|
||||
КонецФункции
|
||||
|
||||
Функция BridgeExecuteQuery(Параметры, DryRun, AllowMutation)
|
||||
ТекстЗапроса = Строка(ПолучитьПоле(Параметры, "query", ""));
|
||||
Если ПустаяСтрока(ТекстЗапроса) Тогда
|
||||
Возврат ОшибкаSFERA("query is required");
|
||||
КонецЕсли;
|
||||
Если ЗапросОпасный(ТекстЗапроса) И Не AllowMutation Тогда
|
||||
Возврат ОшибкаSFERA("Mutation query is blocked. Set allow_mutation=true and disable dry_run.");
|
||||
КонецЕсли;
|
||||
Если DryRun Тогда
|
||||
Результат = Новый Структура;
|
||||
Результат.Вставить("status", "dry_run");
|
||||
Результат.Вставить("query", ТекстЗапроса);
|
||||
Результат.Вставить("mutation_detected", ЗапросОпасный(ТекстЗапроса));
|
||||
Возврат Результат;
|
||||
КонецЕсли;
|
||||
Запрос = Новый Запрос(ТекстЗапроса);
|
||||
ПараметрыЗапроса = ПолучитьПоле(Параметры, "parameters", Неопределено);
|
||||
Если ТипЗнч(ПараметрыЗапроса) = Тип("Структура") Тогда
|
||||
Для Каждого Параметр Из ПараметрыЗапроса Цикл
|
||||
Запрос.УстановитьПараметр(Параметр.Ключ, Параметр.Значение);
|
||||
КонецЦикла;
|
||||
КонецЕсли;
|
||||
Таблица = Запрос.Выполнить().Выгрузить();
|
||||
Строки = Новый Массив;
|
||||
Для Каждого СтрокаТаблицы Из Таблица Цикл
|
||||
Строки.Добавить(СтрокаТаблицыВСтруктуру(СтрокаТаблицы, Таблица.Колонки));
|
||||
Если Строки.Количество() >= 1000 Тогда
|
||||
Прервать;
|
||||
КонецЕсли;
|
||||
КонецЦикла;
|
||||
Результат = Новый Структура;
|
||||
Результат.Вставить("status", "ok");
|
||||
Результат.Вставить("rows", Строки);
|
||||
Результат.Вставить("limit", 1000);
|
||||
Возврат Результат;
|
||||
КонецФункции
|
||||
|
||||
Функция BridgeReadData(Параметры)
|
||||
Если ЗначениеЗаполнено(ПолучитьПоле(Параметры, "query", "")) Тогда
|
||||
Возврат BridgeExecuteQuery(Параметры, Ложь, Ложь);
|
||||
КонецЕсли;
|
||||
Возврат ОшибкаSFERA("For generic data read use query with SELECT text.");
|
||||
КонецФункции
|
||||
|
||||
Функция BridgeWriteData(Параметры, DryRun, AllowMutation)
|
||||
Если Не AllowMutation Тогда
|
||||
Возврат ОшибкаSFERA("Write operation is blocked.");
|
||||
КонецЕсли;
|
||||
Если DryRun Тогда
|
||||
Результат = Новый Структура;
|
||||
Результат.Вставить("status", "dry_run");
|
||||
Результат.Вставить("message", "Write request accepted for preview only.");
|
||||
Результат.Вставить("payload", Параметры);
|
||||
Возврат Результат;
|
||||
КонецЕсли;
|
||||
Возврат ОшибкаSFERA("Generic write adapter is intentionally not enabled yet. Implement object-specific handlers first.");
|
||||
КонецФункции
|
||||
|
||||
Функция BridgeMetadataApply(Параметры, DryRun)
|
||||
Результат = Новый Структура;
|
||||
Результат.Вставить("status", "planned");
|
||||
Результат.Вставить("message", "Changing configuration structure is performed by SFERA Windows Agent through Designer and .cfe update, not by runtime HTTP.");
|
||||
Результат.Вставить("dry_run", DryRun);
|
||||
Результат.Вставить("payload", Параметры);
|
||||
Возврат Результат;
|
||||
КонецФункции
|
||||
|
||||
#КонецОбласти
|
||||
|
||||
#Область СлужебныеПроцедурыИФункции
|
||||
|
||||
Функция ПрочитатьКонтекст(Запрос)
|
||||
Тело = Запрос.ПолучитьТелоКакСтроку();
|
||||
Если ПустаяСтрока(Тело) Тогда
|
||||
Возврат Новый Структура;
|
||||
КонецЕсли;
|
||||
Чтение = Новый ЧтениеJSON;
|
||||
Чтение.УстановитьСтроку(Тело);
|
||||
Возврат ПрочитатьJSON(Чтение);
|
||||
КонецФункции
|
||||
|
||||
Функция Авторизован(Запрос, Контекст)
|
||||
// Основная авторизация выполняется публикацией 1С/IIS. Токен SFERA включается после настройки секрета.
|
||||
ОжидаемыйТокен = "";
|
||||
Если ПустаяСтрока(ОжидаемыйТокен) Тогда
|
||||
Возврат Истина;
|
||||
КонецЕсли;
|
||||
Возврат Запрос.Заголовки.Получить("X-SFERA-Token") = ОжидаемыйТокен;
|
||||
КонецФункции
|
||||
|
||||
Функция ОтветJSON(Данные, КодСостояния = 200)
|
||||
Запись = Новый ЗаписьJSON;
|
||||
Запись.УстановитьСтроку();
|
||||
ЗаписатьJSON(Запись, Данные);
|
||||
Тело = Запись.Закрыть();
|
||||
Ответ = Новый HTTPСервисОтвет(КодСостояния);
|
||||
Ответ.Заголовки.Вставить("Content-Type", "application/json; charset=utf-8");
|
||||
Ответ.УстановитьТелоИзСтроки(Тело, КодировкаТекста.UTF8);
|
||||
Возврат Ответ;
|
||||
КонецФункции
|
||||
|
||||
Функция ОтветОшибка(КодСостояния, Сообщение)
|
||||
Данные = Новый Структура;
|
||||
Данные.Вставить("status", "error");
|
||||
Данные.Вставить("message", Сообщение);
|
||||
Возврат ОтветJSON(Данные, КодСостояния);
|
||||
КонецФункции
|
||||
|
||||
Функция ПолучитьПоле(СтруктураИсточник, ИмяПоля, ЗначениеПоУмолчанию = Неопределено)
|
||||
Если ТипЗнч(СтруктураИсточник) = Тип("Структура") И СтруктураИсточник.Свойство(ИмяПоля) Тогда
|
||||
Возврат СтруктураИсточник[ИмяПоля];
|
||||
КонецЕсли;
|
||||
Возврат ЗначениеПоУмолчанию;
|
||||
КонецФункции
|
||||
|
||||
Процедура ДобавитьКоллекциюМетаданных(Коллекции, ИмяКоллекции, КоллекцияМетаданных)
|
||||
Объекты = Новый Массив;
|
||||
Для Каждого ОбъектМетаданных Из КоллекцияМетаданных Цикл
|
||||
Описание = Новый Структура;
|
||||
Описание.Вставить("name", ОбъектМетаданных.Имя);
|
||||
Описание.Вставить("synonym", ОбъектМетаданных.Синоним);
|
||||
Описание.Вставить("full_name", ИмяКоллекции + "." + ОбъектМетаданных.Имя);
|
||||
Объекты.Добавить(Описание);
|
||||
КонецЦикла;
|
||||
Коллекция = Новый Структура;
|
||||
Коллекция.Вставить("name", ИмяКоллекции);
|
||||
Коллекция.Вставить("count", Объекты.Количество());
|
||||
Коллекция.Вставить("objects", Объекты);
|
||||
Коллекции.Добавить(Коллекция);
|
||||
КонецПроцедуры
|
||||
|
||||
Функция ЗапросОпасный(ТекстЗапроса)
|
||||
Текст = НРег(ТекстЗапроса);
|
||||
Возврат Найти(Текст, "вставить") > 0
|
||||
Или Найти(Текст, "изменить") > 0
|
||||
Или Найти(Текст, "удалить") > 0
|
||||
Или Найти(Текст, "поместить") > 0
|
||||
Или Найти(Текст, "создать") > 0;
|
||||
КонецФункции
|
||||
|
||||
Функция СтрокаТаблицыВСтруктуру(СтрокаТаблицы, Колонки)
|
||||
Результат = Новый Структура;
|
||||
Для Каждого Колонка Из Колонки Цикл
|
||||
Результат.Вставить(Колонка.Имя, ЗначениеДляJSON(СтрокаТаблицы[Колонка.Имя]));
|
||||
КонецЦикла;
|
||||
Возврат Результат;
|
||||
КонецФункции
|
||||
|
||||
Функция ЗначениеДляJSON(Значение)
|
||||
Если Значение = Неопределено Или Значение = Null Тогда
|
||||
Возврат Неопределено;
|
||||
КонецЕсли;
|
||||
Если ТипЗнч(Значение) = Тип("Строка")
|
||||
Или ТипЗнч(Значение) = Тип("Число")
|
||||
Или ТипЗнч(Значение) = Тип("Булево") Тогда
|
||||
Возврат Значение;
|
||||
КонецЕсли;
|
||||
Если ТипЗнч(Значение) = Тип("Дата") Тогда
|
||||
Возврат Формат(Значение, "ДФ=yyyy-MM-ddTHH:mm:ss");
|
||||
КонецЕсли;
|
||||
Возврат Строка(Значение);
|
||||
КонецФункции
|
||||
|
||||
Функция ОшибкаSFERA(Сообщение)
|
||||
Результат = Новый Структура;
|
||||
Результат.Вставить("status", "error");
|
||||
Результат.Вставить("message", Сообщение);
|
||||
Возврат Результат;
|
||||
КонецФункции
|
||||
|
||||
#КонецОбласти
|
||||
Reference in New Issue
Block a user