Документация по платформе IONDV.Framework¶
JS framework for rapid business application development
1. О IONDV. Framework¶
IONDV. Framework - это опенсорный фреймворк на node.js для разработки учетных приложений на основе метаданных в формате JSON/YAML и отдельных функциональных модулей. Визуальный редактор IONDV. Studio позволяет создавать приложения по технологии «no code» и собирать приложение с веб-сервисами REST-API (модуль rest). Ключевой модуль registry является универсальным средством представления и редактирования данных, обработки их по бизнес-процессам.
На видео технология разработки и сборки приложения
Бесплатные demo-версии¶
Посмотрите наши демо уже сейчас:
- Studio - специализированная IDE, созданная как приложение iondv для визуальной (no code) разработки приложений на IONDV. Framework. Инструкция и видео по созданию приложения с помощью IONDV. Studio. См. на GitHub.
- Telecom - приложение по организации учета, хранения и отображения данных о наличии услуг связи (интернет, сотовая связь, телевидение, почта и др.) в населенных пукнтах региона. См. на GitHub
- DNT - приложение для разработки и тестирования функциональности фреймворка, в котором каждая учетная сущность отражает тим метаданных, например класс «строка», или класс «коллекция». Это позволяет изучать возможности фреймворка через приложение. См. на GitHub.
- War Archive - это программное решение на основе IONDV. Framework, реализованное для действующего проекта «Вспомнить каждого», цель которого оцифровать архивные документы, внести информацию в базу и обеспечить к ним свободный доступ. См. на GitHub.
- Project Management - приложение по организации проектной деятельности региональных ОГВ , целью которой является контроль результатов, соблюдение и сокращение сроков их достижения, эффективное использование временных, человеческих и финансовых ресурсов, принятие своевременных и обоснованных управленческих решений. См. на GitHub
- CRM - это программное решение, реализованное для организации регистрации, учета, хранения и отображения бизнес-данных (входящие заявки, звонки, посетители, продукция, услуги). См. на GitHub
Логин для доступа - demo, пароль - ion-demo. Регистрация не требуется.
Типовые приложения¶
IONDV. Framework - конструктор веб-приложений широкой специфики, так как преметная область определяется структурой метаданных, описывающих поведение приложение. Например, можно создать приложения:
- CRM - управление отношениями с клиентами;
- учет и управление ресурсами предприятия;
- автоматизация бизнес-процессов организации и документооборота;
- сбор и хранение любых данных, например метрик оборудования (IoT);
- представление данных в виде порталов;
- REST-API для SPA приложений;
- REST-API и бэкграунд для мобильных приложений;
Структура фреймворка¶
Схема приложения на основе фреймворка: core + metadata + modules = application
На рисунке отражены компоненты:
- ION Core - это ядро приложения в виде IONDV. фреймворка;
- meta class, meta view, meta navigation, meta workflow, meta security - это функциональные метаданные приложения - структуры, представления, навигации, бизнес-процессов и безопасности соответственно;
- registry module - отражает подключаемые функциональные модули, например модуль registry для просмотра и редактирования данных;
Чуть ниже представлены дополнительные типы меты и модули. Они представляют собой дополнительную функциональность и применяются в соответствии со спецификой приложения. Зависимости приложения представлены в файле package.json
.
Приложение - это метаописание его поведения в файлах формата JSON (YAML) + функциональный код + HTML шаблоны, расширяющие типовую функциональность -> с ним удобно работать через репозиторий версий git. Посмотрите примеры на Github .
Подробнее о функциональных возможностях фреймворка IONDV. Framework и его модулей в документации.
Функциональные возможности¶
IONDV. Framework обеспечивает реализацию следующей функциональности:
- обеспечение трансляции описательных метаданных в структуру хранения данных в СУБД;
- обеспечение функциональности работы с различными СУБД (ORM технологию);
- обеспечение авторизации в системе с различными политиками, по умолчанию oath2, с открытым конфигурируемым API для подключения авторизационных модулей библиотеки passport обеспечивает до 500 различных политик авторизации;
- обеспечение безопасности доступа к данным – статической к типам данных, к навигации, к этапам бизнес-процессов, к действиям на форме; динамической – через условия в данных, которым должен соответствовать профиль текущего пользователя (принадлежность к подразделению или организации указанной в объекте, группе или другим условиям); через url; обеспечение исключения в авторизации и безопасности по url или для специального пользователя;
- подключение модулей, обеспечивающих дополнительную функциональность и реализуемую через доступ к интерфейсам (API) ядра;
- обеспечение импорта, экспорта данных в системе, метаданных, безопасности из файлов;
- обеспечение взаимодействия с файловой системой для хранения данных, в том числе с внешними файловыми хранилищами, такими как nextcloud;
- расчет значения с формулами и кэширование этих данных;
- обеспечение жадной загрузки данных и их фильтрации в связанных коллекциях;
- кэширование запросов и сессий в memcached, redis;
- выполнение задач по расписанию;
- уведомление пользователей по событиям.
Документация¶
Документация по платформе IONDV.Framework доступна на двух языках - русский и english.
Ссылки¶
Ссылки на дополнительную информацию по разработке приложений с использованием IONDV. Framework.
- Документация
- Web-сайт
- Обучающие видеоролики на Youtube
- Обратная связь на Facebook
Copyright (c) 2016-2020 LLC «ION DV». All rights reserved.
2. Начало работы¶
Как развернуть¶
Шаг 1 Установка окружения¶
Окружение - это список программ необходимых для запуска.
Окружение, необходимое для запуска платформы IONDV. Framework с приложениями:
СУБД¶
- Необходимо установить СУБД MongoDB. Проверенная версия
3.6.9
и4.0.0
. - Далее создаем папку
data
на диске C: и в ней подпапкуdb
. - Для запуска базы данных переходим в папку расположения
MongoDb
, далее в папкуserver\bin
и запускаем файлmongod.exe
. Если есть необходимость использовать каталог с БД отличный отc:\data\db
, тогда файлmongod.exe
необходимо запустить с параметром--dbpath
после которого указать путь к каталогу.
Среда выполнения Node.js¶
Node.js - является средой, в которой осуществляется выполнение компонентов.
- Необходимо установить среду разработки Node.js. Проверенная версия node.JS
10.14.2
. - По умолчанию установщик сам прописывает пути к Node.js в PATH, а также устанавливает менеджер пакетов
npm
.
Установка глобальных зависимостей¶
Установливайте глобальные зависимости в командной строке cmd.exe
, запущенной от имени администратора, после установки node.js
.
NB: команда node -v
- показывает версию node.js.
Установка среды сборки под Windows¶
- Установите глобально пакет node-gyp командой
npm install -g node-gyp
необходимый для сборки различных библиотек. - Для работы библиотеки под операционной системой семейства Windows дополнительно необходимо установить пакет windows-build-tools -
npm install -g --production windows-build-tools
.
Шаг 2 Установка ядра, модулей и приложения¶
Клонирование приложения и его компонентов¶
NB: пути не должны содержать русских букв и пробелов. Мы советуем размещать приложение в c:\workspace
.
Рассматриваем формирование проекта с модулями на примере приложения develop-and-test
.
- Находим приложение в репозитории github. Набираем искомое приложение
develop-and-test
в поле поиска и переходим на него. - Переходим в репозиторий файлов на ветку версии.
- Открываем файл
package.json
в котором смотрим зависимости.
"engines": {
"ion": "3.0.0"
},
"ionModulesDependencies": {
"registry": "3.0.0",
"geomap": "1.5.0",
"portal": "1.4.0",
"report": "2.0.0",
"ionadmin": "2.0.0",
"dashboard": "1.1.0",
"soap": "1.1.2"
},
"ionMetaDependencies": {
"viewlib": "0.9.1"
}
engines": "ion": 3.0.0
- версия ядра3.0.0
.ionModulesDependencies
- список модулей и их версий.ionMetaDependencies
- список других метаданных, необходимых для проекта, в данном случае исключениеviewlib
- библиотека представлений.
NB: для переключения на tag номера версии - смотрите версии в файле package.json
.
Получение репозитория ядра¶
Ядро находится в репозитории framework. На главной странице есть поле с путем к репозиторию.
- Запустите командную строку от имени администратора.
- Скопируйте адрес репозитория, перейдите в папку workspace командой
cd c:\workspace
и выполните командуgit clone https://github.com/iondv/framework
. Эта команда создает папкуframework
и в неё клонирует репозиторий.
Получение модулей¶
- Переходим в папку модулей командой
cd framework\modules
. - Для каждого модуля из списка
package.json
в свойствеionModulesDependencies
- находим репозиторий модуля среди группы модулейhttps://github.com/iondv/ION-MODULES
. - Клонируйте все модули из списка
ionModulesDependencies
командойgit clone https://github.com/iondv/registry
. - Перейдите в папку установленного модуля, переключитесь на tag номера версии
git checkout tags/v1.27.1
. Например1.27.1
- это номер версии модуляregistry
. - Повторите для всех модулей.
Получение приложения¶
- Переходим в папку приложения. Если вы находитесь в папке модулей выполните команду
cd ..\applications
. - Далее вернитесь на страницу репозитория
develop-and-test
, скопируйте путь и клонируйте его командойgit clone https://github.com/iondv/develop-and-test
. - Перейдите в папку установленного приложения, переключитесь на tag номера версии
git checkout tags/v1.17.0
. - Установка зависимостей в
ionMetaDependencies
осуществляется в папкуapplications
, для установки необходимо убедиться, что находитесь в папке приложений. Клонируем приложения из списка в параметреionMetaDependencies
. Для приложенияviewlib
клонируйте командойgit clone https://github.com/iondv/viewlib
. - Перейдите в папку установленного приложения, переключитесь на tag номера версии
git checkout tags/v0.9.1
. Повторите для каждого приложения. - Приложение скомпоновано.
NB: мы советуем создать для него проект в IDE, например, в Visual Studio Code, и в нём создать конфигурациионный файл.
Конфигурациионный файл¶
Конфигурационный файл служит для задания основных параметров окружения приложения и настройки дополнительных параметров запуска.
- Создайте конфигурационный файл
setup
с расширениемini
в папкеconfig
. - Открываем файл в редакторе и вставляем содержимое.
auth.denyTop=false
auth.registration=false
auth.exclude[]=/files/**
auth.exclude[]=/images/**
db.uri=mongodb://127.0.0.1:27017/iondv-dnt-db
server.ports[]=8888
module.default=registry
fs.storageRoot=./files
fs.urlBase=/files
Самый главный параметр - db.uri=mongodb://127.0.0.1:27017/db
. Он указывает на название базы которую мы будем использовать для приложения. База данных будет создана автоматически.
Шаг 3 Cборка и запуск приложения¶
Для всех дальнейших команд, необходимо запустить командную строку от имени администратора.
Перейдите в папку приложения cd c:\workspace\framework
и задайте переменную окружения NODE_PATH
равной пути к приложению.
Для Windows команда - set NODE_PATH=c:\workspace\framework
, для Linux - export NODE_PATH=/workspace/framework
.
Сборка приложения¶
Сборка приложения обеспечивает установку всех библиотек, импорт данных в базу данных и подготовку приложения для запуска.
При первом запуске необходимо выполнить
npm install
- она поставит ключевые зависимости, в том числе локально сборщикgulp
. Убедитесь, что версияGulp
-4.0
. Эта команда ставит все библиотеки из свойстваdependencies
файлаpackage.json
ядра.После этого, а также все последующие разы выполняйте команду сборки приложения
gulp assemble
.NB: Убедитесь, что стоит переменная окружения
NODE_PATH
, запущена базаMongoDB
,Gulp
установлен глобально и локально и его версия4.0
.Перед непосредственным запуском приложения необходимо добавить базового пользователя для входа. Откройте программу
Mongo Compass
и в базе данных найдите таблицуion-user
. Удалите все записи, которые увидите там. Далее вернитесь в консоль и выполните указанные ниже команды. Добавьте пользователя admin с паролем 123 командойnode bin/adduser.js --name admin --pwd 123
. Добавьте пользователю права администратора командойnode bin/acl.js --u admin@local --role admin --p full
.
Запуск приложения с использованием скриптов¶
В папке «bin» содержатся скрипты запуска приложения, реализованного на IONDV. Framework, такие как:
- acl.js
- export.js
- import.js и import-data.js
- setup.js
- www.js
NB. Run locally from the framework folder, command templates are listed in the sections describing the purpose of the script.
Подробнее о скриптах запуска приложения
Запуск приложения¶
После окончания сборки можно запускать приложение. Убедитесь, что стоит переменная окружения NODE_PATH
. Без этого система выдаст ошибку - об отсутствии компонентов.
Запуск системы осуществляется командой npm start
, альтернативой является запуск node bin/www
.
После запуска системы, откройте браузер с адресом http://localhost:8888
и авторизуйтесь в приложении, где 8888
- порт указанный в параметре server.ports
конфигурации запуска.
Cкрипты запуска приложения¶
В папке «bin» содержатся скрипты запуска приложения, реализованного на IONDV. Framework, такие как:
NB. Запускаются локально из папки framework, шаблоны команд указаны в разделах с описанием назначения скрипта.
acl.js¶
Шаблон команды запуска: node %NODE_PATH%\bin\acl.js --d %NODE_PATH%\applications\%IONAPP%\acl
где NODE_PATH
- путь к директории платформы, %IONAPP%
- наименование приложения.
Добавляет права на объекты системы, указанные в папке acl.
Так же доступны команды для создания роли и прав для нее в системе, в случае если в приложении отсутствуют настройки в папке acl:
- Настройка логина и пароль -
node bin/adduser.js --name admin --pwd 123
- Настройка доступа -
node bin/acl.js --u admin@local --role admin --p full
- Права на генерацию токена для сервиса rest/token -
node bin/acl.js --role admin --p USE --res ws:::gen-ws-token
По такому же принципу можно задавать пользователей и права на отдельные ресурсы системы
export.js¶
Шаблон команды запуска: node bin/export --ns %IONAPP%
, где NODE_PATH
- путь к директории платформы, %IONAPP%
- наименование приложения (namespace).
Выполняет экспорт данных и меты из приложения, которое в данный момент собрано и запущено локально. Файлы экспорта формируются в структуру папок, которые расположены на одном уровне с директорией платформы в папке out.
import.js и import-data.js¶
При импорте меты, по умолчанию, импорт данных не выполняется. Поэтому, для импорта меты вместе с данными вызываем команду:
node bin/import.js --src %NODE_PATH%/applications/%IONAPP% --with-data --ns %IONAPP%
где, NODE_PATH
- путь к директории платформы, %IONAPP%
- наименование приложения (namespace).
А для импорта непосредственно данных вызываем:
node %NODE_PATH%/bin/import-data.js --src %NODE_PATH%/applications/%IONAPP%/data --ns %IONAPP%
При этом, если импортируем мету и данные, указываем директорию приложения (при этом данные для импорта будут искаться в поддиректории data), если импортируем данные, нужно указывать непосредственно директорию с данными.
setup.js¶
Шаблон команды запуска: node %NODE_PATH%\bin\setup %IONAPP%
где, NODE_PATH
- путь к директории платформы, %IONAPP%
- наименование приложения.
Выполняет установку приложения, запускает скрипт развертывания приложения, что включает в себя импорт и запись в базу данных меты модулей приложения.
В данном разделе - о том, как развернуть систему. Для развертывания системы необходимо выполнить несколько шагов.
Быстрый запуск¶
IONDV. Studio¶
IONDV. Studio является приложением IONDV. Framework. Может использоваться как отдельное приложение node.js или как десктоп-приложение. Развернуть приложение можно с помощью демо-версии студии. Регистрация и учетная запись не требуются.
Описание
IONDV. Studio - приложение для визуального создания и редактирования метаданных (таких как классы, навигация, представления, бизнес-процессы, портальные формы), которые разворачиваются как веб-приложение IONDV. Framework.
Как запустить приложение в Студии¶
Смотрите видео, о том, как развернуть в IONDV. Studio уже готовое приложение из репозитория.
- Выберите пример готового приложения с github. Например, Nutrition-Tickets.
- Скачайте архивный файл приложения и откройте его в приложении.
- Нажмите кнопку воспроизведения в правом верхнем углу экрана, чтобы запустить приложение.
- Приложение начнет развертывание. Это занимает примерно 80 секунд.
- Получите ссылку на приложение и нажмите на нее.
- Войдите в приложение, используя логин demo и пароль ion-demo.
Приложение запущено! Приложение в демо-Студии хранится в течение 1-го часа, Вы можете ознакомиться с технологией и попробовать самостоятельно внести изменения в структуру приложение и увидеть результат. После этого приложение будет удалено с сервера.
Как создать приложение в студии¶
В Студии также можно создавать приложения. Смотрите видео о создании простого приложения IONDV. Nutrition-tickets в IONDV. Studio. Инструкция доступна в репозитории IONDV. Nutrition-Tickets.
- Нажмите на + чтобы приступить к созданию приложения. В всплывающем окне заполняем обязательные поля. Вкладка приложения, которое вы создали, появляется в левом верхнем углу и управляется по типу браузера.
- Появляется боковое меню - это рабочая панель приложения. Раздел Классы нужен для создания Классов и Атрибутов.
- Создание приложения начинается с Класса. Нажимаем на Класс и в рабочем пространстве нажимаем +Класс. В всплывающем окне заполняем обязательные поля. Описание полей тут.
- У нас появился Класс и автоматически создался Атрибут ID.
- Когда Класс выделен, можно добавить к нему Атрибуты, нажав на +Атрибут. Описание свойств и типов Атрибута тут.
- Когда у вас есть минимум 2 Класса, можно настроить между ними связи. Это выполняется через настройку типа данных при создании атрибута Класса. Основные типы - Коллекция и Ссылка. Заданный тип данных у Атрибута отразится в рабочей области в виде связующей линии.
В разделе Класс появятся созданные вами Классы и их Атрибуты - это называется дерево проекта, по которому будет легко ориентироваться, когда количество Классов приложения увеличится. Это - базовые пункты для создания приложения.
Приложение в IONDV. Studio¶
Для того чтобы разработать приложение в Студии, нужно предварительно запустить ее одним из следующих способов:
- Используйте демо-версию студии.
- Запустите локально как приложение IONDV. Framework, получив исходные коды на github. После чего соберите и разверните его согласно инструкции приложений Framework.
- Откройте в браузере по ссылке http://localhost:8888.
- Запустите локального как отдельное приложение node.js согласно инструкции ниже.
- Запустите как десктоп приложение, согласно инструкции ниже.
- Запустите в docker-конейтнере выполнив docker run -d -p 8888:8888 –name studio iondv/studio.
Откройте в браузере по ссылке http://localhost:8888.
Затем:
- В Студии разработайте Ваше приложение, путем создания классов, навигации.
- Обратите внимание, что данные хранятся в локальном репозитории браузера. Экспортируйте приложение как zip-архив.
- Скачайте последнюю версию IONDV. Framework и модуля IONDV. Registry module - получить их можно c репозиториев GitHub Framework и Registry.
- Следуйте типовой инструкции развертывания приложения из git, за исключением приложения - вместо приложения разверните в папку applictions ваш архив с приложением.
- Далее необходимо собрать и развернуть приложение, согласно инструкции IONDV. Framework.
Варианты использования Студии¶
Отдельное приложение node.js¶
Преимуществами использования отдельного приложения является отсутствие необходимости в базе данных и в IONDV. Framework.
- Выполните команду git clone https://github.com/iondv/studio.git. Имените локальную дирректорию на studio.
- Выполните команду npm install для установки всех необходимых зависимостей, включая локальное приложение сборки gulp.
- Пожалуйста проверьте, что глобально установлен Gulp версии 4.0.
- Выполните команду gulp build для сборки приложения.
- Запустите приложение командой npm start или node www (node standalone для запуска приложения как [standalone](/readme-standalone_ru.md).)
- Перейдите в браузере по адресу http://localhost:8888.
Десктоп приложение Студии (node-webkit)¶
Перед формированием десктоп приложения Студии, соберите Отдельное приложение node.js
- Скачайте последнюю NORMAL версию node-webkit c сайта https://nwjs.io/.
- Распакуйте содержимое архива в любую удобную папку.
- Воспользуйтесь одним из имеющихся способов для того, чтобы соеденить приложение и node-webkit.
Примеры описаны в статье https://github.com/nwjs/nw.js/wiki/How-to-package-and-distribute-your-apps в пунктах 2a и 2b.
Более удобным является вариант воспользоваться пакетом nw-builder:https://github.com/nwjs-community/nw-builder. Пример команды: nwbuild ./studio -p win64 -v 0.34.0 -o ./destination. Стоит отметить, nw-builder сам скачает необходимую версию node-webkit.
В результате вы получите ваше приложение в папке с dll, которые использует nwjs. Запустить приложение можно с помощью nw.exe файла (название может отличаться).
- Скачайте Enigma virtual box с сайта https://enigmaprotector.com/en/downloads.html, установите и запустите
- Занесите в первое поле путь к исполняемому файлу вашего приложения. (Можно выбрать)
- Занесите во второе поле путь сохранения исполняемого файла.
- Занесите в поле Files ВСЕ файлы и папки из директории вашего приложения кроме исполняемого файла .exe.
- В меню Files options, поставьте галочку на путкте Compress.
- Нажмите Process и дождитесь результата.
Вся настройка в deploy.json -> globals -> externalAppTracker
{
"items": [{
"name": "dnt",
"title": "Develop and test",
"url": "https://github.com/iondv/develop-and-test/archive/master.zip"
}, {
"name": "crm-en",
"title": "CRM EN",
"url": "https://github.com/iondv/crm-en/archive/master.zip",
"language": "en"
}, {
"name": "crm-ru",
"title": "CRM RU",
"url": "https://github.com/iondv/crm-ru/archive/master.zip",
"language": "ru"
}],
"front": "/themes/portal/static/archives/",
"storage": "applications/studio/themes/portal/static/archives/",
"tempZip": "applications/studio/temp.zip",
"enableUpdate": false,
"updateInterval": 86400
}
- item.name - задает имя файла при сохранении архива
- item.title - отображается на клиенте при выборе приложения
- item.url - удаленный адрес архива приложения
- item.front - адрес архива для клиента, если не указан, создается по общей настройке и имени
- item.language - если не указан, то приложение отобразится в любом языке
- storage - место сохранения архивов приложений
- front - ссылка до архивов с клиента
- tempzip - временный файл при удаленной закачки с другого сервера
- enableUpdate - вкл/выкл синхронизацию с удаленным сервером. При старте сервера проверяется наличие архивов, и если нет, то скачиваются с указанных URL. По истечению периода updateInterval архивы обновляются
- updateInterval - период повторной загрузки архива на сервер (секунды)
На клиенте можно указать custom URL, но нужно иметь в виду, что браузер разрешает загрузки с чужих хостов только явно разрешенные через Access-Control-Allow-Origin
Оригинальная инструкция на английском представлена на сайте https://github.com/nwjs/nw.js/wiki/How-to-package-and-distribute-your-apps в пункте An alternative way to make an executable file in Windows
Сборка приложения из репозитория¶
Для быстрого запуска приложений с использованием репозитория GitHub выполните следующие шаги:
- Установите системное окружение и глобальные зависимости.
- Клонируйте ядро, модуль и приложение.
- Соберите и разверните приложение.
- Запустите.
Ниже - развернутая инструкция, как собрать приложение из репозитория GitHub.
Развернутая инструкция¶
Системное окружение и глобальные зависимости¶
Запуск фреймворка осуществляется в среде Node.js версии 10.x.x.
Для хранения данных необходимо установить и запустить MongoDb версии старше 3.6.
Для сборки компонентов и библиотек фреймворка необходимо установить глобально:
- пакет node-gyp
npm install -g node-gyp
. Для работы библиотеки под операционной системой семейства windows дополнительно необходимо установить пакет windows-build-toolsnpm install -g --production windows-build-tools
. - пакет сборщика проектов Gulp
npm install -g gulp@4.0
.4.0
- поддерживаемая версияGulp
. - для версий IONDV. Framework 3.x.x и более ранних нужен менджер пакетов фронтенд библиотек Bower
npm install -g bower
. Для версия 4.х.х и старше не требуется.
Ручная установка ядра, модулей и приложения¶
Рассматриваем на примере приложения develop-and-test
. Находим приложение develop-and-test
в репозитории.
Смотрим зависимости указаные в файле package.json
.
"engines": {
"ion": "1.24.1"
},
"ionModulesDependencies": {
"registry": "1.27.1",
"geomap": "1.5.0",
"graph": "1.3.2",
"portal": "1.3.0",
"report": "1.9.2",
"ionadmin": "1.4.0",
"dashboard": "1.1.0",
"lk": "1.0.1",
"soap": "1.1.2",
"gantt-chart": "0.8.0"
},
"ionMetaDependencies": {
"viewlib": "0.9.1"
"viewlib-extra": "0.1.0"
- Начинаем установку с ядра, версия которого указана в парметре
"engines": {"ion": "1.24.1"}
. Скопируйте адрес репозитория ядра и в командной строке выполните коммандуgit clone https://github.com/iondv/framework
. Перейдите в папку ядра, переключитесь на tag номера версииgit checkout tags/v1.24.1
. Так как совместимость обеспечивается на уровне метаданных, а новые версии выпускались из-за изменения технологии сборки, то вы можете использовать последние, например 4.0.0. - После этого устанавливаются необходимые для приложения модули, указанные в параметре
"ionModulesDependencies"
. Модули устанавливаются в папкуmodules
ядра, для этого перейдите в неё командойcd modules
. Клонируем модули из списка"ionModulesDependencies"
, для модуля registry это осуществляется командойgit clone https://github.com/iondv/registry
. Перейдите в папку установленного модуля, переключитесь на tag номера версииgit checkout tags/v1.27.1
. Повторите для каждого модуля. Для большинства приложений, можно использовать последние совместимые с ядром модули. - Установка самого приложения осуществляется в папку
applications
, для этого перейдите в неё командойcd ..\applications
, если вы находитесь в папке модулей. Установку выполните клонированием репозитория коммандойgit clone https://github.com/iondv/dnt_ru
. - После этого установите дополнительно необходимые приложения из параметра
"ionMetaDependencies"
. Установка осуществляется в папкуapplications
, для установки необходимо убедиться, что находитесь в папке приложений. Клонируем приложения из списка в параметре"ionMetaDependencies"
, для приложенияviewlib
осуществляется командойhttps://github.com/iondv/viewlib
. Перейдите в папку установленного приложения, переключитесь на tag номера версииgit checkout tags/v0.9.1
. Повторите для каждого приложения.
Сборка, конфигурирование и развертывание приложения¶
Сборка приложения обеспечивает установку всех зависимых библиотек, импорт данных в базу данных и подготовку приложения для запуска.
Создайте конфигурационный файл setup.ini
в папке config
, куда был клонирован фреймворк для задания основных параметров окружения приложения.
auth.denyTop=false
auth.registration=false
db.uri=mongodb://127.0.0.1:27017/db
server.ports[]=8888
module.default=registry
fs.storageRoot=./files
fs.urlBase=/files
Открываем файл в редакторе и вставляем содержимое. Самый главный параметр db.uri=mongodb://127.0.0.1:27017/ion-dnt
- он указывает на название базы, которую мы будем использовать для приложения. База данных будет создана автоматически.
Задайте переменную окружения NODE_PATH равной пути к ядру приложения следующей командой set NODE_PATH=c:\workspace\dnt
для Windows и export NODE_PATH=/workspace/dnt
для Linux, где workspace\dnt
- папка куда склонирован фреймворк.
При первом запуске необходимо выполнить npm install
- она поставит ключевые зависимости, в том числе локально сборщик gulp
.
Далее выполните команду сборки приложения gulp assemble
.
Если вы хотите выполнить импорт данных в вашем проекте, проверьте папку data
в приложении и выполните команду:
node bin/import-data --src ./applications/develop-and-test/data --ns develop-and-test
Добавьте пользователя admin с паролем 123 командой node bin\adduser.js --name admin --pwd 123
.
Добавьте пользователю права администратора командой node bin/acl.js --u admin@local --role admin --p full
.
Запуск¶
Запустите приложение командой в папке ядра npm start
или node bin\www
.
Откройте браузер с адресом http://localhost:8888
и авторизуйтесь в приложении, где 8888
- порт указанный в параметре server.ports конфигурации запуска.
Docker-контейнер¶
Приложения также можно запустить с использованием докер контейнера.
Docker – это программная платформа для быстрой разработки, тестирования и развертывания приложений.
Шаги¶
- Запустите СУБД mongodb:
docker run --name mongodb -v mongodb_data:/data/db -p 27017:27017 -d mongo
- Запустите IONDV. App
docker run -d -p 80:8888 --link mongodb iondv/app
, где App - название приложения и путь к соответствующему репозиторию. - Откройте ссылку
http://localhost
в браузере через минуту (время требуется для инициализации данных). Для авторизации используйте типовой логин: demo, пароль: ion-demo
Установщик для Linux¶
Вы также можете использовать установщик приложений IONDV. Framework для Linux, требующий установленных node, mongodb и git. В ходе установки будет проверены и установлены все остальные зависимости, а также собрано и запущено само приложение.
Установка в одну строку:
bash <(curl -sL https://raw.githubusercontent.com/iondv/iondv-app/master/iondv-app) -t git -q -i -m localhost:27017 app
Где параметры для iondv-app localhost:27017
адрес MongoDB, а app
название приложения. После запуска открыть ссылку http://localhost:8888, учетная запись бек офиса demo, пароль ion-demo.
Также другой способ заключается в клонировании - git clone https://github.com/iondv/iondv-app.git
и установите приложение с помощью команды bash iondv-app -m localhost:27017 app
, где app - название приложения.
Можно также собрать приложение в докер конейтнерах, тогда из окружения нужен только docker и СУБД mongodb в докер контейнере.
Требования к окружению¶
Для работы системы должна быть запущена СУБД Монго ДБ. В docker-контейнере её можно запустить командой:
docker run --name mongodb -v mongodb_data:/data/db -p 27017:27017 -d mongo
Описание подготовки системы приведено ниже.
Установка, сборка и запуск приложения одной командой в докер-контейнере¶
Примеры сборок ниже, подразумевают что СУБД запущена в контейнере с именем mongodb.
На примере простейшего приложения Nutrition-Tickets, команда скачивает установщик с репозитория github, который собирает и запускает приложение в docker-контейнере в текущей директории.
из репозтория git
bash <(curl -sL https://raw.githubusercontent.com/iondv/iondv-app/master/iondv-app) \ -t docker -q -i -l mongodb nutrition-tickets
из архива zip, например полученного с гитхаб
curl -L https://github.com/iondv/nutrition-tickets/archive/master.zip > ./nutrition-tickets.zip
или созданного в IONDV. Studio. Обратите внимание, что вpackage.json
созданного приложения в атрибуте"ionModulesDependencies"
нужно указать модуль для отображения данным - обычно это"registry"
.bash <(curl -sL https://raw.githubusercontent.com/iondv/iondv-app/master/iondv-app) \ -t docker -q -i -l mongodb ./nutrition-tickets.zip
из папки, при этом оригинальная папка приложения не модифицируется. Обратите внимание, что название папки должно соответствовать неймспейсу приложения (если папка распакована с архива github - то в названии обычно добавляется код ветки - нужно переименовать)
bash <(curl -sL https://raw.githubusercontent.com/iondv/iondv-app/master/iondv-app) \ -t docker -q -i -l mongodb ./nutrition-tickets
Адрес собранного приложения по умолчанию http://localhost:8888, пользователь demo
, пароль ion-demo
.
Установка, сборка и запуск приложения в локальной файловой системе¶
Примеры сборок ниже, подразумевают что СУБД запущена локально и доступна по адресу localhost:27017.
Установка в локальной файловой системе позволяет получить приложение готовое к модификации и доработкам средствами разработчика,
например в IDE - достаточно открыть папку приложения. Папка приложения создается в папке запуска, либо в папке заданной
параметром -p
из репозитория git в папке
/workspace
bash <(curl -sL https://raw.githubusercontent.com/iondv/iondv-app/master/iondv-app) \ -t git -p /workspace -m localhost:27017 https://github.com/iondv/nutrition-tickets.git
из архива zip в текущей папке, например полученного с гитхаб
curl -L https://github.com/iondv/nutrition-tickets/archive/master.zip > ./nutrition-tickets.zip
или созданного в IONDV. Studio. Обратите внимание, что вpackage.json
созданного приложения в атрибуте"ionModulesDependencies"
нужно указать модуль для отображения данным - обычно это"registry"
bash <(curl -sL https://raw.githubusercontent.com/iondv/iondv-app/master/iondv-app) \ -t git -p /workspace -m localhost:27017 ./nutrition-tickets.zip
из папки, при этом оригинальная папка приложения не модифицируется. Обратите внимание, что название папки должно соответствовать неймспейсу приложения (если папка распакована с архива github - то в названии обычно добавляется код ветки - нужно переименовать)
bash <(curl -sL https://raw.githubusercontent.com/iondv/iondv-app/master/iondv-app) \ -t git -q -i -m localhost:27017 ./nutrition-tickets
Параметры запуска¶
iondv-app [OPTION]... IONDV_APP_NAME|IONDV_APP_NAME@VERSION|GIT_URL|IONDV_APP_ZIP|IONDV_APP_PATH
Параметры | Тип сборки приложения |
---|---|
-t [value] | git: клонирование репозиториев в файловую систему (требуется установленный git) docker: сборка в докер-контейнерах, не требует установки окружения на хост-машину |
-c [value] | запуск приложения как кластера с кол-вом инсталляций [value] |
-m [value] | uri для монгодб, примеры: mongodb:27017. localhost:27017 - по умолчанию (при сборке в докере выдаст ошибку подключения к БД(!). Для докера используйте параметр -l, либо укажите внешний адрес СУБД |
-r | проверка и удаление папки с именем приложения в директории сборки |
-i | импорт данных при инициализации приложения |
-a | импорт ролей и учетных записей пользователей при инициализации приложения |
-y | применение всех значений по умолчанию (yes to all) |
-q | тихий режим. Показывается только основная информация, предупреждения и ошибки |
-l [value] | имя контейнера MongoDB для линковки к собранному контейнеру (тип сборки docker или параметр -d при типе сборки git), также формирует конфигурацию с указанием значения mongo uri как [value]:27017 |
-p [value] | путь к директории в которой будет создавать папка с именем приложения и осуществляться сборка |
-s [value] | полный путь к скрипту, запускаемому в папке приложения после сборки, но до деплоя приложения. Может использоваться для дополнительной обработки файлов приложения |
-n [value] | параметр определяющий запуск изменение неймспейса приложения на новое, до деплоя |
-h | пропуск переключения на версии зависимостей приложения, установка последних версий |
-x | выход без запуска приложения |
Параметры для метода git: | |
-d | на основе собранной версии подготовить также docker-контейнер. Также остановить и удалить контейнер, образ с таким именем |
-k | пропустить проверку окружения |
Параметры для метода сборки docker: | сохранять временные версии контейнеров - позволяет ускорить последующие сборки. Но кэширование пропускается, если установлен флаг игнорировать версии зависимостей |
-v | на основе собранной версии подготовить также docker-контейнер. Также остановить и удалить контейнер, образ с таким именем |
Переменные окружения: | |
IONDVUrlGitFramework | URL репозитория фреймворка, по умолчанию https://github.com/iondv/framework.git Вы можете задать логин и пароль к своей версии в приватном репозитории. Например: https://login:password@git.company-name.com/iondv/framework.git |
IONDVUrlGitModules | URL к модулям, по умолчанию by default https://github.com/iondv |
IONDVUrlGitApp | URL к приложениям - используется если для сборки указано только имя приложения, по умолчанию https://github.com/iondv |
IONDVUrlGitExtApp | URL к приложениям-расширениям, по умолчанию https://github.com/iondv |
Подготовка окружения¶
Установка docker¶
Рекомендуется делать не под root
- Установка последней версии docker для CentOS:
1. Обновляем систему
sudo yum update
2. Устанавливаем необходимые библиотеки
yum install -y yum-utils device-mapper-persistent-data lvm2
3. Регистрируем репозиторий
yum-config-manager --add-repo
https://download.docker.com/linux/centos/docker-ce.repo
4. Установка последней версии
yum -y install docker-ce docker-ce-cli containerd.io
5. Запускаем докер
systemctl start docker
6. Для автоматического запуска докера
systemctl enable docker
- Установка последней версии docker для Ubuntu:
Добавляем ключ GDP
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
Проверяем ключ
apt-key fingerprint 0EBFCD88
Добавляем репозиторий
sudo add-apt-repository \ "deb [arch=amd64] https://download.docker.com/linux/ubuntu \ $(lsb_release -cs) \ stable"
Обновляем репозитории
sudo apt-get update
Ставим последнюю версию
sudo apt-get install docker-ce docker-ce-cli containerd.io
Добавляем текущего пользователя в группу docker:
sudo groupadd docker sudo usermod -aG docker $USER
Проверить можно docker run hello-world
Запуск Mongo в докере¶
Запускаем с маппингом на локальный порт:
docker run --name mongodb -v mongodb_data:/data/db -p 27017:27017 -d mongo
Установка node¶
Для ускорения сборки, рекомендуется предварительно скачать локально docker-образ node:10, т.к. он занимает 900Мб.
docker pull node:10
Проверить можно командой docker images | grep node
- будет отображён спискок локальных образов node.
Начать знакомство с IONDV. Framework рекомендуем с быстрого запуска приложений.
В этом разделе приведены инструкции для разворачивания приложений IONDV. Framework. Существует несколько способов быстрого запуска приложений. Вы можете определиться со способом, который удобен для Вас.
Развернуть приложения Вы можете следующими способами:
- с помощью IONDV. Studio
- клонирование репозитория приложения и установка всех компонентов - смотреть
- с помощью docker-контейнера с собранными приложениями
- с помощью установщика для операционной системы Linux
Ссылки¶
Ниже представлены ссылки на дополнительную информацию по разработке приложений с использованием IONDV.Framework.
- Документация
- Домашняя страница фреймворка
- Обратная связь на Facebook
- Обучающие видеоролики на youtube
Copyright (c) 2016-2020 LLC «ION DV».
All rights reserved.
3. Разработка¶
Расширение функциональности¶
Разработка функциональных утилит в приложении¶
Функциональные утилиты приложения предназначены для решения специфичных задач приложения, без реализации отдельной логики в виде модуля.
Например - утилиты вызываемой задачи по расписанию или утилиты вызываемой при переходе в бизнес-процессе.
Утилиты для кнопок действия¶
Утилиты для кнопок действия предназначены для автоматизации выполнения некоторых действий при нажатии кнопки в веб-форме.
Кнопка подключается для веб-формы создания и редактирования объекта через массив commands
основого объекта формы:
{
"commands": [
{
"id": "SAVE",
"caption": "Save",
"visibilityCondition": null,
"enableCondition": null,
"needSelectedItem": false,
"signBefore": false,
"signAfter": false,
"isBulk": false
},
{
"id": "SAVEANDCLOSE",
"caption": "Save and close",
"visibilityCondition": null,
"enableCondition": null,
"needSelectedItem": false,
"signBefore": false,
"signAfter": false,
"isBulk": false
},
{
"id": "CREATE_INDICATOR_VALUE",
"caption": "Form the collected values",
"visibilityCondition": null,
"enableCondition": null,
"needSelectedItem": false,
"signBefore": false,
"signAfter": false,
"isBulk": false
}
],
На этой форме доступно три кнопки: SAVE
, SAVEANDCLOSE
и CREATE_INDICATOR_VALUE
.
Пользовательские кнопки перед подключением к форме необходимо задать в deploy.json
в объекте modules.registry.globals.di.actions.options.actions
:
{
"modules": {
"registry": {
"globals" : {
"di": {
"actions": {
"options": {
"actions": [
{
"code": "CREATE_INDICATOR_VALUE",
"handler": "ion://createIndicatorValueHandler"
},
{
"code": "ASSIGNMENT_TO_EVENT_ONLY",
"handler": "ion://assignmentToEventOnly"
},
{
"code": "CREATE_PROJECT_REPORTS",
"handler": "ion://createProjectReportsHandler"
}
]
А также указать параметры используемого кнопкой модуля-обработчика:
{
"modules": {
"registry": {
"globals" : {
"di": {
"createIndicatorValueHandler": {
"module": "applications/sakh-pm/lib/actions/createIndicatorValueHandler",
"initMethod": "init",
"initLevel": 2,
"options": {
"data": "ion://securedDataRepo",
"workflows": "ion://workflows",
"log": "ion://sysLog",
"changelogFactory": "ion://changelogFactory",
"state": "onapp"
}
},
В этом примере нажатие на кнопку CREATE_INDICATOR_VALUE
запускает скрипт ./applications/sakh-pm/lib/actions/createIndicatorValueHandler.js
.
Содержание скрипта:
/**
* Created by kras on 08.09.16.
*/
'use strict';
const ActionHandler = require('modules/registry/backend/ActionHandler');
const edit = require('modules/registry/backend/items').saveItem;
const ivc = require('../indicator-value-creator');
/**
* @constructor
* @param {{}} options
* @param {DataRepository} options.data
* @param {WorkflowProvider} options.workflows
* @param {Logger} options.log
* @param {ChangelogFactory} [options.changelogFactory]
* @param {String} [options.state]
*/
function CreateIndicatorValueHandler(options) {
options = options || {};
const work = ivc(options);
this.init = function () {
if (options.workflows && options.state) {
options.workflows.on(
'indicatorBasic@sakh-pm.' + options.state,
(e) => {
let logger = null;
if (options.changelogFactory && e.user) {
logger = options.changelogFactory.logger(() => e.user.id());
}
return work(e.item, e.user, logger).then(() => null);
}
);
}
};
/**
* @param {{metaRepo: MetaRepository, securedDataRepo: SecuredDataRepository}} scope
* @param {ChangelogFactory} scope.changelogFactory
* @param {Request} req
* @returns {Promise}
*/
this._exec = function (scope, req) {
let logger;
let user = scope.auth.getUser(req);
if (options.changelogFactory) {
logger = options.changelogFactory.logger(() => user.id());
}
return edit(scope, req, null, logger, true)
.then(item => scope.dataRepo.getItem(item, null))
.then((item) => {
if (item.get('status') !== 'edit') {
throw new Error('Создать значения показателей, можно только при редактировании!');
}
return work(item, user, logger);
})
.then((count) => {
return {$message: 'Создано ' + count + ' значений для ввода по периодам!'};
});
};
}
CreateIndicatorValueHandler.prototype = new ActionHandler();
module.exports = CreateIndicatorValueHandler;
Утилиты для задач по расписанию¶
Утилиты для задач по расписанию (jobs) предназначены для автоматизации регулярного выполнения некоторых действий через определенные промежутки времени.
Для этого каждая утилита должна быть определена в deploy.json приложения в объекте globals.jobs, например:
{
"globals": {
"jobs": {
"ticketClose": {
"description": "Ночной перевод билетов в статус \"проверен\"",
"launch": {
"timeout": 3600000,
"hour": 24
},
"worker": "ticketCloser",
"di": {
"ticketCloser": {
"executable": "applications/khv-ticket-discount/lib/overnightTicketClose",
"options": {
"dataRepo": "ion://dataRepo",
"log": "ion://sysLog",
"workflows": "ion://workflows"
...
В di
должно содержаться поле с именем, равном значению worker
- это задача, которая будет запускаться.
Здесь по расписанию выполняется скрипт applications/khv-ticket-discount/lib/overnightTicketClose.js
.
launch
может быть объектом, содержащим следующие поля:
month
, week
, day
, dayOfYear
, weekday
, hour
, min
, minute
, sec
, second
- задают интервал между выполнениями задачи;
check
- интервал проверки условия выполнения, в милисекундах, по умолчанию - 1000.
Например если check
равен 5000, а sec
- 2, задание будет выполняться лишь каждые 10 секунд, когда интервал между проверками совпадет с интервалом выполнения
Если интервал выполнения задачи не задан, то она будет выполнена при запуске приложения и через каждый интервал проверки.
timeout
- время в милисекундах, после которого запущенная задача прерывается по таймауту;
launch
также может равняться целому числу - интервалу выполнения задания в милисекундах, при этом задача также будет выполнена сразу при запуске приложения. Таймаут будет установлен равным интервалу выполнения.
В поле options
могут быть указаны любые переменные и их значения, которые станут доступны в скрипте через поля объекта, передаваемого как аргумент основной функции модуля.
Скрипт составляется в формате модуля, например так:
"use strict";
const Logger = require("core/interfaces/Logger");
module.exports = function (options) {
return options.dataRepo
.getList(
"ticket@khv-ticket-discount",
"ticketYear@khv-ticket-discount"
)
.then((tickets) => {
let p = Promise.resolve();
tickets.forEach((ticket) => {
p = p
.then(() => options.dataRepo.editItem(ticket.getClassName(), ticket.getItemId(), {"state": "close"}))
.then(item => (item.name === "ticketYear" ?
options.workflows.pushToState(item, "ticketYear@khv-ticket-discount", "close") :
options.workflows.pushToState(item, "ticket@khv-ticket-discount", "close")))
.catch((err) => {
if(options.log instanceof Logger) {
options.log.error(err);
} else {
console.error(err);
}
});
});
return p;
});
};
Утилиты для печатных форм¶
Утилиты для печатных форм (инжекторы) предназначены для обработки выводимых в шаблон данных, в том числе проведения промежуточных расчетов и форматирования.
Печатную форму, для которой будет использоваться инжектор, необходимо определить в deploy.json, например:
"registry": {
"globals": {
"di": {
"pmListToDocx": {
"module": "modules/registry/export/listToDocx",
"initMethod": "init",
"initLevel": 0,
"options": {
"tplDir": "applications/khv-ticket-discount/export/list",
"log": "ion://sysLog",
}
...
}
...
}
...
}
...
}
В данном случае используется модуль listToDocx, следовательно в печатную форму будет выгружен список всех объектов определенного класса.
Для каждого такого класса в tplDir нужно создать папку с названием пространства имен, в которую затем поместить файл с названием нужного для выгрузки класса из этого пространства имен, например:
...\applications\khv-ticket-discount\export\list\khv-ticket-discount\ticketYear.docx
Таким образом в документ будет выгружен список всех объектов класса ticketYear@khv-ticket-discount.
Сама утилита представляет собой .js скрипт, подключаемый к приложению в формате модуля в deploy.json, например так:
"registry": {
"globals": {
"di": {
"weekTicketStatsInjector": {
"module": "applications/khv-ticket-discount/export/injectors/monthTicketStats",
"options": {
"dataRepo": "ion://dataRepo"
}
...
}
...
}
...
}
...
}
.js файл здесь находится по пути «module».
После подключения утилиту необходимо включить в опции печатной формы:
"registry": {
"globals": {
"di": {
"pmListToDocx": {
"module": "modules/registry/export/listToDocx",
"initMethod": "init",
"initLevel": 0,
"options": {
"tplDir": "applications/khv-ticket-discount/export/list",
"log": "ion://sysLog",
"injectors": [
"ion://monthTicketStatsInjector"
]
}
...
}
...
}
...
}
...
}
Скрипт инжектора составляется в формате модуля, с тем условием, что он должен содержать функцию this.inject, в параметр которой будет передан объект с вложенным в него списком объектов заданного ранее класса, для примера из этой справки:
ticketYear@khv-ticket-discount
Пример файла monthTicketStats.js:
function monthTicketStatsInjector() {
this.inject = function (value) {
if (value && value.className === "ticketYear") {
let expValueList = [];
const periodBegF = value.periodBegF;
const periodEndF = value.periodEndF;
const areaF = value.areaF;
let i = 0;
value.list.forEach((vectorparams) => {
if (vectorparams.person.area.code === areaF && vectorparams.dateAirGo >= periodBegF && vectorparams.dateAirGo <= periodEndF && ((vectorparams.state !== "canceled") && (vectorparams.state !== "returned"))) {
expValueList[i++] = vectorparams;
}
});
value.list = expValueList;
}
return value;
};
}
module.exports = monthTicketStatsInjector;
Пример конфигурации экспорта для данной формы в deploy.js:
"registry": {
"globals": {
"di": {
"export": {
"options": {
"configs": {
"ticketYear@khv-ticket-discount": {
"pmListToDocx": {
"type": "list",
"caption": "Ежемесячный отчет",
"mimeType": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
"extension": "docx",
"params": {
"periodBegF": {
"caption": "Период с",
"type": "date"
},
"periodEndF": {
"caption": "по",
"type": "date"
},
"areaF": {
"caption": "Район",
"type": "reference",
"className": "area@khv-ticket-discount"
}
},
"preprocessor": "ion://pmListToDocx",
"eagerLoading": [
"person",
"person.documents",
"person.area",
"route.pointDeparture",
"route.pointArrival",
"route.flight"
],
"fileNameTemplate": "Ежемесячный отчет"
}
}
}
}
...
}
...
}
...
}
Здесь следует обратить внимание на поле params - в нем можно указать параметры, доступные в форме экспорта в веб сервисе приложения. Возможны следующие типы параметров:
«string» - строка для ввода текста,
«date» - интерактивный календарь, в котором можно выбрать интересующую дату
«reference» - ссылка на класс, в данном случае в окне экспорта будет отображен выпадающий список всех объектов класса.
Переданные параметры будут доступны в скрипте через параметр функции this.inject.
Утилиты для веб-сервиса (rest)¶
Утилиты веб-сервиса предназначены для реализации обработки различных видов запросов к серверу.
Cервис подключается к приложению в deploy.json в объекте modules.rest.globals.di, например так:
{
"modules": {
"rest": {
"globals": {
"di": {
"acceptor": {
"module": "modules/rest/lib/impl/acceptor",
"options": {
"dataRepo": "ion://dataRepo",
"metaRepo": "ion://metaRepo"
...
В этом случае подключается сервис acceptor
, он станет доступен для запросов по url https://dnt.iondv.com/rest/acceptor
.
Функциональное описание взаимодействия с запросами должно содержаться в скрипте modules/rest/lib/impl/acceptor.js
.
В поле options
могут быть указаны любые переменные и их значения, которые станут доступны в скрипте через поля объекта, передаваемого как аргумент основной функции модуля.
Скрипт составляется в формате модуля, например так:
const Service = require('modules/rest/lib/interfaces/Service');
/** Simple app service - REST module
* @param {{dataRepo: DataRepository, metaRepo: MetaRepository}} options
* @constructor
*/
function EchoRest(options) {
this._route = function(router) {
this.addHandler(router, '/', 'POST', (req) => {
return Promise.resolve({
echo: 'peekaboo'
});
});
this.addHandler(router, '/', 'GET', (req) => {
return Promise.resolve({
echo: 'peekaboo'
});
});
};
}
EchoRest.prototype = new Service();
module.exports = EchoRest;
Подробное описание принципов создания сервиса можно найти в https://github.com/iondv/rest/blob/master/README_RU.md/ раздел Разработка обработчика сервиса в приложении
Утилиты для бизнес-процесса¶
Утилиты для бизнес-процесса предназначены для автоматизации выполнения некоторых действий при изменении статуса бизнес процесса. Утилита подключается к приложению в deploy.json в объекте globals.plugins, например так:
{
"globals": {
"plugins": {
"wfEvents": {
"module": "applications/sakh-pm/lib/wfEvents",
"initMethod": "init",
"initLevel": 1,
"options": {
"workflows": "ion://workflows",
"metaRepo": "ion://metaRepo",
"dataRepo": "ion://dataRepo",
"log": "ion://sysLog",
"AIPConfigPath": "applications/sakh-pm/paths_config/eventOnlyAIP.json"
Здесь подключается утилита wfEvents
. Скрипт, содержащий описание действий при изменении статуса бизнес-процесса находится по пути applications/sakh-pm/lib/wfEvents.js
.
В поле options
могут быть указаны любые переменные и их значения, которые станут доступны в скрипте через поля объекта, передаваемого как аргумент основной функции модуля.
Скрипт составляется в формате модуля, при условии, что он должен включать метод init, например так:
'use strict';
const ivc = require('./indicator-value-creator');
function WorkflowEvents(options) {
this.init = function () {
options.workflows.on(
['assignmentBasic@sakh-pm.fin'],
(e) => {
if (e.transition === 'toKT') {
return options.dataRepo.getItem(e.item, null, {forceEnrichment: [['meeting','basicObj'],['basicObj']]})
.then((item) => {
const data = {
basicObj: item.property('meeting.basicObj').evaluate() || item.property('basicObj').evaluate(),
name: item.get('name'),
owner: item.get('owner'),
datePlannedEnd: e.item.get('datePlannedEnd'),
priority: e.item.get('priority'),
descript: e.item.get('descript')
};
return options.dataRepo.createItem('eventControl@sakh-pm', data, null, {user: e.user});
});
}
return Promise.resolve();
}
);
options.workflows.on(
['proposal@sakh-pm.cancel'],
(e) => {
if (e.transition === 'curatorToCancel') {
return options.dataRepo.editItem(e.item.getMetaClass().getCanonicalName(), e.item.getItemId(), {archive: true})
.then(
item => collectionToArchive(item, 'proposals')
.then(() => collectionToArchive(item, 'eventBlock'))
.then(() => collectionToArchive(item, 'project'))
);
}
return Promise.resolve();
}
);
};
}
module.exports = WorkflowEvents;
В этом скрипте описаны действия, которые нужно выполнить при изменении статуса бизнес-процесса assignmentBasic@sakh-pm
на fin
, и статуса бизнес-процесса proposal@sakh-pm
на cancel
.
Ключевые функции ядра¶
dataRepo¶
//dataRepo info from
- coreimpldatarepositoryionDataRepository.js
- coreinterfacesDataRepositoryDataRepository.js
- coreinterfacesMetaRepositoryMetaRepository.js
- coreimplmetaDsMetaRepository.js
#. coreiterfacesDataSource.js #.
coreimpldatasourcemongodb.js // supported calls:
- wrap(className, data, [version], [options]) supported options: user …
- setValidators(validators[]) …
- getCount(obj, [options]) supported options: filter
Возвращает количество объектов класса obj в базе данных. …
- getList(obj, [options]) supported options: filter offset count sort countTotal nestingDepth env user
Возвращает список объектов класса obj в базе данных. …
- getIterator(obj, [options]) supported options: filter offset count sort countTotal nestingDepth env user
предположительно https://docs.mongodb.com/manual/tutorial/iterate-a-cursor/ …
- aggregate(className, [options]) supported options: user expressions filter groupBy
предположительно https://docs.mongodb.com/manual/aggregation/
…
- rawData(className, [options]) supported options: user filter attributes distinct
https://docs.mongodb.com/manual/reference/method/db.collection.find/ …
- getItem(obj, [id], [options]) supported options: filter nestingDepth user …
- createItem(className, data, [version], [changeLogger], [options]) supported options: nestingDepth skipResult adjustAutoInc user …
- editItem(className, id, data, [changeLogger], [options]) supported options: nestingDepth skipResult adjustAutoInc user …
- saveItem(className, id, data, [version], [changeLogger], [options]) supported options: nestingDepth autoAssign skipResult adjustAutoInc user …
- deleteItem(className, id, [changeLogger], [options]) supported options: user …
- put(master, collection, details, [changeLogger], [options]) supported options: user …
- eject(master, collection, details, [changeLogger], [options]) supported options: user …
- getAssociationsList(master, collection, [options]) supported options: filter offset count sort countTotal nestingDepth user …
- getAssociationsCount(master, collection, [options]) supported options: filter offset count sort countTotal nestingDepth user …
- bulkEdit(classname, data, [options]) supported options: filter nestingDepth forceEnrichment user …
- bulkDelete(classname, [options]) supported options: filter user
- recache(item, [options]) …
MetaRepo¶
TODO
Workflow¶
TODO
Использование шаблонов для полей ввода данных в веб-форме¶
Шаблоны предназначены для задания пользовательских параметров построения полей ввода данных в веб-форме.
Для подключения шаблона к полю веб-формы, необходимо указать его в опциях соответствующего поля json формы:
{
"tabs": [
{
"caption": "General info",
"fullFields": [
{
"property": "surname",
"caption": "Surname",
//...
"options": {
"template": "capitalize"
},
"tags": ""
},
Шаблоны в формате .ejs
загружаются по пути, указанном в modules.registry.globals.templates
из deploy.json
.
Например, если указан путь applications/khv-ticket-discount/templates/registry
, то в прошлом примере для поля property
будет загружен скрипт applications/khv-ticket-discount/templates/registry/capitalize.ejs
.
Скрипт будет выполнен при загрузке поля в веб-форме. Синтаксис стандартный для ejs.
Внутри скрипта доступны некоторые элементы веб-формы, подробнее: Опции.
Пример скрипта для автоматической замены в текстовом поле ввода нижнего регистра букв на верхний и буквы «ö» на «o»:
<% wfState = item.base.state %>
<div class="form-group <%= wfState === 'edit' || item.id === null ? (field.required ? 'required' : '') : '' %> " style data-type="<%= wfState === 'edit' || item.id === null ? 'input' : 'static' %>" data-name="<%= prop.getName().toLowerCase() %>" data-prop="<%= JSON.stringify(field) %>" >
<label for="a_khv-ticket-discount_<%= item.getClassName().split('@')[0] %>_<%= prop.getName().toLowerCase() %>" class="col-md-2 col-sm-3 control-label"><%= prop.getCaption() %>
</label>
<div class="col-sm-9">
<input id="a_khv-ticket-discount_<%= item.getClassName().split('@')[0] %>_<%= prop.getName().toLowerCase() %>" type="<%= wfState === 'edit' || item.id === null ? 'text' : 'hidden' %>" class="form-control attr-value" name="<%= prop.getName().toLowerCase() %>" data-mask="{"regex":"[öÖa-zA-Z .-]{1,50}"}" placeholder="<%= prop.getCaption() %>" value="<%= prop.getValue() !== null ? prop.getValue() : "" %>" im-insert="true">
<% if(wfState === 'done' && item.id !== null) { %>
<div class="form-control-static"><%= prop.getValue() %></div>
<% } %>
<script>
if (typeof inputField !== 'object') {inputField = [];}
propName = '<%= prop.getName().toLowerCase() %>';
inputField['<%= item.getClassName().split('@')[0] %><%= prop.getName().toLowerCase() %>'] = document.getElementById(`a_khv-ticket-discount_<%= item.getClassName().split('@')[0] %>_${propName}`);
inputField['<%= item.getClassName().split('@')[0] %><%= prop.getName().toLowerCase() %>'].addEventListener('focusout',applyStyle)
inputField['<%= item.getClassName().split('@')[0] %><%= prop.getName().toLowerCase() %>'].addEventListener('keyup', applyStyle)
inputField['<%= item.getClassName().split('@')[0] %><%= prop.getName().toLowerCase() %>'].addEventListener('keydown', applyStyle)
inputField['<%= item.getClassName().split('@')[0] %><%= prop.getName().toLowerCase() %>'].addEventListener('paste', applyStyle)
function applyStyle() {
while ((/[Ö]/).test(inputField['<%= item.getClassName().split('@')[0] %><%= prop.getName().toLowerCase() %>'].value)) {
inputField['<%= item.getClassName().split('@')[0] %><%= prop.getName().toLowerCase() %>'].value = inputField['<%= item.getClassName().split('@')[0] %><%= prop.getName().toLowerCase() %>'].value.replace(/[Ö]/, 'O');
}
while ((/[ö]/).test(inputField['<%= item.getClassName().split('@')[0] %><%= prop.getName().toLowerCase() %>'].value)) {
inputField['<%= item.getClassName().split('@')[0] %><%= prop.getName().toLowerCase() %>'].value = inputField['<%= item.getClassName().split('@')[0] %><%= prop.getName().toLowerCase() %>'].value.replace(/[ö]/, 'o');
}
while ((/[a-z]/).test(inputField['<%= item.getClassName().split('@')[0] %><%= prop.getName().toLowerCase() %>'].value)) {
inputField['<%= item.getClassName().split('@')[0] %><%= prop.getName().toLowerCase() %>'].value = inputField['<%= item.getClassName().split('@')[0] %><%= prop.getName().toLowerCase() %>'].value.toUpperCase();
}
//(/[а-я]/).test(inputField['<%= item.getClassName().split('@')[0] %><%= prop.getName().toLowerCase() %>'].value[0]) ? inputField['<%= item.getClassName().split('@')[0] %><%= prop.getName().toLowerCase() %>'].value = inputField['<%= item.getClassName().split('@')[0] %><%= prop.getName().toLowerCase() %>'].value[0].toUpperCase() + inputField['<%= item.getClassName().split('@')[0] %><%= prop.getName().toLowerCase() %>'].value.substring(1) : ""; - только первая буква}
}
</script>
</div>
</div>
Функциональность¶
Функциональность приложения - это набор возможностей (функций), которые реализуются отдельно и независимо от метаданных, но в рамках приложения.
Наименование | Описание |
---|---|
Шаблоны модулей | Разделяются на системные и проектные шаблоны. |
Печатные формы | Передача форматирования в прописном виде. |
Задания по расписанию | Подсистемы запуска заданий по расписанию. |
Уведомления | Лента новых уведомлений. |
Кеширование данных | Кеширование данных обеспечивает быстрый доступ к запрашиваемой информации. |
Фильтры на форме | Запрос для фильтра на форме представления списка. |
Связь двух неймспейсов | Для связывания двух проектов. |
ЭЦП | Электронно-цифровая подпись. |
Виртуальные атрибуты | Специальный тип атрибутов, который позволяет выводить полный код и наименование класса. |
Утилиты | Дополнительные программы для более специализированного применения |
Шаблоны модулей¶
Тема оформления¶
Тема оформления - директория следующей структуры:
/static/css директория стилей
/static/js директория скриптов
/templates директория шаблонов ejs
Темы оформления могут располагаться:
- В директории
view
модуля и платформы - тогда это системные темы оформления - В директории
applications
платформы как приложения - тогда это проектные темы оформления - В директории
themes
приложения - тогда это проектные темы офрмления
Настройка текущей темы оформления:
- Для платформы
- Настройка theme в config.json платформы
- Настройка globals.theme в deploy.json приложения
- Для модуля
- Настройка theme в config.json модуля
- Настройка Имя модуля.globals.theme в deploy.json приложения
По умолчанию используется системная тема default
(в платформе и модулях registry, geomap, report, offline-sync).
В настроке theme
указывается путь до директории темы, он разрешается в соответствии с правилами:
- Абсолютный путь берется как есть
- Относительный путь разрешается относительно системных путей в следующем порядке:
- Относительно директории
view
модуля или платформы - Относительно директории
applications
платформы - Относительно директории платформы
- Относительно директории
Печатные формы¶
Печатные формы Word¶
- Используется библиотека docxtemplater
- Примеры подключения и использования docxtemplater здесь.
Параметры передачи форматирования¶
Для table_col
параметр для передачи форматирования см. правила/примеры здесь.
Вид:
${table_col:коллекция:разделитель:формат}
Пример:
${table_col:list.instructions.limit:;:DD.MM.YYYY}
Результат:
30.08.2017;06.09.2017
В формате допускается использование символа :
.
Вывод значения суммы в прописном варианте¶
Для docx-шаблонов есть фильтр toWords, который по умолчанию преобразует просто в текст, если добавить вторым параметром true, то будет добавляться рублевый формат (рубли - копейки).
{costing.costExp | toWords:true}
В результате значение атрибута «costExp» = 345,52. Результат в печатной форме будет = Триста сорок пять рублей пятьдесят две копейки.
Преобразования между датой и строкой¶
Доступны к применению следующие функции:
- date - преобразование строки в дату
- upper - строку к верхнему регистру
- lower - строку к нижнему регистру
В экспорте в docx в выражениях доступны фильтры:
- lower - к нижнему регистру
- upper - к верхнему регистру
- dateFormat - дата к строке, примеры применения:
- {now | dateFormat:
ru
} - {since | dateFormat:
ru
} - {date | dateFormat:ru:YYYYMMDD}
- {now | dateFormat:
- toDate - строка к дате
Значение текущей даты _now
¶
{_now} г.
Настройка для отображения значения полей из массива объектов¶
Если необходимо отобразить поля из массива объектов (коллекция например) используется тэг:
${table_col:list.collection.attrFromCollection}
По умолчанию значения будут объеденины через точку с запятой. Чтобы указать другой разделитель, укажите его после второго двоеточия:
${table_col:list.collection.attrFromCollection:разделитель}
Подсистема задания по расписанию¶
Запуск подсистемы заданий по расписанию выполняется двумя способами:
- в отдельном процессе посредством скрипта
bin/schedule.js
- внутри процесса веб-приложения ION (bin/www) путем указания в ini-файле опции
jobs.enabled=true
Во втором случае управление заданиями возможно реализовать в веб-приложении. Задания по расписанию настраиваются в deploy.json приложений в разделе глобальных настроек как параметр jobs.
Пример:¶
"jobs": {
"dummy": {
"launch": { // Периодичность запуска задания
"month": [2,5], // в феврале и мае
"week": 3, // каждую третью неделю (month и week - взаимоисключающие настройки),
"weekday": [1, 3, 5], // по понедельникам, средам и пятницам
"dayOfYear": 5, // раз в 5 дней в течение года,
"day": 10, // раз в 10 дней в течение месяца
"hour": 3, // раз в 3 часа
"minute": [10, 15, 35], // на 10-ой, 15-ой и 35-ой минуте
"sec": 10 // раз в 10 секунд
},
"di": { // скоуп задания
"dummy": {
"module": "applications/develop-and-test/jobs/dummy",
"options": {
}
}
},
"worker": "dummy", // имя компонента из скоупа задания, который будет исполняться
}
}
В качестве запускаемого задания может быть указан компонент, в этом случае он должен иметь метод run
. В качестве запускаемого задания может быть указана и функция. Тогда в di она описывается аналогично компоненту, но с использованием настройки executable
:
"di": {
"dummy": {
"executable": "applications/develop-and-test/jobs/dummy",
"options": {}
}
}
Пример:¶
Раздел jobs в глобальных настройках.
...
"jobs": {
"dummy": {
"launch": {
"sec": 30
},
"worker": "dummy",
"di": {
"dummy": {
"executable": "applications/develop-and-test/jobs/dummy"
}
}
}
...
Уведомления¶
Уведомления - на форме отображются в виде красного колокольчика, при клике на котором отображается лента уведомлений (10 последних непрочитанных), при клике на уведомлении оно скрывается как прочитанное. Лента обновляется раз в 15 секунд. Если колокольчик отсутсвует это значит что уведомлений нет.
Настройка уведомлений¶
Реализована отправка уведомлений на почту. Настраивается в проекте - TODO.
Реализовано API для отправки уведомлений программно. т.е. можно в обработчике события отправить уведомление. В админке при отправке уведомлений в поле «Получатели» указывается список полных имен пользователей (user@local) разделенных пробелом.
Хранение уведомлений происходит в коллекциях: ion_notification, ion_notification_recievers.
Кеширование данных¶
Логика работы¶
Между базовым репозиторием данных dataRepo
и репозиторием данных с проверкой безопасности securedDataRepo
внедрен репозиторий данных с поддержкой кеширования cachedDataRepo
.
Данные загружаются по цепочке: БД -> dataRepo -> cachedDataRepo -> securedDataRepo.
При этом, cachedDataRepo
, при запросе, сначала проверяет наличие данных в кеше (если кеширование активировано), и если данных в кеше нет, запрашивает их у dataRepo
, после чего помещает в кеш и отдает securedDataRepo
.
Настройка кеширования объектов отдельных классов¶
Можно индивидуально в файле настроек конфигурации приложения (deploy.json), в опциях cachedDataRepo
указать список классов, данные которых нужно хранить в кеше.
Пример:¶
...
"options": {
"cachedClasses": ["class1@namespace", "class2@namespace", "class3@namespace"]
}
...
Если cachedClasses не указан, то кешируются все данные.
Кеширование списка объектов¶
Кешируются как индивидуальные обьекты, так и списки.
При кешировании списка на основании его условий выборки (в т.ч. пагинации) формируется ключ, выполняется выборка и все полученные обьекты кешируются индивидуально, а список кешируется как массив идентификаторов обьектов. При выборке списка из кеша на основании этого массива из кеша выбираются соответствующие обьекты и формируется результирующий список.
Аналогично кешируются все объекты по ссылке и коллекции загружаемые жадно.
Настройка гибкого кеширования¶
Для расширенной конфигурации настроек кеширования (таких как, время хранения запросов, глубина хранения объектов в кеше и др.) применяется настройка гибкого кеширования объектов.
Настройка гибкого кеширования задается в файле deploy.json в свойстве "di"
, в компонентах memcached
и redis
в опции connectOptions
.
Все нужные плейсхолдеры прописаны в файле config.json репозитория платформы.
NB: Глубина хранения обьектов в кеше соответствует глубине запроса обьектов из БД, то есть в обьекте хранится информация о его ссылках, а дальше в кеше получается граф обьектов, а не дерево.
Настройка кеширования через ini файл приложения¶
Параметры ini файла:
...
cache.module=redis // - модуль используемый репозиторием данных для кеширования.
//(варианты: ion://memcached, ion://redis, ion://innerCache)
cache.memcached.enabled=true // активируем memcached
cache.memcached.location1 // сервер1
cache.memcached.location2 // сервер2
cache.memcached.timeout // таймаут обращения к кэшу
cache.redis.enabled=true // активируем redis
cache.redis.host=127.0.0.1 // хост redis
cache.redis.port=6379 // порт redis
session.type=redis // хранение сессий авторизации в redis
По умолчанию кеширование не используется.
Фильтры на форме представления списка¶
Если для даты значение в поле фильтра и значение в поле атрибута имеют разный формат, то фильтр по такому полю работать НЕ БУДЕТ
Запрос для фильтра задается выражением (поисковым запросом).
Поддерживает следующие операции:
- группировки скобками
- логических: AND, OR, NOT
- сравнения: =, <, >, <=, >=, <>
- арифметических: +, -, *, /
- строковых: like
- над коллекциями: size
Создание запроса¶
Выбор атрибута выполняется из выпадающего списка, с помощью кнопки >_
, расположенной у основания поля запроса для фильтра. Наименование атрибута оборочивается в «backticks» т.е.:
`Наименование атрибута` != 2
Параметры комбинации значений атрибутов для запроса:
- and - И - т.е. обязательно оба (или больше) значаний,
- or - ИЛИ - т.е. любое из значений оба (или больше) значаний.
пример комбинации:
`Атрибут1` = 1 AND `Атрибут2` != 2
Строковые значения атрибутов при формировании запроса оборачиваются в двойные кавычки:
`Название поля` != "привет"
Обращение к атрибутам по ссылке:
`Атрибут1`.`Атрибут по ссылке из Атрибут 1` = "значение"
Подсказки:
В конце поля запроса для фильтра расположен знак ?
, при клике на который откроется модельное окно с описанием принципа работы фильтра и синтаксиса запроса к нему.
Для парсинга поисковых выражений используется библиотека https://nearley.js.org/
Варианты использования¶
Помимо кнопки рядом со строкой поиска в верхней части страницы, фильтр можно вызывать кликом на аналогичного вида значек, расположенный в каждом столбце таблицы.
Для создания запроса для фильтра необходимо выбрать из выпадающего списка значение, или же начать ввод значения в строку. Как только значение выбрано необходимо нажать клавишу Enter
- в столбце со значениями отобразится результат запроса.
Связь двух неймспейсов¶
Связь нескольких проектов с использованием пространства имен «namespace»¶
Применяется при необходимости связывать между собой 2 проекта и разворачивать их на одной платформе, с указанием ссылок и коллекций не только внутри проекта, но и на другие, развернутые в этом же контексте. Реализуется с применением пространства имен проекта, т.е. что бы было понятно к какому проекту относятся классы по ссылке. Так, например, связываем тестовый проект develop-and-test
с проектом fias
:
Пример¶
{
"namespace": "develop-and-test",
"code": "projectJoin.addressExt",
"orderNumber": 0,
"type": 1,
"title": "",
"caption": "Адрес ФИАС",
"classname": "address@fias",
"container": null,
"collection": null,
"url": null,
"hint": null,
"conditions": [],
"sorting": [],
"pathChains": [],
"metaVersion": "2.0.61.21119"
}
В меню проекта develop-and-test
есть узел навигации, который является представлением класса из проекта fias
. Таким образом при переходе по пункту меню одного проекта - получаем данные из другого проекта, при указании необходимого пространства имен.
Описание¶
Для меты:¶
При импорте неймспейс берется не из параметра, а из меты класса. Убираем неймспейс как параметр навигации и т.д.
При импорте меты навигации, при совпадении системных имен приоритет имеет мета, накатываемая последней, но с учетом заполненности атрибутов. т.е. пустое значение атрибута не переопределяет непустое.
Для студии:¶
В мете класса добавляется свойство namespace
. В студии в настройках проекта ION добавлен параметр - «пространство имен». Это пространство имен по умолчанию проставляется в соответствующее поле на форме создания класса.
Для атрибута «пространство имен» также заданы отдельные поля на формах создания и редактирования класса. В студии теперь системное имя класса везде отображается с неймспейсом через знак @
, если класс объявлен в неймспейсе отличном от неймспейса текущего проекта.
Поле неймспейса в виде выпадающего списка, откуда можно выбрать либо неймспейс проекта, либо неймспейсы связанных проектов (Project references). При этом есть возможность и вбить его руками.
У остальных объектов меты неймспейса нет, но ссылки на классы везде должны проставляться с учетом неймспейса (в ссылочных атрибутах тоже). Это значит, что в списках выбора классов должно быть полное имя класса с неймспейсом.
Также в списки выбора классов должны попадать классы из всех Project References. На физическом уровне неймспейс включается в имя файла меты класса (и директорий, если они участвуют в формировании логики привязки к классу, например, у меты представления).
Электронно-цифровая подпись¶
Описание¶
Электронно-цифровая подпись (ЭЦП) - это реквизит электронного документа, предназначенный для защиты данного электронного документа от подделки, полученный в результате криптографического преобразования информации с использованием закрытого ключа электронной цифровой подписи. Он позволяет идентифицировать владельца сертификата ключа подписи и установить отсутствие искажения информации в электронном документе.
Цель использования¶
В приложении ЭЦП может быть нужна для:
- Проверки целостности данных
- Определения авторства данных
Существует три вида электронной цифровой подписи, которые отличаются по своему применению:
- Простая электронно-цифровая подпись
- для определения авторства данных
- создается с использованием кодов, паролей или иных средств
- Усиленная неквалифицированная электронно-цифровая подпись
- для проверки целостности данных
- для определения авторства данных
- создается с использованием средств электронной подписи
- Усиленная квалифицированная электронно-цифровая подпись
- для проверки целостности данных
- для определения авторства данных
- для создания и проверки электронной подписи используются средства электронной подписи, получившие подтверждение соответствия требованиям законодательства
Специфика работы¶
Работает утилита ЭЦП на основе КриптоПро, поэтому он должен быть установлен на одном компьютере:
- ставим крипто про
- ставим плагин
- для тестирования, выпускаем сертификат
Реализация¶
ЭЦП можно отнести к утилитам для приложения, так как основная ее реализация находится в приложении. Обычно реализация ЭЦП находиться в папке приложения lib/digest
(на примере приложения project-management):
lib/digest/digestData.js
- проверка при загрузке формы объекта на необходимость в электронной подписи (_applicable) и процесс подписи при выполнении перехода БП (_process)lib/digest/signSaver.js
- прикрепление подписи к объекту
Для того, чтобы статус ЭП запрашивался/отображался, для registry добавляем в deploy
настройку signedClasses.
Пример¶
"modules": {
"registry": {
"globals": {
"signedClasses": [
"class@application"
],
...
В БП workflows/indicatorValueBasic.wf.json
добавляем переход со свойством "signBefore": true
.
Пример¶
{
"name": "needAppTrs_sign",
"caption": "На утверждение",
"startState": "edit",
"finishState": "onapp",
"signBefore": true,
"signAfter": false,
"roles": [],
"assignments": [
{
"key": "state",
"value": "onapp"
}
],
"conditions": []
}
Виртуальные атрибуты¶
Описание¶
Виртуальные атрибуты - специальный тип атрибутов, указывается в property
наименование атрибута, начинающееся с __
. Функционал каждого виртуального атрибута различен, существуют следующие виртуальные атрибуты:
__class
- выводит полный код класса, в котором заведен атрибут__classTitle
- выводит наименование класса, в котором заведен атрибут
Утилиты¶
Описание¶
Утилиты - дополнительные программы для более специализированного применения.
Утилиты ядра¶
Утилиты ядра являются самыми необходимыми утилитами от установки до эксплуатации приложения и лежат в папке bin
. Перед их запуском необходимо указать переменную окружения NODE_PATH
, если она не задана заранее (с указанием на папку ядра).
В состав ядра входят утилиты:
bin/acl.js
- для импорта и редактирования настроек безопасности приложения (ресурсы, роли, пользователи, права доступа). Параметры запуска:--u
- указывается пользователь--res
- указывается ресурс--role
- указывается роль--p
- указывается доступ--m
- указывается метод применения доступа--d
- указывается для импорта директория с настройками безопасности
bin/adduser.js
- для добавления новых пользователей в настройки безопасности приложения. Параметры запуска:--name
- указывается логин пользователя (по умолчанию admin)--pwd
- указывается пароль пользователя (по умолчанию admin)
bin/bg.js
- для запуска фоновых процедур с низким приоритетом, требующих больших мощностей от процессора или выполняющихся относительно длительно по времениbin/export.js
- для экспорта приложения в локальную директорию. Параметры запуска:--dst
- путь к директории, в которую будет записан результат экспорта (по умолчанию ../out)--ns
- указывается неймспейс приложения--file-dir
- путь к директории, в которую будут экспортированы файлы из файловых атрибутов--acl
- дополнительно экспортировать настройки безопасности--nodata
- пропустить экспорт для всех созданных объектов в приложении--nofiles
- пропустить экспорт файловых атрибутов--ver
- версия (последняя версия -last)
bin/import.js
- для импорта метаданных приложения. Параметры запуска:--src
- путь к директории, из которой будет происходить импорт (по умолчанию ../in)--ns
- неймспейс приложения--ignoreIntegrityCheck
- при импорте игнорируется целостность данных
bin/import-data.js
- для импорта данных приложения. Параметры запуска:--src
- путь к директории, из которой будет происходить импорт (по умолчанию ../in)--ns
- неймспейс приложения
bin/job-runner.js
- для запуска задач по расписаниюbin/job.js
- для запуска рабочего компонента задания из утилиты job-runnerbin/meta-update.js
- для конвертации меты приложения из одной версии в другуюbin/schedule.js
- для ручного запуска задач по расписаниюbin/setup.js
- для установки настроекdeploy
из приложения. Параметры запуска:--reset
- предварительный сброс всех настроекdeploy
в приложении--sms
- при сбросе настроек, не зачищаются настройкиdeploy
помеченные как важные--rwa
- переопределять, а не дополнять массивы в настройкахdeploy
Утилиты приложения¶
Утилиты приложения реализуют специфичный функционал приложения на этапе эксплуатации, которое пока не реализовано в ядре в унифицированном виде для различных приложений. Как правило, данные утилиты находятся в директории lib
и подключаются к приложению через deploy
.
Примеры реализованных утилит для приложения sakh-pm
:
lib/actions/createIndicatorValueHandler.js
- утилита создания показателей в коллекции за выбранный периодlib/actions/createProjectReportsHandler.js
- утилита автоматического создания печатных форм по проекту с сохранением файлов в облакоlib/actions/assignmentToEventOnly.js
- утилита, формирующая из поручения контрольную точку
Создание утилиты для приложения на примере createIndicatorValueHandler¶
Реализация¶
Для реализации как правило используется язык JavaScript с использованием доступного функционала модулей, входящих в приложение.
При реализации утилит в приложении с относительно большим функционалом сами файлы могут быть разбиты на несколько зависимых файлов.
В приведенном примере в главном файле утилиты lib/actions/createPlanIndicatorsHandler.js
должен быть экспорт последней строкой:
module.exports = CreatePlanIndicatorsHandler;
Подключение к приложению¶
Для запуска утилиты при эксплуатации приложения нужно настроить параметры подключения в deploy
.
Для примера нужно сначала для утилиты добавить элемент интерфейса в представлении, который будет запускать утилиту. Для этого в файле views/indicatorFinancial/item.json
нужно добавить кнопку CREATE_INDICATOR_VALUE
:
{
"id": "CREATE_INDICATOR_VALUE",
"caption": "Сформировать собираемые значения",
"visibilityCondition": null,
"enableCondition": null,
"needSelectedItem": false,
"signBefore": false,
"signAfter": false,
"isBulk": false
}
Затем нужно добавить настройки в deploy
, чтобы связать кнопку в интерфейсе CREATE_INDICATOR_VALUE
и утилиту createIndicatorValueHandler
:
"modules": {
"registry": {
"globals": {
"di": {
"createIndicatorValueHandler": {
"module": "applications/sakh-pm/lib/actions/createIndicatorValueHandler",
"initMethod": "init",
"initLevel": 2,
"options": {
"data": "ion://securedDataRepo",
"workflows": "ion://workflows",
"log": "ion://sysLog",
"changelogFactory": "ion://changelogFactory",
"state": "onapp"
}
},
"actions": {
"options": {
"actions": [
{
"code": "CREATE_INDICATOR_VALUE",
"handler": "ion://createIndicatorValueHandler"
}
]
}
}
В примере все настройки хранятся для модуля registry, так как из него будет вызвана утилита при нажатии на кнопку CREATE_INDICATOR_VALUE
в форме объекта класса indicatorFinancial
.
Локализация¶
Локализация фреймворка, модулей и приложений организована по папкам i18n в соответствующих директориях.
Чтобы перевести строку для определенной локали, нужно добавить ее и ее перевод в:
<корень фреймворка, приложения или модуля>/i18n/<код локали>/index.js
в экспортируемый объект, например:
module.exports = {
'Контрольная панель': `Control panel`
};
Здесь строка „Контрольная панель“, при ее загрузке, будет переведена как „Control Panel“
Структура метаданных¶
Мета классов - общая часть¶
Признак абстрактности класса¶
Признак абстрактности класса - требуется в случае, когда необходимо по ссылке атрибута на базовый класс отображать список выбора его наследников. При формировании списка выбора классов для создания обьекта абстрактные классы не включены. Выставите true
в поле «abstract».
Пример¶
{
"name": "SomeClassName",
"abstract": true
}
Класс становится недоступным для инициализации на уровне UI.
Пример¶
{
"isStruct": false,
"key": [
"id"
],
"semantic": "value|[|plannedValue|](|dateStart|-|dateEnd|)",
"name": "indicatorValueBasic",
"version": "",
"caption": "Значения показателей на период",
"ancestor": null,
"container": null,
"creationTracker": "",
"changeTracker": "",
"history": 0,
"journaling": true,
"abstract": true,
"compositeIndexes": [
{
"properties": [
"indicatorBasic",
"dateStart",
"dateEnd"
],
"unique": true
}
],
"properties": [
...
Наследование¶
Наследование - позволяет создать новый класс на основе уже существующего (родительского), при этом атрибуты родительского класса заимствуются новым классом. Родительский класс может иметь несколько наследников с различным атрибутивным составом. Каждый наследник может включать в себя свой индивидуальный состав атрибутов + атрибуты родительского класса.
Атрибутивный состав¶
В мете родительского класса атрибутивный состав формируется таким образом, чтобы каждый из них можно было использовать для какого-либо из классов наследников. В то время как в мете класса наследника атрибутивный состав для каждого свой и применяется только на класс, в котором находится.
Родительский класс:
{
"isStruct": false,
"key": [
"id"
],
"semantic": "name",
"name": "organization",
"version": "",
"caption": "Организация",
"ancestor": null,
"container": null,
"creationTracker": "",
"changeTracker": "",
"history": 0,
"journaling": true,
"compositeIndexes": [],
"properties": [
Класс-наследник:
{
"isStruct": false,
"key": [
"id"
],
"semantic": "",
"name": "medicalOrg",
"version": "",
"caption": "Медицинская организация",
"ancestor": "organization",
"container": null,
"creationTracker": "",
"changeTracker": "",
"history": 0,
"journaling": true,
"compositeIndexes": [],
"properties": [
"id"
- является уникальным идентификатором для всех его наследников. Хранится в родительском классе.
"name"
- в классе есть атрибут «Наименование», который может отображаться в любом из наследников, или в одном из них. То есть, если атрибут "name"
задается в родительском классе, то он может отображаться в любом из наследников. Но если "name"
задается в классе наследнике, то отображается только в том классе, в котором он был задан.
Представление класса:¶
Если для родительского класса задан признак абстрактности, то представление для него задавать не обязательно.
Представления класса задается для каждого наследника по отдельности, с указанием необходимого атрибутивного состава (из класса, для которого создается + необходимые из родительского класса).
Настройка списка классов наследников для создания объектов по ссылке¶
Задается в мете класса для атрибута типа "Ссылка"
/"Коллекция"
после указания ссылочного класса/класса коллекции:
"itemsClass": "event",
"allowedSubclasses": [
"Subclasses1",
"Subclasses2"
],
itemsClass
- коллекция на базовый класс [event]
Subclasses1
- дочерний класс базого класса [event]
, который будет отображаться в списке, при создании объекта по ссылке (далее перечисляем все дочерние классы, которые нужно отображать в списке).
NB: Если данная настройка не задана - при создании, в списке отображаются все дочерние классы.
- Тип атрибута «Коллекция» или «Ссылка»;
- Для атрибута типа «Коллекция», «Ссылка» указан класс ссылки/коллекции на родительский (базовый) класс (при создании объекта ссылочного класса выводиться окно выбора нескольких классов);
- Помимо скрытия базового класса, при создании объекта не нужно отображать все дочерние классы в списке выбора классов для создания объекта по ссылке.
Родительский класс [Мероприятия] имеет несколько классов наследников ([Мероприятие1], [Мероприятие3], [Мероприятие2]). В классе [Проект] есть атрибут типа «Коллекция», который ссылается на родительский класс [Мероприятие] :
{
"namespace": "ns",
"isStruct": false,
"key": [],
"semantic": "",
"name": "project",
"version": "",
"caption": "Проект",
"ancestor": "",
"container": null,
"creationTracker": "",
"changeTracker": "",
"creatorTracker": "",
"editorTracker": "",
"history": 0,
"journaling": true,
"compositeIndexes": [],
"properties": [
{
"orderNumber": 80,
"name": "event",
"caption": "Мероприятия",
"type": 0,
"size": null,
"decimals": 0,
"allowedFileTypes": null,
"maxFileCount": 0,
"nullable": true,
"readonly": false,
"indexed": true,
"unique": false,
"autoassigned": false,
"hint": null,
"defaultValue": null,
"refClass": "",
"itemsClass": "event@ns",
"allowedSubclasses": [
"event1",
"event2"
],
"backRef": "",
"backColl": "",
"binding": "",
"semantic": null,
"selConditions": [],
"selSorting": [],
"selectionProvider": null,
"indexSearch": false,
"eagerLoading": false,
"formula": null
}
...
В случае, если для класса задана настройка абстрактности, то при создании объекта класса [Мероприятие] в коллекцию, в списке выбора отобразятся те наследники класса [event], которые указаны в свойстве "allowedSubclasses"
. То есть, исходя из примера, в коллекцию «Мероприятия» можно создать только объекты класса «Мероприятие1» и «Мероприятие2».
Многоуровневая иерархия¶
Дочерние классы могут унаследовать атрибутивный состав не только от своих прямых родительских классов, но и от тех, которые находятся выше по иерархии наследования.
[basicObj]
- родительский класс ->> [eventBasic]
- наследник класса [basicObj] ->> [eventBlock]
- наследник класса [eventBasic]
.
{
"isStruct": false,
"key": [
"guid"
],
"semantic": "name",
"name": "basicObj",
"abstract": true,
"version": "31",
"caption": "Учетный объект",
"ancestor": null,
"container": null,
"creationTracker": "createDatet",
"changeTracker": "modifeDate",
"creatorTracker": "creator",
"editorTracker": "editor",
"history": 0,
"journaling": true,
"compositeIndexes": null,
"properties": [
{
"isStruct": false,
"key": [
"guid"
],
"semantic": "name| ( |code| )",
"name": "eventBasic",
"version": "31",
"caption": "Базовое мероприятие",
"ancestor": "basicObj",
"container": null,
"creationTracker": "",
"changeTracker": "",
"history": 0,
"journaling": true,
"compositeIndexes": null,
"abstract": true,
"properties": [
{
"isStruct": false,
"key": [
"guid"
],
"semantic": "name| ( |code| )",
"name": "eventBlock",
"version": "31",
"caption": "Блок мероприятий",
"ancestor": "eventBasic",
"container": null,
"creationTracker": "",
"changeTracker": "",
"history": 0,
"journaling": true,
"compositeIndexes": null,
"properties": [
Наследник [eventBlock]
будет так же наследовать атрибутивный состав родительского класса [basicObj]
, как и наследник [eventBasic]
.
Индексация¶
Индексация - составные уникальные поля. Используется для поиска и контроля целостности данных.
В общей части меты классов есть поле "compositeIndexes"
, которое позволяет задать требование уникальности сочетания полей.
Описание¶
Cоставной индекс задается перечислением входящих в него атрибутов и указанием признака уникальности. Когда в классе присутсвует составной индекс, при сохранении объекта в базе проверяется отсутвие одинаковых сочетаний перечисленных полей. То есть значения полей "protocol"
и "family"
из примера ниже могут повторятся, но пара значений - всегда уникальна.
{
"isStruct": false,
"key": [
"id"
],
"semantic": "protocol|family",
"name": "refusal",
"version": "",
"caption": "Письменные отказы граждан",
"ancestor": null,
"container": null,
"creationTracker": "",
"changeTracker": "",
"history": 0,
"journaling": false,
"compositeIndexes": [
{
"properties": [
"protocol",
"family"
],
"unique": true
}
],
"properties": [
{
"orderNumber": 10,
"name": "id",
"caption": "Идентификатор",
"type": 0,
"size": 24,
"decimals": 0,
"allowedFileTypes": null,
"maxFileCount": 0,
"nullable": false,
"readonly": true,
"indexed": false,
"unique": true,
"autoassigned": true,
"hint": null,
"defaultValue": null,
"refClass": "",
"itemsClass": "",
"backRef": "",
"backColl": "",
"binding": "",
"semantic": null,
"selConditions": [],
"selSorting": [],
"selectionProvider": null,
"indexSearch": false,
"eagerLoading": false,
"formula": null
},
{
"orderNumber": 20,
"name": "protocol",
"caption": "Протокол заседания комиссии",
"type": 0,
"size": null,
"decimals": 0,
"allowedFileTypes": null,
"maxFileCount": 0,
"nullable": true,
"readonly": false,
"indexed": false,
"unique": false,
"autoassigned": false,
"hint": null,
"defaultValue": null,
"refClass": "",
"itemsClass": "",
"backRef": "",
"backColl": "",
"binding": "",
"selConditions": [],
"selSorting": [],
"selectionProvider": null,
"indexSearch": false,
"eagerLoading": false,
"formula": null
},
{
"orderNumber": 31,
"name": "family",
"caption": "Семья, поставленная на учет",
"type": 13,
"size": null,
"decimals": 0,
"allowedFileTypes": null,
"maxFileCount": 0,
"nullable": true,
"readonly": false,
"indexed": false,
"unique": false,
"autoassigned": false,
"hint": null,
"defaultValue": null,
"refClass": "family",
"itemsClass": "",
"backRef": "",
"backColl": "",
"binding": "",
"selConditions": [],
"selSorting": [],
"selectionProvider": null,
"indexSearch": false,
"eagerLoading": false,
"formula": null
}
]
}
Журналирование¶
Журналирование - указывает на необходимость журналирования всех действий произведенных над объектом. Находится в поле journaling
основной части меты класса. Значение true
указывает на необходимость журналирования. Если в поле указано значение false
или отсутсвует, то журналирование изменений объекта не требуется.
Пример:¶
{
"isStruct": false,
"key": "okato",
"semantic": "name",
"name": "naselenniyPunkt",
"caption": "Населенный пункт",
"journaling": true,
"ancestor": null,
"container": "",
"creationTracker": "",
"changeTracker": "",
"properties": []
}
Ключевые поля¶
В каждом классе обязательно должен быть задан ключевой атрибут (поле "key"
основной части меты класса). Без этого приложение не будет функционировать.
Типы ключевых полей¶
- Guid - «Глобальный идентификатор [12]».
- «Строка [0]».
- «Целое [6]».
Требования к ключевому атрибуту¶
При формировании меты ключевого атрибута, поля "unique"
и "autoassigned"
выставляются в true
. Необходимо запретить пустое значение, выставляя "nullable"
в false
.
Если атрибут не генерируется автоматически, то "autoassigned"
можно поставить в false
, тогда поле должно быть задано оператором при создании. Например, если это код классификатора или регистрационный номер задаваемый внешним способом (на бумаге).
Версионирование¶
Версионирование - позволяет хранить в системе сразу несколько версий метаданных. В каждый объект при изменении и сохранении проставляется его версия. Таким образом, версионирование предоставляет возможность работы с различными версиями одних объектов.
Версионирование задается в поле "version"
основной части меты классов. Чтобы изменить версию меты, необходимо добавить атрибут version
(«version» : 2).
Механизм работы¶
При загрузке метаданных, если есть атрибут version («version» : 2) - будет закачена мета с версией, иначе версия = 1.
{
"isStruct": false,
"key": "id",
"semantic": "caption",
"name": "ion_filter",
"caption": "Фильтры",
"ancestor": null,
"container": null,
"creationTracker": "",
"changeTracker": "",
"version" : 2
}
При создании объектов к ним будет добавляться последняя версия метаданных из текущих в базе, а при редактировании объектов они будут редактироваться на основании сохраненной версии.
Пример сохраненных объектов с разными версиями в базе:
{
"_id" : ObjectId("567cfa1eb869fc2833690ea4"),
"id" : 24006,
"class" : "ALL",
"caption" : "11",
"html" : "",
"filter" : "[\"{\\\"property\\\":\\\"contact\\\",\\\"operation\\\":20,\\\"value\\\":\\\"11\\\",\\\"title\\\":\\\"Контактная информация содержит 11\\\",\\\"type\\\":7}\"]",
"period" : "2015-12-08,2016-02-05",
"version" : 1,
"semanticTitle" : "11 "
}
{
"_id" : ObjectId("56944e5cb73f51ec182c7369"),
"class" : "ALL",
"caption" : "fffffff",
"filter" : "[\"{\\\"property\\\":\\\"class\\\",\\\"operation\\\":0,\\\"value\\\":\\\"fff\\\",\\\"title\\\":\\\"Класс фильтра равно fff\\\",\\\"type\\\":1}\"]",
"version" : 2,
"id" : NaN,
"semanticTitle" : "fffffff "
}
Работа в коде¶
При считывании меты классов, данные разделяются по версиям. Имена версионированных классов имеют имена следующего вида “<имякласса><номер версии>”. Например, ion_filter_1, ion_filter_2 – Класс ion_filter версии 1 и 2 соответственно.
При выборке объектов, данные берутся с учётом версии. Версия объекта передаётся в виде параметра version
запроса на открытие объекта.
Семантика¶
Семантика - используется для вывода объекта класса в качестве одной строки заголовка класса.
В мете классов поле "semantic"
встречается дважды:
- в общей части меты класса, где формирует строковое представление для данного класса,
- в мете атрибута класса, где формирует строковое представление объектов класса, на который ссылается атрибут, т.е. используется для ссылочных атрибутов.
Цель использования¶
Используется для корректировки отображения атрибутов и значений атрибутов в списке. В атрибутах, которые выводят табличные данные, семантика используется для ограничения вывода колонок.
Примеры использования в ссылочных атрибутах¶
Например, есть класс class
, у которого есть атрибуты: id
, name
, link
, date
. Есть второй класс classTable
, у которого есть ссылочный атрибут table
на класс class
.
Без использования семантики в объектах класса classTable
в атрибуте table
будут выводится значения идентификаторов объектов класса class
.
Атрибуты, используемые как идентификаторы, указаны в мете класса class
.
Чтобы вывести значения атрибутов name
и link
в атрибуте table
, а не значения идентификаторов, нужно прописать "semantic": "name|link"
. В зависимости от типа атрибута результат будет разный:
- Если атрибут
table
является ссылкой, то в нем будут заполнены значения атрибутовname
иlink
через пробел. Тут можно использовать дополнительные слова и выражения через знак|
, например"semantic": "name|, |link"
или"semantic": "У объекта есть 2 атрибута:|name|, |link"
. - Если атрибут
table
является коллекцией объектов классаclass
, то в нем будут выведеные колонкиname
иlink
.
Формат отображения в семантике¶
Можно обрезать вывод с помощью:
[]
."name[0,50]|..." Указываем позицию и количество выводимых букв из семантики атрибута. Из атрибута name выводим 50 символов семантики (значение атрибута), начиная с первого.
Доступно разыменование через
.
т.е. доступ во вложенный объект."semantic": "digitalTV|kachestvoCTB|analogTV.name|kachestvoAnal|period" где ``analogTV`` - ссылочный атрибут класса, для которого задается семантика, а ``name`` - атрибут класса по ссылке.
Отображение семантики на форме¶
- В списках первого уровня (открываемые непосредственно по узлу навигации), в качестве заголовка выводим только значение из поля «caption» узла навигации.
- В списках выбора в заголовок выводим только значение из поля «caption» класса объектов списка.
- В форме редактирования в заголовок выводим только семантику объекта.
- В форме создания в заголовок выводим только значение из поля «caption» класса.
- В списках выбора над заголовком мелким шрифтом выводим строку «Выбор значения атрибута <…> объекта <…>».
- В форме создания, если создается объект в коллекции или ссылке, над заголовком мелким шрифтом выводим строку «Создание объекта в коллекции/по ссылке <…> объекта <…>».
Метки времени создания и изменения¶
Речь идет о следующих полях общей части меты классов:
"creationTracker"
- Метка времени создания: позволяет сохранять в классе дату/время создания объекта, требует наличия соответствующего атрибута класса,"name"
которого и вносится в данное поле."changeTracker"
- Метка времени изменения: позволяет сохранять в классе дату/время изменения объекта, требует наличия соответствующего атрибута класса,"name"
которого и вносится в данное поле.
Пример¶
{
"isStruct": false,
"key": "id",
"semantic": "rtrs",
"name": "digitTv",
"caption": "Цифровое ТВ",
"ancestor": null,
"container": null,
"creationTracker": "createDate",
"changeTracker": "modifeDate",
"properties": [
{
"orderNumber": 60,
"name": "createDate",
"caption": "Метка времени создания",
"type": 9,
"size": null,
"decimals": 0,
"nullable": false,
"readonly": false,
"indexed": false,
"unique": true,
"autoassigned": true,
"defaultValue": null,
"refClass": "",
"itemsClass": "",
"backRef": "",
"backColl": "",
"binding": "",
"selConditions": [],
"selSorting": [],
"selection_provider": null,
"indexSearch": false,
"eagerLoading": false
},
{
"orderNumber": 70,
"name": "modifeDate",
"caption": "Метка времени изменения",
"type": 9,
"size": null,
"decimals": 0,
"nullable": true,
"readonly": false,
"indexed": false,
"unique": false,
"autoassigned": false,
"defaultValue": null,
"refClass": "",
"itemsClass": "",
"backRef": "",
"backColl": "",
"binding": "",
"selConditions": [],
"selSorting": [],
"selection_provider": null,
"indexSearch": false,
"eagerLoading": false
}
]
}
Метки пользователя создавшего и измененившего объект¶
"creatorTracker"
- Метка пользователя создавшего: позволяет сохранять в классе имя пользователя, создавшего объект, требует наличия соответствующего атрибута класса,"name"
которого и вносится в данное поле."editorTracker"
- Метка пользователя изменившего: позволяет сохранять в классе имя пользователя, изменившего объект, требует наличия соответствующего атрибута класса,"name"
которого и вносится в данное поле.
{
"isStruct": false,
"key": [
"guid"
],
"semantic": "name",
"name": "basicObj",
"abstract": true,
"version": "31",
"caption": "Учетный объект",
"ancestor": null,
"cacheDependencies": [
"basicObj"
],
"container": null,
"creatorTracker": "creator",
"editorTracker": "editor",
"history": 0,
"journaling": true,
"compositeIndexes": null,
"properties": [
...
{
"orderNumber": 20,
"name": "creator",
"caption": "Метка пользователя, создавшего объект",
"type": 18,
"size": null,
"decimals": 0,
"allowedFileTypes": null,
"maxFileCount": 0,
"nullable": true,
"readonly": false,
"indexed": false,
"unique": false,
"autoassigned": true,
"hint": "",
"defaultValue": null,
"refClass": "",
"itemsClass": "",
"backRef": "",
"backColl": "",
"binding": "",
"semantic": null,
"selConditions": [],
"selSorting": [],
"selectionProvider": null,
"indexSearch": false,
"eagerLoading": false,
"formula": null
},
{
"orderNumber": 30,
"name": "editor",
"caption": "Метка пользователя, изменившего объект",
"type": 18,
"size": null,
"decimals": 0,
"allowedFileTypes": null,
"maxFileCount": 0,
"nullable": true,
"readonly": false,
"indexed": false,
"unique": false,
"autoassigned": true,
"hint": "",
"defaultValue": null,
"refClass": "",
"itemsClass": "",
"backRef": "",
"backColl": "",
"binding": "",
"semantic": null,
"selConditions": [],
"selSorting": [],
"selectionProvider": null,
"indexSearch": false,
"eagerLoading": false,
"formula": null
}
],
"metaVersion": "2.0.61"
}
Тип Структура [16]¶
Структура - способ отображения связанных объектов (ссылок). Если у поля указано структура, то данный тип атрибута нужен для уменьшения действий при заведении модели, при заранее известных типовых классах, атрибуты которых используются во многих других классах.
Для класса-структуры в основной части меты класса задается значение true
в поле "isStruct"
.
Для атрибутов типа «Структура [16]» в мете представлений создания и изменения используется тип «Группа [0]». Если не указывать поля у группы, они создаются автоматически по мете. В представлениях списка нет необходимости делать колонки для атрибутов-структур, в объекте не будет такого свойства, а будут соответствующие атрибуты класса-структуры. Для них можно добавить колонки.
NB: Объекты класса-структуры не создаются!
Пример¶
Класс-структура:
{
"isStruct": true,
"key": [
"id"
],
"semantic": "",
"name": "is_struct",
"version": "",
"caption": "\"isStruct\" класс-структура",
"ancestor": null,
"container": null,
"creationTracker": "",
"changeTracker": "",
"history": 0,
"journaling": false,
"compositeIndexes": null,
"properties": [
{
"orderNumber": 10,
"name": "id",
"caption": "Идентификатор",
"type": 12,
"size": null,
"decimals": 0,
"allowedFileTypes": null,
"maxFileCount": 0,
"nullable": false,
"readonly": false,
"indexed": false,
"unique": true,
"autoassigned": true,
"hint": null,
"defaultValue": null,
"refClass": "",
"itemsClass": "",
"backRef": "",
"backColl": "",
"binding": "",
"semantic": null,
"selConditions": [],
"selSorting": [],
"selectionProvider": null,
"indexSearch": false,
"eagerLoading": false,
"formula": null
},
{
"orderNumber": 20,
"name": "last_name",
"caption": "Фамилия",
"type": 0,
"size": null,
"decimals": 0,
"allowedFileTypes": null,
"maxFileCount": 0,
"nullable": true,
"readonly": false,
"indexed": false,
"unique": false,
"autoassigned": false,
"hint": null,
"defaultValue": null,
"refClass": "",
"itemsClass": "",
"backRef": "",
"backColl": "",
"binding": "",
"semantic": null,
"selConditions": [],
"selSorting": [],
"selectionProvider": null,
"indexSearch": false,
"eagerLoading": false,
"formula": null
},
{
"orderNumber": 30,
"name": "first_name",
"caption": "Имя",
"type": 0,
"size": null,
"decimals": 0,
"allowedFileTypes": null,
"maxFileCount": 0,
"nullable": true,
"readonly": false,
"indexed": false,
"unique": false,
"autoassigned": false,
"hint": null,
"defaultValue": null,
"refClass": "",
"itemsClass": "",
"backRef": "",
"backColl": "",
"binding": "",
"semantic": null,
"selConditions": [],
"selSorting": [],
"selectionProvider": null,
"indexSearch": false,
"eagerLoading": false,
"formula": null
},
{
"orderNumber": 40,
"name": "patronymic",
"caption": "Отчество",
"type": 0,
"size": null,
"decimals": 0,
"allowedFileTypes": null,
"maxFileCount": 0,
"nullable": true,
"readonly": false,
"indexed": false,
"unique": false,
"autoassigned": false,
"hint": null,
"defaultValue": null,
"refClass": "",
"itemsClass": "",
"backRef": "",
"backColl": "",
"binding": "",
"semantic": null,
"selConditions": [],
"selSorting": [],
"selectionProvider": null,
"indexSearch": false,
"eagerLoading": false,
"formula": null
},
{
"orderNumber": 50,
"name": "date",
"caption": "Дата рождения",
"type": 9,
"size": null,
"decimals": 0,
"allowedFileTypes": null,
"maxFileCount": 0,
"nullable": true,
"readonly": false,
"indexed": false,
"unique": false,
"autoassigned": false,
"hint": null,
"defaultValue": null,
"refClass": "",
"itemsClass": "",
"backRef": "",
"backColl": "",
"binding": "",
"semantic": null,
"selConditions": [],
"selSorting": [],
"selectionProvider": null,
"indexSearch": false,
"eagerLoading": false,
"formula": null
}
]
}
Класс с атрибутом типа «Структура [16]»:
{
"isStruct": false,
"key": [
"id"
],
"semantic": "",
"name": "struct",
"version": "",
"caption": "Класс \"Структура [16]\" (класс с типом атрибута 16 - структура)",
"ancestor": null,
"container": null,
"creationTracker": "",
"changeTracker": "",
"history": 0,
"journaling": false,
"compositeIndexes": null,
"properties": [
{
"orderNumber": 10,
"name": "id",
"caption": "Идентификатор",
"type": 12,
"size": null,
"decimals": 0,
"allowedFileTypes": null,
"maxFileCount": 0,
"nullable": false,
"readonly": false,
"indexed": false,
"unique": true,
"autoassigned": true,
"hint": null,
"defaultValue": null,
"refClass": "",
"itemsClass": "",
"backRef": "",
"backColl": "",
"binding": "",
"semantic": null,
"selConditions": [],
"selSorting": [],
"selectionProvider": null,
"indexSearch": false,
"eagerLoading": false,
"formula": null
},
{
"orderNumber": 20,
"name": "struct",
"caption": "Класс \"Структура [16]\"",
"type": 16,
"size": null,
"decimals": 0,
"allowedFileTypes": null,
"maxFileCount": 0,
"nullable": true,
"readonly": false,
"indexed": false,
"unique": false,
"autoassigned": false,
"hint": null,
"defaultValue": null,
"refClass": "is_struct",
"itemsClass": "",
"backRef": "",
"backColl": "",
"binding": "",
"semantic": null,
"selConditions": [],
"selSorting": [],
"selectionProvider": null,
"indexSearch": false,
"eagerLoading": false,
"formula": null
}
]
}
Объект класса с атрибутом-структурой в базе:
{
"_id" : ObjectId("57c3e46fd53ecd50123cc4f5"),
"struct$id" : "5f421610-6dba-11e6-874f-1b746e204b07",
"struct$last_name" : "Мирошниченко",
"struct$first_name" : "Ирина",
"struct$patronymic" : "Львовна",
"struct$date" : ISODate("1978-07-13T14:00:00.000Z"),
"id" : "5f41ef00-6dba-11e6-874f-1b746e204b07",
"_class" : "struct@develop-and-test",
"_classVer" : ""
}
Тип Структура¶
Структура - способ отображения связанных объектов (ссылок). Если у поля указано структура, то данный тип атрибута нужен для уменьшения действий при заведении модели, при заранее известных типовых классах, атрибуты которых используются во многих других классах.
Для класса-структуры в основной части меты класса задается значение true
в поле "isStruct"
.
Для атрибутов типа «Структура [16]» в мете представлений создания и изменения используется тип «Группа [0]». Если не указывать поля у группы, они создаются автоматически по мете. В представлениях списка нет необходимости делать колонки для атрибутов-структур, в объекте не будет такого свойства, а будут соответствующие атрибуты класса-структуры. Для них можно добавить колонки.
NB: Объекты класса-структуры не создаются!
Пример¶
Класс-структура:
{
"isStruct": true,
"key": [
"id"
],
"semantic": "",
"name": "is_struct",
"version": "",
"caption": "\"isStruct\" класс-структура",
"ancestor": null,
"container": null,
"creationTracker": "",
"changeTracker": "",
"history": 0,
"journaling": false,
"compositeIndexes": null,
"properties": [
{
"orderNumber": 10,
"name": "id",
"caption": "Идентификатор",
"type": 12,
"size": null,
"decimals": 0,
"allowedFileTypes": null,
"maxFileCount": 0,
"nullable": false,
"readonly": false,
"indexed": false,
"unique": true,
"autoassigned": true,
"hint": null,
"defaultValue": null,
"refClass": "",
"itemsClass": "",
"backRef": "",
"backColl": "",
"binding": "",
"semantic": null,
"selConditions": [],
"selSorting": [],
"selectionProvider": null,
"indexSearch": false,
"eagerLoading": false,
"formula": null
},
{
"orderNumber": 20,
"name": "last_name",
"caption": "Фамилия",
"type": 0,
"size": null,
"decimals": 0,
"allowedFileTypes": null,
"maxFileCount": 0,
"nullable": true,
"readonly": false,
"indexed": false,
"unique": false,
"autoassigned": false,
"hint": null,
"defaultValue": null,
"refClass": "",
"itemsClass": "",
"backRef": "",
"backColl": "",
"binding": "",
"semantic": null,
"selConditions": [],
"selSorting": [],
"selectionProvider": null,
"indexSearch": false,
"eagerLoading": false,
"formula": null
},
{
"orderNumber": 30,
"name": "first_name",
"caption": "Имя",
"type": 0,
"size": null,
"decimals": 0,
"allowedFileTypes": null,
"maxFileCount": 0,
"nullable": true,
"readonly": false,
"indexed": false,
"unique": false,
"autoassigned": false,
"hint": null,
"defaultValue": null,
"refClass": "",
"itemsClass": "",
"backRef": "",
"backColl": "",
"binding": "",
"semantic": null,
"selConditions": [],
"selSorting": [],
"selectionProvider": null,
"indexSearch": false,
"eagerLoading": false,
"formula": null
},
{
"orderNumber": 40,
"name": "patronymic",
"caption": "Отчество",
"type": 0,
"size": null,
"decimals": 0,
"allowedFileTypes": null,
"maxFileCount": 0,
"nullable": true,
"readonly": false,
"indexed": false,
"unique": false,
"autoassigned": false,
"hint": null,
"defaultValue": null,
"refClass": "",
"itemsClass": "",
"backRef": "",
"backColl": "",
"binding": "",
"semantic": null,
"selConditions": [],
"selSorting": [],
"selectionProvider": null,
"indexSearch": false,
"eagerLoading": false,
"formula": null
},
{
"orderNumber": 50,
"name": "date",
"caption": "Дата рождения",
"type": 9,
"size": null,
"decimals": 0,
"allowedFileTypes": null,
"maxFileCount": 0,
"nullable": true,
"readonly": false,
"indexed": false,
"unique": false,
"autoassigned": false,
"hint": null,
"defaultValue": null,
"refClass": "",
"itemsClass": "",
"backRef": "",
"backColl": "",
"binding": "",
"semantic": null,
"selConditions": [],
"selSorting": [],
"selectionProvider": null,
"indexSearch": false,
"eagerLoading": false,
"formula": null
}
]
}
Класс с атрибутом типа «Структура [16]»
{
"isStruct": false,
"key": [
"id"
],
"semantic": "",
"name": "struct",
"version": "",
"caption": "Класс \"Структура [16]\" (класс с типом атрибута 16 - структура)",
"ancestor": null,
"container": null,
"creationTracker": "",
"changeTracker": "",
"history": 0,
"journaling": false,
"compositeIndexes": null,
"properties": [
{
"orderNumber": 10,
"name": "id",
"caption": "Идентификатор",
"type": 12,
"size": null,
"decimals": 0,
"allowedFileTypes": null,
"maxFileCount": 0,
"nullable": false,
"readonly": false,
"indexed": false,
"unique": true,
"autoassigned": true,
"hint": null,
"defaultValue": null,
"refClass": "",
"itemsClass": "",
"backRef": "",
"backColl": "",
"binding": "",
"semantic": null,
"selConditions": [],
"selSorting": [],
"selectionProvider": null,
"indexSearch": false,
"eagerLoading": false,
"formula": null
},
{
"orderNumber": 20,
"name": "struct",
"caption": "Класс \"Структура [16]\"",
"type": 16,
"size": null,
"decimals": 0,
"allowedFileTypes": null,
"maxFileCount": 0,
"nullable": true,
"readonly": false,
"indexed": false,
"unique": false,
"autoassigned": false,
"hint": null,
"defaultValue": null,
"refClass": "is_struct",
"itemsClass": "",
"backRef": "",
"backColl": "",
"binding": "",
"semantic": null,
"selConditions": [],
"selSorting": [],
"selectionProvider": null,
"indexSearch": false,
"eagerLoading": false,
"formula": null
}
]
}
Объект класса с атрибутом-структурой в базе:
{
"_id" : ObjectId("57c3e46fd53ecd50123cc4f5"),
"struct$id" : "5f421610-6dba-11e6-874f-1b746e204b07",
"struct$last_name" : "Мирошниченко",
"struct$first_name" : "Ирина",
"struct$patronymic" : "Львовна",
"struct$date" : ISODate("1978-07-13T14:00:00.000Z"),
"id" : "5f41ef00-6dba-11e6-874f-1b746e204b07",
"_class" : "struct@develop-and-test",
"_classVer" : ""
}
Общая часть меты классов - содержит поля параметров класса, которые имеют отношения к самой структуре и способам оперирования данными в ней.
JSON¶
{
"isStruct": false,
"key": [
"id"
],
"semantic": "",
"name": "class_integer",
"abstract": true,
"version": "",
"caption": "Класс \"Целое [6]\"",
"ancestor": null,
"container": null,
"creationTracker": "",
"changeTracker": "",
"creatorTracker": "",
"editorTracker": "",
"history": 0,
"journaling": false,
"compositeIndexes": null,
"properties": [...]
}
Описание полей¶
Код | Имя | Допустимые значения | Описание |
---|---|---|---|
"isStruct" |
Является структурой | Логическое. | Если выставлено «true» - это говорит о том, что данный класс является структурой, и может быть использован в прочих классах в атрибутах особого типа - Структура [16] |
"key" |
Ключевые атрибуты | Массив строк, минимум одно значение. | Для функционирования приложения, в каждом классе должно быть задано ключевое поле, однозначно идентифицирующее объект в коллекции. |
"semantic" |
Семантический атрибут | Строка. | Задает семантику - правило формирования строкового представления для данного класса. |
"name" |
Системное имя | Строка, только латиница, без пробелов. | Задает в том числе первую часть имени файла меты класса, служебное имя. |
"abstract" |
Признак абстрактности для класса | Логическое | Используется только для родительских (базовых) классов. |
"version" |
Версионирование | Строка. | Позволяет задавать версионирвоание меты, для возможности оперирования данными созданными в разных версиях меты в рамках одной коллекции. |
"caption" |
Логическое имя | Строка. | Отображаемое в пользовательском интерфейсе имя класса |
"ancestor" |
Наследование | Null либо строка. | Набор атрибутов, заведенных в данном классе, наследуется классами-наследниками. Является способом сократить количество сущностей, когда для них можно использовать одинаковый набор атрибутов. Все классы-наследники будут наследовать атрибутивный состав родителя + можно завести атрибуты, принадлежащие индивидуально данному классу-наследнику (при необходимости). |
"container" |
Атрибут ссылки на контейнер | Null либо строка. | Здесь можно выбрать ссылочный атрибут, который будет использован для автоматического построения иерархической навигации. Объект, на который будет ссылаться выбранный атрибут, будет восприниматься средой как контейнер экземпляра доменного класса, и автоматически выстроит иерархию объектов. |
"creationTracker" |
Метка времени создания | Строка | Позволяет сохранять в классе дату/время создания объекта, требует наличия соответствующего атрибута класса, "name" которого и вносится в данное поле. |
"changeTracker" |
Метка времени изменения | Строка | Позволяет сохранять в классе дату/время изменения объекта, требует наличия соответствующего атрибута класса, "name" которого и вносится в данное поле. |
"creatorTracker" |
Метка пользователя создавшего объект | Строка | Позволяет сохранять в классе имя пользователя создавшего объект, требует наличия соответствующего атрибута класса, "name" которого и вносится в данное поле. |
"editorTracker" |
Метка пользователя изменившего объект | Строка | Позволяет сохранять в классе имя пользователя, изменившего объект, требует наличия соответствующего атрибута класса, "name" которого и вносится в данное поле. |
"history" |
Снимки данных | 0 - нет | Хранит снимки данных |
1 - произвольно | |||
2 - с точностью до часа | |||
3 - с точностью до суток | |||
4 - с точностью до недели | |||
5 - с точностью до месяца | |||
6 - с точностью до года | |||
"journaling" |
Журналирование изменений | Логическое. | Разрешает/запрещает журналирование изменений объектов класса. |
"compositeIndexes" |
Индексация | Null либо массив объектов. | Позволяет задать требования уникальности сочетания полей. |
"properties" |
Атрибуты | Массив объектов. | Массив атрибутов сущности. Каждый объект описывается в соответствии с атрибутивной частью меты классов. |
Мета классов - атрибутивная часть¶
Типы атрибутов¶
Коллекция¶
Коллекция - тип данных, позволяющий выводить в объекте списки других объектов. Данные объекты могут быть объектами любого класса включая исходный.
с точки зрения используемых полей атрибутивной части меты классов
один-ко-многим
- означает наличие контейнера и вложенного объекта с ссылкой на контейнер. В контейнере необходимо указать коллекцию, а у нее указать ссылочный атрибут вложенного объекта по которому формируется связь. См. Обратные ссылки в контексте коллекций.многие-ко-многим
- необходимо определить коллекцию без ссылок и указать класс вложенных элементов - связи создаются при помещении в коллекцию и хранятся как отдельные сущности в БД. См. Коллекции.обратная коллекция
- если коллекция многие ко многим задается на основании коллекции в другом объекте, то другая сторона связи задается через backColl. См. Обратные коллекции.
См. полное описание типа Коллекция
в атрибутивной части меты класса - Атрибут коллекции и обратной коллекции.
Тип атрибута дата/время¶
Тип атрибута дата/время - представляет собой дату в формате ISODate. Может быть отображена либо как дата, либо как дата-время.
Режимы хранения даты задаются в параметре mode
атрибутивной части меты класса.
Доступно 3 режима хранения даты - реальный, локализованный, универсальный:
- 0 - Реальный (по умолчанию). Дата хранится без информации о часовом поясе. При отображении приводится к часовому поясу пользователя. Т.е. 01.01.2017 заданное на Камчатке в Хабаровске отобразится как 31.12.2016.
- 1 - Локализованный. Дата хранится вместе с часовым поясом, в котором была задана. При отображении приводится к этому часовому поясу. Т.е. 01.01.2017 заданное на Камчатке, в Хабаровске отобразиться так же - 01.01.2017. Но правильно его отображать с указанием часового пояса, т.е. 01.01.2017 (+11). При редактировании часовой пояс обновляется часовым поясом новой даты. При этом в БД хранится РЕАЛЬНЫЙ момент времени, что нужно учитывать в условиях выборки задаваемых хардкодом в мете.
- 2 - Универсальный. Дата сохраняется как если бы она задавалась в UTC. Т.е. не приводится к UTC, а сохраняется в UTC так же, как была введена. Т.е. если мы в Хабаровске ввели 01.01.2017 по Хабаровску, то сохранится она как «01.01.2017 00:00 UTC», а не как «31.12.2016 14:00 UTC». Отображается в любом часовом поясе так же, как была введена. Использовать для дат в реквизитах (дата рождения, дата выдачи документа и т.д.), т.е. когда важен не реальный, а формальный момент времени. Либо, когда не нужно учитывать время вообще.
{
"isStruct": false,
"metaVersion": "2.0.7",
"key": [
"id"
],
"semantic": "",
"name": "class_datetime",
"version": "",
"caption": "Класс \"Дата/Время [9]\"",
"ancestor": null,
"container": null,
"creationTracker": "",
"changeTracker": "",
"history": 0,
"journaling": false,
"compositeIndexes": null,
"properties": [
{
"orderNumber": 10,
"name": "id",
"caption": "Идентификатор",
"type": 12,
"size": 24,
"decimals": 0,
"allowedFileTypes": null,
"maxFileCount": 0,
"nullable": false,
"readonly": false,
"indexed": false,
"unique": true,
"autoassigned": true,
"hint": null,
"defaultValue": null,
"refClass": "",
"itemsClass": "",
"backRef": "",
"backColl": "",
"binding": "",
"semantic": null,
"selConditions": [],
"selSorting": [],
"selectionProvider": null,
"indexSearch": false,
"eagerLoading": false,
"formula": null
},
{
"orderNumber": 20,
"name": "data_data",
"caption": "Выбор даты [120]",
"type": 9,
"size": null,
"decimals": 0,
"allowedFileTypes": null,
"maxFileCount": 0,
"nullable": true,
"readonly": false,
"indexed": false,
"unique": false,
"autoassigned": false,
"hint": null,
"defaultValue": null,
"refClass": "",
"itemsClass": "",
"backRef": "",
"backColl": "",
"binding": "",
"semantic": null,
"selConditions": [],
"selSorting": [],
"selectionProvider": null,
"indexSearch": false,
"eagerLoading": false,
"formula": null
},
{
"orderNumber": 30,
"name": "data_datatime",
"caption": "Реальная дата",
"type": 9,
"mode": 0,
"size": null,
"decimals": 0,
"allowedFileTypes": null,
"maxFileCount": 0,
"nullable": true,
"readonly": false,
"indexed": false,
"unique": false,
"autoassigned": false,
"hint": null,
"defaultValue": null,
"refClass": "",
"itemsClass": "",
"backRef": "",
"backColl": "",
"binding": "",
"semantic": null,
"selConditions": [],
"selSorting": [],
"selectionProvider": null,
"indexSearch": false,
"eagerLoading": false,
"formula": null
},
{
"orderNumber": 30,
"name": "data_datatime1",
"caption": "Дата с часовым поясом",
"type": 9,
"mode": 1,
"size": null,
"decimals": 0,
"allowedFileTypes": null,
"maxFileCount": 0,
"nullable": true,
"readonly": false,
"indexed": false,
"unique": false,
"autoassigned": false,
"hint": null,
"defaultValue": null,
"refClass": "",
"itemsClass": "",
"backRef": "",
"backColl": "",
"binding": "",
"semantic": null,
"selConditions": [],
"selSorting": [],
"selectionProvider": null,
"indexSearch": false,
"eagerLoading": false,
"formula": null
},
{
"orderNumber": 30,
"name": "data_datatime2",
"caption": "Универсальная дата",
"type": 9,
"mode": 2,
"size": null,
"decimals": 0,
"allowedFileTypes": null,
"maxFileCount": 0,
"nullable": true,
"readonly": false,
"indexed": false,
"unique": false,
"autoassigned": false,
"hint": null,
"defaultValue": null,
"refClass": "",
"itemsClass": "",
"backRef": "",
"backColl": "",
"binding": "",
"semantic": null,
"selConditions": [],
"selSorting": [],
"selectionProvider": null,
"indexSearch": false,
"eagerLoading": false,
"formula": null
}
]
}
Геоданные¶
Тип атрибута геокоординаты - является атрибутом, который хранит координаты с уникальными представлениями для создания и редактирования. Значение свойства «type» для атрибута, имеющего тип геокоординаты равно 100.
Если атрибут имеет тип геокоординаты и на форме создания/редактирования объекта атрибут заполнен (координаты заданы), то отображается поле карты с координатами и кнопка «Изменить». Если атрибут не заполнен – то отображается только кнопка «Задать координаты». Доступно только в студии
Если задано свойство "autoassigned": true
и не заданы данные при создании формы - то нужно определять координаты автоматически по данным адреса из атрибутов указанных в свойствах геометки.
Для отображения атрибута с типом геокоординаты используется тип представления геообъект. Геообъект может быть отображён на форме в одном из трёх режимов:
- Карта (0) - геообъект отображается на карте;
- Поиск по адресу (1) - геообъект отображается на карте, на которой по адресу можно найти место и переместить туда геообъект. Или же можно просто задать координаты геообъекта;
- Холст (2) - геообъект отображается на карте, можно задать интерактивное отображение геообъекта на карте.
Режим отображения задаётся указанием соответствующей цифры в поле "mode"
в мете представлений класса:
«mode»: 0, – Режим отображения Карта
«mode»: 1, – Режим отображения поиск по адресу
«mode»: 2, – Режим отображения Холст
Данные атрибута с типом геокоординаты сохраняются в БД в виде строки со значениями через запятую, строки в формате JSON-массива или строки в формате JSON-объекта.
В логическом имени атрибута (caption
) указан режим отображения (mode
) для разделения атрибутов с одинаковым типом.
{
"orderNumber": 20,
"name": "class_geodata",
"caption": "Геоданные [100] mode [0] - Карта",
"type": 100,
"size": null,
"decimals": 0,
"allowedFileTypes": null,
"maxFileCount": 0,
"nullable": true,
"readonly": false,
"indexed": false,
"unique": false,
"autoassigned": false,
"hint": null,
"defaultValue": null,
"refClass": "",
"itemsClass": "",
"backRef": "",
"backColl": "",
"binding": "",
"semantic": null,
"selConditions": [],
"selSorting": [],
"selectionProvider": null,
"indexSearch": false,
"eagerLoading": false,
"formula": null
}
{
"orderNumber": 30,
"name": "class_geodata1",
"caption": "Геоданные [100] mode [1] - Поиск по адресу",
"type": 100,
"size": null,
"decimals": 0,
"allowedFileTypes": null,
"maxFileCount": 0,
"nullable": true,
"readonly": false,
"indexed": false,
"unique": false,
"autoassigned": false,
"hint": null,
"defaultValue": null,
"refClass": "",
"itemsClass": "",
"backRef": "",
"backColl": "",
"binding": "",
"semantic": null,
"selConditions": [],
"selSorting": [],
"selectionProvider": null,
"indexSearch": false,
"eagerLoading": false,
"formula": null
}
{
"orderNumber": 40,
"name": "class_geodata2",
"caption": "Геоданные [100] mode [2] - Холст",
"type": 100,
"size": null,
"decimals": 0,
"allowedFileTypes": null,
"maxFileCount": 0,
"nullable": true,
"readonly": false,
"indexed": false,
"unique": false,
"autoassigned": false,
"hint": null,
"defaultValue": null,
"refClass": "",
"itemsClass": "",
"backRef": "",
"backColl": "",
"binding": "",
"semantic": null,
"selConditions": [],
"selSorting": [],
"selectionProvider": null,
"indexSearch": false,
"eagerLoading": false,
"formula": null
}
Тип «Структура [16]»¶
Структура - способ отображения связанных объектов (ссылок). Если у поля указана структура, то данный тип атрибута нужен для уменьшения действий при заведении модели, при заранее известных типовых классах, атрибуты которых используются во многих других классах.
Для класса-структуры в основной части меты класса задается значение true
в поле "isStruct"
.
Для атрибутов типа «Структура [16]» в мете представлений создания и изменения используется тип «Группа [0]». Если не указывать поля у группы, они создаются автоматически по мете. В представлениях списка нет необходимости делать колонки для атрибутов-структур, в объекте не будет такого свойства, а будут соответствующие атрибуты класса-структуры. Для них можно добавить колонки.
NB: Объекты класса-структуры не создаются!
Класс-структура:
{
"isStruct": true,
"key": [
"id"
],
"semantic": "",
"name": "is_struct",
"version": "",
"caption": "\"isStruct\" класс-структура",
"ancestor": null,
"container": null,
"creationTracker": "",
"changeTracker": "",
"history": 0,
"journaling": false,
"compositeIndexes": null,
"properties": [
{
"orderNumber": 10,
"name": "id",
"caption": "Идентификатор",
"type": 12,
"size": null,
"decimals": 0,
"allowedFileTypes": null,
"maxFileCount": 0,
"nullable": false,
"readonly": false,
"indexed": false,
"unique": true,
"autoassigned": true,
"hint": null,
"defaultValue": null,
"refClass": "",
"itemsClass": "",
"backRef": "",
"backColl": "",
"binding": "",
"semantic": null,
"selConditions": [],
"selSorting": [],
"selectionProvider": null,
"indexSearch": false,
"eagerLoading": false,
"formula": null
},
{
"orderNumber": 20,
"name": "last_name",
"caption": "Фамилия",
"type": 0,
"size": null,
"decimals": 0,
"allowedFileTypes": null,
"maxFileCount": 0,
"nullable": true,
"readonly": false,
"indexed": false,
"unique": false,
"autoassigned": false,
"hint": null,
"defaultValue": null,
"refClass": "",
"itemsClass": "",
"backRef": "",
"backColl": "",
"binding": "",
"semantic": null,
"selConditions": [],
"selSorting": [],
"selectionProvider": null,
"indexSearch": false,
"eagerLoading": false,
"formula": null
},
{
"orderNumber": 30,
"name": "first_name",
"caption": "Имя",
"type": 0,
"size": null,
"decimals": 0,
"allowedFileTypes": null,
"maxFileCount": 0,
"nullable": true,
"readonly": false,
"indexed": false,
"unique": false,
"autoassigned": false,
"hint": null,
"defaultValue": null,
"refClass": "",
"itemsClass": "",
"backRef": "",
"backColl": "",
"binding": "",
"semantic": null,
"selConditions": [],
"selSorting": [],
"selectionProvider": null,
"indexSearch": false,
"eagerLoading": false,
"formula": null
},
{
"orderNumber": 40,
"name": "patronymic",
"caption": "Отчество",
"type": 0,
"size": null,
"decimals": 0,
"allowedFileTypes": null,
"maxFileCount": 0,
"nullable": true,
"readonly": false,
"indexed": false,
"unique": false,
"autoassigned": false,
"hint": null,
"defaultValue": null,
"refClass": "",
"itemsClass": "",
"backRef": "",
"backColl": "",
"binding": "",
"semantic": null,
"selConditions": [],
"selSorting": [],
"selectionProvider": null,
"indexSearch": false,
"eagerLoading": false,
"formula": null
},
{
"orderNumber": 50,
"name": "date",
"caption": "Дата рождения",
"type": 9,
"size": null,
"decimals": 0,
"allowedFileTypes": null,
"maxFileCount": 0,
"nullable": true,
"readonly": false,
"indexed": false,
"unique": false,
"autoassigned": false,
"hint": null,
"defaultValue": null,
"refClass": "",
"itemsClass": "",
"backRef": "",
"backColl": "",
"binding": "",
"semantic": null,
"selConditions": [],
"selSorting": [],
"selectionProvider": null,
"indexSearch": false,
"eagerLoading": false,
"formula": null
}
]
}
Класс с атрибутом типа «Структура [16]»
{
"isStruct": false,
"key": [
"id"
],
"semantic": "",
"name": "struct",
"version": "",
"caption": "Класс \"Структура [16]\" (класс с типом атрибута 16 - структура)",
"ancestor": null,
"container": null,
"creationTracker": "",
"changeTracker": "",
"history": 0,
"journaling": false,
"compositeIndexes": null,
"properties": [
{
"orderNumber": 10,
"name": "id",
"caption": "Идентификатор",
"type": 12,
"size": null,
"decimals": 0,
"allowedFileTypes": null,
"maxFileCount": 0,
"nullable": false,
"readonly": false,
"indexed": false,
"unique": true,
"autoassigned": true,
"hint": null,
"defaultValue": null,
"refClass": "",
"itemsClass": "",
"backRef": "",
"backColl": "",
"binding": "",
"semantic": null,
"selConditions": [],
"selSorting": [],
"selectionProvider": null,
"indexSearch": false,
"eagerLoading": false,
"formula": null
},
{
"orderNumber": 20,
"name": "struct",
"caption": "Класс \"Структура [16]\"",
"type": 16,
"size": null,
"decimals": 0,
"allowedFileTypes": null,
"maxFileCount": 0,
"nullable": true,
"readonly": false,
"indexed": false,
"unique": false,
"autoassigned": false,
"hint": null,
"defaultValue": null,
"refClass": "is_struct",
"itemsClass": "",
"backRef": "",
"backColl": "",
"binding": "",
"semantic": null,
"selConditions": [],
"selSorting": [],
"selectionProvider": null,
"indexSearch": false,
"eagerLoading": false,
"formula": null
}
]
}
Объект класса с атрибутом-структурой в базе:
{
"_id" : ObjectId("57c3e46fd53ecd50123cc4f5"),
"struct$id" : "5f421610-6dba-11e6-874f-1b746e204b07",
"struct$last_name" : "Мирошниченко",
"struct$first_name" : "Ирина",
"struct$patronymic" : "Львовна",
"struct$date" : ISODate("1978-07-13T14:00:00.000Z"),
"id" : "5f41ef00-6dba-11e6-874f-1b746e204b07",
"_class" : "struct@develop-and-test",
"_classVer" : ""
}
Ссылки¶
Ссылка - тип данных, который хранит в себе ссылку на другой объект. Данный объект может быть объектом исходного класса, если ссылка указывает на класс, в котором она определена.
Значение в поле атрибута типа «Ссылка» выводятся в соответствии с семантикой, указанной для класса по ссылке. Главное отличие от типа «Коллекция» в том, что в поле атрибута типа «Ссылка» может отображаться и храниться только один объект класса по ссылке.
См. полное описание типа Ссылка
в атрибутивной части меты класса - Атрибут ссылки и обратной ссылки.
Способы задания ссылок с точки зрения используемых полей атрибутивной части меты классов:
один-к-одному
- означает наличие ссылки и вложенного объекта с ссылкой-связкой на исходный объект. В ссылке необходимо указать ссылку-связку, а у нее указать ссылочный атрибут вложенного объекта по которому формируется связь. Обязательно в атрибуте-ссылке указать свойство уникальности -true
. См. Обратные ссылки в контексте ссылок.один-ко-многим
- необходимо определить ссылку и указать класс вложенного элемента - связи создаются при помещении в ссылку и хранятся как отдельная сущность в БД. См. Ссылки.
Расписание¶
Расписание - тип данных реализующий хранение периодов времени или периодичность выполнения регулярных событий.
В представлении для расписания предусмотрено два типа полей:
SCHEDULE = 210
– расписание отображается в табличном виде
CALENDAR = 220
– расписание отображается в виде календаря
{
"caption": "Расписание [210]",
"type": 210,
"property": "schedule",
"size": 2,
"maskName": null,
"mask": null,
"mode": null,
"fields": [],
"hierarchyAttributes": null,
"columns": [],
"actions": null,
"commands": null,
"orderNumber": 20,
"required": false,
"visibility": null,
"enablement": null,
"obligation": null,
"readonly": false,
"selectionPaginated": true,
"validators": null,
"hint": "",
"historyDisplayMode": 0,
"tags": null
}
{
"caption": "Календарь [220]",
"type": 220,
"property": "calendar",
"size": 2,
"maskName": null,
"mask": null,
"mode": null,
"fields": [],
"hierarchyAttributes": null,
"columns": [],
"actions": null,
"commands": null,
"orderNumber": 30,
"required": false,
"visibility": null,
"enablement": null,
"obligation": null,
"readonly": false,
"selectionPaginated": true,
"validators": null,
"hint": "",
"historyDisplayMode": 0,
"tags": null
}
Периоды времени задаются как объекты периодичности в атрибуте occurs
с указанием атрибута duration
. Пропуски во временном периоде указываются в атрибуте skipped
.
[
{
"description": "Рабочие часы",
"item": "develop-and-test@WorkTime@12345", // Ссылка на объект данных
"occurs": [ // происходит
{
"hour": 9, // на 9 час суток
"duration": 14400 // длится 4 часа (4 * 60 * 60)
},
{
"hour": 14, // на 14 час суток
"duration": 14400 // длится 4 часа (4 * 60 * 60)
}
],
"skipped": [ // пропускается
{
"weekday": 6 // по субботам
},
{
"weekday": 7 // по воскресеньям
}
]
},
// ...
]
В объекте периодичности атрибуты задаются в рамках своих обычных значений, кроме атрибута year
- год. Атрибут year
, задаётся в виде частоты, так как является не периодической характеристикой.
{
"second": 30, // 1 - 60
"minute": 20, // 1 - 60
"hour": 9, // 0 - 23
"day": 5, // 1 - 31
"weekday": 1 // 1 - 7
"month": 3 // 1 - 12
"year": 2,
"duration": 30 //
}
Описание примера:
В примере определён временной интервал длительностью 30 секунд, который повторяется один раз в два года, пятого марта в 9 часов 20 минут 30 секунд и только если день выпадает на понедельник.
Пользовательские типы¶
Пользовательский тип - "type": 17
, задает значение пользовательского типа на основе базового типа. Находится в директории meta
, types
+ [название типа].type.json. Используется в случаях, когда необходимо применить маску на значения определенного атрибута в различных классах.
При создании пользовательского типа доступны следующие базовые типы:
- Строка [0]
- Целое [6]
- Действительное [7]
- Дата/Время [9]
- Десятичное [8]
{
"name": "userPassport",
"caption": "Номер паспорта",
"type": 0,
"mask": "99 99 999999",
"mask_name": "passport",
"size": 12,
"decimals": null
}
Пользовательские типы подключаются путем указания типа атрибута «Пользовательский [17]» - "type": 17
и указанием наименования пользовательского типа в поле «refClass».
{
"orderNumber": 20,
"name": "passport",
"caption": "Номер паспорта (Пользовательский тип [17])",
"type": 17,
"size": null,
"decimals": 0,
"allowedFileTypes": null,
"maxFileCount": 0,
"nullable": true,
"readonly": false,
"indexed": false,
"unique": false,
"autoassigned": false,
"hint": null,
"defaultValue": null,
"refClass": "userPassport",
"itemsClass": "",
"backRef": "",
"backColl": "",
"binding": "",
"semantic": null,
"selConditions": [],
"selSorting": [],
"selectionProvider": null,
"indexSearch": false,
"eagerLoading": false,
"formula": null
}
Таким образом, при вводе значения для атрибута "Номер паспорта (Пользовательский тип [17])"
будет применяться маска, заданая для типа "userPassport"
по ссылке свойства "refClass"
.
Тип атрибута - указывает на тип поддерживаемых атрибутом данных, как например размер допустимых значений и другие.
Код | Имя | Тип в БД | Описание |
---|---|---|---|
0 | Строка | String | Тип данных, значениями которого является произвольная последовательность (строка) символов алфавита. Каждая переменная такого типа (строковая переменная) может быть представлена фиксированным количеством символов. |
1 | Текст | String | Хранит текстовые данные. |
2 | HTML | String | Форматированный текст, содержащий гипертекстовую разметку с возможностью редактирования с учетом возможных начертаний. |
3 | URL | String | Хранит ссылку, позволяет сохранить любую строку. |
4 | Изображение | String | Изображение, сохраняемое в файловом хранилище с предпросмотром в представлениях. |
5 | Файл | String | Файл, сохраняемый в файловом хранилище. В процессе реализации в регистри. |
6 | Целое | Int32 | Целое число |
7 | Действительное | Double | Любое положительное число, отрицательное число или ноль. |
9 | Дата/время | Date | Дата в формате ISODate. Может быть отображена как дата, либо как дата-время. |
8 | Десятичное | Double | Число, представленное в десятичной системе счисления. Алфавит этой системы счисления состоит из 10 цифр от нуля до 9, отсюда и название - десятичная. |
10 | Логический | Boolean | Принимает два возможных значения, называемых истиной (true) и ложью (false). |
11 | Пароль | String | Хеш пароля |
12 | Глобальный идентификатор | String | Тип предназначенный для ключевого поля класса. Предполагает выставление атрибутов уникальности и автозаполнения. |
13 | Ссылка | String | Тип данных, хранящий в себе ссылку на объекты другого класса. |
14 | Коллекция | Array | Коллекция - тип данных, который хранит в себе ссылки на другие объекты. Каждая ссылка содержит значение идентификатора объекта, определенного в мете класса. Разделяются ссылки через запятую. Все значение из последовательности ссылок и запятых хранится строкой в базе. |
15 | Множество | String | Храним набор дискретных значений из предопределенного списка выбора. |
16 | Структура | String | Тип данных, хранящий в себе ссылку на объект класса-структуры. |
17 | Пользовательский тип | String | Дает возможность определения пользовательских типов на основе примитивных типов. |
18 | Пользователь | Строка | Хранит имя пользователя, для настройки безопасности, в формате имя@local |
100 | Геоданные | Object | Особый тип данных, хранящий координаты с уникальными представлениями для создания и редактирования. |
110 | Коллекция файлов | String | Тип атрибута для хранения комплекта файлов до 5 штук, с общим ограничением размера и возможностью задания допустимых расширений файлов |
210 | Расписание | Array | Тип данных, предназначеный для хранения данных календаря/расписания |
Идентификаторы типов атрибутов:¶
module.exports = {
STRING: 0,
TEXT: 1,
HTML: 2,
URL: 3,
IMAGE: 4,
FILE: 5,
INT: 6,
REAL: 7,
DECIMAL: 8,
DATETIME: 9,
BOOLEAN: 10,
PASSWORD: 11,
GUID: 12,
REFERENCE: 13,
COLLECTION: 14,
SET: 15,
STRUCT: 16,
CUSTOM: 17,
USER: 18,
PERIOD: 60,
GEO: 100,
FILE_LIST: 110,
SCHEDULE: 210
};
Автозаполняемые атрибуты¶
Тип автозаполняемые поля "autoassigned": true
- указывает, что значение данного атрибута должно быть заполнено автоматически при создании экземпляра класса. Применяется в основном для атрибутов типа «Уникальный идентификатор» "unique": true
для целосчисленных и строковых атрибутов, а также для атрибутов типа «Дата-время».
Принцип формирования:¶
Для атрибутов «Дата-время» атрибуту должно быть присвоено значение текущего момента времени. Используется для меток создания и изменения.
Для целочисленных атрибутов, если указано значение «Уникальный идентификатор» (
"unique": true
) при создании формы, заполняется случайным набором символов.Для строк, если указано значение «Уникальный идентификатор» (
"unique": true
), то должно быть сгенерировано случайное значение hex - размером с длину строки - в примере ниже 20 символов.var crypto = require('crypto'); ID = crypto.randomBytes(20).toString('hex');
Для типа «Глобальный идентификатор» - реализуется аналогично строке.
NB: Необходимо сделать проверку при сохранении. Поле должно генерироваться автоматически для пустых значений или даты. Для всех остальных (целое, строка) должны генерироваться ранее созданные значения.
{
"orderNumber": 50,
"name": "auto",
"caption": "auto",
"type": 6,
"size": null,
"decimals": 0,
"nullable": true,
"readonly": false,
"indexed": false,
"unique": true,
"autoassigned": true
}
Кеширование значения вычисляемого атрибута¶
Описание функционала¶
При применении функционала кеширования, значения атрибутов рассчитываются при создании и изменении объекта. При выборках берутся ранее рассчитанные значения.
Если есть два вычисляемых атрибута A и B обращающиеся к коллекции C, и при этом на A настроено кеширование, а на B не настроено, то при редактировании коллекция C будет выдергиваться 2 раза - один раз для атрибута B на уровне securedDataRepo
для проверки доступа, второй раз для атрибута A при его пересчете уже в dataRepo
. При чтении объекта из БД в данном случае кеш атрибута A просто не имеет смысла, так как коллекция в любом случае будет выбираться для атрибута B.
Кеширование семантик¶
Для кеширования семантик объектов в мете класса необходимо указать параметр:
semanticCached: true
Для атрибутов используемых в кешируемых семантиках не выполняется предварительная выборка объектов загрузки. Также в таких семантиках не рекомендуется использовать даты, т.к. они не будут приведены к формату часового пояса пользователя, так как кешируются при редактировании объекта на уровне DBAL
.
Кеширование значения вычисляемого атрибута¶
Для кеширования значения вычисляемого атрибута в его мете указываем:
cached: true
Кроме того, реализована возможность обновлять кеши у объектов по ссылкам при редактировании основного объекта.
Для этого в мете класса указываем настройку:
cacheDependencies: ["refAttr1", "refAttr2.refAttr3", "refAttr2.collAttr4"]
В настройке необходимо указать ссылки и коллекции, кеши объектов в которых необходимо обновить при редактировании объекта данного класса. Обновления выполняестя рекурсивно, то есть если в классе объекта в refAttr1
настроено обновление кешей, оно будет запущено. Настройка наследуется в классах наследниках.
{
"orderNumber": 40,
"name": "kolStatOps",
"caption": "Количество стационарных ОПС",
"type": 6,
"size": null,
"decimals": 0,
"allowedFileTypes": null,
"maxFileCount": 0,
"nullable": true,
"readonly": false,
"indexed": true,
"unique": false,
"autoassigned": false,
"hint": null,
"defaultValue": null,
"refClass": "",
"itemsClass": "",
"backRef": "",
"backColl": "",
"binding": "",
"semantic": null,
"selConditions": [],
"selSorting": [],
"selectionProvider": null,
"indexSearch": false,
"eagerLoading": false,
"formula": "count($raionObslu.oktmo_nasPunkta.svyaz.ops,&eq($gops, b), 1)",
"cached": true
}
Кешируется значение данного атрибута, получаемое из формулы. Дополнительно для обновления значения при редактирования объекта необходимо обновлять кеши объектов по ссылке: для этого в мете класса каждого объекта по ссылке указываем cacheDependencies:
.
{
"isStruct": false,
"key": [
"okato"
],
"semantic": "name",
"name": "naselenniyPunkt",
"version": "",
"caption": "Населенный пункт",
"ancestor": null,
"container": "",
"creationTracker": "",
"changeTracker": "",
"history": 0,
"journaling": true,
"compositeIndexes": null,
"cacheDependencies": ["supOktmo"],
"properties": [
...
Значение по умолчанию¶
Значение по умолчанию задается при необходимости вывода значения в поле атрибута автоматически при открытии формы создания объекта. Значение по умолчанию задается присвоением значения default
для свойства "defaultValue"
. Основное применение - для списков выбора допустимых значений.
Пример¶
{
"orderNumber": 20,
"name": "defaultValue",
"caption": "Значение поля",
"type": 0,
"size": null,
"decimals": 0,
"allowedFileTypes": null,
"maxFileCount": 0,
"nullable": true,
"readonly": false,
"indexed": false,
"unique": false,
"autoassigned": false,
"hint": null,
"defaultValue": "default",
"refClass": "",
"itemsClass": "",
"backRef": "",
"backColl": "",
"binding": "",
"semantic": null,
"selConditions": [],
"selSorting": [],
"selectionProvider": {
"type": "SIMPLE",
"list": [
{
"key": "default",
"value": "Значение, которое отображается по умолчанию при создании объекта"
},
{
"key": "other",
"value": "Другое значение"
}
],
"matrix": [],
"parameters": [],
"hq": ""
},
"indexSearch": false,
"eagerLoading": false,
"formula": null
}
Для реализации автоматического расчета значения по умолчанию можно использовать функцию max
:
"defaultValue": {max: ["className@namespace", "attr", {"filterAttr": "filterValue"}]}
Значение по умолчанию для атрибута типа «Ссылка» задается с помощью операции get
следующими способами:
get(className) // возвращаем id случайно выбранного объекта класса
get(className, id) // проверяем наличие объекта в БД, если объект есть, возвращаем его id
get(className, attr1, val1, attr2, val2, ...) // возвращаем id первого объекта удовлетворяющего критериям поиска: attr1=val1 и attr2=val2 и т.д.
Вычисляемые атрибуты (без кеширования)¶
Описание¶
Вычисляемые атрибуты (формулы) применяются для моментального формирования строкового выражения (результата) по заданному алгоритму при обращении к объекту класса через API. Например, при открытии объекта.
На уровне меты класса вычисляемые атрибуты хранят алгоритм формирования строкового выражения в свойстве formula
.
Для примера можно получить все уникальные значения из атрибута name
, значения которого хранятся в коллеции ownOrg
. Затем уникальные значения с разделителями «,» между собой объединяются в одно строковое значение.
"formula": {
"merge": [
"$ownOrg",
"name",
null,
1,
", "
]
}
Например, если есть коллекция с не уникальными значениями, например «ownOrg1», «ownOrg2». и снова «ownOrg1», то чтобы получить только уникальные значения коллекции «Организация 1 и Организация 2», пригодится выше описанная формула для вычисляемого атрибута с использованием функции merge
.
В зависимости от функции можно обращаться к необходимому атрибуту для получения значения через атрибуты типа «Ссылка», «Коллекция».
При сохранении изменений и закрытии формы объекта результат не сохраняется в атрибуте, если не настроено кеширование.
Если в мете класса задано несколько вычисляемых атрибутов, то порядок их вычисления задается в свойстве orderNumber
. При этом можно использовать результаты вычислений по заданному порядку orderNumber
в последующих вычисляемых атрибутах.
В семантике класса или атрибута можно указывать вычисляемые атрибуты.
Если в свойстве formula
задать Null
, то атрибут не будет являться вычисляемым и кеширование к такому атрибуту не должно применяться.
Модель записи формулы¶
Каждая формула начинается с описания объекта и функции в формате JSON.
"formula": {
"function1": [
{
"function2": [
"operand3"
]
},
"operand1",
"operand2"
]
}
В объекте обязательно нужно указать подходящую функцию необходимым количеством операндов для получения результата в function1
.
В объекте содержится полное описание алгоритма, по которому будут происходить вычисления, за исключением тех функций, которые находятся в зависимых вычисляемых атрибутах.
Массив в функции хранит порядок операндов, которые передаются в функцию.
Операндами функции могут быть:
Строковые значения, хранящие константу
"formula": { "function1": [ "string" ] }
Строковые значения, хранящие переменные.
"formula": { "function1": [ "$attr1" ] }
Числовые значения
"formula": { "function1": [ 3.14 ] }
Пустые значения
"formula": { "function1": [ null ] }
Объекты
"formula": { "function1": [ { "function2": [ "operand1" ] } ] }
Пример применения формулы:¶
{
"orderNumber": 5,
"name": "addressString",
"caption": "",
"type": 0,
"size": null,
"decimals": 0,
"allowedFileTypes": null,
"maxFileCount": 0,
"nullable": true,
"readonly": false,
"indexed": true,
"unique": false,
"autoassigned": false,
"hint": null,
"defaultValue": null,
"refClass": "",
"itemsClass": "",
"backRef": "",
"backColl": "",
"binding": "",
"semantic": null,
"selConditions": [],
"selSorting": [],
"selectionProvider": null,
"indexSearch": false,
"eagerLoading": false,
"formula": {
"concat": [
{
"if": [
"$zipCode",
{
"concat": [
"$zipCode"
]
},
""
]
},
" ",
{
"if": [
"$subjectFederation",
"$subjectFederation",
""
]
},
{
"if": [
"$federationBorough",
{
"concat": [
", ",
"$federationBorough"
]
},
""
]
},
{
"if": [
{
"and": [
{
"ne": [
"$subjectFederation",
"Санкт-Петербург г"
]
},
{
"ne": [
"$subjectFederation",
"Москва г"
]
}
]
},
{
"concat": [
", ",
"$town"
]
},
""
]
},
{
"if": [
"$street",
{
"concat": [
", ",
"$street"
]
},
""
]
},
{
"if": [
"$houseNumber",
{
"concat": [
", Дом ",
"$houseNumber"
]
},
""
]
},
{
"if": [
"$flatNumber",
{
"concat": [
", Квартира (офис) ",
"$flatNumber"
]
},
""
]
}
]
}
}
Результат: вывод адреса с пробелами и запятыми между значениями атрибутов
Поддерживаемые функции¶
eq
- равно
ne
- не равно
lt
- меньше
gt
- больше
lte
- меньше либо равно
gte
- больше, либо равно
and
- и
or
- или
not
- не
add
- арифметическое сложение
sub
- арифметическое вычитание
mul
- арифметическое умножение
div
- арифметическое деление
nempty
- не пусто
empty
- пусто
pad
- дополнение строки символами до нужной длины
next
- извлекает новое значение последовательности
merge
- конкатенация атрибутов в коллекции
size
- принимает в качестве аргумента атрибуты типа строка и коллекция. Для строк возвращает длину, для коллекций - количество элементов
element
- получение произвольного элемента из массива, индексирование с 0 ([массив значений], [индекс элемента: 0 - первый элемент, last - последний элемент])
dateAdd
- добавление к дате (в нотации momentjs - [Дата], [добавляемый интервал (число)], [ед.изм (строка [d, m, y, h, min, s, ms)])
dateDiff
- разница между датами (в нотации momentjs - [ед.изм], [Дата1], [Дата2])
now
- текущая дата-время
concat
- конкатенация строк
substring - получение подстроки ([Строка], [ с какого символа], [сколько символов])
obj
- формирование объекта, нечетные аргументы - имена свойств, четные - значения
агрегация:
max
, min
, avg
, sum
, count
Все функции агрегации принимают следующие аргументы:
либо
[$Имя атрибута коллекции], [Имя агрегируемого атрибута], [функция фильтрации элементов коллекции]
либо
[Имя класса], [Имя агрегируемого атрибута], [Объект фильтра сформированный функцией obj соответствующий нотации фильтров mongodb]
1
- указывает на уникальность объекта, то есть позволяет для функций агрегации производить подсчет только по уникальным объектам
\n
- перенос на другую строку
"formula": {
"merge": [
"$atr1",
"atr2.name",
null,
1,
"\n"
]
},
Автоприсвоение и получение значения атрибута в вычисляемом выражении¶
- Чтобы вычисляемое выражение не выполнялось при открытии формы создания, у атрибута надо выставить
autoassigned: true
. Тогда выражения будут вычислены непосредственно перед сохранением объекта. Это актуально при использовании функцииnext
в вычислениях, так как не всегда необходимо извлекать очередное значение последовательности при каждом открытии формы создания. - Значения по умолчанию рассчитываются до записи объекта в БД, то есть на этапе их вычисления в простых автоприсваемых атрибутах еще ничего нет.
- Функция
next($id)
(если в$id
задано значение) будет всегда возвращать 1, так как для каждого объекта будет создаваться отдельная последовательность, из которой выбирается только первое значение.
Индексация атрибутов¶
Индексация атрибутов необходима для ускорения поиска. Индексация задается вручную, присвоением значения true
для свойства "indexed"
, то есть:
"indexed": true
За исключением следующих типов атрибутов:
- Индексация задается автоматически (независимо от того, что указано в индексации для поля):
- для ключевого поля;
- для объектов с полем
"compositeIndexes": true
в основной части меты класса.
- При импорте меты принудительно индексируются все объекты атрибутов типа «Ссылка».
- Объекты атрибутов типа «Коллекция» не индексируются, так как коллекции с обратной ссылкой не хранятся в объекте, соответственно, в индексации нет необходимости.
NOTE. Запрещается индексация атрибутов типа "Текст" [1] и "HTML" [2].
Связано с ограничением MongoDB на размер индексируемого значения,
т.к. размер значения атрибутов данных типов может превышать допустимый размер.
Коллекция¶
Коллекция - тип данных, позволяющий выводить в объекте списки других объектов. Данные объекты могут быть объектами любого класса включая исходный.
Ссылки разделяются через запятую. Все значения из последовательности ссылок и запятых хранятся строкой в базе данных.
Способы задания коллекций:¶
с точки зрения используемых полей атрибутивной части меты классов
один-ко-многим
- классическая связь дочернего объекта на родительский объект. Означает наличие контейнера и вложенного объекта с ссылкой на контейнер. В контейнере необходимо указать коллекцию, а у коллекции указать ссылочный атрибут вложенного объекта, по которому формируется связь. См. Обратные ссылкимногие-ко-многим
- определяется через коллекцию без ссылок и класса вложенных элементов - связи создаются при помещении в коллекцию и хранятся как отдельные сущности в БД. См. Коллекции.обратная коллекция
- связь один-ко-многим, но в обратную сторону - со стороны объекта на который идут ссылки. Задается через backColl. См. Обратные коллекции.
Атрибут коллекция в формате JSON¶
{
"orderNumber": 50,
"name": "table",
"caption": "Таблица",
"type": 14,
"size": null,
"decimals": 0,
"allowedFileTypes": null,
"maxFileCount": 0,
"nullable": true,
"readonly": false,
"indexed": false,
"unique": false,
"autoassigned": false,
"hint": null,
"defaultValue": null,
"refClass": "",
"itemsClass": "collRefCatalog@develop-and-test",
"backRef": "",
"backColl": "",
"binding": "",
"semantic": null,
"selConditions": [],
"selSorting": [],
"selectionProvider": null,
"indexSearch": false,
"eagerLoading": false,
"formula": null
}
NB: Если коллекция ссылается на класс, содержащий множество потомков, то при заполнении коллекции будет возможность создавать объекты как родительского, так и дочерних классов.
Коллекции вместе с объектом грузятся по семантике, заданной в мете класса-коллекции или атрибута-коллекции.
Обратная ссылка в контексте коллекций¶
Обратная ссылка в контексте коллекций образуется следующим образом:
- Создается обычная коллекция с указанием ссылочного класса
- В ссылочном классе должен быть атрибут-ссылка, ссылающийся на исходный класс и имеющий свойство
unique
равнымfalse
. Значение атрибут-ссылке присваивается сразу при создании связи с коллекцией, без необходимости сохранения формы - В исходном классе обычной коллекции заполняем свойство
"backRef"
- туда записывается код атрибута-ссылки из ссылочного класса
Атрибут обратная ссылка в формате JSON¶
{
"orderNumber": 30,
"name": "coll",
"caption": "Коллекция с обратной ссылкой",
"type": 14,
"size": null,
"decimals": 0,
"allowedFileTypes": null,
"maxFileCount": 0,
"nullable": true,
"readonly": false,
"indexed": false,
"unique": false,
"autoassigned": false,
"hint": null,
"defaultValue": null,
"refClass": null,
"itemsClass": "ref_backcoll_ref@develop-and-test",
"backRef": "ref_backcoll_ref",
"backColl": "",
"binding": "",
"semantic": "backcoll_data",
"selConditions": [],
"selSorting": [],
"selectionProvider": null,
"indexSearch": false,
"eagerLoading": true,
"formula": null
}
Режимы отображения атрибута типа «Коллекция» на форме:¶
Режимы отображения задаются в мете представления. Могут определяться при помощи свойства "mode"
, либо задаваться шаблоном в свойстве "options"
.
- mode: 4 - «Облако тегов» хранит значения одного или нескольких объектов по ссылке в виде тегов, наименование которых определяется семантикой объекта по ссылке.
- mode: 3 - «Таблица» хранит значения одного или нескольких объектов по ссылки в таблице, колонки которой предопределены для формы представления.
{
"caption": "Таблица",
"type": 3,
"property": "table",
"size": 2,
"maskName": null,
"mask": null,
"mode": 3,
"fields": [],
"columns": [],
...
},
...
- «Комментарий» - задается аналогично режиму отображения «Таблица», но с наложением шаблона, указанном в свойстве
"options"
. Представляет собой поле, которое содержит данные, зараннее предопределенные в свойстве"columns"
для объекта по ссылке. Предназначено, в основном, для обсуждения информации по объекту на определенном этапе бизнес-процесса.
{
"caption": "Коментарий",
"type": 3,
"property": "coment",
"size": 2,
"maskName": null,
"mask": null,
"mode": 3,
"fields": [],
"columns": [
{
"sorted": true,
"caption": "Дата",
"type": 120,
"property": "date",
...
},
{
"sorted": true,
"caption": "Подтверждение (Обоснование)",
"type": 7,
"property": "descript",
...
},
{
"caption": "Ведущий",
"type": 2,
"property": "owner",
...
}
],
"actions": null,
"commands": [
{
"id": "CREATE",
"caption": "Создать",
"visibilityCondition": null,
"enableCondition": null,
"needSelectedItem": false,
"signBefore": false,
"signAfter": false,
"isBulk": false
},
{
"id": "EDIT",
"caption": "Править",
"visibilityCondition": null,
"enableCondition": null,
"needSelectedItem": true,
"signBefore": false,
"signAfter": false,
"isBulk": false
}
],
"orderNumber": 80,
...
"tags": null,
"options": {
"template": "comments",
"comments": {
"textProperty": "descript",
"userProperty": "owner",
"parentProperty": "answlink",
"photoProperty": "owner_ref.foto.link",
"dateProperty": "date"
}
}
}
Обратная коллекция¶
Пример коллекции выше преобразуется для обратной коллекции следующим образом:
{
"orderNumber": 30,
"name": "backcoll",
"caption": "Обратная коллекции",
"type": 14,
"size": null,
"decimals": 0,
"allowedFileTypes": null,
"maxFileCount": 0,
"nullable": true,
"readonly": false,
"indexed": false,
"unique": false,
"autoassigned": false,
"hint": null,
"defaultValue": null,
"refClass": "",
"itemsClass": "coll_backcoll_coll",
"backRef": "",
"backColl": "coll",
"binding": "",
"semantic": "backcoll_data",
"selConditions": [],
"selSorting": [],
"selectionProvider": null,
"indexSearch": false,
"eagerLoading": true,
"formula": null
}
Обратите внимание на указание в свойстве "backColl"
дополнительного значения - имя атрибута из класса в коллекции (из примера это coll)
Таким образом, реализуется связь многие-ко-многим
без промежуточного класса. Не только атрибут "backcoll"
с типом «Коллекция» может содержать несколько ссылок, но и объекты по ссылкам также могут содержать в своей коллекции «coll» несколько ссылок на объекты исходного класса.
Внимание:¶
"type": 14
- тип атрибута «Коллекция»"backColl"
- название ссылочного атрибута типа коллеции, ссылающегося на исходный класс с коллекцией"itemsClass"
- название класса, объекты которого могут хранить свои идентификаторы в коллекции и, таким образом, формировать связь к объекту по идентификатору"backRef"
- атрибут-ссылка из ссылочного класса, указанного в"itemsClass"
- При указании класса-родителя есть возможность создавать объекты родительского и дочерних классов
- Коллекции вместе с объектом грузятся по семантике, заданной в мете класса-коллекции или атрибута-коллекции
Схема обработки коллекций и формат хранения в БД¶
Для сохранения коллекции, необходимо передать в соответствующем ей атрибуте объекта массив действий вида:
"collection": [
{"action": "put", "id": "1234"},
{"action": "put", "id": "1235"},
{"action": "put", "id": "1236"},
{"action": "eject", "id": "1230"}
]
Порядок объектов должен соответствовать порядку выполнения соответствующих действий. Коды операций: put
- добавление в коллекцию, eject
- извлечение из коллекции. Алгоритм для создания и редактирования одинаков. Действия с коллекциями выполняются после создания или сохранения контейнера.
Принцип работы коллекций на форме создания и редактирования принципиально разный:
- На форме создания взаимодействие с сервером требуется лишь для получения и отображения в таблице выбранного/созданного объекта коллекции
- На форме редактирования реализована возможность получения ответа сервера при необходимости, и изменение параметров выборки при запросе, в зависимости от выполненных действий над коллекцией.
Ссылка¶
Описание¶
Ссылка - тип данных, который хранит простое значение и которое интерпретируется системой как ссылка на ключевой атрибут объекта другого класса. Данный объект может быть объектом любого класса, включая исходный. При указании класса-родителя есть возможность создавать объекты родительского и дочерних классов. Ссылки вместе с объектом грузятся по семантике, заданной в мете класса-ссылки или атрибута-ссылки.
Отображаемые значения в атрибуте ссылочного типа выводятся в соответствии с семантикой, указанной в ссылочном классе этого атрибута.
Возможность замены объекта по обратной ссылке определяется параметром nullable
, связывающего ссылочный атрибут. При замене объекта связь будет потеряна, и объект по ссылке будет удален при попытке изменить связь из коллекции с обратной ссылкой.
Типы связей, реализуемые типом «Ссылка»:¶
Ссылочный тип с точки зрения используемых полей атрибутивной части меты классов:
один-ко-многим
- классическая связь дочернего объекта на родительский объект. Необходимо определить ссылку и указать класс вложенного элемента - связи создаются при помещении в ссылку и хранятся как отдельная сущность в БД.один-к-одному
- аналогична связи один-ко-многим, означает наличие ссылки и вложенного объекта с ссылкой-связкой на исходный объект. В ссылке необходимо указать ссылку-связку, а у нее указать ссылочный атрибут вложенного объекта по которому формируется связь. Обязательно в атрибуте-ссылке указать свойство"unique": true
.
Ссылка в формате JSON¶
{
"orderNumber": 20,
"name": "ssylka",
"caption": "Ссылка",
"type": 13,
"size": null,
"decimals": 0,
"allowedFileTypes": null,
"maxFileCount": 0,
"nullable": true,
"readonly": false,
"indexed": false,
"unique": false,
"autoassigned": false,
"hint": null,
"defaultValue": null,
"refClass": "collRefCatalog@develop-and-test",
"itemsClass": "",
"backRef": "",
"backColl": "",
"binding": "",
"semantic": null,
"selConditions": [],
"selSorting": [],
"selectionProvider": null,
"indexSearch": false,
"eagerLoading": false,
"formula": null
}
Режимы отображения атрибута типа «Ссылка» на форме:¶
Режимы отображения задаются в мете представления. Могут определяться при помощи свойства "mode"
либо задаваться шаблоном в свойстве "options"
.
- «mode»: 0 - отображение только семантики объекта по ссылке
- «mode»: 1 - отображение ссылки на форму объекта по ссылке
- «mode»: 3 - иерархический поиск объекта
- «mode»: 4 - уточняющий поиск объекта
Обратные ссылки¶
Обратная ссылка в контексте ссылок получается следующим образом:
- Создаётся атрибут с типом 13, указанием ссылочного класса
refClass
и указанием свойства"backRef"
- куда записывается код атрибута из ссылочного класса. - В ссылочном классе должен быть атрибут-ссылка, ссылающийся на исходный класс и имеющий свойство
"unique": true
.
Обратная ссылка в формате JSON¶
{
"orderNumber": 30,
"name": "backref",
"caption": "Обратная ссылка",
"type": 13,
"size": null,
"decimals": 0,
"allowedFileTypes": null,
"maxFileCount": 0,
"nullable": true,
"readonly": false,
"indexed": false,
"unique": false,
"autoassigned": false,
"hint": null,
"defaultValue": null,
"refClass": "otorbrRef@develop-and-test",
"itemsClass": "",
"backRef": "ref",
"backColl": "",
"binding": "",
"semantic": "data",
"selConditions": [],
"selSorting": [],
"selectionProvider": null,
"indexSearch": false,
"eagerLoading": true,
"formula": null
}
"type": 13
- тип атрибута «Ссылка»"refClass"
- название класса, объекты которого могут хранить свои идентификаторы в ссылке и, таким образом, формировать связь к объекту по идентификатору."backRef"
- указывается имя атрибута, который принадлежит классу, заданному в свойстве"refClass"
. Атрибут должен иметь тип «Ссылка» и ссылку на исходный класс.- При указании класса-родителя есть возможность создавать объекты родительского и дочерних классов.
- Ссылки вместе с объектом грузятся по семантике, заданной в мете класса-ссылки или атрибута-ссылки.
Employee: {
property: {
aaa: {
refClass: Post,
backRef: bbb,
...
},
...
}
}
Post: {
property: {
bbb: {
refClass: Employee,
...
},
...
}
}
Условия отбора допустимых значений¶
Описание¶
Условия отбора допустимых значений - условия, позволяющие ограничить выбор объектов по ссылке, допустимых для привязки в данном ссылочном атрибуте.
Фильтр списка допустимых значений используется в мете классов для атрибутов типа «Ссылка» и «Коллекция». Фильтром накладываются условия ограничения выборки объектов. Условия накладываются как список последовательных операций.
• EQUAL: 0, // равно =
• NOT_EQUAL: 1, // не равно <>
• EMPTY: 2, // пусто '' или null
• NOT_EMPTY: 3, // не пусто !'' или !null
• LIKE: 4, // похож
• LESS: 5, // меньше <
• MORE: 6, // больше >
• LESS_OR_EQUAL: 7, // меньше или равно <=
• MORE_OR_EQUAL: 8, // больше или равно >=
• IN: 9, // элемент входит в коллекцию/массив (IN)
• CONTAINS: 10 // содержит
module.exports = {
AND: 0,
OR: 1,
NOT: 2,
MIN: 3,
MAX: 4,
AVG: 5,
SUM: 6,
COUNT: 7
};
Описание операций¶
Операции могут быть разделены на группы по наличию свойств в условии:
Атрибут не указан в условии и условие - объект
- nestedConditions не содержит условий
- Операции агрегации
AgregOpers
- MIN
- MAX
- AVG
- SUM
- COUNT
- Операции агрегации
- nestedConditions содержит условия
- Логические операции сравнения вложенных условий
BoolOpers
- OR
- NOT
- Логические операции сравнения вложенных условий
Атрибут указан и условие - объект: операции сравнения значения артибута в условии со значением в value
- EMPTY
- NOT_EMPTY
- CONTAINS
- EQUAL
- NOT_EQUAL
- LESS
- MORE
- LESS_OR_EQUAL
- MORE_OR_EQUAL
- LIKE
- IN
Условие в виде массива
- Применяется логическая операция AND для сравнения результатов условий (объектов в массиве).
В операции типа ключ-выражение ключом является имя атрибута в классе ссылки или в классе коллекции. Смежные условия объединяются логической операцией «И» (если не указана другая операция) - добавляются фильтры в свойство «selConditions».
Применение операций и другие особенности¶
При выполнении запроса к атрибуту, необходимо использовать условие «nestedConditions». Для каждого атрибута выполняется отдельная операция. Не указывайте вложенные ссылочные атрибуты через точку в поле «property».
Для запроса значений атрибута, которые не равны нулю, необходимо выполнить операцию nempty
, в поле «value» указываем null
.
Операция CONTAINS применима к типам атрибута:
- строка - к строке данных применяется операция LIKE
- коллекция
- применяется операция IN, если сравниваемое значение
value
является массивом и содержит хотя бы один элемент - происходит переход к вложенным условиям
nestedConditions
, если сравниваемое значениеvalue
не является массивом или не содержит хотя бы один элемент в массиве
- применяется операция IN, если сравниваемое значение
JSON¶
{
"selConditions": [
{
"property": "region",
"operation": 10,
"value": "Хабаровский край",
"nestedConditions": [
{
"property": "town",
"operation": 0,
"value": "г Хабаровск",
"nestedConditions": []
}
]
}
]
}
{
"selConditions": [
{
"property": "town",
"operation": 3,
"value": null,
"nestedConditions": []
}
]
}
Описание полей¶
Поле | Наименование | Допустимые значения | Описание |
---|---|---|---|
"property" |
Атрибут | Строка, только латиница без пробелов | Атрибут класса ссылки, по которому производится фильтрация значений |
"operation" |
Операция | Код операции (см. выше) | Операция, согласно которой производится фильтрация |
"value" |
Значение | Зависит от типа операции | Второе значение для бинарных операций фильтрации |
"nestedConditions" |
Вложенные условия отбора | Объект, структура аналогична структуре самого объекта условий отбора. |
Внимание
Поле «selection_provider». См. подробнее Список выбора допустимых значений.
«type»: «SIMPLE» - простой тип,
«list»: [] - массив допустимых значений
{ "orderNumber": 80, "name": "type", "caption": "Тип организации", "type": 0, "size": null, "decimals": 0, "nullable": true, "readonly": false, "indexed": false, "unique": false, "autoassigned": false, "defaultValue": null, "refClass": "", "itemsClass": "", "backRef": "", "backColl": "", "binding": "", "selConditions": [], "selSorting": [], "selectionProvider": { "type": "SIMPLE", "list": [ { "key": "customer", "value": "Заказчик" }, { "key": "executor", "value": "Исполнитель" } ], "matrix": [], "parameters": [], "hq": "" }, "indexSearch": false, "eagerLoading": false }
В ссылочном атрибуте необходимо показать только те объекты, у которых в ссылочном классе задан атрибут «selConditions» и в поле property
этого атрибута указано поле связанного класса,чьё значение в поле «value» соответствует условию «operation».
В атрибуте организация, задача показать только организации («refClass»: «organization»), у которых в поле тип ( «property»: «type») равно ( «operation»: 0) значению azchik («value»: «customer»).
Все условия в "selConditions"
объединяются по условию «И».
{
"orderNumber": 120,
"name": "customer",
"caption": "Заказчик",
"type": 13,
"size": null,
"decimals": 0,
"nullable": true,
"readonly": false,
"indexed": false,
"unique": false,
"autoassigned": false,
"defaultValue": null,
"refClass": "organization",
"itemsClass": "",
"backRef": "",
"backColl": "",
"binding": "",
"selConditions": [
{
"property": "type",
"operation": 0,
"value": "customer",
"nestedConditions": []
}
],
"selSorting": [],
"selectionProvider": null,
"indexSearch": false,
"eagerLoading": false
},
{
"orderNumber": 130,
"name": "executor",
"caption": "Исполнитель",
"type": 13,
"size": null,
"decimals": 0,
"nullable": true,
"readonly": false,
"indexed": false,
"unique": false,
"autoassigned": false,
"defaultValue": null,
"refClass": "organization",
"itemsClass": "",
"backRef": "",
"backColl": "",
"binding": "",
"selConditions": [
{
"property": "type",
"operation": 0,
"value": "executor",
"nestedConditions": []
}
],
"selSorting": [],
"selectionProvider": null,
"indexSearch": false,
"eagerLoading": false
}
Условия отбора допустимых значений для атрибутов с типом «Дата»¶
В ядре реализован атрибут контекста $$now
, возвращающий текущую дату.
$$now
доступен везде при задании условий.
Подробнее см. переменные.
Условие: выводить объекты, у которых значение атрибута [dataStart] меньше текущей даты:
{
"property": "dateStart",
"operation": 5,
"value": [
"$$now"
],
"nestedConditions": []
}
Список выбора допустимых значений¶
Список выбора допустимых значений - задает список выбора допустимых значений для поля ввода атрибута и находится в атрибутивной части меты класса - "selectionProvider"
. Список формируется в виде массива объектов типа «ключ-значения» и представляет собой список выбора значения для атрибута с типом «Строка», «Действительное», «Целое», «Десятичное», «Текст».
Есть три типа списка выбора, тип задается в поле ("type"
) одной из следующих ключевых фраз:
"SIMPLE"
- список выбора простого типа;"MATRIX"
- список выбора матричного типа.
Описание полей структуры¶
"selectionProvider": {
"type": "SIMPLE",
"list": [...],
"matrix": [],
"parameters": [],
"hq": ""
},
Поле | Наименование | Допустимые значения | Описание |
---|---|---|---|
"type" |
Тип | "SIMPLE", "MATRIX", "HQL" |
Тип списка выбора |
"list" |
Простой тип | Массив объектов типа «ключ-значение». | Список выбора просто типа («SIMPLE») хранится здесь. |
"matrix" |
Матрица | Массив векторов, каждый из которых состоит из именования, комплекта условий выбора и комплекта пар «ключ-значение». | Список выбора матричного типа («MATRIX»). |
"parameters" |
Параметры запроса | Массив объектов типа «ключ-значение». | Параметры запроса, не реализовано |
"hq" |
Запрос | Строка запроса в соответствии с форматом обработчика не используется в текущей версии | Строка запроса, не реализовано |
"list"
- массив объектов следующей структуры¶"list": [
{
"key": "2001-03-23 09:00:00.000Z",
"value": "Затопление орбитальной станции «Мир» (23 марта 2001 г. 09:00 мск)"
},
{
"key": "1957-10-04 19:28:00.000Z",
"value": "Запуск первого в мире искусственного спутника (4 октября 1957 г. в 19:28 гринвич)"
},
{
"key": "1970-04-17 12:07:00.000Z",
"value": "Завершение полёта «Аполлон-13» (17 апреля 1970 г. 12:07 Хьюстон)"
}
],
Поле | Наименование | Допустимые значения | Описание |
---|---|---|---|
"key" |
Ключ | Любое значение, соответствующее типу атрибута для которого заведен данный список выбора | При сохранении объекта именно значение ключа записывается в базу |
"value" |
Значение | Любая строка, могут быть проблемы при наличии управляющих последовательностей | Значение этого поля выводится в пользовательском интерфейсе |
"matrix"
- массив объектов следующей структуры¶ "matrix": [
{
"comment": "Оба отрицательные",
"conditions": [
{
"property": "matrix_base_1",
"operation": 5,
"value": "0",
"nestedConditions": []
},
{
"property": "matrix_base_2",
"operation": 5,
"value": "0",
"nestedConditions": []
}
],
"result": [
{
"key": "Оба отрицательные",
"value": "Оба отрицательные"
}
]
},
{
"comment": "Оба неотрицательные",
"conditions": [
{
"property": "matrix_base_1",
"operation": 8,
"value": "0",
"nestedConditions": []
},
{
"property": "matrix_base_2",
"operation": 8,
"value": "0",
"nestedConditions": []
}
],
"result": [
{
"key": "Оба неотрицательные",
"value": "Оба неотрицательные"
}
]
},
{
"comment": "Первое неотрицательное второе отрицательное",
"conditions": [
{
"property": "matrix_base_1",
"operation": 8,
"value": "0",
"nestedConditions": []
},
{
"property": "matrix_base_2",
"operation": 5,
"value": "0",
"nestedConditions": []
}
],
"result": [
{
"key": "Первое неотрицательное второе отрицательное",
"value": "Первое неотрицательное второе отрицательное"
}
]
},
{
"comment": "Первое отрицательное, второе неотрицательное",
"conditions": [
{
"property": "matrix_base_1",
"operation": 5,
"value": "0",
"nestedConditions": []
},
{
"property": "matrix_base_2",
"operation": 8,
"value": "0",
"nestedConditions": []
}
],
"result": [
{
"key": "Первое отрицательное, второе неотрицательное",
"value": "Первое отрицательное, второе неотрицательное"
}
]
}
],
"parameters": [],
"hq": ""
},
Каждый объект массива "MATRIX"
содержит следующие обязательные поля:
Поле | Наименование | Допустимые значения | Описание |
---|---|---|---|
"comment" |
Комментарий | Любая строка | Комментарий к вектору |
"conditions" |
Условия | Массив объектов | Определяет условия при которых выводится список элементов описанный в "result" данного вектора |
"result" |
Результаты | Массив объектов, аналогичен структуре поля "list" |
Задает список выбора, который выводится при соблюдении условий, перечисленных в "conditions" данного вектора |
"conditions"
массива "MATRIX"
¶Поле | Наименование | Допустимые значения | Описание |
---|---|---|---|
"property" |
Атрибут | Строка, только латиница без пробелов | Атрибут класса, значение поля которого проверяется на соответствие данному условию данного вектора |
"operation" |
Операция | Код операции | Операция, согласно которой производится определение |
0 - равно (И) | |||
1 - не равно (ИЛИ) | |||
2 - пусто (НЕ) | |||
3 - не пусто (МИН ИЗ) | |||
4 - (МАКС ИЗ) | |||
5 - < () | |||
6 - > | |||
7 - <= | |||
8 - >= | |||
9 - IN /Похож/ | |||
10 - содержит | |||
"value" |
Значение | Зависит от типа операции | Второе значение для бинарных операций |
"nestedConditions" |
Вложенные условия отбора | Объект, структура аналогична структуре самого объекта условий отбора. |
NB: Код операции соответствует разным значениям операций, в зависимости от того, выбран атрибут или нет. Если поле "property"
равно null
, то кодируется логическое условие, по которому объединяются вложенные условия отбора. (Указаны в скобках в таблице выше)
Описание¶
Данный список выбора позволяет создать жестко зашитый в приложении пресет значений поля, ограничив тем самом выбор пользователя.
Для поля в обязательном порядке следует задать тип представления - «Выпадающий список [5]».
Подразумевает возможность сохранять данные в базе в типе, отличном от типа данных, выводимых пользователю.
Например: Если задать в качестве полей key
элементы списка выбора значения даты-времени в ISODate, а в качестве value
- описание события, то предоставим пользвателю возможность выбрать событие, но внутри приложения работать с данными типа ISODate.
NB: Если у атрибута со списком выбора разрешено пустое значение: "nullable": true
- в списке выбора добавляется пустое значение по умолчанию!
{
"orderNumber": 50,
"name": "sp_date",
"caption": "Сохраняем ключ дата-время",
"type": 9,
"size": null,
"decimals": 0,
"allowedFileTypes": null,
"maxFileCount": 0,
"nullable": true,
"readonly": false,
"indexed": false,
"unique": false,
"autoassigned": false,
"hint": null,
"defaultValue": null,
"refClass": "",
"itemsClass": "",
"backRef": "",
"backColl": "",
"binding": "",
"semantic": null,
"selConditions": [],
"selSorting": [],
"selectionProvider": {
"type": "SIMPLE",
"list": [
{
"key": "2001-03-23T09:00:00.000Z",
"value": "Затопление орбитальной станции «Мир» (23 марта 2001 г. 09:00 мск)"
},
{
"key": "1957-10-04T19:28:00.000Z",
"value": "Запуск первого в мире искусственного спутника (4 октября 1957 г. в 19:28 гринвич)"
},
{
"key": "1970-04-17T12:07:00.000Z",
"value": "Завершение полёта «Аполлон-13» (17 апреля 1970 г. 12:07 Хьюстон)"
}
],
"matrix": [],
"parameters": [],
"hq": ""
},
"indexSearch": false,
"eagerLoading": false,
"formula": null
}
Необходимо:
- выбрать исходя из требований предметной области наиболее удобный тип атрибута,
- выбрать идентификаторы данного типа (
"key"
) с той целью, что бы при необходимости автоматизированной обработки оперировать значениями в базе максимально эффективно, - задать к каждому идентификатору подпись, которая будет отображаться в интерфейсе
"value"
, - задать в представлениях тип представления - «Выпадающий список [5]» в обязательном порядке.
В матрицах результирующий список выбора это все, что попадает под условия. Если условий нет - то система считает, что список выбора применяется всегда. Для предсказуемости работы приложения, необходимо чтобы были соблюдены два условия:
Вектора не должны перекрывать друг друга.
Массив значений опорного атрибута, как основание матрицы (массив сочетаний значений опорных атрибутов) должен полностью закрываться описанными векторами.
Система берет значение опорного поля (полей) и последовательно применяет к нему условия описанные в векторах. Каждый вектор - это набор условий и собственный список выбора. Как только система дойдет до вектора, условиям которого удовлетворяет значение опорного поля, она берет из него список выбора и определяет к выводу в пользовательском интерфейсе. Подразумевается, что на любое значение опорного поля система найдет соответствующий вектор.
JSON класса:
{
"isStruct": false,
"key": [
"id"
],
"semantic": "",
"name": "selection_provider_matrix_dc",
"version": "",
"caption": "\"MATRIX\" от двух оснований",
"ancestor": null,
"container": null,
"creationTracker": "",
"changeTracker": "",
"history": 0,
"journaling": false,
"compositeIndexes": [],
"properties": [
{
"orderNumber": 10,
"name": "id",
"caption": "Идентификатор",
"type": 12,
"size": null,
"decimals": 0,
"allowedFileTypes": null,
"maxFileCount": 0,
"nullable": false,
"readonly": false,
"indexed": false,
"unique": true,
"autoassigned": true,
"hint": null,
"defaultValue": null,
"refClass": "",
"itemsClass": "",
"backRef": "",
"backColl": "",
"binding": "",
"semantic": null,
"selConditions": [],
"selSorting": [],
"selectionProvider": null,
"indexSearch": false,
"eagerLoading": false,
"formula": null
},
{
"orderNumber": 20,
"name": "matrix_base_1",
"caption": "Первое целое основание матрицы",
"type": 6,
"size": null,
"decimals": 0,
"allowedFileTypes": null,
"maxFileCount": 0,
"nullable": true,
"readonly": false,
"indexed": false,
"unique": false,
"autoassigned": false,
"hint": null,
"defaultValue": null,
"refClass": "",
"itemsClass": "",
"backRef": "",
"backColl": "",
"binding": "",
"semantic": null,
"selConditions": [],
"selSorting": [],
"selectionProvider": null,
"indexSearch": false,
"eagerLoading": false,
"formula": null
},
{
"orderNumber": 30,
"name": "matrix_base_2",
"caption": "Второе целое основание матрицы",
"type": 6,
"size": null,
"decimals": 0,
"allowedFileTypes": null,
"maxFileCount": 0,
"nullable": true,
"readonly": false,
"indexed": false,
"unique": false,
"autoassigned": false,
"hint": null,
"defaultValue": null,
"refClass": "",
"itemsClass": "",
"backRef": "",
"backColl": "",
"binding": "",
"semantic": null,
"selConditions": [],
"selSorting": [],
"selectionProvider": null,
"indexSearch": false,
"eagerLoading": false,
"formula": null
},
{
"orderNumber": 40,
"name": "selection_provider_matrix",
"caption": "Список выбора типа \"MATRIX\"",
"type": 0,
"size": null,
"decimals": 0,
"allowedFileTypes": null,
"maxFileCount": 0,
"nullable": true,
"readonly": false,
"indexed": false,
"unique": false,
"autoassigned": false,
"hint": null,
"defaultValue": null,
"refClass": "",
"itemsClass": "",
"backRef": "",
"backColl": "",
"binding": "",
"semantic": null,
"selConditions": [],
"selSorting": [],
"selectionProvider": {
"type": "MATRIX",
"list": [],
"matrix": [
{
"comment": "Оба отрицательные",
"conditions": [
{
"property": "matrix_base_1",
"operation": 5,
"value": "0",
"nestedConditions": []
},
{
"property": "matrix_base_2",
"operation": 5,
"value": "0",
"nestedConditions": []
}
],
"result": [
{
"key": "Оба отрицательные",
"value": "Оба отрицательные"
}
]
},
{
"comment": "Оба неотрицательные",
"conditions": [
{
"property": "matrix_base_1",
"operation": 8,
"value": "0",
"nestedConditions": []
},
{
"property": "matrix_base_2",
"operation": 8,
"value": "0",
"nestedConditions": []
}
],
"result": [
{
"key": "Оба неотрицательные",
"value": "Оба неотрицательные"
}
]
},
{
"comment": "Первое неотрицательное второе отрицательное",
"conditions": [
{
"property": "matrix_base_1",
"operation": 8,
"value": "0",
"nestedConditions": []
},
{
"property": "matrix_base_2",
"operation": 5,
"value": "0",
"nestedConditions": []
}
],
"result": [
{
"key": "Первое неотрицательное второе отрицательное",
"value": "Первое неотрицательное второе отрицательное"
}
]
},
{
"comment": "Первое отрицательное, второе неотрицательное",
"conditions": [
{
"property": "matrix_base_1",
"operation": 5,
"value": "0",
"nestedConditions": []
},
{
"property": "matrix_base_2",
"operation": 8,
"value": "0",
"nestedConditions": []
}
],
"result": [
{
"key": "Первое отрицательное, второе неотрицательное",
"value": "Первое отрицательное, второе неотрицательное"
}
]
}
],
"parameters": [],
"hq": ""
},
"indexSearch": false,
"eagerLoading": false,
"formula": null
}
]
}
Порядок разработки
Необходимо разделить все возможные сочетания пар атрибутов "matrix_base_1"
и "matrix_base_2"
на 4 вектора. Делить необходимо относительно нуля, то есть каждое поле может быть либо отрицательным, либо неотрицательным. Ниже представлена схема:

Выписываем векторы и их условия:
- Оба отрицательные: (matrix_base_1 < 0) && (matrix_base_2 < 0)
- Оба неотрицательные: (matrix_base_1 >= 0) && (matrix_base_2 >= 0)
- Первое неотрицательное второе отрицательное: (matrix_base_1 >= 0) && (matrix_base_2 < 0)
- Первое отрицательное, второе неотрицательное: (matrix_base_1 < 0) && (matrix_base_2 >= 0)
- Если в 3 и 4 условиях неверно указать равенство нулю, то как результат - выпадающие элементы и перекрытие векторов.
В примере выше для каждого вектора список выбора ограничен одним пунктом, но их может быть больше.
{
"isStruct": false,
"metaVersion": "2.0.7",
"key": [
"id"
],
"semantic": "",
"name": "selection_provider_matrix_real",
"version": "",
"caption": "\"MATRIX\" с векторами \u003c, \u003e, \u003c\u003d, \u003e\u003d, \u003d от действительного",
"ancestor": null,
"container": null,
"creationTracker": "",
"changeTracker": "",
"history": 0,
"journaling": false,
"compositeIndexes": null,
"properties": [
{
"orderNumber": 10,
"name": "id",
"caption": "Идентификатор",
"type": 12,
"size": null,
"decimals": 0,
"allowedFileTypes": null,
"maxFileCount": 0,
"nullable": false,
"readonly": false,
"indexed": false,
"unique": true,
"autoassigned": true,
"hint": null,
"defaultValue": null,
"refClass": "",
"itemsClass": "",
"backRef": "",
"backColl": "",
"binding": "",
"semantic": null,
"selConditions": [],
"selSorting": [],
"selectionProvider": null,
"indexSearch": false,
"eagerLoading": false,
"formula": null
},
{
"orderNumber": 20,
"name": "matrix_base",
"caption": "Действительное основание для списка выбора матричного типа",
"type": 7,
"size": null,
"decimals": 0,
"allowedFileTypes": null,
"maxFileCount": 0,
"nullable": true,
"readonly": false,
"indexed": false,
"unique": false,
"autoassigned": false,
"hint": null,
"defaultValue": null,
"refClass": "",
"itemsClass": "",
"backRef": "",
"backColl": "",
"binding": "",
"semantic": null,
"selConditions": [],
"selSorting": [],
"selectionProvider": null,
"indexSearch": false,
"eagerLoading": false,
"formula": null
},
{
"orderNumber": 30,
"name": "selection_provider_matrix",
"caption": "Список выбора со сложными условиями",
"type": 6,
"size": null,
"decimals": 0,
"allowedFileTypes": null,
"maxFileCount": 0,
"nullable": false,
"readonly": false,
"indexed": false,
"unique": false,
"autoassigned": false,
"hint": null,
"defaultValue": null,
"refClass": "",
"itemsClass": "",
"backRef": "",
"backColl": "",
"binding": "",
"semantic": null,
"selConditions": [],
"selSorting": [],
"selectionProvider": {
"type": "MATRIX",
"list": [],
"matrix": [
{
"comment": "matrix_base \u003c 3",
"conditions": [
{
"property": "matrix_base",
"operation": 5,
"value": [
"3"
],
"nestedConditions": []
}
],
"result": [
{
"key": "1",
"value": "Сохраним 1 при основании меньше 3"
},
{
"key": "2",
"value": "Сохраним 2 при основании меньше 3"
}
]
},
{
"comment": "matrix_base \u003d 3",
"conditions": [
{
"property": "matrix_base",
"operation": 0,
"value": [
"3"
],
"nestedConditions": []
}
],
"result": [
{
"key": "3",
"value": "Сохраним 3 при основании 3"
}
]
},
{
"comment": "matrix_base \u003e 3 и matrix_base \u003c\u003d 15",
"conditions": [
{
"property": "matrix_base",
"operation": 6,
"value": [
"3"
],
"nestedConditions": []
},
{
"property": "matrix_base",
"operation": 7,
"value": [
"15"
],
"nestedConditions": []
}
],
"result": [
{
"key": "5",
"value": "Сохраним 5 при основании \u003e 3 и \u003c\u003d 15"
},
{
"key": "10",
"value": "Сохраним 10 при основании \u003e 3 и \u003c\u003d 15"
},
{
"key": "15",
"value": "Сохраним 15 при основании \u003e 3 и \u003c\u003d 15"
}
]
},
{
"comment": "matrix_base \u003e\u003d16",
"conditions": [
{
"property": "matrix_base",
"operation": 8,
"value": [
"16"
],
"nestedConditions": []
}
],
"result": [
{
"key": "50",
"value": "Сохраним 50 при основании \u003e\u003d 16"
},
{
"key": "100",
"value": "Сохраним 100 при основании \u003e\u003d16"
},
{
"key": "1000",
"value": "Сохраним 1000 при основании \u003e\u003d16"
},
{
"key": "5000",
"value": "Сохраним 5000 при основании \u003e\u003d16"
}
]
},
{
"comment": "matrix_base \u003e 15 и matrix_base \u003c 16",
"conditions": [
{
"property": "matrix_base",
"operation": 6,
"value": [
"15"
],
"nestedConditions": []
},
{
"property": "matrix_base",
"operation": 5,
"value": [
"16"
],
"nestedConditions": []
}
],
"result": [
{
"key": "0",
"value": "Сохраним 0, если основание где-то между 15 и 16"
}
]
}
],
"parameters": [],
"hq": ""
},
"indexSearch": false,
"eagerLoading": false,
"formula": null
}
]
}
Векторы и их условия:
- matrix_base < 3
- matrix_base = 3
- (matrix_base > 3) && (matrix_base <= 15)
- matrix_base >= 16
- (matrix_base > 15) && (matrix_base < 16)
Сортировка выборки допустимых значений¶
Описание¶
Сортировка выборки допустимых значений - задается при создания сущности в поле "selSorting"
и представляет собой фильтр, который задает способ сортировки объектов. Применяется для атрибутов типа "Ссылка"
.
- Сортировка по возрастанию
- Сортировка по убыванию
JSON¶
{
"orderNumber": 20,
"name": "ref",
"caption": "Ссылка",
"type": 13,
"size": null,
"decimals": 0,
"allowedFileTypes": null,
"maxFileCount": 0,
"nullable": true,
"readonly": false,
"indexed": false,
"unique": false,
"autoassigned": false,
"hint": null,
"defaultValue": null,
"refClass": "selSortingCatalog@develop-and-test",
"itemsClass": "",
"backRef": "",
"backColl": "",
"binding": "",
"semantic": null,
"selConditions": [],
"selSorting": [
{
"property": "string",
"mode": 1
}
],
Описание полей¶
Поле | Наименование | Допустимые значения | Описание |
---|---|---|---|
"property" |
Атрибут | Строка, только латиница без пробелов | Атрибут, по которому будет производится сортировка. |
"mode" |
Порядок сортировки | 0 - по возрастанию | Порядок сортировки |
1 - по убыванию |
Основание коллекции¶
Основание коллекции - атрибут в объекте, по значению которого выполняется поиск объектов в коллекции на основании сравнения с атрибутом обратной ссылки.
Цель использования¶
Основание коллекции может быть использовано для создания динамичных коллекций, когда объекты в коллекции могут быть загружены в зависимости от введенных данных или расчитанных по формуле значений, в отличие от обычных обратных ссылок с поиском только по ключевым атрибутам.
Пример¶
Для примера в проекте develop-and-test заведены два класса:
searchRefs
- в нем добавлен атрибут-строкаcode_binding
в качестве обратной ссылки дляbinding
.{ "orderNumber": 30, "name": "code_binding", "caption": "Код для binding", "type": 0, "size": null, "decimals": 0, "allowedFileTypes": null, "maxFileCount": 0, "nullable": true, "readonly": false, "indexed": true, "unique": false, "autoassigned": false, "hint": null, "defaultValue": null, "refClass": "", "itemsClass": null, "backRef": null, "backColl": "", "binding": "", "semantic": "", "selConditions": null, "selSorting": [], "selectionProvider": null, "indexSearch": false, "eagerLoading": false, "formula": null }
backref_searchRefs
- в этом классе используются атрибутыbackref_searchRefs_binding
иbackref_searchRefs_text
.backref_searchRefs_binding
является динамичной коллекцией, аbackref_searchRefs_text
используется в качестве фильтра для коллекцииbackref_searchRefs_binding
. Выборка в коллекциюbackref_searchRefs_binding
идет по равенству значенийbackref_searchRefs_text
из классаbackref_searchRefs
иcode_binding
из классаsearchRefs
. При добавлении объектов в коллекцию вручную автоматически заполняется атрибутcode_binding
.
{
"orderNumber": 25,
"name": "backref_searchRefs_binding",
"caption": "Обратная ссылка (с подключенным binding) на класс searchRefs",
"type": 14,
"size": null,
"decimals": 0,
"allowedFileTypes": null,
"maxFileCount": 0,
"nullable": true,
"readonly": false,
"indexed": false,
"unique": false,
"autoassigned": false,
"hint": null,
"defaultValue": null,
"refClass": "",
"itemsClass": "searchRefs",
"backRef": "code_binding",
"backColl": "",
"binding": "backref_searchRefs_text",
"semantic": null,
"selConditions": null,
"selSorting": [],
"selectionProvider": null,
"indexSearch": false,
"eagerLoading": false,
"formula": null
},
{
"orderNumber": 30,
"name": "backref_searchRefs_text",
"caption": "Значение",
"type": 0,
"size": null,
"decimals": 0,
"allowedFileTypes": null,
"maxFileCount": 0,
"nullable": true,
"readonly": false,
"indexed": true,
"unique": false,
"autoassigned": false,
"hint": null,
"defaultValue": null,
"refClass": "",
"itemsClass": "",
"backRef": "",
"backColl": "",
"binding": "",
"semantic": null,
"selConditions": null,
"selSorting": [],
"selectionProvider": null,
"indexSearch": false,
"eagerLoading": false,
"formula": null
}
Предварительная выборка¶
Предварительная выборка объектов загрузки (от англ. eager loading - «жадная загрузка») - процесс, который позволяет указать в запросе какие связанные данные, в объёме достаточном для корректного отображения семантики связанного объекта, необходимо загрузить при выполнении запроса.
Предварительная выборка помогает в отображении объектов системы в тех случаях, когда данные находятся на большом уровне вложенности, например в атрибутах типа «Ссылка» и «Коллекция».
В мете применяется только в особых случаях и используется в основном для экономии временных ресурсов, в качестве альтернативы тонкой настройки.
Пример¶
Управление предварительной выборкой для атрибута определяется свойством eagerLoading
принимающим значения true
или false
.
"properties": [
{
...
"eagerLoading": true,
"formula": null
}
Настройка¶
Рекомендуемый способ настройки предварительной выборки - через файл deploy.json
проекта для атрибутов класса, навигации. Это позволит централизовано определить предварительно выбираемые атрибуты для многих классов.
"eagerLoading": {
"node1": {
"class1": {
"list": ["attr1", "attr2.attr3"],
"item": ["attr1", "attr2.attr3"]
}
}
}
NB: Если вместо "node1"
поставить "*"
, то при попадании из любой навигации на данный объект заявления можно использовать одну настройку класса для экспорта объекта.
Настройка для экспорта в списках и формах¶
Принцип настройки предварительной выборки для экспорта в списках и формах совпадает с настройкой в файле deploy.json, за одним исключением. Вместо list
и item
, указываем exportList
и exportItem
.
"eagerLoading": {
"class1@ns": {
"exportList": ["attr1", "attr2.attr3"]
},
"class1@ns": {
"exportItem": ["attr1", "attr2.attr3.attr4"]
}
}
Глубина предварительной выборки объектов загрузки¶
Глубина предварительной выборки задаётся свойством maxEagerDepth: 1
в файле deploy.json
проекта.
Максимальная глубина предварительной выборки определяет максимально допустимый уровень вложенности объекта относительно открытого объекта на странице.
Семантика¶
Семантика - используется для вывода объекта класса в качестве одной строки заголовка класса.
В мете классов поле "semantic"
встречается дважды:
- в общей части меты класса, где формирует строковое представление для данного класса,
- в мете атрибута класса, где формирует строковое представление объектов класса, на который ссылается атрибут, т.е. используется для ссылочных атрибутов.
Цель использования¶
Используется для корректировки отображения атрибутов и значений атрибутов в списке. В атрибутах, которые выводят табличные данные, семантика используется для ограничения вывода колонок.
Примеры использования в ссылочных атрибутах¶
Например, есть класс class
, у которого есть атрибуты: id
, name
, link
, date
. Есть второй класс classTable
, у которого есть ссылочный атрибут table
на класс class
.
Без использования семантики в объектах класса classTable
в атрибуте table
будут выводится значения идентификаторов объектов класса class
.
Атрибуты, используемые как идентификаторы, указаны в мете класса class
.
Чтобы вывести значения атрибутов name
и link
в атрибуте table
, а не значения идентификаторов, нужно прописать "semantic": "name|link"
. В зависимости от типа атрибута результат будет разный:
- Если атрибут
table
является ссылкой, то в нем будут заполнены значения атрибутовname
иlink
через пробел. Тут можно использовать дополнительные слова и выражения через знак|
, например"semantic": "name|, |link"
или"semantic": "У объекта есть 2 атрибута:|name|, |link"
. - Если атрибут
table
является коллекцией объектов классаclass
, то в нем будут выведеные колонкиname
иlink
.
Формат отображения в семантике¶
Можно обрезать вывод с помощью:
[]
."name[0,50]|..." Указываем позицию и количество выводимых букв из семантики атрибута. Из атрибута name выводим 50 символов семантики (значение атрибута), начиная с первого.
Доступно разыменование через
.
т.е. доступ во вложенный объект."semantic": "digitalTV|kachestvoCTB|analogTV.name|kachestvoAnal|period" где ``analogTV`` - ссылочный атрибут класса, для которого задается семантика, а ``name`` - атрибут класса по ссылке.
Отображение семантики на форме¶
- В списках первого уровня (открываемые непосредственно по узлу навигации), в качестве заголовка выводим только значение из поля «caption» узла навигации.
- В списках выбора в заголовок выводим только значение из поля «caption» класса объектов списка.
- В форме редактирования в заголовок выводим только семантику объекта.
- В форме создания в заголовок выводим только значение из поля «caption» класса.
- В списках выбора над заголовком мелким шрифтом выводим строку «Выбор значения атрибута <…> объекта <…>».
- В форме создания, если создается объект в коллекции или ссылке, над заголовком мелким шрифтом выводим строку «Создание объекта в коллекции/по ссылке <…> объекта <…>».
Атрибутивная часть меты класса описывает поля атрибута класса. Атрибутов в классе обычно минимум два - ключевое поле и поле данных. Они содержатся в виде массива в поле "properties"
основной части меты классов. Каждый атрибут - это объект следующей структуры:
JSON¶
{
"orderNumber": 20,
"name": "integer_integer",
"caption": "Редактор целых чисел [14]",
"type": 6,
"size": null,
"decimals": 0,
"allowedFileTypes": null,
"maxFileCount": 0,
"nullable": true,
"readonly": false,
"indexed": false,
"unique": false,
"autoassigned": false,
"hint": null,
"defaultValue": null,
"refClass": "",
"itemsClass": "",
"backRef": "",
"backColl": "",
"binding": "",
"semantic": null,
"selConditions": [],
"selSorting": [],
"selectionProvider": null,
"indexSearch": false,
"eagerLoading": false,
"formula": null,
"cached": true
}
Описание полей¶
Код | Имя | Допустимые значения | Описание |
---|---|---|---|
"orderNumber" |
Порядковый номер | Целое неотрицательное | Задает расположение атрибута относительно других атрибутов этого же класса. |
"name" |
Системное имя | Строка, только латиница без пробелов | Указывается имя атрибута, с которым будет работать система, а значит не может быть пустым, может содержитать только символовы латинского алфавита, без пробелов (задается один раз при создании атрибута). В последующем поменять имя нельзя. |
"caption" |
Логическое имя | Строка | Отображение имени атрибута в пользовательском интерфейсе. |
"type" |
Тип | Целое - идентификатор (код) типа | Тип данных атрибута. См. Типы атрибутов |
"size" |
Размер | Целое положительное | Максимальный размер данных атрибута, допистимые значения зависят от типа атрибута. |
"decimals" |
Число знаков после запятой | Целое неотрицательное | Число знаков после запятой, задается только для типа «Десятичное [8]». |
"allowedFileTypes" |
Допустимые типы файлов | Массив строк | Позволяет задать допустимые расширения файлов, которые пользователь может загрузить в атрибут типа «Коллекция файлов [110]». |
"maxFileCount" |
Максимальное количество файлов | Число от 1 до 5 | Задает максимальное количество файлов, которые пользователь может загрузить в атрибут типа «Коллекция файлов [110]». |
"nullable" |
Допустимо пустое значение | Логический | Разрешает или запрещает пустое значение атрибута. |
"readonly" |
Только для чтения | Логический | Разрешает или запрещает изменять значение атрибута. |
"indexed" |
Индексация для поиска | Логический | Указывает, нужно ли индексировать значения данного атрибута для ускорения поиска. |
"unique" |
Уникальные значения | Логический | Для атрибута накладывает ограничение уникальности (Внимание: нельзя создать два объекта класса с одинаковыми значениями в уникальном атрибуте). |
"autoassigned" |
Автозаполнение | Логический | Разрешает или запрещает автоматическое заполнение поля приложением. |
"hint" |
Подсказка | Строка | Задает сообщение, которые выведется в пользовательском интерфейсе рядом с именем атрибута. |
"defaultValue" |
Значение по умолчанию | Зависит от типа атрибута | Указывается значение, которое будет заполнено в атрибуте в форме создания (при создании объекта). |
"refClass" |
Атрибут ссылки | Строка, только латиница, без пробелов | Содержит значение поля "name" (Системное имя) класса, который должен использоваться в атрибуте типа «Ссылка [13]». |
"itemsClass" |
Атрибут коллекции | Строка, только латиница без пробелов | Содержит значение поля "name" (Системное имя) класса, объекты которого могут привязаться к атрибуту типа «Коллекция [14]» |
"backRef" |
Атрибут обратной ссылки | Строка, только латиница без пробелов | Указывается атрибут типа «Ссылка [13]», из класса, указанного в свойстве Класс коллекции, который ссылается на исходный класс. Нужно для фильтрации и привязки объектов из класса Класс коллекции по значению ссылочного атрибута. |
"backColl" |
Атрибут обратной коллекции | Строка, только латиница без пробелов | Указывается атрибут типа «Коллекция [14]», из класса, указанного в свойстве Класс коллекции, который ссылается на исходный класс. Нужно для фильтрации и привязки объектов из класса Класс коллекции по значению ссылочного атрибута. |
"binding" |
Основание коллекции | Строка, только латиница без пробелов | Указывается атрибут класса, к которому привязывается атрибут обратной ссылки. Если не указан, то принимается ключевой атрибут. |
"semantic" |
Семантика | Строка | Указывается для ссылочных атрибутов для того, чтобы выводить и формировать информацию из ссылочного класса, корректную для описания артибута в объекте исходного класса. |
"selConditions" |
Условия отбора допустимых значений | Null либо массив объектов | Позволяет ограничить выбор объектов по ссылке, допустимых для привязкки в данном ссылочном атрибуте. |
"selSorting" |
Сортировка выборки допустимых значений | Null либо массив объектов | Позволяет сортировать выбор объектов по ссылке, допустимых для привязкки в данном ссылочном атрибуте. |
"selectionProvider" |
Список выбора допустимых значений | Null либо объект | Задает список выбора допустимых значений для атрибута. |
"indexSearch" |
Полнотекстовый поиск | Логический | Признак использования атрибута в полнотекстовом поиске. Указывает, что значение данного атрибута должно индексироваться поисковой системой. См. Индексация |
"eagerLoading" |
Жадная загрузка | Логический | Загрузка достаточного объема данных объекта по ссылке (для атрибутов типа ссылка и коллекция). |
"formula" |
Вычисляемые поля | Null либо объект | Указывает на формулу расчета. |
"cached" |
Кеширование значения вычислимого атрибута | Логический | Применяется только для значений атрибута, полученных с помощью вычисления по формуле. Указывает на возможность кеширования значения вычислимого атрибута. |
Мета навигации¶
Мета навигации - регулирует расположение элементов в навигационном блоке.
Мета навигации разделяется на мету узлов навигации и мету секции навигации.
Мета секций навигации¶
Мета секций навигации состоит из поля "name" + .section.json
и находится в директории navigation
.
Например: workflow.section.json
.
Мета узлов навигации¶
Мета узлов навигации состоит из:
- Для узлов навигации первого порядка - тех узлов, которые находятся непосредственно в секции навигации: поле
"code"
+.json
и находится в директории, имя которой совпадает с именем файла секции навигации к которому относится узел навигации.
Например: В директории navigation
есть файл секции навигации simpleTypes.section.json
. И есть узел навигации classString.json
, который размещается в секции simpleTypes
. Файл узла навигации будет иметь путь: navigation\simpleTypes\classString.json
.
- Для узлов навигации второго порядка - тех узлов, которые входят в группу (особый тип узлов навигации, поле
"type"
в которых содержит значение0
). Разница в том, что поле"code"
у таких узлов составное и состоит из поля"code"
группы и личного наименования.
Например: navigation\relations\classReference.refBase.json
. Это файл узла навигации refBase
, который находится в группе classReferense
секции навигации relations
.
Условия выборки - "conditions"
¶
Условия выборки "conditions"
- это фильтры при открытии списка объектов.
Перед открытием любой страницы, в реестрах происходит считывание фильтров, которые подходят для данного окна. Подходящие фильтры состоят из двух частей:
- Общие фильтры, которые применимы для всех классов.
- Фильтры, сохраненные конкретно для данного класса.
Общие фильтры для всех классов - это фильтры, которые отображаются для всех открываемых классов. Их отличие в коде в том, что в атрибуте класса у общего фильтра стоит ключевое слово ALL
, у персональных фильтров в этом атрибуте стоит название класса, для которого он применим.
Чтобы сделать фильтр для всех классов, при сохранении поставьте «Для всех классов».
Чтобы создать фильтр для конкретного класса, откройте объекты этого класса, сгенерируйте фильтр и сохраните его убедившись, что поле «Для всех классов» не отмечено.
Реализована единая спецификация выражений, как для вычисляемых выражений, так и для условий отбора и расчетов в агрегации.
В основном работаем с файлом _list-filter-ui - именно он запускает поиск нужных фильтров, а также разбирает текущие данные для создания новых фильтров. В файле _list-filter-ui описано какие атрибуты могут участвовать в создании фильтров и как именно они должны выглядеть и сохраняться (например, дата и чекбокс выглядят по разному).
В параметре cond
находятся данные фильтра, которые в последствие подставляются в условие для поиска (в файле _metaCRUD.js).
if (cond !== undefined && cond !== '' && cond !== 'undefined') {
var condObj = JSON.parse(cond);
if (Array.isArray(condObj) && condObj.length > 0) {
for (var k = 0; k < condObj.length; k++) {
if (condObj[k].type === 6) {
condObj[k].value = new Date(condObj[k].value);
}
where[condObj[k].property] = getwherebyOperation(condObj[k]);
}
}
}
NB: новые фильтры - min
и max
расширяют возможности создания фильтров и условий в меню.
Необходимая мета для работы - это класс фильтров ion_filter
. Он находится в папке calc
, которая по умолчанию является папкой с классами и метой для системы. Кроме одного класса ничего более не нужно. Пересмотреть
Если поиск идет по принципу равно или содержит - то ищется в семантике этого объекта. Если поиск идет по принципу - максимум/минимум - то ищем уже значение поля. Таким образом, есть возможность поиска в ссылочных атрибутах, при этом без лишних запросов к базе, что повышает производительность.
[{property:okatoNasPunkta_title,operation:20,value:Лес,title:Населенный пункт содержит Лес,type:2}]
Есть возможность не только выдавать отсортированные данные в списке из условий меню, но и ограничивать выборки, т.е. применять фильтры.
{
"code": "passportObject.naselenie",
"type": 1,
"orderNumber": 10,
"caption": "Население",
"classname": "naselenie",
"container": null,
"collection": null,
"conditions": [
{"property": "god"
,"operation": 10}
],
"sorting": [],
"pathChains": []
}
Атрибут conditions
содержит два объекта:
property
- свойство, по которому происходит фильтрацияoperation
- операция фильтрации
В данном случае этот фильтр имеет такой смысл - показать все объекты класса ``naselenie`` с минимальным годом.
Если нужно указать значение, то третьим атрибутом пойдет value
и значение для поиска.
Например:
{"property": "god"
,"operation": 0
, "value": 2015}
Страницей класса для узла навигации является родительский класс. Если при переходе по данной навигации необходимо отображать объекты класса наследника данного класса, то применяется фильтр вида:
{
property: "atr1.__class",
operation: 0,
value: ["childClass@ns"]
}
где atr1.__class
- атрибут родительского класса, по которому идет выборка объектов, childClass
- наследник, объекты которого отображаются в навигации. То есть - показать на форме списка только те объекты, у которых атрибут ``atr1`` является объектом класса-наследника ``childClass``.
Поле | Наименование | Допустимые значения | Описание |
---|---|---|---|
"property" |
Атрибут | Строка, только латиница без пробелов | Атрибут класса, значение поля которого проверяется на соответствие данному условию данного вектора. |
"operation" |
Операция | Код операции | Операция, согласно которой производится определение. |
0 - равно (И) | |||
1 - не равно (ИЛИ) | |||
2 - пусто (НЕ) | |||
3 - не пусто (МИН ИЗ) | |||
4 - (МАКС ИЗ) | |||
5 - < () | |||
6 - > | |||
7 - <= | |||
8 - >= | |||
9 - IN /Похож/ | |||
10 - содержит | |||
"value" |
Значение | Зависит от типа операции | Второе значение для бинарных операций |
"nestedConditions" |
Вложенные условия отбора | Объект, структура аналогична структуре самого объекта условий отбора. |
NB: код операции соответствует разным значениям операций, в зависимости от того, выбран атрибут или нет. Если поле "property"
равно null
, то кодируется логическое условие, по которому объединяются вложенные условия отбора (указаны в скобках в таблице выше).
код | значение | системное имя |
---|---|---|
8 | Создаем дату | DATE |
9 | Добавляем к дате интервал | DATEADD |
10 | Находим интервал между датами | DATEDIFF |
12 | Вычитание | |
24 | День месяца |
Аргументы DATEADD
: дата, интервал, ед.изм интервала [ms, s, min, h, d, m, y] (по умолчанию - день(d))
Аргументы DATEDIFF
: конечная дата, начальная дата, ед. изм. результата [ms, s, min, h, d, m, y] (по умолчанию - день(d)), логический флаг приведения к целому числу
Настройка выборки объектов в списке с возможностью сравнения значения даты с любым месяцем года. Например, настройка фильтра таким образом, чтобы в навигации показывались только те объекты, у которых значение атрибута «Дата окончания» - текущий месяц.
Для этого вычисляется начало текущего месяца. После этого к нему можно добавлять или вычитать произвольное колличество месяцев и сравнивать полученный результат с необходимой датой.
Вычисление конца текущего месяца:
{
"property": null,
"operation": 9,
"value": null,
"nestedConditions": [
{
"property": null,
"operation": 9,
"value": null,
"nestedConditions": [
{
"property": null,
"operation": 8,
"value": ["today"],
"nestedConditions": []
},
{
"property": null,
"operation": 12,
"value": null,
"nestedConditions": [
{
"property": null,
"operation": null,
"value": [0],
"nestedConditions": []
},
{
"property": null,
"operation": 24,
"value": null,
"nestedConditions": [
{
"property": null,
"operation": 8,
"value": ["today"],
"nestedConditions": []
}
]
}
]
},
{
"property": null,
"operation": null,
"value": ["d"],
"nestedConditions": []
}
]
},
{
"property": null,
"operation": null,
"value": [1],
"nestedConditions": []
},
{
"property": null,
"operation": null,
"value": ["m"],
"nestedConditions": []
}
]
}
- Для начала вычисляется значение дня месяца для текущей даты:
{
"property": null,
"operation": 24,
"value": null,
"nestedConditions": [
{
"property": null,
"operation": 8,
"value": ["today"],
"nestedConditions": []
}
]
}
- Получено условное значение «d». Далее необходимо отнять полученное значение от 0 (0-d):
{
"property": null,
"operation": 12,
"value": null,
"nestedConditions": [
{
"property": null,
"operation": null,
"value": [0],
"nestedConditions": []
},
{
"property": null,
"operation": 24,
"value": null,
"nestedConditions": [
{
"property": null,
"operation": 8,
"value": ["today"],
"nestedConditions": []
}
]
}
]
}
- Получено условное значение «-d». Далее к текущей дате прибавляется значение «-d» дней:
{
"property": null,
"operation": 9,
"value": null,
"nestedConditions": [
{
"property": null,
"operation": 8,
"value": ["today"],
"nestedConditions": []
},
{
"property": null,
"operation": 12,
"value": null,
"nestedConditions": [
{
"property": null,
"operation": null,
"value": [0],
"nestedConditions": []
},
{
"property": null,
"operation": 24,
"value": null,
"nestedConditions": [
{
"property": null,
"operation": 8,
"value": ["today"],
"nestedConditions": []
}
]
}
]
},
{
"property": null,
"operation": null,
"value": ["d"],
"nestedConditions": []
}
]
}
- Получено начало текущего месяца.
- Для вычисления конца текущего месяца нужно прибавить к полученному значению начала месяца 1 месяц:
{
"property": "date",
"operation": 5,
"value": null,
"nestedConditions": [
{
"property": null,
"operation": 9,
"value": null,
"nestedConditions": [
{
"property": null,
"operation": 9,
"value": null,
"nestedConditions": [
{
"property": null,
"operation": 8,
"value": ["today"],
"nestedConditions": []
},
{
"property": null,
"operation": 12,
"value": null,
"nestedConditions": [
{
"property": null,
"operation": null,
"value": [0],
"nestedConditions": []
},
{
"property": null,
"operation": 24,
"value": null,
"nestedConditions": [
{
"property": null,
"operation": 8,
"value": ["today"],
"nestedConditions": []
}
]
}
]
},
{
"property": null,
"operation": null,
"value": ["d"],
"nestedConditions": []
}
]
},
{
"property": null,
"operation": null,
"value": [1],
"nestedConditions": []
},
{
"property": null,
"operation": null,
"value": ["m"],
"nestedConditions": []
}
]
}
]
}
Мета узлов навигации¶
{
"code": "classDatetime",
"orderNumber": 0,
"type": 1,
"caption": "Класс \"Дата/Время [9]\"",
"classname": "classDatetime",
"container": null,
"collection": null,
"url": null,
"external": true,
"hint": null,
"conditions": [],
"sorting": [],
"eagerLoading": {
"list": { // Здесь задается жадная загрузка для списков
"internet": ["okato"],
"someClass1": ["refAttr1", "refAttr2.refAttr3"],
"someClass2": ["colAttr4"]
},
"item": { // Здесь задается жадная загрузка для форм редактирования
"internet": ["okato", "standart"],
"someClass1": ["refAttr1", "refAttr2.refAttr3", "refAttr5", "colAttr4"],
"someClass2": ["colAttr4"]
}
},
"pathChains": [],
"searchOptions": null
"metaVersion": "2.0.7"
}
Поле | Наименование | Допустимые значения | Описание |
---|---|---|---|
"code" |
Системное имя | Строка латиницей, без пробелов | Системное имя узла навигации может быть составным, если принадлежит узлу навигации типа Группа [0]. |
"orderNumber" |
Порядковый номер | Целое число | Задает порядок сортировки пунктов меню в пределах секции навигации |
"type" |
Тип | Целое число | Задает логику работы пункта меню, выводимые при переходе/активации значения. Накладывает ограничения на прочие поля меты узла навигации. |
0 | Группа. Объединяет в себе другие узлы навигации по какому-либо общему признаку, не является страницей класса. | ||
1 | Страница класса. Отображает структуру и объекты класса, заданного в поле «classname». | ||
2 | Страница контейнера. Выполняет отображение списка объектов в коллекции. Для таких узлов навигации нужно указывать класс и идентификатор объекта-контейнера, а также имя атрибута коллекции. | ||
3 | Гиперссылка. Осуществляет переход на ссылку, заданную в поле «url» | ||
"title" |
Заголовок | Строка | Позволяет дополнительно указать заголовок страницы. |
"caption" |
Логическое имя | Строка | Наименование узла навигации отображаемое в интерфейсе. |
"classname" |
Класс | Строка латиницей, без пробелов | Если «Тип» - «Страница класса (1)», то поле обязательно к заполнению. |
"container" |
ID контейнера | Строка или null | Идентификатор объекта содержащего коллекцию отображаемую на странице. |
"collection" |
Атрибут коллекции | Строка или null | Имя атрибута коллекции, содержимое которого надо вывести на странице. |
"url" |
URL | Гиперссылка (принимает любые строки) | Если «Тип» - «Гиперссылка (3)», то поле обязательно к заполнению. |
"external" |
Признак внешнего ресурса | Логический | Открывает страницу по ссылке в новом окне, если присвоено значение true . |
"hint" |
Подсказка | Строка | Текст, заданный в этой строке, отображается при наведении на узел навигации, которому она принадлежит. |
"conditions" |
Условия выборки | Массив объектов | Фильтр при открытии списка объектов. Используется для узлов типа «Страница класса» и «Страница контейнера». |
"sorting" |
Сортировка | Массив объектов | Используется для узлов типа «Страница класса» и «Страница контейнера». Здесь задаются параметры сортировки объектов в списке. Параметры задаются аналогично настройкам сортировки и выборки допустимых значений в атрибутах. |
"eagerLoading" |
Жадная загрузка | Объект | Настройка жадной загрузки в навигации. Если нужна ЖЗ для класса по всем навигациям, то правильнее ее задавать в файле deploy.json. Поэтому данный параметр используется редко. |
"pathChains" |
Хлебные крошки | Массив объектов | Здесь задается логика формирования «иерархической» навигации от страницы объекта к вышестоящим объектам. Может быть использовано конкретной реализацией ION-приложения для оптимизации навигации. |
"searchOptions" |
Поиск в узле навигации | Массив объектов | На уровне класса определяет как искать объекты класса из представления списка: по вхождению слов или полные слова, по отдельным атрибутам или по указанным атрибутам в списке с параметрами поиска через пробел. |
"metaVersion" |
Версия меты | Строка | Версия метаданных. |
"searchOptions": {
"person": {
"searchBy": [ // атрибуты по которым ищем, по умолчанию то, что выводится в колонках
"surname",
"name",
"patronymic"
],
"splitBy": "\\s+", // разбивать поисковую фразу на регулярное выражение, части сопоставить с атрибутами
"mode": ["starts", "starts", "starts"], // режимы сопоставления - в данном случае "начинается с" (доступны like, contains, starts, ends)
"joinBy": "and" // режим объединения условий на атрибуты (по умолчанию or)
}
}
{
"_id" : ObjectId("578f07aa0ce0024ce143e71e"),
"code" : "classDatetime",
"orderNumber" : 0,
"type" : 1,
"caption" : "Класс \"Дата/Время [9]\"",
"classname" : "classDatetime",
"container" : null,
"collection" : null,
"url" : null,
"hint" : null,
"conditions" : [],
"sorting" : [],
"pathChains" : [],
"itemType" : "node",
"section" : "simpleTypes",
"namespace" : ""
}
Мета секций навигации¶
{
"caption": "Простые типы",
"name": "simpleTypes",
"mode": 0,
"tags": null
}
Поле | Наименование | Допустимые значения | Описание |
---|---|---|---|
"caption" |
Логическое имя | Строка | Наименование секции навигации отображаемое в интерфейсе. |
"name" |
Системное имя | Строка латиницей, без пробелов | Задает в том числе первую часть имени файла меты секции навигации, служебное имя. |
"mode" |
Режим отображения | Меню: 0 | Задает режим отображения меню. |
Содержание: 1 | |||
Ниспадающий список: 2 | |||
Иерархия: 3 | |||
"tags" |
Теги | Массив строк либо null. | Теги. Могут определять дополнительные свойства секции, влиять на отображение. Не реализовано. |
{
"_id" : ObjectId("578f07aa0ce0024ce143e720"),
"caption" : "Простые типы",
"name" : "simpleTypes",
"mode" : 0,
"tags" : null,
"itemType" : "section",
"namespace" : ""
}
Заголовок страницы - "title"
¶
Поле «title» необходимо, чтобы задать отличный от поля "caption"
заголовок страницы в меню навигации.
- Для формирования заголовка страницы в первую очередь используется значение поля
"title"
соответствующего узла навигации. Если поле"title"
не задано - пустая строка, то для формирования заголовка страницы используется поле"caption"
меты узла навигации. - Для формирования заголовка страницы на страницах списка выбора (при открытии списка класса справочника из форм) используется
"caption"
общей части меты класса.
{
"code": "administrations.municipals",
"orderNumber": 0,
"type": 1,
"title": "Администрации муниципальных районов", \\ отличается от наименования узла навигации поля `"caption"`
"caption": "Муниципальные районы",
"classname": "Organisation",
"container": null,
"collection": null,
"url": null,
"hint": "Список администраций муниципальных районов",
"conditions": [],
"sorting": [],
}
Мета отчёта¶
Пример простого полного отчета¶
name: support
caption: Отчет по заявкам в техническую поддержку
sources:
- name: task
caption: Заявка
load:
- className: task
results:
- field: id
expr: $id
- field: date
expr: $dateCreate
- field: typeComunication
expr:
if:
- eq:
- $typeComunication
- call
- 'Звонок'
- if:
- eq:
- $typeComunication
- metting
- 'Встреча'
- if:
- eq:
- $typeComunication
- letter
- 'Письмо'
- if:
- eq:
- $typeComunication
- mail
- 'E-mail'
- ' '
- field: typeTask
expr:
if:
- eq:
- $typeTask
- question
- 'Консультация'
- if:
- eq:
- $typeTask
- problem
- 'Инцидент'
- if:
- eq:
- $typeTask
- offer
- 'Предложение'
- ' '
- field: predmetSupport
expr: $support.name
- field: temaTask
expr:
if:
- nempty:
- $supportScenario0
- $supportScenario0.name
- ' '
- field: nameClassification
expr:
if:
- nempty:
- $supportScenario1
- $supportScenario1.name
- if:
- nempty:
- $supportScenario2
- $supportScenario2.name
- if:
- nempty:
- $supportScenario3
- $supportScenario3.name
- if:
- nempty:
- $supportScenario4
- $supportScenario4.name
- if:
- nempty:
- $supportScenario5
- $supportScenario5.name
- if:
- nempty:
- $supportScenario6
- $supportScenario6.name
- ' '
- field: coment
expr: $comment
index:
- id
- name: support
caption: Заявки в техническую поддержку
load:
- source: task
joins:
- table: date
alias: da
left: id
right: id
- table: typeComunication
alias: comun
left: id
right: id
- table: typeTask
alias: ta
left: id
right: id
- table: predmetSupport
alias: sup
left: id
right: id
- table: coment
alias: com
left: id
right: id
results:
- field: id
expr: $id
- field: date
expr: $date
- field: typeComunication
expr: $typeComunication
- field: typeTask
expr: $typeTask
- field: predmetSupport
expr: $predmetSupport
- field: temaTask
expr: $temaTask
- field: nameClassification
expr: $nameClassification
- field: coment
expr: $coment
reports:
- name: technicalSupport
caption: Заявки ТП
sheets:
- name: technicalSupport
caption: Заявки в техническую поддержку
type: aggregation
source: support
fetch:
date: $date
typeComunication: $typeComunication
typeTask: $typeTask
predmetSupport: $predmetSupport
temaTask: $temaTask
nameClassification: $nameClassification
coment: $coment
rangeFilters:
date:
caption: За период с|по
format: date
inclusive: both
columns:
- field: date
caption: Дата создания
- field: typeComunication
caption: Тип коммуникации
- field: typeTask
caption: Тип заявки
- field: predmetSupport
caption: Предмет поддержки
- field: temaTask
caption: Тема заявки
- field: nameClassification
caption: Наименование классификации
- field: coment
caption: Комментарий
Описание¶
Мета отчёта - предназначена для построения шахты данных, содержащей аналитическую информацию по данным из меты системы, организованную в виде таблиц. В мете модуля отчетов указываются источники данных, на основе которых формируется информация для построения отчета, и в дальнейшем формирование колонок таблицы отчета, с указанием ресурса на данные из метаклассов системы.
Мета модуля отчетов находится в папке bi
проекта в формате YML.
NB: Определение «Шахта данных»
Шахта данных - (смежный термин от англ. Data Mining - глубинный анализ данных)
это некое хранилище, которое содержит глубинную аналитическую информацию
обо всех источниках данных и информацию для построения отчетов,
организованную в виде таблиц.
Пример YML¶
name: reportTest
caption: Тестовые данные
sources:
- name: dataSource
caption: Источник данных
load:
- className: sourceClass
results:
- field: id
expr: $id
- field: date
expr: $dateCreate
- field: name
expr: $nameObject
index:
- id
- name: test
caption: Отчет тестовый
load:
- source: dataTest
joins:
- table: date
alias: da
left: id
right: id
results:
- field: id
expr: $id
- field: date
expr: $date
- field: name
expr: $name
reports:
- name: reportTest
caption: Отчет тестовый
sheets:
- name: reportTest
caption: Отчет тестовый
type: aggregation
source: test
fetch:
date: $date
rangeFilters:
date:
caption: За период с|по
format: date
inclusive: both
columns:
- field: date
caption: Дата создания
- field: name
caption: Наименование
Описание примера¶
Отчет тестовый содержит в себе данные из класса «sourceClass». Источник данных «dataSource» извлекает данные из меты соответствующего класса, которые указаны в свойстве results:
. Далее подраздел «test» на основе данных, полученных из источника, указанного в свойстве source:
формирует и преобразовывает данные для корректного отображения в таблицах отчета. Свойство joins:
задает атрибут, который является идентификатором для построения отчета (в данном случае id объекта).
Далее система формирует таблицы отчета, на основе преобразованных данных из источника, в разделе reports:
. Свойство rangeFilters:
содержит информацию о фильтрах, настраиваемых для отчета (в данном случае необходимо указать диапазон дат, в соответствии с данными из класса). В модуле фильтр по диапазону задается через параметры запроса: ?rangeFld[]=0&rangeFld[]=5
, где rangeFld - это поле по которому ищем. Если идет поиск по датам - дату передавать в формате локали, которая передается в http-заголовке 'accept-language'
, либо в формате ISO8601
. Свойство columns:
позволяет формировать колонки таблицы (порядковые номера фактические).
Результат: таблица из двух колонок (Дата и Наименование), в которой будут выводится объекты класса из источника _»dataSource»_ , в соответствии с фильтром по датам, настроенном в rangeFilters:, а количество объектов в таблице будет равно количеству значений идентификатора, настроенном в свойстве joins:.
Пример простого полного отчета можно посмотреть здесь.
Настройка строгости сравнения¶
Настройка строгости сравнения на границах интервала rangeFilters
в отчете:
"rangeFilters": {
"regDate": {
"caption": "За период с|по",
"format": "date",
"inclusive": "both" | "left" | "right"
}
}
both
- обе границы могут быть равны искомым значениям
left
- левая граница (меньшая) может быть равна искомым значениям
right
- правая граница (большая) может быть равна искомым значениям
Если inclusive
не указан - сравнение строгое на обоих границах.
Иерархическая сборка¶
Настройка иерархической сборки необходима для обработки исходных данных при сборке шахты:
- Чтобы сделать в одном источнике данных выгрузку данных по всей иерархии в базе
- Чтобы вывести данные по первому столбцу с отступами в зависимости от глубины вложенности
Настройка иерархической сборки в шахте данных:¶
В конфигурации источника настройка "hierarchyBy"
представляет собой объект с набором свойств: id
, parent
, level
, order
.
hierarchyBy:
id: guidProj
parent: basicobj1.guidObj
level: objLevel
order: objOrder
где id
- атрибут в данных, идентифицирующий элемент иерархии
parent
- атрибут в данных, содержащий идентификатор родительского элемента
level
- атрибут в результирующем источнике, куда будет записан уровень вложенности элемента
order
- атрибут в результирующем источнике, куда будет записано значение для упорядочивания иерархии при отображении.
Поля objLevel
и objOrder
это поля для записи значения (их не надо считать, агрегировать и т.д.)
Пример YML¶
reports:
- name: roadmap
caption: Дорожная карта
sheets:
- name: roadmap
caption: >-
Дорожная карта
type: aggregation
needFilterSet: true
needFilterMessage: Выберите проект
styles:
objLevel:
1: text-indent-1
2: text-indent-2
3: text-indent-3
nameObjIndex:
"3": level2
"2": level1
"1": level0
"0": level0
source: roadmapSource
fetch:
objLevel: $objLevel
guidObj: $guidObj
numLevelObj: $numLevelObj
...
NB: Иерархическая сборка возможна только на основе источника и невозможна на основе класса.
Алгоритм сборки:¶
- Создаем результирующий источник.
- Делаем выборку корневых элементов, у которых пустое поле
parent
. - Перебираем и записываем элементы в результирующий источник (при этом в спецатрибут
element_id
- идентификатор (id) обьекта, вlevel
- значение 0, вorder
- приведенный к строке порядковый номер элемента в выборке, дополненный до длины 6 символов лидирующими нолями). - Итеративно делаем выборки следующих уровней вложенности (начиная с 0), до тех пор пока на очередной итерации не будет извлечено 0 объектов. Выборки делаются путем объединения исходного источника с результирующим по связи
parent = element_id
и ограничениюlevel=текущий уровень
вложенности. - На каждой итерации перебираем и записываем элементы в результирующий сорс, при этом:
- в спецатрибут
element_id
пишем идентфикатор (id) обьекта, - в
level
пишем текущий уровень вложенности, - в
order
пишем конкатенацию order родительского элемента и приведенного к строке порядкового номера элемента в выборке, дополненного до длины 6 символов лидирующими нолями.
- в спецатрибут
Настройка скрытия объектов¶
Настройка скрытия всех объектов, если табличные фильтры не заданы. Чтобы при открытии отчета все объекты скрывались, пока не будет выбрано значение из списка в фильтре необходимо для него применить настройку "needFilterSet: true"
.
Отображение в заголовке отчета параметров выборки посредством паттернов¶
Пример YML¶
...
byPeriod:
sum:
- if:
- and:
- gte:
- $date
- ':since' # берем из params->since
- lte:
- $date
- ':till' # берем из params->till
- $amount
- 0
byMonth:
sum:
- if:
- and:
- eq:
- month:
- dateAdd:
- $date
- 10
- h
- ':month' # берем из params->month
- eq:
- year:
- dateAdd:
- $date
- 10
- h
- ':year' # берем из params->year
- $amount
- 0
byYear:
sum:
- if:
- eq:
- year:
- dateAdd:
- $date
- 10
- h
- ':year' # берем из params->year
- $amount
- 0
...
params:
year:
caption: Год
format: int
month:
caption: Месяц
format: int
select: # выпадающий список
'1': январь
'2': февраль
'3': март
'4': апрель
'5': май
'6': июнь
'7': июль
'8': август
'9': сентябрь
'10': октябрь
'11': ноябрь
'12': декабрь
since:
caption: с
format: date
till:
caption: по
format: date
...
columns:
- field: title
caption: Показатель
- field: dimension
align: center # наименование заголовка в шапке по центру ячейки
caption: Единица измерения
- caption: '{$year}' # наименование заголовка в шапке из параметра year
align: center
columns: # колонка в шапке - группа вложенных колонок
- field: byPeriod
# наименование заголовка в шапке из параметров since и till
caption: 'c {$since} по {$till}'
align: center
format: number
- field: byMonth
# наименование заголовка в шапке из параметра month
caption: 'За {$month}'
align: center
format: number
- field: byYear
caption: За год
align: center
format: number
Стилизация строк отчета на основании данных¶
Пример YML¶
...
fetch:
category: $category
title:
case:
- eq:
- $category
- AA4
- 'Выдано заключений, всего в т.ч.:'
- eq:
- $category
- AB5
- '1. Государственная экспертиза, всего в т.ч.:'
- eq:
- $category
- AC6
- '- положительных'
- eq:
- $category
- AD7
- '- отрицательных'
...
dimension:
case:
- eq:
- $category
- AA4
- штук
- eq:
- $category
- AB5
- штук
...
styles:
category:
AA4: level0
AB5: level1
AC6: level2
AD7: level2
Возможность использования комбобоксов в параметрах и фильтрах¶
Пример YML¶
...
params:
year:
caption: Год
format: int
month:
caption: Месяц
format: int
select: # выпадающий список
'1': январь
'2': февраль
'3': март
'4': апрель
'5': май
'6': июнь
'7': июль
'8': август
'9': сентябрь
'10': октябрь
'11': ноябрь
'12': декабрь
since:
caption: с
format: date
till:
caption: по
format: date
...
Настройка обработки параметров в фильтре на странице отчета¶
Пример YML¶
reports:
...
filter:
eq:
- $yearStart
- year:
- ':dateSelect'
...
Значение года в атрибуте $yearStart
равно значению года из даты в атрибуте :dateSelect
.
Настройка пагинатора "pageSize"
¶
NB: Применяется для отчетов с типом type: list
.
Для случаев, когда отчет содержит в себе много объектов и на страницах нужно выводить строки постранично, чтобы не нагружать браузер тяжелой обработкой данных.
Пример YML¶
reports:
- name: test
caption: Тестовый отчет
sheets:
- name: main
caption: Тестовый отчет
type: list
pageSize: 100
Настройка вывода построчно¶
Настройка вывода вложенных данных в отчете построчно настраивается следующим образом:
Пример YML¶
...
reports:
- name: testReport
...
columns:
- caption: Группирующее поле
columns: // поля для группировки
- field: columns1
caption: Поле1
format: string
- field: columns2
caption: Поле2
format: string
...
Настройка инкрементальной загрузки¶
Для настройки инкрементальной загрузки данных в источник при сборке шахты необходимо выставить параметр:
append: true
Он необходим для подгрузки статистики за день в шахту, чтоб не пересчитывать весь объем исходных данных и иметь историю по периодам.
Особенности сортировки объектов¶
Учитывая функционал агрегации MongoDB - сортировка возможна только по результирующим полям. Это значит, что для обратной совместимости поля результата, по которым сортируем, необходимо называть так же, как и поля в источнике данных.
Пример сортировки (свойство sort
):¶
reports:
- name: sors
caption: Источник
sheets:
...
rangeFilters:
...
sort:
regDateOrder: asc
columns:
...
Мета безопасности¶
Описание¶
Мета безопасности - регулирует настройку прав безопасности на объекты системы. Можно разделить на статическую и динамическую безопасность:
Статическая безопасность - регулирует права доступа на объекты системы для определенной роли.
Динамическая безопасность - регулирует права доступа на объекты системы для конкретной персоны, в соответствии с какими-либо условиями, в то время как групповая динамическая безопасность - это права для группы безопасности.
Настройка динамической безопасности производится в файле deploy.json
, а также в файле acl/resources-and-roles.yml
. Статическая безопасность задается только в файле acl/resources-and-roles.yml
.
Правила формирования идентификаторов ресурсов¶
- узел навигации -
n:::namespace@code
- класс -
c:::classname@namespace
- объект -
i:::classname@namespace@id
- атрибут -
a:::classname@namespace.propertyname
- геомета:
- узел навигации: geonav:::код узла@namespace
- слой: geolayer:::код слоя@namespace
- данные: geodata:::код слоя@namespace@индекс запроса
- пути (модулей):
- модуль portal:
sys:::url:portal/*
- модуль geomap:
sys:::url:geomap/*
- модуль portal:
Типы прав¶
Чтение read
¶
read
- это право на просмотр информации по объектам класса. Задает разрешение просматривать объекты класса только для чтения и запрещает их создание/редактирование.
- id: Users
name: Обычные пользователи
permissions:
n:::ns@navigationName:
- read
...
Запись write
¶
write
- это право на создание объектов класса. Задает разрешение на создание новых объектов класса, но запрещает редактирование существующих.
- id: Users
name: Обычные пользователи
permissions:
n:::ns@navigationName:
- write
...
Использование use
¶
use
- это право на создание объектов класса. Задает разрешение на создание объектов класса, и использование объектов класса в ссылках и коллекциях.
Без use
- ссылки тоже отображаются в коллекции. Если есть read
, но нет use
, то нельзя выбрать объект и поместить его в коллекцию.
- id: Users
name: Обычные пользователи
permissions:
n:::ns@navigationName:
- use
...
Удаление delete
¶
delete
- это право на удаление объектов класса.
Полный доступ full
¶
full
- это право на полный доступ к объектам класса.
Динамическая безопасность¶
"PROJECT_BENEFITIAR": {
"resource":
{ "id": "pm::project" }
,
"attribute": "stakeholders.id"
}
Если у проекта в stakeholders.id
есть значение ассоциированное с текущим пользователем (настроено подтягивание организации как глобальной роли пользователя), то стоит учитывать текущего пользователя PROJECT_BENEFITIAR
и проверить права на ресурс pm:project
- эти права и будут правами на проект.
pm:project
- это некий виртуальный ресурс безопасности. Необходимо абстрагировать настройки доступа от проверяемого объекта
для разных ролей, можно разные ресурсы указать на один класс и наоборот.
Если ресурс не указать, то будут проверяться права на класс объекта. Тогда эту роль можно использовать как статическую, то есть выдавать статические права динамически.
Групповая динамическая безопасность¶
"roleMap": {
"organization@project-management": {
"ORGANIZATION_STAFF": {
"caption": "Сотрудник организации",
"resource": {
"id": "pm::organization",
"caption": "Организация"
},
"sids": [ // применять роль, если:
"$employee", // в атрибуте employee связанное с user значение (user это сотрудник)
// ИЛИ
"admin", // user это admin (здесь роль, учетная запись или идентификаторы связанные с user)
// ИЛИ
[
"$boss", // в атрибуте $boss связанное с user значение (user это руководитель)
// И
"supervisor" // user это supervisor (роль или учетная запись)
]
],
"conditions": {"eq": ["$state", "active"]}, // применять роль только для активных организаций
"attribute": "employee.id", // добавляется к sids
}
}
}
При указании sids
каждый уровень вложенности массивов значений меняет вид операции И
/ИЛИ
. На первом уровне применяется ИЛИ
.
Определение ролей пользователя¶
- Регистрируем пользователя с полным административным доступом -
admin
. - Под
admin
вregistry
в разделе Безопасность.Подразделения заводим иерархию подразделений (код подразделения = идентификатор безопасности). - Регистрируем пользователя без прав -
user
. - Под админ в
registry
в разделе Безопасность.Сотрудники заводим Сотрудника, указываем у него в атрибуте Пользователь пользователя без прав. Привязываем сотрудника к самому нижестоящему подразделению. - Заходим под
user
- прав нет ни на что. - Заходим под
admin
и даем роли (соответствующей самому вышестоящему подразделению) права на произвольные классы и узлы навигации. - Заходим под
user
- есть доступ к объектам, к которым есть доступ у подразделения. - Аналогично проверяем применение разрешений по всей иерархии подразделений.
Пример настройки в deploy.json
¶
"actualAclProvider":{
"module": "core/impl/access/aclmongo",
"initMethod": "init",
"initLevel": 1,
"options":{
"dataSource": "ion://Db"
}
},
"roleAccessManager": {
"module": "core/impl/access/amAccessManager",
"initMethod": "init",
"initLevel": 1,
"options": {
"dataSource": "ion://Db"
}
},
"aclProvider": {
"module": "core/impl/access/aclMetaMap",
"options":{
"dataRepo": "ion://dataRepo",
"acl": "ion://actualAclProvider",
"accessManager": "ion://roleAccessManager",
"map": {
"employee@develop-and-test": {
"isEntry": true,
"sidAttribute": "uid",
"jumps": ["department"]
},
"department@develop-and-test": {
"sidAttribute": "code",
"jumps": ["superior"]
}
}
}
}
Модель отображения атрибутов и объектов в соответствии с заданными правами¶
Есть класс [Проекты], в нем содержится атрибут с типом «Коллекция» - [Мероприятия]. Если для класса [Мероприятия] нет прав на чтение, то атрибут этого класса не показывается на форме класса [Проекты].
Если для класса есть динамическая безопасность - то независимо есть или нет права на чтение класса [Мероприятия] - атрибут на форме класса [Проекты] будет показан, но сами объекты мероприятий будут показаны только если на них есть права.
NB: Для отображения атрибута и объектов необходимо задавать как статическую, так и динамическую безопасность на класс по ссылке атрибута.
Если есть статическое право на чтение на класс, то пользователь увидит все объекты этого класса вне зависимости от динамических прав, и дополнительно будет делаться выборка объектов, на которые настроена динамическая безопасность и они будут отображаться для пользователя в соответствии с настройками в ней.
Мета представлений - общая часть¶
Поиск в списках объектов «allowSearch»¶
Поле основной части меты представления списка "allowSearch"
разрешает или запрещает отображение в форме поля поиска.
Логика работы¶
Архитектурой платформы и регистри накладываются следующие ограничения.
Для того, чтобы работал поиск в представлении «СПИСОК», нужно выполнение одного из условий:
- В ключе класса должны быть поля какого-нибудь из следующих типов: Строка, Дата-Время, Целое, Действительное, Десятичное
- В классе должны быть не ключевые атрибуты этих же типов помеченные как индексируемые
Если ни одно из условий не соблюдается, поиск в представлении «СПИСОК» невозможен - соответсвенно поле для поиска не отображается. Если одно или оба условия выполняются, то поиск доступен и выполняется путем сопоставления каждого индексированного атрибута с поисковой фразой. Если хотя бы один из атрибутов соответствует поисковой фразе - объект считается удовлетворяющим условию поиска и добавляется в выборку.
В зависимости от поля, сопоставление выполняется по следующим правилам:
- Строка - ищется вхождение поисковой фразы в значение строкового атрибута посредством регулярного выражения.
- Дата-время - поисковая фраза приводится к дате-времени, и, если получилось это сделать, то проверяется эквивалентность значения атрибута полученной дате. Сравнение строгое - до секунд, т.е. если в поиске не указано время - будут искаться даты с временем 00:00.
- Целое, Действительное, Десятичное число - поисковая фраза приводится к числу и проверяется равенство значению атрибута.
Действия¶
Действия - это доступные команды, которые можно выполнять над объектом класса.
JSON¶
{
"id": "SAVE",
"caption": "Сохранить",
"visibilityCondition": null,
"enableCondition": null,
"needSelectedItem": false,
"signBefore": false,
"signAfter": false,
"isBulk": false
}
Описание полей¶
Поле | Наименование | Допустимые значения | Описание |
---|---|---|---|
"id" |
Код | «CREATE» - создать объект/объект ссылочного поля | Внутренний код действия с объектом. |
«EDIT» - изменить объект/привязанный объект ссылочного поля | |||
«DELETE» - удалить объект | |||
«CREATE-INLINE» - создать объект (не переходя на форму создания) | Создание объекта без открытия формы создания, для ускорения заведения объектов. | ||
«SAVEANDCLOSE» - сохранить изменения и закрыть фрейм | |||
«SAVE» - сохранить изменения | |||
«REMOVE» - удалить привязку к объекту по ссылке | |||
«ADD» - добавить привязку к объекту по ссылке | |||
"caption" |
Имя | Строка | Видимое наименование - подпись на кнопке действия (при наличии). |
"visibilityCondition" |
Условие видимости | Строка или null | Условие, при котором кнопка действия будет отображена. |
"enableCondition" |
Условие активности | Строка или null | Условие, при котором кнопка действия будет активна. |
"needSelectedItem" |
Условие видимости - наличие выбранного элемента | Логическое значение | Поле выставляется в true для действий, которым необходимо наличие выбранного элемента для активации. |
"signBefore" |
ЭП входящих данных | Логическое значение | |
"signAfter" |
ЭП исходящих данных | Логическое значение | |
"isBulk" |
Групповая | Логическое значение | Признак пакетной операции, для действий ссылочных полей. Выставляется в true для действий, которые выполняются со всеми привязанными объектами одновременно. |
Логика действий над ссылочными объектами¶
Операция "Выбрать"
- это установление связи между объектами, вне зависимости от типа связи должна быть возможность ее установить (и разорвать) на уровне бизнес логики.
- Если это связь по ссылке один ко многим, т. е. ссылка на ключ - то приняв сторону «один» за A, сторону «многие» за B, реализуем:
- на стороне объекта B (ссылка на A): Операция
"Выбрать"
(SELECT) - находим объект (A), устанавливаем значение ссылочного атрибута объекта B равным ключу объекта A (обнуляем атрибут для разрыва связи); - на стороне объекта A (коллекция или т.н. обратная ссылка): операция
"Добавить"
(ADD) - находим объект (B), устанавливаем значение ссылочного атрибута этого объекта (B) равное ключу объекта A, операция"Извлечь"
(REMOVE) - выбираем в коллекции объект (B), обнуляем ссылку на A.
- на стороне объекта B (ссылка на A): Операция
- Если это связь по ссылке многие ко многим, т. е. ссылка на не ключевой атрибут, то для обоих концов коллекции реализуем связи:
- Операция «Добавить» (ADD) - находим объект, устанавливаем значение его ссылки равным соответствующему атрибуту контейнера. При этом объект окажется в коллекциях всех контейнеров с таким же значением атрибута, это специфика данного типа связей)
- Операция
"Извлечь"
(REMOVE) - выбираем объект в коллекции, обнуляем ссылку, при этом объект также удаляется из коллекций всех контейнеров с соответствующим значением атрибута.
- Если это связь многие-ко-многим без ссылки (связь через системную промежуточную сущность, сюда относятся и «прямые» коллекции и «обратные», как разные концы связи), то для обоих коллекций реализуем:
- Операция
"Добавить"
(ADD) - находим объект, создаем сущность-связь с контейнером - объект появляется только в коллекции данного контейнера - Операция
"Извлечь"
(REMOVE) - выбираем объект в коллекции, удаляем сущность-связь с контейнером - объект пропадает только из коллекции данного контейнера
- Операция
С точки зрения UI различий между типами связей вообще нет никаких - везде имеем дело с коллекциями, везде потенциально доступны операции добавления и извлечения. А настраивать наличие тех или иных кнопок у поля колекции можно и нужно на уровне модели представления. В бизнес логике должны быть реализованы стандартные обработчики для кнопок ADD
и REMOVE
в соответствии с описанной выше логикой.
Логика действий над объектами класса¶
Поле "commands"
, заданное в общей части меты представлений класса, задает список действий, допустимых над объектами данного класса.
В общей части меты представлений класса могут быть указаны команды следующих кодов "id"
:
"CREATE"
- создать объект"EDIT"
- изменить объект"DELETE"
- удалить объект"SAVEANDCLOSE"
- сохранить изменения и закрыть"SAVE"
- сохранить изменения
Для представления атрибутов со свойством "type":2
применяются следующие действия:¶
"SELECT"
- добавить"EDIT"
- править"REMOVE"
- удалить
Структура в mongoDB (registry)¶
{
"id" : "SAVE",
"caption" : "Сохранить",
"visibilityCondition" : null,
"enableCondition" : null,
"needSelectedItem" : false,
"signBefore" : false,
"signAfter" : false,
"isBulk" : false
}
Режим наложения¶
Поле Режим наложения - "overrideMode"
позволяет задать два значения "Перекрыть"
и "Переопределить"
.
Настройка режимов наложения в мете представления:
Тип 1 - "Переопределить"
- переопределяет стандартный способ отображения соответствующих атрибутов заданных в мете представления класса. Атрибуты, которые не заданы в мете представления класса, отображаются стандартным образом на форме согласно заданной очередности по умолчанию.
Тип 2 - "Перекрыть"
- выводятся только атрибуты заданные в мете представления.
Пример¶
"actions": null,
"siblingFixBy": null,
"siblingNavigateBy": null,
"historyDisplayMode": 0,
"collectionFilters": null,
"version": null,
"overrideMode": 1,
"commands": [
Выделение цветом строк в списке¶
Условия выделение цветом строк в списке задаются с помощью формулы.
Список поддерживаемых функций можно посмотреть :doc`здесь </3_development/metadata_structure/meta_class/meta_class_attribute/attr_formula>`. Настройка задается в общей части меты представления списка и выглядит следующим образом:
"styles": {
"css-class": "формула"
}
где, "css-class"
- класс доступных тем оформления, а "формула"
- формула с условием для применения выделения цветом строк в списке.
Доступные темы оформления "css-class"
¶
attention-1
- redattention-2
- yellowattention-3
- orangeattention-4
- grayattention-5
- blueattention-6
- green
Назначение¶
При открытии формы представления списка объектов, в соответствии с условиями формулы и класса темы оформления - строки таблицы выделяются цветом.
Пример¶
"styles": {
"attention-1": "lt($real, 0)"
},
$real
- любое целое число. Если $real - меньше 0, то столбец выделяется красным цветом.
Вкладки¶
Вкладки - задаются в представлении создания и редактирования и используются для разбиения атрибутов класса по отдельным вкладкам на форме.
Структура:¶
{
"tabs": [
{
"caption": "1",
"fullFields": [],
"shortFields": []
},
{
"caption": "2",
"fullFields": [],
"shortFields": []
}
]
}
где, caption
- наименование вкладки и fullFields
- атрибуты на вкладке
Пример¶
{
"tabs": [
{
"caption": "Первая вкладка",
"fullFields": [
{
"caption": "Первый атрибут на первой вкладке",
"type": 1,
"property": "tab_1_1",
"size": 2,
"maskName": null,
"mask": null,
"mode": null,
"fields": [],
"hierarchyAttributes": null,
"columns": [],
"actions": null,
"commands": [],
"orderNumber": 10,
"required": false,
"visibility": null,
"enablement": null,
"obligation": null,
"readonly": false,
"selectionPaginated": true,
"validators": null,
"hint": null,
"historyDisplayMode": 0,
"tags": ["css:background-color:#AFFFAF"]
},
{
"caption": "Второй атрибут на первой вкладке",
"type": 1,
"property": "tab_1_2",
"size": 2,
"maskName": null,
"mask": null,
"mode": null,
"fields": [],
"hierarchyAttributes": null,
"columns": [],
"actions": null,
"commands": [],
"orderNumber": 20,
"required": false,
"visibility": null,
"enablement": null,
"obligation": null,
"readonly": false,
"selectionPaginated": true,
"validators": null,
"hint": null,
"historyDisplayMode": 0,
"tags": null
}
]
Представление Комментарий
для атрибутов типа «Коллекция»¶
warning: | Для корректной работы функционала обязательно в зависимостях проекта должен быть указан репозиторий viewlib . |
---|
Подключение:
- В файле package.json проекта:
...
"ionMetaDependencies": {
"viewlib": "0.7.1"
}
...
- В директорию application рядом с текущим проектом добавить репозиторий проекта
viewlib
Инструкция по подключению функционала¶
Представление реализуется посредством шаблона вида templates/registry/item_footer.ejs
. Обратите внимание на пояснение строк после знака // :
ejs
<%
let status = item.get('status'); // атрибут со статусом БП
let readOnly = state === 'conf' || status === 'approv'; //статус в котором отображаем коллекцию на форме
if ((item.getMetaClass().checkAncestor('classColl@ns')) //класс, в котором содержится атрибут Комментарий
&& item.getItemId() && (status === 'onapprov' || readOnly)) { // статус, на котором атрибут отображается только для чтения
let comments = resolveTpl('comments', null, true);
if (comments) {
let prop = item.property('atrClassColl'); //системное имя атрибута с представлением Комментарий
let commId = `${form.ids.attr}_${prop.getName()}_сom`;
%>
<div class="line-tabs tabs">
<div id="item-footer-order-toggle" class="order-toggle asc" data-direction="asc"
title="Изменить порядок в списке">
<span class="glyphicon"></span>
</div>
<ul class="nav nav-tabs">
<li class="active">
<a href='#footer-tab-1' data-toggle="tab">
<%- prop.getCaption() %>
</a>
</li>
</ul>
<div class="tab-content">
<div id="footer-tab-1" class="tab-pane active">
<div class="comments">
<%-partial(comments, {
item,
id: commId,
property: prop,
comment: { // атрибуты для класса по ссылке из атрибута Коллекции
text: 'descript',
user: 'owner',
parent: 'answlink',
photo: 'owner_ref.foto.link'
},
count: 100,
orderToggleId: '#item-footer-order-toggle',
readOnly
})%>
</div>
</div>
</div>
</div>
<script>
$(function () {
$('#<%= commId %>').on('comment-added comment-deleted', function () {
loadWorkflowState();
});
});
$('#item-footer-order-toggle').click(function () {
if ($(this).hasClass('asc')) {
$(this).removeClass('asc').addClass('desc').data('direction', 'desc');
} else {
$(this).removeClass('desc').addClass('asc').data('direction', 'asc')
}
});
$(document.body).on('mouseenter', '.item-comment', function () {
$(this).addClass('mouse-enter');
});
$(document.body).on('mouseleave', '.item-comment', function () {
$(this).removeClass('mouse-enter');
});
</script>
<% }} %>
"options"
¶Далее подключаем функционал "options"
для представление Комментарий на форме представления изменения для атрибута типа «Коллекция»:
{
"caption": "Коментарий",
"type": 3,
"property": "coment",
"size": 2,
"maskName": null,
"mask": null,
"mode": 3,
"fields": [],
"columns": [
{
"sorted": true,
"caption": "Дата",
"type": 120,
"property": "date",
"size": 2,
"maskName": null,
"mask": null,
"mode": null,
"fields": [],
"columns": [],
"actions": null,
"commands": null,
"orderNumber": 2,
"required": false,
"visibility": null,
"enablement": null,
"obligation": null,
"readonly": false,
"selectionPaginated": true,
"validators": null,
"hint": "",
"historyDisplayMode": 0,
"tags": null,
"selConditions": null,
"selSorting": null
},
{
"sorted": true,
"caption": "Подтверждение (Обоснование)",
"type": 7,
"property": "descript",
"size": 2,
"maskName": null,
"mask": null,
"mode": null,
"fields": [],
"hierarchyAttributes": null,
"columns": [],
"actions": null,
"commands": null,
"orderNumber": 1,
"required": true,
"visibility": null,
"enablement": null,
"obligation": null,
"readonly": false,
"selectionPaginated": true,
"validators": null,
"hint": null,
"historyDisplayMode": 0,
"tags": null,
"selConditions": null,
"selSorting": null
},
{
"caption": "Ведущий",
"type": 2,
"property": "owner",
"size": 2,
"maskName": null,
"mask": null,
"mode": 1,
"fields": [],
"hierarchyAttributes": null,
"columns": [],
"actions": null,
"commands": null,
"orderNumber": 6,
"required": false,
"visibility": null,
"enablement": null,
"obligation": null,
"readonly": false,
"selectionPaginated": true,
"validators": null,
"hint": null,
"historyDisplayMode": 0,
"tags": null
}
],
"actions": null,
"commands": [
{
"id": "CREATE",
"caption": "Создать",
"visibilityCondition": null,
"enableCondition": null,
"needSelectedItem": false,
"signBefore": false,
"signAfter": false,
"isBulk": false
},
{
"id": "EDIT",
"caption": "Править",
"visibilityCondition": null,
"enableCondition": null,
"needSelectedItem": true,
"signBefore": false,
"signAfter": false,
"isBulk": false
}
],
"orderNumber": 80,
"required": false,
"visibility": null,
"enablement": null,
"obligation": null,
"readonly": false,
"selectionPaginated": true,
"validators": null,
"hint": "",
"historyDisplayMode": 0,
"tags": null,
"options": {
"template": "comments",
"comments": {
"textProperty": "descript", // атрибут "Описание" из класса по ссылке
"userProperty": "owner", // атрибут "Ответственный" из класса по ссылке (отображается имя пользователя, оставившего комментарий)
"parentProperty": "answlink", // атрибут "Ответ" из класса по ссылке (для возможности "Ответить" на комментарий пользователя)
"photoProperty": "owner_ref.foto.link", // атрибут "Фото" из класса Персона (отображается фото персоны)
"dateProperty": "date" // атрибут "Дата" из класса по ссылке
}
}
}
Особенности¶
- В классе создается обычный атрибут с типом «Коллекция».
- В представлении формы изменения создается аналогично стандартному атрибуту с типом «Коллекция», но с добавлением настройки
"options"
, подробнее смотрите настройка «options». - В классе создается атрибутивный состав и их системные наименования обязательно должны соответствовать наименованиям в шаблоне
item_footer.ejs
и в свойстве"options"
. Дополнительно к обязательным - класс может содержать любые атрибуты.
Класс Персона должен содержать атрибут, в которых будет задаваться информация об имени пользователя (в данном случае это атрибут «user») и фотография персоны (атрибут «Фото»), а так же ФИО персоны, которые являются семантикой данного класса.
{
"namespace": "develop-and-test",
"isStruct": false,
"key": [
"id"
],
"semantic": "surname| |name| |patronymic",
"name": "person",
"version": "",
"caption": "Персона",
"ancestor": null,
"container": null,
"creationTracker": "",
"changeTracker": "",
"creatorTracker": "",
"editorTracker": "",
"history": 0,
"journaling": true,
"compositeIndexes": [],
"properties": [
{
"orderNumber": 10,
"name": "id",
"caption": "Идентификатор",
"type": 12,
"size": 24,
"decimals": 0,
"allowedFileTypes": null,
"maxFileCount": 0,
"nullable": false,
"readonly": true,
"indexed": false,
"unique": true,
"autoassigned": true,
"hint": null,
"defaultValue": null,
"refClass": "",
"itemsClass": "",
"backRef": "",
"backColl": "",
"binding": "",
"semantic": null,
"selConditions": [],
"selSorting": [],
"selectionProvider": null,
"indexSearch": false,
"eagerLoading": false,
"formula": null
},
{
"orderNumber": 20,
"name": "surname",
"caption": "Фамилия",
"type": 0,
"size": null,
"decimals": 0,
"allowedFileTypes": null,
"maxFileCount": 0,
"nullable": true,
"readonly": false,
"indexed": true,
"unique": false,
"autoassigned": false,
"hint": null,
"defaultValue": null,
"refClass": "",
"itemsClass": "",
"backRef": "",
"backColl": "",
"binding": "",
"semantic": null,
"selConditions": [],
"selSorting": [],
"selectionProvider": null,
"indexSearch": false,
"eagerLoading": false,
"formula": null
},
{
"orderNumber": 30,
"name": "name",
"caption": "Имя",
"type": 0,
"size": null,
"decimals": 0,
"allowedFileTypes": null,
"maxFileCount": 0,
"nullable": true,
"readonly": false,
"indexed": true,
"unique": false,
"autoassigned": false,
"hint": null,
"defaultValue": null,
"refClass": "",
"itemsClass": "",
"backRef": "",
"backColl": "",
"binding": "",
"semantic": null,
"selConditions": [],
"selSorting": [],
"selectionProvider": null,
"indexSearch": false,
"eagerLoading": false,
"formula": null
},
{
"orderNumber": 40,
"name": "patronymic",
"caption": "Отчество",
"type": 0,
"size": null,
"decimals": 0,
"allowedFileTypes": null,
"maxFileCount": 0,
"nullable": true,
"readonly": false,
"indexed": true,
"unique": false,
"autoassigned": false,
"hint": null,
"defaultValue": null,
"refClass": "",
"itemsClass": "",
"backRef": "",
"backColl": "",
"binding": "",
"semantic": null,
"selConditions": [],
"selSorting": [],
"selectionProvider": null,
"indexSearch": false,
"eagerLoading": false,
"formula": null
},
{
"orderNumber": 40,
"name": "user",
"caption": "Пользователь",
"type": 18,
"size": null,
"decimals": 0,
"allowedFileTypes": null,
"maxFileCount": 0,
"nullable": true,
"readonly": false,
"indexed": true,
"unique": false,
"autoassigned": false,
"hint": null,
"defaultValue": null,
"refClass": "",
"itemsClass": "",
"backRef": "",
"backColl": "",
"binding": "",
"semantic": null,
"selConditions": [],
"selSorting": [],
"selectionProvider": null,
"indexSearch": false,
"eagerLoading": false,
"formula": null
},
{
"orderNumber": 70,
"name": "foto",
"caption": "Фотография",
"type": 5,
"size": null,
"decimals": 0,
"allowedFileTypes": null,
"maxFileCount": 0,
"nullable": true,
"readonly": false,
"indexed": false,
"unique": false,
"autoassigned": false,
"hint": null,
"defaultValue": null,
"refClass": "",
"itemsClass": "",
"backRef": "",
"backColl": "",
"binding": "",
"semantic": null,
"selConditions": [],
"selSorting": [],
"selectionProvider": null,
"indexSearch": false,
"eagerLoading": false,
"formula": null
}
],
"metaVersion": "2.0.61.21119"
}
Ведение проектных документов¶
Ведение проектных документов - это настройка "fileshare-list"
и "fileshare"
предназначена для управления документами, как например, возможность скачать и/или получить ссылку на файл. Для настройки, в представлении атрибута типа «Файл» необходимо указать свойство:
"options": {
"template": "fileshare-list"
}
fileshare-list
- для типаmultifile
- множественные файлыfileshare
- для типаfile
- один файл
В deploy.json
в настройках registry
подключаем кастомный файл-аплоадер (который с шарой директории и расширенными настройками):
"modules": {
"registry": {
"globals": {
...
"di": {
...
"fileshareController": {
"module": "applications/viewlib/lib/controllers/api/fileshare",
"initMethod": "init",
"initLevel": 0,
"options": {
"module": "ion://module",
"fileStorage": "ion://fileStorage"
}
}
Cохранение файлов в облаке¶
Путь для сохранения файла в облаке настраивается в deploy.json
приложения. Для обращения к свойствам объекта используется знак $
.
{item.названиеСвойства.свойствоСсылочногоОбъекта}
т.е. используем ${item.}
для того чтобы обозначить что это обращение к объекту.
"modules": {
"registry": {
"globals": {
"storage": {
"basicObj@project-management": {
"cloudFile": "/${class}/pm_${attr}/${dddd}/"
},
"project@project-management": {
"cloudFile": "/${item.name} (${item.code})/"
},
"eventControl@project-management": {
"cloudFile": "/${class}/pm_${attr}/${dddd}/"
},
"eventOnly@project-management": {
"cloudFile": "/${class}/pm_${attr}/${dddd}/"
}
}
}
}
}
Настройка позволяет задавать любую структуру хранения файлов (линейно/иерархически, коллекцией/один файл)
Функционал шаринга на файлы¶
При клике на значок «share» необходимо открывать окно управления шарой аналогичное как в овнклауд - в окне предусмотреть кнопки:
применить
- по апи облачного хранилища для файлика/каталога передаем все выбранные параметры:поделиться ссылкой
- формируем шару на файлик/каталог - после применения возвращаем в поле для возможности копирования ссылкиразрешить на редактирование
защитить паролем
- поле для ввода пароляустановить срок действия
- поле для датыперейти в хранилище
- открываем в новой вкладке по ссылке на шару где находится файл/каталог - ( к примеру файл к примеру каталог )закрыть
- закрыть окно управления файлом
NB: Настройка шаринга доступна как для каждого файла, так и для всего каталога. Если на файле/каталоге уже есть шаринг, то при открытии управляющего окна отображаются настройки шаринга, при необходимости свойства можно изменить.
Переход по прямой ссылки до хранения файла¶
- сразу скачать
- перейти на nextCloud и там увидеть/редактировать
Условия хранения ссылок, созданных в процессе работы с файлами: TO DO
возможность удалять все ссылки, созданные в процессе работы с файлом спустя какое-то время или же за ненадобностью.
Настройка пользователей и прав доступа к объектам хранилища Owncloud. В ряде случаев необходимо задавать пользователей и права для них на создаваемые объекты хранилища.
Настройка задается в файле deploy.json
проекта.
"ownCloud": {
"module": "core/impl/resource/OwnCloudStorage",
"options": {
...
"users": [
{
"name": "user",
"permissions": {
"share": true,
"create": false,
"edit": true,
"delete": false
}
}
]
}
}
list_view¶
TODO
Описание¶
Мета представлений - позволяет задавать желаемый состав атрибутов этого класса для отображения на форме, в соответствии с видом формы представления (представление формы списка list.json, создания create.json, изменения класса item.json) и указывать для каждого отдельного атрибута свойства, переопределяемые и (или) дополняемые свойства, задаваемые в мете класса для данного атрибута.
Виды меты представлений¶
Мета представлений подразделяется на виды:
- Форма представления списка
- Форма представления создания и изменения
Форма представления списка¶
Форма представления списка - позволяет выводить объекты класса в виде списка.
JSON¶
{
"columns": [...],
"styles": {},
"actions": null,
"commands": [...],
"allowSearch": false,
"pageSize": null,
"useEditModels": true,
"version": null,
"overrideMode": null,
"filterDepth": 3
}
Описание полей¶
Поле | Наименование | Допустимые значения | Описание |
---|---|---|---|
"columns" |
Колонки | Массив объектов | Колонки или столбцы атрибутов класса, каждый из которых описывается атрибутивной частью меты представлений. |
"styles" |
Выделение цветом строк | Формула | В соответствии с условиями формулы столбцы таблицы окрашены в заданный цвет. |
"actions" |
Поведение | Целое или Null | не используется в текущей версии |
"commands" |
Действия | Массив объектов | Набор действий над объектами класса. |
"allowSearch" |
Доступен поиск | Логическое | Разрешает или запрещает отображение формы поиска. |
"pageSize" |
Количество записей на странице | Целое положительное | Указывает количество объектов на одной странице по умолчанию. |
"useEditModels" |
Использовать формы редактирования для детализации | Логическое | Разрешает или запрещает использование формы редактирования для детализации данных объекта класса. |
"version" |
Версия | Строка | Версия метаданных. |
"overrideMode" |
Режим наложения | 0 - Перекрыть | Задает режим наложения представлений. |
1 - Переопределить | |||
"filterDepth" |
Глубина запроса фильтра в списках | Целое положительное | Глубина для фильтра в списках объектов. По умолчанию 2. |
Форма представления создания и изменения¶
Форма представления создания и изменения - позволяет создавать и изменять объекты класса.
JSON¶
{
"tabs": [
{
"caption": "",
"fullFields": [...],
"shortFields": []
}
],
"actions": null,
"commands": [...],
"siblingFixBy": null,
"siblingNavigateBy": null,
"historyDisplayMode": 0,
"collectionFilters": null,
"version": null,
"overrideMode": null
}
Описание полей¶
Поле | Наименование | Допустимые значения | Описание |
---|---|---|---|
"tabs" |
Вкладки | Объект | Позволяет создавать несколько страниц объектов на одной форме представления. |
"caption" |
Имя вкладки | Строка | Поле объекта "tabs" наименование будет отображаться в строке перехода на вкладку. |
"fullFields" |
Поле в полном виде | Массив объектов | Поле объекта "tabs" , массив содержит атрибуты которые должны отображаться в представлени с полным видом, описанные согласно атрибутивной части меты представлений. |
"shortFields" |
Поле в кратком виде | Массив объектов | Поле объекта "tabs" , массив содержит атрибуты которые должны отображаться в представлени с кратким видом, описанные согласно атрибутивной части меты представлений. |
"actions" |
Поведение | Целое или Null | не используется в текущей версии |
"commands" |
Действия | Массив объектов | Набор действий над объектом класса. |
"siblingFixBy" |
Отбор смежных объектов по | Массив строк | Перечисление атрибутов коллекции, по которым будет производится отбор смежных объектов. |
"siblingNavigateBy" |
Переход к смежным объектам по | Массив строк | Перечисление атрибутов коллекции, по которым будет осуществляться переход к смежным объектам. |
"historyDisplayMode" |
Отображение истории | Целое | Указать формат отображения истории изменения объектов. |
"collectionFilters" |
Фильтрация коллекций | Массив объектов | Выбор атрибутов из коллекций, по которым будет произведена фильтрация. |
"version" |
Версия | Строка | Версия метаданных. |
"overrideMode" |
Режим наложения | 0 - Перекрыть | Задает режим наложения представлений. |
1 - Переопределить |
Мета представлений - атрибутивная часть¶
Действия¶
Действия - это доступные команды, которые можно выполнять над объектом класса.
JSON¶
{
"id": "SAVE",
"caption": "Сохранить",
"visibilityCondition": null,
"enableCondition": null,
"needSelectedItem": false,
"signBefore": false,
"signAfter": false,
"isBulk": false
}
Поле | Наименование | Допустимые значения | Описание |
---|---|---|---|
"id" |
Код | «CREATE» - создать объект/объект ссылочного поля | Внутренний код действия с объектом. |
«EDIT» - изменить объект/привязанный объект ссылочного поля | |||
«DELETE» - удалить объект | |||
«CREATE-INLINE» - создать объект (не переходя на форму создания) | Создание объекта без открытия формы создания, для ускорения заведения объектов. | ||
«SAVEANDCLOSE» - сохранить изменения и закрыть фрейм | |||
«SAVE» - сохранить изменения | |||
«REMOVE» - удалить привязку к объекту по ссылке | |||
«ADD» - добавить привязку к объекту по ссылке | |||
"caption" |
Имя | Строка | Видимое наименование - подпись на кнопке действия (при наличии). |
"visibilityCondition" |
Условие видимости | Строка или null | Условие, при котором кнопка действия будет отображена. |
"enableCondition" |
Условие активности | Строка или null | Условие, при котором кнопка действия будет активна. |
"needSelectedItem" |
Условие видимости - наличие выбранного элемента | Логическое значение | Поле выставляется в true для действий, которым необходимо наличие выбранного элемента для активации. |
"signBefore" |
ЭП входящих данных | Логическое значение | |
"signAfter" |
ЭП исходящих данных | Логическое значение | |
"isBulk" |
Групповая | Логическое значение | Признак пакетной операции, для действий ссылочных полей. Выставляется в true для действий, которые выполняются со всеми привязанными объектами одновременно. |
Операция "Выбрать"
- это установление связи между объектами, вне зависимости от типа связи должна быть возможность ее установить (и разорвать) на уровне бизнес логики.
- Если это связь по ссылке один ко многим, т. е. ссылка на ключ - то приняв сторону «один» за A, сторону «многие» за B, реализуем:
- на стороне объекта B (ссылка на A): Операция
"Выбрать"
(SELECT) - находим объект (A), устанавливаем значение ссылочного атрибута объекта B равным ключу объекта A (обнуляем атрибут для разрыва связи); - на стороне объекта A (коллекция или т.н. обратная ссылка): операция
"Добавить"
(ADD) - находим объект (B), устанавливаем значение ссылочного атрибута этого объекта (B) равное ключу объекта A, операция"Извлечь"
(REMOVE) - выбираем в коллекции объект (B), обнуляем ссылку на A.
- на стороне объекта B (ссылка на A): Операция
- Если это связь по ссылке многие ко многим, т. е. ссылка на не ключевой атрибут, то для обоих концов коллекции реализуем связи:
- Операция «Добавить» (ADD) - находим объект, устанавливаем значение его ссылки равным соответствующему атрибуту контейнера. При этом объект окажется в коллекциях всех контейнеров с таким же значением атрибута, это специфика данного типа связей)
- Операция
"Извлечь"
(REMOVE) - выбираем объект в коллекции, обнуляем ссылку, при этом объект также удаляется из коллекций всех контейнеров с соответствующим значением атрибута.
- Если это связь многие-ко-многим без ссылки (связь через системную промежуточную сущность, сюда относятся и «прямые» коллекции и «обратные», как разные концы связи), то для обоих коллекций реализуем:
- Операция
"Добавить"
(ADD) - находим объект, создаем сущность-связь с контейнером - объект появляется только в коллекции данного контейнера - Операция
"Извлечь"
(REMOVE) - выбираем объект в коллекции, удаляем сущность-связь с контейнером - объект пропадает только из коллекции данного контейнера
- Операция
С точки зрения UI различий между типами связей вообще нет никаких - везде имеем дело с коллекциями, везде потенциально доступны операции добавления и извлечения. А настраивать наличие тех или иных кнопок у поля колекции можно и нужно на уровне модели представления. В бизнес логике должны быть реализованы стандартные обработчики для кнопок ADD
и REMOVE
в соответствии с описанной выше логикой.
Поле "commands"
, заданное в общей части меты представлений класса, задает список действий, допустимых над объектами данного класса.
В общей части меты представлений класса могут быть указаны команды следующих кодов "id"
:
"CREATE"
- создать объект"EDIT"
- изменить объект"DELETE"
- удалить объект"SAVEANDCLOSE"
- сохранить изменения и закрыть"SAVE"
- сохранить изменения
Для представления атрибутов со свойством "type":2
применяются следующие действия:¶
"SELECT"
- добавить"EDIT"
- править"REMOVE"
- удалить
{
"id" : "SAVE",
"caption" : "Сохранить",
"visibilityCondition" : null,
"enableCondition" : null,
"needSelectedItem" : false,
"signBefore" : false,
"signAfter" : false,
"isBulk" : false
}
Условия активности¶
Описание¶
Условия активности - задают условия активности, то есть доступности поля для редактирования в представлении. Синтаксис условий такой же, как в условиях отображения.
{
{
"caption": "Основание для условия активности",
"type": 1,
"property": "enablement_condition_base",
"size": 2,
"maskName": null,
"mask": null,
"mode": null,
"fields": [],
"hierarchyAttributes": null,
"columns": [],
"actions": null,
"commands": [],
"orderNumber": 20,
"required": false,
"visibility": null,
"enablement": null,
"obligation": null,
"readonly": false,
"selectionPaginated": true,
"validators": null,
"hint": null,
"historyDisplayMode": 0,
"tags": null
},
{
"caption": "Поле активно, если основание заполнено",
"type": 1,
"property": "enablement_condition_use",
"size": 2,
"maskName": null,
"mask": null,
"mode": null,
"fields": [],
"hierarchyAttributes": null,
"columns": [],
"actions": null,
"commands": [],
"orderNumber": 30,
"required": false,
"visibility": null,
"enablement": ".enablement_condition_base !\u003d \u0027\u0027",
"obligation": null,
"readonly": false,
"selectionPaginated": true,
"validators": null,
"hint": null,
"historyDisplayMode": 0,
"tags": null
},
{
"caption": "Поле активно, если в основании \u00271\u0027",
"type": 1,
"property": "enablement_condition_1",
"size": 2,
"maskName": null,
"mask": null,
"mode": null,
"fields": [],
"hierarchyAttributes": null,
"columns": [],
"actions": null,
"commands": [],
"orderNumber": 40,
"required": false,
"visibility": null,
"enablement": ".enablement_condition_base \u003d\u003d \u00271\u0027",
"obligation": null,
"readonly": false,
"selectionPaginated": true,
"validators": null,
"hint": null,
"historyDisplayMode": 0,
"tags": null
}
}
Поля¶
Описание¶
Поля - содержат в себе атрибуты класса, объединенные, по какому-либо признаку, в группу (более подробное описание см. Тип «Группа [0]»).
Внимание: данное свойство применяется только для атрибута типа «Группа [0]».
NB: На форме представления, заданные атрибуты, отображаются на нижнем уровне иерархии, на верхнем находится наименование группы.
{
"tabs": [
{
"caption": "",
"fullFields": [
{
"caption": "nameGroup",
"type": 0,
"property": "",
"size": 2,
"maskName": null,
"mask": null,
"mode": null,
"fields": [
{
"caption": "atr1",
"type": 1,
...
},
{
"caption": "atr2",
"type": 1,
...
}
]
}
],
"shortFields": []
}
]
}
Маски ввода¶
Описание¶
Маски ввода - предоставляют возможность сообщить системе, какой шаблон или образец должны использовать данные. Применяются для облегчения обработки значений, имеющих фиксированный шаблон, – например, телефонных номеров. Маски ввода нужны для помощи пользователям с вводом предопределенного формата в атрибуте.
Поле "mask"
для представлений¶
{
"tabs": [
{
"caption": "Информационная система",
"fullFields": [
{
"caption": "Уникальный идентификационный номер ОУ",
"type": 1,
"property": "OuId",
"size": 2,
"maskName": null,
"mask": null,
В данный момент возможно задание маски в виде строки или объекта в поле "mask"
.
Маски по умолчанию¶
Маски по умолчанию можно переопределить в расширениях:
- 9 — число
- a — буква
- A — буква в верхнем регистре
- — число или буква
Виды масок¶
Статичные маски определены заранее и не изменяется при вводе.
"mask": "aa-9999",
"mask": {"mask": "aa-9999"},
Необязательные маски допускают некоторую часть в определении маски сделать необязательной для ввода.
В квадратных скобках []
задается необязательная часть ввода.
"mask": {"mask": "(99) 9999[9]-9999"},
Динамичные маски могут изменятся при вводе.
В фигурных скобках {}
задается динамичная часть ввода, применяется к выражению перед скобками:
- {n} - n повторений
- {n,m} - с n по m повторений
- {+} - от 1 и больше повторений
- {*} - от 0 и больше повторений
"mask": {"mask": "aa-9{1,4}"},
Синтаксис генерируемых масок похож на выражение OR. Маска может быть одной из трех вариантов, указанных в генераторе. Для определения генератора используется |
.
"mask": {"mask": "(aaa)|(999)"},
"mask": {"mask": "(aaa|999|9AA)"},
По умолчанию: null (~false). Используется в комбинации с синтаксисом генератора и оставляет маску статичной по мере ввода. Когда задается массив масок, keepStatic автоматически становится равен true, если явно не задан через параметры.
"mask": { "mask": ["+55-99-9999-9999", "+55-99-99999-9999" ], "keepStatic": true },
Результат: Вводим 1212345123 => должны получить +55-12-1234-5123 вводим еще 4 => переключаемся на +55-12-12345-1234
Дополнительные примеры масок:¶
«99 99 999999» — серия и номер паспорта
«[+]9 (999) 999-99-99» — номер мобильного телефона
«(999)|(aaa)» - позволяет ввести либо три цифры, либо три символа
Сложные маски¶
Задание сложной маски с определением валидации символов. Допустимые значения полей внутри определения определяются плагином inputmask версии 4.0.0.
Задается массивом в field.mask
:
field.mask: ["X{1,4}-AA №999999", {definitions: {"X": {validator: "[lLvVcCxX]", cardinality: 1, casing: "upper"}}}]
Где индекс 0 - определение маски, а индекс 1 - дополнительные опции.
Реализованы также маски через «regex».
"mask": {
"regex": "[A-Za-z]{1,50}"
},
Маски по идентификатору¶
Для задания маски из вшитого пресета масок используется поле "maskName"
атрибутивной части меты представлений. Не реализовано.
Условия обязательности¶
Описание¶
Условия обязательности - задают условие обязательности заполнения поля в представлении.
Синтаксис условий такой же, как в условиях отображения.
Условия обязательности отличаются выполнением действий. При данном условии атрибут становится обязательным для заполнения, иначе атрибут остается таким же, каким был задан в представлении до применения условия обязательности.
Пример в JSON:¶
{
{
"caption": "Основание для условия обязательности",
"type": 1,
"property": "obligation_condition_base",
"size": 2,
"maskName": null,
"mask": null,
"mode": null,
"fields": [],
"hierarchyAttributes": null,
"columns": [],
"actions": null,
"commands": [],
"orderNumber": 20,
"required": false,
"visibility": null,
"enablement": null,
"obligation": null,
"readonly": false,
"selectionPaginated": true,
"validators": null,
"hint": null,
"historyDisplayMode": 0,
"tags": null
},
{
"caption": "Поле обязательно, если основание заполнено",
"type": 1,
"property": "obligation_condition_use",
"size": 2,
"maskName": null,
"mask": null,
"mode": null,
"fields": [],
"hierarchyAttributes": null,
"columns": [],
"actions": null,
"commands": [],
"orderNumber": 30,
"required": false,
"visibility": null,
"enablement": null,
"obligation": ".obligation_condition_base !\u003d \u0027\u0027",
"readonly": false,
"selectionPaginated": true,
"validators": null,
"hint": null,
"historyDisplayMode": 0,
"tags": null
},
{
"caption": "Поле обязательно, если в основании \u00271\u0027",
"type": 1,
"property": "obligation_condition_1",
"size": 2,
"maskName": null,
"mask": null,
"mode": null,
"fields": [],
"hierarchyAttributes": null,
"columns": [],
"actions": null,
"commands": [],
"orderNumber": 40,
"required": false,
"visibility": null,
"enablement": null,
"obligation": ".obligation_condition_base \u003d\u003d \u00271\u0027",
"readonly": false,
"selectionPaginated": true,
"validators": null,
"hint": null,
"historyDisplayMode": 0,
"tags": null
}
}
Опции¶
Опции - предназначены для установки дополнительных параметров атрибута. Интерпретация настроек выполняется конкретной специфической реализацией модуля.
На данный момент в модуле registry
поддерживаются следующие настройки:
"options": {
"cssClasses": ["class1", "class2"],
"cssStyles": {
"background-color": "#FF0000"
},
"template": "some-custom-template"
}
cssClasses
- классы css, которые нужно применить к полю (в стандартном шаблоне)cssStyles
- css стили, которые нужно применить к полю (в стандартном шаблоне)template
- имя шаблона, который будет использован для отрисовки поля. Будет выполнен поиск ejs-шаблона с таким именем в стандартной теме, а в директориях, указанных в настройке templates модуля.
В кастомном шаблоне доступны все переменные, передаваемые в стандартные шаблоны атрибутов:
item
- объект, отображаемый формойprop
- свойство объекта, представляемое полем (если есть)field
- мета-объект поляid
- идентификатор поля, сформированный по стандартному алгоритму
Сортировка - "reorderable": true
¶
Применимо для атрибутов типа «Коллекция». Определяет возможность сортировки элементов коллекции стрелками вверх и вниз, меняет порядковые номера между двумя элементами коллекции.
"options": {
"reorderable": true`
}
Подключение шаблона библиотеки template
¶
Указываем значение пути к шаблону - располагаются в папке проекта .\templates\registry\
. Пример для шаблона ниже ./templates/registry/attrs/project/stateView.ejs
"options": {
"template": "attrs/project/stateView"
}
Шаблону передается элемент item
с основными командами ${item.getItemId()}
:
- получения значения элемента
item.property('stage').getValue()
, - идентификатора
item.getItemId()
- имени класса
item.getClassName()
Элемент объектаprop
- имени (кода) свойства
prop.getName()
- вычислении значения атрибута (если формула)
prop.evaluate()
- значения атрибута
prop.getValue()
- ссылки на класс
prop.meta.refClass
Также передаются пути модуля ${module}
для подключения шаблонов , например <% stylesheet(
${module}/app-static/css/styles.css) -%>
treegrid
¶"options": {
"template": "treegrid/collection",
"reorderable": true,
"treegrid": {
"width": "auto,100,100,100,100,0",
"align": "left, center,center,center,center, left",
"sort": "str, date, date, date, date, int",
"enableAutoWidth": false,
"paging": {
"size": 20
}
}
}
По тому же принципу, что и в мете представлений создания/редактирования, можно задавать переопределяющие шаблоны для меты представлений списков для каждой колонки:
...
"options":{
"template": "templateDir/name"
}
...
"options": {
"template": "slider",
"slider": {
"skin": "dhx_skyblue"
}
}
range
¶Задается в представлении для свойства "options"
:
...
"tags": null,
"options": {
"template": "range"
}
...
"options": {
"inplaceInsertion": true,
"inplaceInsertionClass": "className@namespace"
}
"options"
атрибута «Таблица»¶{
"caption": "Таблица",
"type": 3,
"property": "table",
"size": 2,
"maskName": null,
"mask": null,
"mode": 3,
"fields": [],
"columns": [],
"actions": null,
"commands": null,
"orderNumber": 50,
"required": false,
"visibility": null,
"enablement": null,
"obligation": null,
"readonly": false,
"selectionPaginated": true,
"validators": null,
"hint": "",
"historyDisplayMode": 0,
"tags": null,
"options": {
"inplaceInsertion": true
},
"selConditions": [],
"selSorting": []
}
"inplaceInsertionClass"
указываем в том случае, если при создании объекта нужно выбирать класс (если есть наследники).
Настройка расположения заголовка атрибута над значением.¶
"options": {
"cssClasses": ["top-label"]
}
Настройка поля атрибута на всю длину строки (без наименования).¶
"options": {
"cssClasses": ["no-label"]
}
Настройка стилей применяемых к контейнеру, в котором содержится поле ввода с названием.¶
"options": {
"cssStyles": {
"max-width": "30%",
"padding": "25px"
}
}
Настройка параметров колонок таблицы для атрибута типа «Коллекция»¶
По умолчанию колонка даты имеет ширину 110 пикселей и выравнивание по центру.
Возможные опции атрибута:
"options": {
"template": "treegrid/collection",
"treegrid": {
"width": "150,auto,200",
"align": "center,left,center",
"sort": "str, str, str",
"enableAutoWidth": false,
"paging": {
"size": 20
}
}
}
Настройка CSS полей через tags
и options
¶
Можно настраивать CSS поля либо через tags
, либо через options
. В регистри есть соответствующие стандартные css-классы с нужным поведением: nolabel, toplabel, fill.
Для атрибута в мете представлений css-классы назначаются так:
options
:¶"options": {
"cssClasses": ["toplabel", "fill"]
}
tags
(обратная совместимость)¶"tags": ["css-class:nolabel", "css-class:fill"]
Помимо классов можно напрямую задавать и стили (они будут применены только к контейнеру).
Задаем стили для атрибута в мете представлений:
options
:¶"options": {
"cssStyles": {
"max-width": "30%",
"padding": "25px"
}
}
tags
:¶"tags": ["css:min-width:10%", "css:background-color:green"]
Описание выше относится только к стандартным шаблонам полей из стандартной темы оформления.
CSS поля¶
CSS поля - задают стили для значений атрибутов и настраиваются посредством атрибута tags
. Аналогичная настройка задается в "options"
с использованием шаблонов. Подробнее см. «Опции».
Синтаксис:¶
{
...
tags: [
"css-class:myCustomCssClass", // добавляем css-класс
"css:background-color:green", // добавляем css-стиль
"css:color:white" // добавляем css-стиль
]
}
{
"caption": "Первый атрибут на первой вкладке",
"type": 1,
"property": "tab_1_1",
"size": 2,
"maskName": null,
"mask": null,
"mode": null,
"fields": [],
"hierarchyAttributes": null,
"columns": [],
"actions": null,
"commands": [],
"orderNumber": 10,
"required": false,
"visibility": null,
"enablement": null,
"obligation": null,
"readonly": false,
"selectionPaginated": true,
"validators": null,
"hint": null,
"historyDisplayMode": 0,
"tags": ["css:background-color:##AFFFAF"]
}
Настройка стартовой позиции на карте¶
{
"caption": "Координаты",
"type": 100,
"property": "geo",
"size": 2,
"maskName": null,
"mask": null,
"mode": 0,
"fields": [],
"columns": [],
"actions": null,
"commands": null,
"orderNumber": 34,
"required": false,
"visibility": null,
"enablement": null,
"obligation": null,
"readonly": false,
"selectionPaginated": true,
"validators": null,
"hint": "",
"historyDisplayMode": 0,
"tags": [
"tryfind:Хабаровский край",
"tryfind:$address"
],
"selConditions": [],
"selSorting": []
}
Результат: при открытии формы создания координат - автоматически определятся координаты в соответствии со значением свойства "tags"
. Где $address
- значение атрибута address из текущего класса.
Режим отображения «Коллекция» и «Ссылка»¶
Режимы отображения типа представления «Коллекция» и «Ссылка» - это следующие константы в платформе:
module.exports = {
TEXT_SIMPLE: 0,
TEXT_AUTOCOMPLETE: 1,
COLLECTION_LIST: 0,
COLLECTION_LINK: 1,
COLLECTION_LINKS: 2,
COLLECTION_TABLE: 3,
COLLECTION_HASHTAGS: 4,
REF_STRING: 0,
REF_LINK: 1,
REF_INFO: 2,
REF_HIERARCHY: 3,
REF_SPECIFY: 4,
GEO_MAP: 0,
GEO_LOCATOR: 1,
GEO_CANVAS: 2,
GROUP_VERTICAL: 0,
GROUP_HORIZONTAL: 1
};
Для атрибута с типом «Коллекция» на форме представления реализованы режимы отображения "mode"
:¶
"mode": 0
- Список"mode": 1
- Ссылка"mode": 2
- Список ссылок"mode": 3
- Таблица"mode": 4
- Облако тегов
Для атрибута с типом «Ссылка» на форме представления реализованы режимы отображения "mode"
:¶
"mode": 0
- Строка"mode": 1
- Ссылка"mode": 2
- Форма"mode": 3
- Иерархическая ссылка"mode": 4
- Уточняющий поиск
Подробнее «Иерархическая ссылка»¶
В режиме Иерархическое поле, на основании заданных вложенных полей (fields) отображаются параметры фильтра на уровни иерархии. При первичной инициализации поля, выполняется ajax-запрос к контроллеру на получение первого списка выбора (фильтр не задан). При получении ответа от сервера отображается первое поле фильтра со списком выбора. Далее при выборе значения в каждом из полей фильтра сбрасываются значения следующих за ним полей и запрашивается новый список выбора для следующего поля. Поля не имеющие списка выбора скрываются. Если в списке выбора получен один вариант, он автоматически присваивается в фильтр и выполняется определение списка выбора для следующего уровня иерархии. При получении специального значения «transit» вместо списка выбора в следующий фильтр присваивается значение текущего и выполняется процедура получения списка выбора для очередного уровня иерархии, а поле, соответствующее фильтру, скрывается. Когда заданы значения всех полей фильтрации, контроллер возвращает список выбора объекта по ссылке, который автоматически отображается в отдельном поле расположенном после полей фильтрации.
Подробнее «Уточняющий поиск»¶
Поля уточняющего поиска нужны для того, чтобы упростить поиск объектов в ссылке. Проектировщик меты, исходя из предметной области, может определить часть атрибутивного состава искомого объекта как «уточняющую» и, таким образом, облегчить задачу как для БД, так и для пользователя. Т.е. вместо выбора из всего множества продуктов мы сперва выбираем значение поля «производитель», затем значение поля «тип продукта», варианты которого уже ограничены предыдущим фильтром, и т.д, таким образом существенно сокращаем выборку только теми продуктами, что соответствуют уточняющим атрибутам. Для такого поля становится возможным указать поля, которые будут ссылаться на атрибуты класса по ссылке и станут «уточняющими».
Тип Группа [0]¶
Описание¶
Группа [0] - структура представлений создания и изменения, которая позволяет в рамках одного класса группировать аттрибуты из других классов в представлении создания/изменения в горизонтальном и/или вертикальном виде.
Виды отображения типа Группа [0]¶
- GROUP_VERTICAL
"mode": 0
- поля группы располагаются друг под другом - GROUP_HORIZONTAL
"mode": 1
- поля группы располагаются горизонтально в строку (т. е. колонками, если хватает места)
Формат настройки в мете представления для типа «Группа»¶
{
"type": 0, // группа полей
"mode": 1, // отображается горизонтально
"fields": [
// поля
]
}
{
"type": 0, // группа верхнего уровня
"mode": 1, // колонки
"fields": [
{
"type": 0, // группа-колонка 1
"mode": 0,
"size": 0, // очень узкая
"fields": [
{
"property": "attr1",
"type": 1,
"caption": "Текстовое поле 1"
},
{
"property": "attr2",
"type": 1,
"caption": "Текстовое поле 2"
}
]
},
{
"type": 0, // группа-колонка 2
"mode": 0,
"size": 0, // очень узкая
"fields": [
{
"property": "attr3",
"type": 1,
"caption": "Текстовое поле 3"
},
{
"property": "attr4",
"type": 1,
"caption": "Текстовое поле 4"
}
]
},
{
"type": 0, // группа-колонка 3
"mode": 0,
"size": 3, // широкая
"fields": [
{
"property": "attr5",
"type": 1,
"caption": "Текстовое поле 5"
},
{
"property": "attr6",
"type": 1,
"caption": "Текстовое поле 6"
}
]
}
]
}
Типы представлений¶
Типы представлений - это следующие константы в платформе:
module.exports = {
GROUP: 0,
TEXT: 1,
REFERENCE: 2,
COLLECTION: 3,
CHECKBOX: 4,
COMBO: 5,
DATE_PICKER: 120,
DATETIME_PICKER: 6,
MULTILINE: 7,
WYSIWYG: 8,
RADIO: 9,
MULTISELECT: 10,
FILE: 11,
PASSWORD: 12,
IMAGE: 13,
NUMBER_PICKER: 14,
DECIMAL_EDITOR: 15,
URL: 17,
PERIOD_PICKER: 60,
GEO: 100,
ATTACHMENTS: 110,
SCHEDULE: 210,
CALENDAR: 220
};
NB: подробнее см. таблицу соответствий.
Код | Наименование | Описание |
---|---|---|
0 | Группа | Особая структура представлений создания и изменения. |
1 | Строковое | Представление для текстовых данных или приведение к текстовому виду. Настроен trim - т.е. отбрасывание пробелов с начала и конца строки |
2 | Ссылка | Для ссылочных полей, связь 1кN. Позволяет задавать возможные операции над объектами класса, на который ссылаемся. |
3 | Коллекция | Для коллекций, связь Nк1. Позволяет задавать возможные операции над объектами класса, на который ссылаемся. |
4 | Флаг | Чекбокс для логического типа. |
5 | Выпадающий список | Для имеющих заданное поле selectionProvider . |
7 | Многострочный текст | Представление для текста. Настроен trim - т.е. отбрасывание пробелов с начала и конца строки |
8 | Форматированный текст | Редактор форматированного текста. |
9 | Альтернативный выбор | В атрибуте типа «Множество [15]» может быть один элемент множества. Не реализовано |
10 | Множественный выбор | В атрибуте типа «Множество [15]» может быть несколько элементов множества. Не реализовано |
11 | Выбор файла | Представление для выбора и загрузки файла. |
12 | Пароль | По идее должно обеспечивать скрытие вводимых данных, но не реализовано. |
13 | Выбор изображения | Представление для выбора и загрузки изображения, проверяет что загружено именно изображение, отображает превью. |
14 | Редактор целых чисел | Редактор для целых чисел, проверяет корректность ввода. |
15 | Редактор вещественных чисел | Редактор для вещественных чисел, проверяет корректность ввода, требует использвоания . для отделения дробной части. |
17 | URL | Не реализовано |
60 | Выбор периода | Представление позволяющее вести две даты - границы периода. |
100 | Геоданные | Задает представление для типа «Геоданные [100]». |
110 | Набор файлов | Представление для выбора и загрузки нескольких файлов. Контролирует что файлы принадлежат к одному из указанных в мете атрибута типов, общий размер файлов и количество. |
210 | Расписание | Представление для типа атрибута «Расписание [210]», позволяет задать расписание, отображение в табличном виде. |
220 | Календарь | Представление для типа атрибута «Расписание [210]», позволяет задать календарь, отображение в виде календаря. |
Условия отображения¶
Описание¶
Условия отображения - задаёт условия отображения поля в представлении класса.
Настройка выполняется не только для логических полей, но и для строковых, строковых перечислимых (сравнивается значение по коду перечислимого).
Синтаксис¶
Символ
\u003d
обозначает операцию=
Символ
\u0027
обозначает операцию'
"visibility": ".visibility_condition_base !\u003d \u0027\u0027"
Данные символы нужны для корректного отображения условий в формате .json
Типы условий¶
Сложные условия:
".state == 'work' || .state == 'result' || .state == 'fin'"
где идет проверка по трём условиям с объединением
ИЛИ
(для условияИ
применяется знак&
).Сам синтаксис настройки похож на условия в js.
Логический:
".archive == true"
где идет проверка по значению логического атрибута.
- Простое условие:
".state == 'work'"
где идет проверка по значению атрибута со списком выбора.
- Числовое условие:
".magistral == 1"
где идет проверка по числовому значению атрибута.
- Пусто:
".meeting == ''"
- Не пусто:
"!! .meeting"
где идет проверка - есть ли значение в указанном атрибуте.
Пример в JSON:¶
{
{
"caption": "Основание для условия отображения",
"type": 1,
"property": "visibility_condition_base",
"size": 2,
"maskName": null,
"mask": null,
"mode": null,
"fields": [],
"hierarchyAttributes": null,
"columns": [],
"actions": null,
"commands": [],
"orderNumber": 20,
"required": false,
"visibility": null,
"enablement": null,
"obligation": null,
"readonly": false,
"selectionPaginated": true,
"validators": null,
"hint": null,
"historyDisplayMode": 0,
"tags": null
},
{
"caption": "Поле отобразится, если основание заполнено",
"type": 1,
"property": "visiility_condition_use",
"size": 2,
"maskName": null,
"mask": null,
"mode": null,
"fields": [],
"hierarchyAttributes": null,
"columns": [],
"actions": null,
"commands": [],
"orderNumber": 30,
"required": false,
"visibility": ".visibility_condition_base !\u003d \u0027\u0027",
"enablement": null,
"obligation": null,
"readonly": false,
"selectionPaginated": true,
"validators": null,
"hint": null,
"historyDisplayMode": 0,
"tags": null
},
{
"caption": "Поле отобразится, если в основании \u00271\u0027",
"type": 1,
"property": "visiility_condition_1",
"size": 2,
"maskName": null,
"mask": null,
"mode": null,
"fields": [],
"hierarchyAttributes": null,
"columns": [],
"actions": null,
"commands": [],
"orderNumber": 40,
"required": false,
"visibility": ".visibility_condition_base \u003d\u003d \u00271\u0027",
"enablement": null,
"obligation": null,
"readonly": false,
"selectionPaginated": true,
"validators": null,
"hint": null,
"historyDisplayMode": 0,
"tags": null
}
}
Описание¶
Атрибутивная часть меты представлений - описывает представление атрибута класса на форме. Атрибуты содержатся в виде массивов в соответствующих полях основной части меты представлений. Представление каждого атрибута - это объект следующей структуры:
JSON¶
{
"caption": "Редактор целых чисел [14]",
"type": 14,
"property": "integer_integer",
"size": 2,
"maskName": null,
"mask": null,
"mode": null,
"fields": [],
"hierarchyAttributes": null,
"columns": [],
"actions": null,
"commands": [],
"orderNumber": 20,
"required": false,
"visibility": null,
"enablement": null,
"obligation": null,
"readonly": false,
"selectionPaginated": true,
"validators": null,
"hint": "",
"historyDisplayMode": 0,
"tags": null
}
Описание полей¶
Поле | Наименование | Допустимые значения | Описание |
---|---|---|---|
"sorted" |
Разрешена сортировка | Логическое | Поле для представлений списка. Не используется в представлениях создания и изменения. Разрешает или запрещает сортировку по данному столбцу. |
"caption" |
Заголовок | Строка | Заголовок поля ввода/колонки атрибута отображаемый в представлениях. |
"type" |
Тип | Целое - идентификатор (код) типа | Тип представления атрибута. |
"property" |
Атрибут | Строка, только латиница без пробелов | Указывается имя атрибута, с которым будет работать система, а значит не может быть пустым (Кроме типа представления Группа [0]). |
"size" |
Размер | Целое - код размера поля ввода, типозависимо | Позволяет указать код размера поля для разных типов атрибута/представления. Константы в платформе FieldSizes. |
"maskName" |
Имя маски | Строка | При наличии в платформе предустановленных масок - можно задать маску по внутреннему имени, указав его в данном поле. |
"mask" |
Маска | Строка | Позволяет предопределять формат вводимого значения для атрибута. |
"mode" |
Режим отображения | Целое - код режима отображения | В ряде случаев бывает необходимо отображать данные атрибута по разному, как отображать - указывается в этом поле. Пример использования. |
"fields" |
Поля | Массив объектов | Позволяет сформировать представление создания/изменения особым образом. |
"hierarchyAttributes" |
Иерархия по | объект или Null | не используется в текущей версии |
"columns" |
Столбцы | Массив объектов | Применяется для атрибутов типа «Коллекция [3]». Позволяет выбрать атрибуты для отображения на форме представления в виде колонок таблицы (атрибуты берутся из класса по ссылке) |
"actions" |
Поведение | Целое или Null | не используется в текущей версии |
"commands" |
Действия | Массив объектов либо Null | Описывает допустимые действия (групповые действия) над объектами ссылочного поля. Null для дефолтного набора действий. |
"orderNumber" |
Порядковый номер | Целое неотрицательное | Порядковый номер атрибута задает расположение атрибута относительно других атрибутов этого же класса в пользовательском интерфейсе. |
"required" |
Обязательное | Логическое | Определяет обязательно ли заполнение данного атрибута при создании/изменении объекта. |
"visibility" |
Условия отображения | Строка | Задает условие отображения поля в представлении. |
"enablement" |
Условия активности | Строка | Задает условие активности (доступности для редактирования) поля в представлении с форматом, аналогичным условиям отображения. |
"obligation" |
Условия обязательности | Строка | Задает условие обязательности заполнения поля в представлении с форматом, аналогичным условиям отображения. |
"readonly" |
Только чтение | Логическое | Разрешает или запрещает изменять значение атрибута в данном представлении. |
"selectionPaginated" |
Постраничный список выбора | Логическое | Разрешает или запрещает постраничный список выбора. |
"validators" |
Валидаторы | Строка | Наименование валидатора, проверяющего введенные в поле атрибута значения. Не реализовано. |
"hint" |
Подсказка | Строка | Задает (или переопределяет заданное в поле "hint" меты атрибута) сообщение, которые выведется в пользовательском интерфейсе рядом с именем атрибута. |
"historyDisplayMode" |
Отображение истории | Целое | Указывает формат отображения истории изменения объектов. |
"tags" |
Теги | Массив строк | Хранит модификаторы отображения и стили для значений атрибутов. Расширенная спецификации свойства tags применяется в "options" , но не является взаимозаменяемой. |
Дополнительно:
Структура в mongoDB (registry) для представлений списка¶
{
"sorted" : true,
"caption" : "Редактор целых чисел [14]",
"type" : 14,
"property" : "integer_integer",
"size" : 2,
"maskName" : null,
"mask" : null,
"mode" : null,
"fields" : [],
"hierarchyAttributes" : null,
"columns" : [],
"actions" : null,
"commands" : [],
"orderNumber" : 20,
"required" : false,
"visibility" : null,
"enablement" : null,
"obligation" : null,
"readonly" : false,
"selectionPaginated" : true,
"validators" : null,
"hint" : "",
"historyDisplayMode" : 0,
"tags" : null
}
Структура атрибута для представлений создания и изменения отличается лишь отсутствием поля "sorted"
.
Мета бизнес-процесса¶
Безопасность бизнес-процесса¶
Описание¶
Безопасность в бизнес-процессе нужна для контроля прав над конкретным объектом одним пользователем и задается через мету класса, статусы и переходы бизнес-процесса.
Реализация¶
В мете заранее надо опеределить строковый атрибут, в котором будет храниться идентификатор пользователя.
Для контроля прав при переходах по БП надо в перееходе добавить присваивание текущего пользователя в атрибут, по которому будут выдаваться права на следующем статусе БП.
Затем задаем в статусе БП уровень доступа в свойстве itemPermissions
:
"itemPermissions": [
{
"role": ...
"permissions": ...
}
]
role
- указывается атрибут, который хранит идентификатор пользователяpermissions
- задается число по битовой маске, которое соотноcится с уровнем доступаrole
к объекту- 1 - чтение
- 2 - запись
- 4 - удаление
- 8 - использование
- 31 - полный доступ
Можно использовать права в любом порядке. Например:
- чтение + запись = 3
- чтение + запись + удаление = 7
- чтение + запись + удаление + использование = 15
Внимание! В бизнес-процессе динамические права могут только предоставить больше доступа. Уменьшить доступ нельзя.
Присваивание в переходе БП атрибуту person
текущего пользователя, работающим с объектом
"assignments": [
{
"key": "person",
"value": "$$uid"
}
]
Добавление itemPermissions
в статус БП
"states": [
{
"itemPermissions": [
{
"role": "person",
"permissions": 15
}
]
}
]
Статусы бизнес-процесса¶
JSON¶
"states": [
{
"name": "new",
"caption": "Новое",
"maxPeriod": null,
"conditions": [],
"itemPermissions": [],
"propertyPermissions": [],
"selectionProviders": []
}
]
Описание полей¶
Поле | Описание |
---|---|
"name" |
Системное имя статуса |
"caption" |
Логическое имя статуса |
"maxPeriod" |
нет данных |
"conditions" |
Условия для статуса БП. Задаются аналогично «Условиям отбора допустимых значений». |
"itemPermissions" |
Разрешения для объекта |
"propertyPermissions" |
Разрешения для свойств |
"selectionProviders" |
Выборка допустимых значений |
Переходы бизнес-процесса¶
JSON¶
"transitions": [
{
"name": "basic",
"caption": "На согласование",
"startState": "create",
"finishState": "inAgreed",
"signBefore": false,
"signAfter": false,
"roles": [],
"assignments": [],
"conditions": []
}
]
Описание полей¶
Поле | Описание |
---|---|
"name" |
Системное имя статуса. |
"caption" |
Логическое имя статуса. |
"startState" |
Начальный статус для осуществления перехода по БП. |
"finishState" |
Конечный статус по завершению перехода по БП. |
"signBefore" |
Логическое значение «Подписать до начала перехода». |
"signAfter" |
Логическое значение «Подписать по завершению перехода». |
"roles" |
Список ролей, с правами на осуществление перехода. |
"assignments" |
Присвоение значения атрибутам после осуществления перехода по БП. |
"conditions" |
Условия, выполняемые для осуществления перехода по БП. Задаются аналогично «Условиям отбора допустимых значений». |
Присвоение значения атрибутам по ссылке¶
Задается через свойство "assignments"
в переходе БП.
Пример
...
"assignments": [
{
"key": "resolution.stateRemPet",
"value": "end"
}
]
...
По ссылке атрибута типа «Ссылка» [resolution], для атрибута [stateRemPet] присвоить значение «end» - при выполнении данного перехода по БП.
Описание¶
Бизнес-процесс - это четкая последовательность действий, которую выполняют для получения заданного результата. Как правило, процесс многократно повторяется. Применение бизнес-процесса позволяет отображать стадии выполняемого процесса и задавать условия для его выполнения.
JSON¶
{
"name": "basic",
"caption": "Поручения",
"wfClass": "basic",
"startState": "new",
"states": [],
"transitions": [],
"metaVersion": "2.0.61"
}
Описание полей¶
Поле | Наименование | Описание |
---|---|---|
"name" |
Системное имя | Системное имя бизнес-процесса |
"caption" |
Логическое имя | логическое имя бизнес-процесса |
"wfClass" |
Класс БП | Класс, к которому применяется бизнес-процесс |
"startState" |
Статус | Статус, присвоенный началу бизнес-процесса |
"states" |
Список статусов | Список статусов бизнес-процесса. |
"transitions" |
Переходы | Переходы между статусами для бизнес-процесса. |
"metaVersion" |
Версионирование | Версия метаданных. |
Условие «contains» («содержит»)¶
Внимание! Чтобы в БП работало поле «contains», в коллекции должна быть настроена жадная загрузка. Иначе в коллекции будет пусто, и результат будет всегда false. Условия применяются к объекту извлеченному из БД, дополнительных запросов не делается.
Пример¶
{
"property": "charge",
"operation": 10,
"value": null,
"nestedConditions": [
{
"property": "state",
"operation": 1,
"value": [
"close"
],
"nestedConditions": []
}
]
}
Настройка подсказок¶
Настройка подсказок при переходе по статусу БП - представляет собой вывод инструкции в отдельном модальном окне с кнопками - «продолжить» или «отменить». При наведении на кнопку появляется всплывающий хинт, для более удобного использования бизнес-процессов.
Пример¶
"transitions": [
{
...
"confirm": true,
"confirmMessage": null
}
"confirm"
- подтверждение действия на переходе (+ стандартный вывод текста - вы действительно хотите выполнить действие «name»)."confirmMessage"
- уникальный текст для вывода в подтверждении взамен стандартного.
Утилита формирования массива объектов¶
Утилита позволяет создавать объект в коллекцию при переходе основного объекта в заданный статус. Поля созданного объекта автоматически заполняются в соответствии с настройками, заданными для свойства "values"
.
Теперь чтобы прикрепить утилиту создания значений показателя к этапу БП, надо в di
в свойстве options
прописать опцию
state - имя этапа БП
при переходе на который, должны создаваться объекты в коллекцию.
Есть возможность использовать утилиту как «action». При переделке нужно просто убрать команду из модели представления. Параметры задаются в файле deploy.json проекта. Синтаксис настройки:
"map": {
"workflow@namespace.stage": {
"className@namespace": { // для объекта какого класса создается объект в коллекцию
"collection": { // наименование атрибута коллекции, в которой создается объект
"elementClass": "className2@namespace", // класс, объекты которого создаются утилитой
"patterns": [
{
"values": {
"attr1": "string", // строка
"attr2": 123, // число
"attr3": true,
"attr4": "$containerProperty1", // свойство контейнера
"attr5": {"add": ["$containerProperty2", 300]} // формула
},
"push": [
"workflow2@namespace.stage1", // присвоение БП созданных объектов статуса
]
},
...
]
},
...
},
...
},
....
}
Безопасность бизнес-процесса¶
Безопасность в бизнес-процессе нужна для контроля прав над конкретным объектом одним пользователем и задается через мету класса, статусы и переходы бизнес-процесса. Подробнее о безопасности БП.
Таблица соответствия типов атрибутов типам представлений¶
Код типа атрибута | Наименование типа атрибута | Код основного типа представления | Наименование основного типа представления | Предпочитаемый тип отображения для основного типа представления | Допустимые типы представлений (выборочно) |
---|---|---|---|---|---|
0 | Строка | 1 | Текстовое | 7 - Многострочный текст, 8 - Форматированный текст | |
1 | Текст | 7 | Многострочный текст | 1 - Текстовое, 8 - Форматированный текст | |
2 | HTML | 8 | Форматированный текст | 1 - Текстовое, 7 -Многострочный текст | |
3 | URL | 17 | URL | ||
4 | Изображение | 13 | Выбор изображения | ||
5 | Файл | 11 | Выбор файла | ||
6 | Целое | 14 | Редактор целых чисел | ||
7 | Действительное | 15 | Редактор вещественных чисел | ||
8 | Десятичное | 15 | Редактор вещественных чисел | ||
9 | Дата/Время | 120 | Выбор даты | 6 - Выбор даты-времени | |
10 | Логический | 4 | Флаг | ||
11 | Пароль | 12 | Пароль | ||
12 | Глобальный идентификатор | 1 | Текстовое | ||
13 | Ссылка | 2 | Ссылка | 1 - Ссылка | |
14 | Коллекция | 3 | Коллекция | 3 - Таблица | |
15 | Множество | 9 | Альтернативный выбор | 10 - Множественный выбор | |
16 | Структура | 0 | Группа | ||
17 | Пользовательский тип | не определено, зависит от базового типа | |||
18 | Пользователь | 1 | Текстовое | ||
60 | Период | 60 | Выбор периода | ||
100 | Геоданные | 100 | Геообъект | 0 - Карта | |
110 | Коллекция файлов | 110 | Набор файлов |
Переменные¶
Значение атрибутов¶
$
- применяется вместе с системным наименованием атрибута и возвращает значение указанного атрибута, т.е. если указать $name
при формировании какого-либо условия для действий над значениями атрибутов, то значение атрибута name
и будет источником для заданного условия.
Пример применения для вычислямого атрибута
{
"formula": {
"count": [
"$projects"
]
}
...
}
В текущем классе есть атрибут типа «Коллекция» projects
и, согласно формуле, необходимо посчитать колличество значений данного атрибута.
Результат: количество объектов атрибута projects
.
Текущая дата/время, дата¶
$$now
- возвращает текущую дату и время
Пример применения для фильтра допустимых значений в навигации:
{
"property": "dateEnd",
"operation": 5,
"value": [
"$$now"
],
"nestedConditions": []
}
"dateEnd"
меньше текущей даты/времени
Пример применения для вывода значения по умолчанию в мете класса:
...
"defaultValue": "$$now",
...
$$today
- возвращает начало суток текущей даты
принцип тот же, только дата без времени
Синтаксис форматирования дат в формате momentjs¶
'DD.MM.YYYY'
NB: В драйвере к монгодб поддерживаются только основные возможности формата momentjs
Текущий пользователь¶
$$uid
- возвращает текущего пользователя
Пример применения для фильтра допустимых значений в коллекции:
{
"property": "collectionAttr",
"operation": 10,
"nestedConditions": [
{
"property": "user",
"operation": 0,
"value": ["$$uid"]
}
]
}
По ссылке атрибута типа «коллекция» отображаются только те объекты, у которых значение атрибута «user» совпадает со значением текущего пользователя.
Метаданные (Мета) - совокупность JSON-файлов в полной мере описывающих комплект структур, которыми оперирует приложение, способов отображения данных структур в пользовательском интерфейсе и навигации по ним, а так же файлов конфигурации приложения.
Типы файлов меты¶
Структура основных типов меты¶

Структуру основных типов меты можно представить следующим образом:
Мета классов является основным источником формирования данных в приложении. Мета классов состоит из атрибутов (атрибутивная часть) и параметров самого класса (общая часть). Атрибуты - это объекты массива «properties» общей части, которая содержит поля, имеющие отношение к самой структуре и способам оперирования данными в структуре.
На основе меты классов задается мета представлений, мета навигации, мета отчетов, мета бизнес-процессов и т.д.
Мета представления (класса) позволяет задавать желаемый состав атрибутов этого класса для отображения на форме, в соответствии с типом формы представления (представление формы списка list.json
, создания create.json
, изменения класса item.json
) и указывать для каждого отдельного атрибута свойства, переопределяемые и (или) дополняемые свойства, задаваемые в мете класса для данного атрибута.
Мета представления + Атрибуты класса = Отображение атрибутов на форме
Мета навигации регулирует расположение элементов в навигационном блоке. Мета навигации разделяется на мету узлов навигации и мету секции навигации.
Наименование файлов меты:¶
Мета класса | Мета представлений | Мета навигации |
---|---|---|
Находится в
директории
meta и состоит из
наименования
общей части меты
класса +
.class.json. .Например:
adress.class.json . |
В наименовании директории
определяется к какому классу относится
представление. Мета представлений
располагается в директории
views , вкоторой содержатся директории,
наименования которых совпадают с
первой частью наименований файлов
меты классов. Например:
address@project_name , где address относится к классу
address . |
Мета секций
навигации: состоит из
поля
"name" + .section.json инаходится в
директории
navigation .Например:
workflow.section.json . |
Конфигурация платформы¶
Настройки авторизации и безопасности¶
Параметры конфигурации приложения, файл deploy.json
¶
Параметры конфигурации приложения предназначены для определения ключевых возможностей системы при работе приложения на этапе проектирования и изменения параметров по умолчанию.
Настройка параметров авторизации при работе с паролем¶
Параметры и требования работы с паролем задаются в di
в конфигурации компонента auth
модуля.
Но в основном настройки задаются глобально.
{
"globals": {
"parametrised": true,
"plugins":{
"auth": {
"module": "lib/auth",
"initMethod": "init",
"initLevel": 2,
"options": {
"app": "ion://application",
"logger": "ion://sysLog",
"dataSource": "ion://Db",
"acl": "ion://aclProvider",
"passwordLifetime": "[[auth.passwordLifeTime]]", // Максимальный срок действия пароля
"passwordMinPeriod": "[[auth.passwordMinPeriod]]", // Минимальный срок действия пароля
"passwordMinLength": "[[auth.passwordMinLength]]", // Минимальная длина пароля
"passwordComplexity": { // Требования к сложности пароля
"upperLower": true, // Обязательно верхний и нижний регистр
"number": true, // Обязрательно использование хотя бы одного числа
"special": true // Обязательно использование хотя бы одного специального символа
},
"passwordJournalSize": "[[auth.passwordJournalSize]]", // Вести журнал паролей размере паролей
"tempBlockInterval": "[[auth.tempBlockInterval]]", // Время до сброса счетчика блокировки
"attemptLimit": "[[auth.attemptLimit]]", // Пороговое значение количества попыток для блокировки
"tempBlockPeriod": "[[auth.tempBlockPeriod]]" // Продолжительность блокировки учетной записи
}
}
При этом значения обозначенные [[auth.passwordLifeTime]]
могут быть переконфигурированы в файле настроек приложения /config/setup.ini
.
Но для этого обязательно нужно проверить, что задана настройка «parametrised»: true, на уровне global.
Время жизни задается в формает [длительность][ед. изм]
, при этом единицы измерения:
- y - год
- d - день
- h - час
- m - минута
- s - секунда
По умолчанию значения ключевых параметров:
- passwordLifetime = 100y
- passwordMinPeriod = 0d
- passwordMinLength = 8
Все создаваемые пароли в системе, в том числе импортированные, автоматически проставляются как требуемые к смене.
Чтобы при импорте пароли не требовалось менять, в свойствах пользователя в импортируемом файле acl должен быть указан параметр needPwdReset: false
Настройка минимальной длины пароля для входа в систему¶
Для указания минимальной длины пароля для входа в систему используем свойство "passwordMinLength"
"plugins":{
"accounts": {
"options": {
"passwordMinLength": 8
}
}
}
Настройка прав доступа «aclProvider»¶
"plugins":{
"aclProvider": {
"module": "core/impl/access/aclMetaMap",
"initMethod": "init",
"initLevel": 1,
"options":{
"dataRepo": "lazy://dataRepo",
"acl": "lazy://actualAclProvider",
"accessManager": "lazy://roleAccessManager"
}
}
Параметры настроек фреймворка и приложения в файле config/setup.ini
¶
Настройки предназначены для уточнения и изменения параметров приложения и инициализируются при запуске. Настройки имеют более высокий приоритет, чем параметры конфигурации.
Настройки приложения могут быть также заданы в переменных окружения; при этом переменные окружения имеют более высокий приоритет перед настройками.
Переопределение параметров конфигурации паролей¶
Параметры работы с паролями, заданные в deploy.json
проекта, если включена параметризация и указан код параметр, можно переопределить через настройки платформы или через переменные окружения.
Пример файла настроек /config/setup.ini
, в котором переопределяются значения, указанные в примере файла deploy.json
.
# Максимальный срок действия пароля
auth.passwordLifeTime=90d
# Минимальный срок действия пароля
auth.passwordMinPeriod=75d
# Минимальная длина пароля
auth.passwordMinLength=8
# Вести журнал паролей размере паролей
auth.passwordJournalSize=5
# Время до сброса счетчика блокировки
auth.tempBlockInterval=30m
# Пороговое значение блокировки
auth.attemptLimit=6
# Продолжительность блокировки учетной записи
auth.tempBlockPeriod=30m
# Время жизни авторизованной сессии, при отсутствии активности
auth.sessionLifeTime=4h
Настройка параметров сессии в системе¶
Длина сессии задается в config/config.json в sessionHandler
, с применением плейсхолдеров для параметра cookie.maxAge
:
"sessionHandler": {
"module": "lib/session",
"initMethod": "init",
"initLevel": 1,
"options": {
"app": "ion://application",
"dataSource": "ion://Db",
"session": {
"secret": "ion:demo:secret",
"resave": false,
"saveUninitialized": true,
"cookie": {
"httpOnly": true,
"secure": false,
"maxAge": "[[auth.sessionLifeTime]]"
}
}
}
}
Добавляем настройку в deploy.ini-файл проекта. Формат задания аналогичен настройкам периодов в auth
:
auth.tempBlockPeriod=2s
auth.tempBlockInterval=15m
auth.blockPeriod=1d
auth.sessionLifeTime=2h
Также можно задавать просто числом, тогда это будет задание в миллисекундах.
Для хранения сессии не в базе данных, а в сервере кеширования redis, добавляем настройку и параметры кеширования в deploy.ini-файл проекта
session.type=redis
cache.redis.host=127.0.0.1
cache.redis.port=6379
Настройка отключения формы авторизации для перехода на страницу модуля¶
В конфиге ядра у поля «auth» есть настройка exclude
:
"auth": {
"module": "lib/auth",
"initMethod": "init",
"initLevel": 2,
"options": {
"app": "ion://application",
"logger": "ion://sysLog",
"dataSource": "ion://Db",
"denyTopLevel": "[[auth.denyTop]]",
"authCallbacks": ["[[auth.callback]]"],
"publicRegistration": "[[auth.registration]]",
"exclude": ["[[auth.exclude1]]", "[[auth.exclude2]]", "[[auth.exclude3]]"]
}
}
То есть прописываем в ini-файле проекта:
auth.exclude[] = /registry/ # исключаем только запросы к корню модуля
auth.exclude[] = /registry/** # исключаем запросы ко всем страницам модуля
auth.exclude[] = \/registry\/khv-svyaz-info@naselenniePunkty\/\w+ # исключаем запросы ко всем страницам модуля
внутри ноды khv-svyaz-info@naselenniePunkty
auth.exclude[] = /registry/api/naselenniyPunkt@khv-svyaz-info/** # исключаем запросы к api класса
При переходе на страницу указанного в настройке модуля - данные отображаются без необходимости авторизации.
Отключение авторизации для статичных путей на примере проекта develop-and-test:¶
; Исключение статичных путей ядра из проверки доступа безопасности
auth.exclude[]=/
auth.exclude[]=/vendor/**
auth.exclude[]=/css/**
auth.exclude[]=/fonts/**
auth.exclude[]=/favicon.ico
; Исключение статичных путей модулей из проверки доступа безопасности
auth.exclude[]=/registry/vendor/**
auth.exclude[]=/registry/css/**
auth.exclude[]=/registry/js/**
auth.exclude[]=/registry/app-vendor/**
auth.exclude[]=/registry/app-static/**
auth.exclude[]=/registry/common-static/**
auth.exclude[]=/registry/img/**
auth.exclude[]=/registry/fonts/**
auth.exclude[]=/dashboard/vendor/**
auth.exclude[]=/dashboard/develop-and-test/** ; для проекта develop-and-test
auth.exclude[]=/dashboard/js/**
auth.exclude[]=/registry/viewlib-ext-static/** ; для проекта viewlib-extra
auth.exclude[]=/registry/viewlib-static/js/** ; для проекта viewlib
auth.exclude[]=/gantt-chart/vendor/**
auth.exclude[]=/gantt-chart/gantt/**
auth.exclude[]=/gantt-chart/css/**
auth.exclude[]=/gantt-chart/js/**
auth.exclude[]=/gantt-chart/common-static/**
auth.exclude[]=/gantt-chart/fonts/**
auth.exclude[]=/geomap/vendor/**
auth.exclude[]=/geomap/css/**
auth.exclude[]=/geomap/js/**
auth.exclude[]=/geomap/common-static/**
auth.exclude[]=/geomap/img/**
auth.exclude[]=/geomap/fonts/**
auth.exclude[]=/report/vendor/**
auth.exclude[]=/report/css/**
auth.exclude[]=/report/js/**
auth.exclude[]=/report/common-static/**
auth.exclude[]=/report/img/**
auth.exclude[]=/report/fonts/**
; Исключение всего модуля из проверки доступа безопасности
auth.exclude[]=/portal/**
Способы конфигурации параметров:¶
- через ini-файлы
- через переменную окружения
NB: Приоритетной является настройка, заданная через переменные окружения, а не через ini-файлы. При этом настройки /config/setup.ini не влияют на настройки деплой приложения - они используются только для ядра и модулей. Deploy.json чаще всего параметризируеются через ini в дирректории приложения, например файл deploy.ini.
Пример конфигурации параметров ownCloud, вместе с учетной записью¶
Для начала необходимо задать в deploy.json
параметрические настройки хранилища:
"ownCloud":
"ownCloud": {
"module": "core/impl/resource/OwnCloudStorage",
"options": {
"url": "[[ownCloud.url]]",
"login": "[[ownCloud.login]]",
"password": "[[ownCloud.pwd]]"
}
}
Конфигурация параметров deploy через ini-файлы:¶
В ini-файле deploy.ini
рядом c deploy.json задать параметры следующего вида:
ownCloud.url=https://owncloud.com/
ownCloud.login=api
ownCloud.pwd=api
Конфигурация параметров deploy через переменную окружения:¶
В переменных окружения для ноды при конфигурации приложения задать параметры следующего вида:
ownCloud.url=https://owncloud.com/
ownCloud.login=api
ownCloud.pwd=api
Настройка ограничения¶
Настройка ограничения переключения по пунктам системного меню для анонимного пользователя. Системное меню формируется с учетом контроля доступа к страницам модулей, т.е. нет прав на страницу модуля - не отображается пункт меню, для перехода на данный модуль, в системном меню. В ini-файле приложения необходимо выставить auth.checkUrlAccess=true
, чтобы задать настройку ограничения.
Изменение всех ссылок на относительные¶
Чтобы изменить все ссылки на относительные, в ini-файле проекта укажите:
app.baseUrl= '/нужный_путь/'
Если путь не указан то считается по умолчанию „/“.
Настройка в модуле админа блока управления запуском заданий по расписанию¶
Для отображения пункта меню необходимо добавить в ini-файл проекта настройку:
jobs.enabled=true
Она включит шедулер (англ. scheduler) в процессе веб-сервера, что даст возможность управлять джобами из модуля админа.
Шедулер — управляет таймерами запуска задач.
Джоб — конкретная задача, запускаемая по таймеру.
Настройка кеширования данных на уровне ядра¶
Настройка кеширования данных на уровне ядра - позволяет корректно восстановливать из кеша жаднозагружаемые ссылочные атрибуты и коллекции, а также файлы и вычисляемые атрибуты. Корректно кешируются списки. Внедрено кеширование в геомодуле. Настройка раз и навсегда решает проблему циклических ссылок при сериализации объектов.
В ini-файле прописываем:
cache.module=memcached
Настройка временных ограничений¶
connectTimeOut
- максимальное время установления соединения.
operTimeOut
- максимальное время выполнения операции.
db.connectTimeOut=
db.operTimeOut=
Настройка минимальной длины пароля¶
auth.passwordMinLength=8
Переопределить настройку для отдельного приложения можно в файле deploy.json
Конфигурационный файл - deploy.json
¶
Сборка deploy из отдельных файлов¶
Разделение файла конфигурации deploy.json¶
Для удобства организации и повышения читаемости конфигурации приложения в deploy.json есть возможность разделить этот файл на несколько отдельных файлов конфигурации.
Варианты разделения могут быть любыми - можно вынести из него только конфигурацию модулей приложения или описывать каждый объект deploy в отдельном файле.
Для конфигурации в папке deploy приложения нужно поместить произвольные файлы с расширениями .json или .yml.
Для корректной работы в них необходимо сохранить изначальную структуру deploy.json - объекты должны быть вложены друг в друга в том же порядке, что в исходном файле. Исключение - модули приложения.
Например, если в deploy.json был определен объект globals.jobs.ticketClose.di, то для вынесения объекта di в отдельный файл в этом файле должна быть воспроизведена структура этих вложенных объектов:
---
globals:
jobs:
ticketClose:
di:
ticketCloser:
executable: applications/khv-ticket-discount/lib/overnightTicketClose
options:
dataRepo: ion://dataRepo
log: ion://sysLog
workflows: ion://workflows
Файлы конфигурации модулей¶
В случае конфигов модулей, их можно также
- Разместить в директориях deploy/modules/<имя модуля>/
- Вынести конфиг для модуля целиком в файл deploy/modules/<имя модуля>.yml (.json)
Описание при этом начинается с корня модуля (а не приложения):
---
globals:
navigation:
namespaces:
khv-ticket-discount: Льготные билеты
eagerLoading:
"*":
applicant@khv-ticket-discount:
item:
- documents.vidDocument
flight@khv-ticket-discount:
list:
- route.pointDeparture
- route.pointArrival
listSearchOptions:
ticketYear@khv-ticket-discount:
"*":
searchBy:
- flight
- person
- numberTicket
- area
refDepth: 3
flight@khv-ticket-discount:
"*":
searchBy:
- route
- number
refDepth: 3
di:
pmListToDocx:
module: modules/registry/export/listToDocx
initMethod: init
initLevel: 0
options:
tplDir: applications/khv-ticket-discount/export/list
log: ion://sysLog
injectors:
- ion://monthTicketStatsInjector
...
Глобальные настройки в deploy.json
¶
Глобальные настройки конфигурации приложения включает в себя следующие разделы:
- Пространство имен приложния
"namespace"
- Параметризация
"parametrised"
- Путь к шаблонам
"theme"
- Время кеширования и другие параметры для статичных файлов https://expressjs.com/en/4x/api.html#express.static
"staticOptions"
(работает при NODE_ENV=production) - Наименование вкладки в браузере
"pageTitle"
- Модули приложения
"moduleTitles"
- перейти - Настройка отображения общего системного меню для всех модулей проекта
"explicitTopMenu"
- перейти - Переопределение настроек хранилища сессий
"sessionHandler"
"actualAclProvider"
"aclProvider"
- Настройка HTML атрибутов для отображения и сохранения картинок в атрибуте
"fileStorage"
- перейти - Настройки отображения имени пользователя и аватара во всех модулях проекта
"customProfile"
- перейти - Настройка глубины жадной загрузки
"dataRepo"
- перейти "accounts"
"securedDataRepo"
"ldap"
"auth"
"sendmail"
"nodemailer"
"emailNotifier"
"notifier"
"eventNotifier"
- Настройки интеграции с календарем
"icsMailer"
- перейти "recache"
"fact-creator"
"report-builder"
"projectReportCreator"
Структура которых строится следующим образом:
{
"namespace": "...",
"parametrised": true,
"globals": {
"theme": "...",
"staticOptions": {...},
"pageTitle": "...",
"moduleTitles": {...},
"explicitTopMenu": [...],
"plugins": {
"sessionHandler": {...},
"actualAclProvider": {...},
"aclProvider": {...},
"fileStorage": {...},
"customProfile": {...},
"dataRepo": {...},
"accounts": {...},
"securedDataRepo": {...},
"ldap": {...},
"auth": {...},
"sendmail": {...},
"nodemailer": {...},
"emailNotifier": {...},
"notifier": {...},
"eventNotifier": {...},
"icsMailer": {...}
},
"jobs": {
"recache": {...},
"fact-creator": {...},
"report-builder": {...},
"projectReportCreator": {...}
}
}
}
Модули приложения¶
Для свойства необходимо задать модули, которые будут использованы в приложении в поле «moduleTitles». Также эти же модули будут отображаться в системном меню.
{
"namespace": "crm",
"globals": {
"moduleTitles": {
"registry": "Тех. поддержка",
"report": "Отчеты"
}
}
}
Для скрытия модуля из системного меню проекта присваиваем этому модулю, в файле deploy.json
, значение null, например "ionadmin": null
.
{
"namespace": "project-management",
"parametrised": true,
"globals": {
"moduleTitles": {
"registry": {
"description": "Проектное управление",
"order": 10,
"skipModules": true
},
"ionadmin": null
}
}
}
Настройка отображения общего системного меню для всех модулей проекта¶
Для того, чтобы в системном меню отображался одинаковый набор пунктов, не зависимо от того, на странице какого модуля находишься - необходимо в deploy.json
файле проекта задать "explicitTopMenu"
на глобальном уровне, с сохранением возможности переопределять "explicitTopMenu"
в registry
.
"globals": {
"explicitTopMenu": [
{
"id":"mytasks",
"url": "/registry/project-management@indicatorValue.all",
"caption":"Мои задачи"
},
{
"id":"projectmanagement",
"url": "/registry/project-management@project",
"caption":"Проектное управление"
},
{
"type": "system",
"name": "gantt-chart"
},
{
"type": "system",
"name": "portal"
},
{
"type": "system",
"name": "geomap"
},
{
"type": "system",
"name": "report"
},
{
"id":"distionary",
"url": "/registry/project-management@classification.okogu",
"caption":"Справочники"
},
{
"id":"mark",
"url": "/registry/project-management@person",
"caption":"Прогресс-индикатор"
}
],
"id"
- идентификатор секции навигации"url"
- url секции навигации"caption"
- наименование секции навигации"name"
- системное наименование модуля
Поле «plugins»¶
В данном поле задаются настройки, которые позволяют дополнительно расширить возможности приложения.
"plugins":{
"fileStorage": {
"module": "core/impl/resource/OwnCloudStorage",
"options": {
"url": "https://owncloud.iondv.ru/",
"login": "api",
"password": "apiapi"
}
}
"htmlFiles": {
"module": "core/impl/resource/FsStorage",
"initMethod":"init",
"initLevel": 3,
"options": {
"storageBase": "./htmlFiles",
"urlBase": "/htmlFiles",
"dataSource": "ion://Db",
"log": "ion://sysLog",
"app": "ion://application",
"auth": "ion://auth"
},
"htmlImages": {
"module": "core/impl/resource/ImageStorage",
"initMethod": "init",
"initLevel": 3,
"options": {
"fileStorage": "ion://htmlFiles",
"app": "ion://application",
"auth": "ion://auth",
"log": "ion://sysLog",
"urlBase": "/htmlFiles",
"thumbnails": {
"small": {
"width": 100,
"height": 100
}
}
}
}
}
"modules": {
"registry": {
"globals":
{
"refShortViewDelay": 1000, // количество миллисекунд до появления окна с инфо. Если не указан или 0, или нет shortView представления, то окно не выводится
"defaultImageDir": "images",
"contentImageStorage": "htmlImages"
}
Настройки отображения имени пользователя и аватара во всех модулях проекта¶
Для задания аватара через деплой прописываем связь с изображением. Аватар будет браться из соответствующего атрибута класса, объект которого привязан к текущему системному пользователю.
"customProfile": {
"module": "lib/plugins/customProfile",
"initMethod": "inject",
"options": {
"auth": "ion://auth",
"metaRepo": "ion://metaRepo",
"dataRepo": "ion://dataRepo",
"propertyMap": {
"person@project-management": {
"filter": "user",
"properties": {
"avatar": "foto"
}
}
}
}
}
Настройка глубины жадной загрузки¶
"dataRepo": {
"options": {
"maxEagerDepth": 4
}
}
Настройки интеграции с календарем¶
Интеграция осуществляется следующим образом: модуль по событию отправляет письмо с прикрепленным ics-файлом
, в котором указано событие iCalendar. Outlook воспринимает такое письмо как приглашение на собрание. Яндекс тоже добавляет собрание в календарь.
Конфигурации модуля:
"icsMailer": {
"module": "applications/extensions/lib/icsMailer",
"initMethod": "init",
"initLevel": 2,
"options": {
"dataRepo": "ion://dataRepo",
"transport": {...}, //Настройки smtp-сервера
"defaults": {...}, //Общий настройки всех писем
"listeners": [
{
"component": //Ссылка на слушаемый компонент
"events": {
"...": {// Идентификатор события
"calendar": {...}, //Настройки календаря, несущего событие и передаваемого в ics-вложении
"event": {...}, //Настройки VEVENT, передаваемого в ics-вложении
"filename": "...", //Имя вложенного ics-файла
"letter": {...} //Настройки письма, отправляемого по событию.
}
}
}
]
}
}
- Подробности настройки transport и defaults.
- Подробности настройки letter
- Подробности настройки calendar
- Подробности настройки event
Для настроек letter, event, filename и calendar предусмотрена возможность использовать данные из объекта события, указывая имена свойств через точку refAttr.stringAttr
, либо обернув эту конструкцию в ${refAttr.stringAttr}
когда необходимо использовать шаблон.
Полный пример файла deploy.json
Настройки модулей в deploy.json
¶
- Модуль «registry»
- Модуль «geomap»
- Модуль «gantt-chart»
- Модуль «report»
- Модуль «rest»
- Модуль «portal»
- Модуль «ionadmin»
- Модуль «dashboard»
- Модуль «diagram»
Модуль «registry»¶
Модуль регистра (registry) – ключевой модуль предназначенный непосредственно для работы с данными на основе структур метаданных – в том числе по ведению проектов, программ, мероприятий и др. Подробнее о модуле регистра.
Для того, что бы задать путь сохранения файла в хранилище - указываем:
"modules": {
"registry": {
"globals": {
...
"storage": {
"className@ns":{
"file_attr":"/${class}/example_${attr}/${dddd}/"
}
},
...
В объекте ключом является название класса, дальше «название атрибута» : «относительный путь».
Алиасы записываются в ${алиас}
. Доступные алиасы:
class
- имя классattr
- имя атрибута- также доступны обозначения дат из
moment.js
Для всего приложения - "listSearchMinLength"
.
"modules": {
"registry": {
"globals": {
"listSearchMinLength": 1
}
}
}
Для отдельного класса "minLength"
.
"modules": {
"registry": {
"globals": {
"listSearchOptions": {
"className@ns": {
"*": {
"searchBy": [
"atr1"
],
"splitBy": "\\s+",
"mode": [
"starts"
],
"joinBy": "and",
"minLength": 3
}
}
}
}
}
Для случаев, когда необходимо присваивать значение для атрибут по ссылке, не при сохранении объекта, а при создании, указываем в deploy.json
приложения настройку для класса, который содержит присваемое значение:
"registry": {
"globals": {
"forceMaster": {
"name_class@ns": true
}
}
}
Пример использования генераторов последовательностей - сейчас для каждого объекта его код - это код его непосредственного контейнера плюс очередное значение счетчика последовательности привязанного к объекту-контейнеру.
"skipEnvOptions"
¶Подробнее о печатных формах.
С помощью флага skipEnvOptions
можно настроить/отключить жадную загрузку.
...
"modules": {
"registry": {
"globals": {
...
"di": {
...
"export": {
"options": {
"configs": {
"class@ns": {
"expertItemToDocx": {
"type": "item",
"caption": "Наименование",
"mimeType": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
"extension": "docx",
"skipEnvOptions": true,
"preprocessor": "ion://expertItemToDocx"
}
}
}
}
}
...
}
}
}
}
...
При жадной загрузке файл создается быстро, но это не всегда может быть приемлемо.
В настройке уведомления о редактировании объекта другим пользователем указывается время жизни для блокировки в милисекундах:
"modules": {
"registry": {
"globals": {
"concurencyCheck": 10000
}
}
}
Компонент ConcurencyChecker:
Компонент ConcurencyChecker
в датасорсе хранит состояние блокировки для объектов.
Хранит следующие параметры:
- полный id объекта (класс@id),
- датавремя блокировки (blockDate),
- заблокировавший пользователь.
Компонент создает состояния блокировки, при этом запускается таймер, по которому запись о блокировке удаляется по истечении таймаута. Если на момент срабатывания таймера запись оказывается еще актуальной (обновляли blockDate), то запись не удаляется, а таймер обновляется.
Логика в контроллере view:
Читаем из сетингов настройку registry.concurencyCheck (таймаут блокировки в секундах).
Если она больше 0, обращаемся к ConcurencyCheker
- проверяем состояние блокировки.
Если не найдено (либо просрочена - blockDate < now() - registry.concurencyCheck), то через чекер записываем новую блокировку от имени текущего пользователя. Если найдена живая блокировка - передаем в шаблон информацию о блокировке, которую отображаем на форме и отображаем форму в режиме для чтения (globalReadOnly
).
Дополнительный контроллер concurencyState
, который принимает id объекта и проверяет его состояние блокировки. Если объект не заблокирован (нет блокировки, либо она просрочена), то блокирует объект от имени текущего пользователя. Если объект заблокирован текущим пользователем, обновляет blockDate на new Date(). Возвращает состояние блокировки.
Поведение формы объекта:
Если в шаблон передана инфа о блокировке, то добавляется скрипт, который периодически (с периодом registry.concurencyCheck/2
) обращается к контроллеру concurencyState
.
Если в ответ приходит информация о блокировке другим пользователем - она отображается (обновляем сообщение), если произошел перехват блокировки текущим пользователем - форма перезагружается (она при этом отображается в режиме для редактирования).
Это имеет отношение, например к группам в специальном стиле - чтобы не подключать ресурсы через изменения шаблонов модуля - необходимо их подключить в приложении.
"statics": {
"geoicons": "applications/khv-svyaz-info/icons"
}
Все, что внутри директории icons
доступно по ссылке registry/geoicons
.
Пример с параметрами в params
:
...
"di": {
"pmListToDocx": {
"module": "modules/registry/export/listToDocx",
"initMethod": "init",
"initLevel": 0,
"options": {
"tplDir": "applications/project-management/export/item2",
"log": "ion://sysLog"
}
}
...
"export": {
"options": {
"configs": {
"evaluationPerform@project-management": {
"rating": {
"caption": "Оценка деятельности исполнителя и соисполнителей проекта",
"mimeType": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
"extension": "docx",
"type": "list",
"query": {
"filter": {
"and": [
{
"eq": [
"$basicObjPerform",
":project"
]
},
{
"gte": [
"$date",
":since"
]
},
{
"lte": [
"$date",
":till"
]
}
]
}
},
"params": {
"project": {
"caption": "Проект",
"type": "reference",
"className": "project@project-management"
},
"since": {
"caption": "Период с",
"type": "date",
"default": "$monthStart"
},
"till": {
"caption": "Период по",
"type": "date",
"default": "$monthEnd"
}
},
"eagerLoading": [
"ownOrg",
"basicObjs"
],
"preprocessor": "ion://pmListToDocx"
}
}
...
Функционал позволяет на уровне класса определять, как ищем объекты класса из представления списка: по вхождению слов или полные слова, по отдельным атрибутам или по указанным атрибутам в списке с параметрами поиска через пробел.
"listSearchOptions": {
"person@khv-childzem": {...} // для класса
"khv-childzem@person": {...} // только в узле навигации person
"*": {...} // везде по умолчанию
}
вместо ...
подставляем атрибуты и задаем операции для поиска, например:
"searchBy": [ // атрибуты по которым ищем, по умолчанию то, что выводится в колонках
"surname",
"name",
"patronymic"
],
"splitBy": "\\s+", // разбивать поисковую фразу регуляркой, части сопоставить с атрибутами
"mode": ["starts", "starts", "starts"], // режимы сопоставления - в данном случае "начинается с" (доступны like, contains, starts, ends)
"joinBy": "and" // режим объединения условий на атрибуты (по умолчанию or)
Иерархическое представление коллекций- отображает коллекции, в которых элементы связаны друг с другом в виде иерархического справочника. В библиотеке viewlib
реализован кастомный контроллер, возвращающий в формате TreeGrid
очередной уровень иерархии.
"treegridController": {
"module": "applications/viewlib/lib/controllers/api/treegrid",
"initMethod": "init",
"initLevel": 0,
"options": {
"module": "ion://module",
"logger": "ion://sysLog",
"securedDataRepo": "ion://securedDataRepo",
"metaRepo": "ion://metaRepo",
"auth": "ion://auth",
"config": {
"*": {
"project@project-management":{
"roots":[{
"property": "name",
"operation": 1,
"value": [null],
"nestedConditions": []
}],
"childs":["stakeholders", "basicObjs"]
},
"governmentPower@project-management": {
"roots":[],
"childs":null,
"override": {
"descript": "url"
}
},
"object@project-management": {
"roots":[],
"childs":null
},
"event@project-management": {
"roots":[],
"childs":null
}
}
}
}
}
...
Поле config
- в нем все настройки:
- первый ключ это навигационная нода (в данном примере «*» значит распространяется на все ноды),
- потом идут классы, у классов
roots
- это какие объекты этого класса вытаскивать в качестве корневых (используются «conditions»), childs
- это атрибуты класса из которых доставать иерархию.
searchByRefs
- это массив настроек, для обозначения иерархии классов. Можно сопоставлять с несколькими классами.
"family@khv-childzem": {
"*": {
"searchByRefs":[
{
"class": "person@khv-childzem",
"idProperties": ["famChilds", "famParentMale", "famParentFemale"],
"searchBy": [
"surname",
"name",
"patronymic"
],
"splitBy": "\\s+",
"mode": [
"starts",
"starts",
"starts"
],
"joinBy": "and"
}
]
}
}
Модуль «geomap»¶
Геомодуль (geomap) – предназначен для визуализации сведений и данных, имеющих географическую привязку.
Логотип для модуля описывается через стандартный механизм статичных маршрутов:
{
"modules": {
"geomap": {
"statics":[{"path":"applications/khv-svyaz-info/icons", "name":"icons"}],
"logo": "icons/logo.png"
}
}
}
Модуль «gantt-chart»¶
Модуль диаграм ганта (gantt-chart) – модуль, предназначенный для вывода специфичных типов иерархических данных имеющих даты. Подробнее о модуле диаграм ганта.
Шкала времени настраивается посредством настройки «Шаг» в модуле Гаанта.
В преконфигурации «Шаг» задается через параметр step
:
{
"unit": "year",
"step": 5
}
...
"gantt-chart": {
"globals": {
"config": {
...
"preConfigurations": {
...
"config3": {
"caption": "Третья конфигурация",
"showPlan": true,
"units": "year",
"step": 5,
"days_mode": "full",
"hours_mode": "full",
"columnDisplay": {
"text": true,
"owner": true,
"priority": true
},
"filters": {
"priority": "Обычный"
}
}
}
...
}
}
}
Модуль «report»¶
Модуль отчетов (report) – модуль предназначенный для формирования, на основе специальных метаданных – аналитических отчетов и справочной информации. Расчеты могут выполняться по расписанию или быть инициированы оператором. Подробнее о модуле отчетов.
"report": {
"globals": {
"namespaces": {
"project-management": "Проектное управление"
},
"defaultNav": {
"namespace": "project-management",
"mine": "projects",
"report": "roadmap"
},
"mineBuilders": {
"project-management": {
"test": {
"projects": "mineBuilder"
},
"projects": {
"indicatorAll": "mineBuilder"
}
}
},
"di": {},
"statics": {
"common-static": "applications/project-management/templates/static"
},
"logo": "common-static/logo.png"
},
"import": {
"src": "applications/project-management/bi",
"namespace": "project-management"
}
}
Модуль «rest»¶
Модуль REST-сервисов – модуль предназначенный для осуществления интеграции по формату REST. Используется для предоставления данных для модуля портала. Подробнее о модуле REST.
"rest": {
"globals": {
"di": {}
}
},
Модуль «portal»¶
Модуль портала (portal) – модуль, предназначенный для отображения произвольных шаблонов данных. Подробнее о модуле портала
"portal": {
"import": {
"src": "applications/project-management/portal",
"namespace": "project-management"
},
"globals": {
"portalName": "pm",
"needAuth": true,
"default": "index",
"theme": "project-management/portal",
"templates": [
"applications/project-management/themes/portal/templates"
],
"statics": {
"pm": "applications/project-management/themes/portal/static"
},
"pageTemplates": {
"navigation": {
"index": "pages/index"
}
}
}
}
Модуль «ionadmin»¶
Модуль администрирования (ionadmin) – используется для назначения прав, управления задачами по расписанию и другими административными задачами. Подробнее о модуле администрирования.
Для ролей, которые должны быть скрыты в админе от назначения пользователю, в деплое приложения прописываем фильтры на основе регулярных выражений, по которым такие роли и будут определятся.
"ionadmin": {
"globals": {
"securityParams": {
"hiddenRoles": [
"^somePrefix_"
]
}
}
}
Для скрытия модуля из системного меню проекта присваиваем этому модулю, в файле deploy.json
, значение null, например "ionadmin": null
.
{
"namespace": "project-management",
"parametrised": true, //
"globals": {
"moduleTitles": {
"registry": {
"description": "Проектное управление",
"order": 10,
"skipModules": true
}
"ionadmin": null
}
Модуль «dashboard»¶
Модуль дашбоарда (dashboard) – модуль предназначенный для выведения краткой информации в виде блоков. Подробнее о модуле дашбоарда.
Для того что бы данные из меты загружались в модуль «dashboard», необходимо в файле конфигурации приложения
deploy.json
добавить следующую секцию, в раздел "modules"
:
"dashboard": {
"globals": {
"namespaces": {
"project-management": "Проектное управление"
},
"root": {
"project-management": "applications/project-management/dashboard"
}
}
}
Модуль «diagram»¶
"diagram": {
"globals": {
"config": {
"org1": {
"caption": "Организационная структура",
"edit": true,
"showSections": false,
"relations": {
"className": "organization@project-management",
"title": "name",
"text": "address",
"img": "",
"filter": [
{
"property": "headOrg",
"operation": 0,
"value": [
null
],
"nestedConditions": []
}
],
"children": [
{
"className": "branchOrg@project-management",
"property": "branch",
"title": "name",
"text": "address",
"children": [
{
"className": "branchOrg@project-management",
"property": "branch",
"children": []
}
]
}
]
}
}
}
}
}
Полный пример файла deploy.json
Файл deploy.json
на примере приложения «Project management system»¶
{
"namespace": "project-management",
"parametrised": true, //
"globals": {
"moduleTitles": {
"registry": {
"description": "Проектное управление",
"order": 10,
"skipModules": true
}
},
"explicitTopMenu": [
{
"id": "mytasks",
"url": "/registry/project-management@indicatorValue.all",
"caption": "Мои задачи"
},
{
"type": "system",
"name": "report"
}
],
"plugins": {
"sessionHandler": {
"options": {
"storage": {
"type": "[[session.type]]",
"options": {
"host": "[[cache.redis.host]]",
"port": "[[cache.redis.port]]"
}
}
}
},
"wfEvents": {
"module": "applications/project-management/lib/wfEvents",
"initMethod": "init",
"initLevel": 1,
"options": {
"workflows": "ion://workflows",
"metaRepo": "ion://metaRepo",
"dataRepo": "ion://dataRepo",
"log": "ion://sysLog"
}
},
"actualAclProvider": {
"module": "core/impl/access/aclmongo",
"initMethod": "init",
"initLevel": 1,
"options": {
"dataSource": "ion://Db"
}
},
"aclProvider": {
"module": "core/impl/access/aclMetaMap",
"options": {
"dataRepo": "ion://dataRepo",
"acl": "ion://actualAclProvider",
"accessManager": "ion://roleAccessManager",
"map": {
"person@project-management": {
"isEntry": true,
"sidAttribute": "user",
"jumps": [
"employee"
]
}
}
}
},
"fileStorage": {
"module": "core/impl/resource/OwnCloudStorage",
"options": {
"url": "[[ownCloud.url]]",
"login": "[[ownCloud.login]]",
"password": "[[ownCloud.pwd]]"
}
},
"dataRepo": {
"options": {
"maxEagerDepth": 4
}
},
"customProfile": {
"module": "lib/plugins/customProfile",
"initMethod": "inject",
"options": {
"auth": "ion://auth",
"metaRepo": "ion://metaRepo",
"dataRepo": "ion://dataRepo",
"fields": {
"piAct": {
"caption": "Участник прогресс-индикатора",
"required": false,
"readonly": true,
"type": 4
}
},
"propertyMap": {
"person@project-management": {
"filter": "user",
"properties": {
"person": "id",
"piAct": "piAct",
"surname": "surname"
}
}
}
}
},
"securedDataRepo": {
"options": {
"accessManager": "ion://roleAccessManager",
"roleMap": {
"eventBasic@project-management": {
"PROJECT_ADMIN": {
"caption": "Администратор проекта",
"resource": {
"id": "pm::project-events"
},
"attribute": "project.administrator"
},
"PROJECT_RESPONSIBLE": {
"caption": "Ответственный по проекту",
"resource": {
"id": "pm::project-events"
},
"sids": [
"$project.owner"
]
}
}
}
}
},
"indicatorWfHandler": {
"module": "applications/project-management/lib/util/indicatorWfHandler",
"initMethod": "init",
"initLevel": 2,
"options": {
"workflows": "ion://workflows",
"data": "ion://securedDataRepo",
"log": "ion://sysLog"
}
},
"auth": {
"options": {
"checkUrlAccess": [
"/registry/project-management@project",
"/portal"
]
}
}
},
"jobs": {
"fact-creator": {
"description": "Служба генератора фактический показателей",
"launch": {
"day": 1
},
"worker": "factCreator",
"di": {
"factCreator": {
"executable": "applications/project-management/lib/fact-creator",
"options": {
"log": "ion://sysLog",
"data": "ion://dataRepo",
"workflows": "ion://workflows"
}
}
}
},
"report-builder": {
"description": "Служба сборки шахт данных модуля отчетов",
"launch": {
"hour": 24
},
"worker": "rebuilder",
"di": {
"reportMeta": {
"module": "modules/report/lib/impl/DsReportMetaRepository",
"initMethod": "init",
"initLevel": 1,
"options": {
"dataSource": "ion://Db",
"calc": "ion://calculator"
}
},
"stdBuilder": {
"module": "modules/report/lib/impl/StdMineBuilder",
"options": {
"dataSource": "ion://Db",
"metaRepo": "ion://metaRepo",
"dataRepo": "ion://dataRepo"
}
},
"rebuilder": {
"executable": "modules/report/lib/rebuilder",
"options": {
"log": "ion://sysLog",
"meta": "ion://reportMeta",
"mineBuilders": {
"project-management": {
"projects": {
"indicatorAll": "ion://stdBuilder"
}
}
}
}
}
}
}
}
},
"deployer": "built-in",
"modules": {
"registry": {
"globals": {
"signedClasses": [
"indicatorBasic@project-management"
],
"staticOptions": {
"maxAge": 3600000
},
"explicitTopMenu": [
"mytasks",
{
"type": "system",
"name": "report"
}
],
"eagerLoading": {
"*": {
"briefcase@project-management": {
"item": [
"projects.typeProject.name"
],
"list": [
"projects.typeProject.name"
],
"exportItem": [
"direction.name"
],
"exportList": [
"result"
]
}
}
},
"listSearchMinLength": 3,
"listSearchOptions": {
"indicatorBasic@project-management": {
"*": {
"searchBy": [
"name",
"objectBasic"
],
"mode": [
"starts",
"starts"
],
"joinBy": "and"
}
}
},
"storage": {
"basicObj@project-management": {
"cloudFile": "/${item.code} (${item.name})/",
"resultCloudFile": "/${item.code} (${item.name})/"
}
},
"defaultPath": "dashboard",
"inlineForm": true,
"navigation": {
"namespaces": {
"project-management": "Проектное управление"
},
"menus": {
"top": [
"project-management@mark"
]
}
},
"templates": [
"applications/project-management/templates/registry"
],
"customTemplates": [
{
"node": "project-management@eventBasic",
"classes": [
{
"name": "*",
"types": {
"create": "task/view",
"item": "task/view",
"selectClass": "task/selectClass"
}
}
]
},
{
"node": "*",
"classes": [
{
"name": "project@project-management",
"types": {
"item": "to-gantt-view",
"selectClass": "task/selectClass"
}
}
]
}
],
"statics": {
"app-static": "applications/project-management/templates/registry/static",
"app-vendor": "applications/project-management/themes/registry/static/vendor",
"common-static": "applications/project-management/templates/static"
},
"logo": "common-static/logo.png",
"di": {
"pmItemToDocx": {
"module": "modules/registry/export/itemToDocx",
"initMethod": "init",
"initLevel": 0,
"options": {
"tplDir": "applications/project-management/export/item",
"injectors": []
}
},
"pmListToDocx": {
"module": "modules/registry/export/listToDocx",
"initMethod": "init",
"initLevel": 0,
"options": {
"tplDir": "applications/project-management/export/item2",
"log": "ion://sysLog"
}
},
"export": {
"options": {
"configs": {
"project@project-management": {
"passport": {
"caption": "Паспорт проекта",
"mimeType": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
"extension": "docx",
"type": "item",
"preprocessor": "ion://pmItemToDocx",
"isBackground": true
},
"markResult": {
"caption": "Оценка проектов",
"mimeType": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
"extension": "docx",
"type": "list",
"query": {
"filter": {
"and": [
{
"eq": [
"$guid",
":project"
]
}
]
}
},
"params": {
"project": {
"caption": "Проект",
"type": "reference",
"className": "project@project-management"
}
},
"preprocessor": "ion://pmFromListToDocx",
"isBackground": true
}
}
}
}
},
"createIndicatorValueHandler": {
"module": "applications/project-management/lib/actions/createIndicatorValueHandler",
"initMethod": "init",
"initLevel": 2,
"options": {
"data": "ion://securedDataRepo",
"workflows": "ion://workflows",
"log": "ion://sysLog",
"changelogFactory": "ion://changelogFactory",
"state": "onapp"
}
},
"actions": {
"options": {
"actions": [
{
"code": "CREATE_INDICATOR_VALUE",
"handler": "ion://createIndicatorValueHandler"
}
]
}
},
"digestData": {
"module": "applications/project-management/lib/digest/digestData",
"options": {
"log": "ion://sysLog"
}
},
"signManager": {
"options": {
"Preprocessor": "ion://digestData",
"signaturePreprocessor": "ion://signSaver"
}
},
"treegridController": {
"module": "applications/viewlib-extra/lib/controllers/api/treegrid",
"initMethod": "init",
"initLevel": 0,
"options": {
"module": "ion://module",
"logger": "ion://sysLog",
"dataRepo": "ion://securedDataRepo",
"metaRepo": "ion://metaRepo",
"auth": "ion://auth",
"config": {
"*": {
"eventBasic@project-management": {
"roots": [
{
"property": "name",
"operation": 1,
"value": [
null
],
"nestedConditions": []
}
],
"childs": [
"basicObjs"
]
}
}
}
}
},
"fileshareController": {
"module": "applications/viewlib/lib/controllers/api/fileshare",
"initMethod": "init",
"initLevel": 0,
"options": {
"module": "ion://module",
"fileStorage": "ion://fileStorage"
}
}
},
"dashboard": {
"project-management": {
"modules": {
"dashboard": {}
}
}
}
}
},
"geomap": {
"globals": {
"ymapControls": {
"loader": {
"position": {
"left": 15,
"top": 90
}
},
"rulerControl": null,
"typeSelector": {
"float": "right"
},
"zoomControl": {
"position": {
"right": 10,
"top": 10
}
}
},
"panels": {
"rightInfo": {
"type": "rightInfo"
},
"navFloat": {
"type": "float",
"cssClass": "map-nav-float nav-tree",
"cssStyle": "left:10px; top:46px; width: 310px; max-height:calc(100% - 163px);"
},
"filterFloat": {
"type": "float",
"title": "Фильтры",
"cssClass": "map-filter-float collapsible",
"cssStyle": "left:10px; bottom:10px; width: 310px; max-height:calc(100% - 163px);"
}
},
"hidePageHead": false,
"hidePageSidebar": true,
"stroke": {
"panel": {
"name": "filterFloat"
},
"path": {
"strokeColor": "#00ff00",
"strokeWidth": 6,
"opacity": 0.8
},
"polygon": {
"fillColor": "#00ff00",
"fillOpacity": 0.1,
"strokeColor": "#00ff00",
"strokeOpacity": 0.9,
"strokeWidth": 3
}
},
"namespaces": {
"project-management": "Геоданные проекта"
},
"templates": [
"applications/project-management/templates"
],
"statics": {
"geoicons": "applications/project-management/icons"
},
"start": [
135.07,
48.48
],
"zoom": 10,
"regions": {
"enabled": true,
"osmIds": [
"151223"
],
"panel": {
"name": "filterFloat"
},
"button": {
"caption": "Районы",
"hint": "Фильтр по районам",
"resetHint": "Сбросить фильтр"
},
"levels": {
"4": {
"strokeWidth": 3,
"strokeColor": "#7e8dab",
"strokeStyle": "solid",
"strokeOpacity": 1,
"fillColor": "#ffffff",
"fillOpacity": 0
}
}
},
"defaultNav": {
"namespace": "project-management",
"node": "objectBasic"
},
"search": {
"panel": {
"name": "filterFloat",
"orderNumber": 10
},
"enabled": true,
"timeout": 2000
},
"formFilter": {
"panel": {
"name": "filterFloat"
}
},
"di": {
"dataRepo": {
"module": "core/impl/datarepository/ionDataRepository",
"options": {
"dataSource": "ion://Db",
"metaRepository": "ion://metaRepo",
"fileStorage": "ion://fileStorage",
"imageStorage": "ion://imageStorage",
"log": "ion://sysLog",
"keyProvider": {
"name": "keyProvider",
"module": "core/impl/meta/keyProvider",
"options": {
"metaRepo": "ion://metaRepo"
}
},
"maxEagerDepth": 3
}
}
}
},
"import": {
"src": "applications/project-management/geo",
"namespace": "project-management"
}
},
"gantt-chart": {
"globals": {
"staticOptions": {
"maxAge": 3600000
},
"config": {
"columns": [
{
"name": "owner",
"caption": "Владелец",
"align": "center",
"filter": true,
"editor": {
"type": "select2",
"from": "employee@project-management"
}
}
],
"preConfigurations": {
"config2": {
"caption": "Расширенная",
"showPlan": false,
"units": "year",
"days_mode": "full",
"hours_mode": "work",
"columnDisplay": {
"text": true,
"owner": true,
"priority": true,
"start": true,
"progress": true
}
}
},
"roots": [
"briefcase@project-management",
"project@project-management"
],
"initialDepth": 1,
"createUrl": {
"project@project-management": "registry/project-management@myprojectevent.all/new/{{parentClass}}.{{parentId}}/basicObjs/event@project-management"
},
"searchCount": 25,
"inplaceCreation": {
"rootLevel": true,
"skip": [
"briefcase@project-management"
],
"ambigiousDefault": "event@project-management",
"force": {
"@root": "briefcase@project-management",
"eventObject@project-management": "eventOnly@project-management"
}
},
"map": {
"employee@project-management": {
"eager": [
"person",
"organization"
]
},
"project@project-management": {
"type": "project",
"open": true,
"color": "#e3fcef",
"textColor": "#000",
"text": "name",
"override": {
"owner": "head"
},
"parents": [
"briefcase"
],
"filter": {
"ne": [
"$archive",
true
]
},
"url": "registry/project-management@myprojectevent.all/view/:class/:id"
}
}
},
"statics": {
"common-static": "applications/project-management/templates/static"
},
"logo": "common-static/logo.png",
"rootParamNeeded": true
}
},
"report": {
"globals": {
"namespaces": {
"project-management": "Проектное управление"
},
"defaultNav": {
"namespace": "project-management",
"mine": "projects",
"report": "roadmap"
},
"mineBuilders": {
"project-management": {
"test": {
"projects": "mineBuilder"
},
"projects": {
"indicatorAll": "mineBuilder"
}
}
},
"di": {},
"statics": {
"common-static": "applications/project-management/templates/static"
},
"logo": "common-static/logo.png"
},
"import": {
"src": "applications/project-management/bi",
"namespace": "project-management"
}
},
"rest": {
"globals": {
"di": {}
}
},
"portal": {
"import": {
"src": "applications/project-management/portal",
"namespace": "project-management"
},
"globals": {
"portalName": "pm",
"needAuth": true,
"default": "index",
"theme": "project-management/portal",
"templates": [
"applications/project-management/themes/portal/templates"
],
"statics": {
"pm": "applications/project-management/themes/portal/static"
},
"pageTemplates": {
"navigation": {
"index": "pages/index"
}
}
}
},
"ionadmin": {
"globals": {
"defaultPath": "ionadmin",
"securityParams": {
"resourceTypes": {
"*": {
"title": "Общие"
}
},
"hiddenRoles": [
"^PROJ_DEPART_EMPLOYEE"
]
}
},
"statics": {
"common-static": "applications/project-management/templates/static"
},
"logo": "common-static/logo.png"
},
"dashboard": {
"globals": {
"namespaces": {
"project-management": "Проектное управление"
},
"root": {
"project-management": "applications/project-management/dashboard"
}
}
},
"diagram": {
"globals": {
"config": {
"org1": {
"caption": "Организационная структура",
"edit": true,
"showSections": false,
"relations": {
"className": "organization@project-management",
"title": "name",
"text": "address",
"img": "",
"filter": [
{
"property": "headOrg",
"operation": 0,
"value": [
null
],
"nestedConditions": []
}
],
"children": [
{
"className": "branchOrg@project-management",
"property": "branch",
"title": "name",
"text": "address",
"children": [
{
"className": "branchOrg@project-management",
"property": "branch",
"children": []
}
]
}
]
}
}
}
}
}
}
}
Конфигурационный файл deploy.json - это файл, в котором описывается структура параметров программной системы и её конкретная настройка.
Предусмотрен также способ задания конфигурации через множество отдельных файлов: сборка deploy из отдельных файлов
Структура файла deploy.json:¶
Поле | Имя | Описание |
---|---|---|
"namespace": |
Название проекта | Пространство имен проекта. |
"parametrised": true, |
Параметризация | Подключение параметризации. При установленном значении «true» есть возможность задавать параметры, в которые, при сборке приложения, передаются переменные, заданные в ini-файлах или переменных окружения проекта. |
"globals": { |
Глобальные настройки | Глобальные параметры конфигурирования. |
"deployer": "built-in" |
Сборки | Параметр конфигурирования сборки, на данный момент единственный. |
"modules" |
Настройки модулей | Массив объектов - описание модулей. |
Пример файла deploy.json
Зависмости в package.json¶
Файл package.json - определяет структуру зависимостей и детальный состав модулей системы.
"ionMetaDependencies": {
"viewlib": "0.0.1"
}
Логика подключения при помощи скрипта¶
если в названии объекта отсутствует слеш - / => «project-management»- подставляем в путь по умолчанию группу ION-APP - т.е. путь - //git.iondv.ru/ION-APP/project-management.
если в названии есть слеш - значит задан уже с группой и просто склеиваем путь к гиту с группой и метой, пример «ION-METADATA/viewlib» - путь - //git.iondv.ru/ION-METADATA/viewlib.
если значение версии начинается с git+http:// или git+https:// - то это полный путь к внешнему репозиторию - отбрасываем git+ и тянем гитом.
если значение версии начинается с http:// или https:// - то это полный путь к архиву - тянем и распаковываем.
Не реализовано, так как dapp не поддерживает работу с архивами.
Пример файла package.json
¶
{
"name": "develop-and-test",
"description": "Метапроект для тестирования и разработки",
"version": "1.9.2",
"homepage": "http://docker.local:8080",
"engines": {
"ion": "1.24.1"
},
"scripts": {
"test": "mocha ./test/e2e/**/*.js"
},
"ionModulesDependencies": {
"registry": "1.27.1",
"geomap": "1.5.0",
"portal": "1.3.0",
"report": "1.9.2",
"ionadmin": "1.4.0",
"dashboard": "1.1.0",
"rest": "1.1.2",
"gantt-chart": "0.8.0"
},
"ionMetaDependencies": {
"viewlib": "0.9.1"
}
}
Описание полей¶
Поле | Наименование | Описание |
---|---|---|
"name" |
Имя | Имя проекта. |
"description" |
Описание | Описание проекта. |
"version" |
Версия | Номер текущей версии. |
"homepage" |
Домашняя страница | Ссылка на собранный проект на докере. |
"bugs" |
Ошибки | Указывается ссылка на проект приложения в GitLab, где принимаются заявки об ошибках. |
"repository" |
Репозиторий | Состоит из полей «type» и «url». Указыается тип репозитория и ссылка на него. |
"engines" |
Ядро | Номер версии ядра. |
"scripts" |
Скрипты | Скрипт для сборки меты из разных групп и разных url./ |
"ionModulesDependencies" |
Зависимости модулей ion | Задает модули и их версии, используемые в приложении. Проект включает в себя следующий состав модулей: • «ionadmin» – модуль администрирования • «registry» – модуль регистра • «report» – модуль отчетов • «rest» - модуль rest-сервисов • «dashboard» – модуль дашбоардов • «geomap» - геомодуль • «gantt-chart» – модуль диаграмм ганта • «portal» – модуль портала |
"ionMetaDependencies" |
Зависимости метаданных ion | Дополнительные приложения для функционирования системы. |
"dependencies" |
Зависимости | Прочие зависимости проекта из репозитория npm. |
Операции с учетными записями MongoDB через CLI¶
Авторизация¶
Для авторизации при взаимодействии с СУБД через консольный интерфейс, в mongo
передаются параметры
--authenticationDatabase <база данных, на основе которой производится авторизация>
-u <имя пользователя>
-p <пароль>
пример:
mongo --authenticationDatabase admin -u admin -p 123
Создание пользователя¶
Для создания пользователя необходимо иметь роль dbOwner
, либо иметь роль userAdmin
в базе данных, на основании которой производится авторизация,
например admin
, и во всех базах данных, где добавляются роли, или привилегию на действие createUser
в этой базе и привилегии на действие grantRole
в базах данных, где добавляются роли.
Создание пользователя через консольный интерфейс осуществляется командой
mongo --eval "(new Mongo()).getDB(<имя бд, куда писать данные авторизации>').createUser( \
{ \
user: '<пользователь>', \
pwd: '<пароль>', \
roles: [ \
{ role: 'readWrite', db: '<бд куда доступ на чтение-запись>' }, \
{ role: 'read', db: '<бд где только чтение>' }, \
{ role: 'write', db: '<бд где только запись>' } \
]})"
пример:
mongo --eval "(new Mongo()).getDB('admin').createUser( \
{ \
user: 'admin', \
pwd: '123', \
roles: [ \
{ role: 'readWrite', db: 'admin' }, \
{ role: 'readWrite', db: 'config' }, \
{ role: 'readWrite', db: 'local' } \
]})"
или в одну строку
mongo --eval "(new Mongo()).getDB('admin').createUser({user: 'demo',pwd: '123',roles: [{ role: 'readWrite', db: 'admin' },{ role: 'readWrite', db: 'config' },{ role: 'readWrite', db: 'local' }]})"
Удаление пользователя¶
Для удаления пользователя необходимо иметь роль dbOwner
, либо иметь роль userAdmin
или привилегию на действие dropUser
в базе данных, на основе которой производится
авторизация, например admin
.
Удалить пользователя через CLI mongodb можно командой
mongo --eval "(new Mongo()).getDB('<бд с данными авторизации>').dropUser('<имя>')"
пример:
mongo --eval "(new Mongo()).getDB('admin').dropUser('demo')"
4. Модули¶
Модуль Registry¶
Логика формирования id элементов, связанных с объектами по типам¶
Реализовано¶
INPUT, SELECT, TEXTAREA¶
1. для редактирования атрибута объекта a_{неймспейс, класс, атрибут}
<input type="text" class="form-control" id="a_develop-and-test_class_integer_integer_integer" name="integer_integer" pattern="[0-9]+([\.|,][0-9]+)?" value="5120">
BUTTON¶
1. действие списка la_{неймспейс, класс, имя команды}
<button id="la_develop-and-test_class_integer_edit" class="edit btn btn-info command" title="Редактировать" data-id="EDIT" style="display: inline-block;">Править</button>
2. действие формы fa_{неймспейс, класс, имя команды}
<button id="fa_develop-and-test_class_integer_saveandclose" data-id="SAVEANDCLOSE" type="button" class="btn command object-control SAVEANDCLOSE" style="">
Сохранить и Закрыть
</button>
3. действие ссылочного поля ra_{неймспейс, класс, атрибут, имя команды}
<button id="ra_develop-and-test_ref_use_ref_use_create" type="button" class="create-btn btn btn-success" data-ref-property="ref_use" title="Создать">
<span class="glyphicon glyphicon-plus-sign"></span>
</button>
4. действие поля коллекции ca_{неймспейс, класс, атрибут, имя команды}
нет возможности проверить, коллекции в процессе
5. плавающие кнопки формы ffa_{неймспейс, класс, атрибут, имя команды}
<button id="ffa_develop-and-test_class_integer_close" type="button" class="btn btn-default CLOSE" title="Закрыть" data-cmd="CLOSE">
<span class="glyphicon glyphicon-remove"></span>
</button>
FORM, DIV, TR, LI (для представления объектов)¶
1. секции и узлы навигации n_{имя секции навигации}
<a id="n_simple_types" href="#" title="Простые типы">
<i class="fa fa-menu-arrow pull-right toggler"></i>
<i class="main-icon fa fa-institution" title="Простые типы"></i>
<span>Простые типы</span>
</a>
Узел навигации n_{код узла навигации}
.
<a id="n_class_integer" class="menu-link" href="/registry/develop-and-test@class_integer" title="Класс "Целое [6]">Класс "Целое [6]</a>
Узел навигации открытого класса.
Настройки DI¶
Подключение в глобальных настройках модуля регистра¶
Пример в deploy.json¶
"modules": {
"registry": {
"globals": {
"di": {
treegridController¶
Описание¶
Предназначен для создания иерархичных списков объектов в атрибуте-коллекции класса или в навигации класса.
Работает с использованием компонента dhtmlxSuite_v51_pro (https://dhtmlx.com/docs/products/dhtmlxTreeGrid/).
Подключение в DI¶
"treegridController": {
"module": "applications/viewlib/lib/controllers/api/treegrid",
"initMethod": "init",
"initLevel": 0,
"options": {
"module": "ion://module",
"logger": "ion://sysLog",
"securedDataRepo": "ion://securedDataRepo",
"metaRepo": "ion://metaRepo",
"auth": "ion://auth",
"config": { // основной конфиг
"*": { // выборка объектов возможна в каждой навигации
"eventBasic@project-management":{ // выборка объектов по указанному классу
"roots":[{ // поиск корней
"property": "name",
"operation": 1,
"value": [null],
"nestedConditions": []
}],
"childs":["basicObjs"] // поиск дочерних элементов
},
Виды шаблонов¶
"template": "treegrid/collection"
Для атрибута-коллекции. Подключается в представлении формы объекта:
"options": {
"template": "treegrid/collection",
"reorderable": true,
"treegrid": {
"width": "auto,100,100,100,100,0",
"align": "left, center,center,center,center, left",
"sort": "str, date, date, date, date, int",
"enableAutoWidth": false,
"paging": {
"size": 20
}
}
}
"template": "treegrid/list"
Для навигации класса. Подключение:
"options": {
"template": "treegrid/list"
}
- Настройка
skin
https://docs.dhtmlx.com/grid__skins.html
"options" : {
...
"treegrid" : {
"skin": "material" // по умолчанию
// "skin": "skyblue"
// "skin": "terrace"
// "skin": "web"
}
}
Модуль регистра (registry) – ключевой модуль, предназначенный непосредственно для работы с данными на основе структур метаданных – в том числе для ведения проектов, программ, мероприятий и др.
Настройка¶
Deploy¶
Настройка частоты опроса в deploy.json¶
Настройка частоты опроса сервера, что объект не заблокирован в deploy.json:
"registry": {
"globals": {
"notificationCheckInterval": 60000 // раз в минуту
}
}
Настройка createByCopy¶
Настройка отображения кнопки «Создать еще» в deploy.json:
"createByCopy": [
"person@khv-childzem" // класс
],
Модуль Report¶
Замечания при проектировании шахты¶
Операции «NOT CONTAINS»¶
При использовании Монго БД операции NOT CONTAINS
работать корректно не будут, так как NOT применяется не к CONTAINS, а к условиям вхождения.
На данный момент изменить это не представляется возможным.
Не настроен сборщик для источника данных¶
Не настроен сборщик для источника данных "summaryArea.serviceGrid"
. Кроме самой меты в deploy.json
в modules.report.globals
необходимо прописать следующее:
"mineBuilders": {
"khv-svyaz-info": {
"summaryArea": {
"internet": "mineBuilder",
"population": "mineBuilder",
"internetGrid": "mineBuilder",
"station": "mineBuilder",
"serviceGrid": "mineBuilder"
}
}
}
Это - привязка сборщиков к источникам данных, чтобы иметь возможность агрегировать из разных БД (и вообще источников). Сейчас пока используется стандартный mineBuilder, использующий локальный датасорс Db.
Нельзя сравнить два поля¶
Если сравниваем два поля между собой с использованием поисковых выражений, то работать не будет. Монго БД не умеет сравнивать два поля между собой. Например подобные выражения работать не будут:
{"attr1": {"$regex": "$attr2", "$options": "i"}}
Фильтры¶
Для сорсов на основе классов фильтры указываются через кондишнсы.
"filter": [
{
"property": "typePet",
"operation": 0,
"value": "statement",
"nestedConditions": []
}
]
Модуль отчетов (report) – модуль для формирования аналитических отчетов и справочной информации в виде графиков на основе специальных метаданных. Расчеты могут выполняться по расписанию или быть инициированы оператором.
Библиотека для построения отчетов вида Pivot¶
Библиотекой для построения отчетов вида Pivot служит PivotTable.js (Примеры и описание: https://pivottable.js.org ) Функционал богатый, в то же время сложный для построения отчетов уровня экселя или ворда. На данный момент, при проектировании отчета, лучше посоветоваться с разработчиками и поставить таск на реализацию отчета вида Pivot, если ожидаемый функционал отчета относительно сложен.
Настройка автоматической сборки шахты данных¶
Добавьте настройку jobs.enabled=true
в файл config.ini чтобы настроить автоматическую сборку шахты данных.
Пример¶
Чтобы запускать задание при старте приложения и далее каждые 6 часов, нужно настроить джоб следующим образом:
"jobs": {
"report-builder": {
"description": "Служба сборки шахт данных модуля отчетов",
"launch": {
"hour": 21600000
}
}
Модуль Gantt-chart¶
Модуль диаграм ганта (gantt-chart) – модуль, предназначенный для вывода специфичных типов иерархических данных, имеющих даты.
Конфигурация в deploy¶
Указание длины поисковой выдачи¶
"searchCount": 25
Добавление фильтров на колонки¶
"gantt-chart": {
"globals": {
"config": {
"columns": [
{
"name": "text",
"caption": "Название"
},
{
"name": "owner",
"caption": "Владелец",
"align": "center",
"filter": true
},
{
"name": "priority",
"caption": "Приоритет",
"align": "center",
"filter": true
},
Указание для разных классов разные createUrl¶
"createUrl": {
"project@project-management": "registry/project-management@eventBasic/new/eventBasic",
"event@project-management": "registry/project-management@eventBasic/new/eventBasic",
"eventObject@project-management": "registry/project-management@eventOnly/new/eventOnly",
"eventOnly@project-management": "registry/project-management@eventOnly/new/eventOnly",
"projectKNA704@project-management": "registry/project-management@eventKNA704/new/eventKNA704",
"eventKNA704@project-management": "registry/project-management@eventOnlyKNA704/new/eventOnlyKNA704",
"eventObjectKNA704@project-management": "registry/project-management@eventOnlyKNA704/new/eventOnlyKNA704",
"eventOnlyKNA704@project-management": "registry/project-management@eventOnlyKNA704/new/eventOnlyKNA704"
}
Настройки видов представлений¶
"preConfigurations": {
"config1": {
"caption": "Основная",
"showPlan": true,
"units": "month",
"step": 3,
"days_mode": "full",
"hours_mode": "full",
"default": true
},
"config2": {
"caption": "Расширенная",
"showPlan": false,
"units": "year",
"days_mode": "full",
"hours_mode": "work",
"columnDisplay": {
"text": true,
"owner": true
},
"filters": {
"priority": "Высокий"
}
},
"config3": {
"caption": "Обзорная",
"showPlan": true,
"units": "year",
"step": 5,
"days_mode": "full",
"hours_mode": "full",
"columnDisplay": {
"text": true,
"owner": true,
"priority": true
},
"filters": {
"priority": "Обычный"
}
}
}
В поле filters
- задаем свойство и значения для фильтра
Настраиваемый фильтр при выборке подузлов¶
В формулах в общем синтаксисе выражений теперь можно обращаться к данным контекста. Пока реализовано только для списков в регистри и ганте. По мере перехода на общий синтаксис реализуем поддержку повсеместно в ядре.
Настраиваемый фильтр не применяется к корневому обьекту явно указанному через параметр урла, или выбранный в выпадающем списке. Фильтр применяется только при ВЫБОРКЕ ПОДУЗЛОВ.
Сортировка выдачи¶
При выводе проекта, в них мероприятия сортируются по атрибуту numEvent - на всех уровнях иерархии.
"sortBy": "numEvent"
// либо
"sortBy": {"numEvent": -1, "anyOtherAttr": 1}
Настройка списка выбора объекта для вывода информации¶
Применяется при условии настроенного фильтра для колонки и позволяет не отображать все объекты сразу, а выбирать из списка. Если значение "rootParamNeeded:true"
- выводится пустой экран и окно для выбора проекта.
"gantt-chart": {
"globals": {
"rootParamNeeded": true
}
}
Модуль портала¶
Модуль портала (portal) – модуль, предназначенный для отображения произвольных шаблонов данных. Модуль портала выполняет функцию отображения дизайна различной информации с помощью языков разметки Markdown и HTML.
Состав¶
Слой представления - отвечает за отображение данных:
Adapter Provider
- выполняет функцию связи между данными и отображением их на портале (настройка через файл „deploy.json“)File Adapter
- возвращает ресурсы типа «Файл» (остается в памяти приложения)Class Adapter
- предназначен для отображения данных из базы через репозиторий данных (каждый раз обновляются)
Логика отображения данных на портале¶
Стили портала¶
Для описания/оформления внешнего вида страниц портала применяются CSS (каскадные таблицы стилей) Пример оформления страницы портала в Dnt - /develop-and-test/portal/view/static/css/style.css
Возможные варианты для применения стилей задаются в папке portal/view/static/style.css.
.navbar {
border-radius: 0;
margin-bottom: 0;
}
.navbar .navbar-brand {
padding: 5px;
}
...
Страницы портала¶
Шаблоны страниц портала настраиваются в папке portal/view/templates.
Расположение объектов на странице описывается в формате языка разметки HTML:
<html>
<head>
<title><%= portal %></title>
<link href="/<%= module %>/vendor/bootstrap/css/bootstrap.min.css" rel="stylesheet">
<link href="/<%= module %>/dnt/css/style.css" rel="stylesheet">
</head>
<body>
<%- partial('../parts/menu', { menu }) %>
<%- body -%>
<script src="/<%= module %>/vendor/jquery/jquery.min.js"></script>
<script src="/<%= module %>/vendor/bootstrap/js/bootstrap.min.js"></script>
<script src="/<%= module %>/js/scripts.js"></script>
</body>
</html>
- Содержание тега
<head>
включает в себя отображение стилей оформления внешнего вида портала. - В тег
<body>
включается информация об объектах, отображаемых на странице портала. - Тег
<script>
содержит в себе информацию в виде ссылки на программу или ее текст на определенном языке. Скрипты могут располагаться во внешнем файле и связываться с любым HTML-документом, что позволяет использовать одни и те же функции на нескольких веб-страницах, тем самым ускоряя их загрузку. В данном случае тег<script>
применяется с атрибутомsrc
, который указывает на адрес скрипта из внешнего файла для импорта в текущий документ.
Навигация портала¶
Мета навигации портала представляет собой набор узлов навигации, у каждого из которых указан тип ресурса.
Пример создания секции навигации:
{
"code": "main",
"caption": "Главное меню",
"itemType": "section",
"subNodes":["classes", "texts"]
}
- code - системной имя объекта
- caption - логическое имя объекта
- itemType - тип отображения объекта
- subNodes - массив узлов навигации, содержащихся в данной секции
Пример создания узла навигации:
{
"code": "texts",
"caption": "Публикация текстов",
"resources": "texts",
"PageSize": 5,
"itemType": "node"
}
- code - системное имя объекта
- caption - логическое имя объекта
- resources - превращение данных в контент портала
- PageSize - размер страницы
- itemType - тип отображения объекта
Оформление данных¶
Формат разбиения информации на страницы
<% layout('./layout/content') %> <% if (Array.isArray(resources) && resources.length) { resources.forEach(function(resource){ %> <div> <h3 id="<%= node.code %>_<%= resource.getId() %>"> <a href="/<%= module %>/<%= node.code %>/<%= resource.getId() %>"> <%= resource.getTitle() %> </a> <% var formatedDate = null; var date = resource.getDate(); if (date) { formatedDate = date.toLocaleString('ru',{year: 'numeric', month: 'numeric', day: 'numeric'}); } %> <% if (formatedDate) { %><small><%= formatedDate %></small><% } %> </h3> <p><%- resource.getContent() %></p> </div> <% }) } %> <%- partial('./parts/pagination', { resources }) %>
Формат корректного отображения текста ошибок
<% layout('./layout/layout') %>
<div class="container">
<h1>404</h1>
<h2>Страница не найдена</h2>
</div>
- Формат преобразования данных в контент портала
<% layout('./layout/layout') %>
<div class="container">
<div class="row">
<div class="col-md-12">
<div class="page-header">
<h2><%= resource.getTitle() %></h2>
</div>
<div>
<%
var formatedDate = null;
var date = resource.getDate();
if (date) {
formatedDate = date.toLocaleString('ru',{year: 'numeric', month: 'numeric', day: 'numeric'});
}
%>
<% if (formatedDate) { %><h1><small><%= formatedDate %></small></h1><% } %>
</div>
<div>
<%- resource.getContent() %>
</div>
</div>
</div>
</div>
- Формат отображения текста
<% layout('./layout/layout') %>
<div class="container">
<div class="row">
<div class="col-md-12">
<div>
<%
var formatedDate = null;
var date = resource.getDate();
if (date) {
formatedDate = date.toLocaleString('ru',{year: 'numeric', month: 'numeric', day: 'numeric'});
}
%>
<% if (formatedDate) { %><h1><small><%= formatedDate %></small></h1><% } %>
</div>
<div>
<%- resource.getContent() %>
</div>
</div>
</div>
</div>
Модуль Панель управления (dashboard)¶
Модуль дашбоарда (dashboard) – модуль для выведения краткой информации в виде блоков. Основывается на модели виджетов.
Структура модуля¶
Панель управления состоит из трех базовых сущностей - менеджер, макет и виджет.
Менеджер (manager)¶
Менеджер - это основной компонент модуля, отвечающий за создание и инициализацию виджетов, макетов, подключение панели к другим модулям.
let manager = require('modules/dashboard/manager');
Макет (layout)¶
Макет - это EJS шаблон, в котором определяются схема размещения виджетов, параметры ддя шаблонов виджетов, плагин для управления сеткой макета на клиенте (например gridster), подключаются общие ресурсы.
Базовые макеты модуля находятся в папке /dashboard/layouts. Опубликованные из мета-данных в папке /applications/${meta-namespace}/layouts.
Каждый макет имеет уникальный ID. При публикации макета из меты к ID добавляется префикс.
let dashboard = require('modules/dashboard');
dashboard.getLayout('demo');
dashboard.getLayout('develop-and-test-demo');
При рендере макета необходимо передать объект manager.
res.render(dashboard.getLayout('demo'), { dashboard });
Виджет (widget)¶
Виджет - это объект, который размещается на макете и взаимодействует с сервером через ajax-запросы.
Базовые виджеты модуля находятся в папке /dashboard/widgets. Опубликованные из мета-данных в папке /applications/${meta-namespace}/widgets.
Виджет состоит из файла класса index.js и шаблона представления view.ejs. Класс должен наследоваться от базового класса /dashboard/base-widget или его потомков.
- Метод init() отвечает за начальную инициализацию виджета при старте сервера.
- Метод refresh() вызывается при получении ajax-запроса от клиента.
- Метод job() получает данные для виджета.
Каждый виджет имеет уникальный ID. При публикации виджета из меты к ID добавляется префикс.
dashboard.getWidget('demo');
dashboard.getWidget('develop-and-test-demo');
При рендере представления виджета необходимо передать объект widget.
<% var widget = dashboard.getWidget('develop-and-test-demo') %>
<%- partial(widget.view, {widget}) %>
Публикация из меты¶
Пример структуры в applications/develop-and-test
dashboard
layouts
demo-layout
widgets
demo-widget
index.js
view.ejs
static
layouts
widgets
demo-widget
Для того, чтобы данные из меты подгружались в модуль дашборда, необходимо в файле конфигурации приложения
deploy.json
добавить следующую секцию, в раздел "modules"
:
"dashboard": {
"globals": {
"namespaces": {
"develop-and-test": "Мета для тестирования и разработки"
},
"root": {
"develop-and-test": "applications/develop-and-test/dashboard"
}
}
}
Модуль Ionadmin¶
Безопасность¶
Инициализация¶
При первичной настройке безопасности необходимо выполнить следующее:
- Синхронизировать права, чтобы права, заведенные через утилиту acl, появились в админке. Для этого на странице
/ionadmin/security/sync
жмем кнопку"Синхронизация прав доступа"
.
По завершении будет сообщение "Синхронизация прав доступа успешно проведена!"
.
- Сделать импорт ресурсов. Если на странице
/ionadmin/security/resource
нет объектов или их действительно мало, тогда надо выполнить импорт ресурсов.
Выполняется на странице /ionadmin/security/sync
по кнопке "Импорт ресурсов"
.
По завершении будет сообщение "Импорт успешно завершен!"
.
Управление ролями¶
На странице /ionadmin/security/role
можно создавать, редактировать или удалять роли:
- Создание роли. Для создания роли на странице
/ionadmin/security/role
нажимаем кнопку «Создать»
Происходит переход на новую страницу, где надо указать идентификатор роли на английском языке. Нажимаем на кнопку «Сохранить» для подтверждения создания указанной роли
- Редактирование роли. Для редактирования роли на странице
/ionadmin/security/role
выбираем необходимую роль и нажимаем кнопку «Править»
Происходит переход на новую страницу, где на форме отображаются следующие поля:
Идентификатор
- выражение на английском языке для присваивания уникального имени роли. При ее изменении могут слететь права у пользователей, которые ранее привязали данную роль со старым идентификатором. В таком случае, необходимо каждому пользователю привязать роль заново.
Название
- осмысленное название роли, может содержать выражения на русском языке.
Права доступа
- вкладки для раздачи прав:
- Общие - используется для раздачи роли доступа ко всем ресурсам (* - все ресурсы)
- Навигация - используется для раздачи роли доступа к меню модуля регистра. Сначала отображается системное наименование проекта, у которого есть знак плюса для отображения внутренних и импортированных ресурсов. Раздаются в данном пункте пока только права на чтение меню.
- Классы - используется для раздачи роли доступа к классам метаданных. Сначала отображается системное наименование проекта, у которого есть знак плюса для отображения внутренних и импортированных ресурсов. У этих ресурсов можно задать отдельные права по каждому ресурсу.
- Удаление роли. Для удаления роли на странице
/ionadmin/security/role
выбираем необходимую роль и нажимаем кнопку «Удалить»
Подтверждаем удаление роли:
Доступ к ресурсу¶
При управлении ролями в правах доступа предоставляются следующие доступы к каждому ресурсу:
Доступ | Описание доступа |
---|---|
Полный доступ | Включает в себя все остальные доступы. Нельзя выбрать полный доступ и еще дополнительный доступ на чтение, запись, удаление или использование. Для навигации предоставляется доступ только на чтение ресурса. |
Чтение | Возможность чтение объектов ресурса |
Запись | Возможность редактирования объектов ресурса, не применяется для навигации |
Удаление | Возможность удаления объектов ресурса, не применяется для навигации |
Использование | Возможность создания объектов ресурса, не применяется для навигации |
Доступ может назначаться всей группе ресурсов или отдельно каждому ресурсу и доступу в нем.
Управление пользователями¶
На странице /ionadmin/security/user
можно создавать, редактировать или удалять пользователей:
- Создание пользователя. Для создания пользователя на странице
/ionadmin/security/user
нажимаем кнопку «Создать»
Происходит переход на новую страницу, где надо указать логин пользователя на английском языке, пароль, описание в имени. Нажимаем на кнопку «Сохранить» для подтверждения создания указанного пользователя
- Редактирование пользователя. Для редактирования пользователя на странице
/ionadmin/security/user
выбираем необходимого пользователя и нажимаем кнопку «Править»
Происходит переход на новую страницу, где на форме отображаются следующие поля:
Тип
- тип учетной записи пользователя, пока доступны в админке локальные пользователи.
Логин
- идентификатор пользователя на английском языке.
Пароль
- пароль пользователя.
Имя
- осмысленное название пользователя, может содержать выражения на русском языке, например, Фамилия И.О.
Роли
- список ролей пользователя. Если проставлена галка у роли, то роль привязана к пользователю.
- Удаление пользователя. Для удаления пользователя на странице
/ionadmin/security/user
выбираем необходимого пользователя и нажимаем кнопку «Удалить»
Подтверждаем удаление пользователя.
Настройки аутентификации пользователя. Требования к паролю.¶
Настройка требований к паролю задается в ini-файле приложения, после чего переменные необходимо объявить в файле настройки конфигурации приложения deploy.json.
В файле setup.ini:
auth.passwordLifeTime=90d # Максимальный срок действия пароля
auth.passwordMinPeriod=75d # Минимальный срок действия пароля
auth.passwordMinLength=8 # Минимальная длина пароля
auth.passwordJournalSize=5 # Число уникальных новых паролей пользователя до повторного использования старого пароля
auth.tempBlockInterval=30m # Время до сброса счетчика блокировки
auth.attemptLimit=6 # Количество неудачных попыток входа в систему, приводящее к блокировке учетной записи пользователя
auth.tempBlockPeriod=30m # Продолжительность блокировки учетной записи
auth.sessionLifeTime=4h # Время жизни авторизованной сессии, при отсутствии активности
Длительность везде задается в формате: [длительность][ед. изм]
Ед. измерения | Значение |
---|---|
y |
Год |
d |
День |
h |
Час |
m |
Минута |
s |
Секунда |
В файле deploy.json:
NB: Нужно обязательно, чтобы стояла настройка "parametrised": true, на уровне "global"
{
"parametrised": true,
"globals": {
"plugins":{
"auth": {
"module": "lib/auth",
"initMethod": "init",
"initLevel": 2,
"options": {
"app": "ion://application",
"logger": "ion://sysLog",
"dataSource": "ion://Db",
"acl": "ion://aclProvider",
"passwordLifetime": "[[auth.passwordLifeTime]]", // максимальный срок действия пароля
"passwordMinPeriod": "[[auth.passwordMinPeriod]]", // минимальный срок действия пароля
"passwordMinLength": "[[auth.passwordMinLength]]", // минимальная длина пароля
"passwordComplexity": { // требования к сложности пароля
"upperLower": true, // требование использовать буквы в разном регистре
"number": true, // требование использовать числа
"special": true // требование использовать спецсимволы
},
"passwordJournalSize": "[[auth.passwordJournalSize]]", // ведение журнала паролей
"tempBlockInterval": "[[auth.tempBlockInterval]]", // счетчик блокировки
"attemptLimit": "[[auth.attemptLimit]]", // пороговое значение блокировки
"tempBlockPeriod": "[[auth.tempBlockPeriod]]" // продолжительность блокировки
}
}
}
}
}
Модуль администрирования (ionadmin) – используется для назначения прав, управления задачами по расписанию и другими административными задачами.
Настройка модуля ionadmin в файле config.json¶
Настройка записи медленных запросов¶
Настройка в виде модального окна на списке медленных запросов. В в файле config.json модуля ionadmin указывать источник:
"profiling": {
"slowQuery": {
"sources": [
{
"collection": "system.profile"
}
]
}
}
Если свойство "sources"
не задано или null, то будет браться из таблицы:
{
"profiling": {
"slowQuery": {
"sources": null
}
}
}
Если задан пустой массив, то источников нет.
Настройка источников логов¶
Источники логов (может быть несколько) указываются в конфиге модуля:
"profiling": {
"slowQuery": {
"sources": [
{
"collection": "system.profile"
},
{
"file": "D:/Temp/slow-query.txt"
}
]
}
}
Сделанные выборки хранятся в отдельной таблице и не зависят от текущего состояния источников логов. Их можно дополнить редактированием. Например, комментариями или пометками, сообщающими решена проблема или нет.
Настройка резервирования БД¶
Настройка в ionmodule/config:
"backup": {
"dir": "../ion-backups",
"zlib": {
"level": 1
}
}
dir
содержит путь папки, в которой было запущено приложение ноды. По умолчанию «../ion-backups»zlib.level
- уровень сжатия, также влияет на скорость создания архива. По умолчанию - значение 3- К тому же, необходимо что бы утилита
export.js
с заданными параметрами корректно отрабатывала сама по себе.
Личный кабинет¶
Личный кабинет - используется для отображения различных «инструментальных» форм, т.е. в приложениях при заведении навигации (или форм-страниц), модуль их считывает и формирует на их основании навигацию и логику отображения страниц.
Настройка модуля¶
- В приложении в некую директорию кладем html-страницы.
- В deploy.json в настройках модуля ЛК прописываем эту директорию, а также опционально хеш-массив соответствия между именем файла и отображаемым названием.
- ЛК считывает эти настройки и в мастер-шаблоне отображает меню навигации ЛК.
- По клику на пункте меню в рабочей области окна ЛК отображается соответствующая разметка из html-файла.
- Также в deploy.json в настройках модуля ЛК указывается страница-инструмент по умолчанию, если не указан берется первый считанный по порядку.
Также есть возможность структурирования меню посредством вложенности директорий.
Модуль Soap¶
NB: модуль Soap не поддерживает GET запросы к сервисам.
Отчасти это объясняется тем, что в теле запроса передаётся SOAP-запрос, а у GET-запроса тела нет (если можно так выразиться). По этой причине нужно отправлять POST запрос. Это можно сделать с помощью утилиты SOAP-UI (можно и в браузере, но в теле запроса нужно писать SOAP-запрос, который основан на WSDL и является достаточно громоздким).
Настройки структуры данных crud-сервиса¶
Опция types
содержит в себе задаваемое в виде мапинга соответствие между классом (полным именем) и мапой публикуемых атрибутов этого класса. В мапе ключом является имя атрибута, а значением - либо строковый псевдоним, либо булево значение, указывающее включается атрибут в схему или нет. т.е. если указан псевдоним, то атрибут появляется в схеме под этим псевдонимом, во всех других случаях, кроме указания false
, атрибут появляется под своим именем.
Настройка применяется при парсинге классов при формировании схемы данных сервиса, а также при парсинге входящих сообщений и генерации ответов. Путем замены normalize на функцию корректно приводящую данные к схеме.
Для работы с коллекциями и ссылками¶
Если значения коллекций и ссылок тоже надо распарсить как то иначе, объекты, которые находятся в этих свойствах можно тоже описать мапой в deploy.json
вот по такому принципу:
"название_свойства": {
"name": "новое_название(если нужно, поле необязательное)",
"types": {
//описания свойств
}
}
Пример¶
"petitionExperts": {
"module": "modules/soap/service/crud",
"options": {
"dataRepo": "ion://dataRepo",
"metaRepo": "ion://metaRepo",
"keyProvider": "ion://keyProvider",
"namespace": "khv-gosekspertiza",
"className": "petitionExpert",
"types": {
"petitionExperts@khv-gosekspertiza":{
"property1":"new_property_name",
"property2":true
}
}
}
}
Настройка, убирающая из запроса системные атрибуты¶
let gosEkspRemPetNew = normalize(e.item, null, {skipSystemAttrs: true});
Авторизация по токену oauth2 в модуле SOAP¶
Аутентификация по парам логин-пароль и логин-токен по умолчанию применяется для всех сервисов. Для аутентификации soap-запросов добавляем в сообщение заголовок безопасности WSSecurity
. Для аутентфиикации REST-сервисов добавляем стандартные заголовки HTTP-аутентифкации
.
Настройка типа проверки - по паролю или токену (pwd/token) выполняется в deploy.json настройкой authMode
в соответствующем модуле:
Пример¶
"soap": {
"globals": {
"authMode": {
"petitionExperts": "none",
"petitionEstimated": "none",
"gosEkspContract": "none",
"bankAccounts": "none",
"resolution": "none"
}
По умолчанию все сервисы аутентифицируются по паролю. Для генерации токена пользователя в админке реализована специальная форма. Настраиваем authMode
для сервиса в token, переходим в админку, генерируем токен, используем его вместо пароля в заголовках.
Модуль Image-storage¶
Image-storage - модуль IONDV.Framework. Используется для предварительного просмотра картинок.
Описание и назначение модуля¶
Модуль представляет собой дополнительный компонент системы и используется при наличии в приложении атрибутов, позволяющих содержать в себе изображения.
Для подключения модуля необходимо обозначить его в зависимостях приложения. Для этого указываем модуль в файле package.json приложения, в разделе "dependencies"
:
"dependencies": {
"image-storage": "git+https://github.com/iondv/image-storage.git"
}
с указанием ссылки на репозиторий модуля в github.com.
Далее нужно добавить на форму списка атрибут, изображение которого будет использовано в режиме предпросмотра. После чего, изображения, загруженные для объектов можно просматривать сразу на форме списка.
Модуль REST¶
REST - модуль, обеспечивающий работу с данными приложения IONDV через REST API
. Используется для создания веб-сервисов к различным видам данных, созданным, в том числе, только визуальным способом путем проектирования в IONDV. Studio.
Описание¶
Модуль IONDV. REST предназначен для:
- готовой «из коробки» CRUD модели для доступа к данным, управления бизнес-процессами, различными типами авторизации - в качестве бакенда для мобильных приложений, для SPA приложений (созданных на фреймворках Angular, Redux, Vue и т.д.) или приложений с разделенным фронт и бек офисом;
- быстрой разработки собственных веб-сервисов, путем их регистрации и написания кода на готовом API работы с данными для реализации микросервисной архитектуры;
- обеспечения интеграции приложений созданных на IONDV. Framework с другими системами по REST API.
Модуль IONDV. REST является оберткой для работы с данными через стандартные функции CRUD или подключает собственные сервисы приложения, в том числе использующие API ядра.
Подробнее:
Авторизация при запросах к сервисам¶
Получение токена¶
Получение токена возможно двумя способами: в консоли модуля ionadmin или через сервис token
модуля rest.
Все сгенерированные токены хранятся в коллекции ion_user_tokens
в базе данных приложения.
Для получения токена через консоль администратора перейдите в пункт навигации «Ключи безопасности веб-сервисов»
модуля ionadmin, например по адресу locahost:8888/ionadmin/token
На странице «Генератор токенов безопасности»:
- Введите имя пользоватля в поле «Имя пользователя»
- Укажите в поле «Тип учетной записи» значение «local»
- Нажмите кнопку «Сгенерировать токен»
- В поле «Токен» появится значение токена подобное
3a546090355317c287886c0e81dfd304fa5bda99
, его и нужно использовать как значение заголовкаauth-token
.
Время жизни токена созданного по умолчанию 100 лет.
Прокси-клиент для доступа к функциям модуля без получения нового токена¶
Подключение клиента осуществляется в modules.registry.globals.di
в deploy.json
:
{
"modules": {
"registry": {
"globals": {
"di":{
"apiGateWay": {
"module": "modules/rest/client/GateWay",
"options": {
"log": "ion://sysLog",
"base": "/registry-ajax-api",
"clientId": "ext@system",
"clientSecret": "ion-demo",
"tokenPath": "/rest/token",
"endPoint": "[[rest.endPoint]]",
"definition": {
"paths": {
"/rest/echo-token": {
"post": true,
"get": true
}
}
}
}
}
Пример запроса к rest/echo-token через прокси-клиент:
curl -X POST --cookie-jar 1.txt -d username="demo@local" -d password="ion-demo" http://localhost:8888/auth
curl -X GET --cookie 1.txt https://dnt.iondv.com/registry-ajax-api/rest/echo-token
пример запроса в dnt: test/modules/rest/gateway.spec.js
/Checking rest-api proxy
Авторизация для доступа к сервисам может быть осуществлена следующими способами:
Сервисы без аутентификации¶
Для реализации работы сервиса без аутентификации, необходимо задать для него значение none
в настройке authMode
в deploy.json
{
"modules": {
"rest": {
"globals": {
"authMode": {
"echo": "none"
Запрос к сервису не будет требовать аутентификации, пример запроса curl https://dnt.iondv.com/rest/echo
Пример запроса к сервису без аутентификации в dnt: test/modules/rest/echo.spec.js
/Checking echo-pwd service/# Requesting echo-pwd GET/check if the request can be made using the headers auth
Сервисы со стандартрным механизмом авторизации по учетной записи¶
Все сервисы по умолчанию используют стандартный механизм авторизации, подразумевающий передачу учетных данных в заголовке:
путем авторизации через Basic Auth, пример
curl -u demo@local:ion-demo https://dnt.iondv.com/rest/simple
пример запроса с авторизацией Basic Auth в develop-and-test (dnt): test/modules/rest/echopwd.spec.js
/Checking echo-pwd service/# Requesting echo-pwd GET/check if the request can be made using the basicAuth
путем передачи учетных данных в заголовках запроса
curl -H "auth-user: demo" -H "auth-pwd: ion-demo" -H "auth-user-type: local" https://dnt.iondv.com/rest/simple
или
curl -H "auth-user: demo@local" -H "auth-pwd: ion-demo" https://dnt.iondv.com/rest/simple
пример запроса с авторизацией учетными данными в заголовке в dnt: test/modules/rest/echopwd.spec.js
/Checking echo-pwd service/# Requesting echo-pwd GET/check if the request can be made using the headers auth
Сервисы с аутентификацией через токен¶
Аутентификация по токену используется для исключения постоянной передачи учетной записи в запросах. Токены ограничены по времени жизни.
Для реализации работы сервиса с аутентификацией через токен, необходимо задать для него значение token
в настройке authMode
в deploy.json
{
"modules": {
"rest": {
"globals": {
"authMode": {
"echo-token": "token"
Аутентификация через токен осуществляется путем отправки значения токена в заголовке запроса auth-token
curl -H "auth-token: c369a361db9742e9a9ae8e9fe55950a571493812" http://dnt.iondv.com/rest/echo-token
пример запроса с авторизацией через токен в dnt: test/modules/rest/token.spec.js
/Checking token service/# basicAuth authorization with admin rights/# check if the generated token is valid (basicAuth) (using echo-token)
подробнее о получении токена: Получение токена
Прокси-клиент для доступа к функциям модуля без получения нового токена.
Сервисы с аутентификацией методом OAuth2¶
Для реализации работы сервиса с аутентификацией oauth2, необходимо предварительно подключить в deploy.json плагин вида
"oauth": {
"module": "lib/oAuthAdapter",
"options": {
"auth": "ion://auth",
"dataSource": "ion://Db"
}
}
затем можно задать для сервиса значение oauth
в настройке auth_mode
:
{
"modules": {
"rest": {
"globals": {
"authMode": {
"echo-oauth": "oauth"
спецификация oauth2 доступна по ссылке: https://oauth2-server.readthedocs.io/en/latest/index.html
Этот тип авторизации используется для предоставления третьей стороне ограниченного доступа к ресурсам пользователя без необходимости предоставлять логин и пароль. Запросы для получения доступа производятся в следующем порядке:
Со стороны пользователя получаем cookie с id сессии:
curl -X POST --cookie-jar 1.txt -d username="demo@local" -d password="ion-demo" http://dnt.iondv.com/auth
Используя авторизованную сессию разрешаем клиенту ext@system запросы от нашего имени:
curl -X POST --cookie ./1.txt "http://dnt.iondv.com/oauth2/grant?client_id=ext@system&response_type=code&state=123"
В ответе будет содержаться параметр
code
.Теперь используя
code
можно получить токен:curl -X POST -d grant_type="authorization_code" -d code="<code>" -H "Authorization:Basic ZXh0QHN5c3RlbTppb24tZGVtbw==" http://dnt.iondv.com/oauth2/token
в заголовке Authorization нужно ввести
Basic <client_secret>
код клиента. В ответе будет полученaccess_token
.Для запросов от лица пользователя в сервисах с авторизацией oauth2 теперь можно авторизоваться используя access_token:
curl -X POST -H "Authorization:Bearer <access_token>" http://dnt.iondv.com/rest/echo-oauth
пример запроса к сервису с авторизацией oauth2 в dnt: test/modules/rest/echooauth.spec.js
/Checking echo-oauth service
Сервисы REST¶
Встроенный сервис Acceptor¶
Сервис acceptor
предназначен для массового сохранения объектов разных классов.
Доступен по адресу <адрес сервера>/rest/acceptor
.
Для работы с сервисом требуется его регистрация в файле конфигураций приложений deploy.json. При этом для сервиса
обязательно должны быть указаны репозитории dataRepo
и metaRepo
в options
. Например:
{
"modules": {
"rest": {
"globals": {
"di": {
"acceptor": {
"module": "modules/rest/lib/impl/acceptor",
"options": {
"dataRepo": "ion://dataRepo",
"metaRepo": "ion://metaRepo"
}
}
Авторизация осуществляется через все основные типы доступа.
Сервис работает по методу POST
, объекты передаются в виде массива объектов в формате JSON в теле запроса с обязательным
указанием в заголовке содержания json Content-Type:application/json
. Автосоздаваемые поля указывать не обязательно.
В заголовке (header) в свойстве ion-converter
может быть передано имя конвертора, который нужно использовать при обработке данных - как запроса, так и ответа.
При этом сам конвертор данных должен быть зарегистрирован в options
сервиса.
Если обработчик не указан, используется обработчик по умолчанию.
В данных объекта обязательно указываются:
_id
- идентификатор объекта по ключевому полю_class
- класс объекта с неймспейсом_classVer
- версия класса
Остальные значения должны соответствовать свойствам класса, включая соответствие типов данных. Пример:
curl -X POST -u demo@local:ion-demo \
-H "Content-Type:application/json" \
-d '[{"_class": "class_string@develop-and-test", "__classVer": null,"id": "10101010-5583-11e6-aef7-cf50314f026b",\
"string_text": "Example10", "string_miltilinetext": "Example10", "string_formattext": "Example10"}]' \
https://dnt.iondv.com/rest/acceptor
пример запроса на создание объектов к сервису acceptor в dnt: test/modules/rest/acceptor.spec.js
/Checking acceptor service/# basicAuth authorization with admin rights, POSTing strings/# result of creation of objects
Метод возвращает код 200
и массив сохраненных объектов.
[
{
"id": "10101010-5583-11e6-aef7-cf50314f026b",
"_class": "class_string@develop-and-test",
"_classVer": "",
"string_formattext": "Example10",
"string_miltilinetext": "Example10",
"string_text": "Example10",
"_id": "10101010-5583-11e6-aef7-cf50314f026b"
}
]
В случае ошибки код ответа будет 400
, а текст ответа содержать
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Error</title>
</head>
<body>
<pre>Bad Request</pre>
</body>
</html>
Встроенный сервис Token¶
Сервис token предназначен для выдачи токена пользователю, прошедшему аутентификацию, для его дальнейшего использования в сервисах, осуществляющих аутентификацию по токену.
Доступен по адресу <адрес сервера>/rest/token
.
Сервис не требует регистрации в deploy.json. Сервис обеспечивает выдачу токена для авторизованного пользователя,
если он имеет права use
для ресурса ws:::gen-ws-token
или имеет права администратора.
В ответ на запрос, возвращается токен вида e444c69894d2087696e0a6c6914788f67ebcf6ee
. Время жизни токена по умолчанию 100 лет.
Пример запроса через аутентификацию типа Basic Auth
curl -u demo@local:ion-demo https://dnt.iondv.com/rest/token
Пример запроса с аутентификацией через параметры в заголовке
curl -H "auth-user: demo@local" -H "auth-pwd: ion-demo" -H "auth-user-type: local" https://dnt.iondv.com/rest/token
Примеры запросов к сервису token в dnt: test/modules/rest/token.spec.js
/Checking token service/# basicAuth authorization with admin rights
/Checking token service/# authorization with admin rights using header parameters
Добавить ресурс возможности генерации токенов для роли можно из комадной строки node bin/acl.js --role restGrp --p USE --res ws:::gen-ws-token
(где restGrp - название существующей группы)
Второй способ добавления прав на ресурс - использование консоли администратора модуля ionadmin, например, по адресу locahost:8888/ionadmin/
:
- Выберите пункт навигации «Безопасность»,
- Выберите подпункт навигации «Роли»
- Выберите существующую роль и нажмите кнопку «редактировать» или «создать новую роль».
- В поле «Права доступа» роли выберите вкладку «Services»
- Раскройте список прав для ресурса «Генерация токенов безопасности посредством веб-сервисов (ws:::gen-ws-token)»
- Выбрать пункт «Использование» и нажмите кнопку «Сохранить»
Встроенный сервис crud¶
Сервис crud реализует REST API по модели основных операций CRUD (create, read, update, delete).
Доступен по адресу <адрес сервера>/rest/crud
.
Сервис требует регистрации в deploy.json приложения и обязательного указания источника данных dataRepo
в options
сервиса, а также источника авторизации auth
для доступа к данным пользователя.
Целесообразно указывать в качестве репозитория данных - репозиторий с полной обработкой безопасности, чтобы отрабатывать
доступ к объектам с учетом динамической безопаности. Например:
{
"modules": {
"rest": {
"globals": {
"di": {
"crud": {
"module": "modules/rest/lib/impl/crud",
"options": {
"auth": "ion://auth",
"dataRepo": "ion://securedDataRepo"
}
}
Аутентификация осуществляется через все основные типы доступа.
Пример:
curl -X POST -u demo@local:ion-demo https://dnt.iondv.com/rest/crud
Пример запроса к сервису crud без параметров в dnt: test/modules/rest/crud.spec.js
/Checking crud service/# check if the response for null parameters is valid
По умолчанию, без правильных параметров - код ответа сервера 404
об ошибке
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Error</title>
</head>
<body>
<pre>Cannot POST /rest/crud</pre>
</body>
</html>
Информация по взаимодействию с crud через основные методы:
Создание объекта осуществляется методом POST
, при этом указывается код класса с нейспейсом,
например rest/crud/class_string@develop-and-test
. Сам объект передается в теле запроса в формате json с обязательным
указанием в заголовке типа содержания json Content-Type:application/json
. Автосоздаваемые поля указывать не обязательно.
Пример:
curl -X POST -u demo@local:ion-demo \
-H "Content-Type:application/json" \
-d '{"string_text": "Example3", "string_miltilinetext": "Example3", "string_formattext": "Example3"}' \
https://dnt.iondv.com/rest/crud/class_string@develop-and-test/
Пример запроса к сервису crud для создания объекта dnt: test/modules/rest/crud.spec.js
/Checking crud service/POST/# creating an object (POST)
В ответ будет возвращён созданный объект, в котором будут заполнены все автосозданные поля и указан код ответа 200
.
{
"_creator": "admin@local",
"_id": "10c77900-b96e-11e9-a7ce-314f02bd4197",
"__string": "10c77900-b96e-11e9-a7ce-314f02bd4197",
"__class": "class_string@develop-and-test",
"__classTitle": "Class \"String [0]\"",
"id": "10c77900-b96e-11e9-a7ce-314f02bd4197",
"string_text": "Example3",
"string_miltilinetext": "Example3",
"string_formattext": "Example3"
}
В случае ошибки код ответа будет 400
, а текст ответа содержать
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Error</title>
</head>
<body>
<pre>Bad Request</pre>
</body>
</html>
Получение объекта осуществляется методом GET
, при этом указывается код класса с нейспейсом и значение ключа объекта,
например rest/crud/class_string@develop-and-test/66dbb3d0-5583-11e6-aef7-cf50314f026b
curl -X GET -u demo@local:ion-demo https://dnt.iondv.com/rest/crud/class_string@develop-and-test/66dbb3d0-5583-11e6-aef7-cf50314f026b
Пример запроса к сервису crud для получения объекта в dnt: test/modules/rest/crud.spec.js
/Checking crud service/GET/# getting an object (GET)
При этом дополнительно в query может быть задан параметр _eager
содержащий список свойств класса, разделенных символом |
для которых необходимо осуществить жадную загрузку данных (ссылки или коллекции). Например
curl -X GET -u demo@local:ion-demo https://dnt.iondv.com/rest/crud/class_string@develop-and-test/66dbb3d0-5583-11e6-aef7-cf50314f026b?_eager=string_text
Пример запроса к сервису crud для получения объекта с жадной загрузкой свойства «table» в dnt: test/modules/rest/crud.spec.js
/Checking crud service/GET/# getting an object with eager loading of the "table" property (GET)
Если объект существует - возвращает код ответа 200
и сам объект в формате json, если объект не найден 404
, если нет прав 403
.
{
"_id": "66dbb3d0-5583-11e6-aef7-cf50314f026b",
"__string": "Example of the \"String [0]\" type in the \"Text [1]\" view",
"__class": "class_string@develop-and-test",
"__classTitle": "Class \"String [0]\"",
"id": "66dbb3d0-5583-11e6-aef7-cf50314f026b",
"string_text": "Example of the \"String [0]\" type in the \"Text [1]\" view",
"string_miltilinetext": "Example of the \"String [0]\"\r\n in the Multiline text [7] view",
"string_formattext": "Example of the \r\n \"String [0]\" type \r\n in the \r\nFormatted text [7] view"
}
Запрос списка объектов осуществляется методом GET
, при этом указывается код класса и нейспейс, например rest/crud/class_string@develop-and-test/
curl -X GET -u demo@local:ion-demo https://dnt.iondv.com/rest/crud/class_string@develop-and-test/
Пример запроса к сервису crud для получения списка объектов в dnt: test/modules/rest/crud.spec.js
/Checking crud service/GET/# getting a list of text objects
В ответ сервис выдает JSON Объект со смещением 0 и кол-вом 5ть записей и статусом 200
, если такого класса нет возвращает код 404
.
[{"_creator":"admin@local",
"_id":"4567a830-b8ea-11e9-9cdf-7bd384cbb7a5",
"__string":"example1",
"__class":"class_string@develop-and-test",
"__classTitle":"Class \"String [0]\"",
"id":"4567a830-b8ea-11e9-9cdf-7bd384cbb7a5",
"string_text":"example1",
"string_miltilinetext":"example1",
"string_formattext":"<p>example1</p>"},
{"_id":"66dbb3d0-5583-11e6-aef7-cf50314f026b",
"__string":"Example of the \"String [0]\" type in the \"Text [1]\" view",
"__class":"class_string@develop-and-test",
"__classTitle":"Class \"String [0]\"",
"id":"66dbb3d0-5583-11e6-aef7-cf50314f026b",
"string_text":"Example of the \"String [0]\" type in the \"Text [1]\" view",
"string_miltilinetext":"Example of the \"String [0]\"\r\n in the Multiline text [7] view",
"string_formattext":"Example of the \r\n \"String [0]\" type \r\n in the \r\nFormatted text [7] view"}]
Запрос может быть осуществлен со следущими query параметрами:
_offset
- смещение выборки, по умолчанию 0_count
- кол-во значение в выборке, по умолчанию 5_eager
- список свойств класса, разделенных символом|
для которых необходимо осуществить жадную загрузку данных.[name of property]
- все параметры запроса, кроме начинающихся на_
считаются именами атрибутов класса, а их значения задаются в качестве фильтров.
Примеры:
Запрос списка объектов класса со смещением 1 и кол-вом 2
curl -X GET -u demo@local:ion-demo https://dnt.iondv.com/rest/crud/class_string@develop-and-test/?_offset=1&_count=2
Запрос списка объектов, у которы свойство string_text имеет значение example1
curl -X GET -u demo@local:ion-demo https://dnt.iondv.com/rest/crud/class_string@develop-and-test/?string_text=example1
Запрос списка объектов, у которы свойство string_text имеет значение example1, со смещением 1 и кол-вом 2
curl -X GET -u demo@local:ion-demo https://dnt.iondv.com/rest/crud/class_string@develop-and-test/?string_text=example1&_offset=1&_count=2
Пример запроса к сервису crud для получения списка объектов с различными параметрами сдвига и фильтрации в dnt: test/modules/rest/crud.spec.js
/Checking crud service/GET/# getting a list of text objects, with an offset of 1 and a count of 2
/Checking crud service/GET/# getting a list of text objects containing a specific string
Обращение к HTTP-методу SEARCH
в сервисе CRUD осуществляется аналогично методу GET
. Исключением является то, что в теле сообщения можно в формате .json задать условия фильтрации, сортировки и жадной загрузки в нотации метода GetList
репозитория данных:
{
"filter": {
"eq": ["attr3", "etalon"]
},
"forceEnrichment": [["attr1", "attr2"], ["col1"]]
"sort": {
"attr4": -1
}
}
curl -X GET -u admin@local:ION-admin http://modws-26.develop-and-test.kube.local/rest/crud/class_string@develop-and-test/
Проверка наличия объекта осуществляется методом HEAD
, при этом указывается код класса с нейспейсом и значение ключа объекта,
например rest/crud/class_string@develop-and-test/66dbb3d0-5583-11e6-aef7-cf50314f026b
curl -X HEAD -u demo@local:ion-demo https://dnt.iondv.com/rest/crud/class_string@develop-and-test/66dbb3d0-5583-11e6-aef7-cf50314f026b
Пример запроса к сервису crud для проверки наличия объекта в dnt: test/modules/rest/crud.spec.js
/Checking crud service/HEAD/# checking if an object is present (HEAD)
Если объект существует - возвращает код ответа 200
, если объект не найден 404
, если нет прав 403
.
Обновление объекта осуществляется методом PATCH
или PUT
, при этом указывается код класса с нейспейсом и значение ключа объекта,
например rest/crud/class_string@develop-and-test/66dbb3d0-5583-11e6-aef7-cf50314f026b
. Сам объект передается в теле запроса в формате json с обязательным указанием в заголовке типа содержания json Content-Type:application/json
.
Пример:
curl -X PATCH -u demo@local:demo-ion -H "Content-Type:application/json" -d '{"string_text": "NEW Example", "string_miltilinetext": "NEW Example", "string_formattext": "NEW Example"}' https://dnt.iondv.com/rest/crud/class_string@develop-and-test/66dbb3d0-5583-11e6-aef7-cf50314f026b
# Или эквивалентно
curl -X PUT -u demo@local:demo-ion -H "Content-Type:application/json" -d '{"string_text": "NEW Example", "string_miltilinetext": "NEW Example", "string_formattext": "NEW Example"}' https://dnt.iondv.com/rest/crud/class_string@develop-and-test/66dbb3d0-5583-11e6-aef7-cf50314f026b
Пример запроса к сервису crud для обновления объекта в dnt: test/modules/rest/crud.spec.js
/Checking crud service/PATCH/# updating an object (PATCH)
Если объект существует - возвращает код ответа 200
и сам объект в формате json, если объект не найден код 404
, при ошибке обработки код 500
, если нет прав 403
.
Пример объекта.
{
"_editor": "admin@local",
"_id": "66dbb3d0-5583-11e6-aef7-cf50314f026b",
"__string": "NEW Example",
"__class": "class_string@develop-and-test",
"__classTitle": "Class \"String [0]\"",
"id": "66dbb3d0-5583-11e6-aef7-cf50314f026b",
"string_text": "NEW Example",
"string_miltilinetext": "NEW Example",
"string_formattext": "NEW Example"
}
Удаление объекта осуществляется методом DELETE
, при этом указывается код класса с нейспейсом и значение ключа объекта,
например rest/crud/class_string@develop-and-test/66dbb3d0-5583-11e6-aef7-cf50314f026b
.
curl -X DELETE -u demo@local:demo-ion https://dnt.iondv.com/rest/crud/class_string@develop-and-test/66dbb3d0-5583-11e6-aef7-cf50314f026b
Пример запроса к сервису crud на удаление объектов в dnt: test/modules/rest/crud.spec.js
/Checking crud service/DELETE/# deleting an object (DELETE)
В случае успеха - сервис возвращает код ответа 200
, в случае если объект не найден 404
.
При запросе к CRUD методами POST, PATCH и PUT, в теле запроса можно передать файлы.
Отправка и прием файлов осуществляется двумя способами:
- данные отправляются в формате
json
, тогда контент файла передается как строка в формате Base64 в соответствующем поле класса метаданных. - данные отправляются как
FormData
(application/x-www-form-urlencoded), тогда файлы передаются как компонент multipart.
Корректный прием файловых атрибутов в случае отправки таких запросов осуществляется методами POST
, PUT
и PATCH
в CRUD сервисе.
Так же возможна передача ссылок и коллекций по примеру, описанному для soap модуля.
Примеры POST запросов с файлами к CRUD
в dnt:
test/modules/rest/crud.spec.js
/checking crud service/# sending a file with multipart body request (POST)
/checking crud service/# sending a file with json body request (POST)
Cервис публикации метаданных Meta¶
Meta meta
- встроенный сервис в rest модуле, который предоставляет доступ к интерфейсу метарепозитория в формате веб-сервиса.
Сервис требует подключения в deploy.json
и обязательного указания options.dataRepo
и options.metaRepo
, пример:
"meta": {
"module": "modules/rest/lib/impl/meta",
"options": {
"dataRepo": "ion://dataRepo",
"metaRepo": "ion://metaRepo"
}
}
Поддерживаются все типы авторизации, по умолчанию - авторизация учетными данными.
Запрос осуществляется по пути <URL сервера>/rest/<название сервиса>/getMeta/<имя класса>
,
где имя класса указывается с неймспейсом.
В запросе можно указать дополнительные параметры:
version
namespace
Пример запроса:
https://localhost:8888/rest/meta/getMeta/class_text@develop-and-test
будет запрошена информация по классу class_text
в неймспейсе develop-and-test
, пример ответа:
{ namespace: 'develop-and-test',
isStruct: false,
metaVersion: '2.0.7',
key: [ 'id' ],
semantic: '',
name: 'class_text',
version: '',
caption: 'Class "Text [1]"',
ancestor: null,
container: null,
creationTracker: '',
changeTracker: '',
history: 0,
journaling: false,
compositeIndexes: null,
properties:
[ { orderNumber: 10,
name: 'id',
caption: 'Identifier',
type: 12,
size: 24,
decimals: 0,
allowedFileTypes: null,
maxFileCount: 0,
nullable: false,
readonly: false,
indexed: true,
unique: true,
autoassigned: true,
hint: null,
defaultValue: null,
refClass: '',
itemsClass: '',
backRef: '',
backColl: '',
binding: '',
semantic: null,
selConditions: null,
selSorting: [],
selectionProvider: null,
indexSearch: false,
eagerLoading: false,
formula: null },
{ orderNumber: 20,
name: 'text_text',
caption: 'Text [1]',
type: 1,
size: null,
decimals: 0,
allowedFileTypes: null,
maxFileCount: 0,
nullable: true,
readonly: false,
indexed: true,
unique: false,
autoassigned: false,
hint: null,
defaultValue: null,
refClass: '',
itemsClass: '',
backRef: '',
backColl: '',
binding: '',
semantic: null,
selConditions: null,
selSorting: [],
selectionProvider: null,
indexSearch: false,
eagerLoading: false,
formula: null },
{ orderNumber: 30,
name: 'text_multilinetext',
caption: 'Multiline text [7]',
type: 1,
size: null,
decimals: 0,
allowedFileTypes: null,
maxFileCount: 0,
nullable: true,
readonly: false,
indexed: true,
unique: false,
autoassigned: false,
hint: null,
defaultValue: null,
refClass: '',
itemsClass: '',
backRef: '',
backColl: '',
binding: '',
semantic: null,
selConditions: null,
selSorting: [],
selectionProvider: null,
indexSearch: false,
eagerLoading: false,
formula: null },
{ orderNumber: 40,
name: 'text_formattext',
caption: 'Formatted text [8]',
type: 1,
size: null,
decimals: 0,
allowedFileTypes: null,
maxFileCount: 0,
nullable: true,
readonly: false,
indexed: true,
unique: false,
autoassigned: false,
hint: null,
defaultValue: null,
refClass: '',
itemsClass: '',
backRef: '',
backColl: '',
binding: '',
semantic: null,
selConditions: null,
selSorting: [],
selectionProvider: null,
indexSearch: false,
eagerLoading: false,
formula: null } ] }
Этот пример в dnt: test/modules/rest/metadatasrv.spec.js
/checking metadata service/# accessing info about metadata class: getMeta
Запрос осуществляется по пути <URL сервера>/rest/<название сервиса>/listMeta
.
В запросе можно указать дополнительные параметры:
ancestor
version
direct
namespace
Пример запроса:
https://localhost:8888/rest/meta/listMeta
будет запрошена информация по всем классам из метарепозитория, указанного в настройках сервиса meta
в deploy.json
.
Этот пример в dnt: test/modules/rest/metadatasrv.spec.js
/checking metadata service/# accessing the list of metadata classes: listMeta
Запрос осуществляется по пути <URL сервера>/rest/<название сервиса>/ancestor/<имя класса>
,
где имя класса указывается с неймспейсом.
В запросе можно указать дополнительные параметры:
version
namespace
Пример запроса:
https://localhost:8888/rest/meta/getMeta/event@develop-and-test
будет запрошена информация по классу-предку класса event
в неймспейсе develop-and-test
- basicObj
.
Этот пример в dnt: test/modules/rest/metadatasrv.spec.js
/checking metadata service/# accessing info about class ancestor
Запрос осуществляется по пути <URL сервера>/rest/<название сервиса>/propertyMetas/<имя класса>
,
где имя класса указывается с неймспейсом.
В запросе можно указать дополнительные параметры:
version
namespace
Пример запроса:
https://localhost:8888/rest/meta/propertyMetas/class_text@develop-and-test
будет запрошена информация о свойствах объектов класса class_text
в неймспейсе develop-and-test
, например:
[ { orderNumber: 10,
name: 'id',
caption: 'Identifier',
type: 12,
size: 24,
decimals: 0,
allowedFileTypes: null,
maxFileCount: 0,
nullable: false,
readonly: false,
indexed: true,
unique: true,
autoassigned: true,
hint: null,
defaultValue: null,
refClass: '',
itemsClass: '',
backRef: '',
backColl: '',
binding: '',
semantic: null,
selConditions: null,
selSorting: [],
selectionProvider: null,
indexSearch: false,
eagerLoading: false,
formula: null,
definitionClass: 'class_text@develop-and-test',
mode: 0 },
{ orderNumber: 20,
name: 'text_text',
caption: 'Text [1]',
type: 1,
size: null,
decimals: 0,
allowedFileTypes: null,
maxFileCount: 0,
nullable: true,
readonly: false,
indexed: true,
unique: false,
autoassigned: false,
hint: null,
defaultValue: null,
refClass: '',
itemsClass: '',
backRef: '',
backColl: '',
binding: '',
semantic: null,
selConditions: null,
selSorting: [],
selectionProvider: null,
indexSearch: false,
eagerLoading: false,
formula: null,
definitionClass: 'class_text@develop-and-test',
mode: 0 },
{ orderNumber: 30,
name: 'text_multilinetext',
caption: 'Multiline text [7]',
type: 1,
size: null,
decimals: 0,
allowedFileTypes: null,
maxFileCount: 0,
nullable: true,
readonly: false,
indexed: true,
unique: false,
autoassigned: false,
hint: null,
defaultValue: null,
refClass: '',
itemsClass: '',
backRef: '',
backColl: '',
binding: '',
semantic: null,
selConditions: null,
selSorting: [],
selectionProvider: null,
indexSearch: false,
eagerLoading: false,
formula: null,
definitionClass: 'class_text@develop-and-test',
mode: 0 },
{ orderNumber: 40,
name: 'text_formattext',
caption: 'Formatted text [8]',
type: 1,
size: null,
decimals: 0,
allowedFileTypes: null,
maxFileCount: 0,
nullable: true,
readonly: false,
indexed: true,
unique: false,
autoassigned: false,
hint: null,
defaultValue: null,
refClass: '',
itemsClass: '',
backRef: '',
backColl: '',
binding: '',
semantic: null,
selConditions: null,
selSorting: [],
selectionProvider: null,
indexSearch: false,
eagerLoading: false,
formula: null,
definitionClass: 'class_text@develop-and-test',
mode: 0 } ]
Этот пример в dnt: test/modules/rest/metadatasrv.spec.js
/checking metadata service/# accessing info about meta object properties: propertyMetas
Запрос осуществляется по пути <URL сервера>/rest/<название сервиса>/getNode/<код навигации>
,
где код навигации указывается в формате namespace@code
.
В запросе можно указать дополнительные параметры:
namespace
Пример запроса:
https://localhost:8888/rest/meta/getNode/develop-and-test@semantic
будет запрошен объект узла навигации semantic
в неймспейсе develop-and-test
, пример ответа:
{ code: 'semantic',
orderNumber: 0,
type: 0,
caption: 'Display semantics [semantic]',
classname: null,
container: null,
collection: null,
url: null,
hint: null,
conditions: null,
sorting: [],
pathChains: [],
metaVersion: '2.0.61',
itemType: 'node',
section: 'develop-and-test@classProperties',
namespace: 'develop-and-test',
children:
[ { code: 'semantic.semErrCatalog',
orderNumber: 0,
type: 1,
caption:
'Catalog for checking semantics (string1| |string2| |string3| |date| |integer)',
classname: 'semErrCatalog@develop-and-test',
container: null,
collection: null,
url: null,
hint: null,
conditions: null,
sorting: [],
pathChains: [],
metaVersion: '2.0.61',
itemType: 'node',
section: 'develop-and-test@classProperties',
namespace: 'develop-and-test',
children: [] },
{ code: 'semantic.semErrClass',
orderNumber: 0,
type: 1,
caption: 'Attribute semantics is taken from reference class',
classname: 'semErrClass@develop-and-test',
container: null,
collection: null,
url: null,
hint: null,
conditions: null,
sorting: [],
pathChains: [],
metaVersion: '2.0.61',
itemType: 'node',
section: 'develop-and-test@classProperties',
namespace: 'develop-and-test',
children: [] }]
}
Этот пример в dnt: test/modules/rest/metadatasrv.spec.js
/checking metadata service/# access info about a navigation node: getNode
Запрос осуществляется по пути <URL сервера>/rest/<название сервиса>/getNodes/<код секции>
,
где код секции указывается в формате namespace@name
.
В запросе можно указать дополнительные параметры:
section
parent
namespace
Пример запроса:
https://localhost:8888/rest/meta/getNodes/develop-and-test@simpleTypes
будет запрошен список узлов навигации в секции simpleTypes
в неймспейсе develop-and-test
.
Этот пример в dnt: test/modules/rest/metadatasrv.spec.js
/checking metadata service/# access the list of navigation nodes in a section: getNodes
Запрос осуществляется по пути <URL сервера>/rest/<название сервиса>/getListViewModel/<имя класса>
,
где имя класса указывается с неймспейсом.
В запросе можно указать дополнительные параметры:
node
namespace
version
Пример запроса:
https://localhost:8888/rest/meta/getListViewModel/class_text@develop-and-test
будет запрошен объект представления объектов класса class_text
в списочной форме в неймспейсе develop-and-test
, пример ответа:
{ columns:
[ { sorted: true,
caption: 'Identifier',
type: 1,
property: 'id',
size: 2,
maskName: null,
mask: null,
mode: null,
fields: [],
hierarchyAttributes: null,
columns: [],
actions: null,
commands: [],
orderNumber: 10,
required: false,
visibility: null,
enablement: null,
obligation: null,
readonly: true,
selectionPaginated: true,
validators: null,
hint: '',
historyDisplayMode: 0,
tags: null },
{ sorted: true,
caption: 'Text [1]',
type: 1,
property: 'text_text',
size: 2,
maskName: null,
mask: null,
mode: null,
fields: [],
hierarchyAttributes: null,
columns: [],
actions: null,
commands: [],
orderNumber: 20,
required: false,
visibility: null,
enablement: null,
obligation: null,
readonly: false,
selectionPaginated: true,
validators: null,
hint: '',
historyDisplayMode: 0,
tags: null },
{ sorted: true,
caption: 'Multiline text [7]',
type: 7,
property: 'text_multilinetext',
size: 2,
maskName: null,
mask: null,
mode: null,
fields: [],
hierarchyAttributes: null,
columns: [],
actions: null,
commands: [],
orderNumber: 30,
required: false,
visibility: null,
enablement: null,
obligation: null,
readonly: false,
selectionPaginated: true,
validators: null,
hint: '',
historyDisplayMode: 0,
tags: null },
{ sorted: true,
caption: 'Formatted text [8]',
type: 8,
property: 'text_formattext',
size: 2,
maskName: null,
mask: null,
mode: null,
fields: [],
hierarchyAttributes: null,
columns: [],
actions: null,
commands: [],
orderNumber: 40,
required: false,
visibility: null,
enablement: null,
obligation: null,
readonly: false,
selectionPaginated: true,
validators: null,
hint: '',
historyDisplayMode: 0,
tags: null } ],
actions: null,
commands:
[ { id: 'CREATE',
caption: 'Create',
visibilityCondition: null,
enableCondition: null,
needSelectedItem: false,
signBefore: false,
signAfter: false,
isBulk: false },
{ id: 'EDIT',
caption: 'Edit',
visibilityCondition: null,
enableCondition: null,
needSelectedItem: true,
signBefore: false,
signAfter: false,
isBulk: false },
{ id: 'DELETE',
caption: 'Delete',
visibilityCondition: null,
enableCondition: null,
needSelectedItem: false,
signBefore: false,
signAfter: false,
isBulk: true } ],
allowSearch: false,
pageSize: null,
useEditModels: true,
version: null,
overrideMode: null,
metaVersion: '2.0.7',
type: 'list',
className: 'class_text@develop-and-test',
path: '',
caption: '' }
Этот пример в dnt: test/modules/rest/metadatasrv.spec.js
/checking metadata service/# access meta class list view model: getListViewModel
Запрос осуществляется по пути <URL сервера>/rest/<название сервиса>/getCollectionViewModel/<имя класса>
,
где имя класса указывается с неймспейсом.
В запросе можно указать дополнительные параметры:
collection
node
namespace
version
Пример запроса:
https://localhost:8888/rest/meta/getCollectionViewModel/class_text@develop-and-test
будет запрошен объект представления объектов класса class_text
в форме коллекции в неймспейсе develop-and-test
.
Этот пример в dnt: test/modules/rest/metadatasrv.spec.js
/checking metadata service/# access meta class collection view model: getCollectionViewModel
Запрос осуществляется по пути <URL сервера>/rest/<название сервиса>/getCreationViewModel/<имя класса>
,
где имя класса указывается с неймспейсом.
В запросе можно указать дополнительные параметры:
node
namespace
version
Пример запроса:
https://localhost:8888/rest/meta/getCreationViewModel/class_text@develop-and-test
будет запрошен объект представления объектов класса class_text
при их создании в неймспейсе develop-and-test
, пример ответа:
{ tabs: [ { caption: '', fullFields: [Array], shortFields: [] } ],
actions: null,
commands:
[ { id: 'SAVE',
caption: 'Save',
visibilityCondition: null,
enableCondition: null,
needSelectedItem: false,
signBefore: false,
signAfter: false,
isBulk: false },
{ id: 'SAVEANDCLOSE',
caption: 'Save and close',
visibilityCondition: null,
enableCondition: null,
needSelectedItem: false,
signBefore: false,
signAfter: false,
isBulk: false } ],
siblingFixBy: null,
siblingNavigateBy: null,
historyDisplayMode: 0,
collectionFilters: null,
version: null,
overrideMode: null,
metaVersion: '2.0.7',
type: 'create',
className: 'class_text@develop-and-test',
path: '',
caption: '' }
Этот пример в dnt: test/modules/rest/metadatasrv.spec.js
/checking metadata service/# access meta class creation view model: getCreationViewModel
Запрос осуществляется по пути <URL сервера>/rest/<название сервиса>/getItemViewModel/<имя класса>
,
где имя класса указывается с неймспейсом.
В запросе можно указать дополнительные параметры:
node
namespace
version
Пример запроса:
https://localhost:8888/rest/meta/getItemViewModel/class_text@develop-and-test
будет запрошен объект представления объектов класса class_text
при их редактировании в неймспейсе develop-and-test
, пример ответа:
{ tabs: [ { caption: '', fullFields: [Array], shortFields: [] } ],
actions: null,
commands:
[ { id: 'SAVE',
caption: 'Save',
visibilityCondition: null,
enableCondition: null,
needSelectedItem: false,
signBefore: false,
signAfter: false,
isBulk: false },
{ id: 'SAVEANDCLOSE',
caption: 'Save and close',
visibilityCondition: null,
enableCondition: null,
needSelectedItem: false,
signBefore: false,
signAfter: false,
isBulk: false } ],
siblingFixBy: null,
siblingNavigateBy: null,
historyDisplayMode: 0,
collectionFilters: null,
version: null,
overrideMode: null,
metaVersion: '2.0.7',
type: 'item',
className: 'class_text@develop-and-test',
path: '' }
Этот пример в dnt: test/modules/rest/metadatasrv.spec.js
/checking metadata service/# access meta class item view model: getItemViewModel
Запрос осуществляется по пути <URL сервера>/rest/<название сервиса>/getDetailViewModel/<имя класса>
,
где имя класса указывается с неймспейсом.
В запросе можно указать дополнительные параметры:
node
namespace
version
Пример запроса:
https://localhost:8888/rest/meta/getDetailViewModel/class_text@develop-and-test
будет запрошен объект представления объектов класса class_text
при их просмотре в неймспейсе develop-and-test
.
Этот пример в dnt: test/modules/rest/metadatasrv.spec.js
/checking metadata service/# access meta class detail view model: getDetailViewModel
Запрос осуществляется по пути <URL сервера>/rest/<название сервиса>/getWorkflows/<имя класса>
,
где имя класса указывается с неймспейсом.
В запросе можно указать дополнительные параметры:
namespace
version
Пример запроса:
https://localhost:8888/rest/meta/getWorkflows/workflowBase@develop-and-test
будет запрошен список бизнес-процессов для класса workflowBase
в неймспейсе develop-and-test
, пример ответа:
[ { name: 'simpleWorkflow',
caption: 'Simple WF',
wfClass: 'workflowBase@develop-and-test',
startState: 'canStart',
states: [ [Object], [Object], [Object], [Object], [Object] ],
transitions: [ [Object], [Object], [Object], [Object], [Object] ],
metaVersion: '2.0.61.16945',
namespace: 'develop-and-test' } ]
Этот пример в dnt: test/modules/rest/metadatasrv.spec.js
/checking metadata service/# accessing the list of possible workflows for meta class: getWorkflows
Запрос осуществляется по пути <URL сервера>/rest/<название сервиса>/getListViewModel/<имя класса>/<имя бизнес-процесса>/<имя состояния>
,
где имя класса и имя бизнес-процесса указываются с неймспейсом.
В запросе можно указать дополнительные параметры:
workflow
state
namespace
version
Пример запроса:
https://localhost:8888/rest/meta/getWorkflowView/workflowBase@develop-and-test/simpleWorkflow@develop-and-test/canStart
будет запрошен объект представления объектов класса workflowBase
при состоянии canStart
бизнес-процесса simpleWorkflow
в неймспейсе develop-and-test
, пример ответа:
{ tabs: [ { caption: '', fullFields: [Array], shortFields: [] } ],
actions: null,
siblingFixBy: null,
siblingNavigateBy: null,
historyDisplayMode: 0,
collectionFilters: null,
version: null,
overrideMode: 1,
commands:
[ { id: 'SAVE',
caption: 'Save',
visibilityCondition: null,
enableCondition: null,
needSelectedItem: false,
signBefore: false,
signAfter: false,
isBulk: false },
{ id: 'SAVEANDCLOSE',
caption: 'Save and close',
visibilityCondition: null,
enableCondition: null,
needSelectedItem: false,
signBefore: false,
signAfter: false,
isBulk: false } ],
metaVersion: '2.0.61',
type: 'item',
className: 'workflowBase@develop-and-test',
path: 'workflows:simpleWorkflow@develop-and-test.canStart',
caption: '' }
Этот пример в dnt: test/modules/rest/metadatasrv.spec.js
/checking metadata service/# access meta class view model in a certain workflow state: getWorkflowView
Запрос осуществляется по пути <URL сервера>/rest/<название сервиса>/getWorkflow/<имя класса>/<имя бизнес-процесса>
,
где имя класса и имя бизнес-процесса указываются с неймспейсом.
В запросе можно указать дополнительные параметры:
workflow
namespace
version
Пример запроса:
https://localhost:8888/rest/meta/getWorkflow/workflowBase@develop-and-test/simpleWorkflow@develop-and-test
будет запрошен объект бизнес-процесса simpleWorkflow
для класса объектов workflowBase
в неймспейсе develop-and-test
. Пример ответа:
{ name: 'simpleWorkflow',
caption: 'Simple WF',
wfClass: 'workflowBase@develop-and-test',
startState: 'canStart',
states:
[ { name: 'canStart',
caption: 'Ready to check',
maxPeriod: null,
conditions: [Object],
propertyPermissions: [],
itemPermissions: [],
selectionProviders: [] },
{ name: 'inProcess',
caption: 'In process',
maxPeriod: null,
conditions: null,
itemPermissions: [Array],
propertyPermissions: [],
selectionProviders: [] },
{ name: 'accepted',
caption: 'Accepted',
maxPeriod: null,
conditions: null,
itemPermissions: [],
propertyPermissions: [],
selectionProviders: [] },
{ name: 'returned',
caption: 'Returned',
maxPeriod: null,
conditions: null,
itemPermissions: [Array],
propertyPermissions: [],
selectionProviders: [] },
{ name: 'rejected',
caption: 'Rejected',
maxPeriod: null,
conditions: null,
itemPermissions: [],
propertyPermissions: [],
selectionProviders: [] } ],
transitions:
[ { name: 'startCheck',
caption: 'Start checking',
startState: 'canStart',
finishState: 'inProcess',
signBefore: false,
signAfter: false,
roles: [],
assignments: [Array],
conditions: null,
confirm: false,
confirmMessage: null },
{ name: 'return',
caption: 'Return',
startState: 'inProcess',
finishState: 'returned',
signBefore: false,
signAfter: false,
roles: [],
assignments: [Array],
conditions: null,
confirm: false,
confirmMessage: null },
{ name: 'accept',
caption: 'Accept',
startState: 'inProcess',
finishState: 'accepted',
signBefore: false,
signAfter: false,
roles: [],
assignments: [Array],
conditions: null,
confirm: false,
confirmMessage: null },
{ name: 'reject',
caption: 'Reject',
startState: 'inProcess',
finishState: 'rejected',
signBefore: false,
signAfter: false,
roles: [],
assignments: [Array],
conditions: null,
confirm: false,
confirmMessage: null },
{ name: 'notify',
caption: 'To check',
startState: 'returned',
finishState: 'canStart',
signBefore: false,
signAfter: false,
roles: [],
assignments: [Array],
conditions: [Object],
confirm: false,
confirmMessage: null } ],
metaVersion: '2.0.61.16945',
namespace: 'develop-and-test' }
Этот пример в dnt: test/modules/rest/metadatasrv.spec.js
/checking metadata service/# access information about workflow: getWorkflow
Запрос осуществляется по пути <URL сервера>/rest/<название сервиса>/getMask/<имя маски>
.
Например:
https://localhost:8888/rest/meta/getMask/snils
будет запрошен объект маски snils
.
Этот пример в dnt: test/modules/rest/metadatasrv.spec.js
/checking metadata service/# access information about view mask: getMask
Запрос осуществляется по пути <URL сервера>/rest/<название сервиса>/getValidators
, например:
https://localhost:8888/rest/meta/getValidators
будет запрошен список доступных валидаторов.
Этот пример в dnt: test/modules/rest/metadatasrv.spec.js
/checking metadata service/# access information about input validators: getValidators
В большинстве запросов к сервису метаданных (meta
), помимо самого запроса, можно указать
дополнительные параметры. Список дополнительных параметров, которые необходимо применить к запросу
начинается символом ?
, после этого пишется название и значение параметра через знак =
,
несколько параметров разделяются между собой с помощью &
.
Пример GET запроса к meta/getList
с дополнительным параметром ancestor
- фильтрацией по предку:
https://localhost:8888/rest/meta/listMeta?ancestor=basicObj@develop-and-test
В ответ будет возвращен список классов метаданных, которые являются производными от basicObj
.
Этот пример в dnt: test/modules/rest/metadatasrv.spec.js
/checking metadata service/# accessing the list of metadata classes filtering by ancestor: listMeta
Сервис исполнения бизнес-процессов Workflows¶
Workflows workflows
- встроенный сервис в rest модуле, который предоставляет возможности контроля и управления бизнес-процессами.
Сервис требует подключения в deploy.json
и обязательного указания options.dataRepo
, options.metaRepo
, options.auth
и options.workflow
, пример:
"workflows": {
"module": "modules/rest/lib/impl/workflows",
"options": {
"auth": "ion://auth",
"dataRepo": "ion://dataRepo",
"metaRepo": "ion://metaRepo",
"workflow": "ion://workflow"
}
}
Поддерживаются все типы авторизации, по умолчанию - авторизация учетными данными.
Сервис содержит три метода:
GET
- без параметров, возвращает информацию о текущем статусе в БП (возможные переходы)PUT
- выполняет перевод обьекта в указанные следующие этапы разных БП.PATCH
- выполняет принудительный перевод обьекта в указанные этапы разных БП.
Для всех методов запросы принимаются по пути <URL сервера>/rest/<имя сервиса>/:class/:id
для идентификации обьекта данных.
Методом GET осуществляется получение текущего положения обьекта в бизнес-процессах.
Запрос осуществляется по пути <URL сервера>/rest/<название сервиса>/<имя класса>/<id объекта>
, пример:
https://localhost:8888/rest/workflows/workflowBase@develop-and-test/1
В ответ будет получен объект с состояниями бизнес-процессов:
{ stages:
{ 'simpleWorkflow@develop-and-test':
{ stage: 'inProcess',
since: '2020-05-12T06:36:06.045Z',
next: [Object],
workflowCaption: 'Simple WF',
stageCaption: 'In process' } },
itemPermissions: { read: true },
propertyPermissions: {},
selectionProviders: {} }
Пример GET
запроса к workflows
в dnt:
test/modules/rest/workflows.spec.js
/checking workflows service/# accessing workflow statuses of the object: GET
Методом PUT сервиса workflows
осуществляется выполнение переходов объекта по БП (в том числе последовательных).
Запрос осуществляется по пути <URL сервера>/rest/<название сервиса>/<имя класса>/<id объекта>
.
Имя класса указывается с неймспейсом.
В теле запроса передается один из вариантов:
- объект с атрибутами - именами БП, которые содержат список из переходов по этим бизнес-процессам.
- список из строк формата
<имя бизнес-процесса>.<название перехода>
имена бизнес-процессов указываются с неймспейсом.
Пример запроса:
PUT
https://localhost:8888/rest/workflows/workflowBase@develop-and-test/1
body: {
'simpleWorkflow@develop-and-test': [
'startCheck',
'accept'
]
}
что равносильно:
PUT
https://localhost:8888/rest/workflows/workflowBase@develop-and-test/1
body: [
'simpleWorkflow@develop-and-test.startCheck',
'simpleWorkflow@develop-and-test.accept'
]
Переходы выполняются последовательно. Для каждого перехода будет предпринята попытка выполнения, даже если в одном из них произошла ошибка.
В ответ будет возвращен список из ошибок по каждому переходу:
[ { code: 'workflow.ti',
params: { workflow: 'Simple WF', trans: 'Start checking' },
message:
'Невозможно выполнение перехода \'Start checking\' рабочего процесса \'Simple WF\'.' },
{ code: 'workflow.ti',
params: { workflow: 'Simple WF', trans: 'Accept' },
message:
'Невозможно выполнение перехода \'Accept\' рабочего процесса \'Simple WF\'.' } ]
или пустой список.
Примеры PUT
запросов к workflows
в dnt:
test/modules/rest/workflows.spec.js
/checking workflows service/# move the object through workflow: PUT, list body
/checking workflows service/# move the object through workflow: PUT, object body
Методом PATCH осуществляется принудительное перемещение объекта в указанные состояния бизнес-процессов.
Запрос осуществляется по пути <URL сервера>/rest/<название сервиса>/<имя класса>/<id объекта>
. Имя класса указывается с неймспейсом.
В теле запроса передается массив целевых состояний бизнес-процессов, которые указываются как
строки в формате <имя бизнес-процесса>.<состояние>
. Имя бизнес-процесса указывается с неймспейсом.
Объект последовательно перемещается в каждое из состояний.
Пример запроса:
PATCH
https://localhost:8888/rest/workflows/workflowBase@develop-and-test/1
body: [
'simpleWorkflow@develop-and-test.canStart'
]
В ответ будет возвращен список ошибок, возникших при перемещениях, либо пустой список.
Пример PATCH
запроса к workflows
в dnt:
test/modules/rest/workflows.spec.js
/checking workflows service/# move the object to certain state in a workflow: PATCH
Разработка обработчика сервиса в приложении¶
Все сервисы реализуются как наследники от Service - функции модуля rest.
Каждый сервис должен экспортировать функцию обработчика, в которой реализован асинхронный метод this._route
, в котором
необходимо зарегистрировать обрабатываемые методы и пути через функции this.addHandler
, возвращающие Promise. Функция обработки
будет иметь доступ к options
, через который доступ к репозиториям данных, авторизации, метаданным и классам (если они
указаны в конфигурации приложения в файле deploy.json), а также получит объект с типовым названием req
- являющимся
объектом request
библиотеки express.
Данные, прошедшие парсинг в объект будут находиться в req.body
.
Функция-обработчик должна вернуть Promise разрешающийся в результат обработки (для обработки в Service modules/rest/lib/interfaces/Service.js
),
обработчик выдаст его с кодом 200
и типом содержания Content-Type:application/json
.
Если в ходе обработки будет ошибка, перехваченная catch, то для ошибок связанных с контролем доступа будет возвращен ответ с текстом ошибки и с кодом 403
, а для всех остальных код ответа 500
и сообщением об ошибке Internal server error
.
Заголовок можно переопределить, для этого в ответе нужно отдать тип заголовка headers
, а объект в атрибуте data
Promise.resolve({headers: ['Content-Type: image/png', 'Content-Length: 107'],
data: Buffer.from([0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0x00, 0x00, 0x00, 0x0D, 0x49,
0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x08, 0x06, 0x00, 0x00, 0x00,
0x1F, 0x15, 0xC4, 0x89, 0x00, 0x00, 0x00, 0x06, 0x62, 0x4B, 0x47, 0x44, 0x00, 0xFF, 0x00, 0xFF,
0x00, 0xFF, 0xA0, 0xBD, 0xA7, 0x93, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00,
0x2E, 0x23, 0x00, 0x00, 0x2E, 0x23, 0x01, 0x78, 0xA5, 0x3F, 0x76, 0x00, 0x00, 0x00, 0x0B, 0x49,
0x44, 0x41, 0x54, 0x08, 0xD7, 0x63, 0x60, 0x00, 0x02, 0x00, 0x00, 0x05, 0x00, 0x01, 0xE2, 0x26,
0x05, 0x9B, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4E, 0x44, 0xAE, 0x42, 0x60, 0x82])
})
Пример реализации сервиса, выдающего списки объектов с фильтрами для класса class_string
есть в приложении develop-and-test
.
Также, для изучения удобно смотреть сам метод crud, находящийся по адресу modules/rest/lib/impl/crud.js
const Service = require('modules/rest/lib/interfaces/Service');
/**
* @param {{dataRepo: DataRepository, echoClassName: String}} options
* @constructor
*/
function listClassString(options) {
/**
* @param {Request} req
* @returns {Promise}
* @private
*/
this._route = function(router) {
this.addHandler(router, '/', 'POST', (req) => {
return new Promise(function (resolve, reject) {
try {
let filter = [];
if (req.body.string_text)
filter.push({string_text: {$eq: req.body.string_text}});
if (req.body.string_miltilinetext)
filter.push({string_miltilinetext: {$eq: req.body.string_miltilinetext}});
if (filter.length === 0)
filter = {};
else if (filter.length === 1)
filter = filter[0];
else
filter = {$and: filter};
options.dataRepo.getList(options.stringClassName, {filter: filter}).then(function (results) {
let items = [];
for (let i = 0; i < results.length; i++) {
const props = results[i].getProperties();
const item = {};
for (let p in props) {
if (props.hasOwnProperty(p))
item[props[p].getName()] = props[p].getValue();
}
items.push(item);
}
resolve({data: items});
});
} catch (err) {
reject(err);
}
});
});
}
}
listClassString.prototype = new Service();
module.exports = listClassString;
Запрос без атрибутов в теле запроса
curl -X POST -u demo@local:ion-demo https://dnt.iondv.com:8888/rest/string-list
вернет весь список:
[{"__class":"class_string@develop-and-test",
"__classTitle":"Class \"String [0]\"",
"id":"4567a830-b8ea-11e9-9cdf-7bd384cbb7a5",
"string_text":"example1",
"string_miltilinetext":"example1",
"string_formattext":"<p>example1</p>"},
{"__class":"class_string@develop-and-test",
"__classTitle":"Class \"String [0]\"",
"id":"4a80bdc0-b8ea-11e9-9cdf-7bd384cbb7a5",
"string_text":"example1",
"string_miltilinetext":"example2",
"string_formattext":"<p>example2</p>"},
{"__class":"class_string@develop-and-test",
"__classTitle":"Class \"String [0]\"",
"id":"66dbb3d0-5583-11e6-aef7-cf50314f026b",
"string_text":"Example of the \"String [0]\" type in the \"Text [1]\" view",
"string_miltilinetext":"Example of the \"String [0]\"\r\n in the Multiline text [7] view",
"string_formattext":"Example of the \r\n \"String [0]\" type \r\n in the \r\nFormatted text [7] view"}]
А запрос с параметром атрибута равного значению в атрибуте string_text
Example of the \"String [0]\" type in the \"Text [1]\" view
curl -X POST -d "string_text=Example of the \"String [0]\" type in the \"Text [1]\"" \
-u demo@local:ion-demo https://dnt.iondv.com:8888/rest/string-list
вернет объекты удовлетворяющие условию:
[{"__class":"class_string@develop-and-test",
"__classTitle":"Class \"String [0]\"",
"id":"66dbb3d0-5583-11e6-aef7-cf50314f026b",
"string_text":"Example of the \"String [0]\" type in the \"Text [1]\" view",
"string_miltilinetext":"Example of the \"String [0]\"\r\n in the Multiline text [7] view",
"string_formattext":"Example of the \r\n \"String [0]\" type \r\n in the \r\nFormatted text [7] view"}]
Пример регистрации тестового сервиса, подробнее см. Регистрация сервиса в конфигурации приложения
{
"modules": {
"rest": {
"globals": {
"di": {
"string-list": {
"module": "applications/develop-and-test/service/String-list",
"options": {
"stringClassName": "class_string@develop-and-test",
"dataRepo": "ion://dataRepo"
}
}
Для реализации обработки multipart запросов, например для запросов, содержащих файлы, можно использовать библиотеку multipart.js
(rest/backend/multipart.js
) модуля REST
. Пример реализации есть в сервисе CRUD
:
function reqToData(req) {
return multipart(req).then(data => data || req.body);
}
Этой цели также служит библиотека util.js
(rest/backend/util.js
), обеспечивающая корректность действий при работе с файлами и файловым хранилищем, пример из CRUD
:
reqToData(req)
.then(data => <util.js.>prepareUpdates(options, data, cm, req.params.id))
Регистрация сервиса в конфигурации приложения¶
Для подключения сервисов в приложении их необходимо сконфигурировать в глобальных настройках модуля rest в файле deploy.json приложения. Пример:
{
"modules": {
"rest": {
"globals": {
"di": {
"simple": {
"module": "applications/develop-and-test/service/SimpleRest"
},
"string-list": {
"module": "applications/develop-and-test/service/String-list",
"options": {
"stringClassName": "class_string@develop-and-test",
"dataRepo": "ion://dataRepo"
}
},
"crud": {
"module": "modules/rest/lib/impl/crud",
"options": {
"auth": "ion://auth",
"dataRepo": "ion://securedDataRepo"
}
}
Путь к регистрациям сервиса в файле deploy.json
- modules.rest.globals.di
. Далее указывается название сервиса, которое
будет доступно по адресу https://domain.com/rest/serviceName
, где serviceName - имя сервиса, указываемого в di, например
в примере выше simple
или string-list
.
В атрибуте module
указывается путь к js-файлу с обработчиком сервиса с путем относительно
корня фреймворка. Обработчик может быть как в приложении, так и в любом модуле или фреймворке, в т.ч. типовые обработчики модуля rest.
В параметре options
указываются специфические настройки сервиса.
Например, для сервиса crud указаны:
- в поле
dataRepo
- репозиторий данных с контролем доступа, используемый для операций над обьектами - в поле
auth
- компонент аутентификации, используемый для получения текущей учетной записи пользователя.
А для сервиса string-list указаны:
в поле
dataRepo
- репозиторий данных, используемый для выборки данныхв поле
stringClassName
- имя класса получаемых обьектов в данном случае классclass_string@develop-and-test
будет передан в методgetList
репозитория данныхoptions.dataRepo.getList(options.stringClassName, {})
Запросы к сервисам на примере тестов¶
Примеры запросов к основным сервисам REST можно найти в подготовленных для этих сервисов тестах. Тесты написаны для mocha и находятся в репозитории приложения iondv develop-and-test.
Для запуска тестов нужно установить пакеты request-promise-native
и mocha
,
например запустив npm install
в папке develop-and-test/test
.
Предварительно нужно сконфигурировать параметры сервера и пользователей в develop-and-test/test/modules/rest/config.js
.
Запуск осуществляется вызовом mocha/lib/cli/cli.js
для тестового скрипта, например:
node node_modules/mocha/lib/cli/cli.js modules/rest/echo.spec.js
Можно запустить все тесты в папке:
node node_modules/mocha/lib/cli/cli.js modules/rest/*.spec.js
Также возможен запуск отдельных юнит-тестов:
node node_modules/mocha/lib/cli/cli.js -g "<ЧАСТЬ НАЗВАНИЯ ТЕСТА>" modules/rest/*.spec.js
например:
node node_modules/mocha/lib/cli/cli.js -g "creating an object" modules/rest/*.spec.js
Модуль REST имеет несколько встроенных сервисов, предназначенных для реализации типовых операций с модулем:
- Сервис Acceptor - обеспечивает массовое создание объектов.
- Сервис Token - обеспечивает выдачу токена для авторизованного пользователя.
- Сервис CRUD - сервис CRUD для объектов системы.
- Cервис Meta - обеспечивает доступ к интерфейсу метаданных.
- Cервис Workflows - обеспечивает возможности контролировать и управлять бизнес-процессами.
Также поддерживается разработка и подключение пользовательских сервисов.
Разработка обработчика в приложении - подробнее.
Регистрация сервиса в конфигурации приложения - подробнее.
Модули - это независимые блоки с обязательной или дополнительной функциональностью, структура которых подчиняется определенным правилам.
Наименование | Описание |
---|---|
Registry | Ключевой модуль предназначенный непосредственно для работы с данными на основе структур метаданных. |
Report | Модуль предназначенный для формирования аналитических отчетов. |
Gantt-chart | Модуль для вывода данных с датами. |
Portal | Модуль для вывода произвольных шаблонов данных. |
Dashboard | Модуль предназначенный для выведения краткой информации в виде блоков. |
Ionadmin | Модуль администрирования для назначения прав. |
Account | Модуль личного кабинета, который формирует логику отображения. |
Soap | Модуль запросов к сервисам. |
Image-storage | Модуль предварительного просмотра картинок. |
REST | Модуль обеспечивающий работу с данными приложения IONDV через REST API. |
Функциональность IONDV. Framework и его модулей¶
IONDV. Framework¶
IONDV. Framework обеспечивает реализацию следующей функциональности:
- обеспечение трансляции описательных метаданных в структуру хранения данных в СУБД;
- обеспечение функциональности работы с различными СУБД (ORM технологию);
- обеспечение авторизации в системе с различными политиками, по умолчанию oath2, с открытым конфигурируемым API для подключения авторизационных модулей библиотеки passport обеспечивает до 500 различных политик авторизации;
- обеспечение безопасности доступа к данным – статической к типам данных, к навигации, к этапам бизнес-процессов, к действиям на форме; динамической – через условия в данных, которым должен соответствовать профиль текущего пользователя (принадлежность к подразделению или организации указанной в объекте, группе или другим условиям); через url; обеспечение исключения в авторизации и безопасности по url или для специального пользователя;
- подключение модулей, обеспечивающих дополнительную функциональность и реализуемую через доступ к интерфейсам (API) ядра;
- обеспечение импорта, экспорта данных в системе, метаданных, безопасности из файлов;
- обеспечение взаимодействия с файловой системой для хранения данных, в том числе с внешними файловыми хранилищами, такими как nextcloud;
- расчет значения с формулами и кэширование этих данных;
- обеспечение жадной загрузки данных и их фильтрации в связанных коллекциях;
- кэширование запросов и сессий в memcached, redis;
- выполнение задач по расписанию;
- уведомление пользователей по событиям.
Модули¶
Дополнительная функциональность, реализуется стандартными подключаемыми модулями.
Модуль учета данных registry:¶
- отображение навигации в иерархическом виде;
- отображение списков объектов данных по условиям навигации, фильтров, результатов поиска;
- возможность создания объектов;
- отображение унифицированных форм объектов с возможностью редактирования, удаления, изменения бизнес-процессов, реализации условия отображения и перегрузки представления формы по бизнес-процессу;
- отображение различных типов атрибутов, включая связанные в виде таблиц или ссылок, геообъектов (включая поиск координат по адресу);
- отображение данных по их семантике (условиям изменениям);
- возможность изменения отображения и взаимодействия с атрибутами объектов через кастомизированные HTML шаблоны, получающие данные по REST-API;
- подготовка печатных форм в формате docx и xlsx на основе списков или данных объектов;
- отображение уведомлений пользователей;
- возможность реализации собственных кнопок действий с серверной обработкой данных.
Модуль отчетности и аналитики - report:¶
- формирование выходных рассчитываемых форм, с возможностью фильтрации по значениям;
- фильтрация данных;
- математические операции над данными;
- pivot таблицы;
- REST API к данным отчетов.
Модуль представления данных с геокоординатами – geomap:¶
- реализация слоев данных с фильтрацией по условиям;
- возможность задавать иконки представления данных по типам данных;
- отображение всплывающего окошка с краткой информацией по объекту;
- отображение шаблона подробной информации по объекту;
- поиск объектов;
- фильтрация по произвольно указанной границе;
- районирование и фильтрация по границам районов;
- подключение данных модуля report, в том числе с расчетными данными по району.
Модули интеграции по REST и SOAP со стандартными API с учетом безопасности пользователя:¶
- различные настраиваемые типы авторизации: в заголовке, токен (включение сервис получение токена после авторизации в заголовке), без авторизации;
- получения списков объектов каждого типа с различными условиями фильтрации;
- сервис CRUD для любых типов данных;
- сервис переходов по этапам бизнес-процессов;
- сервис получения метаданных;
- возможность подключения произвольных собственных сервисов обработки.
Модуль дашбордов - dashboard:¶
- обеспечение формирования информационных блоков с цифровыми и графическими данными;
- позволяет настраивать несколько групп представлений и кастомизировать для каждого пользователя.
Модуль администрирования - ionadmin:¶
- обеспечивает ведение пользователей, прав и ролей, блокировку пользователей;
- формирование ключей безопасности (токенов) для интеграционных сервисов;
- мониторинг ключевых серверных ресурсов (с использованием модуля дашборд);
- анализ выполнения медленных запросов СУБД;
- настройку задач по расписанию;
- отслеживание изменений объектов системы;
- осуществление резервирования данных и метаданных;
- пересчет кешей семантики и формул;
- управление уведомлениями.
Модуль создания произвольных веб-страниц - portal:¶
- регистрацию произвольных страниц по адресу обработки (маршруту);
- регистрацию статического контента;
- управление безопасностью доступа;
- поддержку рендеринга страниц из шаблонов EJS.
Приложение IONDV. Studio для создания метаданных:¶
- создание навигации;
- создание структуры классов;
- создание представлений для классов;
- создание бизнес-процессов;
- базовая настройка приложения;
- экспорт и импорт метаданных;
- работа в стендалоне режиме с файлами проекта;
- работа онлайн с несколькими проектами, размещаемыми в хранилище браузера.
JS framework for rapid business application development
This page in English
IONDV. Framework¶
Описание¶
IONDV. Framework - это опенсорный фреймворк на node.js для разработки учетных приложений на основе метаданных в формате JSON/YAML и отдельных функциональных модулей. Визуальный редактор Studio позволяет создавать приложения по технологии «no code» и собирать приложение с веб-сервисами REST-API (модуль rest). Ключевой модуль registry является универсальным средством представления и редактирования данных, обработки их по бизнес-процессам.
На видео технология разработки и сборки приложения.
Бесплатные демоверсии¶
Посмотрите наши демо уже сейчас:
- Studio - специализированная IDE созданная как приложение iondv, для визуальной (no code) разработки приложений на IONDV. Framework. GitHub Репозиторий. Видео инструкция и текстовая по созданию приложения при помощи ION. Studio.
- Telecom - приложение по организации учета, хранения и отображения данных о наличии услуг связи (интернет, сотовая связь, телевидение, почта и др.) в населенных пукнтах региона. GitHub Repo
- DNT - приложение для разработки и тестирования функциональности фреймворка, в котором каждая учетная сущность отражает тим метаданных, например класс «строка», или класс «коллекция». Это позволяет изучать возможности фреймворка через приложение. GitHub Репозиторий.
- War Archive - это программное решение на основе IONDV. Framework, реализованное для действующего проекта «Вспомнить каждого», цель которого оцифровать архивные документы, внести информацию в базу и обеспечить к ним свободный доступ. GitHub Репозиторий.
- Project Management - приложение по организации проектной деятельности региональных ОГВ , целью которой является контроль результатов, соблюдение и сокращение сроков их достижения, эффективное использование временных, человеческих и финансовых ресурсов, принятие своевременных и обоснованных управленческих решений. GitHub Repo
- CRM - скоро на GitHub.
Логин для доступа - demo, пароль - ion-demo. Регистрация не требуется.
Типичные приложения¶
Фреймворк - конструктор веб-приложений любой специфики, так как преметная область определяется структурой метаданных, описывающих поведение приложение. Например можно создать приложения
- CRM - управления отношения с клиентами;
- учет и управление ресурсов предприятия;
- автоматизация бизнес-процессов организации и документооборота;
- сбор и хранение любых данных, например метрик оборудования (IoT);
- представление данных в виде порталов;
- REST-API для SPA приложений;
- REST-API и бекграунд для мобильных приложений;
Функциональные возможности¶
IONDV. Framework обеспечивает реализацию следующей функциональности:
- обеспечение трансляции описательных метаданных в структуру хранения данных в СУБД;
- обеспечение функциональности работы с различными СУБД (ORM технологию);
- обеспечение авторизации в системе с различными политиками, по умолчанию oath2, с открытым конфигурируемым API для подключения авторизационных модулей библиотеки passport обеспечивает до 500 различных политик авторизации;
- обеспечение безопасности доступа к данным – статической к типам данных, к навигации, к этапам бизнес-процессов, к действиям на форме; динамической – через условия в данных, которым должен соответствовать профиль текущего пользователя (принадлежность к подразделению или организации указанной в объекте, группе или другим условиям); через url; обеспечение исключения в авторизации и безопасности по url или для специального пользователя;
- подключение модулей, обеспечивающих дополнительную функциональность и реализуемую через доступ к интерфейсам (API) ядра;
- обеспечение импорта, экспорта данных в системе, метаданных, безопасности из файлов;
- обеспечение взаимодействия с файловой системой для хранения данных, в том числе с внешними файловыми хранилищами, такими как nextcloud;
- расчет значения с формулами и кэширование этих данных;
- обеспечение жадной загрузки данных и их фильтрации в связанных коллекциях;
- кэширование запросов и сессий в memcached, redis;
- выполнение задач по расписанию;
- уведомление пользователей по событиям.
Структура фреймворка: core + metadata + modules = application
На рискнуке:
- ioncore - ядро приложения в виде IONDV. фреймворка
- meta class, meta view, meta navigation, meta workflow, meta security - функциональные метаданные приложения - структуры, представления, навигации, бизнес-процессов и безопасности соответственно
- registry module - подлкючаемые функциональные модули, например модуль registry для просмотра и редактирования данных
Чуть ниже представлены дополнительные типы меты и модули. Они представляют собой дополнительную функциональность и применяются в соответствии с приложением. Зависимости приложения смотрим в файле package.json
.
Так как приложение - это метаописание его поведения в файлах формата JSON (YAML) и функциональный код и HTML шаблоны расширяющие типовую функциональность - то с ним удобно работать через репозиторий версий git. Посмотрите примеры на Github
Подробнее о функциональных возможностях фреймворка и его модулей можно узнать в документации.
Быстрый старт¶
Вы можете посмотреть собранные приложения, развернутые в облаке или получить продукты для изучения другим способом на сайте фреймворка, в том числе:
- инсталятор для операционной системы Linux
- клонирование репозитория приложения и установка всех компонентов (инструкция ниже)
- docker-контейнеры с собранными приложениями
Cистемное окружение¶
Запуск фреймворка осуществляется в среде Node.js версии 10.x.x.
Для хранения данных необходимо установить и запустить MongoDb версии старше 3.6.
Установщик¶
Для ускорения Вы можете использовать установщик приложений IONDV. Framework iondv-app, требующий установленных node, mongodb и git. В ходе установки будет проверены и установлены все остальные зависимости, а также собрано и запущено само приложение.
Установка в одну строку:
bash <(curl -sL https://raw.githubusercontent.com/iondv/iondv-app/master/iondv-app) -t git -q -i -m localhost:27017 develop-and-test
Где параметры для iondv-app localhost:27017
адрес MongoDB, а develop-and-test
название приложения. После запуска открыть ссылку „http://localhost:8888“, типовая учетная запись бек офиса demo, пароль ion-demo.
Дугой способ заключается в клонировании сборщика - (git clone https://github.com/iondv/iondv-app.git
) и установите приложение с помощью команды bash iondv-app -m localhost:27017 develop-and-test
.
Можно также собрать приложение в докер конейтнерах, тогда из окружения нужен только docker и СУБД mongodb в докер контейнере. Подробнее на странице сборщика приложения IONDV. Framework iondv-app
Сборка приложения из репозитория¶
Глобальные зависимости¶
Для сборки компонентов и библиотек фреймворка необходимо установить глобально:
- пакет node-gyp
npm install -g node-gyp
. Для работы библиотеки под операционной системой семейства windows дополнительно необходимо установить пакет windows-build-toolsnpm install -g --production windows-build-tools
. - пакет сборщика проектов Gulp
npm install -g gulp@4.0
.4.0
- поддерживаемая версияGulp
. - для версий IONDV. Framework 3.x.x и более ранних нужен менджер пакетов фронтенд библиотек Bower
npm install -g bower
. Для версия 4.х.х и старше не требуется.
Ручная установка ядра, модулей и приложения¶
Рассматриваем на примере приложения develop-and-test
. Находим приложение develop-and-test
в репозитории.
Смотрим зависимости указаные в файле package.json
.
"engines": {
"ion": "1.24.1"
},
"ionModulesDependencies": {
"registry": "1.27.1",
"geomap": "1.5.0",
"graph": "1.3.2",
"portal": "1.3.0",
"report": "1.9.2",
"ionadmin": "1.4.0",
"dashboard": "1.1.0",
"lk": "1.0.1",
"soap": "1.1.2",
"gantt-chart": "0.8.0"
},
"ionMetaDependencies": {
"viewlib": "0.9.1"
"viewlib-extra": "0.1.0"
- Начинаем установку с ядра, версия которого указана в парметре
"engines": {"ion": "1.24.1"}
. Скопируйте адрес репозитория ядра и в командной строке выполните коммандуgit clone https://github.com/iondv/framework
. Перейдите в папку ядра, переключитесь на tag номера версииgit checkout tags/v1.24.1
. Так как совместимость обеспечивается на уровне метаданных, а новые версии выпускались из-за изменения технологии сборки, то вы можете использовать последнии, например 4.0.0. - После этого устанавливаются необходимые для приложения модули, указанные в параметре
"ionModulesDependencies"
. Модули устанавливаются в папкуmodules
ядра, для этого перейдите в неё командойcd modules
. Клонируем модули из списка"ionModulesDependencies"
, для модуля registry это осуществляется коммандойgit clone https://github.com/iondv/registry
. Перейдите в папку установленного модуля, переключитесь на tag номера версииgit checkout tags/v1.27.1
. Повторите для каждого модуля. Для большинства приложений, можно использовать последние совместимые с ядром модули. - Установка самого приложения осуществляется в папку
applications
, для этого перейдите в неё командойcd ..\applications
, если вы находитесь в папке модулей. Установку выполните клонированием репозитория коммандойgit clone https://github.com/iondv/dnt_ru
. - После этого установите дополнительно необходимые приложения из параметра
"ionMetaDependencies"
. Установка осуществляется в папкуapplications
, для установки необходимо убедиться, что находитесь в папке приложений. Клонируем приложения из списка в параметре"ionMetaDependencies"
, для приложенияviewlib
осуществляется командойhttps://github.com/iondv/viewlib
. Перейдите в папку установленного приложения, переключитесь на tag номера версииgit checkout tags/v0.9.1
. Повторите для каждого приложения.
Сборка, конфигурирование и развертывание приложения¶
Сборка приложения обеспечивает установку всех зависимых библиотек, импорт данных в базу данных и подготовку приложения для запуска.
Создайте конфигурационный файл setup.ini
в папке config
куда вы клонировали фреймворк для задания основных параметров окружения приложения.
auth.denyTop=false
auth.registration=false
db.uri=mongodb://127.0.0.1:27017/db
server.ports[]=8888
module.default=registry
fs.storageRoot=./files
fs.urlBase=/files
Открываем файл в редакторе и вставляем содержимое. Самый главный параметр db.uri=mongodb://127.0.0.1:27017/ion-dnt
он указывает на название базы которую мы будем использовать для приложения. База данных будет создана автоматически.
Задайте переменную окружения NODE_PATH равной пути к ядру приложения следующей командой set NODE_PATH=c:\workspace\dnt
для Windows и export NODE_PATH=/workspace/dnt
для Linux, где workspace\dnt
- папка куда склонирован фреймворк.
При первом запуске необходимо выполнить npm install
- она поставит ключевые зависимости, в том числе локально сборщик gulp
.
Далее выполните команду сборки приложения gulp assemble
.
Если вы хотите выполнить импорт данных в вашем проекте, проверьте папку data
в приложении и выполните команду:
node bin/import-data --src ./applications/develop-and-test/data --ns develop-and-test
Добавьте пользователя admin с паролем 123 командой node bin\adduser.js --name admin --pwd 123
.
Добавьте пользователю права администратора командой node bin/acl.js --u admin@local --role admin --p full
.
Запуск¶
Запустите приложение командой в папке ядра npm start
или node bin\www
.
Откройте браузер с адресом http://localhost:8888
и авторизуйтесь в приложении, где 8888
- порт указанный в параметре server.ports конфигурации запуска.
Docker¶
Запуск приложения с использованием докер контейнера:
- Запустите СУБД mongodb:
docker run --name mongodb -v mongodb_data:/data/db -p 27017:27017 -d mongo
- Запустите IONDV. develop-and-test
docker run -d -p 80:8888 --link mongodb iondv/develop-and-test
. - Откройте ссылку
http://localhost
в браузере через минуту (время требуется для инициализации данных). Для авторизации используйте типовой логин: demo, пароль: ion-demo
Документация¶
Документация по платформе IONDV.Framework доступна на двух языках - русский и english.
Ссылки¶
Ниже представлены ссылки на дополнительную информацию по разработке приложений с использованием IONDV.Framework.
- Документация
- Домашняя страница фреймворка
- Обратная связь на Facebook
- Обучающие видеоролики на youtube
License Contact us English¶
Copyright (c) 2016-2020 LLC «ION DV».
All rights reserved.