initial commit
67
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,67 @@
|
||||||
|
#ignore target dir
|
||||||
|
target*/
|
||||||
|
|
||||||
|
#gradle files
|
||||||
|
.gradle*/
|
||||||
|
|
||||||
|
*.orig
|
||||||
|
#
|
||||||
|
# Eclipse project files
|
||||||
|
#
|
||||||
|
#.classpath
|
||||||
|
#.project
|
||||||
|
#.settings*/
|
||||||
|
.springBeans
|
||||||
|
.metadata/
|
||||||
|
war*/
|
||||||
|
|
||||||
|
#
|
||||||
|
# IntelliJ IDEA project files
|
||||||
|
#
|
||||||
|
.idea*/
|
||||||
|
.classes*/
|
||||||
|
*.ipr
|
||||||
|
*.iml
|
||||||
|
*.iws
|
||||||
|
*.ids
|
||||||
|
atlassian-ide-plugin.xml
|
||||||
|
|
||||||
|
#ignore NetBeans project files
|
||||||
|
nb-configuration.xml
|
||||||
|
profiles.xml
|
||||||
|
catalog.xml
|
||||||
|
nbactions.xml
|
||||||
|
|
||||||
|
#ignore some temporary files
|
||||||
|
*.vpp~*
|
||||||
|
|
||||||
|
# os meta files
|
||||||
|
Thumbs.db
|
||||||
|
.DS_Store
|
||||||
|
|
||||||
|
|
||||||
|
pom.xml.versionsBackup
|
||||||
|
*.jasper
|
||||||
|
|
||||||
|
#studio
|
||||||
|
.studio*/
|
||||||
|
|
||||||
|
resources/src/main/generated-resources*/
|
||||||
|
resources/src/main/resources/database/database_structure.xml
|
||||||
|
|
||||||
|
frontend/build*/
|
||||||
|
frontend/tmp*/
|
||||||
|
frontend/.angular*/
|
||||||
|
frontend/build_dev*/
|
||||||
|
frontend/dist*/
|
||||||
|
frontend/node_modules*/
|
||||||
|
frontend/src/ts/**/*.js
|
||||||
|
frontend/src/ts/**/*.js.map
|
||||||
|
frontend/src/ts/**/*.ngsummary.json
|
||||||
|
frontend/src/ts/aot*/
|
||||||
|
frontend/src/ts/generated*/
|
||||||
|
npm-debug.log
|
||||||
|
|
||||||
|
#Sublime project files
|
||||||
|
*.sublime-project
|
||||||
|
*.sublime-workspace
|
||||||
29
.studioignore
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
#Files for Webbpm-Studio to ignore
|
||||||
|
frontend/build/
|
||||||
|
frontend/build_dev/
|
||||||
|
frontend/dist/
|
||||||
|
frontend/node_modules/
|
||||||
|
frontend/src/ts/page.routing.ts
|
||||||
|
frontend/src/ts/generated-sources/
|
||||||
|
frontend/src/ts/generated/
|
||||||
|
frontend/target/
|
||||||
|
|
||||||
|
backend/target/
|
||||||
|
backend/src/main/generated-sources/
|
||||||
|
|
||||||
|
distribution/target/
|
||||||
|
|
||||||
|
resources/target/
|
||||||
|
|
||||||
|
test/
|
||||||
|
extensions/
|
||||||
|
|
||||||
|
config/
|
||||||
|
target/
|
||||||
|
themes/
|
||||||
|
|
||||||
|
.studio/
|
||||||
|
.git/
|
||||||
|
.idea/
|
||||||
|
.studioignore
|
||||||
|
**.js
|
||||||
224
README.md
Normal file
|
|
@ -0,0 +1,224 @@
|
||||||
|
# Создание БД проекта
|
||||||
|
|
||||||
|
Создание роли для основной схемы БД проекта
|
||||||
|
|
||||||
|
```
|
||||||
|
CREATE ROLE "<your-project-main-role>" WITH
|
||||||
|
LOGIN
|
||||||
|
NOSUPERUSER
|
||||||
|
INHERIT
|
||||||
|
NOCREATEDB
|
||||||
|
NOCREATEROLE
|
||||||
|
NOREPLICATION
|
||||||
|
PASSWORD '<your password>';
|
||||||
|
```
|
||||||
|
|
||||||
|
Создание роли для схемы безопасности БД проекта
|
||||||
|
|
||||||
|
```
|
||||||
|
CREATE ROLE "<your-project-security-role>" WITH
|
||||||
|
LOGIN
|
||||||
|
NOSUPERUSER
|
||||||
|
INHERIT
|
||||||
|
NOCREATEDB
|
||||||
|
NOCREATEROLE
|
||||||
|
NOREPLICATION
|
||||||
|
PASSWORD '<your password>';
|
||||||
|
```
|
||||||
|
|
||||||
|
Создание БД проекта
|
||||||
|
|
||||||
|
```
|
||||||
|
CREATE DATABASE "<your-project-db>"
|
||||||
|
WITH
|
||||||
|
OWNER = "<your-project-main-role>";
|
||||||
|
```
|
||||||
|
|
||||||
|
ВНИМАНИЕ: в общем случае, отдельную БД для безопасности создавать не нужно. В конфигурации источника данных security-ds в файле standalone.xml в качестве имени базы данных используйте базу данных приложения.
|
||||||
|
|
||||||
|
Предоставление необходимых прав для роли <your-project-security-role>
|
||||||
|
|
||||||
|
```
|
||||||
|
GRANT CREATE ON DATABASE "<your-project-db>" TO "<your-project-security-role>";
|
||||||
|
```
|
||||||
|
|
||||||
|
Создание таблицы shedlock для автосинхронизации
|
||||||
|
|
||||||
|
```
|
||||||
|
CREATE TABLE shedlock
|
||||||
|
(
|
||||||
|
name varchar not null
|
||||||
|
constraint tasks_lock_pkey
|
||||||
|
primary key,
|
||||||
|
lock_until timestamp,
|
||||||
|
locked_at timestamp,
|
||||||
|
locked_by varchar
|
||||||
|
);
|
||||||
|
|
||||||
|
comment on table shedlock is 'Таблица для синхронизации выполнения запланированных задач между нодами.';
|
||||||
|
|
||||||
|
ALTER TABLE shedlock
|
||||||
|
OWNER to "owner";
|
||||||
|
```
|
||||||
|
|
||||||
|
## Дополнительные ограничения базы секьюрити
|
||||||
|
|
||||||
|
Логин пользователя <user_account.username> и имена ролей <user_role.name> не должны совпадать, так как в ходе работы jbpm-а они сохраняются в одну и ту же таблицу.
|
||||||
|
Пример ошибки при совпадении: username = 'qa_test' и role_name = 'qa_test' (роль привязана к этому пользователю). Ошибка возникает при запуске любого процесса под этим пользователем.
|
||||||
|
|
||||||
|
```
|
||||||
|
ERROR [errorhandling.ExceptionHandlerController] (default task-5) [19usm9-bgyi63]
|
||||||
|
Organizational entity already exists with [GroupImpl:'qa_test'] id,
|
||||||
|
please check that there is no group and user with same id:
|
||||||
|
java.lang.RuntimeException: Organizational entity already exists with [GroupImpl:'qa_test'] id,
|
||||||
|
please check that there is no group and user with same id
|
||||||
|
```
|
||||||
|
|
||||||
|
## Создание нового администратора
|
||||||
|
|
||||||
|
Создайте группу <your-admin-group> и предоставьте ей права в модуль администрирования. Для этого выполните в БД проекта
|
||||||
|
|
||||||
|
```
|
||||||
|
INSERT INTO security.user_group(
|
||||||
|
user_group_id, name, access_level_id)
|
||||||
|
(SELECT uuid_in(md5(random()::text || clock_timestamp()::text)::cstring),
|
||||||
|
'<your-admin-group>', access_level_id FROM security.access_level where level=999);
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
INSERT INTO security.link_user_group_user_role(
|
||||||
|
link_user_group_user_role_id, user_group_id, user_role_id)
|
||||||
|
(SELECT uuid_in(md5(random()::text || clock_timestamp()::text)::cstring),
|
||||||
|
(SELECT user_group_id FROM security.user_group WHERE name = '<your-admin-group>'),
|
||||||
|
(SELECT user_role_id FROM security.user_role WHERE name = 'Security - User Admin'));
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
INSERT INTO security.link_user_group_user_role(
|
||||||
|
link_user_group_user_role_id, user_group_id, user_role_id)
|
||||||
|
(SELECT uuid_in(md5(random()::text || clock_timestamp()::text)::cstring),
|
||||||
|
(SELECT user_group_id FROM security.user_group WHERE name = '<your-admin-group>'),
|
||||||
|
(SELECT user_role_id FROM security.user_role WHERE name = 'Security - Group Admin'));
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
INSERT INTO security.link_user_group_user_role(
|
||||||
|
link_user_group_user_role_id, user_group_id, user_role_id)
|
||||||
|
(SELECT uuid_in(md5(random()::text || clock_timestamp()::text)::cstring),
|
||||||
|
(SELECT user_group_id FROM security.user_group WHERE name = '<your-admin-group>'),
|
||||||
|
(SELECT user_role_id FROM security.user_role WHERE name = 'Security - Role Admin'));
|
||||||
|
```
|
||||||
|
|
||||||
|
# Настройка браузера для входа в систему с помощью Kerberos
|
||||||
|
|
||||||
|
1. Запустите браузер firefox.
|
||||||
|
2. В адресной строке введите about:config, нажать кнопку "я принимаю на себя риск"
|
||||||
|
3. С помощью поиска найдите параметр network.negotiate-auth.trusted-uris и в качестве значения ввести домен(например для домена example.com надо ввести .example.com)
|
||||||
|
4. Откройте в браузере приложение. Пример http://app.example.com/ . Приложение должно открыться без запроса логина/пароля
|
||||||
|
|
||||||
|
# Восстановление структуры БД
|
||||||
|
|
||||||
|
На основе БД проекта с помощью jOOQ генерируются Java классы для каждого объекта БД. Это происходит по нажатию кнопки Обновить на панели БД в студии. При необходимости можно сформировать DDL на основе данных классов. Пример класса для генерации DDL
|
||||||
|
|
||||||
|
```
|
||||||
|
package ru.cg.webbpm.test_project.db_beans;
|
||||||
|
|
||||||
|
import org.jooq.*;
|
||||||
|
import org.jooq.impl.*;
|
||||||
|
|
||||||
|
public class Main {
|
||||||
|
public static void main (String args []) {
|
||||||
|
DefaultConfiguration defaultConfiguration = new DefaultConfiguration();
|
||||||
|
defaultConfiguration.setSQLDialect(SQLDialect.POSTGRES);
|
||||||
|
Queries ddl = DSL.using(defaultConfiguration).ddl(DefaultCatalog.DEFAULT_CATALOG);
|
||||||
|
|
||||||
|
for (Query query : ddl.queries()) {
|
||||||
|
System.out.println(query);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
** ВНИМАНИЕ: **
|
||||||
|
|
||||||
|
- этим способом нельзя восстановить функции/процедуры БД
|
||||||
|
|
||||||
|
см. также [https://www.jooq.org/doc/latest/manual/sql-building/ddl-statements/generating-ddl/](https://www.jooq.org/doc/latest/manual/sql-building/ddl-statements/generating-ddl/)
|
||||||
|
|
||||||
|
# Сборка проекта
|
||||||
|
## В dev режиме
|
||||||
|
```bash
|
||||||
|
mvn clean && mvn package
|
||||||
|
```
|
||||||
|
## В prod режиме
|
||||||
|
```bash
|
||||||
|
mvn clean && mvn package -Pprod -DngcCoreCount=4 -DpagePackSizeMb=24
|
||||||
|
```
|
||||||
|
ngcCoreCount - количество ядер, выделяемых процессу компиляции ngc. По умолчанию - количество ядер - 1
|
||||||
|
pagePackSizeMb - размер пачки в МБ. По умолчанию - количество ядер - 24 МБ.
|
||||||
|
|
||||||
|
## С обновлением database beans
|
||||||
|
```bash
|
||||||
|
mvn clean && mvn package -Dwebbpm.generate-db-beans
|
||||||
|
```
|
||||||
|
|
||||||
|
# Версия проекта
|
||||||
|
|
||||||
|
Если версия проекта содержит SNAPSHOT (например 1.0-SNAPSHOT), то при установке такой версии на сервере приложений будет запущена процедура остановки запущенных процессов данной версии. Этот режим удобен при отладке процесса на рабочем месте аналитика.
|
||||||
|
На боевом и тестовом стенде необходимо передавать дистрибутив проекта, с версией, которая не содержит SNAPSHOT. Например - 1.0
|
||||||
|
|
||||||
|
# Обновление платформы
|
||||||
|
|
||||||
|
## Обновления версии платформы
|
||||||
|
|
||||||
|
### С помощью студии
|
||||||
|
|
||||||
|
1. Откройте проект в студии. Версия платформы обновится автоматически
|
||||||
|
|
||||||
|
### Вручную
|
||||||
|
|
||||||
|
1. Обновите значение webbpm-platform.version в pom.xml. Пример
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<webbpm-platform.version>3.164.0-SNAPSHOT</webbpm-platform.version>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Обновление базового пакета компонент
|
||||||
|
|
||||||
|
### С помощью студии
|
||||||
|
|
||||||
|
1. Откройте проект в студии.
|
||||||
|
|
||||||
|
2. Откройте меню "Проект - Пакеты"
|
||||||
|
|
||||||
|
3. Нажмите обновить.
|
||||||
|
|
||||||
|
|
||||||
|
### Вручную
|
||||||
|
|
||||||
|
#### Из удаленного репозитория
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mvn webbpm:update-package -DpackageVersion="3.158.8"
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Из файла
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mvn webbpm:update-package -DexecuteNpmInstall=false -Dpath=resources-<your-version>.jar
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Руками
|
||||||
|
|
||||||
|
1. Измените версию платформы и backend модуля в файле [pom.xml](pom.xml) вашего проекта на нужную версию
|
||||||
|
2. Скопируйте ресурсы
|
||||||
|
```
|
||||||
|
из директории: webbpm-platform\components\resources\target\classes\
|
||||||
|
в директорию: {your-project}\packages\ru.cg.webbpm.packages.base.resources\
|
||||||
|
```
|
||||||
|
3. Скопируйте фронт
|
||||||
|
```
|
||||||
|
из директории: webbpm-platform\components\frontend\dist
|
||||||
|
в директорию: {your-project}\frontend\node_modules\@webbpm\base-package\
|
||||||
|
```
|
||||||
|
4. Запретите выполнение npm install при запуске студии. Для этого добавьте параметр `-DexecuteNpmInstall=false` в настройках Run/Debug Configurations студии
|
||||||
309
backend/pom.xml
Normal file
|
|
@ -0,0 +1,309 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<parent>
|
||||||
|
<groupId>ru.micord.ervu</groupId>
|
||||||
|
<artifactId>eks</artifactId>
|
||||||
|
<version>1.0.0-SNAPSHOT</version>
|
||||||
|
</parent>
|
||||||
|
<groupId>ru.micord.ervu.eks</groupId>
|
||||||
|
<artifactId>backend</artifactId>
|
||||||
|
<packaging>war</packaging>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.jsonwebtoken</groupId>
|
||||||
|
<artifactId>jjwt-api</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.jsonwebtoken</groupId>
|
||||||
|
<artifactId>jjwt-impl</artifactId>
|
||||||
|
<scope>runtime</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>ru.micord.ervu.eks</groupId>
|
||||||
|
<artifactId>resources</artifactId>
|
||||||
|
<scope>runtime</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>ru.cg.webbpm.modules.reporting.reporting-jasper</groupId>
|
||||||
|
<artifactId>reporting-jasper-fonts</artifactId>
|
||||||
|
<scope>runtime</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.ocpsoft.prettytime</groupId>
|
||||||
|
<artifactId>prettytime</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.jooq</groupId>
|
||||||
|
<artifactId>jooq</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>javax.servlet</groupId>
|
||||||
|
<artifactId>javax.servlet-api</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>slf4j-api</artifactId>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework</groupId>
|
||||||
|
<artifactId>spring-core</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework</groupId>
|
||||||
|
<artifactId>spring-context</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework</groupId>
|
||||||
|
<artifactId>spring-beans</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework</groupId>
|
||||||
|
<artifactId>spring-aop</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework</groupId>
|
||||||
|
<artifactId>spring-jdbc</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework</groupId>
|
||||||
|
<artifactId>spring-tx</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework</groupId>
|
||||||
|
<artifactId>spring-aspects</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework</groupId>
|
||||||
|
<artifactId>spring-web</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework</groupId>
|
||||||
|
<artifactId>spring-webmvc</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.security</groupId>
|
||||||
|
<artifactId>spring-security-web</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.security</groupId>
|
||||||
|
<artifactId>spring-security-config</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>ru.cg.webbpm.modules</groupId>
|
||||||
|
<artifactId>inject</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>ru.cg.webbpm.modules</groupId>
|
||||||
|
<artifactId>webkit-rpc</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>ru.cg.webbpm.modules</groupId>
|
||||||
|
<artifactId>webkit-beans</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>ru.cg.webbpm.modules.core</groupId>
|
||||||
|
<artifactId>core-runtime-api</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>ru.cg.webbpm.modules.resources</groupId>
|
||||||
|
<artifactId>resources-api</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>ru.cg.webbpm.modules.core</groupId>
|
||||||
|
<artifactId>error-handling-api</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>ru.cg.webbpm.modules.database</groupId>
|
||||||
|
<artifactId>database-api</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>ru.cg.webbpm.modules.database</groupId>
|
||||||
|
<artifactId>database-impl</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>ru.cg.webbpm.modules.jndi</groupId>
|
||||||
|
<artifactId>jndi-beans</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>ru.cg.webbpm.modules.jndi</groupId>
|
||||||
|
<artifactId>jndi-inject</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.sun.mail</groupId>
|
||||||
|
<artifactId>javax.mail</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>ru.cg.webbpm.modules.database</groupId>
|
||||||
|
<artifactId>database-test</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>ru.cg.webbpm.modules</groupId>
|
||||||
|
<artifactId>standard-annotations</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>ru.cg.webbpm.modules.security</groupId>
|
||||||
|
<artifactId>security-beans</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>ru.cg.webbpm.modules.security</groupId>
|
||||||
|
<artifactId>security-api</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>ru.cg.webbpm.modules.security</groupId>
|
||||||
|
<artifactId>security-esia</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>ru.cg.webbpm.modules.reporting</groupId>
|
||||||
|
<artifactId>reporting-api</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>ru.cg.webbpm.modules.reporting</groupId>
|
||||||
|
<artifactId>reporting-runtime-api</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>ru.cg.webbpm.modules.reporting</groupId>
|
||||||
|
<artifactId>reporting-runtime-impl</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>ru.cg.webbpm.modules.reporting.reporting-jasper</groupId>
|
||||||
|
<artifactId>reporting-jasper-impl</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>ru.cg.webbpm.modules.reporting.reporting-jasper</groupId>
|
||||||
|
<artifactId>reporting-jasper-runtime-impl</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>ru.cg.webbpm.modules.reporting.reporting-xdoc</groupId>
|
||||||
|
<artifactId>reporting-xdoc-impl</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>ru.cg.webbpm.modules.reporting.reporting-xdoc</groupId>
|
||||||
|
<artifactId>reporting-xdoc-runtime-impl</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.liquibase</groupId>
|
||||||
|
<artifactId>liquibase-core</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>ru.cg.webbpm.modules</groupId>
|
||||||
|
<artifactId>webkit-base</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>ru.cg.webbpm.modules.security</groupId>
|
||||||
|
<artifactId>security-db-synchronization-api</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>ru.cg.webbpm.modules.security</groupId>
|
||||||
|
<artifactId>security-db-synchronization-ldap-impl</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>xerces</groupId>
|
||||||
|
<artifactId>xercesImpl</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.google.guava</groupId>
|
||||||
|
<artifactId>guava</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>ru.micord.fias</groupId>
|
||||||
|
<artifactId>client</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.tika</groupId>
|
||||||
|
<artifactId>tika-core</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.security.kerberos</groupId>
|
||||||
|
<artifactId>spring-security-kerberos-core</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.security.kerberos</groupId>
|
||||||
|
<artifactId>spring-security-kerberos-web</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.bouncycastle</groupId>
|
||||||
|
<artifactId>bcprov-jdk15on</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.bouncycastle</groupId>
|
||||||
|
<artifactId>bcpkix-jdk15on</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>net.javacrumbs.shedlock</groupId>
|
||||||
|
<artifactId>shedlock-spring</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>net.javacrumbs.shedlock</groupId>
|
||||||
|
<artifactId>shedlock-provider-jdbc-template</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>ru.cg.webbpm.packages.base</groupId>
|
||||||
|
<artifactId>backend</artifactId>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<useIncrementalCompilation>false</useIncrementalCompilation>
|
||||||
|
<forceJavacCompilerUse>true</forceJavacCompilerUse>
|
||||||
|
<release>17</release>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.codehaus.mojo</groupId>
|
||||||
|
<artifactId>build-helper-maven-plugin</artifactId>
|
||||||
|
<version>3.2.0</version>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>add-source</id>
|
||||||
|
<phase>generate-sources</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>add-source</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<sources>
|
||||||
|
<source>${project.basedir}/target/generated-sources/java</source>
|
||||||
|
</sources>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
<profiles>
|
||||||
|
<profile>
|
||||||
|
<id>studio</id>
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<artifactId>maven-war-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<warName>${project.artifactId}</warName>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>ru.cg.webbpm.modules.resources</groupId>
|
||||||
|
<artifactId>resources-impl-development</artifactId>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</profile>
|
||||||
|
<profile>
|
||||||
|
<id>dev</id>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.postgresql</groupId>
|
||||||
|
<artifactId>postgresql</artifactId>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</profile>
|
||||||
|
</profiles>
|
||||||
|
</project>
|
||||||
92
backend/src/main/java/AppConfig.java
Normal file
|
|
@ -0,0 +1,92 @@
|
||||||
|
import net.javacrumbs.shedlock.core.LockProvider;
|
||||||
|
import net.javacrumbs.shedlock.provider.jdbctemplate.JdbcTemplateLockProvider;
|
||||||
|
import net.javacrumbs.shedlock.spring.ScheduledLockConfiguration;
|
||||||
|
import net.javacrumbs.shedlock.spring.ScheduledLockConfigurationBuilder;
|
||||||
|
import org.apache.http.client.config.RequestConfig;
|
||||||
|
import org.apache.http.impl.client.CloseableHttpClient;
|
||||||
|
import org.apache.http.impl.client.HttpClients;
|
||||||
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.ComponentScan;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.context.annotation.EnableAspectJAutoProxy;
|
||||||
|
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
|
||||||
|
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
|
||||||
|
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||||
|
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
|
||||||
|
import org.springframework.web.client.RestTemplate;
|
||||||
|
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
|
||||||
|
|
||||||
|
import javax.sql.DataSource;
|
||||||
|
import java.time.Duration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Root application context
|
||||||
|
* This context imports XML configs from all the other jars, and is created by {@link WebAppInitializer}
|
||||||
|
* NB: modules are excluded from component scan since spring-context.xml sometimes holds important parameters and / or annotations
|
||||||
|
* @author krylov
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
@ComponentScan(basePackages = {
|
||||||
|
"service",
|
||||||
|
"dao",
|
||||||
|
"bpmn",
|
||||||
|
"i18n",
|
||||||
|
"errorhandling",
|
||||||
|
"database",
|
||||||
|
"security",
|
||||||
|
"component.addresses",
|
||||||
|
"gen",
|
||||||
|
"ru.cg",
|
||||||
|
"ru.micord"
|
||||||
|
})
|
||||||
|
@EnableAspectJAutoProxy(proxyTargetClass = true)
|
||||||
|
@EnableWebMvc
|
||||||
|
@EnableScheduling
|
||||||
|
public class AppConfig {
|
||||||
|
|
||||||
|
@Value("${config.data.executor.socket.timeout:10}")
|
||||||
|
private int socketTimeout;
|
||||||
|
@Value("${config.data.executor.connection.timeout:10}")
|
||||||
|
private int connectionTimeout;
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer(){
|
||||||
|
return new PropertySourcesPlaceholderConfigurer();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public ScheduledLockConfiguration taskScheduler(LockProvider lockProvider) {
|
||||||
|
ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
|
||||||
|
scheduler.setPoolSize(12);
|
||||||
|
scheduler.initialize();
|
||||||
|
return ScheduledLockConfigurationBuilder
|
||||||
|
.withLockProvider(lockProvider)
|
||||||
|
.withTaskScheduler(scheduler)
|
||||||
|
.withDefaultLockAtMostFor(Duration.ofHours(4))
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public LockProvider lockProvider(@Qualifier("datasource") DataSource dataSource) {
|
||||||
|
return new JdbcTemplateLockProvider(dataSource);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public RestTemplate restTemplate() {
|
||||||
|
RequestConfig requestConfig = RequestConfig.custom()
|
||||||
|
.setSocketTimeout(socketTimeout * 1000)
|
||||||
|
.setConnectionRequestTimeout(connectionTimeout * 1000)
|
||||||
|
.setConnectTimeout(connectionTimeout * 1000)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
CloseableHttpClient httpClient = HttpClients.custom()
|
||||||
|
.setDefaultRequestConfig(requestConfig)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(httpClient);
|
||||||
|
|
||||||
|
return new RestTemplate(factory);
|
||||||
|
}
|
||||||
|
}
|
||||||
31
backend/src/main/java/WebAppInitializer.java
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
import javax.servlet.ServletContext;
|
||||||
|
import javax.servlet.ServletException;
|
||||||
|
|
||||||
|
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
|
||||||
|
import org.springframework.web.util.IntrospectorCleanupListener;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This initializer creates root context and registers dispatcher servlet
|
||||||
|
* Spring scans for initializers automatically
|
||||||
|
*/
|
||||||
|
public class WebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
|
||||||
|
|
||||||
|
public void onStartup(ServletContext servletContext) throws ServletException {
|
||||||
|
super.onStartup(servletContext);
|
||||||
|
servletContext.addListener(new IntrospectorCleanupListener());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String[] getServletMappings() {
|
||||||
|
return new String[]{"/"};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Class<?>[] getRootConfigClasses() {
|
||||||
|
return new Class[]{AppConfig.class};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Class<?>[] getServletConfigClasses() {
|
||||||
|
return new Class[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
24
backend/src/main/java/dto/ExportDataRequest.java
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
package dto;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class ExportDataRequest {
|
||||||
|
public String type;
|
||||||
|
public List<String> ids;
|
||||||
|
|
||||||
|
public String getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setType(String type) {
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getIds() {
|
||||||
|
return ids;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIds(List<String> ids) {
|
||||||
|
this.ids = ids;
|
||||||
|
}
|
||||||
|
}
|
||||||
27
backend/src/main/java/rpc/ConfigExecutorRpcService.java
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
package rpc;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import ru.cg.webbpm.modules.webkit.annotations.RpcCall;
|
||||||
|
import ru.cg.webbpm.modules.webkit.annotations.RpcService;
|
||||||
|
import ru.cg.webbpm.modules.webkit.beans.Behavior;
|
||||||
|
import service.ConfigExecutorService;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Evgenii Malkov
|
||||||
|
*/
|
||||||
|
@RpcService
|
||||||
|
public class ConfigExecutorRpcService extends Behavior {
|
||||||
|
|
||||||
|
private final ConfigExecutorService configExecutorService;
|
||||||
|
|
||||||
|
public ConfigExecutorRpcService(@Autowired ConfigExecutorService configExecutorService) {
|
||||||
|
this.configExecutorService = configExecutorService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@RpcCall
|
||||||
|
public void callConfigExecutor(String methodPath, List<String> ids) {
|
||||||
|
configExecutorService.call(methodPath, ids);
|
||||||
|
}
|
||||||
|
}
|
||||||
30
backend/src/main/java/rpc/ExportDataRpcService.java
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
package rpc;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import dto.ExportDataRequest;
|
||||||
|
import model.FileModel;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import service.ConfigExecutorService;
|
||||||
|
|
||||||
|
import ru.cg.webbpm.modules.webkit.annotations.RpcCall;
|
||||||
|
import ru.cg.webbpm.modules.webkit.annotations.RpcService;
|
||||||
|
import ru.cg.webbpm.modules.webkit.beans.Behavior;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author kochetkov
|
||||||
|
*/
|
||||||
|
@RpcService
|
||||||
|
public class ExportDataRpcService extends Behavior {
|
||||||
|
|
||||||
|
private final ConfigExecutorService configExecutorService;
|
||||||
|
|
||||||
|
public ExportDataRpcService(@Autowired ConfigExecutorService configExecutorService) {
|
||||||
|
this.configExecutorService = configExecutorService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@RpcCall
|
||||||
|
public FileModel exportData(ExportDataRequest request) {
|
||||||
|
return configExecutorService.exportData(request);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,169 @@
|
||||||
|
package ru.micord.ervu_eks.component.service;
|
||||||
|
|
||||||
|
import java.sql.Array;
|
||||||
|
import java.sql.Connection;
|
||||||
|
import java.sql.PreparedStatement;
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
import java.sql.ResultSetMetaData;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import bpmn.handler.sql_handler.SQLHandlerUtils;
|
||||||
|
import bpmn.handler.sql_handler.SQLParameters;
|
||||||
|
import org.jooq.DSLContext;
|
||||||
|
import org.jooq.Record;
|
||||||
|
import org.jooq.Result;
|
||||||
|
import org.jooq.exception.DataAccessException;
|
||||||
|
import org.jooq.impl.DefaultDataType;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import service.button.sql.ExecuteSqlButtonService;
|
||||||
|
import utils.SqlQueryUtils;
|
||||||
|
|
||||||
|
import ru.cg.webbpm.modules.core.runtime.api.context.ExecutionContextHelper;
|
||||||
|
import ru.cg.webbpm.modules.database.api.provider.DslProvider;
|
||||||
|
import ru.cg.webbpm.modules.standard_annotations.editor.TextAreaEditor;
|
||||||
|
import ru.cg.webbpm.modules.standard_annotations.validation.NotNull;
|
||||||
|
|
||||||
|
public class ReadOnlySqlButtonServiceImpl implements ExecuteSqlButtonService {
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(ReadOnlySqlButtonServiceImpl.class);
|
||||||
|
@Autowired
|
||||||
|
private DslProvider dslProvider;
|
||||||
|
@Autowired
|
||||||
|
protected ExecutionContextHelper executionContextHelper;
|
||||||
|
private DSLContext dsl;
|
||||||
|
@TextAreaEditor
|
||||||
|
@NotNull
|
||||||
|
public String sql;
|
||||||
|
public String jndiName;
|
||||||
|
|
||||||
|
public void initDsl() {
|
||||||
|
|
||||||
|
if (dsl != null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
dsl = this.dslProvider.getDslContext(jndiName);
|
||||||
|
if (dsl == null) {
|
||||||
|
throw new RuntimeException("Couldn't get dslContext with datasourceJndiName = " + jndiName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<?> executeSql(Object[] params) {
|
||||||
|
initDsl();
|
||||||
|
SQLParameters parameters = new SQLParameters();
|
||||||
|
parameters.setSql(sql);
|
||||||
|
parameters.setSqlParameters(params);
|
||||||
|
|
||||||
|
return switch (SqlQueryUtils.queryType(sql)) {
|
||||||
|
case SELECT -> executeSelect(parameters);
|
||||||
|
case UNKNOWN -> executeUnknownQuery(parameters);
|
||||||
|
default -> Collections.EMPTY_LIST;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<?> executeSelect(SQLParameters parameters) {
|
||||||
|
Result<Record> result = executeSelectRaw(parameters);
|
||||||
|
|
||||||
|
if (result.size() > 1) {
|
||||||
|
String message = String.format("Query \"%s\" with arguments %s returned more than one row.",
|
||||||
|
parameters.getSql(), Arrays.toString(parameters.getSqlParameters())
|
||||||
|
);
|
||||||
|
throw new IllegalStateException(message);
|
||||||
|
}
|
||||||
|
Record row = result.get(0);
|
||||||
|
List<Object> results = new ArrayList<>();
|
||||||
|
|
||||||
|
for (int i = 0;
|
||||||
|
i < row.size();
|
||||||
|
i++) {
|
||||||
|
results.add(row.getValue(i));
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<?> executeUnknownQuery(SQLParameters parameters) {
|
||||||
|
// jooq does not provide any way to get generated keys for sql queries
|
||||||
|
Connection connection = dsl.configuration().connectionProvider().acquire();
|
||||||
|
try (PreparedStatement statement = connection.prepareStatement(parameters.getSql())) {
|
||||||
|
setParameters(statement, parameters, connection);
|
||||||
|
|
||||||
|
String query = dsl.renderInlined(
|
||||||
|
dsl.query(parameters.getSql(), parameters.getSqlParameters()));
|
||||||
|
String executionContext =
|
||||||
|
"\n with Execution Context: \n" + executionContextHelper.getExecutionContext();
|
||||||
|
logger.debug("Executing query " + query + executionContext);
|
||||||
|
|
||||||
|
statement.execute();
|
||||||
|
ResultSet resultSet = statement.getResultSet();
|
||||||
|
|
||||||
|
if (resultSet != null) {
|
||||||
|
List<Object> results = new ArrayList<>();
|
||||||
|
ResultSetMetaData metaData = resultSet.getMetaData();
|
||||||
|
while (resultSet.next()) {
|
||||||
|
Object[] row = new Object[metaData.getColumnCount()];
|
||||||
|
for (int i = 0;
|
||||||
|
i < metaData.getColumnCount();
|
||||||
|
i++) {
|
||||||
|
row[i] = resultSet.getObject(i + 1);
|
||||||
|
}
|
||||||
|
results.add(row);
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (SQLException e) {
|
||||||
|
StringBuilder sb = new StringBuilder("Failed to execute SQL query. SQL: \"").append(
|
||||||
|
parameters.getSql()).append("\"");
|
||||||
|
if (parameters.getSqlParameters() != null && parameters.getSqlParameters().length > 0) {
|
||||||
|
String parametersStr = Arrays.toString(parameters.getSqlParameters());
|
||||||
|
sb.append(", with parameters: ").append(parametersStr);
|
||||||
|
}
|
||||||
|
throw new DataAccessException(sb.toString(), e);
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
dsl.configuration().connectionProvider().release(connection);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setParameters(PreparedStatement statement, SQLParameters parameters,
|
||||||
|
Connection connection) throws SQLException {
|
||||||
|
for (int i = 0;
|
||||||
|
i < parameters.getSqlParameters().length;
|
||||||
|
i++) {
|
||||||
|
Object parameter = parameters.getSqlParameters()[i];
|
||||||
|
if (parameter == null) {
|
||||||
|
// Also documentation states that it's better to use setNull method
|
||||||
|
// because not all databases support setObject with null value but
|
||||||
|
// in practice we don't know parameter type and the only sql type left
|
||||||
|
// for setNull method argument is java.sql.Types.NULL, which is not
|
||||||
|
// supported by all databases as well.
|
||||||
|
statement.setObject(i + 1, null);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (SQLHandlerUtils.isArrayExceptBytesArray(parameter)) {
|
||||||
|
Object[] castParameter = (Object[]) parameter;
|
||||||
|
org.jooq.SQLDialect dialect = dsl.configuration().dialect();
|
||||||
|
String typeName = DefaultDataType.getDataType(dialect,
|
||||||
|
castParameter.getClass().getComponentType()
|
||||||
|
).getTypeName();
|
||||||
|
Array arrayOf = connection.createArrayOf(typeName, castParameter);
|
||||||
|
statement.setArray(i + 1, arrayOf);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
statement.setObject(i + 1, parameter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Result<Record> executeSelectRaw(SQLParameters parameters) {
|
||||||
|
return dsl.resultQuery(parameters.getSql(), parameters.getSqlParameters()).fetch();
|
||||||
|
}
|
||||||
|
}
|
||||||
88
backend/src/main/java/service/ConfigExecutorService.java
Normal file
|
|
@ -0,0 +1,88 @@
|
||||||
|
package service;
|
||||||
|
|
||||||
|
import java.lang.invoke.MethodHandles;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Base64;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
import dto.ExportDataRequest;
|
||||||
|
import model.FileModel;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.http.HttpEntity;
|
||||||
|
import org.springframework.http.HttpHeaders;
|
||||||
|
import org.springframework.http.HttpMethod;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.web.client.RestTemplate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Evgenii Malkov
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public class ConfigExecutorService {
|
||||||
|
|
||||||
|
private static final Logger LOGGER = LoggerFactory.getLogger(
|
||||||
|
MethodHandles.lookup().lookupClass());
|
||||||
|
private final RestTemplate restTemplate;
|
||||||
|
private final String url;
|
||||||
|
|
||||||
|
public ConfigExecutorService(@Autowired RestTemplate restTemplate,
|
||||||
|
@Value("${config.data.executor.url}") String url) {
|
||||||
|
this.restTemplate = restTemplate;
|
||||||
|
this.url = url;
|
||||||
|
}
|
||||||
|
|
||||||
|
public FileModel exportData(ExportDataRequest request) {
|
||||||
|
HttpHeaders headers = new HttpHeaders();
|
||||||
|
HttpEntity<ExportDataRequest> entity = new HttpEntity<>(request, headers);
|
||||||
|
|
||||||
|
ResponseEntity<byte[]> response = restTemplate.exchange(
|
||||||
|
url.concat("/").concat("downloadCSV"),
|
||||||
|
HttpMethod.POST, entity, byte[].class
|
||||||
|
);
|
||||||
|
|
||||||
|
String content = Base64.getEncoder().encodeToString(response.getBody());
|
||||||
|
FileModel fileModel = new FileModel();
|
||||||
|
fileModel.setFileContent(content);
|
||||||
|
fileModel.setFileExtension(".csv");
|
||||||
|
fileModel.setFileName(
|
||||||
|
request.getType() + "_" + new SimpleDateFormat("dd.MM.yyyy").format(new Date()) + ".csv");
|
||||||
|
return fileModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void call(String methodPath, List<String> ids) {
|
||||||
|
HttpHeaders headers = new HttpHeaders();
|
||||||
|
headers.setContentType(MediaType.APPLICATION_JSON);
|
||||||
|
HttpEntity<List<String>> entity = new HttpEntity<>(ids, headers);
|
||||||
|
LOGGER.info("Starts call config executor service with method: {}, for ids: {}", methodPath,
|
||||||
|
ids
|
||||||
|
);
|
||||||
|
try {
|
||||||
|
ResponseEntity<Object> response = restTemplate.exchange(url.concat(methodPath),
|
||||||
|
HttpMethod.POST, entity, Object.class
|
||||||
|
);
|
||||||
|
LOGGER.info("Method: {}, executed with status: {}, for ids:{}", methodPath,
|
||||||
|
response.getStatusCode().value(), ids
|
||||||
|
);
|
||||||
|
}
|
||||||
|
catch (Exception e) {
|
||||||
|
throw new RuntimeException(
|
||||||
|
String.format("Failed call config executor service method: %s for ids: %s with error",
|
||||||
|
methodPath, ids
|
||||||
|
), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getExportDataIds() {
|
||||||
|
ResponseEntity<String[]> listDownloadTypes = restTemplate.getForEntity(
|
||||||
|
url.concat("/").concat("listDownloadTypes"), String[].class);
|
||||||
|
return Arrays.stream(Objects.requireNonNull(listDownloadTypes.getBody())).toList();
|
||||||
|
}
|
||||||
|
}
|
||||||
35
backend/src/main/java/service/DataTypeComboBoxService.java
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
package service;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import model.ComboBoxModel;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import service.field.ComboBoxService;
|
||||||
|
|
||||||
|
public class DataTypeComboBoxService implements ComboBoxService {
|
||||||
|
@Autowired
|
||||||
|
private ConfigExecutorService configExecutorService;
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ComboBoxModel> loadData() {
|
||||||
|
return configExecutorService.getExportDataIds().stream().sorted().map(s -> new ComboBoxModel(s, s, s, true)).toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ComboBoxModel loadModelWithoutGraphConditions(Object id, Object parentValue) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ComboBoxModel> loadDataWithFilter(Object filterValue) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ComboBoxModel> loadDataByParentValueWithFilter(Object parentValue,
|
||||||
|
Object filterValue) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
}
|
||||||
0
backend/src/main/resources/.gitkeep
Normal file
38
config-data-executor/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
target/
|
||||||
|
!.mvn/wrapper/maven-wrapper.jar
|
||||||
|
!**/src/main/**/target/
|
||||||
|
!**/src/test/**/target/
|
||||||
|
|
||||||
|
### IntelliJ IDEA ###
|
||||||
|
.idea/modules.xml
|
||||||
|
.idea/jarRepositories.xml
|
||||||
|
.idea/compiler.xml
|
||||||
|
.idea/libraries/
|
||||||
|
*.iws
|
||||||
|
*.iml
|
||||||
|
*.ipr
|
||||||
|
|
||||||
|
### Eclipse ###
|
||||||
|
.apt_generated
|
||||||
|
.classpath
|
||||||
|
.factorypath
|
||||||
|
.project
|
||||||
|
.settings
|
||||||
|
.springBeans
|
||||||
|
.sts4-cache
|
||||||
|
|
||||||
|
### NetBeans ###
|
||||||
|
/nbproject/private/
|
||||||
|
/nbbuild/
|
||||||
|
/dist/
|
||||||
|
/nbdist/
|
||||||
|
/.nb-gradle/
|
||||||
|
build/
|
||||||
|
!**/src/main/**/build/
|
||||||
|
!**/src/test/**/build/
|
||||||
|
|
||||||
|
### VS Code ###
|
||||||
|
.vscode/
|
||||||
|
|
||||||
|
### Mac OS ###
|
||||||
|
.DS_Store
|
||||||
4
config-data-executor/Dockerfile
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
FROM bellsoft/liberica-openjdk-alpine:17-cds
|
||||||
|
COPY target/*.jar app.jar
|
||||||
|
|
||||||
|
CMD ["java", "-jar", "app.jar"]
|
||||||
114
config-data-executor/pom.xml
Normal file
|
|
@ -0,0 +1,114 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<parent>
|
||||||
|
<groupId>ru.micord.ervu</groupId>
|
||||||
|
<artifactId>eks</artifactId>
|
||||||
|
<version>1.0.0-SNAPSHOT</version>
|
||||||
|
</parent>
|
||||||
|
<groupId>ru.micord.ervu.eks</groupId>
|
||||||
|
<artifactId>config-data-executor</artifactId>
|
||||||
|
<packaging>war</packaging>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<maven.compiler.source>17</maven.compiler.source>
|
||||||
|
<maven.compiler.target>17</maven.compiler.target>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<dependencyManagement>
|
||||||
|
<dependencies>
|
||||||
|
</dependencies>
|
||||||
|
</dependencyManagement>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-web</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework</groupId>
|
||||||
|
<artifactId>spring-tx</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.atomikos</groupId>
|
||||||
|
<artifactId>transactions-jta</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.atomikos</groupId>
|
||||||
|
<artifactId>transactions-jdbc</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>javax.transaction</groupId>
|
||||||
|
<artifactId>javax.transaction-api</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.postgresql</groupId>
|
||||||
|
<artifactId>postgresql</artifactId>
|
||||||
|
<scope>runtime</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.projectlombok</groupId>
|
||||||
|
<artifactId>lombok</artifactId>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>jakarta.xml.bind</groupId>
|
||||||
|
<artifactId>jakarta.xml.bind-api</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.sun.xml.bind</groupId>
|
||||||
|
<artifactId>jaxb-impl</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.arangodb</groupId>
|
||||||
|
<artifactId>arangodb-java-driver</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.amazonaws</groupId>
|
||||||
|
<artifactId>aws-java-sdk-s3</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>javax.servlet</groupId>
|
||||||
|
<artifactId>javax.servlet-api</artifactId>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
<repositories>
|
||||||
|
<repository>
|
||||||
|
<id>maven_central</id>
|
||||||
|
<name>Maven Central</name>
|
||||||
|
<url>https://repo.maven.apache.org/maven2/</url>
|
||||||
|
</repository>
|
||||||
|
</repositories>
|
||||||
|
<build>
|
||||||
|
<finalName>${artifactId}</finalName>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-war-plugin</artifactId>
|
||||||
|
<version>3.1.0</version>
|
||||||
|
<configuration>
|
||||||
|
<failOnMissingWebXml>false</failOnMissingWebXml>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||||
|
<version>2.7.18</version>
|
||||||
|
<configuration>
|
||||||
|
<mainClass>org.micord.Main</mainClass>
|
||||||
|
</configuration>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<goals>
|
||||||
|
<goal>repackage</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
</project>
|
||||||
15
config-data-executor/src/main/java/org/micord/Main.java
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
package org.micord;
|
||||||
|
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Maksim Tereshin
|
||||||
|
*/
|
||||||
|
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
|
||||||
|
public class Main {
|
||||||
|
public static void main(String[] args) {
|
||||||
|
SpringApplication.run(Main.class, args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
package org.micord;
|
||||||
|
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
|
||||||
|
|
||||||
|
@SpringBootApplication
|
||||||
|
public class SpringBootTomcatApplication extends SpringBootServletInitializer {
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,34 @@
|
||||||
|
package org.micord.config;
|
||||||
|
|
||||||
|
import com.arangodb.ArangoDB;
|
||||||
|
import com.arangodb.ArangoDBException;
|
||||||
|
import com.arangodb.ArangoDatabase;
|
||||||
|
import org.micord.models.AqlConnectionParams;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Maksim Tereshin
|
||||||
|
*/
|
||||||
|
public class ArangoDBConnection {
|
||||||
|
|
||||||
|
public static ArangoDatabase getConnection(AqlConnectionParams params) {
|
||||||
|
try {
|
||||||
|
ArangoDB arangoDB = new ArangoDB.Builder()
|
||||||
|
.host(params.getHost(), params.getPort())
|
||||||
|
.user(params.getUsername())
|
||||||
|
.password(params.getPassword())
|
||||||
|
.build();
|
||||||
|
|
||||||
|
ArangoDatabase db = arangoDB.db(params.getDatabase());
|
||||||
|
|
||||||
|
if (!db.exists()) {
|
||||||
|
throw new ArangoDBException("Database does not exist: " + params.getDatabase());
|
||||||
|
}
|
||||||
|
|
||||||
|
return db;
|
||||||
|
|
||||||
|
} catch (ArangoDBException e) {
|
||||||
|
throw new RuntimeException("Failed to connect to ArangoDB", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,39 @@
|
||||||
|
package org.micord.config;
|
||||||
|
|
||||||
|
import com.atomikos.icatch.jta.UserTransactionImp;
|
||||||
|
import com.atomikos.icatch.jta.UserTransactionManager;
|
||||||
|
import javax.transaction.TransactionManager;
|
||||||
|
import javax.transaction.UserTransaction;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||||
|
import org.springframework.transaction.jta.JtaTransactionManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Maksim Tereshin
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
@EnableTransactionManagement
|
||||||
|
public class AtomikosConfig {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public UserTransaction userTransaction() throws Throwable {
|
||||||
|
UserTransactionImp userTransactionImp = new UserTransactionImp();
|
||||||
|
userTransactionImp.setTransactionTimeout(300);
|
||||||
|
return userTransactionImp;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public TransactionManager atomikosTransactionManager() {
|
||||||
|
UserTransactionManager userTransactionManager = new UserTransactionManager();
|
||||||
|
userTransactionManager.setForceShutdown(true);
|
||||||
|
return userTransactionManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public JtaTransactionManager transactionManager() throws Throwable {
|
||||||
|
return new JtaTransactionManager(userTransaction(), atomikosTransactionManager());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,67 @@
|
||||||
|
package org.micord.config;
|
||||||
|
|
||||||
|
import com.atomikos.jdbc.AtomikosDataSourceBean;
|
||||||
|
import org.micord.models.SqlConnectionParams;
|
||||||
|
|
||||||
|
import javax.sql.DataSource;
|
||||||
|
import java.sql.Connection;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Maksim Tereshin
|
||||||
|
*/
|
||||||
|
public class DatabaseConnection {
|
||||||
|
|
||||||
|
private static final Map<String, DataSource> dataSources = new HashMap<>();
|
||||||
|
|
||||||
|
public static Connection getConnection(SqlConnectionParams params) throws SQLException {
|
||||||
|
try {
|
||||||
|
Class.forName(params.getJdbcDriverClassName());
|
||||||
|
} catch (ClassNotFoundException e) {
|
||||||
|
throw new SQLException("Unable to load the JDBC driver class", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return getXaDataSource(params).getConnection();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DataSource getXaDataSource(SqlConnectionParams params) {
|
||||||
|
String database = params.getJdbcDatabase();
|
||||||
|
|
||||||
|
if (!dataSources.containsKey(database)) {
|
||||||
|
AtomikosDataSourceBean xaDataSource = new AtomikosDataSourceBean();
|
||||||
|
xaDataSource.setUniqueResourceName("jdbcDatasource_" + database);
|
||||||
|
xaDataSource.setXaDataSourceClassName(params.getJdbcXaDataSourceClassName());
|
||||||
|
xaDataSource.setPoolSize(Integer.parseInt(params.getJdbcXaDataSourcePoolSize()));
|
||||||
|
|
||||||
|
if (params.getJdbcXaDataSourceBorrowConnectionTimeout() != null) {
|
||||||
|
xaDataSource.setBorrowConnectionTimeout(Integer.parseInt(params.getJdbcXaDataSourceBorrowConnectionTimeout()));
|
||||||
|
}
|
||||||
|
|
||||||
|
Properties xaProperties = loadDatabaseProperties(params);
|
||||||
|
xaDataSource.setXaProperties(xaProperties);
|
||||||
|
|
||||||
|
dataSources.put(database, xaDataSource);
|
||||||
|
}
|
||||||
|
|
||||||
|
return dataSources.get(database);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Properties loadDatabaseProperties(SqlConnectionParams params) {
|
||||||
|
Properties xaProperties = new Properties();
|
||||||
|
try {
|
||||||
|
xaProperties.setProperty("user", params.getJdbcUsername());
|
||||||
|
xaProperties.setProperty("password", params.getJdbcPassword());
|
||||||
|
xaProperties.setProperty("serverName", params.getJdbcHost());
|
||||||
|
xaProperties.setProperty("portNumber", String.valueOf(params.getJdbcPort()));
|
||||||
|
xaProperties.setProperty("databaseName", params.getJdbcDatabase());
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException("Failed to load database properties", e);
|
||||||
|
}
|
||||||
|
return xaProperties;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
package org.micord.config;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
import java.net.http.HttpClient;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Maksim Tereshin
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
public class HttpClientConfig {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public HttpClient httpClient() {
|
||||||
|
return HttpClient.newHttpClient();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,76 @@
|
||||||
|
package org.micord.config;
|
||||||
|
|
||||||
|
import org.micord.models.S3ConnectionParams;
|
||||||
|
import org.micord.models.S3Request;
|
||||||
|
|
||||||
|
import javax.crypto.Mac;
|
||||||
|
import javax.crypto.spec.SecretKeySpec;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.net.http.HttpRequest;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.time.ZonedDateTime;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import java.util.Base64;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Maksim Tereshin
|
||||||
|
*/
|
||||||
|
public class S3HttpConnection {
|
||||||
|
|
||||||
|
public static HttpRequest buildHttpRequest(S3Request request, String file) throws Exception {
|
||||||
|
S3ConnectionParams connectionParams = request.getS3ConnectionParams();
|
||||||
|
String host = connectionParams.getHost() + ":" + connectionParams.getPort();
|
||||||
|
String s3Key = connectionParams.getS3Key();
|
||||||
|
String s3Secret = connectionParams.getS3Secret();
|
||||||
|
String method = connectionParams.getMethod().toUpperCase();
|
||||||
|
String body = connectionParams.getBody();
|
||||||
|
|
||||||
|
String resource = "/" + file;
|
||||||
|
String contentType = connectionParams.getContentType();
|
||||||
|
String date = ZonedDateTime.now().format(DateTimeFormatter.RFC_1123_DATE_TIME);
|
||||||
|
|
||||||
|
String signature = generateSignature(method, contentType, date, resource, s3Secret);
|
||||||
|
|
||||||
|
HttpRequest.Builder requestBuilder = HttpRequest.newBuilder()
|
||||||
|
.uri(URI.create("http://" + host + resource))
|
||||||
|
.header("Date", date)
|
||||||
|
.header("Content-Type", contentType)
|
||||||
|
.header("Authorization", "AWS " + s3Key + ":" + signature);
|
||||||
|
|
||||||
|
|
||||||
|
switch (method) {
|
||||||
|
case "DELETE":
|
||||||
|
requestBuilder.DELETE();
|
||||||
|
break;
|
||||||
|
case "GET":
|
||||||
|
requestBuilder.GET();
|
||||||
|
break;
|
||||||
|
case "PUT":
|
||||||
|
requestBuilder.PUT(HttpRequest.BodyPublishers.ofString(body != null ? body : ""));
|
||||||
|
break;
|
||||||
|
case "POST":
|
||||||
|
requestBuilder.POST(HttpRequest.BodyPublishers.ofString(body != null ? body : ""));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException("Unsupported HTTP method: " + method);
|
||||||
|
}
|
||||||
|
|
||||||
|
return requestBuilder.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String generateSignature(String method, String contentType, String date, String resource, String s3Secret) throws Exception {
|
||||||
|
String stringToSign = method + "\n" +
|
||||||
|
"\n" + // MD5 - not used for DELETE requests
|
||||||
|
contentType + "\n" +
|
||||||
|
date + "\n" +
|
||||||
|
resource;
|
||||||
|
|
||||||
|
Mac mac = Mac.getInstance("HmacSHA1");
|
||||||
|
SecretKeySpec secretKey = new SecretKeySpec(s3Secret.getBytes(StandardCharsets.UTF_8), "HmacSHA1");
|
||||||
|
mac.init(secretKey);
|
||||||
|
|
||||||
|
byte[] hash = mac.doFinal(stringToSign.getBytes(StandardCharsets.UTF_8));
|
||||||
|
return Base64.getEncoder().encodeToString(hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,78 @@
|
||||||
|
package org.micord.controller;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.micord.models.DownloadCSVRequest;
|
||||||
|
import org.micord.service.ApiService;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.core.io.InputStreamResource;
|
||||||
|
import org.springframework.core.io.Resource;
|
||||||
|
import org.springframework.http.HttpHeaders;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* REST Controller for API operations.
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/api")
|
||||||
|
public class ApiController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ApiService apiService;
|
||||||
|
|
||||||
|
@PostMapping("/block")
|
||||||
|
public ResponseEntity<?> block(@RequestBody List<String> ids) throws FileNotFoundException {
|
||||||
|
apiService.process("block", ids);
|
||||||
|
return ResponseEntity.ok("");
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/unblock")
|
||||||
|
public ResponseEntity<?> unblock(@RequestBody List<String> ids) throws FileNotFoundException {
|
||||||
|
|
||||||
|
apiService.process("unblock", ids);
|
||||||
|
return ResponseEntity.ok("");
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/removeFromSystem")
|
||||||
|
public ResponseEntity<?> removeFromSystem(@RequestBody List<String> ids)
|
||||||
|
throws FileNotFoundException {
|
||||||
|
|
||||||
|
apiService.process("removeFromSystem", ids);
|
||||||
|
return ResponseEntity.ok("");
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/removeFromCallList")
|
||||||
|
public ResponseEntity<?> removeFromCallList(@RequestBody List<String> ids)
|
||||||
|
throws FileNotFoundException {
|
||||||
|
apiService.process("removeFromCallList", ids);
|
||||||
|
return ResponseEntity.ok("");
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/downloadCSV")
|
||||||
|
public ResponseEntity<Resource> downloadCSV(@RequestBody DownloadCSVRequest request)
|
||||||
|
throws IOException {
|
||||||
|
|
||||||
|
File csvFile = apiService.download("downloadCSV", request);
|
||||||
|
InputStreamResource resource = new InputStreamResource(new FileInputStream(csvFile));
|
||||||
|
|
||||||
|
return ResponseEntity.ok()
|
||||||
|
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + csvFile.getName())
|
||||||
|
.contentType(MediaType.parseMediaType("text/csv"))
|
||||||
|
.contentLength(csvFile.length())
|
||||||
|
.body(resource);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/listDownloadTypes")
|
||||||
|
public ResponseEntity<?> listDownloadTypes()
|
||||||
|
throws FileNotFoundException {
|
||||||
|
List<String> downloadCSVTypes = apiService.getDownloadTypes("downloadCSV");
|
||||||
|
|
||||||
|
return ResponseEntity.ok(downloadCSVTypes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
package org.micord.enums;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Maksim Tereshin
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
public enum RequestArgumentType {
|
||||||
|
SQL("SQL"),
|
||||||
|
AQL("AQL"),
|
||||||
|
S3("S3");
|
||||||
|
|
||||||
|
private final String type;
|
||||||
|
|
||||||
|
RequestArgumentType(String type) {
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,50 @@
|
||||||
|
package org.micord.models;
|
||||||
|
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
import jakarta.xml.bind.annotation.XmlElement;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Maksim Tereshin
|
||||||
|
*/
|
||||||
|
@Setter
|
||||||
|
public class AqlConnectionParams {
|
||||||
|
|
||||||
|
private String host;
|
||||||
|
private int port;
|
||||||
|
private String username;
|
||||||
|
private String password;
|
||||||
|
private String database;
|
||||||
|
private String collection;
|
||||||
|
|
||||||
|
@XmlElement(name = "Host")
|
||||||
|
public String getHost() {
|
||||||
|
return host;
|
||||||
|
}
|
||||||
|
|
||||||
|
@XmlElement(name = "Port")
|
||||||
|
public int getPort() {
|
||||||
|
return port;
|
||||||
|
}
|
||||||
|
|
||||||
|
@XmlElement(name = "Username")
|
||||||
|
public String getUsername() {
|
||||||
|
return username;
|
||||||
|
}
|
||||||
|
|
||||||
|
@XmlElement(name = "Password")
|
||||||
|
public String getPassword() {
|
||||||
|
return password;
|
||||||
|
}
|
||||||
|
|
||||||
|
@XmlElement(name = "Database")
|
||||||
|
public String getDatabase() {
|
||||||
|
return database;
|
||||||
|
}
|
||||||
|
|
||||||
|
@XmlElement(name = "Collection")
|
||||||
|
public String getCollection() {
|
||||||
|
return collection;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,42 @@
|
||||||
|
package org.micord.models;
|
||||||
|
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
import jakarta.xml.bind.annotation.XmlElement;
|
||||||
|
import jakarta.xml.bind.annotation.XmlElementWrapper;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Maksim Tereshin
|
||||||
|
*/
|
||||||
|
@Setter
|
||||||
|
public class AqlRequest extends BaseRequest {
|
||||||
|
|
||||||
|
private AqlConnectionParams aqlConnectionParams;
|
||||||
|
private List<AqlRequestCollection> aqlRequestCollections;
|
||||||
|
|
||||||
|
@XmlElement(name = "AqlConnectionParams")
|
||||||
|
public AqlConnectionParams getAqlConnectionParams() {
|
||||||
|
return aqlConnectionParams;
|
||||||
|
}
|
||||||
|
|
||||||
|
@XmlElementWrapper(name = "AqlRequestCollections")
|
||||||
|
@XmlElement(name = "AqlRequestCollection")
|
||||||
|
public List<AqlRequestCollection> getAqlRequestCollections() {
|
||||||
|
return aqlRequestCollections;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<AqlRequestCollection> getReadCollections() {
|
||||||
|
return aqlRequestCollections.stream()
|
||||||
|
.filter(collection -> collection.getType() != null && collection.getType().contains("read"))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<AqlRequestCollection> getWriteCollections() {
|
||||||
|
return aqlRequestCollections.stream()
|
||||||
|
.filter(collection -> collection.getType() != null && collection.getType().contains("write"))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
package org.micord.models;
|
||||||
|
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
import jakarta.xml.bind.annotation.XmlAttribute;
|
||||||
|
import jakarta.xml.bind.annotation.XmlValue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Maksim Tereshin
|
||||||
|
*/
|
||||||
|
@Setter
|
||||||
|
public class AqlRequestCollection {
|
||||||
|
|
||||||
|
private String type;
|
||||||
|
private String collectionName;
|
||||||
|
|
||||||
|
@XmlAttribute(name = "type")
|
||||||
|
public String getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
@XmlValue
|
||||||
|
public String getCollectionName() {
|
||||||
|
return collectionName;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
package org.micord.models;
|
||||||
|
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
import jakarta.xml.bind.annotation.XmlElement;
|
||||||
|
import jakarta.xml.bind.annotation.XmlSeeAlso;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Maksim Tereshin
|
||||||
|
*/
|
||||||
|
@Setter
|
||||||
|
@XmlSeeAlso({SqlRequest.class, S3Request.class, AqlRequest.class})
|
||||||
|
public abstract class BaseRequest {
|
||||||
|
|
||||||
|
private List<RequestArgument> requestArguments;
|
||||||
|
private String requestURL;
|
||||||
|
|
||||||
|
@XmlElement(name = "RequestArgument")
|
||||||
|
public List<RequestArgument> getRequestArguments() {
|
||||||
|
return requestArguments;
|
||||||
|
}
|
||||||
|
|
||||||
|
@XmlElement(name = "RequestURL")
|
||||||
|
public String getRequestURL() {
|
||||||
|
return requestURL;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
package org.micord.models;
|
||||||
|
|
||||||
|
import java.nio.file.attribute.FileTime;
|
||||||
|
|
||||||
|
public class CachedConfig {
|
||||||
|
private final Requests config;
|
||||||
|
private final FileTime modifiedTime;
|
||||||
|
|
||||||
|
public CachedConfig(Requests config, FileTime modifiedTime) {
|
||||||
|
this.config = config;
|
||||||
|
this.modifiedTime = modifiedTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Requests getConfig() {
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
|
public FileTime getModifiedTime() {
|
||||||
|
return modifiedTime;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
package org.micord.models;
|
||||||
|
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class DownloadCSVRequest {
|
||||||
|
private String type;
|
||||||
|
private List<String> ids;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
package org.micord.models;
|
||||||
|
|
||||||
|
import jakarta.xml.bind.annotation.XmlElement;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
|
||||||
|
@Setter
|
||||||
|
public class DownloadRequest extends BaseRequest {
|
||||||
|
|
||||||
|
private SqlConnectionParams sqlConnectionParams;
|
||||||
|
private String downloadRequestType;
|
||||||
|
|
||||||
|
@XmlElement(name = "SqlConnectionParams")
|
||||||
|
public SqlConnectionParams getSqlConnectionParams() {
|
||||||
|
return sqlConnectionParams;
|
||||||
|
}
|
||||||
|
|
||||||
|
@XmlElement(name = "DownloadRequestType")
|
||||||
|
public String getDownloadRequestType() {
|
||||||
|
return downloadRequestType;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
package org.micord.models;
|
||||||
|
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
import jakarta.xml.bind.annotation.XmlElement;
|
||||||
|
import jakarta.xml.bind.annotation.XmlSeeAlso;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Maksim Tereshin
|
||||||
|
*/
|
||||||
|
@Setter
|
||||||
|
@XmlSeeAlso({SqlRequest.class, S3Request.class})
|
||||||
|
public abstract class Request {
|
||||||
|
|
||||||
|
private List<RequestArgument> requestArguments;
|
||||||
|
private String requestURL;
|
||||||
|
|
||||||
|
@XmlElement(name = "RequestArgument")
|
||||||
|
public List<RequestArgument> getRequestArguments() {
|
||||||
|
return requestArguments;
|
||||||
|
}
|
||||||
|
|
||||||
|
@XmlElement(name = "RequestURL")
|
||||||
|
public String getRequestURL() {
|
||||||
|
return requestURL;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,44 @@
|
||||||
|
package org.micord.models;
|
||||||
|
|
||||||
|
import lombok.Setter;
|
||||||
|
import org.micord.enums.RequestArgumentType;
|
||||||
|
|
||||||
|
import jakarta.xml.bind.annotation.XmlAttribute;
|
||||||
|
import jakarta.xml.bind.annotation.XmlElement;
|
||||||
|
import jakarta.xml.bind.annotation.XmlElementWrapper;
|
||||||
|
import jakarta.xml.bind.annotation.XmlRootElement;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Maksim Tereshin
|
||||||
|
*/
|
||||||
|
@Setter
|
||||||
|
@XmlRootElement(name = "RequestArgument")
|
||||||
|
public class RequestArgument {
|
||||||
|
|
||||||
|
private RequestArgumentType type;
|
||||||
|
private String requestArgumentName;;
|
||||||
|
private String requestArgumentURL;
|
||||||
|
private SqlConnectionParams requestArgumentConnectionParams;
|
||||||
|
|
||||||
|
@XmlAttribute(name = "type")
|
||||||
|
public RequestArgumentType getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
@XmlElement(name = "RequestArgumentName")
|
||||||
|
public String getRequestArgumentName() {
|
||||||
|
return requestArgumentName;
|
||||||
|
}
|
||||||
|
|
||||||
|
@XmlElement(name = "RequestArgumentURL")
|
||||||
|
public String getRequestArgumentURL() {
|
||||||
|
return requestArgumentURL;
|
||||||
|
}
|
||||||
|
|
||||||
|
@XmlElement(name = "RequestArgumentConnectionParams")
|
||||||
|
public SqlConnectionParams getRequestArgumentConnectionParams() {
|
||||||
|
return requestArgumentConnectionParams;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,41 @@
|
||||||
|
package org.micord.models;
|
||||||
|
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
import jakarta.xml.bind.annotation.XmlElement;
|
||||||
|
import jakarta.xml.bind.annotation.XmlRootElement;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Maksim Tereshin
|
||||||
|
*/
|
||||||
|
@Setter
|
||||||
|
@XmlRootElement(name = "Requests")
|
||||||
|
public class Requests {
|
||||||
|
|
||||||
|
private List<SqlRequest> sqlRequests;
|
||||||
|
private List<AqlRequest> aqlRequests;
|
||||||
|
private List<S3Request> s3Requests;
|
||||||
|
private List<DownloadRequest> downloadRequests;
|
||||||
|
|
||||||
|
@XmlElement(name = "DownloadRequest")
|
||||||
|
public List<DownloadRequest> getDownloadRequests() {
|
||||||
|
return downloadRequests;
|
||||||
|
}
|
||||||
|
|
||||||
|
@XmlElement(name = "SqlRequest")
|
||||||
|
public List<SqlRequest> getSqlRequests() {
|
||||||
|
return sqlRequests;
|
||||||
|
}
|
||||||
|
|
||||||
|
@XmlElement(name = "AqlRequest")
|
||||||
|
public List<AqlRequest> getAqlRequests() {
|
||||||
|
return aqlRequests;
|
||||||
|
}
|
||||||
|
|
||||||
|
@XmlElement(name = "S3Request")
|
||||||
|
public List<S3Request> getS3Requests() {
|
||||||
|
return s3Requests;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,56 @@
|
||||||
|
package org.micord.models;
|
||||||
|
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
import jakarta.xml.bind.annotation.XmlElement;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Maksim Tereshin
|
||||||
|
*/
|
||||||
|
@Setter
|
||||||
|
public class S3ConnectionParams {
|
||||||
|
|
||||||
|
private String s3Key;
|
||||||
|
private String s3Secret;
|
||||||
|
private String host;
|
||||||
|
private String port;
|
||||||
|
private String contentType;
|
||||||
|
private String method;
|
||||||
|
private String body;
|
||||||
|
|
||||||
|
@XmlElement(name = "S3Key")
|
||||||
|
public String getS3Key() {
|
||||||
|
return s3Key;
|
||||||
|
}
|
||||||
|
|
||||||
|
@XmlElement(name = "S3Secret")
|
||||||
|
public String getS3Secret() {
|
||||||
|
return s3Secret;
|
||||||
|
}
|
||||||
|
|
||||||
|
@XmlElement(name = "Host")
|
||||||
|
public String getHost() {
|
||||||
|
return host;
|
||||||
|
}
|
||||||
|
|
||||||
|
@XmlElement(name = "Port")
|
||||||
|
public String getPort() {
|
||||||
|
return port;
|
||||||
|
}
|
||||||
|
|
||||||
|
@XmlElement(name = "ContentType")
|
||||||
|
public String getContentType() {
|
||||||
|
return contentType;
|
||||||
|
}
|
||||||
|
|
||||||
|
@XmlElement(name = "Method")
|
||||||
|
public String getMethod() {
|
||||||
|
return method;
|
||||||
|
}
|
||||||
|
|
||||||
|
@XmlElement(name = "Body")
|
||||||
|
public String getBody() {
|
||||||
|
return body;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
package org.micord.models;
|
||||||
|
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
import jakarta.xml.bind.annotation.XmlElement;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Maksim Tereshin
|
||||||
|
*/
|
||||||
|
@Setter
|
||||||
|
public class S3Request extends BaseRequest {
|
||||||
|
|
||||||
|
private S3ConnectionParams s3ConnectionParams;
|
||||||
|
|
||||||
|
@XmlElement(name = "S3ConnectionParams")
|
||||||
|
public S3ConnectionParams getS3ConnectionParams() {
|
||||||
|
return s3ConnectionParams;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,66 @@
|
||||||
|
package org.micord.models;
|
||||||
|
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
import jakarta.xml.bind.annotation.XmlElement;
|
||||||
|
|
||||||
|
@Setter
|
||||||
|
public class SqlConnectionParams {
|
||||||
|
|
||||||
|
private String jdbcHost;
|
||||||
|
private String jdbcPort;
|
||||||
|
private String jdbcUsername;
|
||||||
|
private String jdbcPassword;
|
||||||
|
private String jdbcDriverClassName;
|
||||||
|
private String jdbcXaDataSourceClassName;
|
||||||
|
private String jdbcXaDataSourcePoolSize;
|
||||||
|
private String jdbcDatabase;
|
||||||
|
private String jdbcXaDataSourceBorrowConnectionTimeout;
|
||||||
|
|
||||||
|
|
||||||
|
@XmlElement(name = "JdbcXaDataSourceBorrowConnectionTimeout")
|
||||||
|
public String getJdbcXaDataSourceBorrowConnectionTimeout() {
|
||||||
|
return jdbcXaDataSourceBorrowConnectionTimeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
@XmlElement(name = "JdbcXaDataSourcePoolSize")
|
||||||
|
public String getJdbcXaDataSourcePoolSize() {
|
||||||
|
return jdbcXaDataSourcePoolSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
@XmlElement(name = "JdbcHost")
|
||||||
|
public String getJdbcHost() {
|
||||||
|
return jdbcHost;
|
||||||
|
}
|
||||||
|
|
||||||
|
@XmlElement(name = "JdbcPort")
|
||||||
|
public String getJdbcPort() {
|
||||||
|
return jdbcPort;
|
||||||
|
}
|
||||||
|
|
||||||
|
@XmlElement(name = "JdbcUsername")
|
||||||
|
public String getJdbcUsername() {
|
||||||
|
return jdbcUsername;
|
||||||
|
}
|
||||||
|
|
||||||
|
@XmlElement(name = "JdbcPassword")
|
||||||
|
public String getJdbcPassword() {
|
||||||
|
return jdbcPassword;
|
||||||
|
}
|
||||||
|
|
||||||
|
@XmlElement(name = "JdbcDriverClassName")
|
||||||
|
public String getJdbcDriverClassName() {
|
||||||
|
return jdbcDriverClassName;
|
||||||
|
}
|
||||||
|
|
||||||
|
@XmlElement(name = "JdbcXaDataSourceClassName")
|
||||||
|
public String getJdbcXaDataSourceClassName() {
|
||||||
|
return jdbcXaDataSourceClassName;
|
||||||
|
}
|
||||||
|
|
||||||
|
@XmlElement(name = "JdbcDatabase")
|
||||||
|
public String getJdbcDatabase() {
|
||||||
|
return jdbcDatabase;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
package org.micord.models;
|
||||||
|
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
import jakarta.xml.bind.annotation.XmlElement;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Maksim Tereshin
|
||||||
|
*/
|
||||||
|
@Setter
|
||||||
|
public class SqlRequest extends BaseRequest {
|
||||||
|
|
||||||
|
private SqlConnectionParams sqlConnectionParams;
|
||||||
|
|
||||||
|
@XmlElement(name = "SqlConnectionParams")
|
||||||
|
public SqlConnectionParams getSqlConnectionParams() {
|
||||||
|
return sqlConnectionParams;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,64 @@
|
||||||
|
package org.micord.service;
|
||||||
|
|
||||||
|
import org.micord.models.*;
|
||||||
|
import org.micord.utils.ConfigLoader;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class ApiService {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ConfigLoader configLoader;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private RequestService sqlAndAqlService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private DownloadService downloadService;
|
||||||
|
|
||||||
|
public void process(String methodName, List<String> ids) throws FileNotFoundException {
|
||||||
|
Requests config = getConfig(methodName);
|
||||||
|
sqlAndAqlService.processSqlAndAqlRequests(config, ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
public File download(String methodName, DownloadCSVRequest request) throws IOException {
|
||||||
|
Requests config = getConfig(methodName);
|
||||||
|
|
||||||
|
String type = request.getType();
|
||||||
|
List<String> ids = Optional.ofNullable(request.getIds())
|
||||||
|
.filter(list -> !list.isEmpty())
|
||||||
|
.orElse(null);
|
||||||
|
|
||||||
|
DownloadRequest selectedRequest = config.getDownloadRequests().stream()
|
||||||
|
.filter(r -> r.getDownloadRequestType().equals(type))
|
||||||
|
.findFirst()
|
||||||
|
.orElseThrow(() -> new IllegalArgumentException("Invalid download type: " + type));
|
||||||
|
|
||||||
|
return downloadService.download(selectedRequest, ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getDownloadTypes(String methodName) throws FileNotFoundException {
|
||||||
|
Requests config = getConfig(methodName);
|
||||||
|
|
||||||
|
return config.getDownloadRequests().stream()
|
||||||
|
.map(DownloadRequest::getDownloadRequestType)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
private Requests getConfig(String methodName) throws FileNotFoundException {
|
||||||
|
Optional<Requests> optionalConfig = configLoader.loadConfigIfModified(methodName);
|
||||||
|
|
||||||
|
if (optionalConfig.isEmpty()) {
|
||||||
|
throw new FileNotFoundException("Configuration for method " + methodName + " could not be loaded.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return optionalConfig.get();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,157 @@
|
||||||
|
package org.micord.service;
|
||||||
|
|
||||||
|
import org.micord.config.DatabaseConnection;
|
||||||
|
import org.micord.models.DownloadRequest;
|
||||||
|
import org.micord.models.RequestArgument;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.PrintWriter;
|
||||||
|
import java.sql.Connection;
|
||||||
|
import java.sql.PreparedStatement;
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class DownloadService {
|
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(DownloadService.class);
|
||||||
|
|
||||||
|
public File download(DownloadRequest selectedRequest, List<String> ids) {
|
||||||
|
|
||||||
|
return processDownloadRequest(selectedRequest, ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
private File processDownloadRequest(DownloadRequest request, List<String> ids) {
|
||||||
|
Map<String, Object> query = buildSqlQuery(request, ids);
|
||||||
|
try (Connection connection = DatabaseConnection.getConnection(
|
||||||
|
request.getSqlConnectionParams())) {
|
||||||
|
String requestURL = (String) query.get("requestURL");
|
||||||
|
|
||||||
|
List<String[]> results = executeSqlQuery(connection, requestURL);
|
||||||
|
|
||||||
|
File csvFile = File.createTempFile("download-", ".csv");
|
||||||
|
|
||||||
|
try (PrintWriter writer = new PrintWriter(csvFile)) {
|
||||||
|
for (String[] row : results) {
|
||||||
|
writer.println(String.join(",", row));
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.error("Failed to write to CSV file", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return csvFile;
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (SQLException | IOException e) {
|
||||||
|
logger.error("SQL execution failed for query: {}", query, e);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, Object> buildSqlQuery(DownloadRequest request, List<String> ids) {
|
||||||
|
Map<String, Object> resultMap = new HashMap<>();
|
||||||
|
String endpointArguments;
|
||||||
|
|
||||||
|
String requestURL = request.getRequestURL();
|
||||||
|
|
||||||
|
if (ids == null || ids.isEmpty()) {
|
||||||
|
resultMap.put("requestURL", requestURL
|
||||||
|
.replace("${DB}", request.getSqlConnectionParams().getJdbcDatabase())
|
||||||
|
.replace("where id in ${endpointArguments}", ""));
|
||||||
|
|
||||||
|
return resultMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (requestURL.contains(":=")) {
|
||||||
|
endpointArguments = "'{" + ids.stream()
|
||||||
|
.map(String::trim)
|
||||||
|
.collect(Collectors.joining(", ")) + "}'";
|
||||||
|
} else {
|
||||||
|
endpointArguments = "(" + ids.stream()
|
||||||
|
.map(s -> "'" + s.trim() + "'")
|
||||||
|
.collect(Collectors.joining(", ")) + ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request.getRequestArguments() != null && !request.getRequestArguments().isEmpty()) {
|
||||||
|
for (RequestArgument argument : request.getRequestArguments()) {
|
||||||
|
|
||||||
|
if (argument.getRequestArgumentConnectionParams() != null) {
|
||||||
|
try (Connection connection = DatabaseConnection.getConnection(
|
||||||
|
argument.getRequestArgumentConnectionParams())) {
|
||||||
|
String query = argument.getRequestArgumentURL();
|
||||||
|
List<String> result = fetchFileListFromDatabaseSQL(connection, query);
|
||||||
|
|
||||||
|
resultMap.put("ids", result);
|
||||||
|
|
||||||
|
|
||||||
|
if (result != null && !result.isEmpty()) {
|
||||||
|
String resultSet = "(" + result.stream()
|
||||||
|
.map(s -> "'" + s.trim() + "'")
|
||||||
|
.collect(Collectors.joining(", ")) + ")";
|
||||||
|
|
||||||
|
requestURL = requestURL.replace("${" + argument.getRequestArgumentName() + "}", resultSet);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (SQLException e) {
|
||||||
|
logger.error("Failed to execute query for RequestArgument", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resultMap.put("requestURL", requestURL
|
||||||
|
.replace("${DB}", request.getSqlConnectionParams().getJdbcDatabase())
|
||||||
|
.replace("${endpointArguments}", endpointArguments));
|
||||||
|
|
||||||
|
return resultMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<String[]> executeSqlQuery(Connection connection, String query) throws SQLException {
|
||||||
|
List<String[]> results = new ArrayList<>();
|
||||||
|
try (PreparedStatement stmt = connection.prepareStatement(query);
|
||||||
|
ResultSet resultSet = stmt.executeQuery()) {
|
||||||
|
|
||||||
|
int columnCount = resultSet.getMetaData().getColumnCount();
|
||||||
|
// Add headers
|
||||||
|
String[] headers = new String[columnCount];
|
||||||
|
for (int i = 1; i <= columnCount; i++) {
|
||||||
|
headers[i - 1] = resultSet.getMetaData().getColumnName(i);
|
||||||
|
}
|
||||||
|
results.add(headers);
|
||||||
|
|
||||||
|
// Add rows
|
||||||
|
while (resultSet.next()) {
|
||||||
|
String[] row = new String[columnCount];
|
||||||
|
for (int i = 1; i <= columnCount; i++) {
|
||||||
|
row[i - 1] = resultSet.getString(i);
|
||||||
|
}
|
||||||
|
results.add(row);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> fetchFileListFromDatabaseSQL(Connection connection, String query)
|
||||||
|
throws SQLException {
|
||||||
|
List<String> results = new ArrayList<>();
|
||||||
|
try (PreparedStatement stmt = connection.prepareStatement(query);
|
||||||
|
ResultSet rs = stmt.executeQuery()) {
|
||||||
|
while (rs.next()) {
|
||||||
|
results.add(rs.getString(1)); // Fetch the first column
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,329 @@
|
||||||
|
package org.micord.service;
|
||||||
|
|
||||||
|
import java.net.HttpURLConnection;
|
||||||
|
import java.net.http.HttpClient;
|
||||||
|
import java.net.http.HttpRequest;
|
||||||
|
import java.net.http.HttpResponse;
|
||||||
|
import java.sql.Connection;
|
||||||
|
import java.sql.PreparedStatement;
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import com.arangodb.ArangoCursor;
|
||||||
|
import com.arangodb.ArangoDBException;
|
||||||
|
import com.arangodb.ArangoDatabase;
|
||||||
|
import com.arangodb.entity.StreamTransactionEntity;
|
||||||
|
import com.arangodb.model.AqlQueryOptions;
|
||||||
|
import com.arangodb.model.StreamTransactionOptions;
|
||||||
|
import org.micord.config.ArangoDBConnection;
|
||||||
|
import org.micord.config.DatabaseConnection;
|
||||||
|
import org.micord.config.S3HttpConnection;
|
||||||
|
import org.micord.enums.RequestArgumentType;
|
||||||
|
import org.micord.models.*;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Maksim Tereshin
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public class RequestService {
|
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(RequestService.class);
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private HttpClient httpClient;
|
||||||
|
|
||||||
|
public void processS3Requests(List<S3Request> s3Requests, List<String> ids) {
|
||||||
|
if (s3Requests != null) {
|
||||||
|
s3Requests.forEach(request -> {
|
||||||
|
List<CompletableFuture<Void>> futures = ids.stream()
|
||||||
|
.map(id -> CompletableFuture.runAsync(() -> processS3Request(request, id)))
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]))
|
||||||
|
.thenRun(() -> logger.info("Successfully processed all S3 requests."))
|
||||||
|
.exceptionally(ex -> {
|
||||||
|
logger.error("Failed to process S3 requests", ex);
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void processS3Request(S3Request request, String id) {
|
||||||
|
try {
|
||||||
|
List<String> files = new ArrayList<>();
|
||||||
|
|
||||||
|
if (request.getRequestArguments() != null && !request.getRequestArguments().isEmpty()) {
|
||||||
|
for (RequestArgument argument : request.getRequestArguments()) {
|
||||||
|
try (Connection connection = DatabaseConnection.getConnection(
|
||||||
|
argument.getRequestArgumentConnectionParams())) {
|
||||||
|
String query = argument.getRequestArgumentURL();
|
||||||
|
List<String> result = fetchFileListFromDatabaseSQL(connection, query);
|
||||||
|
if (result != null && !result.isEmpty()) {
|
||||||
|
files.addAll(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (SQLException e) {
|
||||||
|
logger.error("Failed to execute query for RequestArgument", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
files.forEach(file -> {
|
||||||
|
HttpRequest httpRequest;
|
||||||
|
try {
|
||||||
|
httpRequest = S3HttpConnection.buildHttpRequest(request, file);
|
||||||
|
}
|
||||||
|
catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
httpClient.sendAsync(httpRequest, HttpResponse.BodyHandlers.ofString())
|
||||||
|
.thenAccept(response -> {
|
||||||
|
if (response.statusCode() == HttpURLConnection.HTTP_NO_CONTENT
|
||||||
|
|| response.statusCode() == HttpURLConnection.HTTP_OK) {
|
||||||
|
logger.info("Successfully deleted object for ID {}", id);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
logger.error("Failed to delete object for ID {}. Response code: {}", id,
|
||||||
|
response.statusCode()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.exceptionally(ex -> {
|
||||||
|
logger.error("Failed to delete object for ID {}", id, ex);
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (Exception e) {
|
||||||
|
logger.error("Failed to process S3 request for id: {}", id, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
public void processSqlAndAqlRequests(Requests config, List<String> ids) {
|
||||||
|
if (config.getSqlRequests() != null) {
|
||||||
|
for (SqlRequest request : config.getSqlRequests()) {
|
||||||
|
processSqlRequests(request, ids);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config.getAqlRequests() != null) {
|
||||||
|
for (AqlRequest request : config.getAqlRequests()) {
|
||||||
|
processAqlRequests(request, ids);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
processS3Requests(config.getS3Requests(), ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void processSqlRequests(SqlRequest request, List<String> ids) {
|
||||||
|
Map<String, Object> query = buildSqlQuery(request, ids);
|
||||||
|
try (Connection connection = DatabaseConnection.getConnection(
|
||||||
|
request.getSqlConnectionParams())) {
|
||||||
|
String requestURL = (String) query.get("requestURL");
|
||||||
|
executeSqlQuery(connection, requestURL);
|
||||||
|
|
||||||
|
List<String> queryIds = (List<String>) query.get("ids");
|
||||||
|
if (queryIds != null && !queryIds.isEmpty()) {
|
||||||
|
ids.addAll(queryIds);
|
||||||
|
} else {
|
||||||
|
logger.warn("No IDs found for the query");
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.info("Successfully executed query {} for IDs: ({})", requestURL, String.join(", ", ids));
|
||||||
|
}
|
||||||
|
catch (SQLException e) {
|
||||||
|
logger.error("SQL execution failed for query: {}", query, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, Object> buildSqlQuery(SqlRequest request, List<String> ids) {
|
||||||
|
Map<String, Object> resultMap = new HashMap<>();
|
||||||
|
String endpointArguments;
|
||||||
|
|
||||||
|
String requestURL = request.getRequestURL();
|
||||||
|
|
||||||
|
if (requestURL.contains(":=")) {
|
||||||
|
endpointArguments = "'{" + ids.stream()
|
||||||
|
.map(String::trim)
|
||||||
|
.collect(Collectors.joining(", ")) + "}'";
|
||||||
|
} else {
|
||||||
|
endpointArguments = "(" + ids.stream()
|
||||||
|
.map(s -> "'" + s.trim() + "'")
|
||||||
|
.collect(Collectors.joining(", ")) + ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request.getRequestArguments() != null && !request.getRequestArguments().isEmpty()) {
|
||||||
|
for (RequestArgument argument : request.getRequestArguments()) {
|
||||||
|
|
||||||
|
if (argument.getRequestArgumentConnectionParams() != null) {
|
||||||
|
try (Connection connection = DatabaseConnection.getConnection(
|
||||||
|
argument.getRequestArgumentConnectionParams())) {
|
||||||
|
String query = argument.getRequestArgumentURL();
|
||||||
|
List<String> result = fetchFileListFromDatabaseSQL(connection, query);
|
||||||
|
|
||||||
|
resultMap.put("ids", result);
|
||||||
|
|
||||||
|
|
||||||
|
if (result != null && !result.isEmpty()) {
|
||||||
|
String resultSet = "(" + result.stream()
|
||||||
|
.map(s -> "'" + s.trim() + "'")
|
||||||
|
.collect(Collectors.joining(", ")) + ")";
|
||||||
|
|
||||||
|
requestURL = requestURL.replace("${" + argument.getRequestArgumentName() + "}", resultSet);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (SQLException e) {
|
||||||
|
logger.error("Failed to execute query for RequestArgument", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resultMap.put("requestURL", requestURL
|
||||||
|
.replace("${DB}", request.getSqlConnectionParams().getJdbcDatabase())
|
||||||
|
.replace("${endpointArguments}", endpointArguments));
|
||||||
|
|
||||||
|
return resultMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private boolean executeSqlQuery(Connection connection, String query) throws SQLException {
|
||||||
|
try (PreparedStatement stmt = connection.prepareStatement(query)) {
|
||||||
|
return stmt.execute();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> fetchFileListFromDatabaseSQL(Connection connection, String query)
|
||||||
|
throws SQLException {
|
||||||
|
List<String> results = new ArrayList<>();
|
||||||
|
try (PreparedStatement stmt = connection.prepareStatement(query);
|
||||||
|
ResultSet rs = stmt.executeQuery()) {
|
||||||
|
while (rs.next()) {
|
||||||
|
results.add(rs.getString(1)); // Fetch the first column
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void processAqlRequests(AqlRequest request, List<String> ids) {
|
||||||
|
ArangoDatabase arangoDb = ArangoDBConnection.getConnection(request.getAqlConnectionParams());
|
||||||
|
|
||||||
|
// TODO: implement for multiple request arguments
|
||||||
|
RequestArgument requestArgument = request.getRequestArguments().get(0);
|
||||||
|
List<String> aqlCollectionRead = request.getReadCollections().stream()
|
||||||
|
.map(AqlRequestCollection::getCollectionName)
|
||||||
|
.toList();
|
||||||
|
String aqlCollectionWrite = request.getWriteCollections().stream()
|
||||||
|
.map(AqlRequestCollection::getCollectionName)
|
||||||
|
.findFirst().orElseGet(null);
|
||||||
|
|
||||||
|
StreamTransactionEntity tx = null;
|
||||||
|
try {
|
||||||
|
StreamTransactionOptions options = new StreamTransactionOptions()
|
||||||
|
.writeCollections(aqlCollectionWrite)
|
||||||
|
.readCollections(aqlCollectionRead.toArray(new String[0]));
|
||||||
|
|
||||||
|
tx = arangoDb.beginStreamTransaction(options);
|
||||||
|
String transactionId = tx.getId();
|
||||||
|
|
||||||
|
logger.info("Stream transaction started with ID: {}", transactionId);
|
||||||
|
|
||||||
|
Map<String, Object> entities = executeSelectAqlRequest(arangoDb, aqlCollectionWrite, requestArgument, ids, transactionId);
|
||||||
|
executeMainAqlRequest(arangoDb, aqlCollectionWrite, request.getRequestURL(), entities, transactionId);
|
||||||
|
|
||||||
|
arangoDb.commitStreamTransaction(transactionId);
|
||||||
|
logger.info("Stream transaction with ID {} committed successfully", transactionId);
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (ArangoDBException e) {
|
||||||
|
if (tx != null) {
|
||||||
|
arangoDb.abortStreamTransaction(tx.getId());
|
||||||
|
logger.error("Stream transaction with ID {} aborted due to an error", tx.getId(), e);
|
||||||
|
}
|
||||||
|
throw new RuntimeException("Failed to execute AQL request within a stream transaction", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.info("Successfully executed AQL request");
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, Object> executeSelectAqlRequest(ArangoDatabase arangoDb,
|
||||||
|
String aqlCollectionWrite,
|
||||||
|
RequestArgument requestArgument,
|
||||||
|
List<String> ids, String transactionId) {
|
||||||
|
Map<String, Object> entities = new HashMap<>();
|
||||||
|
|
||||||
|
String url = requestArgument.getRequestArgumentURL();
|
||||||
|
RequestArgumentType type = requestArgument.getType();
|
||||||
|
|
||||||
|
if (type == RequestArgumentType.AQL) {
|
||||||
|
Map<String, Object> bindVars = new HashMap<>();
|
||||||
|
bindVars.put("ids", ids);
|
||||||
|
|
||||||
|
AqlQueryOptions aqlQueryOptions = new AqlQueryOptions().streamTransactionId(transactionId);
|
||||||
|
|
||||||
|
try (ArangoCursor<Map> cursor = arangoDb.query(url, Map.class, bindVars, aqlQueryOptions)) {
|
||||||
|
while (cursor.hasNext()) {
|
||||||
|
Map<String, Object> result = cursor.next();
|
||||||
|
|
||||||
|
for (Map.Entry<String, Object> entry : result.entrySet()) {
|
||||||
|
String key = entry.getKey();
|
||||||
|
Object entityValue = entry.getValue();
|
||||||
|
|
||||||
|
entities.put(key, entityValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e) {
|
||||||
|
logger.error("Failed to execute AQL url", e);
|
||||||
|
}
|
||||||
|
} else if (type == RequestArgumentType.SQL) {
|
||||||
|
if (requestArgument.getRequestArgumentConnectionParams() != null) {
|
||||||
|
try (Connection connection = DatabaseConnection.getConnection(
|
||||||
|
requestArgument.getRequestArgumentConnectionParams())) {
|
||||||
|
String query = requestArgument.getRequestArgumentURL();
|
||||||
|
List<String> result = fetchFileListFromDatabaseSQL(connection, query);
|
||||||
|
|
||||||
|
entities.put(aqlCollectionWrite, result);
|
||||||
|
}
|
||||||
|
catch (SQLException e) {
|
||||||
|
logger.error("Failed to execute query for RequestArgument", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return entities;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void executeMainAqlRequest(ArangoDatabase arangoDb, String aqlCollectionWrite, String requestURL,
|
||||||
|
Map<String, Object> entities, String transactionId) {
|
||||||
|
if (entities == null || entities.isEmpty()) {
|
||||||
|
logger.warn("No entities found for main AQL request.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, Object> bindVars = new HashMap<>();
|
||||||
|
// TODO: verify correctness of received entities and compare keys
|
||||||
|
Object writeEntity = entities.get(aqlCollectionWrite);
|
||||||
|
bindVars.put("ids", entities);
|
||||||
|
|
||||||
|
AqlQueryOptions aqlQueryOptions = new AqlQueryOptions().streamTransactionId(transactionId);
|
||||||
|
|
||||||
|
arangoDb.query(requestURL, null, bindVars, aqlQueryOptions);
|
||||||
|
|
||||||
|
logger.info("Successfully removed {}: {}", aqlCollectionWrite, writeEntity);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,70 @@
|
||||||
|
package org.micord.utils;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.attribute.FileTime;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
import jakarta.xml.bind.JAXBContext;
|
||||||
|
import jakarta.xml.bind.JAXBException;
|
||||||
|
import jakarta.xml.bind.Unmarshaller;
|
||||||
|
|
||||||
|
import org.micord.models.CachedConfig;
|
||||||
|
import org.micord.models.Requests;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Maksim Tereshin
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class ConfigLoader {
|
||||||
|
|
||||||
|
private static final Logger LOGGER = Logger.getLogger(ConfigLoader.class.getName());
|
||||||
|
private static final Map<String, CachedConfig> cachedConfigs = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
@Value("${configDirectory}")
|
||||||
|
private String configDirectory;
|
||||||
|
|
||||||
|
public Optional<Requests> loadConfigIfModified(String methodName) {
|
||||||
|
String fileName = methodName + ".xml";
|
||||||
|
|
||||||
|
if (configDirectory == null) {
|
||||||
|
LOGGER.log(Level.SEVERE, "No configuration directory found for method: " + methodName);
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
File configFile = new File(configDirectory + File.separator + fileName);
|
||||||
|
Path configFilePath = configFile.toPath();
|
||||||
|
FileTime currentModifiedTime = Files.getLastModifiedTime(configFilePath);
|
||||||
|
CachedConfig cachedConfig = cachedConfigs.getOrDefault(methodName, null);
|
||||||
|
|
||||||
|
if (cachedConfig == null || !currentModifiedTime.equals(cachedConfig.getModifiedTime())) {
|
||||||
|
// Load the updated configuration
|
||||||
|
JAXBContext jaxbContext = JAXBContext.newInstance(Requests.class);
|
||||||
|
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
|
||||||
|
Requests loadedConfig = (Requests) unmarshaller.unmarshal(configFile);
|
||||||
|
cachedConfigs.put(methodName, new CachedConfig(loadedConfig, currentModifiedTime));
|
||||||
|
return Optional.of(loadedConfig);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return Optional.of(cachedConfigs.get(methodName).getConfig());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (IOException e) {
|
||||||
|
LOGGER.log(Level.SEVERE, "Failed to load configuration file: " + fileName, e);
|
||||||
|
return Optional.empty(); // Return empty if there is an IO error
|
||||||
|
}
|
||||||
|
catch (JAXBException e) {
|
||||||
|
LOGGER.log(Level.SEVERE, "Failed to unmarshal configuration file: " + fileName, e);
|
||||||
|
return Optional.empty(); // Return empty if unmarshalling fails
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
1
config-data-executor/src/main/resources/application.yml
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
configDirectory: C:\work\ervu-secret\config\cde-xml
|
||||||
749
config.md
Normal file
|
|
@ -0,0 +1,749 @@
|
||||||
|
# Описание параметров конфигурации сервера приложений
|
||||||
|
|
||||||
|
Файл /standalone/configuration/standalone.xml
|
||||||
|
|
||||||
|
## Общие
|
||||||
|
|
||||||
|
- `webbpm.security.login.case_sensitive`. Default value = true. Параметр отвечающий за чувствительность к регистру при обработке логина пользователя.
|
||||||
|
- true - Login и login, обрабатываются как разные логины.
|
||||||
|
- false - Login и login, обрабатывается как один и тот же логин.
|
||||||
|
- `webbpm.db.pool_size`. Нужен только для `webbpm.mode` = development.
|
||||||
|
- `webbpm.mode`. Режим работы приложения. Значения - development, production.
|
||||||
|
- development - в этом режиме используется соединение к БД проекта, заданное в Studio.
|
||||||
|
- production - в этом режиме используется соединение к БД проекта, заданное с помощью jndi имени.
|
||||||
|
|
||||||
|
## jBPM
|
||||||
|
|
||||||
|
- `com.arjuna.ats.arjuna.allowMultipleLastResources`
|
||||||
|
- `webbpm.jbpm.audit-log.disabled` - флаг, отвечающий за включение/отключение аудита jBPM
|
||||||
|
- `webbpm.jbpm.cleaner_cron` - cron расписание автоматической очистки БД JBPM, по умолчанию "-" т.е. выключен. Очищаются незавершенные процессы.
|
||||||
|
- `webbpm.jbpm.cleaner_timeout` - время, спустя которое процесс считается устаревшим. По умолчанию - 10 часов.
|
||||||
|
- `webbpm.jbpm.finished_process_cleaner_cron` - cron расписание автоматической очистки аудита процессов в БД JBPM, по умолчанию "-"
|
||||||
|
т.е. выключен
|
||||||
|
- `webbpm.jbpm.finished_process_cleaner_timeout` - время, спустя которое процесс считается устаревшим. По умолчанию - 10 часов.
|
||||||
|
|
||||||
|
Пример:
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<property name="com.arjuna.ats.arjuna.allowMultipleLastResources" value="true"/>
|
||||||
|
<property name="webbpm.db.pool_size" value="5"/>
|
||||||
|
<property name="webbpm.mode" value="development"/>
|
||||||
|
```
|
||||||
|
|
||||||
|
### jBPM Runtime Strategy
|
||||||
|
|
||||||
|
Возможные варианты runtime strategy:
|
||||||
|
|
||||||
|
- SINGLETON
|
||||||
|
- PER_REQUEST (значение по умолчанию)
|
||||||
|
- PER_PROCESS_INSTANCE
|
||||||
|
- PER_CASE
|
||||||
|
|
||||||
|
Пример:
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<property name="webbpm.jbpm.runtime_strategy" value="PER_PROCESS_INSTANCE"/>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Способ аутентификации
|
||||||
|
|
||||||
|
- authentication.method - способ аутентификации. Поддерживаемые способы аутентификации: form, kerberos, cert_over_db, cert_over_ldap
|
||||||
|
|
||||||
|
### По логину и паролю
|
||||||
|
|
||||||
|
Пример конфигурации:
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<property name="authentication.method" value="form"/>
|
||||||
|
```
|
||||||
|
|
||||||
|
### По сертификату
|
||||||
|
|
||||||
|
- cert_over_db - проверка наличия пользователя в базе данных безопасности
|
||||||
|
- cert_over_ldap - проверка наличия пользователя в базе данных безопасности и в LDAP
|
||||||
|
|
||||||
|
Примеры:
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<property name="authentication.method" value="cert_over_db"/>
|
||||||
|
<property name="authentication.method" value="cert_over_ldap"/>
|
||||||
|
```
|
||||||
|
|
||||||
|
Параметр способа аутентификации authentication.method должен быть также установлен на клиентской части приложения в app-config.json
|
||||||
|
|
||||||
|
Также для аутентификации по сертификату нужны свойства для хранилища сертификатов:
|
||||||
|
|
||||||
|
- certificate.keystore.location - путь до java key store. Key store - это хранилище доверенных сертификатов, с помощью которых можно проверить корневой сертификат. Сертификат устанавливается с помощью команды:
|
||||||
|
|
||||||
|
```text
|
||||||
|
keytool -importcert -alias myAlias -file Example.cer -keystore exampleKeyStore
|
||||||
|
```
|
||||||
|
|
||||||
|
- certificate.keystore.password - пароль для keystore, установленный при импорте сертификата
|
||||||
|
|
||||||
|
Примеры:
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<property name="certificate.keystore.location" value="${jboss.home.dir}/mfc"/>
|
||||||
|
<property name="certificate.keystore.password" value="mfc_auth"/>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Kerberos
|
||||||
|
|
||||||
|
Получите от администратора Kerberos .keytab файл, из которого командой `klist -k http.keytab` можно получить список principal-ов
|
||||||
|
Проверить успешность авторизации principal-а можно командой `kinit -t -i http.keytab %principal%`.
|
||||||
|
В
|
||||||
|
случае успешной авторизации команда `klist` в качестве default principal которым проводилась авторизация.
|
||||||
|
После этого в standalone.xml поправить параметр `app.service-principal` на principal, которым успешно авторизовались. principal имеет формат: `HTTP/%hostname%@%REALM%`
|
||||||
|
|
||||||
|
Пример конфигурации:
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<property name="app.service-principal" value="HTTP/oleg-rxserver.alt.dom@ALT.DOM"/>
|
||||||
|
<property name="app.keytab-location" value="${jboss.home.dir}/http.keytab"/>
|
||||||
|
<property name="authentication.method" value="kerberos"/>
|
||||||
|
```
|
||||||
|
|
||||||
|
- app.service-principal. Пример - HTTP/oleg-rxserver.alt.dom@ALT.DOM
|
||||||
|
- app.keytab-location - расположение keytab файла. Пример - ${jboss.home.dir}/
|
||||||
|
- http.keytab.
|
||||||
|
|
||||||
|
Также необходимо в настройках браузера на клиенте задать параметр `network.negotiate-auth.trusted-uris` задать значение `.%domain%`.
|
||||||
|
Пример:
|
||||||
|
|
||||||
|
```xml
|
||||||
|
.ALT.DOM
|
||||||
|
```
|
||||||
|
|
||||||
|
### Ldap
|
||||||
|
|
||||||
|
Аутентификация происходит посредством логина и пароля синхронизированного пользователя Ldap.
|
||||||
|
Логин и пароль введенные в форму входа, будут проверены сервисом Ldap.
|
||||||
|
|
||||||
|
Пример конфигурации:
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<property name="ldap.url" value="ldap://localhost:389"/>
|
||||||
|
<property name="ldap.base" value="dc=example,dc=org"/>
|
||||||
|
<property name="ldap.username" value="cn=admin,dc=example,dc=org"/>
|
||||||
|
<property name="ldap.password" value="admin"/>
|
||||||
|
<property name="authentication.method" value="form"/>
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Настройка сервера приложений для работы с Kerberos
|
||||||
|
|
||||||
|
1. создать учетные записи в домене:
|
||||||
|
|
||||||
|
- тестовые для проверки работоспособности функционала (пользователи домена, почтовые ящики):
|
||||||
|
|
||||||
|
`User1 pass1 user1@example.com`
|
||||||
|
|
||||||
|
`User2 pass2 user2@example.com`
|
||||||
|
|
||||||
|
- сервисную для доступа сервиса(приложения) к MS AD - (пользователь домена - снять устаревание пароля, ограничение по времени действия, почтовый ящик):
|
||||||
|
|
||||||
|
`serviceUser servicePass serviceuser@example.com`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
2. завести учетную запись машины `appserver.machine.name` (fqdn-имя сервиса) в AD (вручную, как запись в computer) и в DNS (A-запись)
|
||||||
|
|
||||||
|
`appserver.machine.name 10.250.216.91`
|
||||||
|
|
||||||
|
3. сгенерировать keytab (утилита ktpass) для аутентификации сервисов(приложения) для единой точки входа - `serviceUser` - с именем test.file.name.keytab - привязав к ней пользователя serviceUser
|
||||||
|
|
||||||
|
например, так:
|
||||||
|
|
||||||
|
```
|
||||||
|
ktpass -princ http/appserverMachineName.example.com@example.com -mapuser example.com\serviceUser -pass "пароль_уз_serviceUser" -crypto All -ptype KRB5_NT_PRINCIPAL -out "путь_к_директории_выгрузки_файла\test.file.name.keytab"
|
||||||
|
```
|
||||||
|
|
||||||
|
##### Kerberos FAQ
|
||||||
|
|
||||||
|
- В случае, если авторизация не проходит и в логах сервера приложений присутствует следующий вывод:
|
||||||
|
|
||||||
|
```
|
||||||
|
2019-05-14 05:33:36,588 INFO [security.controller.KerberosAuthenticationController] (default task-3) Authentication request header Authorization not exists
|
||||||
|
2019-05-14 05:33:36,588 INFO [security.controller.KerberosAuthenticationController] (default task-3) Authentication object is not presented
|
||||||
|
```
|
||||||
|
|
||||||
|
необходимо проверить настройку браузера firefox `network.negotiate-auth.trusted-uris`, она должна соответствовать домену из principal-а.
|
||||||
|
Для этого в поисковую строку браузера вводим "about:config", в открывшемся окне нажимаем "accept with risk and continue", в поисковой строке открывшейся страницы ввести `network.negotiate-auth.trusted-uris`.
|
||||||
|
Пример: для principal-а `HTTP/oleg-rxserver.alt.dom@ALT.DOM` настройка в браузере должна быть `.alt.dom`, приложение в браузере должно открываться по `http:\\oleg-rxserver.alt.dom:8080\...`
|
||||||
|
|
||||||
|
- если в логах сервера приложений есть ошибка:
|
||||||
|
|
||||||
|
```xml
|
||||||
|
2019-05-13 14:13:07,095 WARN [org.springframework.security.kerberos.web.authentication.SpnegoAuthenticationProcessingFilter] (default task-1) Negotiate Header was invalid: Negotiate TlRMTVNTUAABAAAAl4II4gAAAAAAAAAAAAAAAAAAAAAKAGNFAAAADw==: org.springframework.security.authentication.BadCredentialsException: Kerberos validation not successful
|
||||||
|
...
|
||||||
|
|
||||||
|
Caused by: java.security.PrivilegedActionException: GSSException: Defective token detected (Mechanism level: GSSHeader did not find the right tag)
|
||||||
|
at java.security.AccessController.doPrivileged(Native Method) [rt.jar:1.8.0_211]
|
||||||
|
at javax.security.auth.Subject.doAs(Subject.java:422) [rt.jar:1.8.0_211]
|
||||||
|
at org.springframework.security.kerberos.authentication.sun.SunJaasKerberosTicketValidator.validateTicket(SunJaasKerberosTicketValidator.java:68) [spring-security-kerberos-core-1.0.1.RELEASE.jar:1.0.1.RELEASE]
|
||||||
|
... 66 more
|
||||||
|
Caused by: GSSException: Defective token detected (Mechanism level: GSSHeader did not find the right tag)
|
||||||
|
at sun.security.jgss.GSSHeader.(GSSHeader.java:97) [rt.jar:1.8.0_211]
|
||||||
|
at sun.security.jgss.GSSContextImpl.acceptSecContext(GSSContextImpl.java:306) [rt.jar:1.8.0_211]
|
||||||
|
at sun.security.jgss.GSSContextImpl.acceptSecContext(GSSContextImpl.java:285) [rt.jar:1.8.0_211]
|
||||||
|
at org.springframework.security.kerberos.authentication.sun.SunJaasKerberosTicketValidatorKerberosValidateAction.run(SunJaasKerberosTicketValidator.java:170) [spring-security-kerberos-core-1.0.1.RELEASE.jar:1.0.1.RELEASE]
|
||||||
|
at org.springframework.security.kerberos.authentication.sun.SunJaasKerberosTicketValidatorKerberosValidateAction.run(SunJaasKerberosTicketValidator.java:153) [spring-security-kerberos-core-1.0.1.RELEASE.jar:1.0.1.RELEASE]
|
||||||
|
... 69 more
|
||||||
|
```
|
||||||
|
|
||||||
|
необходимо проверить правильность указанного в standalone.xml principal-а.
|
||||||
|
|
||||||
|
### Комбинации нескольких способов аутентификации
|
||||||
|
|
||||||
|
Приложение может обрабатывать запросы на несколько способов аутентификации. Для этого необходимо переичислить нужные профили через запятую.
|
||||||
|
Примеры:
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<property name="authentication.method" value="form,cert_over_db"/>
|
||||||
|
<property name="authentication.method" value="form,cert_over_ldap"/>
|
||||||
|
<property name="authentication.method" value="kerberos,cert_over_db"/>
|
||||||
|
<property name="authentication.method" value="kerberos,cert_over_ldap"/>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Время жизни токенов аутентификации
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<property name="webbpm.security.access_token.duration.minutes" value="60"/>
|
||||||
|
<property name="webbpm.security.refresh_token.duration.days" value="30"/>
|
||||||
|
<property name="webbpm.security.session.active.count" value="2"/>
|
||||||
|
```
|
||||||
|
|
||||||
|
`webbpm.security.access_token.duration.minutes` - опциональный параметр (значение по умолчанию 60), время жизни в минутах, сколько будет действителен токен, после истечения этого времени токен будет обновлён `webbpm.security.refresh_token.duration.days` - опциональный параметр (значение по умолчанию 30), время жизни в днях, после истечения этого времени с последнего обновления, пользователю будет необходимо повторно войти `webbpm.security.session.active.count` - опциональный параметр (значение по умолчанию 1), количество сохраняемых в базу токенов обновления (количество активных сессий)
|
||||||
|
|
||||||
|
Примечания.
|
||||||
|
|
||||||
|
- Нельзя использовать одновременно профили cert_over_db c cert_over_ldap и kerberos с form.
|
||||||
|
|
||||||
|
## Синхронизация пользователей с LDAP
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<property name="ldap.auto.sync.enabled" value="true"/>
|
||||||
|
<property name="ldap.synchronizer.cron" value="0 0 * * * *"/>
|
||||||
|
<property name="ldap.url" value="ldap://localhost:389"/>
|
||||||
|
<property name="ldap.base" value="dc=alt,dc=dom"/>
|
||||||
|
<property name="ldap.username" value="uid=test,ou=People,dc=alt,dc=dom"/>
|
||||||
|
<property name="ldap.password" value="password"/>
|
||||||
|
<property name="webbpm.ldap.implementation" value="open-ldap"/>
|
||||||
|
```
|
||||||
|
|
||||||
|
Настройки подключения к LDAP:
|
||||||
|
|
||||||
|
- `ldap.auto.sync.enabled` - включает/отключает автоматическую синхронизацию с LDAP
|
||||||
|
- `ldap.synchronizer.cron` - cron расписание автоматической синхронизации с LDAP
|
||||||
|
- `ldap.url`. Пример - ldap://localhost:389
|
||||||
|
- `ldap.base`. Пример - dc=alt,dc=dom
|
||||||
|
- `ldap.username`. Пример - uid=test,ou=People,dc=alt,dc=dom
|
||||||
|
- `ldap.password`
|
||||||
|
- `webbpm.ldap.implementation`. Допускается два значения: open-ldap и active-directory.
|
||||||
|
|
||||||
|
## WEBGUARD
|
||||||
|
|
||||||
|
Для синхронизации пользователей в WEBGUARD и для корректной работы админки необходимо указать настройки соединения к REST API WEBGUARD
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<property name="webguard.url" value="http://wg-host:8081/security-manager"/>
|
||||||
|
<property name="webguard.user.login" value="wg-user"/>
|
||||||
|
<property name="webguard.user.password" value="wg-password"/>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Статистика
|
||||||
|
|
||||||
|
### jbpm hibernate statistics
|
||||||
|
|
||||||
|
Статистика hibernate jbpm доступна по jmx по пути `org.hibernate:type=Stats,name=jbpm`.
|
||||||
|
Полный список параметров можно посмотреть через jconsole.
|
||||||
|
|
||||||
|
По умолчанию включена, отключить можно настройкой `webbpm.jbpm.hibernate_statistics.enabled`:
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<property name="webbpm.jbpm.hibernate_statistics.enabled" value="false"/>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Schedulers по очистке базы *jbpm*.
|
||||||
|
|
||||||
|
- Очистка таблиц аудита от завершенных процессов по истечении таймаута
|
||||||
|
|
||||||
|
- `webbpm.jbpm.finished_process_cleaner_cron` - задает расписание (*spring cron*), если настройка не задана - джоб не запускается
|
||||||
|
- `webbpm.jbpm.finished_process_cleaner_timeout` - таймаут в часах (*целое числовое значение*)
|
||||||
|
|
||||||
|
Пример:
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<property name="webbpm.jbpm.finished_process_cleaner_cron" value="0 * * * * *"/>
|
||||||
|
<property name="webbpm.jbpm.finished_process_cleaner_timeout" value="2"/>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Ограничения для запросов БД.
|
||||||
|
|
||||||
|
- `webbpm.db.query_limit_enabled` - флаг, отвечающий за вывод сообщений о превышении лимитов на количество возвращаемых записей. По умолчанию - false.
|
||||||
|
|
||||||
|
- `webbpm.db.select_records_max_limit` - максимальный лимит возвращаемых строк для запросов в БД, при превышении/равенстве данного лимита будет выброшена ошибка (*целое числовое значение*). По умолчанию - 100000
|
||||||
|
|
||||||
|
- `webbpm.db.select_records_min_limit` - минимальный лимит возвращаемых строк для запросов в БД, при превышении/равенстве данного лимита в логи будет выведен warning (*целое числовое значение*). По умолчанию - 1000
|
||||||
|
|
||||||
|
- `webbpm.db.execution_time_threshold`. The threshold for time of executing a statement. Система выводит сообщение в логи при превышении. Действует для запросов, созданных в jOOQ. По умолчанию - 1000 миллисекунд
|
||||||
|
|
||||||
|
- `webbpm.db.result_read_time_threshold`. The threshold for time of fetching a set of records from a ResultSet.
|
||||||
|
. Система выводит сообщение в логи при превышении. Действует для запросов, созданных в jOOQ. По умолчанию - 50 миллисекунд
|
||||||
|
|
||||||
|
- `webbpm.db.results_count_threshold`. Система выводит сообщение в логи при превышении. Действует для запросов, созданных в jOOQ. По умолчанию - 1000 записей
|
||||||
|
|
||||||
|
- `webbpm.db.full_time_threshold`. Ограничение на полное время выполнения запроса. Система выводит сообщение в логи при превышении. Действует для запросов, созданных в jOOQ. По умолчанию sum(webbpm.db.result_read_time_threshold, webbpm.db.execution_time_threshold) миллисекунд
|
||||||
|
|
||||||
|
- `webbpm.db.query_timeout`. Ограничение на время выполнения запроса. При превышении запрос будет отклонен. Действует для запросов, созданных в jOOQ в dev режиме. По умолчанию 120 секунд.
|
||||||
|
|
||||||
|
Пример:
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<property name="webbpm.db.query_limit_enabled" value="false"/>
|
||||||
|
<property name="webbpm.db.select_records_max_limit" value="100000"/>
|
||||||
|
<property name="webbpm.db.select_records_min_limit" value="1000"/>
|
||||||
|
<property name="webbpm.db.execution_time_threshold" value="1000"/>
|
||||||
|
<property name="webbpm.db.results_count_threhold" value="50"/>
|
||||||
|
<property name="webbpm.db.result_read_time_threshold" value="50"/>
|
||||||
|
<property name="webbpm.db.full_time_threshold" value="300"/>
|
||||||
|
<property name="webbpm.db.query_timeout" value="120"/>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Добавление версии приложения в URL при запросах к backend-у
|
||||||
|
|
||||||
|
При сборке приложения с профилем enable-version-in-url в URL будет добавляться версия приложения, указанная в pom.xml.
|
||||||
|
Шаблон URL:
|
||||||
|
|
||||||
|
```
|
||||||
|
<protocol>//<hostname>:<port>/backend<app-version>/<some-controller>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Включение регистрации пользователя
|
||||||
|
|
||||||
|
1. Укажите конфигурацию почтового сервера для отправки писем с подтверждением регистрации.
|
||||||
|
Для этого в файле проекта *jndi-resources.xml* добавьте ресурс SmtpConfiguration.
|
||||||
|
Шаблон:
|
||||||
|
```
|
||||||
|
<jndi-resource name="java:comp/env/webbpm/testResource" type="bpmn.handler.common.SmtpConfiguration">{"host":"host","port":1234,"login":"user","password":"password","from":"email_from","senderName":"sender_name","isSecured":true}</jndi-resource>
|
||||||
|
```
|
||||||
|
Почтовый сервер - зарегистрированный актуальный почтовый адрес. В поле password нужно указывать не пароль для входа в почту, а создать пароль для приложений в учетке почты и указать его.
|
||||||
|
2. Для включения регистрации добавьте в *standalone.xml* свойство
|
||||||
|
```
|
||||||
|
<property name="registration.enabled" value="true"/>
|
||||||
|
```
|
||||||
|
3. Также в *standalone.xml* укажите ресурс для отправки писем для подтверждения регистрации (из п.1)
|
||||||
|
```
|
||||||
|
<property name="mail.jndi.resource.name" value="java:comp/env/webbpm/testResource"/>
|
||||||
|
```
|
||||||
|
4. При необходимости, отредактируйте шаблон письма для подтверждения регистрации
|
||||||
|
(resources/src/main/resources/mail/confirmation.html)
|
||||||
|
|
||||||
|
5. При необходимости, отредактируйте шаблон письма для восстановления пароля
|
||||||
|
(resources/src/main/resources/mail/reset_password.html)
|
||||||
|
|
||||||
|
|
||||||
|
#### Настройка браузера для входа в систему с помощью Kerberos
|
||||||
|
|
||||||
|
1. Запустите браузер firefox.
|
||||||
|
2. В адресной строке введите about:config, нажать кнопку "я принимаю на себя риск"
|
||||||
|
3. С помощью поиска найдите параметр network.negotiate-auth.trusted-uris и в качестве значения ввести домен(например для домена example.com надо ввести .example.com)
|
||||||
|
4. Откройте в браузере приложение. Пример [http://app.example.com/](http://app.example.com/) . Приложение должно открыться без запроса логина/пароля
|
||||||
|
|
||||||
|
## Восстановление структуры БД
|
||||||
|
|
||||||
|
На основе БД проекта с помощью jOOQ генерируются Java классы для каждого объекта БД. Это происходит по нажатию кнопки Обновить на панели БД в студии. При необходимости можно сформировать DDL на основе данных классов. Пример класса для генерации DDL
|
||||||
|
|
||||||
|
```
|
||||||
|
package ru.cg.webbpm.test_project.db_beans;
|
||||||
|
|
||||||
|
import org.jooq.*;
|
||||||
|
import org.jooq.impl.*;
|
||||||
|
|
||||||
|
public class Main {
|
||||||
|
public static void main (String args []) {
|
||||||
|
DefaultConfiguration defaultConfiguration = new DefaultConfiguration();
|
||||||
|
defaultConfiguration.setSQLDialect(SQLDialect.POSTGRES);
|
||||||
|
Queries ddl = DSL.using(defaultConfiguration).ddl(DefaultCatalog.DEFAULT_CATALOG);
|
||||||
|
|
||||||
|
for (Query query : ddl.queries()) {
|
||||||
|
System.out.println(query);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
** ВНИМАНИЕ: **
|
||||||
|
|
||||||
|
- этим способом нельзя восстановить функции/процедуры БД
|
||||||
|
|
||||||
|
см. также [Generating DDL from objects](https://www.jooq.org/doc/latest/manual/sql-building/ddl-statements/generating-ddl/)
|
||||||
|
|
||||||
|
## Распределенный кэш (Hazelcast)
|
||||||
|
|
||||||
|
В платформе подключен кэш. Он используется для подсчёта количества пользователей и кэширования подсистемы безопасности
|
||||||
|
|
||||||
|
- `webbpm.cache.hazelcast.port` - входящий порт hazelcast. по дефолту 5701.
|
||||||
|
- Обязательное задать одно из двух следующих параметров
|
||||||
|
- `webbpm.cache.hazelcast.hosts` - список хостов серверов приложений.
|
||||||
|
webbpm.cache.hazelcast.hosts = hostname1,hostname2,hostname3
|
||||||
|
- `webbpm.cache.hazelcast.kubernetes.service_name` - имя сервиса в среде kubernetes,
|
||||||
|
используемый для обнаружения других подов. Подходит как стратегия обнаружения, если используется
|
||||||
|
kubernetes
|
||||||
|
- `webbpm.cache.hazelcast.outbound_port_definitions` - исходящие порты hazelcast. по дефолту не задано, система сама выбирает свободные порты. Задать диапазон 5801 - 5820
|
||||||
|
- `webbpm.cache.hazelcast.backup_count`. Нужны чтобы когда сервер выключается был доступен бекап. Если предполагается выключать несколько серверов за раз, то нужно увеличить.
|
||||||
|
Данный бекап делает копии синхронно с основной записью и операция записи ждет пока будет записана везде. Можно делать бекап асинхронно, настраивается через async_backup_count
|
||||||
|
подробнее про бекапы [Hazelcast IMDG Reference Manual](https://docs.hazelcast.org/docs/3.11/manual/html-single/index.html#backing-up-maps) . по дефолту 1
|
||||||
|
- `webbpm.cache.hazelcast.async_backup_count`
|
||||||
|
- `webbpm.cache.hazelcast.public_address`
|
||||||
|
- `webbpm.cache.hazelcast.interfaces`
|
||||||
|
|
||||||
|
Пример конфигурации:
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<property name="webbpm.cache.hazelcast.hosts" value="app1,app2"/>
|
||||||
|
<property name="webbpm.cache.hazelcast.outbound_port_definitions" value="5801-5820"/>`
|
||||||
|
```
|
||||||
|
|
||||||
|
## Подключение компоненты адреса в режиме ГАР (Государственный адресный реестр)
|
||||||
|
|
||||||
|
Необходимо задать параметры:
|
||||||
|
|
||||||
|
- `gar.enable` - флаг, который включает/отключает сервис для работы с ГАР. Должен быть задан для работы компоненты в режиме ГАР. По умолчанию true, для отключения задать false.
|
||||||
|
- `gar.elastic.url.host` - хост на котором развернут elasticsearch.
|
||||||
|
- `gar.elastic.password` - пароль для аутентификации elasticsearch.
|
||||||
|
|
||||||
|
Дополнительные параметры:
|
||||||
|
|
||||||
|
- `gar.elastic.url.port` - порт на котором развернут elasticsearch.
|
||||||
|
- `gar.elastic.username` - логин для аутентификации elasticsearch.
|
||||||
|
|
||||||
|
Пример конфигурации:
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<property name="gar.enable" value="true"/>
|
||||||
|
<property name="gar.elastic.url.host" value="localhost"/>
|
||||||
|
<property name="gar.elastic.password" value="password"/>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Метрики
|
||||||
|
|
||||||
|
Отчет
|
||||||
|
|
||||||
|
Отчет собирается раз в 30 секунд по дефолту, меняется параметром `webbpm.metrics.report_period_ms`.
|
||||||
|
Все метрики идут за отчетный период, после сбора отчета они сбрасываются.
|
||||||
|
|
||||||
|
Получить json со всеми метриками можно по урлу `backend/metrics/v1/all` - метрики будут с последнего собранного отчета, запрос не триггерит сбор отчета - это независимые операции. Отчет содержит только метрики по которым был совершен хотя бы один вызов в отчетный период. То есть, если какая-то операция не была совершена в отчетный период, то соответствующая ей метрика не попадет в отчет - ее не будет в json.
|
||||||
|
|
||||||
|
### Значения метрик
|
||||||
|
|
||||||
|
Все метрики идут за отчетный период, после сбора отчета они сбрасываются.
|
||||||
|
Нас в основном интересуют `callsCountSum`, `latencyMin`, `latencyAvg`, `latencyMax`
|
||||||
|
|
||||||
|
- `callsCountSum` - количество завершенных вызовов
|
||||||
|
- `latencyMin` - минимальное время выполнения
|
||||||
|
- `latencyAvg` - среднее время выполнения
|
||||||
|
- `latencyMax` - максимальное время выполнения
|
||||||
|
- `activeCallsCountMax` - количество начатых, но еще не завершенных вызовов.
|
||||||
|
- `activeCallsLatencyMax` - длительность самого долгого еще не завершенного вызова
|
||||||
|
|
||||||
|
### Текущие метрики приложения
|
||||||
|
|
||||||
|
- Получение коннекта из пула
|
||||||
|
|
||||||
|
- `webbpm.jbpm.db.connection.acquire`
|
||||||
|
- `webbpm.security.db.connection.acquire`
|
||||||
|
- `webbpm.db.connection.acquire`
|
||||||
|
|
||||||
|
- Время с момента получения коннекта до возврата его в пул
|
||||||
|
|
||||||
|
- `webbpm.jbpm.db.connection.in_use`
|
||||||
|
- `webbpm.security.db.connection.in_use`
|
||||||
|
- `webbpm.db.connection.in_use`
|
||||||
|
|
||||||
|
- Время выполнения запроса на бд проекта
|
||||||
|
|
||||||
|
- `webbpm.db.query.success.execution_time`
|
||||||
|
|
||||||
|
- Время выполнения запроса на бд проекта + время получения коннекта из пула
|
||||||
|
|
||||||
|
- `webbpm.db.query.success.full_time`
|
||||||
|
|
||||||
|
- active-users-count.indicatorMax
|
||||||
|
|
||||||
|
- active-users-count-ttl.indicatorMax
|
||||||
|
|
||||||
|
# Количество пользователей
|
||||||
|
|
||||||
|
- `webbpm.active_users_counter.enabled` - включает подсчет пользователей, нужно чтобы не запускать hazelcast на дев машинах. по дефолту false. На боевых серверах необходимо установить в true.
|
||||||
|
|
||||||
|
- `webbpm.active_users_counter.max_time_between_operations_in_seconds` - время, которое пользователь считается активным после действия. по дефолту 15 минут.
|
||||||
|
|
||||||
|
- `webbpm.active_users_counter.hazelcast.app_pool_size`. Запись в hazelcast производится асинхронно в отдельном пуле, не блокируя обработку http запроса. Это размер этого пула. по дефолту 4. Можно пока оставить 4 и последить за метриками pool.hazelcast-executor.queue.indicatorMax и pool.hazelcast-executor.activeThreads.indicatorMax. Если очередь будет сильно копиться, то увеличить.
|
||||||
|
|
||||||
|
## Настройка логов
|
||||||
|
|
||||||
|
Все настройки делаются в файле `standalone.xml`, если не указано иначе.
|
||||||
|
|
||||||
|
### Общие настройки
|
||||||
|
|
||||||
|
Платформа Web-bpm использует корневую категорию логирования `ru.cg.webbpm`, рекомендуется выставлять ее в уровень `info`. todo check prod config
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<logger category="ru.cg.webbpm">
|
||||||
|
<level name="INFO"/>
|
||||||
|
</logger>
|
||||||
|
```
|
||||||
|
|
||||||
|
При этом компоненты используемые в проекте могут использовать другие категории.
|
||||||
|
|
||||||
|
### Параметры конфигурации
|
||||||
|
|
||||||
|
**Рекомендованное использование:** всегда в `info`.
|
||||||
|
|
||||||
|
Все параметры конфигурации загружаемые платформой web-bpm и пользовательским приложением через api webbpm логируются категорией `ru.cg.webbpm.modules.core.app_info.api.property.BaseProperty`. Она всегда должна быть выставлена в `info`.
|
||||||
|
|
||||||
|
Пример вывода:
|
||||||
|
|
||||||
|
```
|
||||||
|
2017-12-04 16:02:19,074 INFO [ru.cg.webbpm.modules.core.app_info.api.property.BaseProperty] (EclipseGeminiBlueprintExtenderThread-1) System property [webbpm.active_users_counter.enabled] not set. Using default value [false]
|
||||||
|
2017-12-04 16:02:19,074 INFO [ru.cg.webbpm.modules.core.app_info.api.property.BaseProperty] (EclipseGeminiBlueprintExtenderThread-1) System property [webbpm.active_users_counter.hazelcast.hosts] set to [127.0.0.1]
|
||||||
|
```
|
||||||
|
|
||||||
|
### БД проекта
|
||||||
|
|
||||||
|
#### Логирование запросов в бд security и бд проекта
|
||||||
|
|
||||||
|
**Рекомендованное использование:** только при разработке.
|
||||||
|
|
||||||
|
Использовать только при разработке. Категория `org.jooq.tools.LoggerListener` в `debug` уровень.
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<logger category="org.jooq.tools.LoggerListener">
|
||||||
|
<level name="DEBUG"/>
|
||||||
|
</logger>
|
||||||
|
```
|
||||||
|
|
||||||
|
Пример вывода:
|
||||||
|
|
||||||
|
```
|
||||||
|
2017-12-04 18:21:10,391 DEBUG [org.jooq.tools.LoggerListener] (default task-19) Executing query : select "department"."department_name", "department"."department_id", "department"."parent_department_id", "department"."parent_department_id", "department"."department_id", (select (count(*) <> ?) from "public"."department" as "$$child" where "$$child"."parent_department_id" = "department"."department_id") as "$$hasChildren" from "public"."department" as "department" limit ?
|
||||||
|
2017-12-04 18:21:10,395 DEBUG [org.jooq.tools.LoggerListener] (default task-19) -> with bind values : select "department"."department_name", "department"."department_id", "department"."parent_department_id", "department"."parent_department_id", "department"."department_id", (select (count(*) <> 0) from "public"."department" as "$$child" where "$$child"."parent_department_id" = "department"."department_id") as "$$hasChildren" from "public"."department" as "department" limit 2147483647
|
||||||
|
2017-12-04 18:21:10,568 DEBUG [org.jooq.tools.LoggerListener] (default task-19) Fetched result : +-----------------+-------------+--------------------+--------------------+-------------+-------------+
|
||||||
|
2017-12-04 18:21:10,568 DEBUG [org.jooq.tools.LoggerListener] (default task-19) : |department_name |department_id|parent_department_id|parent_department_id|department_id|$$hasChildren|
|
||||||
|
2017-12-04 18:21:10,568 DEBUG [org.jooq.tools.LoggerListener] (default task-19) : +-----------------+-------------+--------------------+--------------------+-------------+-------------+
|
||||||
|
2017-12-04 18:21:10,568 DEBUG [org.jooq.tools.LoggerListener] (default task-19) : |Головной офис 1 | 8| {null}| {null}| 8|true |
|
||||||
|
2017-12-04 18:21:10,568 DEBUG [org.jooq.tools.LoggerListener] (default task-19) : |Головной офис 2 | 9| {null}| {null}| 9|true |
|
||||||
|
2017-12-04 18:21:10,568 DEBUG [org.jooq.tools.LoggerListener] (default task-19) : |Головной офис 3 | 10| {null}| {null}| 10|true |
|
||||||
|
2017-12-04 18:21:10,568 DEBUG [org.jooq.tools.LoggerListener] (default task-19) : |Подразделение 1.1| 11| 8| 8| 11|true |
|
||||||
|
2017-12-04 18:21:10,568 DEBUG [org.jooq.tools.LoggerListener] (default task-19) : |Подразделение 1.2| 12| 8| 8| 12|true |
|
||||||
|
2017-12-04 18:21:10,568 DEBUG [org.jooq.tools.LoggerListener] (default task-19) : +-----------------+-------------+--------------------+--------------------+-------------+-------------+
|
||||||
|
2017-12-04 18:21:10,568 DEBUG [org.jooq.tools.LoggerListener] (default task-19) : |...55 record(s) truncated...
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Логирование больших запросов
|
||||||
|
|
||||||
|
**Рекомендованное использование:** всегда в `info`, с подобранными для проекта значениями. В проде значения должны быть проверены что они не вызывают излишнее логирование.
|
||||||
|
|
||||||
|
1. Для отслеживания больших запросов в пользовательскую базу нужно задать параметры что считать большими запросами, логироваться будут запросы больше заданных показателей.
|
||||||
|
Чтобы логировать все запросы можно задать значение `-1`. Добавляются как property в раздел `system-properties`:
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<property name="webbpm.db.full_time_threshold" value="1050"/>
|
||||||
|
<property name="webbpm.db.results_count_threshold" value="1000"/>
|
||||||
|
```
|
||||||
|
|
||||||
|
В `info` режиме работают:
|
||||||
|
|
||||||
|
- `webbpm.db.full_time_threshold` - полное время выполнения запроса в миллисекундах. Включает построение запроса библиотекой, выполнение и загрузку результатов. Пример сообщения <br>`2023-01-11 13:09:38,361 WARN [ru.cg.webbpm.modules.database.impl.analytics.PerformanceListener] (default task-33) Query full time threshold exceeded. full_time=[6565ms] execution_time=[6565ms] read_time=[0ms] results_count=[4] query=[<your query>]`
|
||||||
|
- `webbpm.db.results_count_threshold` - количество записей, которое вернул запрос. Пример сообщения <br>`2023-01-11 13:10:34,088 WARN [ru.cg.webbpm.modules.database.impl.analytics.PerformanceListener] (default task-41) Query results count threshold exceeded. results_count=[11177] query=[<your query>]`
|
||||||
|
|
||||||
|
В `debug` режиме дополнительно к работающим в info:
|
||||||
|
|
||||||
|
- `webbpm.db.execution_time_threshold` - время выполнения запроса + построения запроса библиотекой.
|
||||||
|
- `webbpm.db.result_read_time_threshold` - время чтения результатов запроса
|
||||||
|
|
||||||
|
2. После задания настроек нужно настроить логирование - категория `ru.cg.webbpm.modules.database.impl.analytics.PerformanceListener`, уровень `info` или `debug`.
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<logger category="ru.cg.webbpm.modules.database.impl.analytics.PerformanceListener">
|
||||||
|
<level name="INFO"/>
|
||||||
|
</logger>
|
||||||
|
```
|
||||||
|
|
||||||
|
### JBPM
|
||||||
|
|
||||||
|
#### Основные настройки
|
||||||
|
|
||||||
|
JBPM использует 3 корневых категории логирования – `org.jbpm`, `org.drools`, `org.kie`. Все они должны быть выставлены в `warn`.
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<logger category="org.jbpm">
|
||||||
|
<level name="WARN"/>
|
||||||
|
</logger>
|
||||||
|
<logger category="org.drools">
|
||||||
|
<level name="WARN"/>
|
||||||
|
</logger>
|
||||||
|
<logger category="org.kie">
|
||||||
|
<level name="WARN"/>
|
||||||
|
</logger>
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Логирование запросов в БД
|
||||||
|
|
||||||
|
**Рекомендованное использование:** только при разработке.
|
||||||
|
|
||||||
|
Для логирования sql запросов нужно включить категорию `org.hibernate.SQL` в `debug`:
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<logger category="org.hibernate.SQL">
|
||||||
|
<level name="DEBUG"/>
|
||||||
|
</logger>
|
||||||
|
```
|
||||||
|
|
||||||
|
Чтобы вывести параметры запросов и результат выполнения – категорию `org.hibernate.type.descriptor.sql` в `trace`:
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<logger category="org.hibernate.type.descriptor.sql">
|
||||||
|
<level name="TRACE"/>
|
||||||
|
</logger>
|
||||||
|
```
|
||||||
|
|
||||||
|
Пример вывода:
|
||||||
|
|
||||||
|
```
|
||||||
|
18:21:06,938 DEBUG [org.hibernate.SQL] (default task-47) select names0_.Task_Names_Id as Task_Nam7_16_0_, names0_.id as id1_16_0_, names0_.id as id1_16_1_, names0_.language as language2_16_1_, names0_.shortText as shortTex3_16_1_, names0_.text as text4_16_1_ from I18NText names0_ where names0_.Task_Names_Id=?
|
||||||
|
18:21:06,939 TRACE [org.hibernate.type.descriptor.sql.BasicBinder] (default task-47) binding parameter [1] as [BIGINT] - [180]
|
||||||
|
18:21:06,940 TRACE [org.hibernate.type.descriptor.sql.BasicExtractor] (default task-47) extracted value ([id1_16_1_] : [BIGINT]) - [539]
|
||||||
|
18:21:06,940 TRACE [org.hibernate.type.descriptor.sql.BasicExtractor] (default task-47) extracted value ([language2_16_1_] : [VARCHAR]) - [en-UK]
|
||||||
|
18:21:06,940 TRACE [org.hibernate.type.descriptor.sql.BasicExtractor] (default task-47) extracted value ([shortTex3_16_1_] : [VARCHAR]) - [Список записей]
|
||||||
|
18:21:06,941 TRACE [org.hibernate.type.descriptor.sql.BasicExtractor] (default task-47) extracted value ([text4_16_1_] : [CLOB]) - [Список записей]
|
||||||
|
18:21:06,941 TRACE [org.hibernate.type.descriptor.sql.BasicExtractor] (default task-47) extracted value ([Task_Nam7_16_0_] : [BIGINT]) - [180]
|
||||||
|
18:21:06,942 TRACE [org.hibernate.type.descriptor.sql.BasicExtractor] (default task-47) extracted value ([id1_16_0_] : [BIGINT]) - [539]
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Дополнительные логи hibernate
|
||||||
|
|
||||||
|
**Рекомендованное использование:** только при разработке в случае необходимости.
|
||||||
|
|
||||||
|
1. Время выполнения запроса и количество результатов.
|
||||||
|
|
||||||
|
Включаются категорией `org.hibernate.stat` в `debug`. При этом в hibernate должен быть включен сбор статистики.
|
||||||
|
Похоже что логируется только hql select запросов.
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<logger category="org.hibernate.stat">
|
||||||
|
<level name="DEBUG"/>
|
||||||
|
</logger>
|
||||||
|
```
|
||||||
|
|
||||||
|
Пример вывода:
|
||||||
|
|
||||||
|
```
|
||||||
|
18:21:06,858 DEBUG [org.hibernate.stat.internal.ConcurrentStatisticsImpl] (default task-41) HHH000117: HQL: select t from AuditTaskImpl t where t.taskId = :taskId, time: 6ms, rows: 1
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Показатели hibernate сессий
|
||||||
|
|
||||||
|
Включаются категорией `org.hibernate.engine.internal.StatisticalLoggingSessionEventListener` в `info`.
|
||||||
|
При этом в hibernate должен быть включен сбор статистики. Тут может быть интересно количество запросов, флашей и общее время на все запросы сессией.
|
||||||
|
|
||||||
|
Пример вывода:
|
||||||
|
|
||||||
|
```
|
||||||
|
2017-12-04 17:25:58,493 INFO [org.hibernate.engine.internal.StatisticalLoggingSessionEventListener] (default task-21) Session Metrics {
|
||||||
|
63408365 nanoseconds spent acquiring 17 JDBC connections;
|
||||||
|
521509 nanoseconds spent releasing 17 JDBC connections;
|
||||||
|
65732621 nanoseconds spent preparing 17 JDBC statements;
|
||||||
|
31471897 nanoseconds spent executing 17 JDBC statements;
|
||||||
|
0 nanoseconds spent executing 0 JDBC batches;
|
||||||
|
0 nanoseconds spent performing 0 L2C puts;
|
||||||
|
0 nanoseconds spent performing 0 L2C hits;
|
||||||
|
0 nanoseconds spent performing 0 L2C misses;
|
||||||
|
297556 nanoseconds spent executing 1 flushes (flushing a total of 16 entities and 0 collections);
|
||||||
|
430168 nanoseconds spent executing 1 partial-flushes (flushing a total of 16 entities and 16 collections)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Логирование hbm2ddl
|
||||||
|
|
||||||
|
**Рекомендованное использование:** всегда в `trace`.
|
||||||
|
|
||||||
|
Должно быть включено всегда. Позволяет убедиться что hibernate не накатывал никакие миграции на базу. Этот функционал отключен у нас в коде.
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<logger category="org.hibernate.tool.hbm2ddl">
|
||||||
|
<level name="TRACE"/>
|
||||||
|
</logger>
|
||||||
|
```
|
||||||
|
|
||||||
|
# Описание параметров конфигурации клиентской части
|
||||||
|
|
||||||
|
Свойства задаются в файле frontend/src/resources/app-config.json или frontend.war/src/resources/app-config.json
|
||||||
|
|
||||||
|
## Общие
|
||||||
|
|
||||||
|
- `dev_mode` - настройка задающая dev_mode для просмотра логов (true/false). При отсутствие оставляет значение при сборке
|
||||||
|
- `guard.confirm_exit` - выводить или нет диалог подтверждения, если обнаружены несохраненные данные в форме. Значение по умолчанию - false.
|
||||||
|
- `password.pattern` - Регулярное выражение для валидации пароля.
|
||||||
|
- `password_pattern_error` - Сообщение об ошибке валидации.
|
||||||
|
- `show.client.errors` - отвечает за отображение ошибок javascript-a пользователю (должна использоваться только в тестовых контурах) по умолчанию выключена
|
||||||
|
- 'available_task.single_fetch' - Отвечает за количество запросов available_task при завершении процесса. true - одиночный запрос, false/не указано - 10 запросов(старая реализация).
|
||||||
|
|
||||||
|
## Вывод сообщений
|
||||||
|
|
||||||
|
- `message_service_error_timeout` время в мс, в течение которого будет отображено сообщение об ошибке. Значение по умолчанию - таймаут не задан (окно не закрывается).
|
||||||
|
- `message_service_warning_timeout` время в мс, в течение которого будет отображено предупреждающее сообщение. Значение по умолчанию - таймаут не задан (окно не закрывается).
|
||||||
|
- `message_service_success_timeout` время в мс, в течение которого будет отображено сообщение об успехе. Значение по умолчанию - таймаут не задан (окно не закрывается).
|
||||||
|
- `message_service_info_timeout` время в мс, в течение которого будет отображено информационное сообщение. Значение по умолчанию - таймаут не задан (окно не закрывается).
|
||||||
|
|
||||||
|
## Электронная подпись
|
||||||
|
|
||||||
|
### Esmart
|
||||||
|
|
||||||
|
- `electronic_sign.esmart_extension_url` - url для создания расширенной подписи. Подробная информация по ссылке [http://demo.esmart.ru](http://demo.esmart.ru)
|
||||||
|
- `electronic_sign.tsp_address` - адрес сервера службы штампов времени
|
||||||
|
|
||||||
|
Пример:
|
||||||
|
|
||||||
|
```text
|
||||||
|
"electronic_sign.esmart_extension_url": "http://dsig.ibsdemo.ru/ibs_dsig/ibs_dSig.asmx"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Способ аутентификации
|
||||||
|
|
||||||
|
- `auth_method` - способ аутентификации. Может принимать одно значение из списка: form, kerberos, cert_over_db, cert_over_ldap
|
||||||
|
|
||||||
|
## Таймер очистки закешированных значений фильтров
|
||||||
|
|
||||||
|
- `filter_cleanup_interval_hours` - время жизни закешированного значения фильтра в часах. По умолчанию - 720 часов,
|
||||||
|
- `filter_cleanup_check_period_minutes` - период проверки наличия просроченных закешированных значений в минутах. По умолчанию - 30 минут
|
||||||
|
|
||||||
|
## Добавление версии приложения в URL при запросах к frontend-у
|
||||||
|
|
||||||
|
В модуле frontend в src/resources/app-config.json добавлены 2 переменные
|
||||||
|
|
||||||
|
- `"enable.version.in.url": "%enable.version.in.url%"` - подставлять ли версию в URL приложения. По умолчанию false. Если сборка произведена
|
||||||
|
- `"app.version": "%project.version%"` - версия приложения.
|
||||||
|
с профилем `enable-version-in-url`, то значение будет true.
|
||||||
|
|
||||||
|
## Добавление Jivo чат в проект
|
||||||
|
|
||||||
|
Свойства задаются в файле frontend/src/resources/app-config.json или frontend.war/src/resources/app-config.json
|
||||||
|
|
||||||
|
- `jivo_chat_widget_api_url` - API url для работы Jivo чата. Необходимо заменить {WIDGET_ID} на реальный Widget API ID
|
||||||
|
- `jivo_chat_widget_enabled` - параметр отвечающий за активацию Jivo чата. По дефолту false, для активации задать true.
|
||||||
|
|
||||||
|
Пример:
|
||||||
|
|
||||||
|
```json
|
||||||
|
"jivo_chat_widget_api_url": "https://code.jivo.ru/widget/{WIDGET_ID}",
|
||||||
|
"jivo_chat_widget_enabled": false
|
||||||
|
```
|
||||||
|
|
||||||
|
# Прочее
|
||||||
|
|
||||||
|
## Смена удалённого репозитория
|
||||||
|
|
||||||
|
1. Смените адрес NPM registry в файле frontend.npmrc. Пример - registry=https://repo.example.com/repository/npm-all/
|
||||||
|
2. Поменяйте ссылки в блоке , файла pom.xml
|
||||||
2
config/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
/*.ear
|
||||||
|
/*.jar
|
||||||
43
config/Dockerfile
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
FROM quay.io/wildfly/wildfly:26.1.3.Final-jdk17
|
||||||
|
USER root
|
||||||
|
ARG POSTGRES_DRIVER_VERSION=42.7.3
|
||||||
|
RUN yum-config-manager --disable base --disable extras --disable updates \
|
||||||
|
&& yum-config-manager --enable C7.8.2003-base --enable C7.8.2003-extras --enable C7.8.2003-updates \
|
||||||
|
&& yum -y --disableplugin=fastestmirror install sudo \
|
||||||
|
&& chown -R jboss: /opt/jboss/
|
||||||
|
|
||||||
|
USER jboss
|
||||||
|
WORKDIR $JBOSS_HOME
|
||||||
|
ENV JAVA_ARGS=-Xmx3g
|
||||||
|
RUN echo 'JAVA_OPTS="$JAVA_OPTS -agentlib:jdwp=transport=dt_socket,address=*:8787,server=y,suspend=n"' >> bin/standalone.conf && \
|
||||||
|
echo 'JAVA_OPTS="$JAVA_OPTS -XX:MaxMetaspaceSize=1g"' >> bin/standalone.conf && \
|
||||||
|
echo 'JAVA_OPTS="$JAVA_OPTS -XX:+UseStringDeduplication -XX:+ParallelRefProcEnabled -XX:+ExplicitGCInvokesConcurrent"' >> bin/standalone.conf && \
|
||||||
|
echo 'JAVA_OPTS="$JAVA_OPTS -XX:+UnlockDiagnosticVMOptions -XX:G1SummarizeRSetStatsPeriod=1"' >> bin/standalone.conf && \
|
||||||
|
echo 'JAVA_OPTS="$JAVA_OPTS -Dfile.encoding=UTF-8"' >> bin/standalone.conf && \
|
||||||
|
echo 'JAVA_OPTS="$JAVA_OPTS -XX:-OmitStackTraceInFastThrow"' >> bin/standalone.conf && \
|
||||||
|
echo 'JAVA_OPTS="$JAVA_OPTS -Dorg.jboss.logmanager.nocolor=true"' >> bin/standalone.conf && \
|
||||||
|
echo 'JAVA_OPTS="$JAVA_OPTS $JAVA_ARGS"' >> bin/standalone.conf
|
||||||
|
|
||||||
|
### Locale support ru_RU ###
|
||||||
|
USER root
|
||||||
|
RUN localedef -i ru_RU -f UTF-8 ru_RU.UTF-8
|
||||||
|
RUN echo "LANG=\"ru_RU.UTF-8\"" > /etc/locale.conf
|
||||||
|
USER jboss
|
||||||
|
ENV LANG ru_RU.UTF-8
|
||||||
|
ENV LANGUAGE ru_RU.UTF-8
|
||||||
|
ENV LC_ALL ru_RU.UTF-8
|
||||||
|
### Locale Support END ###
|
||||||
|
|
||||||
|
COPY --chown=jboss entrypoint.sh .
|
||||||
|
COPY --chown=jboss patches patches
|
||||||
|
RUN (cd patches && wget https://repo.micord.ru/repository/libs-releases-local/org/jboss/ironjacamar/ironjacamar-core-impl/1.5.3.Final/ironjacamar-core-impl-1.5.3.Final.jar)
|
||||||
|
RUN (cd patches/system && wget https://repo1.maven.org/maven2/org/postgresql/postgresql/$POSTGRES_DRIVER_VERSION/postgresql-$POSTGRES_DRIVER_VERSION.jar -O postgresql-driver.jar)
|
||||||
|
|
||||||
|
RUN chmod -R +x patches && \
|
||||||
|
chmod +x entrypoint.sh && \
|
||||||
|
./entrypoint.sh && \
|
||||||
|
rm -rf patches
|
||||||
|
|
||||||
|
ENV SERVER_START=true
|
||||||
|
COPY --chown=jboss *.ear $JBOSS_HOME/standalone/deployments/
|
||||||
|
COPY --chown=jboss *.war $JBOSS_HOME/standalone/deployments/
|
||||||
58
config/Dockerfile.build
Normal file
|
|
@ -0,0 +1,58 @@
|
||||||
|
FROM maven:3-openjdk-17-slim AS builder
|
||||||
|
RUN apt update \
|
||||||
|
&& apt upgrade -y \
|
||||||
|
&& curl -fsSL https://deb.nodesource.com/setup_14.x | bash - \
|
||||||
|
&& apt install -y git nodejs \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
COPY ../ .
|
||||||
|
RUN mvn clean \
|
||||||
|
&& mvn package -T4C \
|
||||||
|
&& cd config-data-executor \
|
||||||
|
&& mvn clean \
|
||||||
|
&& mvn package -T4C
|
||||||
|
|
||||||
|
FROM quay.io/wildfly/wildfly:26.1.3.Final-jdk17
|
||||||
|
USER root
|
||||||
|
ARG POSTGRES_DRIVER_VERSION=42.7.3
|
||||||
|
RUN yum-config-manager --disable base --disable extras --disable updates \
|
||||||
|
&& yum-config-manager --enable C7.8.2003-base --enable C7.8.2003-extras --enable C7.8.2003-updates \
|
||||||
|
&& yum -y --disableplugin=fastestmirror install sudo \
|
||||||
|
&& chown -R jboss: /opt/jboss/
|
||||||
|
|
||||||
|
USER jboss
|
||||||
|
WORKDIR $JBOSS_HOME
|
||||||
|
ENV JAVA_ARGS=-Xmx3g
|
||||||
|
RUN echo 'JAVA_OPTS="$JAVA_OPTS -agentlib:jdwp=transport=dt_socket,address=*:8787,server=y,suspend=n"' >> bin/standalone.conf && \
|
||||||
|
echo 'JAVA_OPTS="$JAVA_OPTS -XX:MaxMetaspaceSize=1g"' >> bin/standalone.conf && \
|
||||||
|
echo 'JAVA_OPTS="$JAVA_OPTS -XX:+UseStringDeduplication -XX:+ParallelRefProcEnabled -XX:+ExplicitGCInvokesConcurrent"' >> bin/standalone.conf && \
|
||||||
|
echo 'JAVA_OPTS="$JAVA_OPTS -XX:+UnlockDiagnosticVMOptions -XX:G1SummarizeRSetStatsPeriod=1"' >> bin/standalone.conf && \
|
||||||
|
echo 'JAVA_OPTS="$JAVA_OPTS -Dfile.encoding=UTF-8"' >> bin/standalone.conf && \
|
||||||
|
echo 'JAVA_OPTS="$JAVA_OPTS -XX:-OmitStackTraceInFastThrow"' >> bin/standalone.conf && \
|
||||||
|
echo 'JAVA_OPTS="$JAVA_OPTS -Dorg.jboss.logmanager.nocolor=true"' >> bin/standalone.conf && \
|
||||||
|
echo 'JAVA_OPTS="$JAVA_OPTS $JAVA_ARGS"' >> bin/standalone.conf
|
||||||
|
|
||||||
|
### Locale support ru_RU ###
|
||||||
|
USER root
|
||||||
|
RUN localedef -i ru_RU -f UTF-8 ru_RU.UTF-8
|
||||||
|
RUN echo "LANG=\"ru_RU.UTF-8\"" > /etc/locale.conf
|
||||||
|
USER jboss
|
||||||
|
ENV LANG ru_RU.UTF-8
|
||||||
|
ENV LANGUAGE ru_RU.UTF-8
|
||||||
|
ENV LC_ALL ru_RU.UTF-8
|
||||||
|
### Locale Support END ###
|
||||||
|
|
||||||
|
COPY --chown=jboss config/entrypoint.sh .
|
||||||
|
COPY --chown=jboss config/patches patches
|
||||||
|
RUN (cd patches && wget https://repo.micord.ru/repository/libs-releases-local/org/jboss/ironjacamar/ironjacamar-core-impl/1.5.3.Final/ironjacamar-core-impl-1.5.3.Final.jar)
|
||||||
|
RUN (cd patches/system && wget https://repo1.maven.org/maven2/org/postgresql/postgresql/$POSTGRES_DRIVER_VERSION/postgresql-$POSTGRES_DRIVER_VERSION.jar -O postgresql-driver.jar)
|
||||||
|
|
||||||
|
RUN chmod -R +x patches && \
|
||||||
|
chmod +x entrypoint.sh && \
|
||||||
|
./entrypoint.sh && \
|
||||||
|
rm -rf patches
|
||||||
|
|
||||||
|
ENV SERVER_START=true
|
||||||
|
COPY --from=builder --chown=jboss /app/distribution/target/*.ear $JBOSS_HOME/standalone/deployments/
|
||||||
|
COPY --from=builder --chown=jboss /app/config-data-executor/target/*.war $JBOSS_HOME/standalone/deployments/
|
||||||
1
config/JDK_version
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
17
|
||||||
50
config/cde-xml/arangorequest.xml
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
<Requests>
|
||||||
|
<AqlRequest>
|
||||||
|
<RequestURL>
|
||||||
|
<![CDATA[
|
||||||
|
with edges
|
||||||
|
for edg IN edges
|
||||||
|
filter edg._key in ${argument}
|
||||||
|
remove edg IN edges
|
||||||
|
]]>
|
||||||
|
</RequestURL>
|
||||||
|
<RequestArgument type="AQL">
|
||||||
|
<RequestArgumentURL>
|
||||||
|
<![CDATA[
|
||||||
|
WITH applications, subject, history, edges
|
||||||
|
|
||||||
|
FOR app IN applications
|
||||||
|
FILTER app.statement.recruitsData.mainInfo[0].id IN @ids
|
||||||
|
LET parentEdges = (
|
||||||
|
FOR vertex, edge, path
|
||||||
|
IN 1..1
|
||||||
|
OUTBOUND app._id edges
|
||||||
|
OPTIONS { uniqueVertices: "path" }
|
||||||
|
FILTER edge.field IN ["applicant", "history", "interdepreq"]
|
||||||
|
RETURN { edgesId: edge._key, parent: DOCUMENT(vertex._id) }
|
||||||
|
)
|
||||||
|
RETURN {
|
||||||
|
applicationId: app._key,
|
||||||
|
edgesId: (FOR e IN parentEdges RETURN e.edgesId),
|
||||||
|
subjectId: (FOR e IN parentEdges FILTER e.parent.schema == "Subject" RETURN e.parent._key),
|
||||||
|
historyId: (FOR e IN parentEdges FILTER e.parent.schema == "History" RETURN e.parent._key),
|
||||||
|
interdepreqId: (FOR e IN parentEdges FILTER e.parent.schema == "Interdepreq" RETURN e.parent._key)
|
||||||
|
}
|
||||||
|
]]>
|
||||||
|
</RequestArgumentURL>
|
||||||
|
</RequestArgument>
|
||||||
|
<AqlRequestCollections>
|
||||||
|
<AqlRequestCollection type="read">applications</AqlRequestCollection>
|
||||||
|
<AqlRequestCollection type="read">subject</AqlRequestCollection>
|
||||||
|
<AqlRequestCollection type="read">history</AqlRequestCollection>
|
||||||
|
<AqlRequestCollection type="read, write">edges</AqlRequestCollection>
|
||||||
|
</AqlRequestCollections>
|
||||||
|
<AqlConnectionParams>
|
||||||
|
<Host>localhost</Host>
|
||||||
|
<Port>8529</Port>
|
||||||
|
<Username>root</Username>
|
||||||
|
<Password>test</Password>
|
||||||
|
<Database>_system</Database>
|
||||||
|
</AqlConnectionParams>
|
||||||
|
</AqlRequest>
|
||||||
|
</Requests>
|
||||||
167
config/cde-xml/block.xml
Normal file
|
|
@ -0,0 +1,167 @@
|
||||||
|
<Requests>
|
||||||
|
<SqlRequest>
|
||||||
|
<RequestURL>
|
||||||
|
<![CDATA[
|
||||||
|
DO
|
||||||
|
$$
|
||||||
|
begin
|
||||||
|
update recruits
|
||||||
|
set current_recruitment_id = '04047533-ee2d-4266-b656-e509a547f0e9'
|
||||||
|
,target_recruitment_id = '04047533-ee2d-4266-b656-e509a547f0e9'
|
||||||
|
,department_id_old = '04047533-ee2d-4266-b656-e509a547f0e9'
|
||||||
|
,system_pgs_status = '13'
|
||||||
|
,extra_info = jsonb_set(coalesce(extra_info,'{}'::jsonb), '{blocked}',
|
||||||
|
('{"cur":'|| coalesce('"'||current_recruitment_id::text||'"','null')||
|
||||||
|
',"trg":'|| coalesce('"'||target_recruitment_id::text||'"','null')||
|
||||||
|
',"dio":'|| coalesce('"'||department_id_old::text||'"','null')||
|
||||||
|
',"st":'|| coalesce('"'||system_pgs_status::text||'"','null')||'}')::jsonb
|
||||||
|
)
|
||||||
|
where id in ${endpointArguments};
|
||||||
|
end
|
||||||
|
$$;
|
||||||
|
]]>
|
||||||
|
</RequestURL>
|
||||||
|
<SqlConnectionParams>
|
||||||
|
<JdbcHost>10.10.31.118</JdbcHost>
|
||||||
|
<JdbcPort>5432</JdbcPort>
|
||||||
|
<JdbcUsername>ervu</JdbcUsername>
|
||||||
|
<JdbcPassword>ervu</JdbcPassword>
|
||||||
|
<JdbcDriverClassName>org.postgresql.Driver</JdbcDriverClassName>
|
||||||
|
<JdbcXaDataSourceClassName>org.postgresql.xa.PGXADataSource</JdbcXaDataSourceClassName>
|
||||||
|
<JdbcXaDataSourcePoolSize>50</JdbcXaDataSourcePoolSize>
|
||||||
|
<JdbcDatabase>person_registry</JdbcDatabase>
|
||||||
|
</SqlConnectionParams>
|
||||||
|
</SqlRequest>
|
||||||
|
|
||||||
|
<SqlRequest>
|
||||||
|
<RequestURL>
|
||||||
|
<![CDATA[
|
||||||
|
DO
|
||||||
|
$$
|
||||||
|
BEGIN
|
||||||
|
DELETE FROM subpoena_history where subpoena_id in (select id FROM subpoena where recruit_id in ${endpointArguments});
|
||||||
|
DELETE FROM subpoena_appearance where subpoena_id in (select id FROM subpoena where recruit_id in ${endpointArguments});
|
||||||
|
DELETE FROM subpoena_send_info where subpoena_id in (select id FROM subpoena where recruit_id in ${endpointArguments});
|
||||||
|
|
||||||
|
DELETE FROM notification_item where restriction_document_item_id in (
|
||||||
|
select id from restriction_document_item where restriction_document_create_id in (
|
||||||
|
select id FROM restriction_document where subpoena_id in (select id FROM subpoena where recruit_id in ${endpointArguments})));
|
||||||
|
DELETE FROM notification_item where restriction_document_item_id in (
|
||||||
|
select id from restriction_document_item where restriction_document_cancel_id in (
|
||||||
|
select id FROM restriction_document where subpoena_id in (select id FROM subpoena where recruit_id in ${endpointArguments})));
|
||||||
|
|
||||||
|
DELETE FROM restriction_document_item where restriction_document_create_id in (
|
||||||
|
select id FROM restriction_document where subpoena_id in (select id FROM subpoena where recruit_id in ${endpointArguments}));
|
||||||
|
DELETE FROM restriction_document_item where restriction_document_cancel_id in (
|
||||||
|
select id FROM restriction_document where subpoena_id in (select id FROM subpoena where recruit_id in ${endpointArguments}));
|
||||||
|
DELETE FROM restriction_document where subpoena_id in (select id FROM subpoena where recruit_id in ${endpointArguments});
|
||||||
|
DELETE FROM subpoena where recruit_id in ${endpointArguments};
|
||||||
|
END
|
||||||
|
$$;
|
||||||
|
]]>
|
||||||
|
</RequestURL>
|
||||||
|
<SqlConnectionParams>
|
||||||
|
<JdbcHost>10.10.31.118</JdbcHost>
|
||||||
|
<JdbcPort>5432</JdbcPort>
|
||||||
|
<JdbcUsername>ervu</JdbcUsername>
|
||||||
|
<JdbcPassword>ervu</JdbcPassword>
|
||||||
|
<JdbcDriverClassName>org.postgresql.Driver</JdbcDriverClassName>
|
||||||
|
<JdbcXaDataSourceClassName>org.postgresql.xa.PGXADataSource</JdbcXaDataSourceClassName>
|
||||||
|
<JdbcXaDataSourcePoolSize>50</JdbcXaDataSourcePoolSize>
|
||||||
|
<JdbcDatabase>subpoena</JdbcDatabase>
|
||||||
|
</SqlConnectionParams>
|
||||||
|
</SqlRequest>
|
||||||
|
|
||||||
|
<SqlRequest>
|
||||||
|
<RequestURL>
|
||||||
|
<![CDATA[
|
||||||
|
DO
|
||||||
|
$$
|
||||||
|
BEGIN
|
||||||
|
DELETE
|
||||||
|
FROM incident_history
|
||||||
|
where incident_id in (select id from incident where recruit_id in ${endpointArguments});
|
||||||
|
DELETE FROM incident where recruit_id in ${endpointArguments};
|
||||||
|
END
|
||||||
|
$$;
|
||||||
|
]]>
|
||||||
|
</RequestURL>
|
||||||
|
<SqlConnectionParams>
|
||||||
|
<JdbcHost>10.10.31.118</JdbcHost>
|
||||||
|
<JdbcPort>5432</JdbcPort>
|
||||||
|
<JdbcUsername>ervu</JdbcUsername>
|
||||||
|
<JdbcPassword>ervu</JdbcPassword>
|
||||||
|
<JdbcDriverClassName>org.postgresql.Driver</JdbcDriverClassName>
|
||||||
|
<JdbcXaDataSourceClassName>org.postgresql.xa.PGXADataSource</JdbcXaDataSourceClassName>
|
||||||
|
<JdbcXaDataSourcePoolSize>50</JdbcXaDataSourcePoolSize>
|
||||||
|
<JdbcDatabase>incidents</JdbcDatabase>
|
||||||
|
</SqlConnectionParams>
|
||||||
|
</SqlRequest>
|
||||||
|
|
||||||
|
<SqlRequest>
|
||||||
|
<RequestURL>
|
||||||
|
<![CDATA[
|
||||||
|
DO
|
||||||
|
$$
|
||||||
|
DECLARE
|
||||||
|
var1 uuid[] := '{
|
||||||
|
${endpointArguments}
|
||||||
|
}';
|
||||||
|
BEGIN
|
||||||
|
DELETE FROM notifications where recruit_id = any (var1);
|
||||||
|
END
|
||||||
|
$$;
|
||||||
|
]]>
|
||||||
|
</RequestURL>
|
||||||
|
<SqlConnectionParams>
|
||||||
|
<JdbcHost>10.10.31.118</JdbcHost>
|
||||||
|
<JdbcPort>5432</JdbcPort>
|
||||||
|
<JdbcUsername>ervu</JdbcUsername>
|
||||||
|
<JdbcPassword>ervu</JdbcPassword>
|
||||||
|
<JdbcDriverClassName>org.postgresql.Driver</JdbcDriverClassName>
|
||||||
|
<JdbcXaDataSourceClassName>org.postgresql.xa.PGXADataSource</JdbcXaDataSourceClassName>
|
||||||
|
<JdbcXaDataSourcePoolSize>50</JdbcXaDataSourcePoolSize>
|
||||||
|
<JdbcDatabase>geps_notifications</JdbcDatabase>
|
||||||
|
</SqlConnectionParams>
|
||||||
|
</SqlRequest>
|
||||||
|
|
||||||
|
<SqlRequest>
|
||||||
|
<RequestURL>
|
||||||
|
<![CDATA[
|
||||||
|
DO
|
||||||
|
$$
|
||||||
|
DECLARE
|
||||||
|
recruitIds uuid[] := ${endpointArguments};
|
||||||
|
importIds uuid[] := ARRAY(SELECT import_id
|
||||||
|
FROM import_results
|
||||||
|
WHERE recruit_id = ANY (recruitIds));
|
||||||
|
BEGIN
|
||||||
|
WITH ImportDeletes AS (DELETE FROM import_journal_start WHERE import_id = ANY (importIds) RETURNING journal_id)
|
||||||
|
DELETE
|
||||||
|
FROM journal
|
||||||
|
WHERE id IN (SELECT journal_id FROM ImportDeletes);
|
||||||
|
|
||||||
|
DELETE FROM import_journal_finish WHERE import_id = ANY (importIds);
|
||||||
|
DELETE FROM import_events_journal WHERE import_id = ANY (importIds);
|
||||||
|
DELETE FROM import_validation_errors WHERE import_id = ANY (importIds);
|
||||||
|
DELETE FROM import_results WHERE import_id = ANY (importIds);
|
||||||
|
DELETE FROM uploaded_files WHERE extra_info ->> 'importId' = ANY (importIds::text[]);
|
||||||
|
DELETE FROM object_history WHERE object_id = ANY (recruitIds);
|
||||||
|
DELETE FROM object_versions WHERE object_id = ANY (recruitIds);
|
||||||
|
END
|
||||||
|
$$;
|
||||||
|
]]>
|
||||||
|
</RequestURL>
|
||||||
|
<SqlConnectionParams>
|
||||||
|
<JdbcHost>10.10.31.118</JdbcHost>
|
||||||
|
<JdbcPort>5432</JdbcPort>
|
||||||
|
<JdbcUsername>ervu</JdbcUsername>
|
||||||
|
<JdbcPassword>ervu</JdbcPassword>
|
||||||
|
<JdbcDriverClassName>org.postgresql.Driver</JdbcDriverClassName>
|
||||||
|
<JdbcXaDataSourceClassName>org.postgresql.xa.PGXADataSource</JdbcXaDataSourceClassName>
|
||||||
|
<JdbcXaDataSourcePoolSize>50</JdbcXaDataSourcePoolSize>
|
||||||
|
<JdbcDatabase>journal_dev</JdbcDatabase>
|
||||||
|
</SqlConnectionParams>
|
||||||
|
</SqlRequest>
|
||||||
|
|
||||||
|
</Requests>
|
||||||
54
config/cde-xml/downloadCSV.xml
Normal file
|
|
@ -0,0 +1,54 @@
|
||||||
|
<Requests>
|
||||||
|
<DownloadRequest>
|
||||||
|
<DownloadRequestType>Type_A</DownloadRequestType>
|
||||||
|
<RequestURL>
|
||||||
|
Select system_id_ern from public.recruits where id in ${endpointArguments};
|
||||||
|
</RequestURL>
|
||||||
|
<SqlConnectionParams>
|
||||||
|
<JdbcHost>10.10.31.118</JdbcHost>
|
||||||
|
<JdbcPort>5432</JdbcPort>
|
||||||
|
<JdbcUsername>ervu</JdbcUsername>
|
||||||
|
<JdbcPassword>ervu</JdbcPassword>
|
||||||
|
<JdbcDriverClassName>org.postgresql.Driver</JdbcDriverClassName>
|
||||||
|
<JdbcXaDataSourceClassName>org.postgresql.xa.PGXADataSource</JdbcXaDataSourceClassName>
|
||||||
|
<JdbcXaDataSourcePoolSize>50</JdbcXaDataSourcePoolSize>
|
||||||
|
<JdbcDatabase>person_registry</JdbcDatabase>
|
||||||
|
<JdbcXaDataSourceBorrowConnectionTimeout>4000</JdbcXaDataSourceBorrowConnectionTimeout>
|
||||||
|
</SqlConnectionParams>
|
||||||
|
</DownloadRequest>
|
||||||
|
<DownloadRequest>
|
||||||
|
<DownloadRequestType>Type_B</DownloadRequestType>
|
||||||
|
<RequestURL>
|
||||||
|
Select system_id_ern from public.recruits where id in ${endpointArguments};
|
||||||
|
</RequestURL>
|
||||||
|
<SqlConnectionParams>
|
||||||
|
<JdbcHost>10.10.31.118</JdbcHost>
|
||||||
|
<JdbcPort>5432</JdbcPort>
|
||||||
|
<JdbcUsername>ervu</JdbcUsername>
|
||||||
|
<JdbcPassword>ervu</JdbcPassword>
|
||||||
|
<JdbcDriverClassName>org.postgresql.Driver</JdbcDriverClassName>
|
||||||
|
<JdbcXaDataSourceClassName>org.postgresql.xa.PGXADataSource</JdbcXaDataSourceClassName>
|
||||||
|
<JdbcXaDataSourcePoolSize>50</JdbcXaDataSourcePoolSize>
|
||||||
|
<JdbcDatabase>person_registry</JdbcDatabase>
|
||||||
|
<JdbcXaDataSourceBorrowConnectionTimeout>4000</JdbcXaDataSourceBorrowConnectionTimeout>
|
||||||
|
</SqlConnectionParams>
|
||||||
|
</DownloadRequest>
|
||||||
|
<DownloadRequest>
|
||||||
|
<DownloadRequestType>Type_C</DownloadRequestType>
|
||||||
|
<RequestURL>
|
||||||
|
Select system_id_ern from public.recruits where id in ${endpointArguments};
|
||||||
|
</RequestURL>
|
||||||
|
<SqlConnectionParams>
|
||||||
|
<JdbcHost>10.10.31.118</JdbcHost>
|
||||||
|
<JdbcPort>5432</JdbcPort>
|
||||||
|
<JdbcUsername>ervu</JdbcUsername>
|
||||||
|
<JdbcPassword>ervu</JdbcPassword>
|
||||||
|
<JdbcDriverClassName>org.postgresql.Driver</JdbcDriverClassName>
|
||||||
|
<JdbcXaDataSourceClassName>org.postgresql.xa.PGXADataSource</JdbcXaDataSourceClassName>
|
||||||
|
<JdbcXaDataSourcePoolSize>50</JdbcXaDataSourcePoolSize>
|
||||||
|
<JdbcDatabase>person_registry</JdbcDatabase>
|
||||||
|
<JdbcXaDataSourceBorrowConnectionTimeout>4000</JdbcXaDataSourceBorrowConnectionTimeout>
|
||||||
|
</SqlConnectionParams>
|
||||||
|
</DownloadRequest>
|
||||||
|
|
||||||
|
</Requests>
|
||||||
52
config/cde-xml/removeFromCallList.xml
Normal file
|
|
@ -0,0 +1,52 @@
|
||||||
|
<Requests>
|
||||||
|
<SqlRequest>
|
||||||
|
<RequestURL>
|
||||||
|
<![CDATA[
|
||||||
|
DO
|
||||||
|
$$
|
||||||
|
BEGIN
|
||||||
|
DELETE FROM summoned_list where recruit_id in ${endpointArguments};
|
||||||
|
DELETE FROM recruit_active_list where recruit_id in ${endpointArguments};
|
||||||
|
DELETE FROM documents where recruit_id in ${endpointArguments};
|
||||||
|
DELETE FROM subpoena where recruit_id in ${endpointArguments};
|
||||||
|
END
|
||||||
|
$$;
|
||||||
|
]]>
|
||||||
|
</RequestURL>
|
||||||
|
<SqlConnectionParams>
|
||||||
|
<JdbcHost>10.10.31.118</JdbcHost>
|
||||||
|
<JdbcPort>5432</JdbcPort>
|
||||||
|
<JdbcUsername>ervu</JdbcUsername>
|
||||||
|
<JdbcPassword>ervu</JdbcPassword>
|
||||||
|
<JdbcDriverClassName>org.postgresql.Driver</JdbcDriverClassName>
|
||||||
|
<JdbcXaDataSourceClassName>org.postgresql.xa.PGXADataSource</JdbcXaDataSourceClassName>
|
||||||
|
<JdbcXaDataSourcePoolSize>50</JdbcXaDataSourcePoolSize>
|
||||||
|
<JdbcDatabase>summon-list-registry</JdbcDatabase>
|
||||||
|
</SqlConnectionParams>
|
||||||
|
</SqlRequest>
|
||||||
|
|
||||||
|
<SqlRequest>
|
||||||
|
<RequestURL>
|
||||||
|
<![CDATA[
|
||||||
|
update recruits
|
||||||
|
set current_recruitment_id = jsonb_extract_path_text(extra_info,'blocked','cur')::uuid
|
||||||
|
,target_recruitment_id = jsonb_extract_path_text(extra_info,'blocked','trg')::uuid
|
||||||
|
,department_id_old = jsonb_extract_path_text(extra_info,'blocked','dio')::uuid
|
||||||
|
,system_pgs_status = '1.2'
|
||||||
|
,conscription = null
|
||||||
|
,extra_info = extra_info - ('blocked')
|
||||||
|
where id in ${endpointArguments};
|
||||||
|
]]>
|
||||||
|
</RequestURL>
|
||||||
|
<SqlConnectionParams>
|
||||||
|
<JdbcHost>10.10.31.118</JdbcHost>
|
||||||
|
<JdbcPort>5432</JdbcPort>
|
||||||
|
<JdbcUsername>ervu</JdbcUsername>
|
||||||
|
<JdbcPassword>ervu</JdbcPassword>
|
||||||
|
<JdbcDriverClassName>org.postgresql.Driver</JdbcDriverClassName>
|
||||||
|
<JdbcXaDataSourceClassName>org.postgresql.xa.PGXADataSource</JdbcXaDataSourceClassName>
|
||||||
|
<JdbcXaDataSourcePoolSize>50</JdbcXaDataSourcePoolSize>
|
||||||
|
<JdbcDatabase>person_registry</JdbcDatabase>
|
||||||
|
</SqlConnectionParams>
|
||||||
|
</SqlRequest>
|
||||||
|
</Requests>
|
||||||
244
config/cde-xml/removeFromSystem.xml
Normal file
|
|
@ -0,0 +1,244 @@
|
||||||
|
<Requests>
|
||||||
|
<!-- 002_2-ervu_subpoena_registry_delete_all_with_recruit -->
|
||||||
|
<SqlRequest>
|
||||||
|
<RequestURL>
|
||||||
|
<![CDATA[
|
||||||
|
DO
|
||||||
|
$$
|
||||||
|
BEGIN
|
||||||
|
DELETE FROM subpoena_history where subpoena_id in (select id FROM subpoena where recruit_id in ${endpointArguments});
|
||||||
|
DELETE FROM subpoena_appearance where subpoena_id in (select id FROM subpoena where recruit_id in ${endpointArguments});
|
||||||
|
DELETE FROM subpoena_send_info where subpoena_id in (select id FROM subpoena where recruit_id in ${endpointArguments});
|
||||||
|
|
||||||
|
DELETE FROM notification_item where restriction_document_item_id in (
|
||||||
|
select id from restriction_document_item where restriction_document_create_id in (
|
||||||
|
select id FROM restriction_document where subpoena_id in (select id FROM subpoena where recruit_id in ${endpointArguments})));
|
||||||
|
DELETE FROM notification_item where restriction_document_item_id in (
|
||||||
|
select id from restriction_document_item where restriction_document_cancel_id in (
|
||||||
|
select id FROM restriction_document where subpoena_id in (select id FROM subpoena where recruit_id in ${endpointArguments})));
|
||||||
|
|
||||||
|
DELETE FROM restriction_document_item_history WHERE recruit_id in ${endpointArguments};
|
||||||
|
DELETE FROM restriction_document_item where restriction_document_create_id in (
|
||||||
|
select id FROM restriction_document where subpoena_id in (select id FROM subpoena where recruit_id in ${endpointArguments}));
|
||||||
|
DELETE FROM restriction_document_item where restriction_document_cancel_id in (
|
||||||
|
select id FROM restriction_document where subpoena_id in (select id FROM subpoena where recruit_id in ${endpointArguments}));
|
||||||
|
DELETE FROM restriction_document where subpoena_id in (select id FROM subpoena where recruit_id in ${endpointArguments});
|
||||||
|
DELETE FROM subpoena where recruit_id in ${endpointArguments};
|
||||||
|
DELETE FROM recruits WHERE id in ${endpointArguments};
|
||||||
|
END
|
||||||
|
$$;
|
||||||
|
]]>
|
||||||
|
</RequestURL>
|
||||||
|
<SqlConnectionParams>
|
||||||
|
<JdbcHost>10.10.31.118</JdbcHost>
|
||||||
|
<JdbcPort>5432</JdbcPort>
|
||||||
|
<JdbcUsername>ervu</JdbcUsername>
|
||||||
|
<JdbcPassword>ervu</JdbcPassword>
|
||||||
|
<JdbcDriverClassName>org.postgresql.Driver</JdbcDriverClassName>
|
||||||
|
<JdbcXaDataSourceClassName>org.postgresql.xa.PGXADataSource</JdbcXaDataSourceClassName>
|
||||||
|
<JdbcXaDataSourcePoolSize>50</JdbcXaDataSourcePoolSize>
|
||||||
|
<JdbcDatabase>subpoena</JdbcDatabase>
|
||||||
|
</SqlConnectionParams>
|
||||||
|
</SqlRequest>
|
||||||
|
|
||||||
|
<!-- 005-ervu_decision_document-delete-recruit -->
|
||||||
|
<SqlRequest>
|
||||||
|
<RequestURL>
|
||||||
|
<![CDATA[
|
||||||
|
DO
|
||||||
|
$$
|
||||||
|
BEGIN
|
||||||
|
DELETE FROM decision where recruit_id in ${endpointArguments};
|
||||||
|
DELETE FROM foreign_decision where recruit_id in ${endpointArguments};
|
||||||
|
DELETE FROM infringement where recruit_id in ${endpointArguments};
|
||||||
|
DELETE FROM system_document where attachment_id in (SELECT id FROM attachment where recruit_id in ${endpointArguments}) ;
|
||||||
|
DELETE FROM attachment where recruit_id in ${endpointArguments};
|
||||||
|
DELETE FROM recruit where id in ${endpointArguments};
|
||||||
|
END
|
||||||
|
$$;
|
||||||
|
]]>
|
||||||
|
</RequestURL>
|
||||||
|
<SqlConnectionParams>
|
||||||
|
<JdbcHost>10.10.31.118</JdbcHost>
|
||||||
|
<JdbcPort>5432</JdbcPort>
|
||||||
|
<JdbcUsername>ervu</JdbcUsername>
|
||||||
|
<JdbcPassword>ervu</JdbcPassword>
|
||||||
|
<JdbcDriverClassName>org.postgresql.Driver</JdbcDriverClassName>
|
||||||
|
<JdbcXaDataSourceClassName>org.postgresql.xa.PGXADataSource</JdbcXaDataSourceClassName>
|
||||||
|
<JdbcXaDataSourcePoolSize>50</JdbcXaDataSourcePoolSize>
|
||||||
|
<JdbcDatabase>decision-document-service</JdbcDatabase>
|
||||||
|
</SqlConnectionParams>
|
||||||
|
</SqlRequest>
|
||||||
|
|
||||||
|
<!-- 004-ervu_journal-delete-recruit -->
|
||||||
|
<SqlRequest>
|
||||||
|
<RequestURL>
|
||||||
|
<![CDATA[
|
||||||
|
DO
|
||||||
|
$$
|
||||||
|
DECLARE
|
||||||
|
recruitIds uuid[] := ${endpointArguments};
|
||||||
|
importIds uuid[] := ARRAY(SELECT import_id
|
||||||
|
FROM import_results
|
||||||
|
WHERE recruit_id = ANY (recruitIds));
|
||||||
|
BEGIN
|
||||||
|
WITH ImportDeletes AS (DELETE FROM import_journal_start WHERE import_id = ANY (importIds) RETURNING journal_id)
|
||||||
|
DELETE
|
||||||
|
FROM journal
|
||||||
|
WHERE id IN (SELECT journal_id FROM ImportDeletes);
|
||||||
|
|
||||||
|
DELETE FROM import_journal_finish WHERE import_id = ANY (importIds);
|
||||||
|
DELETE FROM import_events_journal WHERE import_id = ANY (importIds);
|
||||||
|
DELETE FROM import_validation_errors WHERE import_id = ANY (importIds);
|
||||||
|
DELETE FROM import_results WHERE import_id = ANY (importIds);
|
||||||
|
DELETE FROM uploaded_files WHERE extra_info ->> 'importId' = ANY (importIds::text[]);
|
||||||
|
DELETE FROM object_history WHERE object_id = ANY (recruitIds);
|
||||||
|
DELETE FROM object_versions WHERE object_id = ANY (recruitIds);
|
||||||
|
END
|
||||||
|
$$;
|
||||||
|
]]>
|
||||||
|
</RequestURL>
|
||||||
|
<SqlConnectionParams>
|
||||||
|
<JdbcHost>10.10.31.118</JdbcHost>
|
||||||
|
<JdbcPort>5432</JdbcPort>
|
||||||
|
<JdbcUsername>ervu</JdbcUsername>
|
||||||
|
<JdbcPassword>ervu</JdbcPassword>
|
||||||
|
<JdbcDriverClassName>org.postgresql.Driver</JdbcDriverClassName>
|
||||||
|
<JdbcXaDataSourceClassName>org.postgresql.xa.PGXADataSource</JdbcXaDataSourceClassName>
|
||||||
|
<JdbcXaDataSourcePoolSize>50</JdbcXaDataSourcePoolSize>
|
||||||
|
<JdbcDatabase>journal_dev</JdbcDatabase>
|
||||||
|
</SqlConnectionParams>
|
||||||
|
</SqlRequest>
|
||||||
|
|
||||||
|
<!-- 008-ervu_geps_notifications-delete-recruit -->
|
||||||
|
<SqlRequest>
|
||||||
|
<RequestURL>
|
||||||
|
<![CDATA[
|
||||||
|
DO
|
||||||
|
$$
|
||||||
|
DECLARE
|
||||||
|
var1 uuid[] := '{
|
||||||
|
${endpointArguments}
|
||||||
|
}';
|
||||||
|
BEGIN
|
||||||
|
DELETE FROM notifications where recruit_id = any (var1);
|
||||||
|
END
|
||||||
|
$$;
|
||||||
|
]]>
|
||||||
|
</RequestURL>
|
||||||
|
<SqlConnectionParams>
|
||||||
|
<JdbcHost>10.10.31.118</JdbcHost>
|
||||||
|
<JdbcPort>5432</JdbcPort>
|
||||||
|
<JdbcUsername>ervu</JdbcUsername>
|
||||||
|
<JdbcPassword>ervu</JdbcPassword>
|
||||||
|
<JdbcDriverClassName>org.postgresql.Driver</JdbcDriverClassName>
|
||||||
|
<JdbcXaDataSourceClassName>org.postgresql.xa.PGXADataSource</JdbcXaDataSourceClassName>
|
||||||
|
<JdbcXaDataSourcePoolSize>50</JdbcXaDataSourcePoolSize>
|
||||||
|
<JdbcDatabase>geps_notifications</JdbcDatabase>
|
||||||
|
</SqlConnectionParams>
|
||||||
|
</SqlRequest>
|
||||||
|
|
||||||
|
<!-- 007_2-ervu_incidents-delete-all_of_recruit -->
|
||||||
|
<SqlRequest>
|
||||||
|
<RequestURL>
|
||||||
|
<![CDATA[
|
||||||
|
DO
|
||||||
|
$$
|
||||||
|
DECLARE
|
||||||
|
var1 uuid[] := '{
|
||||||
|
${endpointArguments}
|
||||||
|
}';
|
||||||
|
BEGIN
|
||||||
|
DELETE
|
||||||
|
FROM incident_history
|
||||||
|
where incident_id in (select id from incident where recruit_id = any (var1));
|
||||||
|
DELETE FROM incident where recruit_id = any (var1);
|
||||||
|
DELETE FROM recruits where id = any (var1);
|
||||||
|
END
|
||||||
|
$$;
|
||||||
|
]]>
|
||||||
|
</RequestURL>
|
||||||
|
<SqlConnectionParams>
|
||||||
|
<JdbcHost>10.10.31.118</JdbcHost>
|
||||||
|
<JdbcPort>5432</JdbcPort>
|
||||||
|
<JdbcUsername>ervu</JdbcUsername>
|
||||||
|
<JdbcPassword>ervu</JdbcPassword>
|
||||||
|
<JdbcDriverClassName>org.postgresql.Driver</JdbcDriverClassName>
|
||||||
|
<JdbcXaDataSourceClassName>org.postgresql.xa.PGXADataSource</JdbcXaDataSourceClassName>
|
||||||
|
<JdbcXaDataSourcePoolSize>50</JdbcXaDataSourcePoolSize>
|
||||||
|
<JdbcDatabase>incidents</JdbcDatabase>
|
||||||
|
</SqlConnectionParams>
|
||||||
|
</SqlRequest>
|
||||||
|
|
||||||
|
<!-- 001-ervu_person_registry-delete-recruit -->
|
||||||
|
<SqlRequest>
|
||||||
|
<RequestURL>
|
||||||
|
<![CDATA[
|
||||||
|
DO
|
||||||
|
$$
|
||||||
|
DECLARE
|
||||||
|
var1 uuid[] := '{
|
||||||
|
${endpointArguments}
|
||||||
|
}';
|
||||||
|
BEGIN
|
||||||
|
DELETE FROM recruits_info where recruit_id = any (var1);
|
||||||
|
-- DELETE FROM recruit_archive where recruit_id = any (var1);
|
||||||
|
DELETE FROM recruit_xml_data where recruit_id = any (var1);
|
||||||
|
DELETE FROM recruits_history where recruit_id = any (var1);
|
||||||
|
DELETE FROM application where recruit_id = any (var1);
|
||||||
|
DELETE FROM department_history where recruit_id = any (var1);
|
||||||
|
DELETE FROM documents where recruit_id = any (var1);
|
||||||
|
DELETE FROM decision where recruit_id = any (var1);
|
||||||
|
DELETE FROM personal_documents where recruit_id = any (var1);
|
||||||
|
DELETE FROM recruit_private_file where recruit_id = any (var1);
|
||||||
|
DELETE FROM system_documents where recruit_id = any (var1);
|
||||||
|
DELETE FROM system_document_dto where recruit_id = any (var1);
|
||||||
|
DELETE FROM subpoena_dto where recruit_id = any (var1);
|
||||||
|
DELETE FROM attachments where recruit_id = any (var1);
|
||||||
|
DELETE FROM summoned_list where recruit_id = any (var1);
|
||||||
|
DELETE FROM recruits where id = any (var1);
|
||||||
|
END
|
||||||
|
$$;
|
||||||
|
]]>
|
||||||
|
</RequestURL>
|
||||||
|
<SqlConnectionParams>
|
||||||
|
<JdbcHost>10.10.31.118</JdbcHost>
|
||||||
|
<JdbcPort>5432</JdbcPort>
|
||||||
|
<JdbcUsername>ervu</JdbcUsername>
|
||||||
|
<JdbcPassword>ervu</JdbcPassword>
|
||||||
|
<JdbcDriverClassName>org.postgresql.Driver</JdbcDriverClassName>
|
||||||
|
<JdbcXaDataSourceClassName>org.postgresql.xa.PGXADataSource</JdbcXaDataSourceClassName>
|
||||||
|
<JdbcXaDataSourcePoolSize>50</JdbcXaDataSourcePoolSize>
|
||||||
|
<JdbcDatabase>person_registry</JdbcDatabase>
|
||||||
|
</SqlConnectionParams>
|
||||||
|
</SqlRequest>
|
||||||
|
|
||||||
|
<!-- 009_1-ervu_appeal_document-delete-appeal-with-recruit -->
|
||||||
|
<SqlRequest>
|
||||||
|
<RequestURL>
|
||||||
|
<![CDATA[
|
||||||
|
DO
|
||||||
|
$$
|
||||||
|
DECLARE
|
||||||
|
var1 uuid[] := '{
|
||||||
|
${endpointArguments}
|
||||||
|
}';
|
||||||
|
BEGIN
|
||||||
|
DELETE FROM appeal_document where recruit_id = any (var1);
|
||||||
|
DELETE FROM recruit where id = any (var1);
|
||||||
|
END
|
||||||
|
$$;
|
||||||
|
]]>
|
||||||
|
</RequestURL>
|
||||||
|
<SqlConnectionParams>
|
||||||
|
<JdbcHost>10.10.31.118</JdbcHost>
|
||||||
|
<JdbcPort>5432</JdbcPort>
|
||||||
|
<JdbcUsername>ervu</JdbcUsername>
|
||||||
|
<JdbcPassword>ervu</JdbcPassword>
|
||||||
|
<JdbcDriverClassName>org.postgresql.Driver</JdbcDriverClassName>
|
||||||
|
<JdbcXaDataSourceClassName>org.postgresql.xa.PGXADataSource</JdbcXaDataSourceClassName>
|
||||||
|
<JdbcXaDataSourcePoolSize>50</JdbcXaDataSourcePoolSize>
|
||||||
|
<JdbcDatabase>appeal-document-service</JdbcDatabase>
|
||||||
|
</SqlConnectionParams>
|
||||||
|
</SqlRequest>
|
||||||
|
</Requests>
|
||||||
28
config/cde-xml/s3request.xml
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
<Requests>
|
||||||
|
<S3Request>
|
||||||
|
<RequestArgument>
|
||||||
|
<RequestArgumentURL>
|
||||||
|
select path from paths;
|
||||||
|
</RequestArgumentURL>
|
||||||
|
<RequestArgumentConnectionParams>
|
||||||
|
<JdbcHost>localhost</JdbcHost>
|
||||||
|
<JdbcPort>5432</JdbcPort>
|
||||||
|
<JdbcUsername>postgres</JdbcUsername>
|
||||||
|
<JdbcPassword>password</JdbcPassword>
|
||||||
|
<JdbcDriverClassName>org.postgresql.Driver</JdbcDriverClassName>
|
||||||
|
<JdbcXaDataSourceClassName>org.postgresql.xa.PGXADataSource</JdbcXaDataSourceClassName>
|
||||||
|
<JdbcXaDataSourcePoolSize>50</JdbcXaDataSourcePoolSize>
|
||||||
|
<JdbcDatabase>micord_test</JdbcDatabase>
|
||||||
|
</RequestArgumentConnectionParams>
|
||||||
|
</RequestArgument>
|
||||||
|
<S3ConnectionParams>
|
||||||
|
<S3Key>minioadmin</S3Key>
|
||||||
|
<S3Secret>minioadmin</S3Secret>
|
||||||
|
<Host>127.0.0.1</Host>
|
||||||
|
<Port>9000</Port>
|
||||||
|
<ContentType>application/octet-stream</ContentType>
|
||||||
|
<Method>DELETE</Method>
|
||||||
|
<Body></Body>
|
||||||
|
</S3ConnectionParams>
|
||||||
|
</S3Request>
|
||||||
|
</Requests>
|
||||||
32
config/cde-xml/unblock.xml
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
<Requests>
|
||||||
|
<SqlRequest>
|
||||||
|
<RequestURL>
|
||||||
|
<![CDATA[
|
||||||
|
DO
|
||||||
|
$$
|
||||||
|
begin
|
||||||
|
update recruits
|
||||||
|
set current_recruitment_id = jsonb_extract_path_text(extra_info,'blocked','cur')::uuid
|
||||||
|
,target_recruitment_id = jsonb_extract_path_text(extra_info,'blocked','trg')::uuid
|
||||||
|
,department_id_old = jsonb_extract_path_text(extra_info,'blocked','dio')::uuid
|
||||||
|
,system_pgs_status = '1.2'
|
||||||
|
,conscription = null
|
||||||
|
,extra_info = extra_info - ('blocked')
|
||||||
|
where id in ${endpointArguments};
|
||||||
|
end
|
||||||
|
$$;
|
||||||
|
]]>
|
||||||
|
</RequestURL>
|
||||||
|
<SqlConnectionParams>
|
||||||
|
<JdbcHost>10.10.31.118</JdbcHost>
|
||||||
|
<JdbcPort>5432</JdbcPort>
|
||||||
|
<JdbcUsername>ervu</JdbcUsername>
|
||||||
|
<JdbcPassword>ervu</JdbcPassword>
|
||||||
|
<JdbcDriverClassName>org.postgresql.Driver</JdbcDriverClassName>
|
||||||
|
<JdbcXaDataSourceClassName>org.postgresql.xa.PGXADataSource</JdbcXaDataSourceClassName>
|
||||||
|
<JdbcXaDataSourcePoolSize>50</JdbcXaDataSourcePoolSize>
|
||||||
|
<JdbcDatabase>person_registry</JdbcDatabase>
|
||||||
|
</SqlConnectionParams>
|
||||||
|
</SqlRequest>
|
||||||
|
|
||||||
|
</Requests>
|
||||||
20
config/db.env
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
# App datasource
|
||||||
|
DB_APP_NAME=ervu-eks
|
||||||
|
DB_APP_HOST=db
|
||||||
|
DB_APP_PORT=5432
|
||||||
|
DB_APP_USERNAME=ervu-eks
|
||||||
|
DB_APP_PASSWORD=ervu-eks
|
||||||
|
|
||||||
|
# Security datasource
|
||||||
|
DB_SEC_NAME=ervu-eks
|
||||||
|
DB_SEC_HOST=db
|
||||||
|
DB_SEC_PORT=5432
|
||||||
|
DB_SEC_USERNAME=ervu-eks-sec
|
||||||
|
DB_SEC_PASSWORD=ervu-eks-sec
|
||||||
|
|
||||||
|
# Person datasource
|
||||||
|
DB_PERSON_NAME=person_registry
|
||||||
|
DB_PERSON_HOST=10.10.31.118
|
||||||
|
DB_PERSON_PORT=5432
|
||||||
|
DB_PERSON_USERNAME=ervu
|
||||||
|
DB_PERSON_PASSWORD=ervu
|
||||||
31
config/docker-compose.db.yaml
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
version: "3"
|
||||||
|
services:
|
||||||
|
db:
|
||||||
|
image: postgres:15-bullseye
|
||||||
|
volumes:
|
||||||
|
- ./initdb.d:/docker-entrypoint-initdb.d
|
||||||
|
- db-data:/var/lib/postgresql/data
|
||||||
|
command:
|
||||||
|
- "--max_prepared_transactions=100"
|
||||||
|
ports:
|
||||||
|
- "127.0.0.1:5432:5432"
|
||||||
|
environment:
|
||||||
|
- POSTGRES_PASSWORD=supersecretpassword
|
||||||
|
- TZ="Europe/Moscow"
|
||||||
|
|
||||||
|
webbpm-app:
|
||||||
|
image: ervu-eks:latest
|
||||||
|
depends_on:
|
||||||
|
- db
|
||||||
|
ports:
|
||||||
|
- "127.0.0.1:9990:9990"
|
||||||
|
- "127.0.0.1:8080:8080"
|
||||||
|
volumes:
|
||||||
|
- ./cde-xml:/cde-xml
|
||||||
|
environment:
|
||||||
|
- TZ="Europe/Moscow"
|
||||||
|
env_file:
|
||||||
|
- db.env
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
db-data:
|
||||||
14
config/docker-compose.yaml
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
version: "3"
|
||||||
|
services:
|
||||||
|
webbpm-app:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
volumes:
|
||||||
|
- ./cde-xml:/cde-xml
|
||||||
|
ports:
|
||||||
|
- 8080
|
||||||
|
- 8787
|
||||||
|
- 9990
|
||||||
|
env_file:
|
||||||
|
- micord.env
|
||||||
48
config/entrypoint.sh
Normal file
|
|
@ -0,0 +1,48 @@
|
||||||
|
#! /bin/bash
|
||||||
|
set -e
|
||||||
|
|
||||||
|
function wait_for_server() {
|
||||||
|
until `$JBOSS_HOME/bin/jboss-cli.sh -c ":read-attribute(name=server-state)" 2> /dev/null | grep -q running`; do
|
||||||
|
echo "Retry ..."
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "dump environment variables to env.properties file"
|
||||||
|
printenv > env.properties
|
||||||
|
|
||||||
|
echo "starting JBoss"
|
||||||
|
nohup $JBOSS_HOME/bin/standalone.sh --admin-only 1>&2 2>/dev/null &
|
||||||
|
|
||||||
|
# running system patches
|
||||||
|
wait_for_server
|
||||||
|
$JBOSS_HOME/bin/jboss-cli.sh --connect --file="./patches/system/init.cli" --properties=env.properties
|
||||||
|
$JBOSS_HOME/bin/jboss-cli.sh --connect --file="./patches/system/add-postgresql-driver.cli" --properties=env.properties
|
||||||
|
bash "./patches/system/add-demo-user.sh"
|
||||||
|
|
||||||
|
# running project patches
|
||||||
|
find ./patches/ -type f -name '*.cli' -not -path './patches/system/*' -print0 |
|
||||||
|
while IFS= read -r -d '' f; do
|
||||||
|
wait_for_server
|
||||||
|
echo "running $f"
|
||||||
|
$JBOSS_HOME/bin/jboss-cli.sh --connect --file="$f" --properties=env.properties
|
||||||
|
done;
|
||||||
|
|
||||||
|
find ./patches/ -type f -name '*.sh' -not -path './patches/system/*' -print0 |
|
||||||
|
while IFS= read -r -d '' f; do
|
||||||
|
wait_for_server
|
||||||
|
echo "running $f"
|
||||||
|
bash "$f"
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "stopping JBoss"
|
||||||
|
wait_for_server
|
||||||
|
$JBOSS_HOME/bin/jboss-cli.sh --connect --command=:shutdown
|
||||||
|
|
||||||
|
if ! [[ -z $SERVER_START ]]; then
|
||||||
|
echo "starting JBoss in standalone"
|
||||||
|
sleep 10 # without this occurs error "address already in use"
|
||||||
|
/opt/jboss/wildfly/bin/standalone.sh -c standalone.xml -b 0.0.0.0 -bmanagement 0.0.0.0
|
||||||
|
else
|
||||||
|
echo "cleaning up JBoss logs"
|
||||||
|
rm -rf $JBOSS_HOME/standalone/log
|
||||||
|
fi
|
||||||
23
config/initdb.d/createdb.sql
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
CREATE ROLE "ervu-eks" WITH
|
||||||
|
LOGIN
|
||||||
|
NOSUPERUSER
|
||||||
|
INHERIT
|
||||||
|
NOCREATEDB
|
||||||
|
NOCREATEROLE
|
||||||
|
NOREPLICATION
|
||||||
|
PASSWORD 'ervu-eks';
|
||||||
|
|
||||||
|
CREATE ROLE "ervu-eks-sec" WITH
|
||||||
|
LOGIN
|
||||||
|
NOSUPERUSER
|
||||||
|
INHERIT
|
||||||
|
NOCREATEDB
|
||||||
|
NOCREATEROLE
|
||||||
|
NOREPLICATION
|
||||||
|
PASSWORD 'ervu-eks-sec';
|
||||||
|
|
||||||
|
CREATE DATABASE "ervu-eks"
|
||||||
|
WITH
|
||||||
|
OWNER = "ervu-eks";
|
||||||
|
|
||||||
|
GRANT CREATE ON DATABASE "ervu-eks" TO "ervu-eks-sec";
|
||||||
22
config/micord.env
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
TZ=Europe/Moscow
|
||||||
|
|
||||||
|
# App datasource
|
||||||
|
DB_APP_USERNAME=ervu-eks
|
||||||
|
DB_APP_PASSWORD=ervu-eks
|
||||||
|
DB_APP_HOST=10.10.31.118
|
||||||
|
DB_APP_PORT=5432
|
||||||
|
DB_APP_NAME=ervu-eks
|
||||||
|
|
||||||
|
# Security datasource
|
||||||
|
DB_SEC_USERNAME=ervu-eks-sec
|
||||||
|
DB_SEC_PASSWORD=ervu-eks-sec
|
||||||
|
DB_SEC_HOST=10.10.31.118
|
||||||
|
DB_SEC_PORT=5432
|
||||||
|
DB_SEC_NAME=ervu-eks
|
||||||
|
|
||||||
|
# Person datasource
|
||||||
|
DB_PERSON_USERNAME=ervu
|
||||||
|
DB_PERSON_PASSWORD=ervu
|
||||||
|
DB_PERSON_HOST=10.10.31.118
|
||||||
|
DB_PERSON_PORT=5432
|
||||||
|
DB_PERSON_NAME=person_registry
|
||||||
3
config/patches/add-logger-database.cli
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
/subsystem=logging/logger=org.jooq.tools:add()
|
||||||
|
/subsystem=logging/logger=org.jooq.tools:write-attribute(name=level, value=DEBUG)
|
||||||
|
/subsystem=logging/logger=org.jooq.tools:add-handler(name=CONSOLE)
|
||||||
68
config/patches/default.cli
Normal file
|
|
@ -0,0 +1,68 @@
|
||||||
|
xa-data-source add \
|
||||||
|
--name=AppDS \
|
||||||
|
--enabled=true \
|
||||||
|
--driver-name=postgresql \
|
||||||
|
--jndi-name=java:/webbpm/AppDS \
|
||||||
|
--user-name=${env.DB_APP_USERNAME:app_user} \
|
||||||
|
--password=${env.DB_APP_PASSWORD:apppassword} \
|
||||||
|
--use-ccm=true \
|
||||||
|
--valid-connection-checker-class-name=org.jboss.jca.adapters.jdbc.extensions.postgres.PostgreSQLValidConnectionChecker \
|
||||||
|
--validate-on-match=false \
|
||||||
|
--background-validation=true \
|
||||||
|
--background-validation-millis=5000 \
|
||||||
|
--exception-sorter-class-name=org.jboss.jca.adapters.jdbc.extensions.postgres.PostgreSQLExceptionSorter \
|
||||||
|
--statistics-enabled=true \
|
||||||
|
--max-pool-size=50 \
|
||||||
|
--query-timeout=300 \
|
||||||
|
--xa-datasource-properties=ServerName=${env.DB_APP_HOST:db},PortNumber=${env.DB_APP_PORT:5432},DatabaseName=${env.DB_APP_NAME:app}
|
||||||
|
|
||||||
|
xa-data-source add \
|
||||||
|
--name=SECURITYDS \
|
||||||
|
--enabled=true \
|
||||||
|
--driver-name=postgresql \
|
||||||
|
--jndi-name=java:/webbpm/security-ds \
|
||||||
|
--user-name=${env.DB_SEC_USERNAME:security_user} \
|
||||||
|
--password=${env.DB_SEC_PASSWORD:secpassword} \
|
||||||
|
--max-pool-size=70 \
|
||||||
|
--valid-connection-checker-class-name=org.jboss.jca.adapters.jdbc.extensions.postgres.PostgreSQLValidConnectionChecker \
|
||||||
|
--validate-on-match=false \
|
||||||
|
--background-validation=true \
|
||||||
|
--background-validation-millis=5000 \
|
||||||
|
--exception-sorter-class-name=org.jboss.jca.adapters.jdbc.extensions.postgres.PostgreSQLExceptionSorter \
|
||||||
|
--statistics-enabled=true \
|
||||||
|
--query-timeout=300 \
|
||||||
|
--xa-datasource-properties=ServerName=${env.DB_SEC_HOST:db},PortNumber=${env.DB_SEC_PORT:5432},DatabaseName=${env.DB_SEC_NAME:app}
|
||||||
|
|
||||||
|
data-source add \
|
||||||
|
--name=PERSONDS \
|
||||||
|
--enabled=true \
|
||||||
|
--driver-name=postgresql \
|
||||||
|
--connection-url=jdbc:postgresql://${env.DB_PERSON_HOST:db}:${env.DB_PERSON_PORT:5432}/${env.DB_PERSON_NAME:person_registry} \
|
||||||
|
--jndi-name=java:/webbpm/personRegistryDS \
|
||||||
|
--user-name=${env.DB_PERSON_USERNAME:ervu} \
|
||||||
|
--password=${env.DB_PERSON_PASSWORD:ervu} \
|
||||||
|
--valid-connection-checker-class-name=org.jboss.jca.adapters.jdbc.extensions.postgres.PostgreSQLValidConnectionChecker \
|
||||||
|
--validate-on-match=false \
|
||||||
|
--background-validation=true \
|
||||||
|
--background-validation-millis=5000 \
|
||||||
|
--exception-sorter-class-name=org.jboss.jca.adapters.jdbc.extensions.postgres.PostgreSQLExceptionSorter \
|
||||||
|
--statistics-enabled=true \
|
||||||
|
--query-timeout=300 \
|
||||||
|
--max-pool-size=10
|
||||||
|
|
||||||
|
/system-property=ldap.mapping.login.param:add(value=${env.WEBBPM_LDAP_LOGIN_ATTR:uid})
|
||||||
|
/system-property=ldap.mapping.org.code.param:add(value=${env.WEBBPM_LDAP_ORGANIZATION_ATTR:ou})
|
||||||
|
/system-property=jboss.as.management.blocking.timeout:add(value=900)
|
||||||
|
/subsystem=undertow/server=default-server/http-listener=default/:write-attribute(name=record-request-start-time,value=true)
|
||||||
|
/subsystem=undertow/server=default-server/host=default-host/setting=access-log:add(pattern=%h %t "%r" %s %b %D)
|
||||||
|
/system-property=webbpm.cache.hazelcast.hosts:add(value="127.0.0.1")
|
||||||
|
/system-property=webbpm.cache.hazelcast.outbound_port_definitions:add(value="5801-5820")
|
||||||
|
/system-property=webbpm.security.session.active.count:add(value="20")
|
||||||
|
/system-property=security.password.regex:add(value="^((?=(.*\\d){1,})(?=.*[a-zа-яё])(?=.*[A-ZА-ЯЁ]).{8,})$")
|
||||||
|
/system-property=gar.enable:add(value=false)
|
||||||
|
/system-property=fias.enable:add(value=false)
|
||||||
|
/system-property=bpmn.enable:add(value=false)
|
||||||
|
/system-property=config.data.executor.url:add(value="http://localhost:8080/config-data-executor/api")
|
||||||
|
/system-property=config.data.executor.socket.timeout:add(value="10")
|
||||||
|
/system-property=config.data.executor.connection.timeout:add(value="10")
|
||||||
|
/system-property=configDirectory:add(value="/cde-xml")
|
||||||
1
config/patches/system/add-demo-user.sh
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
$JBOSS_HOME/bin/add-user.sh demo@example.com demo
|
||||||
5
config/patches/system/add-postgresql-driver.cli
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
/subsystem=datasources/jdbc-driver=postgresql:add( \
|
||||||
|
driver-name="postgresql", \
|
||||||
|
driver-module-name="org.postgresql", \
|
||||||
|
driver-xa-datasource-class-name="org.postgresql.xa.PGXADataSource" \
|
||||||
|
)
|
||||||
14
config/patches/system/init.cli
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
/system-property=webbpm.mode:add(value=production)
|
||||||
|
/system-property=authentication.method:add(value=form)
|
||||||
|
/subsystem=undertow/configuration=filter/gzip=gzipFilter:add()
|
||||||
|
/subsystem=undertow/server=default-server/host=default-host/\
|
||||||
|
filter-ref=gzipFilter:add(predicate="exists('%{o,Content-Type}') and regex(pattern='(?:application/javascript|text/css|text/html|text/xml|application/json)(;.*)?', value=%{o,Content-Type}, full-match=true)")
|
||||||
|
/subsystem=undertow/configuration=filter/response-header=vary-header:add(header-name="Vary", header-value="Accept-Encoding")
|
||||||
|
/subsystem=undertow/server=default-server/host=default-host/filter-ref=vary-header:add()
|
||||||
|
/subsystem=undertow/server=default-server/http-listener=default/:write-attribute(name=max-post-size,value=${env.MAX_POST_SIZE:104857600})
|
||||||
|
data-source remove --name=ExampleDS
|
||||||
|
/subsystem=ee/service=default-bindings:remove
|
||||||
|
/system-property=jboss.bind.address.management:add(value=0.0.0.0)
|
||||||
|
/system-property=jboss.bind.address:add(value=0.0.0.0)
|
||||||
|
module add --name=org.postgresql --resources=./patches/system/postgresql-driver.jar --dependencies=javax.api,javax.transaction.api
|
||||||
|
shutdown --restart
|
||||||
590
config/standalone.xml
Normal file
|
|
@ -0,0 +1,590 @@
|
||||||
|
<?xml version="1.0" ?>
|
||||||
|
|
||||||
|
<server xmlns="urn:jboss:domain:19.0">
|
||||||
|
<extensions>
|
||||||
|
<extension module="org.jboss.as.clustering.infinispan"/>
|
||||||
|
<extension module="org.jboss.as.connector"/>
|
||||||
|
<extension module="org.jboss.as.deployment-scanner"/>
|
||||||
|
<extension module="org.jboss.as.ee"/>
|
||||||
|
<extension module="org.jboss.as.ejb3"/>
|
||||||
|
<extension module="org.jboss.as.jaxrs"/>
|
||||||
|
<extension module="org.jboss.as.jdr"/>
|
||||||
|
<extension module="org.jboss.as.jmx"/>
|
||||||
|
<extension module="org.jboss.as.jpa"/>
|
||||||
|
<extension module="org.jboss.as.jsf"/>
|
||||||
|
<extension module="org.jboss.as.logging"/>
|
||||||
|
<extension module="org.jboss.as.mail"/>
|
||||||
|
<extension module="org.jboss.as.naming"/>
|
||||||
|
<extension module="org.jboss.as.pojo"/>
|
||||||
|
<extension module="org.jboss.as.remoting"/>
|
||||||
|
<extension module="org.jboss.as.sar"/>
|
||||||
|
<extension module="org.jboss.as.transactions"/>
|
||||||
|
<extension module="org.jboss.as.webservices"/>
|
||||||
|
<extension module="org.jboss.as.weld"/>
|
||||||
|
<extension module="org.wildfly.extension.batch.jberet"/>
|
||||||
|
<extension module="org.wildfly.extension.bean-validation"/>
|
||||||
|
<extension module="org.wildfly.extension.clustering.web"/>
|
||||||
|
<extension module="org.wildfly.extension.core-management"/>
|
||||||
|
<extension module="org.wildfly.extension.discovery"/>
|
||||||
|
<extension module="org.wildfly.extension.ee-security"/>
|
||||||
|
<extension module="org.wildfly.extension.elytron"/>
|
||||||
|
<extension module="org.wildfly.extension.elytron-oidc-client"/>
|
||||||
|
<extension module="org.wildfly.extension.health"/>
|
||||||
|
<extension module="org.wildfly.extension.io"/>
|
||||||
|
<extension module="org.wildfly.extension.metrics"/>
|
||||||
|
<extension module="org.wildfly.extension.microprofile.config-smallrye"/>
|
||||||
|
<extension module="org.wildfly.extension.microprofile.jwt-smallrye"/>
|
||||||
|
<extension module="org.wildfly.extension.microprofile.opentracing-smallrye"/>
|
||||||
|
<extension module="org.wildfly.extension.request-controller"/>
|
||||||
|
<extension module="org.wildfly.extension.security.manager"/>
|
||||||
|
<extension module="org.wildfly.extension.undertow"/>
|
||||||
|
</extensions>
|
||||||
|
<system-properties>
|
||||||
|
<property name="webbpm.mode" value="production"/>
|
||||||
|
<property name="authentication.method" value="form"/>
|
||||||
|
<property name="jboss.bind.address.management" value="0.0.0.0"/>
|
||||||
|
<property name="jboss.bind.address" value="0.0.0.0"/>
|
||||||
|
<property name="ldap.mapping.login.param" value="${env.WEBBPM_LDAP_LOGIN_ATTR:uid}"/>
|
||||||
|
<property name="ldap.mapping.org.code.param" value="${env.WEBBPM_LDAP_ORGANIZATION_ATTR:ou}"/>
|
||||||
|
<property name="jboss.as.management.blocking.timeout" value="900"/>
|
||||||
|
<property name="webbpm.cache.hazelcast.hosts" value="127.0.0.1"/>
|
||||||
|
<property name="webbpm.cache.hazelcast.outbound_port_definitions" value="5801-5820"/>
|
||||||
|
<property name="webbpm.security.session.active.count" value="20"/>
|
||||||
|
<property name="security.password.regex" value="^((?=(.*\d){1,})(?=.*[a-zа-яё])(?=.*[A-ZА-ЯЁ]).{8,})$"/>
|
||||||
|
<property name="gar.enable" value="false"/>
|
||||||
|
<property name="fias.enable" value="false"/>
|
||||||
|
<property name="bpmn.enable" value="false"/>
|
||||||
|
<property name="com.arjuna.ats.arjuna.allowMultipleLastResources" value="true"/>
|
||||||
|
<property name="config.data.executor.url" value="http://localhost:8080/config-data-executor/api"/>
|
||||||
|
<property name="config.data.executor.socket.timeout" value="10"/>
|
||||||
|
<property name="config.data.executor.connection.timeout" value="10"/>
|
||||||
|
<property name="configDirectory" value="C:\work\ervu-secret\config-data-executor\config-examples"/>
|
||||||
|
</system-properties>
|
||||||
|
<management>
|
||||||
|
<audit-log>
|
||||||
|
<formatters>
|
||||||
|
<json-formatter name="json-formatter"/>
|
||||||
|
</formatters>
|
||||||
|
<handlers>
|
||||||
|
<file-handler name="file" formatter="json-formatter" path="audit-log.log" relative-to="jboss.server.data.dir"/>
|
||||||
|
</handlers>
|
||||||
|
<logger log-boot="true" log-read-only="false" enabled="false">
|
||||||
|
<handlers>
|
||||||
|
<handler name="file"/>
|
||||||
|
</handlers>
|
||||||
|
</logger>
|
||||||
|
</audit-log>
|
||||||
|
<management-interfaces>
|
||||||
|
<http-interface http-authentication-factory="management-http-authentication">
|
||||||
|
<http-upgrade enabled="true" sasl-authentication-factory="management-sasl-authentication"/>
|
||||||
|
<socket-binding http="management-http"/>
|
||||||
|
</http-interface>
|
||||||
|
</management-interfaces>
|
||||||
|
<access-control provider="simple">
|
||||||
|
<role-mapping>
|
||||||
|
<role name="SuperUser">
|
||||||
|
<include>
|
||||||
|
<user name="$local"/>
|
||||||
|
</include>
|
||||||
|
</role>
|
||||||
|
</role-mapping>
|
||||||
|
</access-control>
|
||||||
|
</management>
|
||||||
|
<profile>
|
||||||
|
<subsystem xmlns="urn:jboss:domain:logging:8.0">
|
||||||
|
<console-handler name="CONSOLE">
|
||||||
|
<level name="INFO"/>
|
||||||
|
<formatter>
|
||||||
|
<named-formatter name="COLOR-PATTERN"/>
|
||||||
|
</formatter>
|
||||||
|
</console-handler>
|
||||||
|
<periodic-rotating-file-handler name="FILE" autoflush="true">
|
||||||
|
<formatter>
|
||||||
|
<named-formatter name="PATTERN"/>
|
||||||
|
</formatter>
|
||||||
|
<file relative-to="jboss.server.log.dir" path="server.log"/>
|
||||||
|
<suffix value=".yyyy-MM-dd"/>
|
||||||
|
<append value="true"/>
|
||||||
|
</periodic-rotating-file-handler>
|
||||||
|
<logger category="com.arjuna">
|
||||||
|
<level name="WARN"/>
|
||||||
|
</logger>
|
||||||
|
<logger category="io.jaegertracing.Configuration">
|
||||||
|
<level name="WARN"/>
|
||||||
|
</logger>
|
||||||
|
<logger category="org.jboss.as.config">
|
||||||
|
<level name="DEBUG"/>
|
||||||
|
</logger>
|
||||||
|
<logger category="sun.rmi">
|
||||||
|
<level name="WARN"/>
|
||||||
|
</logger>
|
||||||
|
<logger category="org.jooq.tools">
|
||||||
|
<level name="DEBUG"/>
|
||||||
|
<handlers>
|
||||||
|
<handler name="CONSOLE"/>
|
||||||
|
</handlers>
|
||||||
|
</logger>
|
||||||
|
<root-logger>
|
||||||
|
<level name="INFO"/>
|
||||||
|
<handlers>
|
||||||
|
<handler name="CONSOLE"/>
|
||||||
|
<handler name="FILE"/>
|
||||||
|
</handlers>
|
||||||
|
</root-logger>
|
||||||
|
<formatter name="PATTERN">
|
||||||
|
<pattern-formatter pattern="%d{yyyy-MM-dd HH:mm:ss,SSS} %-5p [%c] (%t) %s%e%n"/>
|
||||||
|
</formatter>
|
||||||
|
<formatter name="COLOR-PATTERN">
|
||||||
|
<pattern-formatter pattern="%K{level}%d{HH:mm:ss,SSS} %-5p [%c] (%t) %s%e%n"/>
|
||||||
|
</formatter>
|
||||||
|
</subsystem>
|
||||||
|
<subsystem xmlns="urn:jboss:domain:batch-jberet:3.0">
|
||||||
|
<default-job-repository name="in-memory"/>
|
||||||
|
<default-thread-pool name="batch"/>
|
||||||
|
<job-repository name="in-memory">
|
||||||
|
<in-memory/>
|
||||||
|
</job-repository>
|
||||||
|
<thread-pool name="batch">
|
||||||
|
<max-threads count="10"/>
|
||||||
|
<keepalive-time time="30" unit="seconds"/>
|
||||||
|
</thread-pool>
|
||||||
|
</subsystem>
|
||||||
|
<subsystem xmlns="urn:jboss:domain:bean-validation:1.0"/>
|
||||||
|
<subsystem xmlns="urn:jboss:domain:core-management:1.0"/>
|
||||||
|
<subsystem xmlns="urn:jboss:domain:datasources:7.0">
|
||||||
|
<datasources>
|
||||||
|
<xa-datasource jndi-name="java:/webbpm/AppDS" pool-name="AppDS" enabled="true" use-java-context="true">
|
||||||
|
<xa-datasource-property name="ServerName">10.10.31.118</xa-datasource-property>
|
||||||
|
<xa-datasource-property name="PortNumber">5432</xa-datasource-property>
|
||||||
|
<xa-datasource-property name="DatabaseName">ervu-eks</xa-datasource-property>
|
||||||
|
<driver>postgresql</driver>
|
||||||
|
<security>
|
||||||
|
<user-name>ervu-eks</user-name>
|
||||||
|
<password>ervu-eks</password>
|
||||||
|
</security>
|
||||||
|
<validation>
|
||||||
|
<valid-connection-checker class-name="org.jboss.jca.adapters.jdbc.extensions.postgres.PostgreSQLValidConnectionChecker" />
|
||||||
|
<validate-on-match>false</validate-on-match>
|
||||||
|
<background-validation>true</background-validation>
|
||||||
|
<background-validation-millis>5000</background-validation-millis>
|
||||||
|
<exception-sorter class-name="org.jboss.jca.adapters.jdbc.extensions.postgres.PostgreSQLExceptionSorter" />
|
||||||
|
</validation>
|
||||||
|
</xa-datasource>
|
||||||
|
<xa-datasource jndi-name="java:/webbpm/security-ds" pool-name="SECURITYDS" enabled="true" use-java-context="true">
|
||||||
|
<xa-datasource-property name="ServerName">10.10.31.118</xa-datasource-property>
|
||||||
|
<xa-datasource-property name="PortNumber">5432</xa-datasource-property>
|
||||||
|
<xa-datasource-property name="DatabaseName">ervu-eks</xa-datasource-property>
|
||||||
|
<driver>postgresql</driver>
|
||||||
|
<security>
|
||||||
|
<user-name>ervu-eks-sec</user-name>
|
||||||
|
<password>ervu-eks-sec</password>
|
||||||
|
</security>
|
||||||
|
<validation>
|
||||||
|
<valid-connection-checker class-name="org.jboss.jca.adapters.jdbc.extensions.postgres.PostgreSQLValidConnectionChecker" />
|
||||||
|
<validate-on-match>false</validate-on-match>
|
||||||
|
<background-validation>true</background-validation>
|
||||||
|
<background-validation-millis>5000</background-validation-millis>
|
||||||
|
<exception-sorter class-name="org.jboss.jca.adapters.jdbc.extensions.postgres.PostgreSQLExceptionSorter" />
|
||||||
|
</validation>
|
||||||
|
</xa-datasource>
|
||||||
|
<!-- -->
|
||||||
|
<datasource jndi-name="java:/webbpm/personRegistryDS" pool-name="personRegistryDS" enabled="true" use-java-context="true">
|
||||||
|
<connection-url>jdbc:postgresql://10.10.31.118:5432/person_registry</connection-url>
|
||||||
|
<driver>postgresql</driver>
|
||||||
|
<security>
|
||||||
|
<user-name>ervu</user-name>
|
||||||
|
<password>ervu</password>
|
||||||
|
</security>
|
||||||
|
<validation>
|
||||||
|
<valid-connection-checker class-name="org.jboss.jca.adapters.jdbc.extensions.postgres.PostgreSQLValidConnectionChecker"/>
|
||||||
|
<validate-on-match>false</validate-on-match>
|
||||||
|
<background-validation>true</background-validation>
|
||||||
|
<background-validation-millis>5000</background-validation-millis>
|
||||||
|
<exception-sorter class-name="org.jboss.jca.adapters.jdbc.extensions.postgres.PostgreSQLExceptionSorter"/>
|
||||||
|
</validation>
|
||||||
|
<timeout>
|
||||||
|
<query-timeout>300</query-timeout>
|
||||||
|
</timeout>
|
||||||
|
</datasource>
|
||||||
|
<drivers>
|
||||||
|
<driver name="h2" module="com.h2database.h2">
|
||||||
|
<xa-datasource-class>org.h2.jdbcx.JdbcDataSource</xa-datasource-class>
|
||||||
|
</driver>
|
||||||
|
<driver name="postgresql" module="org.postgresql">
|
||||||
|
<xa-datasource-class>org.postgresql.xa.PGXADataSource</xa-datasource-class>
|
||||||
|
</driver>
|
||||||
|
</drivers>
|
||||||
|
</datasources>
|
||||||
|
</subsystem>
|
||||||
|
<subsystem xmlns="urn:jboss:domain:deployment-scanner:2.0">
|
||||||
|
<deployment-scanner path="deployments" relative-to="jboss.server.base.dir" scan-interval="5000" runtime-failure-causes-rollback="${jboss.deployment.scanner.rollback.on.failure:false}"/>
|
||||||
|
</subsystem>
|
||||||
|
<subsystem xmlns="urn:jboss:domain:discovery:1.0"/>
|
||||||
|
<subsystem xmlns="urn:jboss:domain:distributable-web:2.0" default-session-management="default" default-single-sign-on-management="default">
|
||||||
|
<infinispan-session-management name="default" cache-container="web" granularity="SESSION">
|
||||||
|
<local-affinity/>
|
||||||
|
</infinispan-session-management>
|
||||||
|
<infinispan-single-sign-on-management name="default" cache-container="web" cache="sso"/>
|
||||||
|
<local-routing/>
|
||||||
|
</subsystem>
|
||||||
|
<subsystem xmlns="urn:jboss:domain:ee:6.0">
|
||||||
|
<spec-descriptor-property-replacement>false</spec-descriptor-property-replacement>
|
||||||
|
<concurrent>
|
||||||
|
<context-services>
|
||||||
|
<context-service name="default" jndi-name="java:jboss/ee/concurrency/context/default" use-transaction-setup-provider="true"/>
|
||||||
|
</context-services>
|
||||||
|
<managed-thread-factories>
|
||||||
|
<managed-thread-factory name="default" jndi-name="java:jboss/ee/concurrency/factory/default" context-service="default"/>
|
||||||
|
</managed-thread-factories>
|
||||||
|
<managed-executor-services>
|
||||||
|
<managed-executor-service name="default" jndi-name="java:jboss/ee/concurrency/executor/default" context-service="default" hung-task-termination-period="0" hung-task-threshold="60000" keepalive-time="5000"/>
|
||||||
|
</managed-executor-services>
|
||||||
|
<managed-scheduled-executor-services>
|
||||||
|
<managed-scheduled-executor-service name="default" jndi-name="java:jboss/ee/concurrency/scheduler/default" context-service="default" hung-task-termination-period="0" hung-task-threshold="60000" keepalive-time="3000"/>
|
||||||
|
</managed-scheduled-executor-services>
|
||||||
|
</concurrent>
|
||||||
|
</subsystem>
|
||||||
|
<subsystem xmlns="urn:jboss:domain:ee-security:1.0"/>
|
||||||
|
<subsystem xmlns="urn:jboss:domain:ejb3:9.0">
|
||||||
|
<session-bean>
|
||||||
|
<stateless>
|
||||||
|
<bean-instance-pool-ref pool-name="slsb-strict-max-pool"/>
|
||||||
|
</stateless>
|
||||||
|
<stateful default-access-timeout="5000" cache-ref="simple" passivation-disabled-cache-ref="simple"/>
|
||||||
|
<singleton default-access-timeout="5000"/>
|
||||||
|
</session-bean>
|
||||||
|
<pools>
|
||||||
|
<bean-instance-pools>
|
||||||
|
<strict-max-pool name="mdb-strict-max-pool" derive-size="from-cpu-count" instance-acquisition-timeout="5" instance-acquisition-timeout-unit="MINUTES"/>
|
||||||
|
<strict-max-pool name="slsb-strict-max-pool" derive-size="from-worker-pools" instance-acquisition-timeout="5" instance-acquisition-timeout-unit="MINUTES"/>
|
||||||
|
</bean-instance-pools>
|
||||||
|
</pools>
|
||||||
|
<caches>
|
||||||
|
<cache name="simple"/>
|
||||||
|
<cache name="distributable" passivation-store-ref="infinispan" aliases="passivating clustered"/>
|
||||||
|
</caches>
|
||||||
|
<passivation-stores>
|
||||||
|
<passivation-store name="infinispan" cache-container="ejb" max-size="10000"/>
|
||||||
|
</passivation-stores>
|
||||||
|
<async thread-pool-name="default"/>
|
||||||
|
<timer-service thread-pool-name="default" default-data-store="default-file-store">
|
||||||
|
<data-stores>
|
||||||
|
<file-data-store name="default-file-store" path="timer-service-data" relative-to="jboss.server.data.dir"/>
|
||||||
|
</data-stores>
|
||||||
|
</timer-service>
|
||||||
|
<remote cluster="ejb" connectors="http-remoting-connector" thread-pool-name="default">
|
||||||
|
<channel-creation-options>
|
||||||
|
<option name="MAX_OUTBOUND_MESSAGES" value="1234" type="remoting"/>
|
||||||
|
</channel-creation-options>
|
||||||
|
</remote>
|
||||||
|
<thread-pools>
|
||||||
|
<thread-pool name="default">
|
||||||
|
<max-threads count="10"/>
|
||||||
|
<keepalive-time time="60" unit="seconds"/>
|
||||||
|
</thread-pool>
|
||||||
|
</thread-pools>
|
||||||
|
<default-security-domain value="other"/>
|
||||||
|
<application-security-domains>
|
||||||
|
<application-security-domain name="other" security-domain="ApplicationDomain"/>
|
||||||
|
</application-security-domains>
|
||||||
|
<default-missing-method-permissions-deny-access value="true"/>
|
||||||
|
<statistics enabled="${wildfly.ejb3.statistics-enabled:${wildfly.statistics-enabled:false}}"/>
|
||||||
|
<log-system-exceptions value="true"/>
|
||||||
|
</subsystem>
|
||||||
|
<subsystem xmlns="urn:wildfly:elytron:15.1" final-providers="combined-providers" disallowed-providers="OracleUcrypto">
|
||||||
|
<providers>
|
||||||
|
<aggregate-providers name="combined-providers">
|
||||||
|
<providers name="elytron"/>
|
||||||
|
<providers name="openssl"/>
|
||||||
|
</aggregate-providers>
|
||||||
|
<provider-loader name="elytron" module="org.wildfly.security.elytron"/>
|
||||||
|
<provider-loader name="openssl" module="org.wildfly.openssl"/>
|
||||||
|
</providers>
|
||||||
|
<audit-logging>
|
||||||
|
<file-audit-log name="local-audit" path="audit.log" relative-to="jboss.server.log.dir" format="JSON"/>
|
||||||
|
</audit-logging>
|
||||||
|
<security-domains>
|
||||||
|
<security-domain name="ManagementDomain" default-realm="ManagementRealm" permission-mapper="default-permission-mapper">
|
||||||
|
<realm name="ManagementRealm" role-decoder="groups-to-roles"/>
|
||||||
|
<realm name="local" role-mapper="super-user-mapper"/>
|
||||||
|
</security-domain>
|
||||||
|
<security-domain name="ApplicationDomain" default-realm="ApplicationRealm" permission-mapper="default-permission-mapper">
|
||||||
|
<realm name="ApplicationRealm" role-decoder="groups-to-roles"/>
|
||||||
|
<realm name="local"/>
|
||||||
|
</security-domain>
|
||||||
|
</security-domains>
|
||||||
|
<security-realms>
|
||||||
|
<identity-realm name="local" identity="$local"/>
|
||||||
|
<properties-realm name="ApplicationRealm">
|
||||||
|
<users-properties path="application-users.properties" relative-to="jboss.server.config.dir" digest-realm-name="ApplicationRealm"/>
|
||||||
|
<groups-properties path="application-roles.properties" relative-to="jboss.server.config.dir"/>
|
||||||
|
</properties-realm>
|
||||||
|
<properties-realm name="ManagementRealm">
|
||||||
|
<users-properties path="mgmt-users.properties" relative-to="jboss.server.config.dir" digest-realm-name="ManagementRealm"/>
|
||||||
|
<groups-properties path="mgmt-groups.properties" relative-to="jboss.server.config.dir"/>
|
||||||
|
</properties-realm>
|
||||||
|
</security-realms>
|
||||||
|
<mappers>
|
||||||
|
<simple-permission-mapper name="default-permission-mapper" mapping-mode="first">
|
||||||
|
<permission-mapping>
|
||||||
|
<principal name="anonymous"/>
|
||||||
|
<permission-set name="default-permissions"/>
|
||||||
|
</permission-mapping>
|
||||||
|
<permission-mapping match-all="true">
|
||||||
|
<permission-set name="login-permission"/>
|
||||||
|
<permission-set name="default-permissions"/>
|
||||||
|
</permission-mapping>
|
||||||
|
</simple-permission-mapper>
|
||||||
|
<constant-realm-mapper name="local" realm-name="local"/>
|
||||||
|
<simple-role-decoder name="groups-to-roles" attribute="groups"/>
|
||||||
|
<constant-role-mapper name="super-user-mapper">
|
||||||
|
<role name="SuperUser"/>
|
||||||
|
</constant-role-mapper>
|
||||||
|
</mappers>
|
||||||
|
<permission-sets>
|
||||||
|
<permission-set name="login-permission">
|
||||||
|
<permission class-name="org.wildfly.security.auth.permission.LoginPermission"/>
|
||||||
|
</permission-set>
|
||||||
|
<permission-set name="default-permissions">
|
||||||
|
<permission class-name="org.wildfly.extension.batch.jberet.deployment.BatchPermission" module="org.wildfly.extension.batch.jberet" target-name="*"/>
|
||||||
|
<permission class-name="org.wildfly.transaction.client.RemoteTransactionPermission" module="org.wildfly.transaction.client"/>
|
||||||
|
<permission class-name="org.jboss.ejb.client.RemoteEJBPermission" module="org.jboss.ejb-client"/>
|
||||||
|
</permission-set>
|
||||||
|
</permission-sets>
|
||||||
|
<http>
|
||||||
|
<http-authentication-factory name="management-http-authentication" security-domain="ManagementDomain" http-server-mechanism-factory="global">
|
||||||
|
<mechanism-configuration>
|
||||||
|
<mechanism mechanism-name="DIGEST">
|
||||||
|
<mechanism-realm realm-name="ManagementRealm"/>
|
||||||
|
</mechanism>
|
||||||
|
</mechanism-configuration>
|
||||||
|
</http-authentication-factory>
|
||||||
|
<http-authentication-factory name="application-http-authentication" security-domain="ApplicationDomain" http-server-mechanism-factory="global">
|
||||||
|
<mechanism-configuration>
|
||||||
|
<mechanism mechanism-name="BASIC">
|
||||||
|
<mechanism-realm realm-name="ApplicationRealm"/>
|
||||||
|
</mechanism>
|
||||||
|
</mechanism-configuration>
|
||||||
|
</http-authentication-factory>
|
||||||
|
<provider-http-server-mechanism-factory name="global"/>
|
||||||
|
</http>
|
||||||
|
<sasl>
|
||||||
|
<sasl-authentication-factory name="management-sasl-authentication" sasl-server-factory="configured" security-domain="ManagementDomain">
|
||||||
|
<mechanism-configuration>
|
||||||
|
<mechanism mechanism-name="JBOSS-LOCAL-USER" realm-mapper="local"/>
|
||||||
|
<mechanism mechanism-name="DIGEST-MD5">
|
||||||
|
<mechanism-realm realm-name="ManagementRealm"/>
|
||||||
|
</mechanism>
|
||||||
|
</mechanism-configuration>
|
||||||
|
</sasl-authentication-factory>
|
||||||
|
<sasl-authentication-factory name="application-sasl-authentication" sasl-server-factory="configured" security-domain="ApplicationDomain">
|
||||||
|
<mechanism-configuration>
|
||||||
|
<mechanism mechanism-name="JBOSS-LOCAL-USER" realm-mapper="local"/>
|
||||||
|
<mechanism mechanism-name="DIGEST-MD5">
|
||||||
|
<mechanism-realm realm-name="ApplicationRealm"/>
|
||||||
|
</mechanism>
|
||||||
|
</mechanism-configuration>
|
||||||
|
</sasl-authentication-factory>
|
||||||
|
<configurable-sasl-server-factory name="configured" sasl-server-factory="elytron">
|
||||||
|
<properties>
|
||||||
|
<property name="wildfly.sasl.local-user.default-user" value="$local"/>
|
||||||
|
<property name="wildfly.sasl.local-user.challenge-path" value="${jboss.server.temp.dir}/auth"/>
|
||||||
|
</properties>
|
||||||
|
</configurable-sasl-server-factory>
|
||||||
|
<mechanism-provider-filtering-sasl-server-factory name="elytron" sasl-server-factory="global">
|
||||||
|
<filters>
|
||||||
|
<filter provider-name="WildFlyElytron"/>
|
||||||
|
</filters>
|
||||||
|
</mechanism-provider-filtering-sasl-server-factory>
|
||||||
|
<provider-sasl-server-factory name="global"/>
|
||||||
|
</sasl>
|
||||||
|
<tls>
|
||||||
|
<key-stores>
|
||||||
|
<key-store name="applicationKS">
|
||||||
|
<credential-reference clear-text="password"/>
|
||||||
|
<implementation type="JKS"/>
|
||||||
|
<file path="application.keystore" relative-to="jboss.server.config.dir"/>
|
||||||
|
</key-store>
|
||||||
|
</key-stores>
|
||||||
|
<key-managers>
|
||||||
|
<key-manager name="applicationKM" key-store="applicationKS" generate-self-signed-certificate-host="localhost">
|
||||||
|
<credential-reference clear-text="password"/>
|
||||||
|
</key-manager>
|
||||||
|
</key-managers>
|
||||||
|
<server-ssl-contexts>
|
||||||
|
<server-ssl-context name="applicationSSC" key-manager="applicationKM"/>
|
||||||
|
</server-ssl-contexts>
|
||||||
|
</tls>
|
||||||
|
</subsystem>
|
||||||
|
<subsystem xmlns="urn:wildfly:elytron-oidc-client:1.0"/>
|
||||||
|
<subsystem xmlns="urn:wildfly:health:1.0" security-enabled="false"/>
|
||||||
|
<subsystem xmlns="urn:jboss:domain:infinispan:13.0">
|
||||||
|
<cache-container name="ejb" default-cache="passivation" marshaller="PROTOSTREAM" aliases="sfsb" modules="org.wildfly.clustering.ejb.infinispan">
|
||||||
|
<local-cache name="passivation">
|
||||||
|
<expiration interval="0"/>
|
||||||
|
<file-store passivation="true" purge="false"/>
|
||||||
|
</local-cache>
|
||||||
|
</cache-container>
|
||||||
|
<cache-container name="web" default-cache="passivation" marshaller="PROTOSTREAM" modules="org.wildfly.clustering.web.infinispan">
|
||||||
|
<local-cache name="passivation">
|
||||||
|
<expiration interval="0"/>
|
||||||
|
<file-store passivation="true" purge="false"/>
|
||||||
|
</local-cache>
|
||||||
|
<local-cache name="sso">
|
||||||
|
<expiration interval="0"/>
|
||||||
|
</local-cache>
|
||||||
|
</cache-container>
|
||||||
|
<cache-container name="server" default-cache="default" marshaller="PROTOSTREAM" modules="org.wildfly.clustering.server">
|
||||||
|
<local-cache name="default">
|
||||||
|
<expiration interval="0"/>
|
||||||
|
</local-cache>
|
||||||
|
</cache-container>
|
||||||
|
<cache-container name="hibernate" marshaller="JBOSS" modules="org.infinispan.hibernate-cache">
|
||||||
|
<local-cache name="entity">
|
||||||
|
<heap-memory size="10000"/>
|
||||||
|
<expiration max-idle="100000"/>
|
||||||
|
</local-cache>
|
||||||
|
<local-cache name="local-query">
|
||||||
|
<heap-memory size="10000"/>
|
||||||
|
<expiration max-idle="100000"/>
|
||||||
|
</local-cache>
|
||||||
|
<local-cache name="timestamps">
|
||||||
|
<expiration interval="0"/>
|
||||||
|
</local-cache>
|
||||||
|
<local-cache name="pending-puts">
|
||||||
|
<expiration max-idle="60000"/>
|
||||||
|
</local-cache>
|
||||||
|
</cache-container>
|
||||||
|
</subsystem>
|
||||||
|
<subsystem xmlns="urn:jboss:domain:io:3.0">
|
||||||
|
<worker name="default"/>
|
||||||
|
<buffer-pool name="default"/>
|
||||||
|
</subsystem>
|
||||||
|
<subsystem xmlns="urn:jboss:domain:jaxrs:2.0"/>
|
||||||
|
<subsystem xmlns="urn:jboss:domain:jca:5.0">
|
||||||
|
<archive-validation enabled="true" fail-on-error="true" fail-on-warn="false"/>
|
||||||
|
<bean-validation enabled="true"/>
|
||||||
|
<default-workmanager>
|
||||||
|
<short-running-threads>
|
||||||
|
<core-threads count="50"/>
|
||||||
|
<queue-length count="50"/>
|
||||||
|
<max-threads count="50"/>
|
||||||
|
<keepalive-time time="10" unit="seconds"/>
|
||||||
|
</short-running-threads>
|
||||||
|
<long-running-threads>
|
||||||
|
<core-threads count="50"/>
|
||||||
|
<queue-length count="50"/>
|
||||||
|
<max-threads count="50"/>
|
||||||
|
<keepalive-time time="10" unit="seconds"/>
|
||||||
|
</long-running-threads>
|
||||||
|
</default-workmanager>
|
||||||
|
<cached-connection-manager/>
|
||||||
|
</subsystem>
|
||||||
|
<subsystem xmlns="urn:jboss:domain:jdr:1.0"/>
|
||||||
|
<subsystem xmlns="urn:jboss:domain:jmx:1.3">
|
||||||
|
<expose-resolved-model/>
|
||||||
|
<expose-expression-model/>
|
||||||
|
<remoting-connector/>
|
||||||
|
</subsystem>
|
||||||
|
<subsystem xmlns="urn:jboss:domain:jpa:1.1">
|
||||||
|
<jpa default-extended-persistence-inheritance="DEEP"/>
|
||||||
|
</subsystem>
|
||||||
|
<subsystem xmlns="urn:jboss:domain:jsf:1.1"/>
|
||||||
|
<subsystem xmlns="urn:jboss:domain:mail:4.0">
|
||||||
|
<mail-session name="default" jndi-name="java:jboss/mail/Default">
|
||||||
|
<smtp-server outbound-socket-binding-ref="mail-smtp"/>
|
||||||
|
</mail-session>
|
||||||
|
</subsystem>
|
||||||
|
<subsystem xmlns="urn:wildfly:metrics:1.0" security-enabled="false" exposed-subsystems="*" prefix="${wildfly.metrics.prefix:wildfly}"/>
|
||||||
|
<subsystem xmlns="urn:wildfly:microprofile-config-smallrye:2.0"/>
|
||||||
|
<subsystem xmlns="urn:wildfly:microprofile-jwt-smallrye:1.0"/>
|
||||||
|
<subsystem xmlns="urn:wildfly:microprofile-opentracing-smallrye:3.0" default-tracer="jaeger">
|
||||||
|
<jaeger-tracer name="jaeger">
|
||||||
|
<sampler-configuration sampler-type="const" sampler-param="1.0"/>
|
||||||
|
</jaeger-tracer>
|
||||||
|
</subsystem>
|
||||||
|
<subsystem xmlns="urn:jboss:domain:naming:2.0">
|
||||||
|
<remote-naming/>
|
||||||
|
</subsystem>
|
||||||
|
<subsystem xmlns="urn:jboss:domain:pojo:1.0"/>
|
||||||
|
<subsystem xmlns="urn:jboss:domain:remoting:4.0">
|
||||||
|
<http-connector name="http-remoting-connector" connector-ref="default" sasl-authentication-factory="application-sasl-authentication"/>
|
||||||
|
</subsystem>
|
||||||
|
<subsystem xmlns="urn:jboss:domain:request-controller:1.0"/>
|
||||||
|
<subsystem xmlns="urn:jboss:domain:resource-adapters:6.1"/>
|
||||||
|
<subsystem xmlns="urn:jboss:domain:sar:1.0"/>
|
||||||
|
<subsystem xmlns="urn:jboss:domain:security-manager:1.0">
|
||||||
|
<deployment-permissions>
|
||||||
|
<maximum-set>
|
||||||
|
<permission class="java.security.AllPermission"/>
|
||||||
|
</maximum-set>
|
||||||
|
</deployment-permissions>
|
||||||
|
</subsystem>
|
||||||
|
<subsystem xmlns="urn:jboss:domain:transactions:6.0">
|
||||||
|
<core-environment node-identifier="${jboss.tx.node.id:1}">
|
||||||
|
<process-id>
|
||||||
|
<uuid/>
|
||||||
|
</process-id>
|
||||||
|
</core-environment>
|
||||||
|
<recovery-environment socket-binding="txn-recovery-environment" status-socket-binding="txn-status-manager"/>
|
||||||
|
<coordinator-environment statistics-enabled="${wildfly.transactions.statistics-enabled:${wildfly.statistics-enabled:false}}"/>
|
||||||
|
<object-store path="tx-object-store" relative-to="jboss.server.data.dir"/>
|
||||||
|
</subsystem>
|
||||||
|
<subsystem xmlns="urn:jboss:domain:undertow:12.0" default-server="default-server" default-virtual-host="default-host" default-servlet-container="default" default-security-domain="other" statistics-enabled="${wildfly.undertow.statistics-enabled:${wildfly.statistics-enabled:false}}">
|
||||||
|
<buffer-cache name="default"/>
|
||||||
|
<server name="default-server">
|
||||||
|
<http-listener name="default" socket-binding="http" max-post-size="${env.MAX_POST_SIZE:104857600}" record-request-start-time="true" redirect-socket="https" enable-http2="true"/>
|
||||||
|
<https-listener name="https" socket-binding="https" ssl-context="applicationSSC" enable-http2="true"/>
|
||||||
|
<host name="default-host" alias="localhost">
|
||||||
|
<location name="/" handler="welcome-content"/>
|
||||||
|
<filter-ref name="cache-control" predicate="path-suffix['.bpmn'] or path-suffix['.bpmn2']"/>
|
||||||
|
<http-invoker http-authentication-factory="application-http-authentication"/>
|
||||||
|
</host>
|
||||||
|
</server>
|
||||||
|
<servlet-container name="default">
|
||||||
|
<jsp-config/>
|
||||||
|
<websockets/>
|
||||||
|
</servlet-container>
|
||||||
|
<handlers>
|
||||||
|
<file name="welcome-content" path="${jboss.home.dir}/welcome-content"/>
|
||||||
|
</handlers>
|
||||||
|
<filters>
|
||||||
|
<response-header name="cache-control" header-name="Cache-Control" header-value="no-store"/>
|
||||||
|
</filters>
|
||||||
|
<application-security-domains>
|
||||||
|
<application-security-domain name="other" security-domain="ApplicationDomain"/>
|
||||||
|
</application-security-domains>
|
||||||
|
</subsystem>
|
||||||
|
<subsystem xmlns="urn:jboss:domain:webservices:2.0" statistics-enabled="${wildfly.webservices.statistics-enabled:${wildfly.statistics-enabled:false}}">
|
||||||
|
<wsdl-host>${jboss.bind.address:127.0.0.1}</wsdl-host>
|
||||||
|
<endpoint-config name="Standard-Endpoint-Config"/>
|
||||||
|
<endpoint-config name="Recording-Endpoint-Config">
|
||||||
|
<pre-handler-chain name="recording-handlers" protocol-bindings="##SOAP11_HTTP ##SOAP11_HTTP_MTOM ##SOAP12_HTTP ##SOAP12_HTTP_MTOM">
|
||||||
|
<handler name="RecordingHandler" class="org.jboss.ws.common.invocation.RecordingServerHandler"/>
|
||||||
|
</pre-handler-chain>
|
||||||
|
</endpoint-config>
|
||||||
|
<client-config name="Standard-Client-Config"/>
|
||||||
|
</subsystem>
|
||||||
|
<subsystem xmlns="urn:jboss:domain:weld:4.0"/>
|
||||||
|
</profile>
|
||||||
|
<interfaces>
|
||||||
|
<interface name="management">
|
||||||
|
<inet-address value="${jboss.bind.address.management:0.0.0.0}"/>
|
||||||
|
</interface>
|
||||||
|
<interface name="public">
|
||||||
|
<inet-address value="${jboss.bind.address:0.0.0.0}"/>
|
||||||
|
</interface>
|
||||||
|
</interfaces>
|
||||||
|
<socket-binding-group name="standard-sockets" default-interface="public" port-offset="${jboss.socket.binding.port-offset:0}">
|
||||||
|
<socket-binding name="ajp" port="${jboss.ajp.port:8009}"/>
|
||||||
|
<socket-binding name="http" port="${jboss.http.port:8080}"/>
|
||||||
|
<socket-binding name="https" port="${jboss.https.port:8443}"/>
|
||||||
|
<socket-binding name="management-http" interface="management" port="${jboss.management.http.port:9990}"/>
|
||||||
|
<socket-binding name="management-https" interface="management" port="${jboss.management.https.port:9993}"/>
|
||||||
|
<socket-binding name="txn-recovery-environment" port="4712"/>
|
||||||
|
<socket-binding name="txn-status-manager" port="4713"/>
|
||||||
|
<outbound-socket-binding name="mail-smtp">
|
||||||
|
<remote-destination host="${jboss.mail.server.host:localhost}" port="${jboss.mail.server.port:25}"/>
|
||||||
|
</outbound-socket-binding>
|
||||||
|
</socket-binding-group>
|
||||||
|
</server>
|
||||||
66
distribution/pom.xml
Normal file
|
|
@ -0,0 +1,66 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<parent>
|
||||||
|
<groupId>ru.micord.ervu</groupId>
|
||||||
|
<artifactId>eks</artifactId>
|
||||||
|
<version>1.0.0-SNAPSHOT</version>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<groupId>ru.micord.ervu.eks</groupId>
|
||||||
|
<artifactId>distribution</artifactId>
|
||||||
|
<packaging>ear</packaging>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<backendContext>/backend</backendContext>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>ru.micord.ervu.eks</groupId>
|
||||||
|
<artifactId>backend</artifactId>
|
||||||
|
<type>war</type>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>ru.micord.ervu.eks</groupId>
|
||||||
|
<artifactId>frontend</artifactId>
|
||||||
|
<type>war</type>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-ear-plugin</artifactId>
|
||||||
|
<version>3.2.0</version>
|
||||||
|
<configuration>
|
||||||
|
<modules>
|
||||||
|
<webModule>
|
||||||
|
<groupId>ru.micord.ervu.eks</groupId>
|
||||||
|
<artifactId>frontend</artifactId>
|
||||||
|
<contextRoot>/</contextRoot>
|
||||||
|
<bundleFileName>frontend.war</bundleFileName>
|
||||||
|
</webModule>
|
||||||
|
<webModule>
|
||||||
|
<groupId>ru.micord.ervu.eks</groupId>
|
||||||
|
<artifactId>backend</artifactId>
|
||||||
|
<contextRoot>${backendContext}</contextRoot>
|
||||||
|
<bundleFileName>backend.war</bundleFileName>
|
||||||
|
</webModule>
|
||||||
|
</modules>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
<finalName>${project.parent.artifactId}</finalName>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
<profiles>
|
||||||
|
<profile>
|
||||||
|
<id>enable-version-in-url</id>
|
||||||
|
<properties>
|
||||||
|
<backendContext>/backend-${project.version}</backendContext>
|
||||||
|
</properties>
|
||||||
|
</profile>
|
||||||
|
</profiles>
|
||||||
|
</project>
|
||||||
1
frontend/.npmrc
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
registry=https://repo.micord.ru/repository/npm-all/
|
||||||
71
frontend/angular.json
Normal file
|
|
@ -0,0 +1,71 @@
|
||||||
|
{
|
||||||
|
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
|
||||||
|
"version": 1,
|
||||||
|
"newProjectRoot": "projects",
|
||||||
|
"projects": {
|
||||||
|
"webbpm-frontend": {
|
||||||
|
"root": "",
|
||||||
|
"sourceRoot": "src",
|
||||||
|
"projectType": "application",
|
||||||
|
"architect": {
|
||||||
|
"build": {
|
||||||
|
"builder": "@angular-devkit/build-angular:browser",
|
||||||
|
"options": {
|
||||||
|
"outputPath": "dist",
|
||||||
|
"index": "src/index.html",
|
||||||
|
"main": "src/ts/main.ts",
|
||||||
|
"tsConfig": "src/tsconfig.json",
|
||||||
|
"polyfills": "src/ts/polyfills.ts",
|
||||||
|
"assets": [
|
||||||
|
"src/resources"
|
||||||
|
],
|
||||||
|
"styles": [
|
||||||
|
],
|
||||||
|
"scripts": [
|
||||||
|
"node_modules/jquery/dist/jquery.min.js",
|
||||||
|
"node_modules/moment/min/moment-with-locales.js",
|
||||||
|
"node_modules/moment-timezone/builds/moment-timezone-with-data.min.js",
|
||||||
|
"node_modules/eonasdan-bootstrap-datetimepicker/build/js/bootstrap-datetimepicker.min.js",
|
||||||
|
"node_modules/selectize/dist/js/standalone/selectize.min.js",
|
||||||
|
"node_modules/downloadjs/download.min.js"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"configurations": {
|
||||||
|
"production": {
|
||||||
|
"optimization": true,
|
||||||
|
"outputHashing": "all",
|
||||||
|
"sourceMap": false,
|
||||||
|
"extractCss": true,
|
||||||
|
"namedChunks": false,
|
||||||
|
"aot": true,
|
||||||
|
"extractLicenses": true,
|
||||||
|
"vendorChunk": false,
|
||||||
|
"buildOptimizer": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"serve": {
|
||||||
|
"builder": "@angular-devkit/build-angular:dev-server",
|
||||||
|
"options": {
|
||||||
|
"browserTarget": "webbpm-frontend:build"
|
||||||
|
},
|
||||||
|
"configurations": {}
|
||||||
|
},
|
||||||
|
"extract-i18n": {
|
||||||
|
"builder": "@angular-devkit/build-angular:extract-i18n",
|
||||||
|
"options": {
|
||||||
|
"browserTarget": "webbpm-frontend:build"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"lint": {
|
||||||
|
"builder": "@angular-devkit/build-angular:tslint",
|
||||||
|
"options": {
|
||||||
|
"tsConfig": [],
|
||||||
|
"exclude": []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"defaultProject": "webbpm-frontend"
|
||||||
|
}
|
||||||
23
frontend/index.html
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>ervu-eks</title>
|
||||||
|
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
|
||||||
|
<link rel="icon" type="image/png" href="src/resources/img/logo.png"/>
|
||||||
|
<link rel="stylesheet" href="src/resources/css/style.css"/>
|
||||||
|
|
||||||
|
<script src="node_modules/core-js/client/shim.min.js"></script>
|
||||||
|
<script src="node_modules/zone.js/dist/zone.js"></script>
|
||||||
|
<script src="node_modules/reflect-metadata/Reflect.js"></script>
|
||||||
|
<script src="node_modules/systemjs/dist/system.src.js"></script>
|
||||||
|
<script src="systemjs.config.js"></script>
|
||||||
|
<script>
|
||||||
|
System.import('webbpm').catch(function (err) {
|
||||||
|
console.error(err);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body webbpm class="webbpm ervu-eks">
|
||||||
|
<div class="progress"></div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
11
frontend/index.webpack.html
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>ervu-eks</title>
|
||||||
|
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
|
||||||
|
<link rel="icon" type="image/png" href="src/resources/img/logo.png"/>
|
||||||
|
</head>
|
||||||
|
<body webbpm class="webbpm ervu-eks">
|
||||||
|
<div class="progress"></div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
100
frontend/package.json
Normal file
|
|
@ -0,0 +1,100 @@
|
||||||
|
{
|
||||||
|
"name": "ervu-eks",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"scripts": {
|
||||||
|
"cleanup": "npm run cleanup-ngc && node ./node_modules/rimraf/bin ./build ./dist",
|
||||||
|
"cleanup-ngc": "node ./node_modules/rimraf/bin ./src/ts/**/*.js ./src/ts/**/*.json ./src/ts/page.routing.ts",
|
||||||
|
"cleanup-and-ngc": "npm run cleanup && npm run ngc",
|
||||||
|
"ngc": "node --max-old-space-size=14336 ./node_modules/@angular/compiler-cli/src/main -p tsconfig.aot.json",
|
||||||
|
"build-webpack": "node --max-old-space-size=14336 ./node_modules/webpack/bin/webpack --config webpack.aot.config.js --progress --profile",
|
||||||
|
"save-ts-metadata": "node save.ts.metadata.js",
|
||||||
|
"tsc": "node ./node_modules/typescript/bin/tsc",
|
||||||
|
"tsc-watch": "node ./node_modules/typescript/bin/tsc --watch",
|
||||||
|
"ts-watch": "node node_modules/cross-env/dist/bin/cross-env.js TSC_NONPOLLING_WATCHER=true npm run tsc-watch",
|
||||||
|
"ts": "npm install && npm run tsc",
|
||||||
|
"compile": "npm run ts-watch",
|
||||||
|
"install-compile": "npm install && npm run ts-watch"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@angular/animations": "7.2.15",
|
||||||
|
"@angular/common": "7.2.15",
|
||||||
|
"@angular/compiler": "7.2.15",
|
||||||
|
"@angular/core": "7.2.15",
|
||||||
|
"@angular/forms": "7.2.15",
|
||||||
|
"@angular/http": "7.2.15",
|
||||||
|
"@angular/platform-browser": "7.2.15",
|
||||||
|
"@angular/platform-browser-dynamic": "7.2.15",
|
||||||
|
"@angular/router": "7.2.15",
|
||||||
|
"@ng-bootstrap/ng-bootstrap": "4.2.2-micord.1",
|
||||||
|
"@webbpm/base-package": "3.185.0",
|
||||||
|
"ag-grid-angular": "29.0.0-micord.4",
|
||||||
|
"ag-grid-community": "29.0.0-micord.4",
|
||||||
|
"angular-calendar": "0.28.28",
|
||||||
|
"autonumeric": "4.5.10-cg",
|
||||||
|
"bootstrap": "4.3.1",
|
||||||
|
"bootstrap-icons": "1.10.3",
|
||||||
|
"cadesplugin_api": "2.0.4-micord.1",
|
||||||
|
"chart.js": "3.8.0-cg.1",
|
||||||
|
"chartjs-adapter-moment": "1.0.0",
|
||||||
|
"core-js": "2.4.1",
|
||||||
|
"date-fns": "2.29.3",
|
||||||
|
"downloadjs": "1.4.8",
|
||||||
|
"eonasdan-bootstrap-datetimepicker": "4.17.47-micord.5",
|
||||||
|
"esmarttokenjs": "2.2.1-cg",
|
||||||
|
"font-awesome": "4.7.0",
|
||||||
|
"google-libphonenumber": "3.0.9",
|
||||||
|
"inputmask": "5.0.5-cg.2",
|
||||||
|
"jquery": "3.7.1",
|
||||||
|
"js-year-calendar": "1.0.0-cg.2",
|
||||||
|
"jsgantt-improved": "2.0.10-cg",
|
||||||
|
"moment": "2.30.1",
|
||||||
|
"moment-timezone": "0.5.46",
|
||||||
|
"ngx-cookie": "3.0.1",
|
||||||
|
"ngx-international-phone-number": "1.0.6",
|
||||||
|
"ngx-toastr": "10.2.0-cg",
|
||||||
|
"popper.js": "1.14.7",
|
||||||
|
"reflect-metadata": "0.1.13",
|
||||||
|
"rxjs": "6.4.0",
|
||||||
|
"rxjs-compat": "6.4.0",
|
||||||
|
"selectize": "0.12.4-cg.11",
|
||||||
|
"systemjs": "0.21.4",
|
||||||
|
"systemjs-plugin-babel": "0.0.25",
|
||||||
|
"tslib": "1.9.3",
|
||||||
|
"zone.js": "0.11.8"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@angular-devkit/build-optimizer": "0.13.9",
|
||||||
|
"@angular-devkit/core": "7.3.9",
|
||||||
|
"@angular/cli": "7.3.9",
|
||||||
|
"@angular/compiler-cli": "7.2.15",
|
||||||
|
"@angular/platform-server": "7.2.15",
|
||||||
|
"@babel/core": "7.18.10",
|
||||||
|
"@babel/preset-env": "7.18.10",
|
||||||
|
"@types/bootstrap": "3.3.39",
|
||||||
|
"@types/eslint": "7.2.5",
|
||||||
|
"@types/jquery": "3.5.5",
|
||||||
|
"@types/node": "7.0.5",
|
||||||
|
"@types/selectize": "0.12.33",
|
||||||
|
"ajv": "8.8.2",
|
||||||
|
"angular-router-loader": "0.8.5",
|
||||||
|
"angular2-template-loader": "0.6.2",
|
||||||
|
"babel-loader": "9.1.2",
|
||||||
|
"codelyzer": "5.2.1",
|
||||||
|
"copy-webpack-plugin": "5.0.3",
|
||||||
|
"cross-env": "5.2.1",
|
||||||
|
"css-loader": "6.11.0",
|
||||||
|
"del": "2.2.2",
|
||||||
|
"file-loader": "6.2.0",
|
||||||
|
"html-webpack-plugin": "5.6.0",
|
||||||
|
"mini-css-extract-plugin": "2.9.1",
|
||||||
|
"mkdirp": "3.0.1",
|
||||||
|
"raw-loader": "4.0.2",
|
||||||
|
"style-loader": "3.3.4",
|
||||||
|
"terser-webpack-plugin": "5.3.10",
|
||||||
|
"tslint": "5.13.1",
|
||||||
|
"typescript": "3.2.4",
|
||||||
|
"typescript-parser": "2.6.1-cg.2",
|
||||||
|
"webpack": "5.90.1",
|
||||||
|
"webpack-cli": "5.0.2"
|
||||||
|
}
|
||||||
|
}
|
||||||
113
frontend/pom.xml
Normal file
|
|
@ -0,0 +1,113 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<parent>
|
||||||
|
<groupId>ru.micord.ervu</groupId>
|
||||||
|
<artifactId>eks</artifactId>
|
||||||
|
<version>1.0.0-SNAPSHOT</version>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<groupId>ru.micord.ervu.eks</groupId>
|
||||||
|
<artifactId>frontend</artifactId>
|
||||||
|
<packaging>war</packaging>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>com.google.code.maven-replacer-plugin</groupId>
|
||||||
|
<artifactId>replacer</artifactId>
|
||||||
|
<version>1.5.3</version>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>replace-version-in-url</id>
|
||||||
|
<phase>process-resources</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>replace</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
<configuration>
|
||||||
|
<includes>
|
||||||
|
<include>${basedir}/src/resources/app-config.json</include>
|
||||||
|
<include>${basedir}/dist/src/resources/app-config.json</include>
|
||||||
|
<include>${basedir}/src/resources/app.version</include>
|
||||||
|
<include>${basedir}/dist/src/resources/app.version</include>
|
||||||
|
</includes>
|
||||||
|
<replacements>
|
||||||
|
<replacement>
|
||||||
|
<token>%project.version%</token>
|
||||||
|
<value>${project.version}</value>
|
||||||
|
</replacement>
|
||||||
|
<replacement>
|
||||||
|
<token>%enable.version.in.url%</token>
|
||||||
|
<value>${enable.version.in.url}</value>
|
||||||
|
</replacement>
|
||||||
|
</replacements>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
<profiles>
|
||||||
|
<profile>
|
||||||
|
<id>dev</id>
|
||||||
|
<activation>
|
||||||
|
<activeByDefault>true</activeByDefault>
|
||||||
|
</activation>
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-war-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<copyWebResources>false</copyWebResources>
|
||||||
|
<webResources>
|
||||||
|
<resource>
|
||||||
|
<directory>${basedir}</directory>
|
||||||
|
<includes>
|
||||||
|
<include>src/resources/**/*</include>
|
||||||
|
<include>build_dev/**/*</include>
|
||||||
|
<include>node_modules/**/*</include>
|
||||||
|
<include>index.html</include>
|
||||||
|
<include>systemjs.config.js</include>
|
||||||
|
</includes>
|
||||||
|
</resource>
|
||||||
|
</webResources>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
</profile>
|
||||||
|
<profile>
|
||||||
|
<id>compile-ts</id>
|
||||||
|
<activation>
|
||||||
|
<activeByDefault>false</activeByDefault>
|
||||||
|
</activation>
|
||||||
|
</profile>
|
||||||
|
<profile>
|
||||||
|
<id>prod</id>
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-war-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<copyWebResources>false</copyWebResources>
|
||||||
|
<webResources>
|
||||||
|
<resource>
|
||||||
|
<directory>${basedir}/dist</directory>
|
||||||
|
</resource>
|
||||||
|
</webResources>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
</profile>
|
||||||
|
<profile>
|
||||||
|
<id>enable-version-in-url</id>
|
||||||
|
<properties>
|
||||||
|
<enable.version.in.url>true</enable.version.in.url>
|
||||||
|
</properties>
|
||||||
|
</profile>
|
||||||
|
</profiles>
|
||||||
|
</project>
|
||||||
23
frontend/preview.html
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Web BPM</title>
|
||||||
|
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
|
||||||
|
<link rel="icon" type="image/png" href="src/resources/img/logo.png"/>
|
||||||
|
<link rel="stylesheet" href="src/resources/css/style.css"/>
|
||||||
|
|
||||||
|
<script src="node_modules/core-js/client/shim.min.js"></script>
|
||||||
|
<script src="node_modules/zone.js/dist/zone.js"></script>
|
||||||
|
<script src="node_modules/reflect-metadata/Reflect.js"></script>
|
||||||
|
<script src="node_modules/systemjs/dist/system.src.js"></script>
|
||||||
|
<script src="systemjs.preview.config.js"></script>
|
||||||
|
<script>
|
||||||
|
System.import('preview').catch(function (err) {
|
||||||
|
console.error(err);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body preview-container id="webbpm-angular-application-container ervu-eks" class="webbpm">
|
||||||
|
<div class="progress"></div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
72
frontend/save.ts.metadata.js
Normal file
|
|
@ -0,0 +1,72 @@
|
||||||
|
#!/usr/bin/env node
|
||||||
|
var tsp = require("typescript-parser");
|
||||||
|
var fs = require('fs');
|
||||||
|
var path = require('path');
|
||||||
|
var ts = require("typescript");
|
||||||
|
|
||||||
|
var parser = new tsp.TypescriptParser();
|
||||||
|
var excludedDirs = [
|
||||||
|
'generated-sources'
|
||||||
|
];
|
||||||
|
|
||||||
|
var walkFileTree = function (dir, action) {
|
||||||
|
if (typeof action !== "function") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fs.readdirSync(dir).forEach(function (file) {
|
||||||
|
var path = dir + "/" + file;
|
||||||
|
var stat = fs.statSync(path);
|
||||||
|
var extension = ".ts";
|
||||||
|
if (stat && stat.isDirectory() && excludedDirs.indexOf(file) === -1) {
|
||||||
|
walkFileTree(path, action);
|
||||||
|
}
|
||||||
|
else if (path.indexOf(extension, path.length - extension.length) !== -1) {
|
||||||
|
action(null, path);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
var dateInLong = Date.now();
|
||||||
|
var arr = [];
|
||||||
|
|
||||||
|
var basePath = path.resolve(__dirname, "src/ts/");
|
||||||
|
walkFileTree(basePath, function (err, file) {
|
||||||
|
var content = fs.readFileSync(file).toString();
|
||||||
|
var jsonStructure = parser.parseTypescript(ts.createSourceFile(
|
||||||
|
file,
|
||||||
|
content,
|
||||||
|
ts.ScriptTarget.Latest,
|
||||||
|
true,
|
||||||
|
ts.ScriptKind.TS
|
||||||
|
),
|
||||||
|
'/');
|
||||||
|
jsonStructure['packageName'] = path.relative(path.resolve(__dirname, "src/ts/"),jsonStructure['filePath']);
|
||||||
|
jsonStructure['imports'].forEach( function (val) {
|
||||||
|
if (val.libraryName.startsWith(".")) {
|
||||||
|
val['libraryName'] = path.resolve(path.dirname(jsonStructure['filePath']), val['libraryName']);
|
||||||
|
val['libraryName'] = path.relative(path.resolve(__dirname, "src/ts/"), val['libraryName']);
|
||||||
|
val['libraryName'] = path.dirname(val['libraryName']).split(path.sep).join(".");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
delete jsonStructure['filePath'];
|
||||||
|
jsonStructure['packageName'] = path.dirname(jsonStructure['packageName']).split(path.sep).join( ".");
|
||||||
|
arr.push(jsonStructure);
|
||||||
|
});
|
||||||
|
var cache = [];
|
||||||
|
|
||||||
|
fs.writeFileSync("./../.studio/typescript.metadata.json",
|
||||||
|
JSON.stringify(arr, function (key, value) {
|
||||||
|
if (typeof value === 'object' && value !== null) {
|
||||||
|
if (cache.indexOf(value) !== -1) {
|
||||||
|
// Circular reference found, discard key
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Store value in our collection
|
||||||
|
cache.push(value);
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}));
|
||||||
|
|
||||||
|
cache = null;
|
||||||
|
console.log("typescript parse time = " + (Date.now() - dateInLong));
|
||||||
19
frontend/src/resources/app-config.json
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
{
|
||||||
|
"electronic_sign.esmart_extension_url": "",
|
||||||
|
"electronic_sign.tsp_address": "",
|
||||||
|
"filter_cleanup_interval_hours": 720,
|
||||||
|
"filter_cleanup_check_period_minutes": 30,
|
||||||
|
"auth_method": "form",
|
||||||
|
"enable.version.in.url": "false",
|
||||||
|
"guard.confirm_exit": false,
|
||||||
|
"message_service_error_timeout": "",
|
||||||
|
"message_service_warning_timeout": "",
|
||||||
|
"message_service_success_timeout": "",
|
||||||
|
"message_service_info_timeout": "",
|
||||||
|
"jivo_chat_widget_api_url": "https://code.jivo.ru/widget/{ID}",
|
||||||
|
"jivo_chat_widget_enabled": false,
|
||||||
|
"password_pattern": "^((?=(.*\\d){1,})(?=.*[a-zа-яё])(?=.*[A-ZА-ЯЁ]).{8,})$",
|
||||||
|
"password_pattern_error": "Пароль должен содержать заглавные или прописные буквы и как минимум 1 цифру",
|
||||||
|
"show.client.errors": false,
|
||||||
|
"available_task.single_fetch": true
|
||||||
|
}
|
||||||
1
frontend/src/resources/app.version
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
1.0.0-SNAPSHOT
|
||||||
1584
frontend/src/resources/css/components-app.css
Normal file
342
frontend/src/resources/css/inbox-app.css
Normal file
|
|
@ -0,0 +1,342 @@
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Segoe';
|
||||||
|
src: url('../fonts/Segoe.ttf');
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: 'SegoeSL';
|
||||||
|
src: url('../fonts/SegoeSL.ttf');
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: 'SegoeSB';
|
||||||
|
src: url('../fonts/SegoeSB.ttf');
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: 'SegoeB';
|
||||||
|
src: url('../fonts/SegoeB.ttf');
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: 'SegoeBL';
|
||||||
|
src: url('../fonts/SegoeBL.ttf');
|
||||||
|
}
|
||||||
|
|
||||||
|
.webbpm a {
|
||||||
|
color: var(--color-link);
|
||||||
|
&:hover,
|
||||||
|
&:focus,
|
||||||
|
&:active {
|
||||||
|
color: var(--color-link-hover);
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
body.webbpm {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
color: var(--color-text-primary);
|
||||||
|
font-family: 'Segoe';
|
||||||
|
background-color: var(--white);
|
||||||
|
}
|
||||||
|
|
||||||
|
.webbpm .container {
|
||||||
|
padding: 70px 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.webbpm [id="page"],
|
||||||
|
.webbpm .container .container-inside {
|
||||||
|
font-family: 'Segoe';
|
||||||
|
font-size: var(--size-text-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.webbpm .logo {
|
||||||
|
height: auto;
|
||||||
|
width: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.webbpm .header-logo {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
margin-left: 40px;
|
||||||
|
|
||||||
|
.logo a {
|
||||||
|
background: url('../../../src/resources/img/logo-full.png') no-repeat 0 50%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.webbpm .header-menu {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: 40px;
|
||||||
|
& > * {
|
||||||
|
margin-right: 20px;
|
||||||
|
&:last-child {
|
||||||
|
margin-right: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.nav-link {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
color: var(--white);
|
||||||
|
font-size: var(--size-text-primary);
|
||||||
|
width: 30px;
|
||||||
|
height: 30px;
|
||||||
|
padding: 0;
|
||||||
|
border: 0;
|
||||||
|
border-radius: 15px;
|
||||||
|
background-color: var(--color-text-primary);
|
||||||
|
outline: transparent;
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover,
|
||||||
|
&:focus,
|
||||||
|
&:active {
|
||||||
|
background-color: var(--color-link);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.logout .user-info {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
color: var(--black);
|
||||||
|
padding: 4px 20px;
|
||||||
|
background: transparent;
|
||||||
|
cursor: default;
|
||||||
|
|
||||||
|
& > * {
|
||||||
|
display: flex;
|
||||||
|
padding-bottom: 10px;
|
||||||
|
margin: 0 0 10px 0;
|
||||||
|
border-bottom: 1px solid #f1f5f9;
|
||||||
|
&:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-fio {
|
||||||
|
padding-bottom: 0;
|
||||||
|
margin-bottom: 0;
|
||||||
|
border-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-department {
|
||||||
|
color: #a0b1bc;
|
||||||
|
line-height: 1.2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.webbpm .header {
|
||||||
|
display: flex;
|
||||||
|
font-family: 'Segoe';
|
||||||
|
width: 100%;
|
||||||
|
height: auto;
|
||||||
|
min-height: 70px;
|
||||||
|
border-bottom: 1px solid var(--bg-light);
|
||||||
|
background: var(--white);
|
||||||
|
box-shadow: 0px 15px 20px 0px rgb(0 0 0 / 4%);
|
||||||
|
|
||||||
|
& > div > * {
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-menu.show {
|
||||||
|
top: 69px !important;
|
||||||
|
right: 0px !important;
|
||||||
|
left: auto !important;
|
||||||
|
transform: none !important;
|
||||||
|
margin: 0;
|
||||||
|
border: 0;
|
||||||
|
border-radius: 0 0 10px 10px;
|
||||||
|
background-color: var(--white);
|
||||||
|
box-shadow: 0 8px 12px rgb(77 72 91 / 5%), 0 6px 10px rgb(77 72 91 / 0%);
|
||||||
|
|
||||||
|
.dropdown-menu-inner {
|
||||||
|
max-height: calc(100vh - 140px);
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:is(process, admin-menu) .dropdown-menu.show {
|
||||||
|
top: 49px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logout .dropdown-menu.show {
|
||||||
|
width: 300px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.webbpm .dropdown-menu-inner:hover {
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.webbpm .dropdown-item {
|
||||||
|
padding: 4px 20px;
|
||||||
|
&:hover,
|
||||||
|
&:focus,
|
||||||
|
&:active {
|
||||||
|
color: var(--color-link);
|
||||||
|
background-color: transparent;
|
||||||
|
outline: transparent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.webbpm footer {
|
||||||
|
color: var(--color-text-primary);
|
||||||
|
font-size: var(--size-text-secondary);
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
padding: 15px 40px;
|
||||||
|
border-top: 1px solid var(--border-light);
|
||||||
|
a {
|
||||||
|
color: var(--color-text-primary);
|
||||||
|
&:hover {
|
||||||
|
color: var(--color-link);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-------------- Menu tasks -------------- */
|
||||||
|
.webbpm .task-list-tree-panel {
|
||||||
|
padding: 0 40px;
|
||||||
|
.task-list-filter {
|
||||||
|
font-family: 'Segoe';
|
||||||
|
box-shadow: none;
|
||||||
|
|
||||||
|
li:first-of-type {
|
||||||
|
font-family: 'SegoeSB';
|
||||||
|
font-weight: normal;
|
||||||
|
padding-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
li.ontime label div {
|
||||||
|
background-color: #31c980;
|
||||||
|
}
|
||||||
|
|
||||||
|
li.overdue label div {
|
||||||
|
background-color: var(--color-link);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.webbpm .task-list-workplace {
|
||||||
|
padding: 20px 40px 0 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.webbpm .task-tbl :is(.tr.task-ontime, .tr.task-overdue) > .td.task::before {
|
||||||
|
top: 24px;
|
||||||
|
background-color: #31c980;
|
||||||
|
}
|
||||||
|
|
||||||
|
.webbpm .task-tbl .tr.task-overdue > .td.task::before {
|
||||||
|
background-color: var(--color-link);
|
||||||
|
}
|
||||||
|
|
||||||
|
.webbpm .task-tbl .thead {
|
||||||
|
display: table-header-group;
|
||||||
|
border: 0;
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.webbpm .task-tbl .th {
|
||||||
|
color: var(--color-text-primary);
|
||||||
|
font-family: 'SegoeSB';
|
||||||
|
font-size: var(--size-text-secondary);
|
||||||
|
font-weight: normal;
|
||||||
|
padding: 9px 12px;
|
||||||
|
border: 0;
|
||||||
|
background: var(--bg-light);
|
||||||
|
}
|
||||||
|
.webbpm .task-tbl .th:first-child {
|
||||||
|
border-top-left-radius: 12px;
|
||||||
|
border-bottom-left-radius: 12px;
|
||||||
|
}
|
||||||
|
.webbpm .task-tbl .th:last-child {
|
||||||
|
border-top-right-radius: 12px;
|
||||||
|
border-bottom-right-radius: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.webbpm .task-tbl .td {
|
||||||
|
color: var(--color-text-primary);
|
||||||
|
font-size: var(--size-text-primary);
|
||||||
|
padding: 16px 12px;
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.webbpm .task-tbl .thead ~ .tr {
|
||||||
|
border-color: var(--border-light);
|
||||||
|
border-width: 1px 0 0 0;
|
||||||
|
border-style: solid;
|
||||||
|
}
|
||||||
|
.webbpm .task-tbl .thead + .tr {
|
||||||
|
border-top-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.webbpm .task-tbl .thead ~ .tr:hover {
|
||||||
|
border-top-color: transparent;
|
||||||
|
border-bottom-color: transparent;
|
||||||
|
}
|
||||||
|
.webbpm .task-tbl .thead ~ .tr:hover +.tr {
|
||||||
|
border-top-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.webbpm .task-tbl .thead ~ .tr:hover .td {
|
||||||
|
background-color: #f9f9f9;
|
||||||
|
}
|
||||||
|
.webbpm .task-tbl .thead ~ .tr:hover .td:first-child {
|
||||||
|
border-top-left-radius: 12px;
|
||||||
|
border-bottom-left-radius: 12px;
|
||||||
|
}
|
||||||
|
.webbpm .task-tbl .thead ~ .tr:hover .td:last-child {
|
||||||
|
border-top-right-radius: 12px;
|
||||||
|
border-bottom-right-radius: 12px;
|
||||||
|
}
|
||||||
|
/*------------- end Menu tasks ----------- */
|
||||||
|
|
||||||
|
/*----------------- Login ---------------- */
|
||||||
|
.webbpm :is(.form-signin, .form-signup, .confirm) {
|
||||||
|
color: var(--color-text-primary);
|
||||||
|
width: 560px;
|
||||||
|
padding: 60px 80px;
|
||||||
|
margin: 30px auto;
|
||||||
|
border: 0;
|
||||||
|
border-radius: 15px;
|
||||||
|
box-shadow: 0px 0px 30px 2px rgb(77 72 91 / 12%);
|
||||||
|
background-color: var(--white);
|
||||||
|
}
|
||||||
|
|
||||||
|
.webbpm :is(.form-signin, .form-signup) .row.title {
|
||||||
|
position: relative;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.webbpm .form-signin h1,
|
||||||
|
.webbpm .form-signin h2,
|
||||||
|
.webbpm .form-signup h2,
|
||||||
|
.webbpm .confirm h2 {
|
||||||
|
font-family: 'SegoeB';
|
||||||
|
font-size: 32px;
|
||||||
|
text-align: left;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.webbpm :is(.form-signin, .form-signup, .confirm) .logo {
|
||||||
|
position: absolute;
|
||||||
|
top: -10px;
|
||||||
|
right: 0;
|
||||||
|
width: 145px;
|
||||||
|
height: 40px;
|
||||||
|
background: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.webbpm .form-signin .row.registration > * + *,
|
||||||
|
.webbpm .form-signin .login-btn-box .password,
|
||||||
|
.webbpm .form-signin .login-btn-box .btn + .btn {
|
||||||
|
margin-left: 20px;
|
||||||
|
}
|
||||||
|
/*--------------- end Login -------------- */
|
||||||
846
frontend/src/resources/css/structure.css
Normal file
|
|
@ -0,0 +1,846 @@
|
||||||
|
:root {
|
||||||
|
--white: #ffffff;
|
||||||
|
--black: #000000;
|
||||||
|
--color-text-primary: #404954;
|
||||||
|
--color-link: #1c92ea;
|
||||||
|
--color-link-hover: #1b84d2;
|
||||||
|
--bg-light: #f5f7fa;
|
||||||
|
--bg-secondary: #4c5969;
|
||||||
|
--border-light: #e3e6ed;
|
||||||
|
|
||||||
|
--size-text-primary: 16px;
|
||||||
|
--size-text-secondary: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
*, *:before, *:after {
|
||||||
|
-webkit-box-sizing: border-box;
|
||||||
|
-moz-box-sizing: border-box;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.webbpm .form-signin label {
|
||||||
|
width: 160px;
|
||||||
|
margin-right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.webbpm .progress {
|
||||||
|
position: absolute;
|
||||||
|
width: 64px;
|
||||||
|
height: 64px;
|
||||||
|
margin-bottom: 0 !important;
|
||||||
|
background: url("../img/progress.gif") no-repeat 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.webbpm > .progress {
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
margin-top: -30px;
|
||||||
|
margin-left: -30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.webbpm .search-task-progress-bar {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.webbpm .modal-body .progress,
|
||||||
|
.webbpm .search-task-progress-bar .progress {
|
||||||
|
position: relative;
|
||||||
|
top: 0;
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-- common class --*/
|
||||||
|
.webbpm .fl-left {
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.webbpm .fl-right {
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.webbpm .anchor {
|
||||||
|
float: none;
|
||||||
|
clear: both;
|
||||||
|
}
|
||||||
|
|
||||||
|
.webbpm :is(ul, ol) li {
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.webbpm :is(h1, h2, h3) {
|
||||||
|
margin: 0;
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
.webbpm h1 {
|
||||||
|
font-size: 2.33em;
|
||||||
|
}
|
||||||
|
.webbpm h2 {
|
||||||
|
font-size: 2em;
|
||||||
|
}
|
||||||
|
.webbpm h3 {
|
||||||
|
font-size: 1.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.webbpm .table {
|
||||||
|
display: table;
|
||||||
|
}
|
||||||
|
|
||||||
|
.webbpm .tr {
|
||||||
|
display: table-row;
|
||||||
|
}
|
||||||
|
|
||||||
|
.webbpm .td, .webbpm .th {
|
||||||
|
display: table-cell;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-- layout --*/
|
||||||
|
html, body.webbpm {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.webbpm {
|
||||||
|
background-color: #f9f9fa;
|
||||||
|
font-family: Arial;
|
||||||
|
font-size: var(--size-text-secondary);
|
||||||
|
min-height: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.webbpm .wrapper {
|
||||||
|
height: 100%;
|
||||||
|
min-height: 100%;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.webbpm .container {
|
||||||
|
width: 100%;
|
||||||
|
max-width: 100%;
|
||||||
|
height: auto;
|
||||||
|
margin: 0;
|
||||||
|
padding: 67px 0 0;
|
||||||
|
position: absolute;
|
||||||
|
top: 0px;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 50px;
|
||||||
|
border: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
[ng-include="taskPageFile"] {
|
||||||
|
position: relative;
|
||||||
|
min-height: 100%;
|
||||||
|
height: 100%;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
.container-inside {
|
||||||
|
font-family: Arial;
|
||||||
|
font-size: var(--size-text-secondary);
|
||||||
|
position: relative;
|
||||||
|
height: 100%;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.webbpm footer {
|
||||||
|
position: absolute;
|
||||||
|
color: var(--black);
|
||||||
|
font-size: 12px;
|
||||||
|
bottom: 0;
|
||||||
|
left: 15px;
|
||||||
|
right: 15px;
|
||||||
|
height: 50px;
|
||||||
|
padding: 15px 0;
|
||||||
|
border-top: 1px solid #c1c1c1;
|
||||||
|
background: transparent;
|
||||||
|
|
||||||
|
span + span {
|
||||||
|
padding-left: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*--------- TOP MENU ----------*/
|
||||||
|
.webbpm .logo {
|
||||||
|
display: inline-block;
|
||||||
|
margin: 0;
|
||||||
|
float: left;
|
||||||
|
|
||||||
|
a {
|
||||||
|
width: 200px;
|
||||||
|
height: 67px;
|
||||||
|
position: absolute;
|
||||||
|
background: url("../img/logo.png") no-repeat 0 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.webbpm .header {
|
||||||
|
position: absolute;
|
||||||
|
color: var(--white);
|
||||||
|
font-family: Corbel;
|
||||||
|
font-size: var(--size-text-secondary);
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
height: 67px;
|
||||||
|
min-height: 67px;
|
||||||
|
line-height: normal;
|
||||||
|
border: 0;
|
||||||
|
padding: 0;
|
||||||
|
background: #b9c0ca;
|
||||||
|
z-index: 997;
|
||||||
|
|
||||||
|
.nav .nav-link {
|
||||||
|
color: var(--white);
|
||||||
|
float: none;
|
||||||
|
display: block;
|
||||||
|
line-height: 60px;
|
||||||
|
padding: 0 15px 0 60px;
|
||||||
|
text-shadow: none;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav .nav-link:hover {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.webbpm .dropdown-menu {
|
||||||
|
background-color: #eee;
|
||||||
|
}
|
||||||
|
|
||||||
|
.webbpm .nav .nav-item .dropdown-menu:after {
|
||||||
|
border-bottom: 6px solid #eee;
|
||||||
|
}
|
||||||
|
|
||||||
|
.webbpm .inner {
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 768px) {
|
||||||
|
.webbpm .navbar .nav > * {
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 767px) {
|
||||||
|
.webbpm .dropdown-menu > div > button {
|
||||||
|
color: #d1dbe5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*--------- end - TOP MENU ----------*/
|
||||||
|
.webbpm .user-department,
|
||||||
|
.webbpm .user-info {
|
||||||
|
color: #5a6473;
|
||||||
|
}
|
||||||
|
|
||||||
|
.webbpm .user-info > * {
|
||||||
|
display: inline-block;
|
||||||
|
margin-left: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.webbpm [log-out] {
|
||||||
|
max-width: 40%;
|
||||||
|
margin-right: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.webbpm .content {
|
||||||
|
padding: 0 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.webbpm .inner {
|
||||||
|
min-height: 100%;
|
||||||
|
height: 100%;
|
||||||
|
overflow-y : scroll;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*--------------task-list------------------*/
|
||||||
|
.task-list {
|
||||||
|
font-size: 0;
|
||||||
|
height: 100%;
|
||||||
|
min-height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-list > div {
|
||||||
|
display: block;
|
||||||
|
float: left;
|
||||||
|
height: 100%;
|
||||||
|
min-height: 100%;
|
||||||
|
font-size: var(--size-text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-list-tree-panel {
|
||||||
|
width: 20%;
|
||||||
|
background: #e9edf2;
|
||||||
|
border-right: 1px solid #b9c1ca;
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-list-tree-panel .task-list-filter {
|
||||||
|
position: relative;
|
||||||
|
margin-top: 15px;
|
||||||
|
z-index: 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-list-tree-panel .task-list-filter li {
|
||||||
|
position: relative;
|
||||||
|
padding: 8px 10px;
|
||||||
|
margin: 2px 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-list-tree-panel .task-list-filter li::before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
left: 0px;
|
||||||
|
bottom: 0px;
|
||||||
|
right: 0;
|
||||||
|
top: 0;
|
||||||
|
border: 1px solid rgb(206, 212, 219);
|
||||||
|
border-radius: 4px;
|
||||||
|
background-color: var(--white);
|
||||||
|
opacity: 0.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-list-tree-panel .task-list-filter li label:hover {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-list-tree-panel .task-list-filter li label {
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
margin: 0;
|
||||||
|
z-index: 11;
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-list-tree-panel .task-list-filter li label input[type="radio"] {
|
||||||
|
float: left;
|
||||||
|
margin-top: 2px;
|
||||||
|
margin-right: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-list-tree-panel .task-list-filter li label span {
|
||||||
|
float: right;
|
||||||
|
background-color: #bbb;
|
||||||
|
padding: 0px 4px;
|
||||||
|
border-radius: 3px;
|
||||||
|
min-width: 25px;
|
||||||
|
text-align: center;
|
||||||
|
color: var(--white);
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-list-tree-panel .task-list-filter li.ontime label span {
|
||||||
|
background-color: #a0c367;
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-list-tree-panel .task-list-filter li.overdue label span {
|
||||||
|
background-color: #fc2d2d;
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-list-header {
|
||||||
|
border-bottom: 1px solid #b9c1ca;
|
||||||
|
background-color: #ccd6e0;
|
||||||
|
height: 30px;
|
||||||
|
line-height: 30px;
|
||||||
|
color: #565968;
|
||||||
|
font-size: var(--size-text-secondary);
|
||||||
|
padding: 0 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.structure-box {
|
||||||
|
padding: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-list-workplace {
|
||||||
|
width: 80%;
|
||||||
|
padding: 15px 15px 0;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
/*--------------task-list end--------------*/
|
||||||
|
|
||||||
|
/*---------------table-list----------------*/
|
||||||
|
.task-tbl {
|
||||||
|
background: var(--white);
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-tbl .td, .task-tbl .th {
|
||||||
|
border: 1px solid #b9c1ca;
|
||||||
|
padding: 10px 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-tbl .th {
|
||||||
|
color: #565968;
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-tbl .td {
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-tbl .thead {
|
||||||
|
background: #ccd6e0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-tbl > .tr:hover {
|
||||||
|
cursor: pointer;
|
||||||
|
background: #e9edf2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-tbl .tr.task-ontime > .td.task,
|
||||||
|
.task-tbl .tr.task-overdue > .td.task {
|
||||||
|
position: relative;
|
||||||
|
padding-left: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-tbl .tr.task-ontime > .td.task::before,
|
||||||
|
.task-tbl .tr.task-overdue > .td.task::before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
top: 12px;
|
||||||
|
left: 5px;
|
||||||
|
width: 10px;
|
||||||
|
height: 10px;
|
||||||
|
background-color: #a0c367;
|
||||||
|
border-radius: 10px;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-tbl .tr.task-overdue > .td.task::before {
|
||||||
|
background-color: #ff0000;
|
||||||
|
}
|
||||||
|
/*----------------table-list end----------------*/
|
||||||
|
|
||||||
|
/*--------------Окно сообщения об ошибке--------------*/
|
||||||
|
.webbpm #toast-container {
|
||||||
|
font-size: 12px;
|
||||||
|
bottom: auto;
|
||||||
|
overflow-y: auto;
|
||||||
|
overflow-x: hidden;
|
||||||
|
max-height: 95%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.webbpm #toast-container .toast:hover {
|
||||||
|
box-shadow: 0 0 12px #999999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.webbpm #toast-container .ngx-toastr {
|
||||||
|
min-width: 540px;
|
||||||
|
opacity: 0.9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.webbpm #toast-container .toast-error {
|
||||||
|
background-color: #d9534f;
|
||||||
|
}
|
||||||
|
|
||||||
|
.webbpm #toast-container .toast-close-button {
|
||||||
|
text-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.webbpm .toast-message > div {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.webbpm .toast-message > .active {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.webbpm .toast-message > .active::after {
|
||||||
|
display: block;
|
||||||
|
content: "";
|
||||||
|
float: none;
|
||||||
|
clear: both;
|
||||||
|
}
|
||||||
|
|
||||||
|
.webbpm .toast-message > .active a {
|
||||||
|
float: right;
|
||||||
|
margin: 5px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.webbpm .toast-message > .toast-msg-close.active ~ .toast-msg-text {
|
||||||
|
display: block;
|
||||||
|
font-size: 0.8em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.webbpm .toast-message a:not([href]):not([tabindex]) {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
/*------------Окно сообщения об ошибке end------------*/
|
||||||
|
|
||||||
|
/*----------------- Ошибка 404 -------------------*/
|
||||||
|
.webbpm .container .task-not-found-page {
|
||||||
|
position: relative;
|
||||||
|
display: table;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.webbpm .container .task-not-found-container {
|
||||||
|
display: table-cell;
|
||||||
|
color: var(--black);
|
||||||
|
font-size: 1.8em;
|
||||||
|
background-color: #c9d4e0;
|
||||||
|
text-align: center;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
.webbpm .container .task-not-found-container > div {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.webbpm .container .task-not-found-container > div:first-child {
|
||||||
|
color: var(--white);
|
||||||
|
font-size: 7.8em;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.webbpm .container .task-not-found-container > div:last-child {
|
||||||
|
text-align: left;
|
||||||
|
margin-left: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.webbpm .container .task-not-found-container h2 {
|
||||||
|
font-size: 2em;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.webbpm .container .task-not-found-container a {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
/*--------------- end Ошибка 404 -----------------*/
|
||||||
|
|
||||||
|
/*-------------- MOBILE --------------*/
|
||||||
|
.webbpm.mobile .task-list-tree-panel,
|
||||||
|
.webbpm.mobile footer {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.webbpm.mobile .task-list-workplace {
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.webbpm.mobile .container {
|
||||||
|
bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.webbpm.mobile form {
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.webbpm.mobile .form-signin {
|
||||||
|
width: auto;
|
||||||
|
padding: 20px;
|
||||||
|
margin: 40px 20px;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.webbpm.mobile .form-signin h1,
|
||||||
|
.webbpm.mobile .form-signin h2 {
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.webbpm.mobile .form-signin label {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.webbpm.mobile .form-signin input[type="text"],
|
||||||
|
.webbpm.mobile .form-signin input[type="password"] {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.webbpm.mobile .form-signin .login-btn-box {
|
||||||
|
width: auto;
|
||||||
|
margin-right: 0;
|
||||||
|
}
|
||||||
|
/*-------------- end MOBILE --------------*/
|
||||||
|
|
||||||
|
|
||||||
|
/*-------------- НОВЫЙ ДИЗАЙН --------------*/
|
||||||
|
/*------------------ Фильтры ------------------*/
|
||||||
|
.webbpm .task-list {
|
||||||
|
height: auto;
|
||||||
|
min-height: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.webbpm .task-list > .task-list-tree-panel {
|
||||||
|
background: var(--white);
|
||||||
|
border-right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.webbpm .task-list > .task-list-tree-panel,
|
||||||
|
.webbpm .task-list > .task-list-workplace {
|
||||||
|
font-size: var(--size-text-secondary);
|
||||||
|
float: none;
|
||||||
|
width: 100%;
|
||||||
|
height: auto;
|
||||||
|
min-height: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.webbpm .task-list-tree-panel .task-list-filter {
|
||||||
|
font-family: Corbel;
|
||||||
|
margin: 0;
|
||||||
|
box-shadow: 0px 4px 10px -5px rgba(40, 40, 40, 0.3);
|
||||||
|
|
||||||
|
ul {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
li {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 12px 0px;
|
||||||
|
margin: 0;
|
||||||
|
|
||||||
|
&:first-of-type {
|
||||||
|
font-size: 1.4em;
|
||||||
|
font-weight: bold;
|
||||||
|
width: 197px;
|
||||||
|
padding: 0 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
label {
|
||||||
|
font-size: 1.3em;
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
label div {
|
||||||
|
display: inline-block;
|
||||||
|
width: 10px;
|
||||||
|
height: 10px;
|
||||||
|
border-radius: 10px;
|
||||||
|
margin-right: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.ontime label div {
|
||||||
|
background-color: #2da6a1;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.overdue label div {
|
||||||
|
background-color: #9c5d7a;
|
||||||
|
}
|
||||||
|
|
||||||
|
label input[type="radio"] {
|
||||||
|
float: none;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
label span {
|
||||||
|
float: none;
|
||||||
|
color: var(--black);
|
||||||
|
font-weight: normal;
|
||||||
|
text-align: left;
|
||||||
|
min-width: auto;
|
||||||
|
padding: 5px 15px;
|
||||||
|
border-radius: 0;
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
label input[type="radio"].ng-valid-parse ~ span {
|
||||||
|
background-color: #eaedf2;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*-------------- end НОВЫЙ ДИЗАЙН --------------*/
|
||||||
|
|
||||||
|
.webbpm .dialog-stack-trace {
|
||||||
|
overflow-x: auto;
|
||||||
|
overflow-y: auto;
|
||||||
|
max-height: 300px;
|
||||||
|
}
|
||||||
|
.webbpm .dialog-show-button {
|
||||||
|
text-decoration: underline;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.webbpm .dialog-error-number {
|
||||||
|
font-size: 1.25rem;
|
||||||
|
}
|
||||||
|
.webbpm .dialog-error-title {
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-- login --*/
|
||||||
|
.webbpm :is(.form-signin, .form-signup, .confirm) {
|
||||||
|
color: #333;
|
||||||
|
width: 580px;
|
||||||
|
padding: 80px 100px;
|
||||||
|
margin: 20px auto;
|
||||||
|
border: 1px solid var(--bg-light);
|
||||||
|
background: var(--white);
|
||||||
|
}
|
||||||
|
|
||||||
|
.webbpm .form-signin.esia {
|
||||||
|
width: 450px;
|
||||||
|
text-align: center;
|
||||||
|
padding: 45px 55px 35px 55px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.webbpm .form-signin h1,
|
||||||
|
.webbpm .form-signin h2,
|
||||||
|
.webbpm .form-signup h2,
|
||||||
|
.webbpm .confirm h2 {
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.webbpm .form-signin.esia :is(h1, h2) {
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.webbpm .form-signin label,
|
||||||
|
.webbpm .form-signup label {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.webbpm .form-signin input {
|
||||||
|
width: 240px;
|
||||||
|
font-size: var(--size-text-secondary);
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.webbpm .form-signin.esia input {
|
||||||
|
width: 160px;
|
||||||
|
margin-top: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.webbpm :is(.form-signin, .form-signup) .row {
|
||||||
|
display: flex;
|
||||||
|
margin: 0 0 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.webbpm .registration-link,
|
||||||
|
.webbpm .login-link {
|
||||||
|
margin-right: 20px;
|
||||||
|
font-size: var(--size-text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.webbpm .form-signin .row.registration {
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
|
||||||
|
.webbpm .form-signin .login-btn-box {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.webbpm .form-signin .row.registration > * + *,
|
||||||
|
.webbpm .form-signin .login-btn-box .password,
|
||||||
|
.webbpm .form-signin .login-btn-box .btn + .btn {
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.webbpm .input-group > .input-group-append > .input-group-text {
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.webbpm .form-signin .register-btn-box,
|
||||||
|
.webbpm .form-signup .register-btn-box,
|
||||||
|
.webbpm .form-signup .reset-password-btn-box {
|
||||||
|
width: 220px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.webbpm .form-signup .row international-phone-number .flagInput .btn {
|
||||||
|
border-left: 1px solid #c6cdd3;
|
||||||
|
}
|
||||||
|
.webbpm .form-signup .row international-phone-number .flagInput ~ input {
|
||||||
|
border-left: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.webbpm .form-signin .has-error .help-block {
|
||||||
|
padding-left: 125px;
|
||||||
|
font-size: var(--size-text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.webbpm .form-signup .has-account a {
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*------------------ Формы регистрации и подтверждения ------------------*/
|
||||||
|
.form-signup .has-account {
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-signup .has-account a span,
|
||||||
|
.confirm a span {
|
||||||
|
margin-right: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-signup .dropbtn.btn {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-signup .input-group-text {
|
||||||
|
border-left-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-signup input.ng-invalid.ng-touched,
|
||||||
|
.form-signup input.ng-invalid.ng-dirty {
|
||||||
|
border-color: red !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-signup .msg-alert {
|
||||||
|
color: red;
|
||||||
|
font-size: 11px;
|
||||||
|
padding: 3px 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-signup .consent {
|
||||||
|
color: #929292;
|
||||||
|
font-size: 13px;
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
/*------------------ End - Формы регистрации и подтверждения ------------------*/
|
||||||
|
|
||||||
|
/*------------------ Сообщения об ошибке ------------------*/
|
||||||
|
.webbpm .error_message {
|
||||||
|
width: 650px;
|
||||||
|
margin: 0 auto;
|
||||||
|
margin-top: 10%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.webbpm .error_title {
|
||||||
|
position: relative;
|
||||||
|
color: #9c5d7a;
|
||||||
|
font-size: 5.5em;
|
||||||
|
font-weight: bold;
|
||||||
|
margin-left: 100px;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
.webbpm .error_title::before {
|
||||||
|
position: absolute;
|
||||||
|
content: "";
|
||||||
|
left: -100px;
|
||||||
|
width: 75px;
|
||||||
|
height: 75px;
|
||||||
|
border-radius: 40px;
|
||||||
|
background-color: #9c5d7a;
|
||||||
|
background-image: url("../img/access_denied.png");
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: 50% 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.webbpm .error_title_long {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
font-size: 2.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.webbpm .error_body {
|
||||||
|
font-size: 2em;
|
||||||
|
line-height: 1.2;
|
||||||
|
margin: 5px 0 0 100px;
|
||||||
|
}
|
||||||
|
/*---------------- end Сообщения об ошибке ---------------*/
|
||||||
|
/*-------------- Поле телефона ------------ */
|
||||||
|
.flag {
|
||||||
|
background-image: url('./../img/country-flags.jpg') !important;
|
||||||
|
}
|
||||||
|
/*-------------- end Поле телефона ------------ */
|
||||||
|
|
||||||
10
frontend/src/resources/css/style.css
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
@import "../../../node_modules/angular-calendar/css/angular-calendar.css";
|
||||||
|
@import "../../../node_modules/bootstrap/dist/css/bootstrap-grid.css";
|
||||||
|
@import "../../../node_modules/bootstrap/dist/css/bootstrap-reboot.css";
|
||||||
|
@import "../../../node_modules/bootstrap/dist/css/bootstrap.css";
|
||||||
|
@import "../../../node_modules/bootstrap-icons/font/bootstrap-icons.css";
|
||||||
|
@import "../../../node_modules/font-awesome/css/font-awesome.css";
|
||||||
|
@import "../../../node_modules/@webbpm/base-package/css/style.css";
|
||||||
|
@import "structure.css";
|
||||||
|
@import "inbox-app.css";
|
||||||
|
@import "components-app.css";
|
||||||
BIN
frontend/src/resources/fonts/Segoe.ttf
Normal file
BIN
frontend/src/resources/fonts/SegoeB.ttf
Normal file
BIN
frontend/src/resources/fonts/SegoeBL.ttf
Normal file
BIN
frontend/src/resources/fonts/SegoeSB.ttf
Normal file
BIN
frontend/src/resources/fonts/SegoeSL.ttf
Normal file
BIN
frontend/src/resources/img/access_denied.png
Normal file
|
After Width: | Height: | Size: 855 B |
BIN
frontend/src/resources/img/admin.png
Normal file
|
After Width: | Height: | Size: 811 B |
BIN
frontend/src/resources/img/country-flags.jpg
Normal file
|
After Width: | Height: | Size: 30 KiB |
BIN
frontend/src/resources/img/create.png
Normal file
|
After Width: | Height: | Size: 673 B |
10
frontend/src/resources/img/icons/dots-six-vertical.svg
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g clip-path="url(#clip0_340_5833)">
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M6.5 3.75C6.5 4.16421 6.16421 4.5 5.75 4.5C5.33579 4.5 5 4.16421 5 3.75C5 3.33579 5.33579 3 5.75 3C6.16421 3 6.5 3.33579 6.5 3.75ZM11 3.75C11 4.16421 10.6642 4.5 10.25 4.5C9.83579 4.5 9.5 4.16421 9.5 3.75C9.5 3.33579 9.83579 3 10.25 3C10.6642 3 11 3.33579 11 3.75ZM5.75 8.75C6.16421 8.75 6.5 8.41421 6.5 8C6.5 7.58579 6.16421 7.25 5.75 7.25C5.33579 7.25 5 7.58579 5 8C5 8.41421 5.33579 8.75 5.75 8.75ZM11 8C11 8.41421 10.6642 8.75 10.25 8.75C9.83579 8.75 9.5 8.41421 9.5 8C9.5 7.58579 9.83579 7.25 10.25 7.25C10.6642 7.25 11 7.58579 11 8ZM5.75 13C6.16421 13 6.5 12.6642 6.5 12.25C6.5 11.8358 6.16421 11.5 5.75 11.5C5.33579 11.5 5 11.8358 5 12.25C5 12.6642 5.33579 13 5.75 13ZM11 12.25C11 12.6642 10.6642 13 10.25 13C9.83579 13 9.5 12.6642 9.5 12.25C9.5 11.8358 9.83579 11.5 10.25 11.5C10.6642 11.5 11 11.8358 11 12.25Z" fill="#353535"/>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<clipPath id="clip0_340_5833">
|
||||||
|
<rect width="16" height="16" fill="white"/>
|
||||||
|
</clipPath>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.1 KiB |
3
frontend/src/resources/img/icons/settings-sm.svg
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M14.4289 4.03093L14.5357 3.84641C14.7628 3.46915 15.2354 3.35853 15.5798 3.56346L15.593 3.57113L17.3235 4.56141C17.7982 4.83272 17.9624 5.4493 17.6908 5.91957C17.1401 6.8701 16.9763 7.94135 17.4902 8.83311C18.0042 9.72502 19.0132 10.12 20.11 10.12C20.656 10.12 21.11 10.5701 21.11 11.12V12.88C21.11 13.426 20.6598 13.88 20.11 13.88C19.0132 13.88 18.0042 14.275 17.4902 15.1669C16.9767 16.058 17.1399 17.1284 17.6896 18.0784C17.9642 18.5612 17.7961 19.1685 17.323 19.4389L15.593 20.4289L15.5798 20.4365C15.2354 20.6415 14.7628 20.5308 14.5357 20.1536L14.4308 19.9724L14.4297 19.9706C13.8837 19.0191 13.0383 18.3425 12.0087 18.3425C10.9799 18.3425 10.1319 19.0187 9.58109 19.9691L9.47424 20.1536C9.24711 20.5308 8.77457 20.6414 8.43014 20.4365L8.41699 20.4289L6.6865 19.4386C6.21174 19.1673 6.04759 18.5507 6.31911 18.0805C6.8698 17.1299 7.03367 16.0587 6.51976 15.1669C6.00578 14.275 4.99672 13.88 3.89998 13.88C3.35011 13.88 2.89998 13.426 2.89998 12.88V11.12C2.89998 10.574 3.35011 10.12 3.89998 10.12C4.99672 10.12 6.00578 9.72502 6.51976 8.83311C7.03367 7.94133 6.8698 6.87005 6.31911 5.9195C6.04759 5.44924 6.21222 4.83243 6.68699 4.56113L8.41699 3.57113L8.43014 3.56346C8.77458 3.35854 9.24714 3.46915 9.47426 3.8464L9.58016 4.02932C10.1262 4.98086 10.9716 5.65749 12.0012 5.65749C13.03 5.65749 13.878 4.9813 14.4289 4.03093ZM6.31911 5.9195C6.31895 5.91922 6.31879 5.91894 6.31863 5.91867L5.53998 6.36999L6.31925 5.91974C6.31921 5.91966 6.31916 5.91958 6.31911 5.9195ZM17.6896 18.0784C17.6902 18.0794 17.6908 18.0804 17.6913 18.0813L18.47 17.63L17.6886 18.0765C17.6889 18.0772 17.6893 18.0778 17.6896 18.0784ZM12.9865 2.92983C13.6989 1.73245 15.2596 1.28388 16.4929 2.01224L18.217 2.99885C19.5618 3.76765 20.0174 5.49069 19.2493 6.82024L19.2486 6.82132C18.8897 7.44056 18.9688 7.79392 19.0498 7.93437C19.1308 8.07497 19.3967 8.31999 20.11 8.31999C21.6439 8.31999 22.91 9.56986 22.91 11.12V12.88C22.91 14.414 21.6601 15.68 20.11 15.68C19.3967 15.68 19.1308 15.925 19.0498 16.0656C18.9688 16.2061 18.8897 16.5594 19.2486 17.1787L19.2514 17.1835C20.0153 18.5204 19.5627 20.2321 18.2165 21.0014L16.4929 21.9878C15.2596 22.7161 13.6989 22.2675 12.9865 21.0702L12.9811 21.0609L12.8711 20.8709L12.8692 20.8676C12.5152 20.25 12.171 20.1425 12.0087 20.1425C11.8451 20.1425 11.4977 20.252 11.1386 20.8713L11.0234 21.0702C10.3111 22.2675 8.75036 22.7161 7.51707 21.9878L5.79345 21.0014C4.4483 20.2328 3.99242 18.5095 4.7607 17.1797L4.76132 17.1787C5.12024 16.5594 5.04113 16.2061 4.96019 16.0656C4.87917 15.925 4.61323 15.68 3.89998 15.68C2.34984 15.68 1.09998 14.414 1.09998 12.88V11.12C1.09998 9.58602 2.34984 8.31999 3.89998 8.31999C4.61323 8.31999 4.87917 8.07497 4.96019 7.93437C5.04113 7.79392 5.12024 7.44056 4.76132 6.82132L4.7607 6.82024C3.99251 5.49069 4.44867 3.76737 5.79345 2.99857L7.51705 2.01224C8.75034 1.28388 10.3111 1.73245 11.0234 2.92983L11.0289 2.93906L11.1408 3.1324C11.4948 3.74995 11.8389 3.85749 12.0012 3.85749C12.1649 3.85749 12.5122 3.74829 12.8713 3.12867L12.9865 2.92983ZM9.89998 12C9.89998 10.8402 10.8402 9.89998 12 9.89998C13.1598 9.89998 14.1 10.8402 14.1 12C14.1 13.1598 13.1598 14.1 12 14.1C10.8402 14.1 9.89998 13.1598 9.89998 12ZM12 8.09998C9.84607 8.09998 8.09998 9.84607 8.09998 12C8.09998 14.1539 9.84607 15.9 12 15.9C14.1539 15.9 15.9 14.1539 15.9 12C15.9 9.84607 14.1539 8.09998 12 8.09998Z" fill="#353535"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 3.4 KiB |
BIN
frontend/src/resources/img/logo-full.png
Normal file
|
After Width: | Height: | Size: 5.7 KiB |
BIN
frontend/src/resources/img/logo.png
Normal file
|
After Width: | Height: | Size: 4.8 KiB |
BIN
frontend/src/resources/img/progress.gif
Normal file
|
After Width: | Height: | Size: 6.6 KiB |
BIN
frontend/src/resources/img/project.png
Normal file
|
After Width: | Height: | Size: 712 B |
BIN
frontend/src/resources/img/tasks.png
Normal file
|
After Width: | Height: | Size: 351 B |
|
|
@ -0,0 +1,9 @@
|
||||||
|
<div>
|
||||||
|
<button type="button"
|
||||||
|
[disabled]="!isEnabled()"
|
||||||
|
class="btn btn-secondary"
|
||||||
|
[ngbTooltip]="tooltip | emptyIfNull"
|
||||||
|
(click)="onClick()"
|
||||||
|
(focus)="onFocus()"
|
||||||
|
(blur)="onBlur()">{{caption}}</button>
|
||||||
|
</div>
|
||||||