Журнал технических изменений

Примечание

Ниже представлены технические изменения вышедших релизов. Краткий перечень изменений релизов отражен в новых функциях. Также см. информацию о важных изменениях.

Версия 2.10

Поисковые критерии для поиска идентификатора процессов и задачи

Значения идентификаторов в поисковых критериях стали числами вместо строк. Сохраненные поисковые запросы с этими критериями теперь не работают. Сохраненные запросы с участием этих критериев можно удалить. Для поиска по идентификаторам нужно заново добавить эти критерии.

Регистронезависимый поиск по тэгам

Изменен маппинг в Opensearch системного поля $tags в индексах и черновиках активов, теперь поиск по данному полю регистронезависимый.

Количество потоков запуска сканера

В backend.properties добавлен параметр org.unidata.mdm.system.cache.jet.cooperative.threads для настройки размера пула потоков Hazelcast Jet. Значение по умолчанию = 8.

Исправлена валидация параметра com.unidata.dg.ee.scanner.runner.local.parallelism. Теперь максимальное значение этого параметра не должно превышать число, заданное в параметре org.unidata.mdm.system.cache.jet.cooperative.threads.

Изменение удаления процессов и задач

REST метод DELETE /v2/workflow/core/process/{processInstanceId} объявлен deprecated. Необходимо использовать DELETE /v2/workflow/core/process с указанием в query params идентификатора процесса и названия процесса (Process Definition Key).

Добавлен новый сегмент com.unidata.dg.workflow.data[ASSET_DELETE_WORKFLOW] в пайплайн удаления актива org.unidata.dg.data[ASSET_DELETE_START], который удаляет связанные процессы при физическом удалении актива.

Преобразования в единицах измерения

  • Для эндпоинта /v2/meta/measurement появился новый параметр "reverseConversionFunction": "String" в measurementUnits.

  • В экспортируемых файлах для каждого измеримого атрибута появилась колонка с единицами измерения.

  • Для импортируемых записей в карточку сохраняются единицы измерения, указанные в загруженном файле.

Доработки сканеров (ограничение запущенных, механизм re-try)

Добавлены новые параметры в backend.properties:

  • org.unidata.dg.data.running.scanners.limit

  • com.universe.dg.dis.integration.scanner.reader.rest.template.timeout

  • com.universe.dg.dis.integration.max.attempts.to.get.scanner.data

REST-модуль подписок subscriptions

Следующие REST-поинты помечены как deprecated:

  • POST v1/subscriptions на создание подписки;

  • GET v1/subscriptions/load на получение подписок без учета фильтров/сортировки;

  • POST v1/subscriptions/load на получение подписок с учетом фильтрации/сортировки;

  • PUT v1/subscriptions/{id} на обновление подписки.

Вместо них необходимо использовать новые поинты.

Аудит событий для черновиков моделей справочников и активов

Добавлены и изменены потоки выполнения действий с моделями типов активов и справочников.

Для модели типов активов:

Добавлен новый пайплайн на удаление черновика модели с сегментами:

  • DG_MODEL_DRAFT_REMOVE_START - начинает удаление черновика модели типов активов.

  • DG_MODEL_DRAFT_AUDIT_EVENT - Точка отправляет аудит сообщение при успешном создании, изменении, удалении, публикации черновика модели типов активов.

  • DG_MODEL_DRAFT_REMOVE_FINISH - Заканчивает удаление черновика модели типов активов.

  • DG_MODEL_DRAFT_AUDIT_FALLBACK - Точка отправляет аудит сообщение при неуспешном создании, изменении, удалении, публикации черновика модели типов активов.

В пайплайн на изменение черновика модели (стартовая точка DG_MODEL_DRAFT_UPSERT_START) добавлены сегменты:

  • DG_MODEL_DRAFT_AUDIT_EVENT - после сегмента DG_MODEL_DRAFT_UPSERT_START перед DG_MODEL_DRAFT_UPSERT_FINISH

  • DG_MODEL_DRAFT_AUDIT_FALLBACK - после DG_MODEL_DRAFT_UPSERT_FINISH

В пайплайн на изменение публикацию черновика модели (стартовая точка MODEL_DRAFT_PUBLISH_START) добавлены сегменты:

  • DG_MODEL_DRAFT_AUDIT_EVENT - после сегмента DG_MODEL_DRAFT_PUBLISH_START перед DG_MODEL_DRAFT_PUBLISH_FINISH

  • DG_MODEL_DRAFT_AUDIT_FALLBACK - после DG_MODEL_DRAFT_PUBLISH_FINISH

Для модели справочников:

Добавлен новый пайплайн на удаление черновика модели c сегментами:

  • MODEL_DRAFT_REMOVE_START - Стартовая точка удаления черновика модели справочников.

  • MODEL_DRAFT_AUDIT_EVENT - Точка, обеспечивающая аудит событий с черновиками модели справочников.

  • MODEL_DRAFT_REMOVE_FINISH - Заканчивает удаление черновика модели справочников.

  • MODEL_DRAFT_AUDIT_FALLBACK - Точка, обеспечивающая аудит неуспешных событий с черновиками модели справочников.

В пайплайн на изменение черновика модели (стартовая точка MODEL_DRAFT_UPSERT_START) добавлены сегменты:

  • MODEL_DRAFT_AUDIT_EVENT - после сегмента MODEL_DRAFT_UPSERT_START перед MODEL_DRAFT_UPSERT_FINISH

  • MODEL_DRAFT_AUDIT_FALLBACK - после MODEL_DRAFT_UPSERT_FINISH

В пайплайн на изменение публикацию черновика модели (стартовая точка MODEL_DRAFT_PUBLISH_START) добавлены сегменты:

  • MODEL_DRAFT_AUDIT_EVENT - после сегмента MODEL_DRAFT_PUBLISH_START перед MODEL_DRAFT_PUBLISH_FINISH

  • MODEL_DRAFT_AUDIT_FALLBACK - после MODEL_DRAFT_PUBLISH_FINISH

Отображение системного имени функции

  • В paltform/uikit в CardPanel.tsx добавлен новый props headerAutoHeight?: boolean для выставления высоты хедера = auto.

Автопрокрутка к новому правилу в наборе правил качества

platform/model-form/ModelCollectionPanel.tsx

Добавлен новый пропс isAutoScrollToNewItem: boolean для включения прокрутки. Добавлена переменная cardRefs: ObservableMap<number, HTMLElement | null>.

В конструкторе добавлена MobX реакция на изменения в cardRefs для прокрутки к последнему добавленному элементу.

Переименование "Модель данных" на "Структура данных"

Frontend:

Изменено название категории "Управление моделью данных" на "Управление структурой данных".

  • platform/app/assets/locale

Сортировка значений параметров операций

  • В platformParametersForm.tsx и platform/ParameterItem.tsx добавлен новый props для передачи функции сортировки: props.onSortOptions?: (parameters: IParameterDescriptor) => IOption[].

  • В module/JobForm.tsx реализована функция сортировки с сохранением элемента с ключом ALL на первом месте. Создана константа DEFAULT_VALUE='ALL'.

Индексация популярности активов

В индекс активов добавлено поле $popularity, пример значения = 0.489. Чем выше значение, тем выше популярность.

Значение поля рассчитывается на основе данных в модуле timelog - DataGovernanceFunctionalExtensions.DG_ACTION_TIMELOG_NAME.

Версия 2.9

Выбор формата импорта ФИО из AD

  • Имя и фамилия в режиме sgi читались из неверных атрибутов, исправлено (sn - фамилия, givenName - имя, Initials - Отчество).

  • Режим sgi заменен на gsi : название - первые буквы атрибутов-источников имени, изменено для ясности.

  • Режим displayName оставлен без изменений.

  • Добавлен режим gsDisplayMix - имя и фамилию берет из атрибутов, отчество вычисляет из атрибута displayName.

  • Требуется в фильтре "Формат имён в Active Directory" выбрать правильное сопоставление Фамилии Отчества Имени в displayName.

  • При режиме gsDisplayMix, если displayName не содержит в себе корректных атрибутов, отчество будет не заполненным, имя и фамилия будут взяты из атрибутов givenName и sn.

Группы пользователей в бизнес-роли

В DG модуле com.unidata.dg.rest.v1.business.roles реализован Rest эндпоинт для получения списка пользователей-кандидатов для назначения на бизнес-роль:

POST-запрос /v1/dg/business-roles/data/users
{
   "text": "", // поисковая строка
   "businessRole": "business_role_1", // название бизнес-роли
   "status": "ACTIVE", // возвращать только активных ("ACTIVE")/неактивных ("INACTIVE")/всех ("ALL" или null) пользователей
   "limit": 10,
   "offset": 0
}

Лимиты для экспорта актива

Добавлен новый параметр в backend.properties com.unidata.dg.bulk.export.assets.xlsx.limit отвечающий за стандартное количество записей, доступных для экспорта.

Упорядоченность списка операций по алфавиту

  • module/job/PropertiesForm.tsx

  • Добавлена сортировка списка типов операций в метод formattedJobName.

Клонирование записей активов

  • Добавлен REST v1/dg/data/atomic/clone с POST методом для клонирования актива:

    • Имя фрагмента активов: asset-clone-fragment-v1

    • Имя фрагмента связей: relations-clone-fragment-v1

Улучшение отображения ошибок правил качества

  • Изменены стили в:

    • platform/record/errorsBadge.module.scss

    • platform/record/errorsRow.module.scss

    • platform/uikit/icon.m.scss

  • В module/dq-base/PortConstantField.tsx для констант <Input> заменен на <Input.TextArea>.

Поиск пользователя для назначения задачи

  • В module-ee/workflow/Reassign.tsx добавлен элемент <Input>, а также 2 метода onSearch и get filteredAcceptedUserList.

Отображение информации об исполнителе в задачах и процессах

  • Добавлен текст локализации "Исполнитель" / "Assignee".

  • В окне просмотра задачи ProcessCard.tsx и в окне просмотра подробностей процесса TaskOverview.tsx добавлен элемент <UserView/> для отображения имени пользователя и всплывающая подсказка с подробной информацией о пользователе.

Операция пакетного экспорта записей

  • Сегмент пайплайна org.unidata.dg.data.service.segments.assets.get.AssetGetOwnerExecutor объявлен deprecated и будет удален в следующих релизах. Вместо него необходимо использовать org.unidata.dg.data.service.segments.assets.get.AssetOwnershipGetConnectorExecutor.

  • Метод org.unidata.dg.data.result.AssetGetResult.getOwnership() объявлен deprecated и будет удален в следующих релизах. Вместо него необходимо использовать org.unidata.dg.data.result.AssetGetResult.fragment(OwnershipGetResult.ID).

  • Убран лимит операции экспорта в 10000 активов.

Удалены устаревшие API

Из сборки исключены следующие API-модули:

  • UserRestService#read;

  • UserRestService#readInfo;

  • UserRestService#readAll(GetUsersRequestRO);

  • UserRestService#readAll(GetUsersByLoginsRequestRO.

А также соответствующие им endpoint-ы (были помечены как deprecated):

  • /v2/core/security/user/{login};

  • /v2/core/security/user/logins;

  • /v2/core/security/user/query;

  • /v2/core/security/user/user-info/{login}.

Объединение reindexDataJob и reindexDgDataJob

  • Модуль org.unidata.dg.job.reindex теперь является deprecated и удален из сборки.

  • В потоки выполнения добавлены два селектора org.unidata.dg.data[ASSET_UPSERT_UPDATE_INDEXING_SELECTOR] и org.unidata.dg.data[ASSET_UPSERT_UPDATE_GRAPH_SELECTOR], позволяющие выбирать, будет ли обновляться граф и индексы.

  • Были скрыты три параметра, ранее доступные в reindexDGDataJob: "Писать лог ошибок", "Обработать лог ошибок", "Не создавать стандартный отчет".

История записи актива

  • Добавлены новые модули истории изменений:

    • История изменений тегов - модуль org.universe.mdm.marks;

    • История изменений владельцев - модуль org.unidata.mdm.core;

    • История изменений назначений пользователей на бизнес роли актива - модуль com.unidata.dg.business.roles.

  • Поток выполнения получения истории изменений актива org.unidata.dg.data[ASSET_HISTORY_START] дополнен следующими сегментами:

    • Получение истории изменений тегов, назначенных на актив org.unidata.dg.data[ASSET_HISTORY_TAGS];

    • Получение истории изменений владельцев, назначенных на актив org.unidata.dg.data[ASSET_HISTORY_OWNERSHIP];

    • Получение истории изменений назначений пользователей на бизнес роли актива com.unidata.dg.business.roles[ASSET_HISTORY_BUSINESS_ROLES].

  • Изменены сегменты в потоке выполнения получения актива org.unidata.dg.data[ASSET_GET_START]:

    • Добавлен сегмент org.unidata.dg.data[ASSET_TAGS_GET_CONNECTOR] для получения тегов, назначенных на получаемый актив (есть возможность получения тегов на определенную дату);

    • Добавлен сегмент org.unidata.dg.data[ASSET_OWNERSHIP_GET_CONNECTOR] для получения владельцев, назначенных на получаемый актив (есть возможность получения владельцев на определенную дату);

    • Обновлен сегмент com.unidata.dg.business.roles[ASSET_GET_BUSINESS_ROLES_CONNECTOR] для получения пользователей, назначенных на бизнес-роли получаемого актива: реализована возможность получения пользователей, назначенных на бизнес-роли на определенную дату.

Поиск процессов и задач по полям статусов

Теперь у процессов и статусов задач на согласование есть поля статусов $process_status/$task_status и $linked_subject_display_value, по которым можно производить поиск и сортировку.

Значения полей не сохраняются в БД, а вычисляются перед индексацией. $task_status вычисляется по $completed и наличию $assignee, $process_status вычисляется по $finished и наличию активных/завершенных задач-потомков, $linked_subject_display_value — по $linked_type_name и $linked_subject_id.

$process_status/$task_status хранятся в числовом виде для упрощения сортировки, в ответе на поисковой запрос REST API числовые значения дополняются человеко-читаемым displayValue.

Добавлен сегмент потока выполнения com.unidata.dg.workflow.data[ASSET_UPSERT_DRAFT_WORKFLOW_REFRESH], отвечающий за переиндексацию процессов и задач бизнес-процессов, относящихся к обновляемому черновику актива, с целью обновления отображаемого значения объектам.

Пример ответа с $process_status
{
   "id": "Process_36181b30-edbf-11ee-9271-031d8add40d5-41864",
   "score": 1.0,
   "status": null,
   "preview": [
      {
            "field": "$initiator_full_name",
            "fieldDisplayName": null,
            "fieldValueType": null,
            "values": [
               "Root2 Admin2"
            ],
            "extendedValues": [
               {
                  "value": "Root2 Admin2",
                  "displayValue": null,
                  "linkedEtalonId": null,
                  "linkedTypeName": null
               }
            ],
            "complexValues": null
      },
      {
            "field": "$definition_id",
            "fieldDisplayName": null,
            "fieldValueType": null,
            "values": [
               "Process_36181b30-edbf-11ee-9271-031d8add40d5:1:41707"
            ],
            "extendedValues": [
               {
                  "value": "Process_36181b30-edbf-11ee-9271-031d8add40d5:1:41707",
                  "displayValue": null,
                  "linkedEtalonId": null,
                  "linkedTypeName": null
               }
            ],
            "complexValues": null
      },
      {
            "field": "$definition_display_name",
            "fieldDisplayName": null,
            "fieldValueType": null,
            "values": [
               "test"
            ],
            "extendedValues": [
               {
                  "value": "test",
                  "displayValue": null,
                  "linkedEtalonId": null,
                  "linkedTypeName": null
               }
            ],
            "complexValues": null
      },
      {
            "field": "$end_event_name",
            "fieldDisplayName": null,
            "fieldValueType": null,
            "values": [],
            "extendedValues": null,
            "complexValues": null
      },
      {
            "field": "$finished",
            "fieldDisplayName": null,
            "fieldValueType": null,
            "values": [
               false
            ],
            "extendedValues": [
               {
                  "value": false,
                  "displayValue": null,
                  "linkedEtalonId": null,
                  "linkedTypeName": null
               }
            ],
            "complexValues": null
      },
      {
            "field": "$linked_subject_id",
            "fieldDisplayName": null,
            "fieldValueType": null,
            "values": [
               "676773a5-edc4-11ee-a295-a91ddb030bdd"
            ],
            "extendedValues": [
               {
                  "value": "676773a5-edc4-11ee-a295-a91ddb030bdd",
                  "displayValue": null,
                  "linkedEtalonId": null,
                  "linkedTypeName": null
               }
            ],
            "complexValues": null
      },
      {
            "field": "$start_date",
            "fieldDisplayName": null,
            "fieldValueType": null,
            "values": [
               "2024-03-29T12:03:54.631Z"
            ],
            "extendedValues": [
               {
                  "value": "2024-03-29T12:03:54.631Z",
                  "displayValue": null,
                  "linkedEtalonId": null,
                  "linkedTypeName": null
               }
            ],
            "complexValues": null
      },
      {
            "field": "$linked_type_name",
            "fieldDisplayName": null,
            "fieldValueType": null,
            "values": [
               "register:UN-25529-test"
            ],
            "extendedValues": [
               {
                  "value": "register:UN-25529-test",
                  "displayValue": null,
                  "linkedEtalonId": null,
                  "linkedTypeName": null
               }
            ],
            "complexValues": null
      },
      {
            "field": "$process_status",
            "fieldDisplayName": null,
            "fieldValueType": null,
            "values": [
               "В РАБОТЕ"
            ],
            "extendedValues": [
               {
                  "value": 1,
                  "displayValue": "В РАБОТЕ",
                  "linkedEtalonId": null,
                  "linkedTypeName": null
               }
            ],
            "complexValues": null
      },
      {
            "field": "$definition_key",
            "fieldDisplayName": null,
            "fieldValueType": null,
            "values": [
               "Process_36181b30-edbf-11ee-9271-031d8add40d5"
            ],
            "extendedValues": [
               {
                  "value": "Process_36181b30-edbf-11ee-9271-031d8add40d5",
                  "displayValue": null,
                  "linkedEtalonId": null,
                  "linkedTypeName": null
               }
            ],
            "complexValues": null
      },
      {
            "field": "$initiator",
            "fieldDisplayName": null,
            "fieldValueType": null,
            "values": [
               "admin"
            ],
            "extendedValues": [
               {
                  "value": "admin",
                  "displayValue": null,
                  "linkedEtalonId": null,
                  "linkedTypeName": null
               }
            ],
            "complexValues": null
      },
      {
            "field": "$end_event_id",
            "fieldDisplayName": null,
            "fieldValueType": null,
            "values": [],
            "extendedValues": null,
            "complexValues": null
      },
      {
            "field": "$business_key",
            "fieldDisplayName": null,
            "fieldValueType": null,
            "values": [
               "register:UN-25529-test:draftId:751"
            ],
            "extendedValues": [
               {
                  "value": "register:UN-25529-test:draftId:751",
                  "displayValue": null,
                  "linkedEtalonId": null,
                  "linkedTypeName": null
               }
            ],
            "complexValues": null
      },
      {
            "field": "$finish_date",
            "fieldDisplayName": null,
            "fieldValueType": null,
            "values": [],
            "extendedValues": null,
            "complexValues": null
      },
      {
            "field": "$initiator_email",
            "fieldDisplayName": null,
            "fieldValueType": null,
            "values": [
               "mail@example.com"
            ],
            "extendedValues": [
               {
                  "value": "mail@example.com",
                  "displayValue": null,
                  "linkedEtalonId": null,
                  "linkedTypeName": null
               }
            ],
            "complexValues": null
      },
      {
            "field": "$id",
            "fieldDisplayName": null,
            "fieldValueType": null,
            "values": [
               "41864"
            ],
            "extendedValues": [
               {
                  "value": "41864",
                  "displayValue": null,
                  "linkedEtalonId": null,
                  "linkedTypeName": null
               }
            ],
            "complexValues": null
      },
      {
            "field": "$etalon_id",
            "fieldDisplayName": null,
            "fieldValueType": null,
            "values": [],
            "extendedValues": null,
            "complexValues": null
      }
   ],
   "source": null
},

Поиск процессов по полям связанных задач

Добавлена возможность искать процессы по полям связанных задач на согласование (supplementary поисковые запросы).

Пример запроса, возвращающего все процессы
{
"payload": {
   "com.unidata.mdm.rest.v2.workflow.core": {
      "countOnly": false,
      "formFields": [],
      "formGroups": [],
      "searchFields": [
      "$id",
      "$definition_display_name",
      "$finished"
      ],
      "returnFields": [
      "$business_key",
      "$id",
      "$definition_id",
      "$definition_key",
      "$definition_display_name",
      "$start_date",
      "$finish_date",
      "$initiator",
      "$initiator_full_name",
      "$initiator_email",
      "$finished",
      "$end_event_id",
      "$end_event_name",
      "$linked_type_name",
      "$linked_subject_id"
      ],
      "fetchAll": true,
      "entity": "",
      "typedVariablesSearch": false,
      "searchWorkflowType": "PROCESS",
      "totalCount": true,
      "page": 1,
      "count": 20,
      "start": 0,
      "sortFields": []
   },
   "org.unidata.mdm.rest.v2.dq.data": {
      "setNames": [],
      "ruleNames": [],
      "functionNames": [],
      "message": null,
      "severity": null,
      "category": null,
      "totalScore": 0,
      "matchAll": false,
      "negate": false
   },
   "com.unidata.mdm.rest.v1.classifiers.multiple": null
}
}
Пример запроса, возвращающего задачи с исполнителем "admin"
{
"payload": {
   "org.unidata.mdm.rest.v2.dq.data": {
      "setNames": [],
      "ruleNames": [],
      "functionNames": [],
      "message": null,
      "severity": null,
      "category": null,
      "totalScore": 0,
      "matchAll": false,
      "negate": false
   },
   "com.unidata.mdm.rest.v1.classifiers.multiple": null,
   "com.unidata.mdm.rest.v2.workflow.core": {
      "countOnly": false,
      "formFields": [
      {
         "name": "$assignee",
         "type": "STRING",
         "searchType": "EXACT",
         "inverted": false,
         "value": "admin"
      }
      ],
      "formGroups": [],
      "searchFields": [
      "$definition_display_name",
      "$id",
      "$assignee",
      "$completed",
      "$process_definition_display_name"
      ],
      "returnFields": [
      "$id",
      "$definition_key",
      "$definition_display_name",
      "$create_date",
      "$due_date",
      "$complete_date",
      "$completed",
      "$assignee",
      "$assignee_full_name",
      "$candidate_groups.$name",
      "$candidate_users.$login",
      "$variables",
      "$initiator",
      "$linked_subject_id",
      "$linked_type_name",
      "$business_key",
      "$process_instance_id",
      "$process_definition_id",
      "$process_definition_key",
      "$process_definition_display_name",
      "$process_start_date",
      "$process_finish_date",
      "$linked_type_name",
      "$linked_subject_id"
      ],
      "fetchAll": false,
      "entity": "",
      "typedVariablesSearch": false,
      "searchWorkflowType": "TASK",
      "totalCount": true,
      "page": 1,
      "count": 20,
      "start": 0,
      "sortFields": []
   }
}
}

На основе примеров выше можно составить поисковой запрос, возвращающий все процессы, у которых связанные задачи удовлетворяют вышеупомянутому запросу.

Пример запроса поиска процессов по полям задач
{
"payload": {
   "com.unidata.mdm.rest.v2.workflow.core": {
      "countOnly": false,
      "formFields": [],
      "formGroups": [],
      "searchFields": [
      "$id",
      "$definition_display_name",
      "$finished"
      ],
      "returnFields": [
      "$business_key",
      "$id",
      "$definition_id",
      "$definition_key",
      "$definition_display_name",
      "$start_date",
      "$finish_date",
      "$initiator",
      "$initiator_full_name",
      "$initiator_email",
      "$finished",
      "$end_event_id",
      "$end_event_name",
      "$linked_type_name",
      "$linked_subject_id"
      ],
      "fetchAll": true,
      "entity": "",
      "typedVariablesSearch": false,
      "searchWorkflowType": "PROCESS",
      "totalCount": true,
      "page": 1,
      "count": 20,
      "start": 0,
      "sortFields": [],
      "supplementary": [
      {
         "countOnly": false,
         "formFields": [
            {
            "name": "$assignee",
            "type": "STRING",
            "searchType": "EXACT",
            "inverted": false,
            "value": "admin"
            }
         ],
         "formGroups": [],
         "searchFields": [
            "$definition_display_name",
            "$id",
            "$assignee",
            "$completed",
            "$process_definition_display_name"
         ],
         "returnFields": [
            "$id",
            "$definition_key",
            "$definition_display_name",
            "$create_date",
            "$due_date",
            "$complete_date",
            "$completed",
            "$assignee",
            "$assignee_full_name",
            "$candidate_groups.$name",
            "$candidate_users.$login",
            "$variables",
            "$initiator",
            "$linked_subject_id",
            "$linked_type_name",
            "$business_key",
            "$process_instance_id",
            "$process_definition_id",
            "$process_definition_key",
            "$process_definition_display_name",
            "$process_start_date",
            "$process_finish_date",
            "$linked_type_name",
            "$linked_subject_id"
         ],
         "fetchAll": false,
         "entity": "",
         "typedVariablesSearch": false,
         "searchWorkflowType": "TASK",
         "totalCount": true,
         "page": 1,
         "count": 20,
         "start": 0,
         "sortFields": []
      }
      ]
   },
   "org.unidata.mdm.rest.v2.dq.data": {
      "setNames": [],
      "ruleNames": [],
      "functionNames": [],
      "message": null,
      "severity": null,
      "category": null,
      "totalScore": 0,
      "matchAll": false,
      "negate": false
   },
   "com.unidata.mdm.rest.v1.classifiers.multiple": null
}
}

Копирование данных из окна о системе

  • universe-platform/security

  • Добавлен экспорт из пакета типа BUILD_VERSION.

  • universe-platform/app - В зависимости добавлена библиотека copy-to-clipboard. - В модальное окно с информацией о системе добавлена кнопка "Скопировать текст".

Версия 2.8

Переименование индексов OpenSearch

Исключена возможная коллизия имен системных индексов, индексов бизнес-процессов и индексов типов активов/справочников OpenSearch.

Имена индексов имеют следующий вид: prefix_default_некоеИмя, где prefix – значение параметра org.unidata.mdm.search.index.prefix (по умолчанию default).

Переименованы следующие индексы (приведен вид имени индекса для настроек по умолчанию):

  • default_default_auditdefault_default_[audit] - индекс аудита;

  • default_default_modeldefault_default_[model] - индекс модели данных;

  • default_default_$modeldefault_default_$[model] - индекс черновиков модели данных (сейчас не используется);

  • default_default_draftdefault_default_[draft] - индекс всех черновиков всех типов (сейчас не имеет доступа ни через FE, ни через REST API BE);

  • default_default_workflowdefault_default_[workflow] - общий индекс задач и процессов;

  • default_default_wf_имяПроцессаdefault_default_[wf]_имяПроцесса - индекс задач и процессов для каждого отдельного бизнес-процесса.

Имена типов активов и справочников теперь не могут содержать в своем имени следующие символы (ограничения добавлены на BE, на FE ограничения на имя уже есть и более строгие):

  • :, ", *, +, /, \, |, ?, #, >, < - ограничения OpenSearch на имя индекса;

  • [, ] - зарезервированные символы для системных индексов,

  • $ - зарезервированный символ для индексов с черновыми элементами – например, $entityName хранит поисковые данные черновиков записей типа актива с именем entityName,

  • . - точка уже была ранее запрещена.

Имена бизнес-процессов теперь не могут содержать в своем имени следующие символы (ограничения добавлены на BE, на FE ограничения на имя уже есть и более строгие):

  • :, ", *, +, /, \, |, ?, #, >, < - ограничения OpenSearch на имя индекса,

  • . - точка уже была ранее запрещена.

Изменения в операции reindexDataJob

  • Параметр "Проиндексировать черновики" переименован в "Проиндексировать черновики записей". Этот параметр индексирует черновики записей и их дочерних сущностей (связей и т.п.) в индексы черновиков выбранных типов активов/справочников;

  • Добавлены новые параметры: - "Проиндексировать черновики" – выполняет индексацию черновиков в индекс default_default_[draft], - "Проиндексировать модель данных" – выполняет индексацию модели данных в индекс default_default_[model].

Инструкция по миграции данных в переименованных индексах

Все индексы (кроме аудита) можно перезаполнить поисковыми данными через операцию переиндексации данных со следующими настройками (Рисунок 1).

Выполните миграцию данных индекса аудита следующим образом (замените хост и порт своими):

  • Старый индекс аудита обновите следующим запросом: PUT http://localhost:9200/default_default_audit/_settings с телом:

    {
      "settings": {
        "index.blocks.write": true
      }
    }
    
  • Если BE после обновления не запускался или уже запускался, но вы не хотите сохранять новые данные в аудите (или их нет), то:

    • Удалите новый индекс, если BE после обновления уже запускался: DELETE http://localhost:9200/default_default_[audit]

    • Затем клонируйте индекс в новый: PUT http://localhost:9200/default_default_audit/_clone/default_default_[audit]

    • Обновите новый индекс следующим запросом: PUT http://localhost:9200/default_default_[audit]/_settings с телом:

      {
        "settings": {
          "index.blocks.write": false
        }
      }
      
  • Если BE после обновления уже запускался и вы хотите сохранить новые данные в аудите, то (этот способ может занять более длительное время при большом размере старого индекса):

    • Выполните запрос реиндекса записей старого индекса в новый: POST http://localhost:9200/_reindex с телом:

      {
          "source": {
              "index": "default_default_audit"
          },
          "dest": {
              "index": "default_default_[audit]"
          }
      }
      
  • Удалите старые индексы с помощью следующих запросов:

    • DELETE http://localhost:9200/default_default_audit

    • DELETE http://localhost:9200/default_default_model

    • DELETE http://localhost:9200/default_default_$model

    • DELETE http://localhost:9200/default_default_draft

    • DELETE http://localhost:9200/default_default_workflow

    • DELETE http://localhost:9200/default_default_wf_*

Настройки операции переиндексации данных

Рисунок 1 – Настройки операции переиндексации данных

Параметр максимального количества выгружаемых записей

  • Добавлен новый параметр в backend.properties для операции экспорта экспорта справочников в XLSX: com.unidata.mdm.bulk.export.records.max.count = ${BULK_EXPORT_RECORDS_MAX_COUNT:50000}, который ограничивает количество записей под выгрузку для настройки под выделенные мощности. В случае попытки экспорта большего кол-ва записей - отображается ошибка.

  • Добавлен новый блок параметров для настройки операции экспорта в XLSX через UI.

  • Количество выгружаемых записей ограничивается параметром.

Выбор единиц измерения в карточке записи

Frontend:

  • TextAttributeField.tsx теперь используется исключительно для текстовых атрибутов. Для числового атрибута создан NumberAttributeField.tsx.

  • В NumberAttributeField.tsx реализована обертка, выводящая селектор единицы измерения. simpleAttributeEditOrPreview используется внутри numberWithMeasurement во избежание потери фокуса на селекторе единицы измерения при смене isEditMode.

  • Использование TextAttributeField для отображения числовых атрибутов отмечено как deprecated. Такое использование будет ограничено в версии 6.11.

Атрибуты в карточке записи

  • Генерация сторов атрибутов происходит всегда независимо от их скрытия (конструктор DataAttributeValueFactory);

  • Удалены лишние вызовы addAttributeIfNotExists, так как теперь все атрибуты должны существовать сразу после инициации карточки;

  • При сохранении из dataEntity удаляются только скрытые атрибуты;

  • Пустые атрибуты, которые были изменены, при сохранении приводятся к единому виду и отправляются на BE;

  • В AbstractRecordEntityStore добавлена опция ignoreDefaultValues, так как дефолтные значения не должны отображаться в пакетной модификации;

  • В ModelCollection добавлен метод commitCollection. Используется при добавлении атрибута в коллекцию dataEntity. Изменение коллекции дата-атрибутов не должно отслеживаться, так как атрибуты могут динамически добавляться, и это не должно влиять на dirty у dataEntity.

Обратная совместимость:

  • Поле hidden в RecordAbstractAttribute отмечено как deprecated, вместо него необходимо использовать метод setHidden и геттер isHidden.

Frontend SDK

  • В компоненте OptionList свойство maxHeight помечено как deprecated в пользу DropDown.maxHeight.

Настройки таймаута заброшенных подключений

  • В файл backend.properties добавлены параметры, отвечающие за настройки таймаута заброшенных подключений к БД: org.unidata.mdm.core.job.datasource.removeAbandonedTimeout и org.unidata.mdm.core.job.datasource.suspectTimeout.

История замещения пользователей

  • Переименован endpoint /v1/commercial-core/user-replacement/list с методом POST на /v1/commercial-core/user-replacement/active.

  • Ранее поинт /v1/commercial-core/user-replacement/history возвращал записи, если пользователь имел все права на администрирование замещений пользователя. Теперь получение всех записей истории возможно при наличии прав на чтение на ресурс безопасности "Администрирование замещений пользователей". В противном случае будут возвращаться только те замещения, для которых текущий пользователь является замещающим/замещаемым/создателем замещения. Для редактирования замещения пользователь должен либо обладать правами на редактирование замещений, либо быть создателем этого замещения.

Изменение настроек создания связей

  • Теперь для запроса списка связей используется POST запрос /dg/meta/relations/list.

  • Добавлен новый endpoint для получения модели связей с возможностью пагинации и сортировки по типам связей, а также с возможностью фильтрации - /v1/dg/meta/relations/list. Метод - POST.

Атрибуты связей

Реализована возможность добавлять атрибуты мета-связей, а также добавлять значения атрибутов при создании связей.

Пока еще не реализовано:

  • Экспорт/импорт актива с атрибутами связи, отображение атрибутов на графе и поиск по атрибутам связи.

  • Ограничение на изменение/удаление атрибутов связи в модели при наличии данных.

Технические изменения:

  • Сегмент потока выполнения [RELATION_DELETE_START] org.unidata.dg.data.service.segments.relations.delete.RelationDeleteModboxExecutor объявлен deprecated и будет удален в следующем релизе.

  • Метод org.unidata.dg.data.type.keys.RelationKeys.getRelationType() объявлен deprecated и будет удален в следующем релизе. Необходимо использовать метод org.unidata.dg.data.type.keys.RelationKeys.getTypeName().

  • Метод org.unidata.dg.meta.type.model.instance.AssetTypeElement.getReferencedLookups() объявлен deprecated и будет удален в следующем релизе. Необходимо использовать метод org.unidata.dg.meta.type.model.instance.DataGovernanceEntityElement.getReferencedLookups().

Отображение информации о пользователе и заместителях

  • Существующий endpoint /v1/commercial-core/user-replacement/load с методом GET помечен как deprecated. Вместо него необходимо использовать новый point /v1/commercial-core/user-replacement/list с методом POST.

  • Добавлены новые поля в модель Substitution: user и replacedUser.

  • Добавлен SearchSubstitutionListOp в SubstitutionService для получения списка заместителей для определенного пользователя.

  • Добавлен SpecificSubstitutionsStore для обработки SearchSubstitutionListOp, так как при использовании SubstitutionsStore вместе с заместителями подгружается и список всех пользователей, что негативно влияет на скорость загрузки.

  • Добавлены точки расширения: UserViewTooltipExtraContent и UserViewContent. Для них реализованы substitutionUserViewTooltip и substitutionUser соответственно.

  • Добавлен чекбокс для UserView showExtraData, который отключает отображение информации о заменяющем, даже если таковой имеется.

Шифрование паролей подключений LDAP

Класс org.unidata.mdm.core.util.CryptUtils объявлен deprecated. Необходимо использовать класс org.unidata.mdm.system.utils.CryptUtils.

Шифрование паролей подключений LDAP переведено на общий механизм платформы. Если шифрование в платформе выключено, подключения LDAP шифроваться не будут.

Старые настройки подключений LDAP после обновления станут неактуальны. Для существующих подключений необходимо заново ввести пароль.

Оптимизация механизма истории запусков сканеров

Результаты старых запусков после обновления станут недоступны.

  • Добавлен новый сегмент org.unidata.dg.data[ASSET_DELETE_SNAPSHOT] для потока выполнения org.unidata.dg.data[ASSET_DELETE_START].

  • Добавлен новый сегмент org.unidata.dg.data[RELATION_DELETE_SNAPSHOT] для потока выполнения org.unidata.dg.data[RELATION_DELETE_START].

Доработка моделей краулеров и объектов физического слоя

  • Методы getNested() и getNesteds() класса org.unidata.dg.meta.type.model.instance.DataGovernanceModelInstance стали Deprecated.

  • Методы withNesteds(DataGovernanceNestedEntitySource...), withNesteds(Collection<DataGovernanceNestedEntitySource>) класса org.unidata.dg.meta.type.model.source.DataGovernanceModel стали Deprecated.

  • После обновления модель типов активов может стать невалидной, если в ней присутствуют типы активов бизнес-слоя (созданные пользователем без тега layer:physical), наследованные от типов активов физического слоя. Чтобы избавиться от наследования бизнес-слоя от физического, рекомендуется воспользоваться импортом модели типов активов через xml (через UI нельзя изменять родительский тип актива). См. подробнее принцип валидации и объединения моделей.

Валидация длины строки атрибута

Добавлена валидация на длину строки атрибутов актива. Теперь нельзя опубликовать запись актива в котором присутствуют атрибуты с длиной строки больше 32 767 символов, так как это ограничение ячейки xlsx.

  • Для простых атрибутов просто сравнивается длина строки.

  • Для массив атрибутов сумма длин строк каждого значения массива, например, если в массиве есть элемент с длиной строки 32 767, то при добавлении элемента с длиной строки 1, черновик не опубликуется, так как массив атрибут при экспорте в xlsx записывается в одну ячейку.

  • Для комплексных атрибутов проверяются все вложенные атрибуты по правилам описанным выше.

Скрытые символы, например, перенос строки или абзаца, тоже считаются в общее количество символов (для кириллицы и латиницы), поэтому может не проходить валидация. Такое поведение считается корректным, т.к. эти символы тоже существуют в xlsx и могут поломать ячейку.

Настройка замещений пользователей

Метод ReadSubstitutionListOp отмечен как deprecated, вместо него необходимо использовать метод ReadSubstitutionHistoryOp.

Версия 2.7

Версия 2.7.1

Шифрование паролей подключений LDAP

Класс org.unidata.mdm.core.util.CryptUtils объявлен deprecated. Необходимо использовать класс org.unidata.mdm.system.utils.CryptUtils.

Шифрование паролей подключений LDAP переведено на общий механизм платформы. Если шифрование в платформе выключено, подключения LDAP шифроваться не будут.

Старые настройки подключений LDAP после обновления станут неактуальны. Для существующих подключений необходимо заново ввести пароль.

Версия 2.7

Отображение удаленных связей

  • На эндпоинтах /v1/dg/data/relations и /v1/dg/data/catalog/next-level добавлен флаг "cascaded", если includeInactive=true и cascaded=true, то возвращаются все активные и логически удаленные каскадно связи.

  • На эндпоинте /v1/dg/data/catalog/next-level также добавлена поддержка флага "includeInactive" (работает так же, как и в /v1/dg/data/relations).

Удаление информационной системы

  • Реализован новый эндпоинт для получения информации о наличии связей с бизнес-слоем или активами другой информационной системы: GET-запрос /dg/meta/information-systems/has-relations с Query-параметром "informationSystem": "Название ИС".

Очистка информационной системы

  • Реализован новый endpoint для очистки ИС с выбором сканера. url: v1/data/clean/crawler-instance/, method: DELETE, params: informationSystemName: Название ИС, crawlerInstanceName: Название сканера (на BE - имя crawler instance в модели org.unidata.mdm.meta.configuration.Descriptors.SOURCE_SYSTEMS).

Ресурс безопасности на пользовательские пакетные операции

  • POST /api/v2/core/import-data

  • POST /api/v2/bulk-operations/execute

  • При отсутствии прав ответ: 403 У пользователя [user1] недостаточно прав для (импорта/экспорта/удаления - в зависимости от выбранной операции) активов. Доступ запрещен.

Кастомный модуль по поддержке SSO Kerberos

Добавлена возможность добавить кнопку Вход по ССО, для этого необходимо добавить параметр "SSO_BUTTON_ENABLED" : true" в customer json

Изменены параметры файла backend.properties:

  • com.universe.mdm.sso.kerberos.realm.name=${SSO_KERBEROS_REALM_NAME:USE.ME} //edit with correct domain name

  • com.universe.mdm.sso.kerberos.keytab.file=${SSO_KERBEROS_KEYTAB_FILE:${unidata.conf}/tomcat.keytab}

  • com.universe.mdm.sso.kerberos.service.principal=${SSO_KERBEROS_SERVICE_PRINCIPAL:HTTP/dmitrova.use.me@USE.ME}

Поддержка файловых массив-атрибутов

  • org.unidata.mdm.rest.system.upload.attachment.directory

  • org.unidata.mdm.rest.system.upload.attachment.memory.threshold

  • org.unidata.mdm.rest.system.upload.attachment.max.size

Были изменены на:

  • org.unidata.mdm.core.upload.attachment.directory

  • org.unidata.mdm.core.upload.attachment.memory.threshold

  • org.unidata.mdm.core.upload.attachment.max.size

Было добавлено поле:

  • org.unidata.mdm.core.file.max.count

Оно задает максимальное количество файлов для атрибута (по умолчанию 10).

Управление статусами вручную

  • Добавлена возможность ручного управления статусами объектов через REST. Подробнее см. в важных изменениях.

  • Метод com.unidata.mdm.data.status.type.transition.DataStatusTransitionHandler.handle(List<DataStatusTransition>) объявлен deprecated. Рекомендуется использовать вместо него метод com.unidata.mdm.data.status.type.transition.DataStatusTransitionHandler.after(List<DataStatusTransition>).

Сортировка записей активов без выбора конкретного актива

Добавлена индексация отображаемых имен активов и их типов, что позволяет выполнять поиск и сортировку по отображаемым именам.

В случае изменения типа актива будет необходимо выполнение переиндексации, о чем появится соответствующее сообщение в момент публикации типа актива.

Поддержка транслитерации в поиске

Для обновления необходимо установить плагин analysis-icu для OpenSearch.

  • Установка с Docker:

При запуске Universe DG из репозитория Docker через Docker Compose плагин будет установлен автоматически.

Важно: Перед запуском команды docker-compose up -d необходимо убедиться, что присутствует файл opensearch-install-plugins-and-start.sh, который производит установку плагина analysis-icu, если она требуется, а также актуализирован файл docker-compose.yml:

...
opensearch-dg:
    image: opensearchproject/opensearch:2.7.0
    restart: always
    environment:
      - "OPENSEARCH_JAVA_OPTS=-Xms1024m -Xmx1024m"
      - "discovery.type=single-node"
      - "DISABLE_SECURITY_PLUGIN=true"
    volumes:
      - dg-opensearch-data:/usr/share/opensearch/data
      - ./hunspell:/usr/share/opensearch/config/hunspell/
      - ./opensearch-install-plugins-and-start.sh:/usr/share/opensearch/opensearch-install-plugins-and-start.sh
    entrypoint: /usr/share/opensearch/opensearch-install-plugins-and-start.sh
...
  • Установка вручную:

Приведенные ниже команды выполняются из директории, где установлен OpenSearch.

  • Команда для проверки установленных плагинов:

    bin/opensearch-plugin list
    
  • Команда для установки плагина analysis-icu:

    bin/opensearch-plugin install analysis-icu
    
  • Пример команды для установки плагина оффлайн (необходимо заранее скачать zip-файл с плагином, например, по ссылке https://artifacts.opensearch.org/releases/plugins/analysis-icu/2.7.0/analysis-icu-2.7.0.zip):

    bin/opensearch-plugin install file:C:/Downloads/analysis-icu-2.7.0.zip
    
  • Пример команды для установки плагина через указание URL на zip-файл с плагином:

    bin/opensearch-plugin install https://artifacts.opensearch.org/releases/plugins/analysis-icu/2.7.0/analysis-icu-2.7.0.zip
    

История изменения актива

Доработан способ получения истории изменений записи актива.

Для сохранения дополнительных элементов истории, которые ранее никак не фиксировались (восстановление/удаление актива), создана таблица org_unidata_dg_data.transitions. Также доступна регистрация новых типов transition'ов и их сохранение в таблицу.

Для различных потоков выполнения восстановления и удаления актива добавлены новые сегменты, которые сохраняют информацию об изменениях в org_unidata_dg_data.transitions (org.unidata.dg.data[ASSET_DELETE_TRANSITION], org.unidata.dg.data[ASSET_RESTORE_TRANSITION]).

Получение истории записи вынесено в отдельный поток выполнения:

{
    "startId": "org.unidata.dg.data[ASSET_HISTORY_START]",
    "subjectId": "",
    "description": "org.unidata.dg.data.asset.history.start.description",
    "segments": [
        {
            "segmentType": "START",
            "id": "org.unidata.dg.data[ASSET_HISTORY_START]"
        },
        {
          "segmentType": "POINT",
            "id": "org.unidata.dg.data[ASSET_HISTORY]"
        },
        {
            "segmentType": "POINT",
            "id": "org.unidata.dg.data[ASSET_HISTORY_TRANSITIONS]"
        },
        {
            "segmentType": "FINISH",
            "id": "org.unidata.dg.data[ASSET_HISTORY_FINISH]"
        }
    ]
}

Добавлены новые эндпоинты:

  • GET-запрос /v1/dg/data/assets-history/types для получения всех типов событий истории актива.

  • POST-запрос /v1/dg/data/assets-history для получения истории записи.

Примечания:

  • Эндпоинт для получения истории записи актива стал Deprecated - POST-запрос /v1/dg/data/assets/vistory

  • Метод org.unidata.dg.data.service.AssetsService.getVistory(AssetVistoryGetContext) стал Deprecated

  • Точки пайплайна org.unidata.dg.data[ASSET_VISTORY_GET_START], org.unidata.dg.data[ASSET_GET_VISTORY] и org.unidata.dg.data[ASSET_VISTORY_GET_FINISH] стали Deprecated

Обновление OrientDB с версии 3.2.4 до 3.2.23

  • Добавлено свойство в backend.properties c названием БД OrientDB: org.unidata.mdm.graph.storage.orientdb.datasource.database=dg

  • Изменено значение для свойства org.unidata.mdm.graph.storage.orientdb.datasource.url

    • Было: org.unidata.mdm.graph.storage.orientdb.datasource.url=remote:localhost:2424/dg

    • Стало: org.unidata.mdm.graph.storage.orientdb.datasource.url=remote:localhost:2424

В url необходимо указывать только хост и порт для подключения к OrientDB.

Выбор формата импорта ФИО из Active Directory

  • Добавлен REST эндпоинт

Запрос: GET http://{{server}}:{{port}}/universe-backend/api/v1/ldap/configuration/name-formats

Ответ (displayName локализован):

{"details":{"info":[],"warning":[],"error":[]},
"names":[
{"name":"LAST_FIRST_MIDDLE","displayName":"фамилия / имя / отчество"},
{"name":"LAST_MIDDLE_FIRST","displayName":"фамилия / отчество / имя"},
{"name":"FIRST_LAST_MIDDLE","displayName":"имя / фамилия / отчество"},
{"name":"FIRST_MIDDLE_LAST","displayName":"имя / отчество / фамилия"},
{"name":"FIRST_LAST","displayName":"имя / фамилия"},
{"name":"LAST_FIRST","displayName":"фамилия / имя"},
{"name":"MIDDLE_LAST_FIRST","displayName":"отчество / фамилия / имя"},
{"name":"MIDDLE_FIRST_LAST","displayName":"отчество / имя / фамилия"}]}
  • Изменен объект для GET/POST/PUT http://{{server}}:{{port}}/unidata-backend/api/v1/ldap/configuration/{{_int}}

  • В объект domains добавлено поле "adUserNameFormat" типа строка. Значение - одно из списка name-formats

Версия 2.6

Работа с задачами

Для задач на backend добавлено поле "Инициатор". Для задач, созданных в более ранних версиях, поле будет отсутствовать в индексе - потребуется переиндексация бизнес-процессов (операция будет доступна в следующих релизах).

Комментирование задач

  • Удален сервис для работы с комментариями com.unidata.mdm.worfklow.core.service.WorkflowCommentsService.

  • Удалено REST API для работы с комментариями БП (эндпоинты /v2/workflow/core/comment)

  • При обновлении системы будет выполнена миграция, которая перенесет старые комментарии в модуль marks.

SSO

  • Поддержан кастомный header в запросах "Single-Sign-On"

  • При получении пустых логина и пароля не будет возвращена ошибка, если пользователь уже аутентифицирован и аутентификация могла быть проверена с помощью одного из AuthenticationProvider в имеющихся SecurityDataSource.

Переиндексация бизнес-процессов

  • Добавлены методы для массовой индексации в WorkflowIndexingComponent.

  • Добавлены методы для конвертации Camunda объектов в Workflow[Process|Task|Attachment|Comment]Converter.

Клонирование записей справочника

  • Добавлена новая точка расширения DgCloneRecordParameters.

Физический слой данных

  • Эндпоинт для удаления/очистки информационных систем (ИС) был изменен на /dg/data/clean/information-system с параметрами informationSystemName (название ИС) и drop (булевое значение: false - очистка ИС, true - очистка и удаление ИС).

Последовательный запуск операций

Реализована возможность запуска новой операции после удачного/неуспешного завершения другой операции.

Запуск новой операции реализован с помощью TriggerExecutionListener.

В JobDefinitionStore имплементирован JobTriggersStore, реализующий настройку цепочек операций.

Добавлены API модули:

  • PUT /v2/core/jobs/triggers/{jobDefinitionId} - создание новой цепочки; сохранение идентификаторов связанных операций в таблице job_trigger.

  • GET /v2/core/jobs/triggers/{jobDefinitionId} - получение всех цепочек операций.

  • DELETE /v2/core/jobs/{jobDefinitionId}/triggers/{triggerId} - удаление цепочки операций.

Права доступа

Добавлены ресурсы:

  • Группы пользователей / User groups (вкладка Безопасность / Security).

  • Каталог доступа/ Access directory (вкладка Система / System).

Логаут заменен на возможность подтянуть обновления при обновлении групп пользователей.

Добавлен статус 401 Unauthorized:

  1. В группе пользователей:

Если нет прав на чтение групп пользователей:

  • GET /v1/commercial-core/users-group/{groupName}/check-users

  • GET /v1/commercial-core/users-group/{groupName}

  • GET /v1/commercial-core/users-group/{groupName}/users

Если нет прав на редактирование групп пользователей:

  • POST /v1/commercial-core/users-group

  • PUT /v1/commercial-core/users-group/{groupName}

  • DELETE /v1/commercial-core/users-group/{groupName}

  • POST /v1/commercial-core/users-group/move

  1. Каталог доступа:

Если нет прав к каталогу доступа:

  • POST /v1/ldap/configuration/sandbox

  • GET /v1/ldap/configuration

  • POST /v1/ldap/configuration

  • GET /v1/ldap/configuration/{id}

  • PUT /v1/ldap/configuration/{id}

  • DELETE /v1/ldap/configuration/{id}

  • POST /v1/ldap/configuration/preview

  • POST /v1/ldap/configuration/preview

  1. Остались открытыми (чтобы у пользователя была возможность просмотреть свои группы в карточке):

  • GET /v1/commercial-core/users-group/by-user-login/{login}

  • GET /v1/commercial-core/users-group

Версия 2.5

Потоки выполнения

  • В поток выполнения [SCANNER_RESULT_START] добавлен новый сегмент [SCANNER_CLEAR_DELETED] типа Point, удаляющий активы и связи, которые ранее были удалены из сторонней информационной системы.

    • Удаление технических активов и связей выполняется после завершения загрузки данных краулером. В отчете работы краулера будет указано количество удаленных активов и связей (отчет доступен для просмотра в Уведомлениях системы).

  • Сегмент [SCANNER_CALCULATE_BREADCRUMBS] потока выполнения [SCANNER_RESULT_START] объявлен deprecated и будет удален в следующем релизе.

Граф связей

В org.unidata.mdm.graph.core.type.storage.GraphStorage добавлен новый метод org.unidata.mdm.graph.core.result.GraphGetResult traverse(org.unidata.mdm.graph.core.context.GraphTraverseContext), который необходимо реализовать для всех кастомных графовых хранилищ.

Операция очистки паролей

Добавлена операция очистки паролей org.unidata.mdm.core.service.impl.job.CleanInactivePasswordsJob. Параметры операции описаны по ссылке.

Конфигурация операции находится в org.unidata.mdm.core.configuration.CoreConfiguration: cleanInactivePasswordsJobDetail и cleanInactivePasswordsJobTrigger.

  • В реализацию org.unidata.mdm.core.service.impl.SecurityServiceImpl.login(AuthenticationRequestContext ctx) включено разрешение на аутентификацию через сервис org.unidata.mdm.core.service.AuthenticationAttemptCheckService.

  • В реализацию org.unidata.mdm.core.service.impl.SecurityServiceImpl добавлена зависимость org.unidata.mdm.core.service.AuthenticationAttemptCheckService.

Реестр компонентов

Сервис interface org.unidata.mdm.core.service.AuthenticationAttemptCheckComponentRegister

Реестр компонентов AuthenticationAttemptCheckComponent - компоненты реализуют проверки права на аутентификацию.

Текущая реализация org.unidata.mdm.core.service.impl.security.AuthenticationAttemptCounterServiceImpl реализует оба AuthenticationAttemptCheckService и AuthenticationAttemptCheckService.

Также реализация хранит лист компонентов. При регистрации компонента проверяет его наличие в списке и если не находит, то регистрирует и выводит в лог сообщение о регистрации с именем компонента. При удалении из типа актива нахождение не проверяется, но в лог пишется снятие с регистрации (даже если не был зарегистрирован).

Методы:

  • void register(AuthenticationAttemptCheckComponent component) - добавляет компонент в реестр.

  • void unregister(AuthenticationAttemptCheckComponent component) - удаляет компонент из реестра.

Ошибка о блокировке доступа

Ошибка: exception org.unidata.mdm.core.exception BlockedAuthenticationAttemptException extends PlatformBusinessException.

В текущей реализации используется для UI сообщения пользователю о превышении лимита неудачных попыток аутентификации.

Примечание

На этом этапе пользователь обычно еще не авторизован, и получить его локаль может быть невозможно. Поэтому в конструкторе необходимо явно указывать локаль, в противном случае будет использоваться локаль системы, указанная в параметрах системы.

Класс для конкретных проверок

Класс abstract class org.unidata.mdm.core.service.AuthenticationAttemptCheckComponent implements AfterModuleStartup реализует конкретную проверку и должен быть зарегистрирован в типе актива, чтобы участвовать при проверке разрешения на аутентификацию.

После старта модуля регистрируется в типе актива AuthenticationAttemptCheckComponentRegister автоматически, если включен (по методу isEnabled()).

Текущие реализации:

  • org.unidata.mdm.core.service.impl.security.UsernameAuthenticationAttemptCheckComponent

  • org.unidata.mdm.core.service.impl.security.ClientIpAuthenticationAttemptCheckComponent

Методы:

  • @Override public final void afterModuleStartup() - регистрирует компонент в типе актива после старта модуля, если компонент включен.

  • protected final void register() - регистрирует компонент в типе актива.

  • protected final void unregister() - снимает регистрацию в типе актива.

  • protected boolean isEnabled() - включение компонента. По умолчанию возвращает true.

  • public String getInternalComponentName() - внутреннее имя компонента. По умолчанию возвращает полное имя класса. В текущей реализации используется только в методе getExternalComponentName по умолчанию.

  • public String getExternalComponentName() - возвращает внешнее имя компонента, например, более читаемое для лога. По умолчанию вызывает getInternalComponentName(). Например, "Username authentication attempt count check component" для UsernameAuthenticationAttemptCheckComponent.

  • protected Locale locale(@NonNull AuthenticationRequestContext ctx) - достает из контекста локаль, присылаемую пользователем при попытке аутентификации, чтобы использовать в локализации текстов. Например, ошибки о превышении лимита неудачных попыток аутентификации для IP-адреса. Поскольку пользователь еще не авторизовался - TextUtils возвращает локаль системы иначе.

  • public abstract boolean isAllowedToLogin(@NonNull AuthenticationRequestContext ctx) - проверяет разрешение на аутентификацию согласно правилам компонента.

  • public abstract void fail(@NonNull AuthenticationRequestContext ctx, Throwable cause) throws BlockedAuthenticationAttemptException - действие при неудачной попытке аутентификации с указанием причины. Например, увеличить счетчик неудачных попыток. Может бросать BlockedAuthenticationAttemptException. Может не бросать исключение, если нет необходимости передавать наружу событие. Чтобы локализовать текст BlockedAuthenticationAttemptException можно использовать метод locale выше для выборки из контекста.

  • public final void fail(@NonNull AuthenticationRequestContext ctx) throws BlockedAuthenticationAttemptException - вызывает метод выше с cause = null.

  • public abstract void success(@NonNull AuthenticationRequestContext ctx) - действие при успешной аутентификации. Например, сбросить счетчики неудачных попыток.

Пример

Задача: необходимо добавить список разрешенных для аутентификации IP-адресов.

  1. Создайте реализацию AuthenticationAttemptCheckComponent.

  2. Реализуйте String getExternalComponentName() - например, пусть возвращает "IP address white list authentication attempt check component".

  3. Добавьте туда список разрешенных адресов.

  4. Реализуйте isEnabled(), если он не должен быть всегда включен.

  • Если включается/выключается в рантайме, то необходимо сделать метод, вызывающий register()/unregister().

  1. Реализуйте boolean isAllowedToLogin(@NonNull AuthenticationRequestContext ctx) - проверьте, находится ли CLIENT_IP из AuthenticationRequestContext в списке разрешенных адресов.

  2. Реализуйте fail(@NonNull AuthenticationRequestContext ctx, Throwable cause) - в этом случае можно ничего не делать или написать в лог.

  3. Реализуйте void success(@NonNull AuthenticationRequestContext ctx) - в этом случае можно ничего не делать.

Подсчет количества неудачных попыток

Класс class org.unidata.mdm.core.type.security.AuthenticationAttempt implements Serializable хранит информацию о количестве неудачных попыток и времени последней неудачной попытки.

Используется для компонентов проверки, которые реализуют счетчики попыток, основанные, например, на Map<Object, AuthenticationAttempt>.

Поля класса:

  • public static final AuthenticationAttempt EMPTY = new AuthenticationAttempt(0, LocalDateTime.MIN) - возвращать, если в истории нет неудачных попыток аутентификации, чтобы не возвращался null.

Поля объекта:

  • private final int tries - количество неудачных попыток.

  • private final LocalDateTime lastTime - время последней попытки.

Методы:

  • public AuthenticationAttempt(int tries, @NonNull LocalDateTime last) - конструктор.

  • public int getTries() - возвращает tries .

  • @NonNull public LocalDateTime getLastTime() - возвращает lastTime.

  • @Override public String toString() - возвращает "LoginAttempt{" + "tries=" + tries + ", lastTime=" + lastTime + '}'.

Реализации кэша

  • interface org.unidata.mdm.core.service.AuthenticationAttemptCache - кэш количества неудачных попыток аутентификации по определенному ключу, если их необходимо запоминать.

Методы:

  • @NonNull AuthenticationAttempt get(@NonNull Object key) - получение AuthenticationAttempt по ключу. Должен возвращать AuthenticationAttempt.EMPTY, если для ключа ничего нет.

  • void put(@NonNull Object key, @NonNull AuthenticationAttempt attempt) - кладет AuthenticationAttempt по ключу.

  • void remove(@NonNull Object key) - удаляет AuthenticationAttempt для ключа, например, при удачной аутентификации для сброса истории неудачных попыток.

  • void clear(long ttlMinutes) - очищает старые записи по TTL (в минутах) на основе AuthenticationAttempt.lastTime.

  • void clear() - очищает кэш.

  • abstract class org.unidata.mdm.core.service.impl.security.AbstractMapBasedAuthenticationAttemptCache implements AuthenticationAttemptCache - реализует кэш на основе Map<Object, AuthenticationAttempt>.

Для hazelcast использование можно посмотреть в ClientIpAuthenticationAttemptCheckComponent или UsernameAuthenticationAttemptCheckComponent.

Абстрактные методы:

  • protected abstract Map<Object, AuthenticationAttempt> getMap() - получить карту, для использования в других методах, например, чтобы достать из hazelcast

Методы:

  • @NonNull @Override public AuthenticationAttempt get(@NonNull Object key) - по умолчанию getMap().getOrDefault(key, AuthenticationAttempt.EMPTY).

  • @Override public void put(@NonNull Object key, @NonNull AuthenticationAttempt attempt) - по умолчанию getMap().put(key, attempt).

  • @Override public void remove(@NonNull Object key) - по умолчанию getMap().remove(key).

  • @Override public void clear(long ttlMinutes) - по умолчанию фильтрует и удаляет записи, у которых истекло время жизни. Для hazelcast нужно переписать, например, используя destroy().

Предложения связей

Добавлены новые модули com.universe.dg.suggestions и com.universe.dg.rest.v1.suggestions для работы с предложениями связей. Подробную информацию о сервисах и примеры запросов см. по ссылке.

Комментарии и оценки карточки записи

Добавлен новый модуль org.universe.mdm.marks, позволяющий маркировать различные объекты системы. В текущей реализации модуль обслуживает функциональность оценок и комментариев карточки записи.

Комментарии и оценки присваиваются комбинации name space(register, asset, lookup, etc.), type name (имя сущности или "*" для всего пространства имен) и subject ID (идентификатор маркируемого объекта). Взаимодействие осуществляется через сервисы, позволяющие делать вставку, удаление и запросы к подсистемам. Также через сервисы происходит регистрация пользовательского кода на события добавления и удаления комментариев или оценок.

Оба сервиса реализуют 2 семейства операций: вставки и удаления, а также запросов - по namespace + typename (optional) + subject ID (идентификатор маркируемого объекта) и по ID(s) самого объекта комментария или оценки.

Комментарии:

Операция вставки всегда требует name space. Кроме режима like/dislike всегда требует subjectId. Наличие ID комментария обновляет объект комментария. Режим like/dislike не требует наличия subject ID.

Операция удаления всегда требует name space + subjectId или ID.

Сервис комментариев:

/**
  * Comments service.
  */
public interface CommentsService {
    /**
      * Upserts a comment.
      * @param ctx the upsert context
      */
    void upsert(CommentUpsertContext ctx);
    /**
    * Deletes a comment or a number of comments.
      * @param ctx the delete context
      */
    void delete(CommentDeleteContext ctx);
    /**
      * Queries comments.
      * @param ctx the context
      * @return query result
      */
    CommentQueryResult query(CommentQueryContext ctx);
    /**
      * Registers a lifecycle listener.
      * @param ns the name space
      * @param typeName the type name, may be null, "", or "*"
      * @param listener the listener
      */
    void register(NameSpace ns, String typeName, CommentLifecycleListener listener);
}

Оценки:

Операция вставки всегда требует name space. Кроме режима rescore всегда требует subjectId. Наличие ID оценки обновляет объект оценки. Режим rescore не требует наличия subject ID.

Операция удаления всегда требует name space + subjectId или ID.

Сервис оценок:

/**
* Score service.
  */
public interface ScoresService {
    /**
      * Upserts a score object.
      * @param ctx the upsert context
      */
    void upsert(ScoreUpsertContext ctx);
    /**
      * Deletes a score object or a number of score objects.
      * @param ctx the delete context
      */
    void delete(ScoreDeleteContext ctx);
    /**
      * Queries score objects.
      * @param ctx the context
      * @return query result
      */
    ScoresQueryResult query(ScoreQueryContext ctx);
    /**
      * Registers a lifecycle listener.
      * @param ns the name space
      * @param typeName the type name, may be null, "", or "*"
      * @param listener the listener
      */
    void register(@Nonnull NameSpace ns, String typeName, @Nonnull ScoreLifecycleListener listener);
}