diff --git a/.github/workflows/master-build.yml b/.github/workflows/master-build.yml
index 70e69121d2a..c3fe0421419 100644
--- a/.github/workflows/master-build.yml
+++ b/.github/workflows/master-build.yml
@@ -36,7 +36,7 @@ jobs:
timeout-minutes: 90
services:
mongo:
- image: mongo:7.0.9
+ image: mongo:8.0.3
ports:
- 27017:27017
@@ -46,7 +46,7 @@ jobs:
- 6379:6379
elasticsearch:
- image: elasticsearch:8.10.4
+ image: elasticsearch:8.15.3
ports:
- 9200:9200
- 9300:9300
@@ -92,7 +92,7 @@ jobs:
restore-keys: ${{ runner.os }}-m2
- name: Generate certificates
- run: cd src/main/resources/certificates && openssl genrsa -out keypair.pem 4096 && openssl rsa -in keypair.pem -pubout -out public.crt && openssl pkcs8 -topk8 -inform PEM -outform DER -nocrypt -in keypair.pem -out private.der && cd ../../../..
+ run: cd application-engine/src/main/resources/certificates && openssl genrsa -out keypair.pem 4096 && openssl rsa -in keypair.pem -pubout -out public.crt && openssl pkcs8 -topk8 -inform PEM -outform DER -nocrypt -in keypair.pem -out private.der && cd ../../../../..
- name: Build
run: mvn clean package install -DskipTests=true
@@ -137,7 +137,7 @@ jobs:
- name: Generate Docs
run: |
mvn javadoc:javadoc
- cp -r ./target/apidocs/* ./docs/javadoc/
+ cp -r ./application-engine/target/reports/apidocs/* ./docs/javadoc/
- uses: EndBug/add-and-commit@v9
with:
diff --git a/.github/workflows/nexus-release.yml b/.github/workflows/nexus-release.yml
new file mode 100644
index 00000000000..4379ba25459
--- /dev/null
+++ b/.github/workflows/nexus-release.yml
@@ -0,0 +1,53 @@
+name: Publish package to Netgrif Nexus
+on: workflow_dispatch
+
+jobs:
+ build:
+ name: Build
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ with:
+ fetch-depth: 0
+
+ - name: Set up JDK 21
+ uses: actions/setup-java@v4
+ with:
+ java-version: 21
+ distribution: 'temurin'
+
+ - name: Cache Maven packages
+ uses: actions/cache@v4
+ with:
+ path: ~/.m2
+ key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
+ restore-keys: ${{ runner.os }}-m2
+
+ - name: Build
+ run: mvn clean verify -DskipTests=true
+
+ publish-OSSRH:
+ runs-on: ubuntu-latest
+ name: Publish to Netgrif Nexus
+ needs: build
+ permissions:
+ contents: read
+ packages: write
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Set up Maven Central Repository
+ uses: actions/setup-java@v4
+ with:
+ java-version: 21
+ distribution: 'temurin'
+ server-id: netgrif-nexus-snapshots
+ server-username: MAVEN_USERNAME
+ server-password: MAVEN_PASSWORD
+
+ - name: Publish package
+ run: mvn -DskipTests=true --batch-mode -P netgrif-nexus-publish deploy
+ env:
+ MAVEN_USERNAME: ${{ secrets.NEXUS_USERNAME }}
+ MAVEN_PASSWORD: ${{ secrets.NEXUS_PASSWORD }}
+
diff --git a/.github/workflows/pr-build.yml b/.github/workflows/pr-build.yml
index 153708dea80..11023d31dbc 100644
--- a/.github/workflows/pr-build.yml
+++ b/.github/workflows/pr-build.yml
@@ -35,7 +35,7 @@ jobs:
timeout-minutes: 200
services:
mongo:
- image: mongo:7.0.9
+ image: mongo:8.0.3
ports:
- 27017:27017
@@ -45,7 +45,7 @@ jobs:
- 6379:6379
elasticsearch:
- image: elasticsearch:8.10.4
+ image: elasticsearch:8.15.3
ports:
- 9200:9200
- 9300:9300
@@ -91,7 +91,7 @@ jobs:
restore-keys: ${{ runner.os }}-m2
- name: Generate certificates
- run: cd src/main/resources/certificates && openssl genrsa -out keypair.pem 4096 && openssl rsa -in keypair.pem -pubout -out public.crt && openssl pkcs8 -topk8 -inform PEM -outform DER -nocrypt -in keypair.pem -out private.der && cd ../../../..
+ run: cd application-engine/src/main/resources/certificates && openssl genrsa -out keypair.pem 4096 && openssl rsa -in keypair.pem -pubout -out public.crt && openssl pkcs8 -topk8 -inform PEM -outform DER -nocrypt -in keypair.pem -out private.der && cd ../../../../..
- name: Build
diff --git a/.github/workflows/release-build.yml b/.github/workflows/release-build.yml
index 6a72353990b..0c2cb66a9b8 100644
--- a/.github/workflows/release-build.yml
+++ b/.github/workflows/release-build.yml
@@ -47,7 +47,7 @@ jobs:
needs: build
services:
mongo:
- image: mongo:7.0.9
+ image: mongo:8.0.3
ports:
- 27017:27017
@@ -57,7 +57,7 @@ jobs:
- 6379:6379
elasticsearch:
- image: elasticsearch:8.10.4
+ image: elasticsearch:8.15.3
ports:
- 9200:9200
- 9300:9300
@@ -103,7 +103,7 @@ jobs:
restore-keys: ${{ runner.os }}-m2
- name: Generate certificates
- run: cd src/main/resources/certificates && openssl genrsa -out keypair.pem 4096 && openssl rsa -in keypair.pem -pubout -out public.crt && openssl pkcs8 -topk8 -inform PEM -outform DER -nocrypt -in keypair.pem -out private.der && cd ../../../..
+ run: cd application-engine/src/main/resources/certificates && openssl genrsa -out keypair.pem 4096 && openssl rsa -in keypair.pem -pubout -out public.crt && openssl pkcs8 -topk8 -inform PEM -outform DER -nocrypt -in keypair.pem -out private.der && cd ../../../../..
- name: Build
run: mvn clean package install -DskipTests=true
@@ -257,8 +257,8 @@ jobs:
- name: Build project
run: |
mkdir -p netgrif-application-engine-${{ steps.getVersion.outputs.version }}/src/main/resources/
- cp target/*-exec.jar netgrif-application-engine-${{ steps.getVersion.outputs.version }}
- cp -R src/main/resources/* netgrif-application-engine-${{ steps.getVersion.outputs.version }}/src/main/resources/
+ cp application-engine/target/*-exec.jar netgrif-application-engine-${{ steps.getVersion.outputs.version }}
+ cp -R application-engine/src/main/resources/* netgrif-application-engine-${{ steps.getVersion.outputs.version }}/src/main/resources/
zip -r netgrif-application-engine-${{ steps.getVersion.outputs.version }}.zip netgrif-application-engine-${{ steps.getVersion.outputs.version }}
- name: Upload binaries to release
diff --git a/.gitignore b/.gitignore
index f0766ef0466..450790f1fdc 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,82 @@
+### Intellij template
+# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
+# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
+
+# User-specific stuff
+.idea/**/workspace.xml
+.idea/**/tasks.xml
+.idea/**/usage.statistics.xml
+.idea/**/dictionaries
+.idea/**/shelf
+
+# AWS User-specific
+.idea/**/aws.xml
+
+# Generated files
+.idea/**/contentModel.xml
+
+# Sensitive or high-churn files
+.idea/**/dataSources/
+.idea/**/dataSources.ids
+.idea/**/dataSources.local.xml
+.idea/**/sqlDataSources.xml
+.idea/**/dynamic.xml
+.idea/**/uiDesigner.xml
+.idea/**/dbnavigator.xml
+
+# Gradle
+.idea/**/gradle.xml
+.idea/**/libraries
+
+# Gradle and Maven with auto-import
+# When using Gradle or Maven with auto-import, you should exclude module files,
+# since they will be recreated, and may cause churn. Uncomment if using
+# auto-import.
+# .idea/artifacts
+# .idea/compiler.xml
+# .idea/jarRepositories.xml
+# .idea/modules.xml
+# .idea/*.iml
+# .idea/modules
+# *.iml
+# *.ipr
+
+# CMake
+cmake-build-*/
+
+# Mongo Explorer plugin
+.idea/**/mongoSettings.xml
+
+# File-based project format
+*.iws
+
+# IntelliJ
+out/
+
+# mpeltonen/sbt-idea plugin
+.idea_modules/
+
+# JIRA plugin
+atlassian-ide-plugin.xml
+
+# Cursive Clojure plugin
+.idea/replstate.xml
+
+# SonarLint plugin
+.idea/sonarlint/
+
+# Crashlytics plugin (for Android Studio and IntelliJ)
+com_crashlytics_export_strings.xml
+crashlytics.properties
+crashlytics-build.properties
+fabric.properties
+
+# Editor-based Rest Client
+.idea/httpRequests
+
+# Android studio 3.1+ serialized cache file
+.idea/caches/build_file_checksums.ser
+
### Java template
# Compiled class file
*.class
@@ -22,6 +101,7 @@
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
+replay_pid*
### Maven template
target/
@@ -36,32 +116,39 @@ buildNumber.properties
# https://github.com/takari/maven-wrapper#usage-without-binary-jar
.mvn/wrapper/maven-wrapper.jar
+# Eclipse m2e generated files
+# Eclipse Core
+.project
+# JDT-specific (Eclipse Java Development Tools)
+.classpath
+
+### VisualStudioCode template
+.vscode/*
+!.vscode/settings.json
+!.vscode/tasks.json
+!.vscode/launch.json
+!.vscode/extensions.json
+!.vscode/*.code-snippets
+
+# Local History for Visual Studio Code
+.history/
+
+# Built Visual Studio Code Extensions
+*.vsix
+
### JetBrains template
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
# User-specific stuff
-.idea/**/workspace.xml
-.idea/**/tasks.xml
-.idea/**/usage.statistics.xml
-.idea/**/dictionaries
-.idea/**/shelf
+
+# AWS User-specific
# Generated files
-.idea/**/contentModel.xml
# Sensitive or high-churn files
-.idea/**/dataSources/
-.idea/**/dataSources.ids
-.idea/**/dataSources.local.xml
-.idea/**/sqlDataSources.xml
-.idea/**/dynamic.xml
-.idea/**/uiDesigner.xml
-.idea/**/dbnavigator.xml
# Gradle
-.idea/**/gradle.xml
-.idea/**/libraries
# Gradle and Maven with auto-import
# When using Gradle or Maven with auto-import, you should exclude module files,
@@ -77,37 +164,41 @@ buildNumber.properties
# *.ipr
# CMake
-cmake-build-*/
# Mongo Explorer plugin
-.idea/**/mongoSettings.xml
# File-based project format
-*.iws
# IntelliJ
-out/
# mpeltonen/sbt-idea plugin
-.idea_modules/
# JIRA plugin
-atlassian-ide-plugin.xml
# Cursive Clojure plugin
-.idea/replstate.xml
+
+# SonarLint plugin
# Crashlytics plugin (for Android Studio and IntelliJ)
-com_crashlytics_export_strings.xml
-crashlytics.properties
-crashlytics-build.properties
-fabric.properties
# Editor-based Rest Client
-.idea/httpRequests
# Android studio 3.1+ serialized cache file
-.idea/caches/build_file_checksums.ser
+
+### Linux template
+*~
+
+# temporary files which can be created if a process still has a handle open of a deleted file
+.fuse_hidden*
+
+# KDE directory preferences
+.directory
+
+# Linux trash folder which might appear on any partition or disk
+.Trash-*
+
+# .nfs files are created when an open file is removed but is still being accessed
+.nfs*
### Example user template template
### Example user template
@@ -117,29 +208,49 @@ fabric.properties
*.iml
out
gen
+### Groovy template
+# .gitignore created from Groovy contributors in https://github.com/apache/groovy/blob/master/.gitignore
-### STS ###
-.apt_generated
-.classpath
-.factorypath
-.project
-.settings
-.springBeans
+user.gradle
+.gradle/
+build/
+
+*.DS_Store
+*.swp
-### IntelliJ IDEA ###
*.ipr
+.shelf
+
+.settings/
+bin/
+
+modules/
+
+### macOS template
+# General
+.DS_Store
+.AppleDouble
+.LSOverride
+
+# Icon must end with two \r
+Icon
+
+# Thumbnails
+._*
+
+# Files that might appear in the root of a volume
+.DocumentRevisions-V100
+.fseventsd
+.Spotlight-V100
+.TemporaryItems
+.Trashes
+.VolumeIcon.icns
+.com.apple.timemachine.donotpresent
+
+# Directories potentially created on remote AFP share
+.AppleDB
+.AppleDesktop
+Network Trash Folder
+Temporary Items
+.apdisk
-### Work folder ###
-_issues/
-storage/
-/rules/
-*.log*
-log/
-!/src/main/java/com/netgrif/workflow/rules/
-!/src/main/java/com/netgrif/workflow/rules/domain/StoredRuleRepository.java
-
-### CERT ###
-/src/main/resources/certificates/keypair.pem
-/src/main/resources/certificates/private.der
-/src/main/resources/certificates/public.crt
-/modules/
diff --git a/.run/ApplicationEngine DEV with modules.run.xml b/.run/ApplicationEngine DEV with modules.run.xml
new file mode 100644
index 00000000000..d9b4347c1ee
--- /dev/null
+++ b/.run/ApplicationEngine DEV with modules.run.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Dockerfile b/Dockerfile
index 1b1659a090f..759dac7cd98 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,14 +1,17 @@
-FROM maven:3.9.7 AS build
-MAINTAINER Netgrif
-WORKDIR /app
-COPY src /app/src
-COPY pom.xml /app
-RUN mvn -P docker-build -DskipTests=true -f /app/pom.xml clean package install
+FROM openjdk:21-jdk
+LABEL authors="Netgrif "
+LABEL org.opencontainers.image.authors="NETGRIF "
+LABEL org.opencontainers.image.title="Netgrif Application Engine"
+LABEL org.opencontainers.image.url="https://platform.netgrif.cloud"
+LABEL org.opencontainers.image.documentation="https://platform.netgrif.cloud/docs"
+LABEL org.opencontainers.image.vendor="NETGRIF"
+RUN mkdir -p /opt/netgrif/engine
+RUN mkdir -p /opt/netgrif/engine/modules
+COPY application-engine/target/app-exec.jar /opt/netgrif/engine/app.jar
+COPY application-engine/src/main/resources /opt/netgrif/engine/src/main/resources
-FROM openjdk:21-jdk
-MAINTAINER Netgrif
-COPY --from=build app/target/app-exec.jar /app.jar
-COPY --from=build app/src/main/resources /src/main/resources
+WORKDIR /opt/netgrif/engine
EXPOSE 8080
-ENTRYPOINT ["java","-jar","/app.jar"]
+
+ENTRYPOINT ["java","-Dfile.encoding=UTF-8","-jar","app.jar"]
diff --git a/Dockerfile.broken b/Dockerfile.broken
new file mode 100644
index 00000000000..5072e1de2e1
--- /dev/null
+++ b/Dockerfile.broken
@@ -0,0 +1,44 @@
+# fetch dependencies
+FROM maven:3.9.7 AS deps
+LABEL authors="Netgrif "
+WORKDIR /nae
+COPY pom.xml .
+COPY nae-object-library/pom.xml nae-object-library/pom.xml
+COPY nae-spring-core-adapter/pom.xml nae-spring-core-adapter/pom.xml
+COPY nae-user-common/pom.xml nae-user-common/pom.xml
+COPY nae-user-ce/pom.xml nae-user-ce/pom.xml
+COPY application-engine/pom.xml application-engine/pom.xml
+RUN mvn -B -e org.apache.maven.plugins:maven-dependency-plugin:3.1.2:go-offline -DexcludeArtifactIds=nae-object-library,nae-spring-core-adapter,nae-user-common,nae-user-ce
+
+
+# build jar
+FROM maven:3.9.7 AS build
+LABEL authors="Netgrif "
+WORKDIR /nae
+COPY --from=deps /root/.m2 /root/.m2
+COPY --from=deps /nae/ /nae
+COPY nae-object-library/src /nae/nae-object-library/src
+COPY nae-spring-core-adapter/src /nae/nae-spring-core-adapter/src
+COPY nae-user-common/src /nae/nae-user-common/src
+COPY nae-user-ce/src /nae/nae-user-ce/src
+COPY application-engine/src /nae/application-engine/src
+RUN mvn -B -e -DskipTests -P docker-build clean package install
+
+
+# prepare runtime
+FROM openjdk:21-jdk
+LABEL authors="Netgrif "
+LABEL org.opencontainers.image.authors="NETGRIF "
+LABEL org.opencontainers.image.title="Netgrif Application Engine"
+LABEL org.opencontainers.image.url="https://platform.netgrif.cloud"
+LABEL org.opencontainers.image.documentation="https://platform.netgrif.cloud/docs"
+LABEL org.opencontainers.image.vendor="NETGRIF"
+
+RUN mkdir -p /opt/netgrif/engine && adduser -M netgrif
+COPY --from=build /nae/application-engine/target/app-exec.jar /opt/netgrif/engine/app.jar
+COPY --from=build /nae/application-engine/src/main/resources /opt/netgrif/engine/src/main/resources
+RUN chown -R netgrif /opt/netgrif/engine
+
+USER netgrif
+EXPOSE 8080
+ENTRYPOINT ["java","-jar","-Dfile.encoding=UTF-8","/app.jar"]
diff --git a/README.md b/README.md
index 359c966db3c..47363ddf0d6 100644
--- a/README.md
+++ b/README.md
@@ -29,6 +29,40 @@ NAE provides additional components to make integration to your project/environme
* License: [NETGRIF Community License](https://netgrif.com/license)
+## DEV quick-start
+
+1. **Build everything once**
+
+Compiles the entire multi-module project and pulls down every dependency.
+
+```bash
+mvn clean install
+```
+
+2. **Loading nae-user-ce as symlink to modules**
+
+```bash
+bash -c 'jar_path=$(find nae-user-ce/target/ -maxdepth 1 -type f -name "nae-user-ce-*.jar" ! -name "*-javadoc.jar" ! -name "*-sources.jar" | head -n1) && [[ -n "$jar_path" ]] && cd application-engine/modules && ln -sf ../../"$jar_path" nae-user-ce.jar && echo "✅ Create a Symlink → application-engine/modules/nae-user-ce.jar" || echo "❌ JAR file not found!"'
+```
+3. **Rebuild only the engine**
+
+```bash
+mvn -pl application-engine -Pdev clean install
+```
+4. **Run the app**
+
+In IntelliJ choose “ApplicationEngine DEV with modules” and press Run (main class org.springframework.boot.loader.launch.PropertiesLauncher, profile dev). The launcher loads every JAR in application-engine/modules/, including the symlinked nae-user-ce.jar.
+
+## Repository Content
+
+| Name | Description | Dependencies |
+|-------------------------|-------------|--------------|
+| nae-object-library | | |
+| nae-spring-core-adapter | | |
+| nae-user-common | | |
+| nae-user-ce | | |
+| engine | | |
+
## Components
Netgrif Application Engine (or NAE for short) consists of several key components:
@@ -61,7 +95,7 @@ run and use the engine:
|--------------------------------------------------------|---------|-----------------------------------------------------------------|:-----------------------------------------------------------------------|
| [Java](https://openjdk.java.net/) | 21+ | Java Development Kit | [OpenJDK 21](https://openjdk.java.net/install/) |
| [Redis](https://redis.io/) | 7+ | Key-value in-memory database used for user sessions and caching | [Redis 7.2.5](https://redis.io/download) |
-| [MongoDB](https://www.mongodb.com/) | 8+ | Main document store database | [MongoDB 8.0.3](hhttps://www.mongodb.com/docs/manual/installation/) |
+| [MongoDB](https://www.mongodb.com/) | 8+ | Main document store database | [MongoDB 8.0.3](hhttps://www.mongodb.com/docs/manual/installation/) |
| [Elasticsearch](https://www.elastic.co/elasticsearch/) | 8+ | Index database used for better application search | [Elasticsearch 8.10.4](https://www.elastic.co/downloads/elasticsearch) |
If you are planning on developing docker container based solution you can use our [docker-compose](docker-compose.yml)
diff --git a/application-engine/.gitignore b/application-engine/.gitignore
new file mode 100644
index 00000000000..78e6194afd8
--- /dev/null
+++ b/application-engine/.gitignore
@@ -0,0 +1,147 @@
+### Java template
+# Compiled class file
+*.class
+
+# Log file
+*.log
+
+# BlueJ files
+*.ctxt
+
+# Mobile Tools for Java (J2ME)
+.mtj.tmp/
+
+# Package Files #
+*.jar
+*.war
+*.nar
+*.ear
+*.zip
+*.tar.gz
+*.rar
+
+# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
+hs_err_pid*
+
+### Maven template
+target/
+pom.xml.tag
+pom.xml.releaseBackup
+pom.xml.versionsBackup
+pom.xml.next
+release.properties
+dependency-reduced-pom.xml
+buildNumber.properties
+.mvn/timing.properties
+# https://github.com/takari/maven-wrapper#usage-without-binary-jar
+.mvn/wrapper/maven-wrapper.jar
+
+### JetBrains template
+# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
+# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
+
+# User-specific stuff
+.idea/**/workspace.xml
+.idea/**/tasks.xml
+.idea/**/usage.statistics.xml
+.idea/**/dictionaries
+.idea/**/shelf
+
+# Generated files
+.idea/**/contentModel.xml
+
+# Sensitive or high-churn files
+.idea/**/dataSources/
+.idea/**/dataSources.ids
+.idea/**/dataSources.local.xml
+.idea/**/sqlDataSources.xml
+.idea/**/dynamic.xml
+.idea/**/uiDesigner.xml
+.idea/**/dbnavigator.xml
+
+# Gradle
+.idea/**/gradle.xml
+.idea/**/libraries
+
+# Gradle and Maven with auto-import
+# When using Gradle or Maven with auto-import, you should exclude module files,
+# since they will be recreated, and may cause churn. Uncomment if using
+# auto-import.
+# .idea/artifacts
+# .idea/compiler.xml
+# .idea/jarRepositories.xml
+# .idea/modules.xml
+# .idea/*.iml
+# .idea/modules
+# *.iml
+# *.ipr
+
+# CMake
+cmake-build-*/
+
+# Mongo Explorer plugin
+.idea/**/mongoSettings.xml
+
+# File-based project format
+*.iws
+
+# IntelliJ
+out/
+
+# mpeltonen/sbt-idea plugin
+.idea_modules/
+
+# JIRA plugin
+atlassian-ide-plugin.xml
+
+# Cursive Clojure plugin
+.idea/replstate.xml
+
+# Crashlytics plugin (for Android Studio and IntelliJ)
+com_crashlytics_export_strings.xml
+crashlytics.properties
+crashlytics-build.properties
+fabric.properties
+
+# Editor-based Rest Client
+.idea/httpRequests
+
+# Android studio 3.1+ serialized cache file
+.idea/caches/build_file_checksums.ser
+
+### Example user template template
+### Example user template
+
+# IntelliJ project files
+.idea
+*.iml
+out
+gen
+
+### STS ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+
+### IntelliJ IDEA ###
+*.ipr
+
+### Work folder ###
+_issues/
+storage/
+/rules/
+*.log*
+log/
+!/src/main/java/com/netgrif/workflow/rules/
+!/src/main/java/com/netgrif/workflow/rules/domain/StoredRuleRepository.java
+
+### CERT ###
+/src/main/resources/certificates/keypair.pem
+/src/main/resources/certificates/private.der
+/src/main/resources/certificates/public.crt
+/modules/
+!src/main/java/**/modules
+!src/main/groovy/**/modules
diff --git a/CHANGELOG.md b/application-engine/CHANGELOG.md
similarity index 100%
rename from CHANGELOG.md
rename to application-engine/CHANGELOG.md
diff --git a/LICENSE.txt b/application-engine/LICENSE.txt
similarity index 100%
rename from LICENSE.txt
rename to application-engine/LICENSE.txt
diff --git a/application-engine/README.md b/application-engine/README.md
new file mode 100644
index 00000000000..359c966db3c
--- /dev/null
+++ b/application-engine/README.md
@@ -0,0 +1,166 @@
+# Netgrif Application Engine
+
+[](https://netgrif.com/license)
+[](https://openjdk.java.net/projects/jdk/11/)
+[](https://petriflow.com)
+[](https://github.com/netgrif/application-engine/releases)
+[](https://github.com/netgrif/application-engine/actions/workflows/master-build.yml)
+[](https://sonarcloud.io/dashboard?id=netgrif_application-engine)
+[](https://sonarcloud.io/dashboard?id=netgrif_application-engine)
+[](https://snyk.io/test/github/netgrif/application-engine)
+
+> Next-generation end-to-end low code platform.
+
+Application Engine is a workflow management system fully supporting low-code language Petriflow. Application Engine (NAE
+for short)
+is based on Spring framework with fully complaint Petriflow language interpreter. NAE runs inside the Java Virtual
+Machine. It can be embedded into Java 11 project or used as a standalone process server. On top of the process server,
+NAE provides additional components to make integration to your project/environment seamless.
+
+* Petriflow low-code language: [http://petriflow.com](https://petriflow.com)
+* Documentation: [https://engine.netgrif.com](https://engine.netgrif.com)
+
+
+
+* Issue Tracker: [GitHub issues](https://github.com/netgrif/application-engine/issues)
+* Java docs: [https://engine.netgrif.com/javadoc](https://engine.netgrif.com/javadoc)
+
+
+
+* License: [NETGRIF Community License](https://netgrif.com/license)
+
+## Components
+
+Netgrif Application Engine (or NAE for short) consists of several key components:
+
+* **Workflow engine**
+ * **Process executions** - Process instance and task management
+ * [**Actions and Events processing**](https://engine.netgrif.com/#/events/events) - Compiling and running action's
+ code, handling events in processes
+ * [**Roles management and permissions resolution**](https://engine.netgrif.com/#/roles/permissions) - Permissions
+ and
+ restrictions resolving for processes
+ * [**Search and filters**](https://engine.netgrif.com/#/search/filter) - Indexing, querying and filter management.
+* **Authentication and authorization** - User management and application-wide permissions
+ * [**LDAP**](https://engine.netgrif.com/#/integration/ad_kerberos) - Integration to authentication solution via LDAP
+ protocol.
+ * **Organization structures** - Managing organization structure for application users
+* **Business rules engine** - Rules execution across whole application based on [Drools](https://drools.org/)
+* **Logging and auditing** - Logging to text file and Event/Audit log generation to the main database
+* **Mail service** - Mail client for sending and receiving emails
+* **Extension services**
+ * [**PDF generator**](https://engine.netgrif.com/#/services/pdf_generator) - Generate PDF from process form / task
+ * **QR code generator** - Generate QR code from process data
+
+## Requirements
+
+The Application engine has some requirements for runtime environment. The following table is summary of requirements to
+run and use the engine:
+
+| Name | Version | Description | Recommendation |
+|--------------------------------------------------------|---------|-----------------------------------------------------------------|:-----------------------------------------------------------------------|
+| [Java](https://openjdk.java.net/) | 21+ | Java Development Kit | [OpenJDK 21](https://openjdk.java.net/install/) |
+| [Redis](https://redis.io/) | 7+ | Key-value in-memory database used for user sessions and caching | [Redis 7.2.5](https://redis.io/download) |
+| [MongoDB](https://www.mongodb.com/) | 8+ | Main document store database | [MongoDB 8.0.3](hhttps://www.mongodb.com/docs/manual/installation/) |
+| [Elasticsearch](https://www.elastic.co/elasticsearch/) | 8+ | Index database used for better application search | [Elasticsearch 8.10.4](https://www.elastic.co/downloads/elasticsearch) |
+
+If you are planning on developing docker container based solution you can use our [docker-compose](docker-compose.yml)
+configuration to run all necessary databases to develop with NAE.
+
+
+
+## Installation
+
+### Running as standalone
+
+You can start using the NAE by its self and then upload your processes via API. You run the NAE from JAR (Java Archive)
+file or as docker container.
+
+#### Running a JAR file
+
+To run the engine from the jar file you can use a release package available from this repository. The latest release
+package you can download from [here](https://github.com/netgrif/application-engine/releases/latest). Before you start
+you must generate own RSA key pair for session tokens, you can
+follow [this guide](https://engine.netgrif.com/#/views/public_view?id=backend).
+
+To quickly start working with the engine just write the following commands to download, unzip, generate security keys
+and start:
+
+```shell
+$ wget -O nae.zip https://github.com/netgrif/application-engine/releases/latest
+$ unzip nae.zip
+$ cd nae
+$ cd src/main/resources/certificates && openssl genrsa -out keypair.pem 4096 && openssl rsa -in keypair.pem -pubout -out public.crt && openssl pkcs8 -topk8 -inform PEM -outform DER -nocrypt -in keypair.pem -out private.der && cd ../../../..
+$ java -jar nae.jar
+```
+
+Only generate security keys:
+
+```shell
+$ cd src/main/resources/certificates && openssl genrsa -out keypair.pem 4096 && openssl rsa -in keypair.pem -pubout -out public.crt && openssl pkcs8 -topk8 -inform PEM -outform DER -nocrypt -in keypair.pem -out private.der && cd ../../../..
+```
+
+By default, the engine assumes that all databases are running locally. If you are running required database on server or
+on different ports, you can pass these settings as arguments to NAE.
+
+```shell
+$ java -jar nae.jar --spring.data.mongodb.uri=mongodb://localhost:27017/nae --spring.data.elasticsearch.url=localhost --spring.session.redis.host=localhost
+```
+
+
+
+#### Running as Docker container
+
+You can also use docker to run the engine from the official image
+on [Docker hub](https://hub.docker.com/r/netgrif/application-engine).
+
+```shell
+$ docker pull netgrif/application-engine
+$ docker run -d -p 8080:8080 netgrif/application-engine
+```
+
+As the engine connects by default to locally ran databases for more precise configuration we recommend to use Docker
+compose file or Kubernetes manifest to run whole stack all at once.
+
+### Embedding
+
+The Application Engine can be used inside your java application as a java library. The engine is written in Spring
+framework, so you can seamlessly integrate it to your Spring Boot application. The engine can be linked as a Maven
+dependency:
+
+```XML
+
+
+ com.netgrif
+ application-engine
+
+```
+
+
+
+## Other projects
+
+
+
+### Application Builder
+
+For creating processes in Petriflow language try our free Application Builder
+on [https://builder.netgrif.com](https://builder.netgrif.com). You can start from scratch or import existing process in
+BPMN 2.0 and builder automatically converts it into Petriflow.
+
+## Reporting issues
+
+If you find a bug, let us know at [Issue page](https://github.com/netgrif/application-engine/issues). First, please read
+our [Contribution guide](https://github.com/netgrif/application-engine/blob/master/CONTRIBUTING.md)
+
+## License
+
+The software is licensed under NETGRIF Community license. You may be found this license
+at [the LICENSE file](https://github.com/netgrif/application-engine/blob/master/LICENSE) in the repository.
diff --git a/THIRD-PARTY.txt b/application-engine/THIRD-PARTY.txt
similarity index 100%
rename from THIRD-PARTY.txt
rename to application-engine/THIRD-PARTY.txt
diff --git a/docker-compose.yml b/application-engine/docker-compose.yml
similarity index 98%
rename from docker-compose.yml
rename to application-engine/docker-compose.yml
index 3e275c95c1a..40842a1cf83 100644
--- a/docker-compose.yml
+++ b/application-engine/docker-compose.yml
@@ -51,13 +51,6 @@ services:
- MINIO_ROOT_USER=root
- MINIO_ROOT_PASSWORD=password
- MINIO_DEFAULT_BUCKETS=default
-networks:
- minionetwork:
- driver: bridge
-
-volumes:
- minio_data:
- driver: local
# kibana:
# image: docker.elastic.co/kibana/kibana:8.10.4
@@ -67,3 +60,11 @@ volumes:
# - docker-elastic
# ports:
# - "5601:5601"
+
+networks:
+ minionetwork:
+ driver: bridge
+
+volumes:
+ minio_data:
+ driver: local
\ No newline at end of file
diff --git a/lombok.config b/application-engine/lombok.config
similarity index 100%
rename from lombok.config
rename to application-engine/lombok.config
diff --git a/src/main/resources/certificates/.gitkeep b/application-engine/modules/.gitkeep
similarity index 100%
rename from src/main/resources/certificates/.gitkeep
rename to application-engine/modules/.gitkeep
diff --git a/application-engine/pom.xml b/application-engine/pom.xml
new file mode 100644
index 00000000000..963516bac6c
--- /dev/null
+++ b/application-engine/pom.xml
@@ -0,0 +1,907 @@
+
+
+ 4.0.0
+
+
+ com.netgrif
+ application-engine-parent
+ 7.0.0-SNAPSHOT
+
+
+ application-engine
+ jar
+
+ NETGRIF Application Engine
+ System provides workflow management functions including user, role and data management.
+ https://engine.netgrif.com
+
+
+
+ NETGRIF Community License
+ https://netgrif.com/license
+ repo
+
+
+
+
+ NETGRIF, s.r.o.
+ https://netgrif.com
+
+
+
+
+ Netgrif
+ oss@netgrif.com
+ NETGRIF, s.r.o.
+ https://netgrif.com
+
+
+
+
+ scm:git:git://github.com/netgrif/application-engine.git
+ scm:git:ssh://git@github.com/netgrif/application-engine.git
+ https://github.com/netgrif/application-engine
+
+
+
+ GitHub
+ https://github.com/netgrif/application-engine/issues
+
+
+
+ 1.9.2
+ 9.44.0.Final
+ 7.74.1.Final
+ 0.11.5
+ 1.78.1
+ 8.5.12
+
+
+
+
+ oss.snapshots
+ OSSRH SNAPSHOT
+ https://s01.oss.sonatype.org/content/repositories/snapshots
+
+ false
+
+
+ true
+
+
+
+ mvnrepository1
+ https://maven.imagej.net/content/repositories/public/
+
+
+ mvnrepository2
+ https://repo.spring.io/plugins-release/
+
+
+ mulesoft
+ https://repository.mulesoft.org/nexus/content/repositories/public/
+
+
+ jitpack.io
+ https://jitpack.io
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-dependencies
+ ${spring.boot.version}
+ pom
+ import
+
+
+
+
+ org.apache.logging.log4j
+ log4j-api
+ 2.17.2
+
+
+ org.apache.commons
+ commons-compress
+ 1.26.0
+
+
+ com.beust
+ jcommander
+ 1.75
+
+
+ commons-beanutils
+ commons-beanutils
+ 1.9.4
+
+
+
+ xalan
+ xalan
+ 2.7.2
+
+
+
+
+
+
+
+ com.netgrif
+ nae-user-ce
+ ${project.version}
+
+
+
+
+ org.springframework.boot
+ spring-boot-loader
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-actuator
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-batch
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-cache
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-data-mongodb
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-data-rest
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-hateoas
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-mail
+
+
+ org.springframework.boot
+ spring-boot-starter-freemarker
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-security
+
+
+ org.jasypt
+ jasypt
+ ${jasypt.version}
+ compile
+
+
+ org.jasypt
+ jasypt-hibernate4
+ ${jasypt.version}
+ compile
+
+
+
+ org.bouncycastle
+ bcmail-jdk18on
+ ${bouncycastle.version}
+
+
+
+ org.bouncycastle
+ bcprov-jdk18on
+ ${bouncycastle.version}
+
+
+ io.jsonwebtoken
+ jjwt-api
+ ${jwt.version}
+
+
+ io.jsonwebtoken
+ jjwt-impl
+ ${jwt.version}
+
+
+ io.jsonwebtoken
+ jjwt-jackson
+ ${jwt.version}
+
+
+
+
+ org.springframework.session
+ spring-session-data-redis
+
+
+ org.springframework.boot
+ spring-boot-starter-data-redis
+
+
+ redis.clients
+ jedis
+
+
+
+ org.aspectj
+ aspectjweaver
+ 1.9.7
+
+
+
+ jakarta.xml.bind
+ jakarta.xml.bind-api
+ ${jakarta.bind.version}
+
+
+
+ com.sun.xml.bind
+ jaxb-impl
+ ${jakarta.bind.version}
+ runtime
+
+
+
+ com.unboundid
+ unboundid-ldapsdk
+ test
+
+
+ org.junit.jupiter
+ junit-jupiter
+ ${junit-jupiter.version}
+ test
+
+
+ org.junit.jupiter
+ junit-jupiter-api
+ ${junit-jupiter.version}
+ test
+
+
+ org.junit.jupiter
+ junit-jupiter-engine
+ ${junit-jupiter.version}
+ test
+
+
+
+
+ org.apache.groovy
+ groovy-all
+ ${groovy.version}
+ pom
+
+
+
+
+ org.projectlombok
+ lombok
+
+
+
+
+
+ commons-collections
+ commons-collections
+ 3.2.2
+
+
+
+
+ org.apache.pdfbox
+ pdfbox
+ 2.0.25
+
+
+ org.apache.xmlgraphics
+ batik-all
+ 1.17
+
+
+ commons-io
+ commons-io
+ 2.7
+
+
+ de.rototor.pdfbox
+ graphics2d
+ 0.32
+
+
+ com.twelvemonkeys.imageio
+ imageio-jpeg
+ 3.8.1
+
+
+ com.twelvemonkeys.imageio
+ imageio-tiff
+ 3.8.1
+
+
+
+
+
+ org.jsoup
+ jsoup
+ 1.15.4
+
+
+
+
+ com.querydsl
+ querydsl-apt
+ ${querydsl.version}
+
+
+ com.querydsl
+ querydsl-mongodb
+ ${querydsl.version}
+
+
+
+ com.querydsl
+ querydsl-core
+ ${querydsl.version}
+
+
+
+
+
+ com.github.kenglxn.qrgen
+ javase
+ 2.6.0
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-data-elasticsearch
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ org.apache.poi
+ poi
+ 5.1.0
+
+
+
+ net.glxn.qrgen
+ core
+ 2.0
+
+
+
+ org.apache.commons
+ commons-lang3
+ 3.17.0
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+
+ org.springframework.ldap
+ spring-ldap-core
+
+
+ org.springframework.security
+ spring-security-ldap
+
+
+ org.springframework.data
+ spring-data-ldap
+
+
+
+
+
+ org.quartz-scheduler
+ quartz
+ 2.3.2
+
+
+ com.netgrif
+ quartz-mongodb-connector
+ 1.0.0-SNAPSHOT
+
+
+
+
+ org.springdoc
+ springdoc-openapi-ui
+ 1.6.9
+
+
+ org.springdoc
+ springdoc-openapi-hateoas
+ 1.6.9
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+ com.icegreen
+ greenmail
+ 2.0.1
+ test
+
+
+ org.springframework.security
+ spring-security-test
+
+
+ xmlunit
+ xmlunit
+ 1.4
+
+
+ org.springframework.boot
+ spring-boot-configuration-processor
+ true
+
+
+ com.google.guava
+ guava
+ 32.0.0-jre
+
+
+
+
+ org.hibernate.validator
+ hibernate-validator
+ 6.2.3.Final
+
+
+ com.fasterxml.jackson
+ jackson-base
+ ${jackson.version}
+ pom
+
+
+ com.fasterxml.jackson.core
+ jackson-core
+ ${jackson.version}
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+ ${jackson.version}
+
+
+ com.fasterxml.jackson.jaxrs
+ jackson-jaxrs-json-provider
+ ${jackson.version}
+
+
+ com.fasterxml.jackson.core
+ jackson-annotations
+ ${jackson.version}
+
+
+ com.fasterxml.jackson.dataformat
+ jackson-dataformat-xml
+ ${jackson.version}
+
+
+ com.fasterxml.jackson.module
+ jackson-module-jsonSchema
+ ${jackson.version}
+
+
+ io.minio
+ minio
+ ${minio.version}
+
+
+
+
+
+
+ src/main/resources
+
+ **/*.*
+
+ false
+
+
+ src/main/resources
+
+ **/*.properties
+
+ true
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+ ZIP
+ com.netgrif.application.engine.ApplicationEngine
+ exe
+
+
+ org.projectlombok
+ lombok
+
+
+
+
+
+
+ repackage
+
+ repackage
+
+ exec
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-dependency-plugin
+
+
+ copy-dependencies
+ package
+
+ copy-dependencies
+
+
+
+
+
+ org.codehaus.gmavenplus
+ gmavenplus-plugin
+ 3.0.2
+
+
+
+ addSources
+ addTestSources
+ generateStubs
+ compile
+ generateTestStubs
+ compileTests
+ groovydoc
+ removeStubs
+ removeTestStubs
+
+
+
+
+ false
+
+
+
+ com.mysema.maven
+ apt-maven-plugin
+ 1.1.3
+
+
+
+ process
+
+
+ target/generated-sources/java
+
+
+ com.querydsl.apt.QuerydslAnnotationProcessor
+
+
+
+ groovy.lang.MetaClass
+ true
+
+
+
+
+
+
+ org.codehaus.mojo
+ jaxb2-maven-plugin
+ 3.1.0
+
+
+ xjc_pos
+
+ xjc
+
+
+
+ com.netgrif.application.engine.objects.importer.model
+ ${project.build.directory}/generated-sources/java
+
+ src/main/resources/petriNets/petriflow_schema.xsd
+
+ false
+ false
+ true
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-clean-plugin
+
+ true
+
+
+ target/generated-sources/groovy-stubs
+
+
+
+
+
+ install
+
+ clean
+
+
+
+ target
+ clean
+
+ clean
+
+
+ true
+
+
+ target
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+ 2.22.2
+
+ 1
+ 1
+ false
+
+
+
+ org.apache.maven.plugins
+ maven-failsafe-plugin
+ 2.22.2
+
+
+ org.jacoco
+ jacoco-maven-plugin
+ 0.8.10
+
+
+ default-prepare-agent
+
+ prepare-agent
+
+
+
+ default-report
+ prepare-package
+
+ report
+
+
+
+
+
+ **/config/*.*
+ **/domain/*.*
+
+
+
+
+ org.apache.maven.plugins
+ maven-resources-plugin
+ 3.2.0
+
+
+ @
+
+ false
+
+ crt
+ der
+ pem
+
+
+
+
+ org.codehaus.mojo
+ license-maven-plugin
+ 2.0.0
+
+
+
+
+
+
+ dev
+
+ dev
+
+
+
+ org.springframework.boot
+ spring-boot-loader
+
+
+
+
+ docker-build
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+ app
+ ZIP
+ com.netgrif.application.engine.ApplicationEngine
+ exe
+
+
+ org.projectlombok
+ lombok
+
+
+
+
+
+ repackage
+
+ repackage
+
+
+ exec
+
+
+
+
+
+
+
+
+ github-publish
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+ repackage
+
+ repackage
+
+
+ true
+
+
+
+
+
+
+
+
+ ossrh-publish
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+ repackage
+
+ repackage
+
+
+ true
+
+
+
+
+
+
+
+
+ netgrif-nexus-publish
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+ repackage
+
+ repackage
+
+
+ true
+
+
+
+
+
+
+
+
+
diff --git a/sonar-project.properties b/application-engine/sonar-project.properties
similarity index 100%
rename from sonar-project.properties
rename to application-engine/sonar-project.properties
diff --git a/src/main/groovy/com/netgrif/application/engine/AsyncRunner.groovy b/application-engine/src/main/groovy/com/netgrif/application/engine/AsyncRunner.groovy
similarity index 100%
rename from src/main/groovy/com/netgrif/application/engine/AsyncRunner.groovy
rename to application-engine/src/main/groovy/com/netgrif/application/engine/AsyncRunner.groovy
diff --git a/src/main/groovy/com/netgrif/application/engine/DevConsole.groovy b/application-engine/src/main/groovy/com/netgrif/application/engine/DevConsole.groovy
similarity index 97%
rename from src/main/groovy/com/netgrif/application/engine/DevConsole.groovy
rename to application-engine/src/main/groovy/com/netgrif/application/engine/DevConsole.groovy
index 7902be1a336..81fc5f265cc 100644
--- a/src/main/groovy/com/netgrif/application/engine/DevConsole.groovy
+++ b/application-engine/src/main/groovy/com/netgrif/application/engine/DevConsole.groovy
@@ -1,6 +1,6 @@
package com.netgrif.application.engine
-import com.netgrif.application.engine.importer.model.Document
+import com.netgrif.application.engine.objects.importer.model.Document
import com.netgrif.application.engine.petrinet.domain.repositories.PetriNetRepository
import com.netgrif.application.engine.workflow.domain.repositories.CaseRepository
import org.slf4j.Logger
diff --git a/src/main/groovy/com/netgrif/application/engine/StringToDataSetConverter.groovy b/application-engine/src/main/groovy/com/netgrif/application/engine/StringToDataSetConverter.groovy
similarity index 88%
rename from src/main/groovy/com/netgrif/application/engine/StringToDataSetConverter.groovy
rename to application-engine/src/main/groovy/com/netgrif/application/engine/StringToDataSetConverter.groovy
index d73cdcfc94a..963b81cd0c5 100644
--- a/src/main/groovy/com/netgrif/application/engine/StringToDataSetConverter.groovy
+++ b/application-engine/src/main/groovy/com/netgrif/application/engine/StringToDataSetConverter.groovy
@@ -1,6 +1,6 @@
package com.netgrif.application.engine
-import com.netgrif.application.engine.workflow.domain.DataField
+import com.netgrif.application.engine.objects.workflow.domain.DataField
import groovy.json.JsonSlurper
import org.springframework.core.convert.converter.Converter
import org.springframework.stereotype.Component
@@ -16,4 +16,4 @@ class StringToDataSetConverter implements Converter
}
-}
\ No newline at end of file
+}
diff --git a/src/main/groovy/com/netgrif/application/engine/StringToMapConverter.groovy b/application-engine/src/main/groovy/com/netgrif/application/engine/StringToMapConverter.groovy
similarity index 100%
rename from src/main/groovy/com/netgrif/application/engine/StringToMapConverter.groovy
rename to application-engine/src/main/groovy/com/netgrif/application/engine/StringToMapConverter.groovy
diff --git a/src/main/groovy/com/netgrif/application/engine/business/orsr/IOrsrService.groovy b/application-engine/src/main/groovy/com/netgrif/application/engine/business/orsr/IOrsrService.groovy
similarity index 100%
rename from src/main/groovy/com/netgrif/application/engine/business/orsr/IOrsrService.groovy
rename to application-engine/src/main/groovy/com/netgrif/application/engine/business/orsr/IOrsrService.groovy
diff --git a/src/main/groovy/com/netgrif/application/engine/business/orsr/OrsrReference.groovy b/application-engine/src/main/groovy/com/netgrif/application/engine/business/orsr/OrsrReference.groovy
similarity index 100%
rename from src/main/groovy/com/netgrif/application/engine/business/orsr/OrsrReference.groovy
rename to application-engine/src/main/groovy/com/netgrif/application/engine/business/orsr/OrsrReference.groovy
diff --git a/src/main/groovy/com/netgrif/application/engine/business/orsr/OrsrService.groovy b/application-engine/src/main/groovy/com/netgrif/application/engine/business/orsr/OrsrService.groovy
similarity index 100%
rename from src/main/groovy/com/netgrif/application/engine/business/orsr/OrsrService.groovy
rename to application-engine/src/main/groovy/com/netgrif/application/engine/business/orsr/OrsrService.groovy
diff --git a/src/main/groovy/com/netgrif/application/engine/business/psc/PostalCodePostRequestService.groovy b/application-engine/src/main/groovy/com/netgrif/application/engine/business/psc/PostalCodePostRequestService.groovy
similarity index 100%
rename from src/main/groovy/com/netgrif/application/engine/business/psc/PostalCodePostRequestService.groovy
rename to application-engine/src/main/groovy/com/netgrif/application/engine/business/psc/PostalCodePostRequestService.groovy
diff --git a/src/main/groovy/com/netgrif/application/engine/configuration/ApplicationContextProvider.groovy b/application-engine/src/main/groovy/com/netgrif/application/engine/configuration/ApplicationContextProvider.groovy
similarity index 100%
rename from src/main/groovy/com/netgrif/application/engine/configuration/ApplicationContextProvider.groovy
rename to application-engine/src/main/groovy/com/netgrif/application/engine/configuration/ApplicationContextProvider.groovy
diff --git a/src/main/groovy/com/netgrif/application/engine/configuration/JsonRootRelProvider.groovy b/application-engine/src/main/groovy/com/netgrif/application/engine/configuration/JsonRootRelProvider.groovy
similarity index 100%
rename from src/main/groovy/com/netgrif/application/engine/configuration/JsonRootRelProvider.groovy
rename to application-engine/src/main/groovy/com/netgrif/application/engine/configuration/JsonRootRelProvider.groovy
diff --git a/src/main/groovy/com/netgrif/application/engine/eventoutcomes/LocalisedEventOutcomeFactory.groovy b/application-engine/src/main/groovy/com/netgrif/application/engine/eventoutcomes/LocalisedEventOutcomeFactory.groovy
similarity index 87%
rename from src/main/groovy/com/netgrif/application/engine/eventoutcomes/LocalisedEventOutcomeFactory.groovy
rename to application-engine/src/main/groovy/com/netgrif/application/engine/eventoutcomes/LocalisedEventOutcomeFactory.groovy
index 96de92bb635..30b5cea32a8 100644
--- a/src/main/groovy/com/netgrif/application/engine/eventoutcomes/LocalisedEventOutcomeFactory.groovy
+++ b/application-engine/src/main/groovy/com/netgrif/application/engine/eventoutcomes/LocalisedEventOutcomeFactory.groovy
@@ -1,6 +1,6 @@
package com.netgrif.application.engine.eventoutcomes
-import com.netgrif.application.engine.workflow.domain.eventoutcomes.EventOutcome
+import com.netgrif.application.engine.objects.workflow.domain.eventoutcomes.EventOutcome
import com.netgrif.application.engine.workflow.web.responsebodies.eventoutcomes.base.LocalisedEventOutcome
class LocalisedEventOutcomeFactory {
diff --git a/application-engine/src/main/groovy/com/netgrif/application/engine/integration/modules/ModuleHolder.groovy b/application-engine/src/main/groovy/com/netgrif/application/engine/integration/modules/ModuleHolder.groovy
new file mode 100644
index 00000000000..546110b0bb7
--- /dev/null
+++ b/application-engine/src/main/groovy/com/netgrif/application/engine/integration/modules/ModuleHolder.groovy
@@ -0,0 +1,7 @@
+package com.netgrif.application.engine.integration.modules
+
+/**
+ * A class where the module services are injected. The plugins are injected into metaclasses
+ */
+class ModuleHolder {
+}
diff --git a/application-engine/src/main/groovy/com/netgrif/application/engine/integration/modules/ModuleServiceHolder.groovy b/application-engine/src/main/groovy/com/netgrif/application/engine/integration/modules/ModuleServiceHolder.groovy
new file mode 100644
index 00000000000..732fc7789db
--- /dev/null
+++ b/application-engine/src/main/groovy/com/netgrif/application/engine/integration/modules/ModuleServiceHolder.groovy
@@ -0,0 +1,7 @@
+package com.netgrif.application.engine.integration.modules
+
+/**
+ * A class where the module services are injected for a named module. The plugins are injected into metaclasses
+ */
+class ModuleServiceHolder {
+}
diff --git a/application-engine/src/main/groovy/com/netgrif/application/engine/integration/modules/ModuleServiceInjector.groovy b/application-engine/src/main/groovy/com/netgrif/application/engine/integration/modules/ModuleServiceInjector.groovy
new file mode 100644
index 00000000000..9aff769ff68
--- /dev/null
+++ b/application-engine/src/main/groovy/com/netgrif/application/engine/integration/modules/ModuleServiceInjector.groovy
@@ -0,0 +1,92 @@
+package com.netgrif.application.engine.integration.modules
+
+import com.netgrif.application.engine.configuration.ApplicationContextProvider
+import com.netgrif.application.engine.startup.ApplicationEngineFinishRunner
+import com.netgrif.application.engine.startup.annotation.RunnerOrder
+import org.slf4j.Logger
+import org.slf4j.LoggerFactory
+import org.springframework.boot.ApplicationArguments
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
+import org.springframework.stereotype.Component
+
+/**
+ * Component responsible for injecting module services into the application runtime.
+ * This class implements {@link ApplicationEngineFinishRunner} to perform the injection
+ * after the application finishes its startup routine. The services are grouped by modules
+ * and made available for runtime action delegation.
+ *
+ * The execution of this class is controlled by properties defined in the application configuration.
+ * By default, it is enabled and executed in the specified order.
+ */
+
+@Component
+@RunnerOrder(209)
+@ConditionalOnProperty(value = "nae.modules.services.enabled", havingValue = "true", matchIfMissing = true)
+class ModuleServiceInjector implements ApplicationEngineFinishRunner {
+
+ private static final Logger log = LoggerFactory.getLogger(ModuleServiceInjector.class)
+ private final String DEFAULT_KEY = "default"
+
+ /**
+ * Executes the injection of services annotated with {@code @ModuleService}.
+ * This method collects all beans marked with the {@code @ModuleService} annotation,
+ * groups them by their associated module, and injects them into the respective meta-classes
+ * (e.g., {@code ModuleHolder} and {@code ModuleServiceHolder}).
+ *
+ * @param args application arguments passed during startup
+ * @throws Exception if any error occurs during the injection process
+ */
+
+ @Override
+ void run(ApplicationArguments args) throws Exception {
+ def injectableBeans = ApplicationContextProvider.getAppContext().getBeansWithAnnotation(ModuleService.class)
+ if (!injectableBeans.isEmpty()) {
+ MetaClass holderMetaClass = ModuleHolder.metaClass
+ def groupedServices = groupServicesByModule(injectableBeans)
+ groupedServices.each { entry ->
+ if (entry.key == DEFAULT_KEY) {
+ entry.value.each { serviceEntry ->
+ log.info("Injecting module service {} into action delegate making it available under module.{}", serviceEntry.key, serviceEntry.key)
+ holderMetaClass[serviceEntry.key] = serviceEntry.value
+ }
+ } else {
+ MetaClass moduleServiceHolderMetaClass = ModuleServiceHolder.metaClass
+ entry.value.each { serviceEntry ->
+ log.info("Injecting module service {} into module holder {} into action delegate making it available under module.{}.{}", serviceEntry.key, entry.key, entry.key, serviceEntry.key)
+ moduleServiceHolderMetaClass[serviceEntry.key] = serviceEntry.value
+ }
+ holderMetaClass[entry.key] = new ModuleServiceHolder()
+ }
+ }
+ }
+ }
+
+ /**
+ * Groups services annotated with {@code @ModuleService} by their associated module.
+ * Each service is categorized under a module key specified by the annotation's value.
+ * Services without a specified module are grouped under the "default" key.
+ *
+ * @param services a map of service names to service instances retrieved from the application context
+ * @return a map where each key represents a module, and the value is another map containing
+ * services (name and instance) associated with that module
+ * @throws IllegalStateException if any service lacks the {@code @ModuleService} annotation
+ */
+
+ private Map> groupServicesByModule(Map services) {
+ Map> grouped = [(DEFAULT_KEY): [:]]
+ services.each { entry ->
+ ModuleService[] annotations = entry.value.getClass().getAnnotationsByType(ModuleService.class)
+ if (annotations.length == 0) throw new IllegalStateException("Module Service bean must have @ModuleService annotations")
+ ModuleService annotation = annotations[0]
+ if (annotation.value().isBlank()) {
+ grouped[(DEFAULT_KEY)].put(entry.key, entry.value)
+ } else {
+ String moduleName = annotation.value()
+ if (!grouped.containsKey(moduleName)) grouped.put(moduleName, [:])
+ grouped[moduleName].put(entry.key, entry.value)
+ }
+ }
+ return grouped
+ }
+
+}
diff --git a/src/main/groovy/com/netgrif/application/engine/migration/ActionMigration.groovy b/application-engine/src/main/groovy/com/netgrif/application/engine/migration/ActionMigration.groovy
similarity index 83%
rename from src/main/groovy/com/netgrif/application/engine/migration/ActionMigration.groovy
rename to application-engine/src/main/groovy/com/netgrif/application/engine/migration/ActionMigration.groovy
index 20228cbce3d..926624c09bd 100644
--- a/src/main/groovy/com/netgrif/application/engine/migration/ActionMigration.groovy
+++ b/application-engine/src/main/groovy/com/netgrif/application/engine/migration/ActionMigration.groovy
@@ -1,10 +1,10 @@
package com.netgrif.application.engine.migration
-import com.netgrif.application.engine.auth.service.interfaces.IUserService
-import com.netgrif.application.engine.petrinet.domain.PetriNet
-import com.netgrif.application.engine.petrinet.domain.VersionType
+import com.netgrif.application.engine.auth.service.UserService
+import com.netgrif.application.engine.objects.petrinet.domain.PetriNet
+import com.netgrif.application.engine.objects.petrinet.domain.VersionType
import com.netgrif.application.engine.petrinet.service.interfaces.IPetriNetService
-import com.netgrif.application.engine.workflow.domain.eventoutcomes.petrinetoutcomes.ImportPetriNetEventOutcome
+import com.netgrif.application.engine.objects.workflow.domain.eventoutcomes.petrinetoutcomes.ImportPetriNetEventOutcome
import groovy.util.logging.Slf4j
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.core.io.ClassPathResource
@@ -20,11 +20,11 @@ class ActionMigration {
private IPetriNetService petriNetService
@Autowired
- private IUserService userService;
+ private UserService userService;
void migrateActions(String petriNetPath) {
InputStream netStream = new ClassPathResource(petriNetPath).inputStream
- ImportPetriNetEventOutcome newPetriNet = petriNetService.importPetriNet(netStream, VersionType.MAJOR, userService.loggedOrSystem.transformToLoggedUser())
+ ImportPetriNetEventOutcome newPetriNet = petriNetService.importPetriNet(netStream, VersionType.MAJOR, userService.transformToLoggedUser(userService.getLoggedOrSystem()))
List oldPetriNets
if(newPetriNet.getNet() != null) {
diff --git a/src/main/groovy/com/netgrif/application/engine/migration/Migration.groovy b/application-engine/src/main/groovy/com/netgrif/application/engine/migration/Migration.groovy
similarity index 100%
rename from src/main/groovy/com/netgrif/application/engine/migration/Migration.groovy
rename to application-engine/src/main/groovy/com/netgrif/application/engine/migration/Migration.groovy
diff --git a/src/main/groovy/com/netgrif/application/engine/migration/MigrationOrderedCommandLineRunner.groovy b/application-engine/src/main/groovy/com/netgrif/application/engine/migration/MigrationOrderedCommandLineRunner.groovy
similarity index 100%
rename from src/main/groovy/com/netgrif/application/engine/migration/MigrationOrderedCommandLineRunner.groovy
rename to application-engine/src/main/groovy/com/netgrif/application/engine/migration/MigrationOrderedCommandLineRunner.groovy
diff --git a/src/main/groovy/com/netgrif/application/engine/migration/MigrationRepository.groovy b/application-engine/src/main/groovy/com/netgrif/application/engine/migration/MigrationRepository.groovy
similarity index 100%
rename from src/main/groovy/com/netgrif/application/engine/migration/MigrationRepository.groovy
rename to application-engine/src/main/groovy/com/netgrif/application/engine/migration/MigrationRepository.groovy
diff --git a/src/main/groovy/com/netgrif/application/engine/pdf/service/PdfBuilder.groovy b/application-engine/src/main/groovy/com/netgrif/application/engine/pdf/service/PdfBuilder.groovy
similarity index 100%
rename from src/main/groovy/com/netgrif/application/engine/pdf/service/PdfBuilder.groovy
rename to application-engine/src/main/groovy/com/netgrif/application/engine/pdf/service/PdfBuilder.groovy
diff --git a/src/main/groovy/com/netgrif/application/engine/pdf/service/PdfUtils.groovy b/application-engine/src/main/groovy/com/netgrif/application/engine/pdf/service/PdfUtils.groovy
similarity index 100%
rename from src/main/groovy/com/netgrif/application/engine/pdf/service/PdfUtils.groovy
rename to application-engine/src/main/groovy/com/netgrif/application/engine/pdf/service/PdfUtils.groovy
diff --git a/application-engine/src/main/groovy/com/netgrif/application/engine/petrinet/domain/dataset/logic/action/Action.groovy b/application-engine/src/main/groovy/com/netgrif/application/engine/petrinet/domain/dataset/logic/action/Action.groovy
new file mode 100644
index 00000000000..da895dbcfa4
--- /dev/null
+++ b/application-engine/src/main/groovy/com/netgrif/application/engine/petrinet/domain/dataset/logic/action/Action.groovy
@@ -0,0 +1,142 @@
+package com.netgrif.application.engine.petrinet.domain.dataset.logic.action
+//package com.netgrif.application.engine.petrinet.domain.dataset.logic.action
+//
+//import com.netgrif.application.engine.objects.petrinet.domain.events.DataEventType
+//import com.querydsl.core.annotations.PropertyType
+//import com.querydsl.core.annotations.QueryType
+//import org.bson.types.ObjectId
+//import org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl
+//
+//
+//class Action implements Serializable{
+//
+// private static final long serialVersionUID = 3687481049847555522L;
+//
+// private String importId;
+//
+// private ObjectId id = new ObjectId()
+//
+// private Map fieldIds = new HashMap<>()
+//
+// private Map transitionIds = new HashMap<>()
+//
+// private String definition
+//
+// private DataEventType trigger
+//
+// Action(Map fieldIds, Map transitionIds, String definition, String trigger) {
+// this(fieldIds, transitionIds, definition, DataEventType.fromString(trigger))
+// }
+//
+// Action(String definition, String trigger) {
+// this(new HashMap(), new HashMap(), definition, trigger)
+// }
+//
+// Action(Map fieldIds, Map transitionIds, String definition, DataEventType trigger) {
+// this.definition = definition
+// this.trigger = trigger
+// this.fieldIds = fieldIds
+// this.transitionIds = transitionIds
+// }
+//
+// Action() {
+// }
+//
+// Action(String trigger) {
+// this.trigger = DataEventType.fromString(trigger)
+// }
+//
+// ObjectId getId() {
+// return id
+// }
+//
+// String getDefinition() {
+// return definition
+// }
+//
+// void setDefinition(String definition) {
+// this.definition = definition
+// }
+//
+// Boolean isTriggeredBy(DataEventType trigger) {
+// return this.trigger == trigger
+// }
+//
+// DataEventType getTrigger() {
+// return trigger;
+// }
+//
+// void setTrigger(DataEventType trigger) {
+// this.trigger = trigger;
+// }
+//
+// Map getFieldIds() {
+// return fieldIds
+// }
+//
+// void addFieldId(String fieldName, String fieldId) {
+// this.fieldIds.put(fieldName, fieldId)
+// }
+//
+// Map getTransitionIds() {
+// return transitionIds
+// }
+//
+// void addTransitionId(String transitionName, String transitionId) {
+// this.transitionIds.put(transitionName, transitionId)
+// }
+//
+// String getImportId() {
+// return importId
+// }
+//
+// void setImportId(String importId) {
+// this.importId = importId
+// }
+//
+// void setFieldIds(Map fieldIds) {
+// this.fieldIds = fieldIds
+// }
+//
+// void setTransitionIds(Map transitionIds) {
+// this.transitionIds = transitionIds
+// }
+//
+// void setId(ObjectId id) {
+// this.id = id
+// }
+//
+// @Override
+// String toString() {
+// return "[$trigger] $definition"
+// }
+//
+// enum ActionTrigger {
+// GET,
+// SET
+//
+// static ActionTrigger fromString(String val) {
+// if (!val)
+// return null
+// return valueOf(val.toUpperCase())
+// }
+// }
+//
+// @Override
+// @QueryType(PropertyType.NONE)
+// MetaClass getMetaClass() {
+// return this.metaClass != null ? this.metaClass : ((MetaClassRegistryImpl) GroovySystem.getMetaClassRegistry()).getMetaClass(this)
+// }
+//
+// @Override
+// Action clone() {
+// Action clone = new Action()
+// clone.setId(new ObjectId(this.getId().toString()))
+// clone.setTrigger(this.trigger)
+// clone.setDefinition(this.definition)
+// clone.setImportId(this.importId)
+// clone.setTransitionIds(new HashMap(this.transitionIds))
+// clone.setFieldIds(new HashMap(this.fieldIds))
+// return clone
+// }
+//}
diff --git a/src/main/groovy/com/netgrif/application/engine/petrinet/domain/dataset/logic/action/ActionDelegate.groovy b/application-engine/src/main/groovy/com/netgrif/application/engine/petrinet/domain/dataset/logic/action/ActionDelegate.groovy
similarity index 96%
rename from src/main/groovy/com/netgrif/application/engine/petrinet/domain/dataset/logic/action/ActionDelegate.groovy
rename to application-engine/src/main/groovy/com/netgrif/application/engine/petrinet/domain/dataset/logic/action/ActionDelegate.groovy
index a4a20aa4204..6f327378236 100644
--- a/src/main/groovy/com/netgrif/application/engine/petrinet/domain/dataset/logic/action/ActionDelegate.groovy
+++ b/application-engine/src/main/groovy/com/netgrif/application/engine/petrinet/domain/dataset/logic/action/ActionDelegate.groovy
@@ -1,12 +1,14 @@
package com.netgrif.application.engine.petrinet.domain.dataset.logic.action
+
import com.netgrif.application.engine.AsyncRunner
-import com.netgrif.application.engine.auth.domain.Author
-import com.netgrif.application.engine.auth.domain.IUser
-import com.netgrif.application.engine.auth.domain.LoggedUser
+import com.netgrif.application.engine.adapter.spring.petrinet.service.ProcessRoleService
+import com.netgrif.application.engine.adapter.spring.workflow.domain.QCase
+import com.netgrif.application.engine.adapter.spring.workflow.domain.QTask
+import com.netgrif.application.engine.auth.service.GroupService
import com.netgrif.application.engine.auth.service.UserDetailsServiceImpl
+import com.netgrif.application.engine.auth.service.UserService
import com.netgrif.application.engine.auth.service.interfaces.IRegistrationService
-import com.netgrif.application.engine.auth.service.interfaces.IUserService
import com.netgrif.application.engine.auth.web.requestbodies.NewUserRequest
import com.netgrif.application.engine.configuration.ApplicationContextProvider
import com.netgrif.application.engine.configuration.PublicViewProperties
@@ -18,43 +20,43 @@ import com.netgrif.application.engine.export.configuration.ExportConfiguration
import com.netgrif.application.engine.export.domain.ExportDataConfig
import com.netgrif.application.engine.export.service.interfaces.IExportService
import com.netgrif.application.engine.impersonation.service.interfaces.IImpersonationService
-import com.netgrif.application.engine.history.service.IHistoryService
import com.netgrif.application.engine.importer.service.FieldFactory
+import com.netgrif.application.engine.integration.modules.ModuleHolder
import com.netgrif.application.engine.mail.domain.MailDraft
import com.netgrif.application.engine.mail.interfaces.IMailAttemptService
import com.netgrif.application.engine.mail.interfaces.IMailService
-import com.netgrif.application.engine.orgstructure.groups.interfaces.INextGroupService
+import com.netgrif.application.engine.objects.auth.domain.Author
+import com.netgrif.application.engine.objects.auth.domain.IUser
+import com.netgrif.application.engine.objects.auth.domain.LoggedUser
+import com.netgrif.application.engine.objects.petrinet.domain.*
+import com.netgrif.application.engine.objects.petrinet.domain.dataset.*
+import com.netgrif.application.engine.objects.petrinet.domain.dataset.logic.ChangedField
+import com.netgrif.application.engine.objects.petrinet.domain.dataset.logic.FieldBehavior
+import com.netgrif.application.engine.objects.petrinet.domain.dataset.logic.action.Action
+import com.netgrif.application.engine.objects.petrinet.domain.dataset.logic.validation.DynamicValidation
+import com.netgrif.application.engine.objects.petrinet.domain.dataset.logic.validation.Validation
+import com.netgrif.application.engine.objects.petrinet.domain.roles.ProcessRole
+import com.netgrif.application.engine.objects.petrinet.domain.version.Version
+import com.netgrif.application.engine.objects.workflow.domain.Case
+import com.netgrif.application.engine.objects.workflow.domain.Task
+import com.netgrif.application.engine.objects.workflow.domain.eventoutcomes.EventOutcome
+import com.netgrif.application.engine.objects.workflow.domain.eventoutcomes.caseoutcomes.CreateCaseEventOutcome
+import com.netgrif.application.engine.objects.workflow.domain.eventoutcomes.dataoutcomes.GetDataEventOutcome
+import com.netgrif.application.engine.objects.workflow.domain.eventoutcomes.dataoutcomes.SetDataEventOutcome
+import com.netgrif.application.engine.objects.workflow.domain.eventoutcomes.taskoutcomes.AssignTaskEventOutcome
+import com.netgrif.application.engine.objects.workflow.domain.eventoutcomes.taskoutcomes.TaskEventOutcome
+import com.netgrif.application.engine.objects.workflow.domain.menu.MenuItemBody
+import com.netgrif.application.engine.objects.workflow.domain.menu.MenuItemConstants
+import com.netgrif.application.engine.objects.workflow.service.InitValueExpressionEvaluator
import com.netgrif.application.engine.pdf.generator.config.PdfResource
import com.netgrif.application.engine.pdf.generator.service.interfaces.IPdfGenerator
-import com.netgrif.application.engine.petrinet.domain.*
-import com.netgrif.application.engine.petrinet.domain.dataset.*
-import com.netgrif.application.engine.petrinet.domain.dataset.logic.ChangedField
-import com.netgrif.application.engine.petrinet.domain.dataset.logic.FieldBehavior
-import com.netgrif.application.engine.petrinet.domain.dataset.logic.validation.DynamicValidation
-import com.netgrif.application.engine.petrinet.domain.dataset.logic.validation.Validation
-import com.netgrif.application.engine.petrinet.domain.roles.ProcessRole
-import com.netgrif.application.engine.petrinet.domain.version.Version
import com.netgrif.application.engine.petrinet.service.interfaces.IPetriNetService
-import com.netgrif.application.engine.petrinet.service.interfaces.IProcessRoleService
import com.netgrif.application.engine.petrinet.service.interfaces.IUriService
-//import com.netgrif.application.engine.rules.domain.RuleRepository
+import com.netgrif.application.engine.plugin.meta.PluginHolder
+import com.netgrif.application.engine.startup.ImportHelper
import com.netgrif.application.engine.startup.runner.DefaultFiltersRunner
import com.netgrif.application.engine.startup.runner.FilterRunner
-import com.netgrif.application.engine.startup.ImportHelper
import com.netgrif.application.engine.utils.FullPageRequest
-import com.netgrif.application.engine.workflow.domain.Case
-import com.netgrif.application.engine.workflow.domain.ProcessResourceId
-import com.netgrif.application.engine.workflow.domain.QCase
-import com.netgrif.application.engine.workflow.domain.QTask
-import com.netgrif.application.engine.workflow.domain.Task
-import com.netgrif.application.engine.workflow.domain.eventoutcomes.EventOutcome
-import com.netgrif.application.engine.workflow.domain.eventoutcomes.caseoutcomes.CreateCaseEventOutcome
-import com.netgrif.application.engine.workflow.domain.eventoutcomes.dataoutcomes.GetDataEventOutcome
-import com.netgrif.application.engine.workflow.domain.eventoutcomes.dataoutcomes.SetDataEventOutcome
-import com.netgrif.application.engine.workflow.domain.eventoutcomes.taskoutcomes.AssignTaskEventOutcome
-import com.netgrif.application.engine.workflow.domain.eventoutcomes.taskoutcomes.TaskEventOutcome
-import com.netgrif.application.engine.workflow.domain.menu.MenuItemBody
-import com.netgrif.application.engine.workflow.domain.menu.MenuItemConstants
import com.netgrif.application.engine.workflow.service.FileFieldInputStream
import com.netgrif.application.engine.workflow.service.TaskService
import com.netgrif.application.engine.workflow.service.interfaces.*
@@ -78,7 +80,6 @@ import org.springframework.data.domain.Pageable
import java.text.Normalizer
import java.time.ZoneId
import java.util.stream.Collectors
-
/**
* ActionDelegate class contains Actions API methods.
*/
@@ -114,7 +115,7 @@ class ActionDelegate {
IWorkflowService workflowService
@Autowired
- IUserService userService
+ UserService userService
@Autowired
IPetriNetService petriNetService
@@ -129,10 +130,10 @@ class ActionDelegate {
IMailService mailService
@Autowired
- INextGroupService nextGroupService
+ GroupService groupService
@Autowired
- IProcessRoleService processRoleService
+ ProcessRoleService processRoleService
@Autowired
IRegistrationService registrationService
@@ -147,7 +148,7 @@ class ActionDelegate {
IDataValidationExpressionEvaluator dataValidationExpressionEvaluator
@Autowired
- IInitValueExpressionEvaluator initValueExpressionEvaluator
+ InitValueExpressionEvaluator initValueExpressionEvaluator
// @Autowired
// RuleRepository ruleRepository
@@ -185,14 +186,18 @@ class ActionDelegate {
@Autowired
IImpersonationService impersonationService
- @Autowired
- IHistoryService historyService
+// @Autowired
+// IHistoryService historyService
@Autowired
PublicViewProperties publicViewProperties
FrontendActionOutcome Frontend
+ ModuleHolder NaeModule
+
+ PluginHolder Plugin
+
/**
* Reference of case and task in which current action is taking place.
*/
@@ -214,6 +219,8 @@ class ActionDelegate {
this.initTransitionsMap(action.transitionIds)
this.outcomes = new ArrayList<>()
this.Frontend = new FrontendActionOutcome(this.useCase, this.task, this.outcomes)
+ this.NaeModule = new ModuleHolder()
+ this.Plugin = new PluginHolder()
}
def initFieldsMap(Map fieldIds) {
@@ -758,7 +765,7 @@ class ActionDelegate {
}
if (field instanceof UserListField && (value instanceof String[] || value instanceof List)) {
LinkedHashSet users = new LinkedHashSet<>()
- value.each { id -> users.add(new UserFieldValue(userService.findById(id as String, false))) }
+ value.each { id -> users.add(new UserFieldValue(userService.findById(id as String, null))) }
value = new UserListFieldValue(users)
}
// if (field instanceof TaskField && targetTask.isPresent()) {
@@ -905,18 +912,18 @@ class ActionDelegate {
}
Case createCase(String identifier, String title = null, String color = "", IUser author = userService.loggedOrSystem, Locale locale = LocaleContextHolder.getLocale(), Map params = [:]) {
- return workflowService.createCaseByIdentifier(identifier, title, color, author.transformToLoggedUser(), locale, params).getCase()
+ return workflowService.createCaseByIdentifier(identifier, title, color, userService.transformToLoggedUser(author), locale, params).getCase()
}
Case createCase(PetriNet net, String title = net.defaultCaseName.getTranslation(locale), String color = "", IUser author = userService.loggedOrSystem, Locale locale = LocaleContextHolder.getLocale(), Map params = [:]) {
- CreateCaseEventOutcome outcome = workflowService.createCase(net.stringId, title, color, author.transformToLoggedUser(), params)
+ CreateCaseEventOutcome outcome = workflowService.createCase(net.stringId, title, color, userService.transformToLoggedUser(author), params)
this.outcomes.add(outcome)
return outcome.getCase()
}
Task assignTask(String transitionId, Case aCase = useCase, IUser user = userService.loggedOrSystem, Map params = [:]) {
String taskId = getTaskId(transitionId, aCase)
- AssignTaskEventOutcome outcome = taskService.assignTask(user.transformToLoggedUser(), taskId, params)
+ AssignTaskEventOutcome outcome = taskService.assignTask(userService.transformToLoggedUser(user), taskId, params)
this.outcomes.add(outcome)
return outcome.getTask()
}
@@ -931,7 +938,7 @@ class ActionDelegate {
Task cancelTask(String transitionId, Case aCase = useCase, IUser user = userService.loggedOrSystem, Map params = [:]) {
String taskId = getTaskId(transitionId, aCase)
- return addTaskOutcomeAndReturnTask(taskService.cancelTask(user.transformToLoggedUser(), taskId, params))
+ return addTaskOutcomeAndReturnTask(taskService.cancelTask(userService.transformToLoggedUser(user), taskId, params))
}
Task cancelTask(Task task, IUser user = userService.loggedOrSystem, Map params = [:]) {
@@ -949,7 +956,7 @@ class ActionDelegate {
void finishTask(String transitionId, Case aCase = useCase, IUser user = userService.loggedOrSystem, Map params = [:]) {
String taskId = getTaskId(transitionId, aCase)
- addTaskOutcomeAndReturnTask(taskService.finishTask(user.transformToLoggedUser(), taskId, params))
+ addTaskOutcomeAndReturnTask(taskService.finishTask(userService.transformToLoggedUser(user), taskId, params))
}
void finishTask(Task task, IUser user = userService.loggedOrSystem, Map params = [:]) {
@@ -978,7 +985,7 @@ class ActionDelegate {
}
Task findTask(String mongoId) {
- return taskService.searchOne(QTask.task._id.eq(new ObjectId(mongoId)))
+ return taskService.findById(mongoId)
}
String getTaskId(String transitionId, Case aCase = useCase) {
@@ -1041,9 +1048,8 @@ class ActionDelegate {
}
SetDataEventOutcome setData(String transitionId, Case useCase, Map dataSet, Map params = [:]) {
- def predicate = QTask.task.caseId.eq(useCase.stringId) & QTask.task.transitionId.eq(transitionId)
- def task = taskService.searchOne(predicate)
- return addSetDataOutcomeToOutcomes(dataService.setData(task.stringId, ImportHelper.populateDataset(dataSet), params))
+ def taskId = useCase.tasks.find { it.transition == transitionId }?.task
+ return addSetDataOutcomeToOutcomes(dataService.setData(taskId, ImportHelper.populateDataset(dataSet), params))
}
@Deprecated
@@ -1097,10 +1103,10 @@ class ActionDelegate {
}
Map getData(String transitionId, Case useCase, Map params = [:]) {
- def predicate = QTask.task.caseId.eq(useCase.stringId) & QTask.task.transitionId.eq(transitionId)
- def task = taskService.searchOne(predicate)
- if (!task)
+ def taskId = useCase.tasks.find { it.transition == transitionId }.task
+ if (!taskId)
return new HashMap()
+ Task task = taskService.findById(taskId)
return mapData(addGetDataOutcomeToOutcomesAndReturnData(dataService.getData(task, useCase, params)))
}
@@ -1289,12 +1295,12 @@ class ActionDelegate {
}
def changeUserByEmail(String email, String attribute, def cl) {
- IUser user = userService.findByEmail(email, false)
+ IUser user = userService.findUserByUsername(email, null)
changeUser(user, attribute, cl)
}
def changeUser(String id, String attribute, def cl) {
- IUser user = userService.findById(id, false)
+ IUser user = userService.findById(id, null)
changeUser(user, attribute, cl)
}
@@ -1310,7 +1316,7 @@ class ActionDelegate {
}
user[attribute] = cl() as String
- userService.save(user)
+ userService.saveUser(user, null)
}
MessageResource inviteUser(String email) {
@@ -1332,7 +1338,7 @@ class ActionDelegate {
}
void deleteUser(String email) {
- IUser user = userService.findByEmail(email, false)
+ IUser user = userService.findByEmail(email, null)
if (user == null)
log.error("Cannot find user with email [" + email + "]")
deleteUser(user)
@@ -1352,7 +1358,7 @@ class ActionDelegate {
}
IUser findUserByEmail(String email) {
- IUser user = userService.findByEmail(email, false)
+ IUser user = userService.findUserByUsername(email, null)
if (user == null) {
log.error("Cannot find user with email [" + email + "]")
return null
@@ -1362,7 +1368,7 @@ class ActionDelegate {
}
IUser findUserById(String id) {
- IUser user = userService.findById(id, false)
+ IUser user = userService.findById(id, null)
if (user == null) {
log.error("Cannot find user with id [" + id + "]")
return null
@@ -1413,7 +1419,7 @@ class ActionDelegate {
}
File exportCasesToFile(List requests, String pathName, ExportDataConfig config = null,
- LoggedUser user = userService.loggedOrSystem.transformToLoggedUser(),
+ LoggedUser user = userService.transformToLoggedUser(userService.getLoggedOrSystem()),
int pageSize = exportConfiguration.getMongoPageSize(),
Locale locale = LocaleContextHolder.getLocale(),
Boolean isIntersection = false) {
@@ -1424,7 +1430,7 @@ class ActionDelegate {
}
OutputStream exportCases(List requests, File outFile, ExportDataConfig config = null,
- LoggedUser user = userService.loggedOrSystem.transformToLoggedUser(),
+ LoggedUser user = userService.transformToLoggedUser(userService.getLoggedOrSystem()),
int pageSize = exportConfiguration.getMongoPageSize(),
Locale locale = LocaleContextHolder.getLocale(),
Boolean isIntersection = false) {
@@ -1444,7 +1450,7 @@ class ActionDelegate {
}
File exportTasksToFile(List requests, String pathName, ExportDataConfig config = null,
- LoggedUser user = userService.loggedOrSystem.transformToLoggedUser(),
+ LoggedUser user = userService.transformToLoggedUser(userService.getLoggedOrSystem()),
int pageSize = exportConfiguration.getMongoPageSize(),
Locale locale = LocaleContextHolder.getLocale(),
Boolean isIntersection = false) {
@@ -1455,7 +1461,7 @@ class ActionDelegate {
}
OutputStream exportTasks(List requests, File outFile, ExportDataConfig config = null,
- LoggedUser user = userService.loggedOrSystem.transformToLoggedUser(),
+ LoggedUser user = userService.transformToLoggedUser(userService.getLoggedOrSystem()),
int pageSize = exportConfiguration.getMongoPageSize(),
Locale locale = LocaleContextHolder.getLocale(),
Boolean isIntersection = false) {
@@ -1488,7 +1494,7 @@ class ActionDelegate {
* @param isIntersection to decide null query handling
* @return page of cases
* */
- Page findCasesElastic(List requests, LoggedUser loggedUser = userService.loggedOrSystem.transformToLoggedUser(),
+ Page findCasesElastic(List requests, LoggedUser loggedUser = userService.transformToLoggedUser(userService.getLoggedOrSystem()),
int page = 1, int pageSize = 25, Locale locale = Locale.default, boolean isIntersection = false) {
return elasticCaseService.search(requests, loggedUser, PageRequest.of(page, pageSize), locale, isIntersection)
}
@@ -1503,7 +1509,7 @@ class ActionDelegate {
* @param isIntersection to decide null query handling
* @return page of cases
* */
- Page findCasesElastic(Map request, LoggedUser loggedUser = userService.loggedOrSystem.transformToLoggedUser(),
+ Page findCasesElastic(Map request, LoggedUser loggedUser = userService.transformToLoggedUser(userService.getLoggedOrSystem()),
int page = 1, int pageSize = 25, Locale locale = Locale.default, boolean isIntersection = false) {
List requests = Collections.singletonList(new CaseSearchRequest(request))
return findCasesElastic(requests, loggedUser, page, pageSize, locale, isIntersection)
@@ -1519,7 +1525,7 @@ class ActionDelegate {
* @param isIntersection to decide null query handling
* @return page of cases
* */
- Page findTasks(List requests, LoggedUser loggedUser = userService.loggedOrSystem.transformToLoggedUser(),
+ Page findTasks(List requests, LoggedUser loggedUser = userService.transformToLoggedUser(userService.getLoggedOrSystem()),
int page = 1, int pageSize = 25, Locale locale = Locale.default, boolean isIntersection = false) {
return elasticTaskService.search(requests, loggedUser, PageRequest.of(page, pageSize), locale, isIntersection)
}
@@ -1534,7 +1540,7 @@ class ActionDelegate {
* @param isIntersection to decide null query handling
* @return page of cases
* */
- Page findTasks(Map request, LoggedUser loggedUser = userService.loggedOrSystem.transformToLoggedUser(),
+ Page findTasks(Map request, LoggedUser loggedUser = userService.transformToLoggedUser(userService.getLoggedOrSystem()),
int page = 1, int pageSize = 25, Locale locale = Locale.default, boolean isIntersection = false) {
List requests = Collections.singletonList(new ElasticTaskSearchRequest(request))
return findTasks(requests, loggedUser, page, pageSize, locale, isIntersection)
@@ -1599,6 +1605,10 @@ class ActionDelegate {
@NamedVariant
Case createFilter(def title, String query, String type, List allowedNets,
String icon, String visibility, def filterMetadata) {
+ if (type == null || type.length() == 0) {
+ throw new IllegalArgumentException("Filter type cannot be null or empty");
+ }
+ type = type.toLowerCase().capitalize()
Case filterCase = createCase(FilterRunner.FILTER_PETRI_NET_IDENTIFIER, title as String)
filterCase.setIcon(icon)
filterCase.dataSet[DefaultFiltersRunner.FILTER_I18N_TITLE_FIELD_ID].value = (title instanceof I18nString) ? title : new I18nString(title as String)
@@ -2481,14 +2491,14 @@ class ActionDelegate {
List findCasesElastic(String query, Pageable pageable) {
CaseSearchRequest request = new CaseSearchRequest()
request.query = query
- List result = elasticCaseService.search([request], userService.system.transformToLoggedUser(), pageable, LocaleContextHolder.locale, false).content
+ List result = elasticCaseService.search([request], userService.transformToLoggedUser(userService.getSystem()), pageable, LocaleContextHolder.locale, false).content
return result
}
long countCasesElastic(String query) {
CaseSearchRequest request = new CaseSearchRequest()
request.query = query
- return elasticCaseService.count([request], userService.system.transformToLoggedUser(), LocaleContextHolder.locale, false)
+ return elasticCaseService.count([request], userService.transformToLoggedUser(userService.getSystem()), LocaleContextHolder.locale, false)
}
@Deprecated
diff --git a/application-engine/src/main/groovy/com/netgrif/application/engine/petrinet/domain/dataset/logic/action/FieldActionsRunner.groovy b/application-engine/src/main/groovy/com/netgrif/application/engine/petrinet/domain/dataset/logic/action/FieldActionsRunner.groovy
new file mode 100644
index 00000000000..b4b1c6ba7ae
--- /dev/null
+++ b/application-engine/src/main/groovy/com/netgrif/application/engine/petrinet/domain/dataset/logic/action/FieldActionsRunner.groovy
@@ -0,0 +1,110 @@
+package com.netgrif.application.engine.petrinet.domain.dataset.logic.action
+
+import com.netgrif.application.engine.business.IPostalCodeService
+import com.netgrif.application.engine.business.orsr.IOrsrService
+import com.netgrif.application.engine.importer.service.FieldFactory
+import com.netgrif.application.engine.objects.event.events.event.ActionStartEvent
+import com.netgrif.application.engine.objects.event.events.event.ActionStopEvent
+import com.netgrif.application.engine.workflow.service.interfaces.IFieldActionsCacheService
+import com.netgrif.application.engine.objects.petrinet.domain.Function
+import com.netgrif.application.engine.objects.workflow.domain.Case
+import com.netgrif.application.engine.objects.workflow.domain.Task
+import com.netgrif.application.engine.objects.workflow.domain.eventoutcomes.EventOutcome
+import org.slf4j.Logger
+import org.slf4j.LoggerFactory
+import org.springframework.beans.factory.annotation.Autowired
+import org.springframework.beans.factory.annotation.Lookup
+import org.springframework.context.ApplicationEventPublisher
+import org.springframework.stereotype.Component
+
+@Component
+@SuppressWarnings("GrMethodMayBeStatic")
+abstract class FieldActionsRunner {
+
+ private static final Logger log = LoggerFactory.getLogger(FieldActionsRunner.class)
+
+ @Lookup("actionDelegate")
+ abstract ActionDelegate getActionDeleget()
+
+ @Autowired
+ private IOrsrService orsrService
+
+ @Autowired
+ private IPostalCodeService postalCodeService
+
+ @Autowired
+ private FieldFactory fieldFactory
+
+ @Autowired
+ private IFieldActionsCacheService actionsCacheService
+
+ @Autowired
+ private ApplicationEventPublisher publisher
+
+ private Map actionsCache = new HashMap<>()
+
+ List run(com.netgrif.application.engine.objects.petrinet.domain.dataset.logic.action.Action action, Case useCase, Map params, List functions = []) {
+ return run(action, useCase, Optional.empty(), params, functions)
+ }
+
+ List run(com.netgrif.application.engine.objects.petrinet.domain.dataset.logic.action.Action action, Case useCase, Optional task, Map params, List functions = []) {
+ if (!actionsCache)
+ actionsCache = new HashMap<>()
+
+ log.debug("Action: $action")
+ def code = getActionCode(action, functions)
+ final ActionStartEvent actionStart = new ActionStartEvent(action)
+ try {
+ publisher.publishEvent(actionStart)
+ code.init(action, useCase, task, this, params)
+ code()
+ publisher.publishEvent(new ActionStopEvent(action, actionStart, true))
+ } catch (Exception e) {
+ log.error("Action: $action.definition")
+ publisher.publishEvent(new ActionStopEvent(action, actionStart, false))
+ throw e
+ }
+ return ((ActionDelegate) code.delegate).outcomes
+ }
+
+ Closure getActionCode(com.netgrif.application.engine.objects.petrinet.domain.dataset.logic.action.Action action, List functions, boolean shouldRewriteCachedActions = false) {
+ return getActionCode(actionsCacheService.getCompiledAction(action, shouldRewriteCachedActions), functions)
+ }
+
+ Closure getActionCode(Closure code, List functions) {
+ def actionDelegate = getActionDeleget()
+
+ actionsCacheService.getCachedFunctions(functions).each {
+ actionDelegate.metaClass."${it.function.name}" << it.code
+ }
+ actionsCacheService.getNamespaceFunctionCache().each { entry ->
+ def namespace = [:]
+ entry.getValue().each {
+ namespace["${it.function.name}"] = it.code.rehydrate(actionDelegate, it.code.owner, it.code.thisObject)
+ }
+ actionDelegate.metaClass."${entry.key}" = namespace
+ }
+ return code.rehydrate(actionDelegate, code.owner, code.thisObject)
+ }
+
+ void addToCache(String key, Object value) {
+ this.actionsCache.put(key, value)
+ }
+
+ void removeFromCache(String key) {
+ this.actionsCache.remove(key)
+ }
+
+ def getFromCache(String key) {
+ return this.actionsCache.get(key)
+ }
+
+ IPostalCodeService getPostalCodeService() {
+ return postalCodeService
+ }
+
+ IOrsrService getOrsrService() {
+ return orsrService
+ }
+
+}
diff --git a/src/main/groovy/com/netgrif/application/engine/petrinet/domain/dataset/logic/action/FileGenerateReflection.groovy b/application-engine/src/main/groovy/com/netgrif/application/engine/petrinet/domain/dataset/logic/action/FileGenerateReflection.groovy
similarity index 93%
rename from src/main/groovy/com/netgrif/application/engine/petrinet/domain/dataset/logic/action/FileGenerateReflection.groovy
rename to application-engine/src/main/groovy/com/netgrif/application/engine/petrinet/domain/dataset/logic/action/FileGenerateReflection.groovy
index d495a02938f..046c7127753 100644
--- a/src/main/groovy/com/netgrif/application/engine/petrinet/domain/dataset/logic/action/FileGenerateReflection.groovy
+++ b/application-engine/src/main/groovy/com/netgrif/application/engine/petrinet/domain/dataset/logic/action/FileGenerateReflection.groovy
@@ -1,7 +1,7 @@
package com.netgrif.application.engine.petrinet.domain.dataset.logic.action
-import com.netgrif.application.engine.petrinet.domain.dataset.FileField
-import com.netgrif.application.engine.workflow.domain.Case
+import com.netgrif.application.engine.objects.petrinet.domain.dataset.FileField
+import com.netgrif.application.engine.objects.workflow.domain.Case
import org.slf4j.Logger
import org.slf4j.LoggerFactory
diff --git a/application-engine/src/main/groovy/com/netgrif/application/engine/petrinet/domain/dataset/logic/action/FrontendActionOutcome.groovy b/application-engine/src/main/groovy/com/netgrif/application/engine/petrinet/domain/dataset/logic/action/FrontendActionOutcome.groovy
new file mode 100644
index 00000000000..d0319498def
--- /dev/null
+++ b/application-engine/src/main/groovy/com/netgrif/application/engine/petrinet/domain/dataset/logic/action/FrontendActionOutcome.groovy
@@ -0,0 +1,26 @@
+package com.netgrif.application.engine.petrinet.domain.dataset.logic.action
+
+import com.netgrif.application.engine.objects.petrinet.domain.dataset.logic.FrontAction
+import com.netgrif.application.engine.objects.workflow.domain.Case
+import com.netgrif.application.engine.objects.workflow.domain.Task
+import com.netgrif.application.engine.objects.workflow.domain.eventoutcomes.EventOutcome
+import com.netgrif.application.engine.objects.workflow.domain.eventoutcomes.dataoutcomes.SetDataEventOutcome
+
+class FrontendActionOutcome {
+
+ Case useCase
+ Optional task
+ List outcomes
+
+ FrontendActionOutcome(Case useCase, Optional task, List outcomes) {
+ this.useCase = useCase
+ this.task = task
+ this.outcomes = outcomes
+ }
+
+ def methodMissing(String name, Object args) {
+ SetDataEventOutcome outcome = new SetDataEventOutcome(this.useCase, this.task.orElse(null))
+ outcome.addFrontAction(new FrontAction(name, args))
+ this.outcomes.add(outcome)
+ }
+}
diff --git a/src/main/groovy/com/netgrif/application/engine/petrinet/domain/dataset/logic/action/TextGenerateReflection.groovy b/application-engine/src/main/groovy/com/netgrif/application/engine/petrinet/domain/dataset/logic/action/TextGenerateReflection.groovy
similarity index 92%
rename from src/main/groovy/com/netgrif/application/engine/petrinet/domain/dataset/logic/action/TextGenerateReflection.groovy
rename to application-engine/src/main/groovy/com/netgrif/application/engine/petrinet/domain/dataset/logic/action/TextGenerateReflection.groovy
index 00f55aea81b..bf8e1612be8 100644
--- a/src/main/groovy/com/netgrif/application/engine/petrinet/domain/dataset/logic/action/TextGenerateReflection.groovy
+++ b/application-engine/src/main/groovy/com/netgrif/application/engine/petrinet/domain/dataset/logic/action/TextGenerateReflection.groovy
@@ -1,7 +1,7 @@
package com.netgrif.application.engine.petrinet.domain.dataset.logic.action
-import com.netgrif.application.engine.petrinet.domain.dataset.TextField
-import com.netgrif.application.engine.workflow.domain.Case
+import com.netgrif.application.engine.objects.petrinet.domain.dataset.TextField
+import com.netgrif.application.engine.objects.workflow.domain.Case
import org.slf4j.Logger
import org.slf4j.LoggerFactory
@@ -57,4 +57,4 @@ class TextGenerateReflection {
return null
}
}
-}
\ No newline at end of file
+}
diff --git a/src/main/groovy/com/netgrif/application/engine/petrinet/domain/dataset/logic/action/context/ActionContext.groovy b/application-engine/src/main/groovy/com/netgrif/application/engine/petrinet/domain/dataset/logic/action/context/ActionContext.groovy
similarity index 100%
rename from src/main/groovy/com/netgrif/application/engine/petrinet/domain/dataset/logic/action/context/ActionContext.groovy
rename to application-engine/src/main/groovy/com/netgrif/application/engine/petrinet/domain/dataset/logic/action/context/ActionContext.groovy
diff --git a/application-engine/src/main/groovy/com/netgrif/application/engine/petrinet/domain/dataset/logic/action/context/CaseContext.groovy b/application-engine/src/main/groovy/com/netgrif/application/engine/petrinet/domain/dataset/logic/action/context/CaseContext.groovy
new file mode 100644
index 00000000000..134b0360c51
--- /dev/null
+++ b/application-engine/src/main/groovy/com/netgrif/application/engine/petrinet/domain/dataset/logic/action/context/CaseContext.groovy
@@ -0,0 +1,10 @@
+package com.netgrif.application.engine.petrinet.domain.dataset.logic.action.context
+
+import com.netgrif.application.engine.objects.workflow.domain.Case
+
+class CaseContext {
+
+ Case useCase
+
+
+}
diff --git a/application-engine/src/main/groovy/com/netgrif/application/engine/petrinet/domain/dataset/logic/action/context/RoleContext.groovy b/application-engine/src/main/groovy/com/netgrif/application/engine/petrinet/domain/dataset/logic/action/context/RoleContext.groovy
new file mode 100644
index 00000000000..cec0a0baeef
--- /dev/null
+++ b/application-engine/src/main/groovy/com/netgrif/application/engine/petrinet/domain/dataset/logic/action/context/RoleContext.groovy
@@ -0,0 +1,17 @@
+package com.netgrif.application.engine.petrinet.domain.dataset.logic.action.context
+
+import com.netgrif.application.engine.objects.petrinet.domain.PetriNet
+import com.netgrif.application.engine.objects.petrinet.domain.roles.ProcessRole
+
+class RoleContext extends ActionContext {
+
+ T user
+ ProcessRole role
+ PetriNet petriNet
+
+ RoleContext(T user, ProcessRole role, PetriNet petriNet) {
+ this.user = user
+ this.role = role
+ this.petriNet = petriNet
+ }
+}
diff --git a/src/main/groovy/com/netgrif/application/engine/petrinet/domain/dataset/logic/action/delegate/AbstractActionDelegate.groovy b/application-engine/src/main/groovy/com/netgrif/application/engine/petrinet/domain/dataset/logic/action/delegate/AbstractActionDelegate.groovy
similarity index 76%
rename from src/main/groovy/com/netgrif/application/engine/petrinet/domain/dataset/logic/action/delegate/AbstractActionDelegate.groovy
rename to application-engine/src/main/groovy/com/netgrif/application/engine/petrinet/domain/dataset/logic/action/delegate/AbstractActionDelegate.groovy
index b19ac577ea7..34636778694 100644
--- a/src/main/groovy/com/netgrif/application/engine/petrinet/domain/dataset/logic/action/delegate/AbstractActionDelegate.groovy
+++ b/application-engine/src/main/groovy/com/netgrif/application/engine/petrinet/domain/dataset/logic/action/delegate/AbstractActionDelegate.groovy
@@ -1,6 +1,6 @@
package com.netgrif.application.engine.petrinet.domain.dataset.logic.action.delegate
-import com.netgrif.application.engine.petrinet.domain.dataset.logic.action.Action
+import com.netgrif.application.engine.objects.petrinet.domain.dataset.logic.action.Action
import com.netgrif.application.engine.petrinet.domain.dataset.logic.action.context.ActionContext
abstract class AbstractActionDelegate {
diff --git a/src/main/groovy/com/netgrif/application/engine/petrinet/domain/dataset/logic/action/delegate/CaseActionDelegate.groovy b/application-engine/src/main/groovy/com/netgrif/application/engine/petrinet/domain/dataset/logic/action/delegate/CaseActionDelegate.groovy
similarity index 100%
rename from src/main/groovy/com/netgrif/application/engine/petrinet/domain/dataset/logic/action/delegate/CaseActionDelegate.groovy
rename to application-engine/src/main/groovy/com/netgrif/application/engine/petrinet/domain/dataset/logic/action/delegate/CaseActionDelegate.groovy
diff --git a/src/main/groovy/com/netgrif/application/engine/petrinet/domain/dataset/logic/action/delegate/RoleActionDelegate.groovy b/application-engine/src/main/groovy/com/netgrif/application/engine/petrinet/domain/dataset/logic/action/delegate/RoleActionDelegate.groovy
similarity index 83%
rename from src/main/groovy/com/netgrif/application/engine/petrinet/domain/dataset/logic/action/delegate/RoleActionDelegate.groovy
rename to application-engine/src/main/groovy/com/netgrif/application/engine/petrinet/domain/dataset/logic/action/delegate/RoleActionDelegate.groovy
index 3fdc03be078..d9d8ef3e010 100644
--- a/src/main/groovy/com/netgrif/application/engine/petrinet/domain/dataset/logic/action/delegate/RoleActionDelegate.groovy
+++ b/application-engine/src/main/groovy/com/netgrif/application/engine/petrinet/domain/dataset/logic/action/delegate/RoleActionDelegate.groovy
@@ -1,14 +1,14 @@
package com.netgrif.application.engine.petrinet.domain.dataset.logic.action.delegate
-import com.netgrif.application.engine.auth.domain.IUser
+import com.netgrif.application.engine.objects.auth.domain.IUser
-import com.netgrif.application.engine.auth.service.interfaces.IUserService
-import com.netgrif.application.engine.petrinet.domain.PetriNet
-import com.netgrif.application.engine.petrinet.domain.dataset.logic.action.Action
+import com.netgrif.application.engine.auth.service.UserService
+import com.netgrif.application.engine.objects.petrinet.domain.PetriNet
+import com.netgrif.application.engine.objects.petrinet.domain.dataset.logic.action.Action
import com.netgrif.application.engine.petrinet.domain.dataset.logic.action.context.RoleContext
-import com.netgrif.application.engine.petrinet.domain.roles.ProcessRole
import com.netgrif.application.engine.petrinet.service.interfaces.IPetriNetService
-import com.netgrif.application.engine.petrinet.service.interfaces.IProcessRoleService
+import com.netgrif.application.engine.adapter.spring.petrinet.service.ProcessRoleService
+import com.netgrif.application.engine.objects.petrinet.domain.roles.ProcessRole
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Component
@@ -17,13 +17,13 @@ import org.springframework.stereotype.Component
class RoleActionDelegate extends AbstractActionDelegate {
@Autowired
- IUserService userService
+ UserService userService
@Autowired
IPetriNetService petriNetService
@Autowired
- IProcessRoleService processRoleService
+ ProcessRoleService processRoleService
Action action
ProcessRole processRole
@@ -89,6 +89,6 @@ class RoleActionDelegate extends AbstractActionDelegate {
ProcessRole role = processRoleService.findById(roleId)
user.getProcessRoles().remove(role)
- return userService.save(user)
+ return userService.saveUser(user, null)
}
}
diff --git a/src/main/groovy/com/netgrif/application/engine/petrinet/domain/dataset/logic/action/runner/CaseFieldsExpressionRunner.groovy b/application-engine/src/main/groovy/com/netgrif/application/engine/petrinet/domain/dataset/logic/action/runner/CaseFieldsExpressionRunner.groovy
similarity index 80%
rename from src/main/groovy/com/netgrif/application/engine/petrinet/domain/dataset/logic/action/runner/CaseFieldsExpressionRunner.groovy
rename to application-engine/src/main/groovy/com/netgrif/application/engine/petrinet/domain/dataset/logic/action/runner/CaseFieldsExpressionRunner.groovy
index db8c9d46b8e..95ab7bce867 100644
--- a/src/main/groovy/com/netgrif/application/engine/petrinet/domain/dataset/logic/action/runner/CaseFieldsExpressionRunner.groovy
+++ b/application-engine/src/main/groovy/com/netgrif/application/engine/petrinet/domain/dataset/logic/action/runner/CaseFieldsExpressionRunner.groovy
@@ -3,7 +3,7 @@ package com.netgrif.application.engine.petrinet.domain.dataset.logic.action.runn
import com.netgrif.application.engine.event.IGroovyShellFactory
import com.netgrif.application.engine.elastic.service.executors.MaxSizeHashMap
import com.netgrif.application.engine.petrinet.domain.dataset.logic.action.ActionDelegate
-import com.netgrif.application.engine.workflow.domain.Case
+import com.netgrif.application.engine.objects.workflow.domain.Case
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.springframework.beans.factory.annotation.Autowired
@@ -31,14 +31,14 @@ abstract class CaseFieldsExpressionRunner {
this.cacheSize = cacheSize
}
- def run(Case useCase, Expression expression, Map params = [:]) {
+ def run(Case useCase, com.netgrif.application.engine.objects.petrinet.domain.dataset.logic.action.runner.Expression expression, Map params = [:]) {
Map fields = useCase.getDataSet().keySet().collectEntries { fieldId ->
[(fieldId): (fieldId)]
} as Map
return run(useCase, fields, expression, params)
}
- def run(Case useCase, Map fields, Expression expression, Map params = [:]) {
+ def run(Case useCase, Map fields, com.netgrif.application.engine.objects.petrinet.domain.dataset.logic.action.runner.Expression expression, Map params = [:]) {
logger().debug("Expression: $expression")
def code = getExpressionCode(expression)
try {
@@ -50,7 +50,7 @@ abstract class CaseFieldsExpressionRunner {
}
}
- protected Closure getExpressionCode(Expression expression) {
+ protected Closure getExpressionCode(com.netgrif.application.engine.objects.petrinet.domain.dataset.logic.action.runner.Expression expression) {
def code
if (cache.containsKey(expression.stringId)) {
code = cache.get(expression.stringId)
diff --git a/src/main/groovy/com/netgrif/application/engine/petrinet/domain/dataset/logic/action/runner/Expression.groovy b/application-engine/src/main/groovy/com/netgrif/application/engine/petrinet/domain/dataset/logic/action/runner/Expression.groovy
similarity index 100%
rename from src/main/groovy/com/netgrif/application/engine/petrinet/domain/dataset/logic/action/runner/Expression.groovy
rename to application-engine/src/main/groovy/com/netgrif/application/engine/petrinet/domain/dataset/logic/action/runner/Expression.groovy
diff --git a/src/main/groovy/com/netgrif/application/engine/petrinet/domain/dataset/logic/action/runner/RoleActionsRunner.groovy b/application-engine/src/main/groovy/com/netgrif/application/engine/petrinet/domain/dataset/logic/action/runner/RoleActionsRunner.groovy
similarity index 95%
rename from src/main/groovy/com/netgrif/application/engine/petrinet/domain/dataset/logic/action/runner/RoleActionsRunner.groovy
rename to application-engine/src/main/groovy/com/netgrif/application/engine/petrinet/domain/dataset/logic/action/runner/RoleActionsRunner.groovy
index 57df6a00091..52b85770537 100644
--- a/src/main/groovy/com/netgrif/application/engine/petrinet/domain/dataset/logic/action/runner/RoleActionsRunner.groovy
+++ b/application-engine/src/main/groovy/com/netgrif/application/engine/petrinet/domain/dataset/logic/action/runner/RoleActionsRunner.groovy
@@ -2,7 +2,7 @@ package com.netgrif.application.engine.petrinet.domain.dataset.logic.action.runn
import com.netgrif.application.engine.event.IGroovyShellFactory
-import com.netgrif.application.engine.petrinet.domain.dataset.logic.action.Action
+import com.netgrif.application.engine.objects.petrinet.domain.dataset.logic.action.Action
import com.netgrif.application.engine.petrinet.domain.dataset.logic.action.context.RoleContext
import com.netgrif.application.engine.petrinet.domain.dataset.logic.action.delegate.RoleActionDelegate
import org.codehaus.groovy.control.CompilerConfiguration
diff --git a/application-engine/src/main/groovy/com/netgrif/application/engine/plugin/PluginInjector.groovy b/application-engine/src/main/groovy/com/netgrif/application/engine/plugin/PluginInjector.groovy
new file mode 100644
index 00000000000..2ce8aa0d891
--- /dev/null
+++ b/application-engine/src/main/groovy/com/netgrif/application/engine/plugin/PluginInjector.groovy
@@ -0,0 +1,82 @@
+package com.netgrif.application.engine.plugin
+
+import com.netgrif.application.engine.adapter.spring.plugin.service.PluginService
+import com.netgrif.application.engine.objects.plugin.domain.EntryPoint
+import com.netgrif.application.engine.objects.plugin.domain.Method
+import com.netgrif.application.engine.objects.plugin.domain.Plugin
+import com.netgrif.application.engine.petrinet.domain.dataset.logic.action.ActionDelegate
+import com.netgrif.application.engine.plugin.meta.EntryPointMeta
+import com.netgrif.application.engine.plugin.meta.PluginHolder
+import com.netgrif.application.engine.plugin.meta.PluginMeta
+import org.springframework.beans.factory.annotation.Autowired
+import org.springframework.stereotype.Component
+
+/**
+ * Component responsible for injecting plugin entry points and methods into
+ * the application's meta-class system at runtime. Uses Groovy's metaClass
+ * mechanism to dynamically add closures that delegate calls to PluginService.
+ *
+ * @see ActionDelegate
+ * @see PluginService
+ */
+@Component
+class PluginInjector {
+
+ /**
+ * Service used to invoke methods on the injected plugins.
+ */
+ @Autowired
+ protected PluginService pluginService
+
+ /**
+ * Injects the provided plugin into the application's meta-class system.
+ * This will allow calls to plugin entry points and methods via dynamic
+ * properties on {@link PluginHolder}.
+ *
+ * @param plugin the Plugin instance to be injected
+ */
+ void inject(Plugin plugin) {
+ updateMetaClasses(plugin, false)
+ }
+
+ /**
+ * Removes the provided plugin from the application's meta-class system.
+ * This will disable dynamic calls to the plugin's entry points and methods
+ * via {@link PluginHolder}.
+ *
+ * @param plugin the Plugin instance to be removed
+ */
+ void unInject(Plugin plugin) {
+ updateMetaClasses(plugin, true)
+ }
+
+ /**
+ * Updates meta-class definitions for the given plugin by registering
+ * each entry point and its methods as closures. Each generated closure
+ * delegates invocation to the {@link PluginService}.
+ *
+ * @param plugin the Plugin instance whose entry points and methods
+ * are to be exposed dynamically
+ */
+ protected void updateMetaClasses(Plugin plugin, boolean isRemoval) {
+ def pluginMeta = new PluginMeta()
+
+ plugin.entryPoints.values().each { EntryPoint ep ->
+ def epMeta = new EntryPointMeta()
+
+ ep.methods.values().each { Method method ->
+ /**
+ * Dynamically generated method closure for entry point invocation.
+ *
+ * @param args variable-length list of Serializable arguments
+ * @return the result returned by PluginService.call(...)
+ */
+ epMeta.metaClass."${method.name}" = isRemoval ? null : { Serializable... args ->
+ pluginService.call(plugin.identifier, ep.name, method.name, args)
+ }
+ }
+ pluginMeta.metaClass."${ep.name}" = isRemoval ? null : epMeta
+ }
+ PluginHolder.metaClass."${plugin.name}" = isRemoval ? null : pluginMeta
+ }
+}
diff --git a/application-engine/src/main/groovy/com/netgrif/application/engine/plugin/meta/EntryPointMeta.groovy b/application-engine/src/main/groovy/com/netgrif/application/engine/plugin/meta/EntryPointMeta.groovy
new file mode 100644
index 00000000000..72e5e3a3b67
--- /dev/null
+++ b/application-engine/src/main/groovy/com/netgrif/application/engine/plugin/meta/EntryPointMeta.groovy
@@ -0,0 +1,8 @@
+package com.netgrif.application.engine.plugin.meta
+
+/**
+ * Class, that has modified meta class and is injected into
+ * {@link com.netgrif.application.engine.petrinet.domain.dataset.logic.action.ActionDelegate}. No class-attributes needed.
+ * */
+class EntryPointMeta {
+}
diff --git a/application-engine/src/main/groovy/com/netgrif/application/engine/plugin/meta/PluginHolder.groovy b/application-engine/src/main/groovy/com/netgrif/application/engine/plugin/meta/PluginHolder.groovy
new file mode 100644
index 00000000000..2c924869966
--- /dev/null
+++ b/application-engine/src/main/groovy/com/netgrif/application/engine/plugin/meta/PluginHolder.groovy
@@ -0,0 +1,5 @@
+package com.netgrif.application.engine.plugin.meta;
+
+
+class PluginHolder {
+}
diff --git a/application-engine/src/main/groovy/com/netgrif/application/engine/plugin/meta/PluginMeta.groovy b/application-engine/src/main/groovy/com/netgrif/application/engine/plugin/meta/PluginMeta.groovy
new file mode 100644
index 00000000000..6cc368b21eb
--- /dev/null
+++ b/application-engine/src/main/groovy/com/netgrif/application/engine/plugin/meta/PluginMeta.groovy
@@ -0,0 +1,5 @@
+package com.netgrif.application.engine.plugin.meta
+
+
+class PluginMeta {
+}
diff --git a/src/main/groovy/com/netgrif/application/engine/startup/ImportHelper.groovy b/application-engine/src/main/groovy/com/netgrif/application/engine/startup/ImportHelper.groovy
similarity index 75%
rename from src/main/groovy/com/netgrif/application/engine/startup/ImportHelper.groovy
rename to application-engine/src/main/groovy/com/netgrif/application/engine/startup/ImportHelper.groovy
index b7e55c8399e..e059f5b5bb2 100644
--- a/src/main/groovy/com/netgrif/application/engine/startup/ImportHelper.groovy
+++ b/application-engine/src/main/groovy/com/netgrif/application/engine/startup/ImportHelper.groovy
@@ -2,34 +2,35 @@ package com.netgrif.application.engine.startup
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.databind.node.ObjectNode
-import com.netgrif.application.engine.auth.domain.*
-import com.netgrif.application.engine.auth.service.interfaces.IAuthorityService
-import com.netgrif.application.engine.auth.service.interfaces.IUserService
-import com.netgrif.application.engine.orgstructure.groups.interfaces.INextGroupService
-import com.netgrif.application.engine.petrinet.domain.PetriNet
-import com.netgrif.application.engine.petrinet.domain.VersionType
-import com.netgrif.application.engine.petrinet.domain.dataset.Field
+import com.netgrif.application.engine.adapter.spring.petrinet.service.ProcessRoleService
import com.netgrif.application.engine.petrinet.domain.repositories.PetriNetRepository
-import com.netgrif.application.engine.petrinet.domain.roles.ProcessRole
-import com.netgrif.application.engine.petrinet.service.ProcessRoleService
import com.netgrif.application.engine.petrinet.service.interfaces.IPetriNetService
import com.netgrif.application.engine.petrinet.service.interfaces.IUriService
import com.netgrif.application.engine.startup.runner.SuperCreatorRunner
-import com.netgrif.application.engine.workflow.domain.Case
-import com.netgrif.application.engine.workflow.domain.Filter
-import com.netgrif.application.engine.workflow.domain.MergeFilterOperation
-import com.netgrif.application.engine.workflow.domain.eventoutcomes.dataoutcomes.SetDataEventOutcome
-import com.netgrif.application.engine.workflow.domain.eventoutcomes.taskoutcomes.AssignTaskEventOutcome
-import com.netgrif.application.engine.workflow.domain.eventoutcomes.taskoutcomes.CancelTaskEventOutcome
-import com.netgrif.application.engine.workflow.domain.eventoutcomes.taskoutcomes.FinishTaskEventOutcome
import com.netgrif.application.engine.workflow.domain.repositories.CaseRepository
import com.netgrif.application.engine.workflow.service.interfaces.IDataService
import com.netgrif.application.engine.workflow.service.interfaces.ITaskService
+import com.netgrif.application.engine.workflow.service.interfaces.IWorkflowService
+import com.netgrif.application.engine.auth.service.AuthorityService
+import com.netgrif.application.engine.auth.service.GroupService
+import com.netgrif.application.engine.auth.service.UserService
+import com.netgrif.application.engine.objects.auth.domain.Authority
+import com.netgrif.application.engine.objects.auth.domain.IUser
+import com.netgrif.application.engine.objects.auth.domain.LoggedUser
+import com.netgrif.application.engine.objects.auth.domain.User
+import com.netgrif.application.engine.objects.auth.domain.enums.UserState
+import com.netgrif.application.engine.objects.petrinet.domain.PetriNet
+import com.netgrif.application.engine.objects.petrinet.domain.VersionType
+import com.netgrif.application.engine.objects.petrinet.domain.dataset.Field
+import com.netgrif.application.engine.objects.petrinet.domain.roles.ProcessRole
+import com.netgrif.application.engine.objects.workflow.domain.Case
+import com.netgrif.application.engine.objects.workflow.domain.eventoutcomes.dataoutcomes.SetDataEventOutcome
+import com.netgrif.application.engine.objects.workflow.domain.eventoutcomes.taskoutcomes.AssignTaskEventOutcome
+import com.netgrif.application.engine.objects.workflow.domain.eventoutcomes.taskoutcomes.CancelTaskEventOutcome
+import com.netgrif.application.engine.objects.workflow.domain.eventoutcomes.taskoutcomes.FinishTaskEventOutcome
//import com.netgrif.application.engine.workflow.service.interfaces.IFilterService
-import com.netgrif.application.engine.workflow.service.interfaces.IWorkflowService
-import com.netgrif.application.engine.workflow.web.requestbodies.CreateFilterBody
import com.netgrif.application.engine.workflow.web.responsebodies.TaskReference
import org.slf4j.Logger
import org.slf4j.LoggerFactory
@@ -55,13 +56,13 @@ class ImportHelper {
private PetriNetRepository petriNetRepository
@Autowired
- private IUserService userService
+ private UserService userService
@Autowired
private CaseRepository caseRepository
@Autowired
- private IAuthorityService authorityService
+ private AuthorityService authorityService
@Autowired
private ITaskService taskService
@@ -85,7 +86,7 @@ class ImportHelper {
private IWorkflowService workflowService
@Autowired
- private INextGroupService groupService
+ private GroupService groupService
@Autowired
private ProcessRoleService processRoleService
@@ -112,18 +113,18 @@ class ImportHelper {
return authorityService.getOrCreate(name)
}
- Optional createNet(String fileName, String release, LoggedUser author = userService.getSystem().transformToLoggedUser(), String uriNodeId = uriService.getDefault().stringId) {
+ Optional createNet(String fileName, String release, LoggedUser author = userService.transformToLoggedUser(userService.getSystem()), String uriNodeId = uriService.getDefault().stringId) {
return createNet(fileName, VersionType.valueOf(release.trim().toUpperCase()), author, uriNodeId)
}
- Optional createNet(String fileName, VersionType release = VersionType.MAJOR, LoggedUser author = userService.getSystem().transformToLoggedUser(), String uriNodeId = uriService.getDefault().stringId) {
+ Optional createNet(String fileName, VersionType release = VersionType.MAJOR, LoggedUser author = userService.transformToLoggedUser(userService.getSystem()), String uriNodeId = uriService.getDefault().stringId) {
InputStream netStream = new ClassPathResource("petriNets/$fileName" as String).inputStream
PetriNet petriNet = petriNetService.importPetriNet(netStream, release, author, uriNodeId).getNet()
log.info("Imported '${petriNet?.title?.defaultValue}' ['${petriNet?.identifier}', ${petriNet?.stringId}]")
return Optional.of(petriNet)
}
- Optional upsertNet(String filename, String identifier, VersionType release = VersionType.MAJOR, LoggedUser author = userService.getSystem().transformToLoggedUser()) {
+ Optional upsertNet(String filename, String identifier, VersionType release = VersionType.MAJOR, LoggedUser author = userService.transformToLoggedUser(userService.getSystem())) {
PetriNet petriNet = petriNetService.getNewestVersionByIdentifier(identifier)
if (!petriNet) {
return createNet(filename, release, author)
@@ -175,8 +176,8 @@ class ImportHelper {
authorities.each { user.addAuthority(it) }
roles.each { user.addProcessRole(it) }
user.state = UserState.ACTIVE
- user = userService.saveNew(user)
- log.info("User $user.name $user.surname created")
+ user = (User) userService.createUser(user, null)
+ log.info("User $user.firstName $user.lastName created")
return user
}
@@ -185,25 +186,25 @@ class ImportHelper {
}
Case createCase(String title, PetriNet net) {
- return createCase(title, net, userService.getSystem().transformToLoggedUser())
+ return createCase(title, net, userService.transformToLoggedUser(userService.getSystem()))
}
Case createCaseAsSuper(String title, PetriNet net) {
- return createCase(title, net, superCreator.loggedSuper ?: userService.getSystem().transformToLoggedUser())
+ return createCase(title, net, superCreator.getLoggedSuper() ?: userService.transformToLoggedUser(userService.getSystem()))
}
// TODO remove deprecated classes and methods
- @Deprecated
- boolean createCaseFilter(String title, String query, MergeFilterOperation operation, LoggedUser user) {
- return filterService.saveFilter(new CreateFilterBody(title, Filter.VISIBILITY_PUBLIC, "This filter was created automatically for testing purpose only.", Filter.TYPE_TASK, query), operation, user)
- }
+// @Deprecated
+// boolean createCaseFilter(String title, String query, MergeFilterOperation operation, LoggedUser user) {
+// return filterService.saveFilter(new CreateFilterBody(title, Filter.VISIBILITY_PUBLIC, "This filter was created automatically for testing purpose only.", Filter.TYPE_TASK, query), operation, user)
+// }
AssignTaskEventOutcome assignTask(String taskTitle, String caseId, LoggedUser author) {
return taskService.assignTask(author, getTaskId(taskTitle, caseId))
}
AssignTaskEventOutcome assignTaskToSuper(String taskTitle, String caseId) {
- return assignTask(taskTitle, caseId, superCreator.loggedSuper ?: userService.getSystem().transformToLoggedUser())
+ return assignTask(taskTitle, caseId, superCreator.loggedSuper ?: userService.transformToLoggedUser(userService.getSystem()))
}
FinishTaskEventOutcome finishTask(String taskTitle, String caseId, LoggedUser author) {
@@ -211,7 +212,7 @@ class ImportHelper {
}
FinishTaskEventOutcome finishTaskAsSuper(String taskTitle, String caseId) {
- return finishTask(taskTitle, caseId, superCreator.loggedSuper ?: userService.getSystem().transformToLoggedUser())
+ return finishTask(taskTitle, caseId, superCreator.loggedSuper ?: userService.transformToLoggedUser(userService.getSystem()))
}
CancelTaskEventOutcome cancelTask(String taskTitle, String caseId, LoggedUser user) {
@@ -219,7 +220,7 @@ class ImportHelper {
}
CancelTaskEventOutcome cancelTaskAsSuper(String taskTitle, String caseId) {
- return cancelTask(taskTitle, caseId, superCreator.loggedSuper ?: userService.getSystem().transformToLoggedUser())
+ return cancelTask(taskTitle, caseId, superCreator.loggedSuper ?: userService.transformToLoggedUser(userService.getSystem()))
}
String getTaskId(String taskTitle, String caseId) {
diff --git a/application-engine/src/main/groovy/com/netgrif/application/engine/startup/PluginRunner.groovy b/application-engine/src/main/groovy/com/netgrif/application/engine/startup/PluginRunner.groovy
new file mode 100644
index 00000000000..3cb6f2e6263
--- /dev/null
+++ b/application-engine/src/main/groovy/com/netgrif/application/engine/startup/PluginRunner.groovy
@@ -0,0 +1,57 @@
+package com.netgrif.application.engine.startup
+//package com.netgrif.application.engine.startup
+//
+//import com.netgrif.application.engine.integration.plugin.injector.PluginInjector
+//import com.netgrif.application.engine.integration.plugins.service.IPluginService
+//import com.netgrif.application.engine.workflow.domain.Case
+//import groovy.util.logging.Slf4j
+//import org.springframework.beans.factory.annotation.Autowired
+//import org.springframework.stereotype.Component
+//
+//import static com.netgrif.application.engine.integration.plugins.utils.PluginUtils.getPluginIdentifier
+//import static com.netgrif.application.engine.integration.plugins.utils.PluginUtils.isPluginActive
+//
+//@Slf4j
+//@Component
+//class PluginRunner extends AbstractOrderedCommandLineRunner {
+//
+// @Autowired
+// private ImportHelper helper
+//
+// @Autowired
+// private IPluginService pluginService
+//
+// @Autowired
+// private PluginInjector pluginInjector
+//
+// private static final String PLUGIN_FILE_NAME = "engine-processes/plugin/plugin.xml"
+// private static final String PLUGIN_PETRI_NET_IDENTIFIER = "plugin"
+//
+// private static final String ENTRY_POINT_FILE_NAME = "engine-processes/plugin/entry_point.xml"
+// private static final String ENTRY_POINT_NET_IDENTIFIER = "entry_point"
+//
+// private static final String METHOD_FILE_NAME = "engine-processes/plugin/method.xml"
+// private static final String METHOD_NET_IDENTIFIER = "method"
+//
+// @Override
+// void run(String... args) throws Exception {
+// importPluginNets()
+//
+// List plugins = pluginService.findAll()
+//
+// log.info("Re-injecting ${plugins.size()} plugins from database into memory.")
+// plugins.each { plugin ->
+// if (isPluginActive(plugin)) {
+// pluginInjector.inject(plugin)
+// } else {
+// log.warn("Plugin with identifier [{}] is disabled and will not be injected.", getPluginIdentifier(plugin))
+// }
+// }
+// }
+//
+// private void importPluginNets() {
+// helper.upsertNet(PLUGIN_FILE_NAME, PLUGIN_PETRI_NET_IDENTIFIER)
+// helper.upsertNet(ENTRY_POINT_FILE_NAME, ENTRY_POINT_NET_IDENTIFIER)
+// helper.upsertNet(METHOD_FILE_NAME, METHOD_NET_IDENTIFIER)
+// }
+//}
diff --git a/application-engine/src/main/groovy/com/netgrif/application/engine/startup/PostalCodeImporter.groovy b/application-engine/src/main/groovy/com/netgrif/application/engine/startup/PostalCodeImporter.groovy
new file mode 100644
index 00000000000..75daa43f594
--- /dev/null
+++ b/application-engine/src/main/groovy/com/netgrif/application/engine/startup/PostalCodeImporter.groovy
@@ -0,0 +1 @@
+package com.netgrif.application.engine.startup
diff --git a/src/main/groovy/com/netgrif/application/engine/validation/domain/ValidationDataInput.groovy b/application-engine/src/main/groovy/com/netgrif/application/engine/validation/domain/ValidationDataInput.groovy
similarity index 88%
rename from src/main/groovy/com/netgrif/application/engine/validation/domain/ValidationDataInput.groovy
rename to application-engine/src/main/groovy/com/netgrif/application/engine/validation/domain/ValidationDataInput.groovy
index 18180167a55..366b66bdaec 100644
--- a/src/main/groovy/com/netgrif/application/engine/validation/domain/ValidationDataInput.groovy
+++ b/application-engine/src/main/groovy/com/netgrif/application/engine/validation/domain/ValidationDataInput.groovy
@@ -1,7 +1,7 @@
package com.netgrif.application.engine.validation.domain
-import com.netgrif.application.engine.petrinet.domain.I18nString
-import com.netgrif.application.engine.workflow.domain.DataField
+import com.netgrif.application.engine.objects.petrinet.domain.I18nString
+import com.netgrif.application.engine.objects.workflow.domain.DataField
public class ValidationDataInput {
diff --git a/src/main/groovy/com/netgrif/application/engine/validation/models/AbstractFieldValidation.groovy b/application-engine/src/main/groovy/com/netgrif/application/engine/validation/models/AbstractFieldValidation.groovy
similarity index 100%
rename from src/main/groovy/com/netgrif/application/engine/validation/models/AbstractFieldValidation.groovy
rename to application-engine/src/main/groovy/com/netgrif/application/engine/validation/models/AbstractFieldValidation.groovy
diff --git a/src/main/groovy/com/netgrif/application/engine/validation/models/BooleanFieldValidation.groovy b/application-engine/src/main/groovy/com/netgrif/application/engine/validation/models/BooleanFieldValidation.groovy
similarity index 100%
rename from src/main/groovy/com/netgrif/application/engine/validation/models/BooleanFieldValidation.groovy
rename to application-engine/src/main/groovy/com/netgrif/application/engine/validation/models/BooleanFieldValidation.groovy
diff --git a/src/main/groovy/com/netgrif/application/engine/validation/models/DateFieldValidation.groovy b/application-engine/src/main/groovy/com/netgrif/application/engine/validation/models/DateFieldValidation.groovy
similarity index 100%
rename from src/main/groovy/com/netgrif/application/engine/validation/models/DateFieldValidation.groovy
rename to application-engine/src/main/groovy/com/netgrif/application/engine/validation/models/DateFieldValidation.groovy
diff --git a/src/main/groovy/com/netgrif/application/engine/validation/models/DateTimeFieldValidation.groovy b/application-engine/src/main/groovy/com/netgrif/application/engine/validation/models/DateTimeFieldValidation.groovy
similarity index 100%
rename from src/main/groovy/com/netgrif/application/engine/validation/models/DateTimeFieldValidation.groovy
rename to application-engine/src/main/groovy/com/netgrif/application/engine/validation/models/DateTimeFieldValidation.groovy
diff --git a/src/main/groovy/com/netgrif/application/engine/validation/models/EnumerationFieldValidation.groovy b/application-engine/src/main/groovy/com/netgrif/application/engine/validation/models/EnumerationFieldValidation.groovy
similarity index 100%
rename from src/main/groovy/com/netgrif/application/engine/validation/models/EnumerationFieldValidation.groovy
rename to application-engine/src/main/groovy/com/netgrif/application/engine/validation/models/EnumerationFieldValidation.groovy
diff --git a/src/main/groovy/com/netgrif/application/engine/validation/models/I18nFieldValidation.groovy b/application-engine/src/main/groovy/com/netgrif/application/engine/validation/models/I18nFieldValidation.groovy
similarity index 100%
rename from src/main/groovy/com/netgrif/application/engine/validation/models/I18nFieldValidation.groovy
rename to application-engine/src/main/groovy/com/netgrif/application/engine/validation/models/I18nFieldValidation.groovy
diff --git a/src/main/groovy/com/netgrif/application/engine/validation/models/NumberFieldValidation.groovy b/application-engine/src/main/groovy/com/netgrif/application/engine/validation/models/NumberFieldValidation.groovy
similarity index 100%
rename from src/main/groovy/com/netgrif/application/engine/validation/models/NumberFieldValidation.groovy
rename to application-engine/src/main/groovy/com/netgrif/application/engine/validation/models/NumberFieldValidation.groovy
diff --git a/src/main/groovy/com/netgrif/application/engine/validation/models/TextFieldValidation.groovy b/application-engine/src/main/groovy/com/netgrif/application/engine/validation/models/TextFieldValidation.groovy
similarity index 100%
rename from src/main/groovy/com/netgrif/application/engine/validation/models/TextFieldValidation.groovy
rename to application-engine/src/main/groovy/com/netgrif/application/engine/validation/models/TextFieldValidation.groovy
diff --git a/src/main/groovy/com/netgrif/application/engine/validation/service/ValidationService.groovy b/application-engine/src/main/groovy/com/netgrif/application/engine/validation/service/ValidationService.groovy
similarity index 93%
rename from src/main/groovy/com/netgrif/application/engine/validation/service/ValidationService.groovy
rename to application-engine/src/main/groovy/com/netgrif/application/engine/validation/service/ValidationService.groovy
index d15959dd44b..a734f8e6fb0 100644
--- a/src/main/groovy/com/netgrif/application/engine/validation/service/ValidationService.groovy
+++ b/application-engine/src/main/groovy/com/netgrif/application/engine/validation/service/ValidationService.groovy
@@ -1,11 +1,11 @@
package com.netgrif.application.engine.validation.service
-import com.netgrif.application.engine.petrinet.domain.I18nString
-import com.netgrif.application.engine.petrinet.domain.dataset.*
+import com.netgrif.application.engine.objects.petrinet.domain.I18nString
+import com.netgrif.application.engine.objects.petrinet.domain.dataset.*
import com.netgrif.application.engine.validation.service.interfaces.IValidationService
import com.netgrif.application.engine.validation.domain.ValidationDataInput
import com.netgrif.application.engine.validation.models.*
-import com.netgrif.application.engine.workflow.domain.DataField
+import com.netgrif.application.engine.objects.workflow.domain.DataField
import groovy.util.logging.Slf4j
import org.springframework.context.i18n.LocaleContextHolder
import org.springframework.stereotype.Service
diff --git a/application-engine/src/main/groovy/com/netgrif/application/engine/validation/service/interfaces/IValidationService.groovy b/application-engine/src/main/groovy/com/netgrif/application/engine/validation/service/interfaces/IValidationService.groovy
new file mode 100644
index 00000000000..36296b67dc6
--- /dev/null
+++ b/application-engine/src/main/groovy/com/netgrif/application/engine/validation/service/interfaces/IValidationService.groovy
@@ -0,0 +1,11 @@
+package com.netgrif.application.engine.validation.service.interfaces
+
+import com.netgrif.application.engine.objects.petrinet.domain.dataset.Field
+import com.netgrif.application.engine.objects.workflow.domain.DataField
+
+
+interface IValidationService {
+
+ public void valid(Field field, DataField dataField);
+
+}
diff --git a/src/main/java/com/netgrif/application/engine/ApplicationEngine.java b/application-engine/src/main/java/com/netgrif/application/engine/ApplicationEngine.java
similarity index 93%
rename from src/main/java/com/netgrif/application/engine/ApplicationEngine.java
rename to application-engine/src/main/java/com/netgrif/application/engine/ApplicationEngine.java
index eb667adb4e5..190129848da 100644
--- a/src/main/java/com/netgrif/application/engine/ApplicationEngine.java
+++ b/application-engine/src/main/java/com/netgrif/application/engine/ApplicationEngine.java
@@ -16,6 +16,7 @@
import org.springframework.core.convert.converter.Converter;
import org.springframework.data.mongodb.config.EnableMongoAuditing;
import org.springframework.data.mongodb.core.convert.MongoCustomConversions;
+import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;
import org.springframework.hateoas.config.EnableHypermediaSupport;
import org.springframework.hateoas.server.LinkRelationProvider;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
@@ -23,17 +24,18 @@
import java.util.ArrayList;
import java.util.List;
+@Slf4j
+@Aspect
@EnableCaching
-@EnableHypermediaSupport(type = EnableHypermediaSupport.HypermediaType.HAL)
+@EnableMongoAuditing
@EnableMethodSecurity
@EnableAspectJAutoProxy
+@ConfigurationPropertiesScan
+@EnableMongoRepositories("com.netgrif")
@SpringBootApplication(
exclude = {DataSourceAutoConfiguration.class},
- scanBasePackages = {"com.netgrif.application.engine"})
-@EnableMongoAuditing
-@ConfigurationPropertiesScan
-@Aspect
-@Slf4j
+ scanBasePackages = {"com.netgrif"})
+@EnableHypermediaSupport(type = EnableHypermediaSupport.HypermediaType.HAL)
public class ApplicationEngine {
@Bean
diff --git a/application-engine/src/main/java/com/netgrif/application/engine/PluginServiceImpl.java b/application-engine/src/main/java/com/netgrif/application/engine/PluginServiceImpl.java
new file mode 100644
index 00000000000..d739d124a4f
--- /dev/null
+++ b/application-engine/src/main/java/com/netgrif/application/engine/PluginServiceImpl.java
@@ -0,0 +1,81 @@
+package com.netgrif.application.engine;
+
+import com.netgrif.application.engine.adapter.spring.plugin.service.PluginService;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.context.ApplicationContext;
+import org.springframework.stereotype.Service;
+
+import java.io.Serializable;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.List;
+
+@Slf4j
+@Service
+@RequiredArgsConstructor
+public class PluginServiceImpl implements PluginService {
+
+ private final ApplicationContext applicationContext;
+
+ @Override
+ public Object call(String pluginId, String entryPoint, String method, Serializable... args) throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {
+ log.info("Executing entry point [{}] with method [{}]...", entryPoint, method);
+ Class>[] paramTypesFromRequest = Arrays.stream(args).map(Object::getClass).toArray(Class[]::new);
+ Object bean = applicationContext.getBean(entryPoint);
+ Method methodToInvoke = findMethod(bean, method, paramTypesFromRequest);
+ return methodToInvoke.invoke(bean, Arrays.stream(args).toArray());
+ }
+
+ private Method findMethod(Object bean, String methodToExecute, Class>[] requestParamTypes)
+ throws NoSuchMethodException, IllegalArgumentException {
+ try {
+ return bean.getClass().getMethod(methodToExecute, requestParamTypes);
+ } catch (NoSuchMethodException e) {
+ return findMethodWithSuperClassParams(bean, methodToExecute, requestParamTypes, e);
+ }
+ }
+
+ private Method findMethodWithSuperClassParams(Object bean, String methodToExecute, Class>[] requestParamTypes,
+ NoSuchMethodException caughtException)
+ throws NoSuchMethodException, IllegalArgumentException {
+ Class> cls = bean.getClass();
+ Method[] methods = cls.getMethods();
+ Method methodToInvoke = null;
+ outerLoop: for (Method method : methods) {
+ if (!methodToExecute.equals(method.getName())) {
+ continue;
+ }
+
+ Class>[] paramTypes = method.getParameterTypes();
+ int requestParamsLen = requestParamTypes.length;
+ int paramsLen = paramTypes.length;
+
+ if (requestParamsLen == 0 && paramsLen == 0) {
+ methodToInvoke = method;
+ break;
+ } else if (paramsLen == 0 || paramsLen != requestParamsLen) {
+ continue;
+ }
+
+ for (int i = 0; i < requestParamTypes.length; ++i) {
+ if (!paramTypes[i].isAssignableFrom(requestParamTypes[i])) {
+ continue outerLoop;
+ }
+ }
+
+ if (methodToInvoke != null) {
+ throw new IllegalArgumentException(String.format("Method %s is ambiguous for the param types %s",
+ methodToExecute, Arrays.toString(requestParamTypes)));
+ }
+ methodToInvoke = method;
+ }
+
+ if (methodToInvoke == null) {
+ throw caughtException;
+ } else {
+ return methodToInvoke;
+ }
+ }
+}
diff --git a/application-engine/src/main/java/com/netgrif/application/engine/auth/domain/AbstractUser.java b/application-engine/src/main/java/com/netgrif/application/engine/auth/domain/AbstractUser.java
new file mode 100644
index 00000000000..2efb6444807
--- /dev/null
+++ b/application-engine/src/main/java/com/netgrif/application/engine/auth/domain/AbstractUser.java
@@ -0,0 +1,91 @@
+//package com.netgrif.application.engine.objects.auth.domain.Authority;;
+//
+//import com.netgrif.application.engine.objects.petrinet.domain.roles.ProcessRole;
+//import lombok.Getter;
+//import lombok.Setter;
+//import org.springframework.data.annotation.Transient;
+//
+//import javax.validation.constraints.NotNull;
+//import java.io.Serializable;
+//import java.util.HashSet;
+//import java.util.Set;
+//
+//public abstract class AbstractUser implements IUser, Serializable {
+//
+// private static final long serialVersionUID = 341922197277508726L;
+//
+// @NotNull
+// @Getter
+// @Setter
+// protected UserState state;
+//
+// @Getter
+// @Setter
+// protected Set authorities;
+//
+// @Getter
+// @Setter
+// protected Set processRoles;
+//
+// @Getter
+// @Setter
+// protected Set nextGroups;
+//
+// @Setter
+// @Getter
+// @Transient
+// protected IUser impersonated;
+//
+// public AbstractUser() {
+// authorities = new HashSet<>();
+// nextGroups = new HashSet<>();
+// processRoles = new HashSet<>();
+// }
+//
+// public void addAuthority(Authority authority) {
+// if (authorities.stream().anyMatch(it -> it.get_id().equals(authority.get_id())))
+// return;
+// authorities.add(authority);
+// }
+//
+// public void addProcessRole(ProcessRole role) {
+// if (processRoles.stream().anyMatch(it -> it.getStringId().equals(role.getStringId())))
+// return;
+// processRoles.add(role);
+// }
+//
+// public void removeProcessRole(ProcessRole role) {
+// processRoles.remove(role);
+// }
+//
+// public void addGroup(String groupId) {
+// this.nextGroups.add(groupId);
+// }
+//
+// public void removeGroup(String groupId) {
+// this.nextGroups.remove(groupId);
+// }
+//
+// public boolean isActive() {
+// return UserState.ACTIVE.equals(state) || UserState.BLOCKED.equals(state);
+// }
+//
+// public Author transformToAuthor() {
+// Author author = new Author();
+// author.setId(this.getStringId());
+// author.setEmail(this.getEmail());
+// author.setFullName(this.getFullName());
+//
+// return author;
+// }
+//
+// @Override
+// public boolean isImpersonating() {
+// return this.impersonated != null;
+// }
+//
+// @Override
+// public IUser getSelfOrImpersonated() {
+// return isImpersonating() ? this.impersonated : this;
+// }
+//}
diff --git a/application-engine/src/main/java/com/netgrif/application/engine/auth/domain/AnonymousUser.java b/application-engine/src/main/java/com/netgrif/application/engine/auth/domain/AnonymousUser.java
new file mode 100644
index 00000000000..d2ec19a3c47
--- /dev/null
+++ b/application-engine/src/main/java/com/netgrif/application/engine/auth/domain/AnonymousUser.java
@@ -0,0 +1,35 @@
+//package com.netgrif.application.engine.objects.auth.domain.Authority;;
+//
+//import lombok.Data;
+//import org.bson.types.ObjectId;
+//import org.springframework.data.mongodb.core.mapping.Document;
+//
+//@Document
+//@Data
+//public class AnonymousUser extends User {
+//
+// public AnonymousUser() {
+// super();
+// }
+//
+// public AnonymousUser(ObjectId id) {
+// super(id);
+// }
+//
+// public AnonymousUser(String email, String password, String name, String surname) {
+// super(email, password, name, surname);
+// }
+//
+// @Override
+// public LoggedUser transformToLoggedUser() {
+// LoggedUser loggedUser = new LoggedUser(this.get_id().toString(), this.getEmail(), "n/a", this.getAuthorities());
+// loggedUser.setFullName(this.getFullName());
+// loggedUser.setAnonymous(true);
+// if (!this.getProcessRoles().isEmpty())
+// loggedUser.parseProcessRoles(this.getProcessRoles());
+// if (!this.getNextGroups().isEmpty())
+// loggedUser.setGroups(this.getNextGroups());
+//
+// return loggedUser;
+// }
+//}
diff --git a/application-engine/src/main/java/com/netgrif/application/engine/auth/domain/Author.java b/application-engine/src/main/java/com/netgrif/application/engine/auth/domain/Author.java
new file mode 100644
index 00000000000..3fb20174ec3
--- /dev/null
+++ b/application-engine/src/main/java/com/netgrif/application/engine/auth/domain/Author.java
@@ -0,0 +1,46 @@
+//package com.netgrif.application.engine.auth.domain;
+//
+//import lombok.Data;
+//
+//import java.io.Serializable;
+//
+//@Data
+//public class Author implements Serializable {
+//
+// private static final long serialVersionUID = 5167778985918909834L;
+//
+// private String id;
+// private String email;
+// private String fullName;
+//
+// public Author() {
+// }
+//
+// public Author(String id, String email, String fullName) {
+// this.id = id;
+// this.email = email;
+// this.fullName = fullName;
+// }
+//
+// public static Author createAnonymizedAuthor() {
+// Author author = new Author();
+// author.setId("");
+// author.setEmail("***");
+// author.setFullName("***");
+// return author;
+// }
+//
+// @Override
+// public String toString() {
+// return "Author{" +
+// "id=" + id +
+// ", email='" + email + '\'' +
+// ", fullName='" + fullName + '\'' +
+// '}';
+// }
+//
+// @Override
+// public Author clone() {
+// return new Author(this.id, this.email, this.fullName);
+// }
+//}
diff --git a/application-engine/src/main/java/com/netgrif/application/engine/auth/domain/Authority.java b/application-engine/src/main/java/com/netgrif/application/engine/auth/domain/Authority.java
new file mode 100644
index 00000000000..998ab158681
--- /dev/null
+++ b/application-engine/src/main/java/com/netgrif/application/engine/auth/domain/Authority.java
@@ -0,0 +1,101 @@
+//package com.netgrif.application.engine.objects.auth.domain.Authority;;
+//
+//import com.fasterxml.jackson.annotation.JsonIgnore;
+//import lombok.Getter;
+//import lombok.Setter;
+//import org.bson.types.ObjectId;
+//import org.springframework.data.annotation.Id;
+//import org.springframework.data.mongodb.core.mapping.Document;
+//import org.springframework.security.core.GrantedAuthority;
+//
+//import javax.validation.constraints.NotNull;
+//import java.util.HashSet;
+//import java.util.Set;
+//
+//@Document
+//public class Authority implements GrantedAuthority {
+//
+// public static final long serialVersionUID = 2839744057647464485L;
+//
+// public static final String PERMISSION = "PERM_";
+// public static final String ROLE = "ROLE_";
+//
+// public static final String admin = ROLE + "ADMIN";
+// public static final String systemAdmin = ROLE + "SYSTEMADMIN";
+// public static final String user = ROLE + "USER";
+// public static final String anonymous = ROLE + "ANONYMOUS";
+//
+//
+// @Id
+// @Getter
+// private ObjectId _id;
+//
+// @NotNull
+// @JsonIgnore
+// @Getter
+// @Setter
+// private String name;
+//
+// @JsonIgnore
+// @Getter
+// @Setter
+// private Set users;
+//
+// public Authority() {
+// }
+//
+// public Authority(String name) {
+// this.name = name;
+// }
+//
+// public static Authority createRole(String name) {
+// return new Authority(ROLE + name);
+// }
+//
+// public static Authority createPermission(String name) {
+// return new Authority(PERMISSION + name);
+// }
+//
+// public void addUser(IUser user) {
+// if (users == null) {
+// users = new HashSet<>();
+// }
+// users.add(user.getStringId());
+// }
+//
+// public String getStringId() {
+// return _id.toString();
+// }
+//
+// @Override
+// public String getAuthority() {
+// return this.name;
+// }
+//
+// public void setAuthority(String authority) {
+// this.name = authority;
+// }
+//
+// @Override
+// public boolean equals(Object o) {
+// if (this == o) return true;
+// if (o == null || getClass() != o.getClass()) return false;
+//
+// Authority authority = (Authority) o;
+//
+// return name.equals(authority.name);
+// }
+//
+// @Override
+// public String toString() {
+// return "Authority{" +
+// "id=" + _id +
+// ", name='" + name + '\'' +
+// '}';
+// }
+//
+// @Override
+// public int hashCode() {
+// return name.hashCode();
+// }
+//}
diff --git a/application-engine/src/main/java/com/netgrif/application/engine/auth/domain/IUser.java b/application-engine/src/main/java/com/netgrif/application/engine/auth/domain/IUser.java
new file mode 100644
index 00000000000..a7572c17861
--- /dev/null
+++ b/application-engine/src/main/java/com/netgrif/application/engine/auth/domain/IUser.java
@@ -0,0 +1,69 @@
+//package com.netgrif.application.engine.objects.auth.domain.Authority;;
+//
+//import com.netgrif.application.engine.objects.petrinet.domain.roles.ProcessRole;
+//
+//import java.util.Set;
+//
+//public interface IUser {
+//
+// String getStringId();
+//
+// String getEmail();
+//
+// void setEmail(String email);
+//
+// String getName();
+//
+// void setName(String name);
+//
+// String getSurname();
+//
+// void setSurname(String surname);
+//
+// String getFullName();
+//
+// String getAvatar();
+//
+// String getTelNumber();
+//
+// UserState getState();
+//
+// void setState(UserState state);
+//
+// Set getAuthorities();
+//
+// void setAuthorities(Set authorities);
+//
+// Set getProcessRoles();
+//
+// void setProcessRoles(Set processRoles);
+//
+// Set getNextGroups();
+//
+// void setNextGroups(Set nextGroups);
+//
+// void addGroup(String groupId);
+//
+// void removeGroup(String groupId);
+//
+// void addAuthority(Authority authority);
+//
+// void addProcessRole(ProcessRole role);
+//
+// void removeProcessRole(ProcessRole role);
+//
+// LoggedUser transformToLoggedUser();
+//
+// Author transformToAuthor();
+//
+// boolean isActive();
+//
+// boolean isImpersonating();
+//
+// IUser getSelfOrImpersonated();
+//
+// IUser getImpersonated();
+//
+// void setImpersonated(IUser user);
+//
+//}
diff --git a/application-engine/src/main/java/com/netgrif/application/engine/auth/domain/LoggedUser.java b/application-engine/src/main/java/com/netgrif/application/engine/auth/domain/LoggedUser.java
new file mode 100644
index 00000000000..b65ad9d7f64
--- /dev/null
+++ b/application-engine/src/main/java/com/netgrif/application/engine/auth/domain/LoggedUser.java
@@ -0,0 +1,137 @@
+//package com.netgrif.application.engine.objects.auth.domain.Authority;;
+//
+//import com.fasterxml.jackson.annotation.JsonIgnore;
+//import com.fasterxml.jackson.annotation.JsonInclude;
+//import com.netgrif.application.engine.objects.petrinet.domain.roles.ProcessRole;
+//import lombok.Getter;
+//import lombok.Setter;
+//import org.bson.types.ObjectId;
+//import org.springframework.security.core.GrantedAuthority;
+//
+//import java.util.Collection;
+//import java.util.HashSet;
+//import java.util.Set;
+//import java.util.stream.Collectors;
+//
+//@JsonInclude(JsonInclude.Include.NON_NULL)
+//public class LoggedUser extends org.springframework.security.core.userdetails.User {
+//
+// public static final long serialVersionUID = 3031325636490953409L;
+//
+// @Getter
+// @Setter
+// protected String id;
+//
+// @Getter
+// @Setter
+// protected String fullName;
+//
+// @Getter
+// @Setter
+// protected Set groups;
+//
+// @Getter
+// @Setter
+// protected Set processRoles;
+//
+// @Getter
+// @Setter
+// protected boolean anonymous;
+//
+// @Getter
+// private LoggedUser impersonated;
+//
+// public LoggedUser(String id, String username, String password, Collection extends GrantedAuthority> authorities) {
+// super(username, password, authorities);
+// this.id = id;
+// this.processRoles = new HashSet<>();
+// this.groups = new HashSet<>();
+// }
+//
+// public void parseProcessRoles(Set processRoles) {
+// processRoles.forEach(role -> this.processRoles.add(role.getStringId()));
+// }
+//
+// public boolean isAdmin() {
+// return getAuthorities().contains(new Authority(Authority.admin));
+// }
+//
+// public String getEmail() {
+// return getUsername();
+// }
+//
+// public IUser transformToUser() {
+// User user = new User(new ObjectId(this.id));
+// user.setEmail(getUsername());
+// String[] names = this.fullName.split(" ");
+// user.setName(names[0]);
+// user.setSurname(names[1]);
+// user.setPassword(getPassword());
+// user.setState(UserState.ACTIVE);
+// user.setAuthorities(getAuthorities().stream().map(a -> ((Authority) a)).collect(Collectors.toSet()));
+// user.setNextGroups(groups.stream().map(String::new).collect(Collectors.toSet()));
+// user.setProcessRoles(processRoles.stream().map(roleId -> {
+// ProcessRole role = new ProcessRole();
+// role.set_id(roleId);
+// return role;
+// }).collect(Collectors.toSet()));
+// if (this.isImpersonating()) {
+// user.setImpersonated(this.getImpersonated().transformToUser());
+// }
+// return user;
+// }
+//
+// public AnonymousUser transformToAnonymousUser() {
+// AnonymousUser anonym = new AnonymousUser(new ObjectId(this.id));
+// anonym.setEmail(getUsername());
+// anonym.setName("Anonymous");
+// anonym.setSurname("User");
+// anonym.setPassword("n/a");
+// anonym.setState(UserState.ACTIVE);
+// anonym.setAuthorities(getAuthorities().stream().map(a -> ((Authority) a)).collect(Collectors.toSet()));
+// anonym.setNextGroups(groups.stream().map(String::new).collect(Collectors.toSet()));
+// anonym.setProcessRoles(processRoles.stream().map(roleId -> {
+// ProcessRole role = new ProcessRole();
+// role.set_id(roleId);
+// return role;
+// }).collect(Collectors.toSet()));
+// return anonym;
+// }
+//
+// public void impersonate(LoggedUser toImpersonate) {
+// this.impersonated = toImpersonate;
+// }
+//
+// public void clearImpersonated() {
+// this.impersonated = null;
+// }
+//
+// public boolean isImpersonating() {
+// return this.impersonated != null;
+// }
+//
+// @JsonIgnore
+// public LoggedUser getSelfOrImpersonated() {
+// return this.isImpersonating() ? this.impersonated : this;
+// }
+//
+// @Override
+// public String toString() {
+// return "LoggedUser{" +
+// "id=" + id +
+// ", fullName='" + fullName + '\'' +
+// ", groups=" + groups +
+// ", processRoles=" + processRoles +
+// ", impersonated=" + impersonated +
+// '}';
+// }
+//
+// public Author transformToAuthor() {
+// Author author = new Author();
+// author.setId(this.id);
+// author.setEmail(getUsername());
+// author.setFullName(this.fullName);
+//
+// return author;
+// }
+//}
diff --git a/application-engine/src/main/java/com/netgrif/application/engine/auth/domain/RegisteredUser.java b/application-engine/src/main/java/com/netgrif/application/engine/auth/domain/RegisteredUser.java
new file mode 100644
index 00000000000..2811b54ca7c
--- /dev/null
+++ b/application-engine/src/main/java/com/netgrif/application/engine/auth/domain/RegisteredUser.java
@@ -0,0 +1,16 @@
+//package com.netgrif.application.engine.auth.domain;
+//
+//import java.time.LocalDateTime;
+//
+//public interface RegisteredUser extends IUser {
+//
+// String getToken();
+//
+// void setToken(String token);
+//
+// String getPassword();
+//
+// void setPassword(String password);
+//
+// void setExpirationDate(LocalDateTime expirationDate);
+//}
diff --git a/application-engine/src/main/java/com/netgrif/application/engine/auth/domain/User.java b/application-engine/src/main/java/com/netgrif/application/engine/auth/domain/User.java
new file mode 100644
index 00000000000..82f4b0949cb
--- /dev/null
+++ b/application-engine/src/main/java/com/netgrif/application/engine/auth/domain/User.java
@@ -0,0 +1,145 @@
+//package com.netgrif.application.engine.objects.auth.domain.Authority;;
+//
+//import com.fasterxml.jackson.annotation.JsonIgnore;
+//import com.fasterxml.jackson.databind.node.ArrayNode;
+//import com.fasterxml.jackson.databind.node.ObjectNode;
+//import com.netgrif.application.engine.objects.petrinet.domain.roles.ProcessRole;
+//import lombok.Getter;
+//import lombok.Setter;
+//import org.bson.types.ObjectId;
+//import org.springframework.data.annotation.Id;
+//import org.springframework.data.mongodb.core.index.Indexed;
+//import org.springframework.data.mongodb.core.mapping.Document;
+//
+//import javax.validation.constraints.NotNull;
+//import java.time.LocalDateTime;
+//import java.util.HashSet;
+//
+//@Document
+//public class User extends AbstractUser implements RegisteredUser {
+//
+// public static final String UNKNOWN = "unknown";
+//
+// @Id
+// @Getter
+// protected ObjectId _id;
+//
+// @NotNull
+// @Getter
+// @Setter
+// @Indexed(unique = true)
+// protected String email;
+//
+// @Getter
+// @Setter
+// protected String telNumber;
+//
+// @Getter
+// @Setter
+// protected String avatar;
+//
+// @JsonIgnore
+// @Getter
+// @Setter
+// protected String password;
+//
+// @NotNull
+// @Getter
+// @Setter
+// @Indexed
+// protected String name;
+//
+// @NotNull
+// @Getter
+// @Setter
+// @Indexed
+// protected String surname;
+//
+// @Getter
+// @Setter
+// protected String token;
+//
+// @Getter
+// @Setter
+// protected LocalDateTime expirationDate;
+//
+// public User() {
+// super();
+// }
+//
+// public User(ObjectId id) {
+// this();
+// this._id = id;
+// nextGroups = new HashSet<>();
+// }
+//
+// public User(User user) {
+// this._id = user.get_id();
+// this.email = user.getEmail();
+// this.surname = user.getSurname();
+// this.name = user.getName();
+// this.state = user.getState();
+// }
+//
+// public User(String email, String password, String name, String surname) {
+// this();
+// this.email = email;
+// this.password = password;
+// this.name = name;
+// this.surname = surname;
+// this.nextGroups = new HashSet<>();
+// }
+//
+// public User(ObjectNode json) {
+// this(json.get("email").asText(), null, json.get("name").asText(), json.get("surname").asText());
+// ((ArrayNode) json.get("processRoles"))
+// .forEach(node -> processRoles.add(new ProcessRole(node.get("_id").asText())));
+// }
+//
+// public String getFullName() {
+// return name + " " + surname;
+// }
+//
+// @JsonIgnore
+// public String getStringId() {
+// return _id.toString();
+// }
+//
+// @JsonIgnore
+// public String getId() {
+// return _id.toString();
+// }
+//
+// public LoggedUser transformToLoggedUser() {
+// LoggedUser loggedUser = new LoggedUser(this.get_id().toString(), this.getEmail(), this.getPassword(), this.getAuthorities());
+// loggedUser.setFullName(this.getFullName());
+// loggedUser.setAnonymous(false);
+// if (!this.getProcessRoles().isEmpty())
+// loggedUser.parseProcessRoles(this.getProcessRoles());
+// loggedUser.setGroups(this.getNextGroups());
+// if (this.isImpersonating()) {
+// loggedUser.impersonate(this.getImpersonated().transformToLoggedUser());
+// }
+// return loggedUser;
+// }
+//
+// @Override
+// public String toString() {
+// return "User{" +
+// "id=" + _id +
+// ", email='" + email + '\'' +
+// ", telNumber='" + telNumber + '\'' +
+// ", avatar='" + avatar + '\'' +
+// ", name='" + name + '\'' +
+// ", surname='" + surname + '\'' +
+// ", state=" + state +
+// ", token='" + token + '\'' +
+// ", expirationDate=" + expirationDate +
+// ", authorities=" + authorities +
+// ", processRoles=" + processRoles +
+// ", groups=" + nextGroups +
+// '}';
+// }
+//
+//
+//}
diff --git a/src/main/java/com/netgrif/application/engine/auth/domain/UserProcessRole.java b/application-engine/src/main/java/com/netgrif/application/engine/auth/domain/UserProcessRole.java
similarity index 100%
rename from src/main/java/com/netgrif/application/engine/auth/domain/UserProcessRole.java
rename to application-engine/src/main/java/com/netgrif/application/engine/auth/domain/UserProcessRole.java
diff --git a/src/main/java/com/netgrif/application/engine/auth/domain/UserProperties.java b/application-engine/src/main/java/com/netgrif/application/engine/auth/domain/UserProperties.java
similarity index 100%
rename from src/main/java/com/netgrif/application/engine/auth/domain/UserProperties.java
rename to application-engine/src/main/java/com/netgrif/application/engine/auth/domain/UserProperties.java
diff --git a/application-engine/src/main/java/com/netgrif/application/engine/auth/domain/UserState.java b/application-engine/src/main/java/com/netgrif/application/engine/auth/domain/UserState.java
new file mode 100644
index 00000000000..cfb87357bbb
--- /dev/null
+++ b/application-engine/src/main/java/com/netgrif/application/engine/auth/domain/UserState.java
@@ -0,0 +1,7 @@
+//package com.netgrif.application.engine.auth.domain;
+//
+//public enum UserState {
+// ACTIVE,
+// BLOCKED,
+// INVITED
+//}
diff --git a/application-engine/src/main/java/com/netgrif/application/engine/auth/domain/repositories/AuthorityRepository.java b/application-engine/src/main/java/com/netgrif/application/engine/auth/domain/repositories/AuthorityRepository.java
new file mode 100644
index 00000000000..7549ab2f839
--- /dev/null
+++ b/application-engine/src/main/java/com/netgrif/application/engine/auth/domain/repositories/AuthorityRepository.java
@@ -0,0 +1,19 @@
+//package com.netgrif.application.engine.auth.domain.repositories;
+//
+//import com.netgrif.application.engine.objects.auth.domain.Authority;
+//import org.bson.types.ObjectId;
+//import org.springframework.data.mongodb.repository.MongoRepository;
+//import org.springframework.data.querydsl.QuerydslPredicateExecutor;
+//import org.springframework.stereotype.Repository;
+//
+//import java.util.List;
+//
+//@Repository
+//public interface AuthorityRepository extends MongoRepository, QuerydslPredicateExecutor {
+//
+// Authority findByName(String name);
+//
+// List findAllByNameStartsWith(String prefix);
+//
+// List findAllBy_idIn(List ids);
+//}
diff --git a/application-engine/src/main/java/com/netgrif/application/engine/auth/domain/repositories/UserRepository.java b/application-engine/src/main/java/com/netgrif/application/engine/auth/domain/repositories/UserRepository.java
new file mode 100644
index 00000000000..5ef319b0b3b
--- /dev/null
+++ b/application-engine/src/main/java/com/netgrif/application/engine/auth/domain/repositories/UserRepository.java
@@ -0,0 +1,43 @@
+//package com.netgrif.application.engine.auth.domain.repositories;
+//
+//import com.netgrif.application.engine.objects.auth.domain.Authority;.QUser;
+//import com.netgrif.application.engine.objects.auth.domain.User;
+//import com.netgrif.application.engine.objects.auth.domain.enums.UserState;
+//import org.bson.types.ObjectId;
+//import org.springframework.data.domain.Page;
+//import org.springframework.data.domain.Pageable;
+//import org.springframework.data.mongodb.repository.MongoRepository;
+//import org.springframework.data.querydsl.QuerydslPredicateExecutor;
+//import org.springframework.data.querydsl.binding.QuerydslBinderCustomizer;
+//import org.springframework.data.querydsl.binding.QuerydslBindings;
+//import org.springframework.stereotype.Repository;
+//
+//import java.time.LocalDateTime;
+//import java.util.List;
+//import java.util.Set;
+//
+//@Repository
+//public interface UserRepository extends MongoRepository, QuerydslPredicateExecutor, QuerydslBinderCustomizer {
+//
+// Page findAllBy_idInAndState(Set ids, UserState state, Pageable pageable);
+//
+// User findByEmail(String email);
+//
+// List findAllByStateAndExpirationDateBefore(UserState userState, LocalDateTime dateTime);
+//
+// Page findDistinctByStateAndProcessRoles__idIn(UserState state, List roleId, Pageable pageable);
+//
+// List findAllByProcessRoles__idIn(List roleId);
+//
+// List removeAllByStateAndExpirationDateBefore(UserState state, LocalDateTime dateTime);
+//
+// List findAllByIdIn(Set ids);
+//
+// List findAllBy_idIn(Set ids);
+//
+// boolean existsByEmail(String email);
+//
+// @Override
+// default void customize(QuerydslBindings bindings, QUser qUser) {
+// }
+//}
diff --git a/application-engine/src/main/java/com/netgrif/application/engine/auth/domain/repositories/UserRepositoryImpl.java b/application-engine/src/main/java/com/netgrif/application/engine/auth/domain/repositories/UserRepositoryImpl.java
new file mode 100644
index 00000000000..98a2321013b
--- /dev/null
+++ b/application-engine/src/main/java/com/netgrif/application/engine/auth/domain/repositories/UserRepositoryImpl.java
@@ -0,0 +1,7 @@
+//package com.netgrif.application.engine.objects.auth.domain.Authority;.repositories;
+//
+//import org.springframework.stereotype.Repository;
+//
+//@Repository("userRepository")
+//public abstract class UserRepositoryImpl implements UserRepository {
+//}
diff --git a/src/main/java/com/netgrif/application/engine/auth/domain/throwable/UnauthorisedRequestException.java b/application-engine/src/main/java/com/netgrif/application/engine/auth/domain/throwable/UnauthorisedRequestException.java
similarity index 100%
rename from src/main/java/com/netgrif/application/engine/auth/domain/throwable/UnauthorisedRequestException.java
rename to application-engine/src/main/java/com/netgrif/application/engine/auth/domain/throwable/UnauthorisedRequestException.java
diff --git a/application-engine/src/main/java/com/netgrif/application/engine/auth/service/AbstractUserService.java b/application-engine/src/main/java/com/netgrif/application/engine/auth/service/AbstractUserService.java
new file mode 100644
index 00000000000..7d3ea3881d2
--- /dev/null
+++ b/application-engine/src/main/java/com/netgrif/application/engine/auth/service/AbstractUserService.java
@@ -0,0 +1,144 @@
+//package com.netgrif.application.engine.auth.service;
+//
+//import com.netgrif.application.engine.objects.auth.domain.Authority;.*;
+//import com.netgrif.application.engine.objects.auth.domain.Authority;.repositories.UserRepository;
+//import com.netgrif.application.engine.auth.service.AuthorityService;
+//import com.netgrif.application.engine.auth.service.UserService;
+//import com.netgrif.application.engine.auth.service.GroupService;
+//import com.netgrif.application.engine.objects.petrinet.domain.PetriNet;
+//import com.netgrif.application.engine.objects.petrinet.domain.roles.ProcessRole;
+//import com.netgrif.application.engine.adapter.spring.petrinet.service.ProcessRoleService;
+//import com.netgrif.application.engine.security.service.ISecurityContextService;
+//import org.springframework.beans.factory.annotation.Autowired;
+//import org.springframework.data.domain.Page;
+//import org.springframework.data.domain.PageImpl;
+//import org.springframework.data.domain.Pageable;
+//import org.springframework.security.core.context.SecurityContextHolder;
+//
+//import java.util.HashSet;
+//import java.util.List;
+//import java.util.stream.Collectors;
+//
+//import static com.netgrif.application.engine.startup.runner.SystemUserRunner.*;
+//
+//public abstract class AbstractUserService implements IUserService {
+//
+// @Autowired
+// protected AuthorityService authorityService;
+//
+// @Autowired
+// protected ProcessRoleService processRoleService;
+//
+//
+// @Autowired
+// protected GroupService groupService;
+//
+// @Autowired
+// protected UserRepository repository;
+//
+// @Autowired
+// private ISecurityContextService securityContextService;
+//
+// @Override
+// public void addDefaultRole(IUser user) {
+// user.addProcessRole(processRoleService.defaultRole());
+// }
+//
+// @Override
+// public void addAnonymousRole(IUser user) {
+// user.addProcessRole(processRoleService.defaultRole());
+// }
+//
+// @Override
+// public void addDefaultAuthorities(IUser user) {
+// if (user.getAuthorities().isEmpty()) {
+// HashSet authorities = new HashSet<>();
+// authorities.add(authorityService.getOrCreate(Authority.user));
+// user.setAuthorities(authorities);
+// }
+// }
+//
+// @Override
+// public void addAnonymousAuthorities(IUser user) {
+// if (user.getAuthorities().isEmpty()) {
+// HashSet authorities = new HashSet<>();
+// authorities.add(authorityService.getOrCreate(Authority.anonymous));
+// user.setAuthorities(authorities);
+// }
+// }
+//
+// @Override
+// public IUser assignAuthority(String userId, String authorityId) {
+// IUser user = resolveById(userId, true);
+// Authority authority = authorityService.getOne(authorityId);
+// user.addAuthority(authority);
+// authority.addUser(user);
+//
+// return save(user);
+// }
+//
+// @Override
+// public LoggedUser getAnonymousLogged() {
+// if (SecurityContextHolder.getContext().getAuthentication().getPrincipal().equals(UserProperties.ANONYMOUS_AUTH_KEY)) {
+// getLoggedUser().transformToLoggedUser();
+// }
+// return (LoggedUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
+// }
+//
+// @Override
+// public IUser addRole(IUser user, String roleStringId) {
+// ProcessRole role = processRoleService.findById(roleStringId);
+// user.addProcessRole(role);
+// securityContextService.saveToken(user.getStringId());
+// securityContextService.reloadSecurityContext(userService.transformToLoggedUser(user));
+// return save(user);
+// }
+//
+// /**
+// * @param user
+// * @param roleStringId
+// * @return
+// * @deprecated use {@link AbstractUserService#removeRole(IUser, ProcessRole)} instead
+// */
+// @Override
+// @Deprecated(since = "6.2.0")
+// public IUser removeRole(IUser user, String roleStringId) {
+// return removeRole(user, processRoleService.findByImportId(roleStringId));
+// }
+//
+// @Override
+// public IUser removeRole(IUser user, ProcessRole role) {
+// user.removeProcessRole(role);
+// securityContextService.saveToken(user.getStringId());
+// securityContextService.reloadSecurityContext(userService.transformToLoggedUser(user));
+// return save(user);
+// }
+//
+// @Override
+// public void removeRoleOfDeletedPetriNet(PetriNet net) {
+// List users = findAllByProcessRoles(net.getRoles().keySet(), false);
+// users.forEach(u -> {
+// net.getRoles().forEach((k, role) -> removeRole(u, role));
+// });
+// }
+//
+// @Override
+// public IUser createSystemUser() {
+// User system = repository.findByEmail(SYSTEM_USER_EMAIL);
+// if (system == null) {
+// system = new User(SYSTEM_USER_EMAIL, "n/a", SYSTEM_USER_NAME, SYSTEM_USER_SURNAME);
+// system.setState(UserState.ACTIVE);
+// repository.save(system);
+// }
+// return system;
+// }
+//
+// public Page changeType(Page users, Pageable pageable) {
+// return new PageImpl<>(changeType(users.getContent()), pageable, users.getTotalElements());
+// }
+//
+// public List changeType(List users) {
+// return users.stream().map(IUser.class::cast).collect(Collectors.toList());
+// }
+//
+//}
diff --git a/application-engine/src/main/java/com/netgrif/application/engine/auth/service/AuthorityService.java b/application-engine/src/main/java/com/netgrif/application/engine/auth/service/AuthorityService.java
new file mode 100644
index 00000000000..c76c32b9f58
--- /dev/null
+++ b/application-engine/src/main/java/com/netgrif/application/engine/auth/service/AuthorityService.java
@@ -0,0 +1,66 @@
+//package com.netgrif.application.engine.auth.service;
+//
+//import com.netgrif.application.engine.objects.auth.domain.Authority;
+//import com.netgrif.application.engine.objects.auth.domain.Authority;.repositories.AuthorityRepository;
+//import com.netgrif.application.engine.auth.service.AuthorityService;
+//import org.bson.types.ObjectId;
+//import org.springframework.beans.factory.annotation.Autowired;
+//import org.springframework.stereotype.Service;
+//import org.springframework.transaction.annotation.Transactional;
+//
+//import java.util.List;
+//import java.util.Optional;
+//import java.util.stream.Collectors;
+//
+//@Service
+//public class AuthorityService implements IAuthorityService {
+//
+// @Autowired
+// private AuthorityRepository repository;
+//
+// @Override
+// public List findAll() {
+// return repository.findAll();
+// }
+//
+// @Override
+// @Transactional
+// public Authority getOrCreate(String name) {
+// Authority authority = repository.findByName(name);
+// if (authority == null)
+// authority = repository.save(new Authority(name));
+// return authority;
+// }
+//
+// @Override
+// public Authority getOrCreatePermission(String name) {
+// return getOrCreate(Authority.PERMISSION + name);
+// }
+//
+// @Override
+// public Authority getOrCreateRole(String name) {
+// return getOrCreate(Authority.ROLE + name);
+// }
+//
+// @Override
+// public List getAllPermissions() {
+// return repository.findAllByNameStartsWith(Authority.PERMISSION);
+// }
+//
+// @Override
+// public List getAllRoles() {
+// return repository.findAllByNameStartsWith(Authority.ROLE);
+// }
+//
+// public Authority getOne(String id) {
+// Optional authority = repository.findById(id);
+// if (!authority.isPresent())
+// throw new IllegalArgumentException("Could not find authority with id [" + id + "]");
+// return authority.get();
+// }
+//
+// @Override
+// public List findAllByIds(List ids) {
+// return repository.findAllBy_idIn(ids.stream().map(ObjectId::new).collect(Collectors.toList()));
+// }
+//}
diff --git a/application-engine/src/main/java/com/netgrif/application/engine/auth/service/AuthorizationService.java b/application-engine/src/main/java/com/netgrif/application/engine/auth/service/AuthorizationService.java
new file mode 100644
index 00000000000..e15ba08075d
--- /dev/null
+++ b/application-engine/src/main/java/com/netgrif/application/engine/auth/service/AuthorizationService.java
@@ -0,0 +1,20 @@
+package com.netgrif.application.engine.auth.service;
+
+import com.netgrif.application.engine.objects.auth.domain.LoggedUser;
+import com.netgrif.application.engine.auth.service.interfaces.IAuthorizationService;
+import com.netgrif.application.engine.auth.service.UserService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+@Service
+public class AuthorizationService implements IAuthorizationService {
+
+ @Autowired
+ private UserService userService;
+
+ @Override
+ public boolean hasAuthority(String authority) {
+ LoggedUser loggedUser = userService.getLoggedUserFromContext().getSelfOrImpersonated();
+ return loggedUser.getAuthoritySet().stream().anyMatch(it -> it.getAuthority().equals(authority));
+ }
+}
diff --git a/src/main/java/com/netgrif/application/engine/auth/service/InvalidUserTokenException.java b/application-engine/src/main/java/com/netgrif/application/engine/auth/service/InvalidUserTokenException.java
similarity index 100%
rename from src/main/java/com/netgrif/application/engine/auth/service/InvalidUserTokenException.java
rename to application-engine/src/main/java/com/netgrif/application/engine/auth/service/InvalidUserTokenException.java
diff --git a/application-engine/src/main/java/com/netgrif/application/engine/auth/service/LdapUserDetailsService.java b/application-engine/src/main/java/com/netgrif/application/engine/auth/service/LdapUserDetailsService.java
new file mode 100644
index 00000000000..2229dd5512e
--- /dev/null
+++ b/application-engine/src/main/java/com/netgrif/application/engine/auth/service/LdapUserDetailsService.java
@@ -0,0 +1,26 @@
+//package com.netgrif.application.engine.auth.service;
+//
+//import com.netgrif.application.engine.objects.auth.domain.IUser;
+//import com.netgrif.application.engine.objects.auth.domain.LoggedUser;
+//import com.netgrif.application.engine.objects.auth.domain.enums.UserState;
+//import com.netgrif.application.engine.ldap.domain.LdapUser;
+//import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
+//import org.springframework.security.core.userdetails.UsernameNotFoundException;
+//
+//@ConditionalOnExpression("${nae.ldap.enabled:false}")
+//public class LdapUserDetailsService extends UserDetailsServiceImpl {
+//
+// @Override
+// protected LoggedUser getLoggedUser(String email) throws UsernameNotFoundException {
+// IUser user = userRepository.findByEmail(email);
+// if (user == null) {
+// throw new UsernameNotFoundException("No user was found for login: " + email);
+// } else if (user.getState() != UserState.ACTIVE) {
+// throw new UsernameNotFoundException("User with login " + email + " cannot be logged in!");
+// } else if (user instanceof LdapUser) {
+// throw new UsernameNotFoundException("Ldap has not verified the user " + email + "!");
+// }
+//
+// return userService.transformToLoggedUser(user);
+// }
+//}
diff --git a/src/main/java/com/netgrif/application/engine/auth/service/LoginAttemptService.java b/application-engine/src/main/java/com/netgrif/application/engine/auth/service/LoginAttemptService.java
similarity index 100%
rename from src/main/java/com/netgrif/application/engine/auth/service/LoginAttemptService.java
rename to application-engine/src/main/java/com/netgrif/application/engine/auth/service/LoginAttemptService.java
diff --git a/application-engine/src/main/java/com/netgrif/application/engine/auth/service/RegistrationService.java b/application-engine/src/main/java/com/netgrif/application/engine/auth/service/RegistrationService.java
new file mode 100644
index 00000000000..9d56ca0ce0d
--- /dev/null
+++ b/application-engine/src/main/java/com/netgrif/application/engine/auth/service/RegistrationService.java
@@ -0,0 +1,241 @@
+package com.netgrif.application.engine.auth.service;
+
+import com.netgrif.application.engine.objects.auth.domain.IUser;
+import com.netgrif.application.engine.objects.auth.domain.RegisteredUser;
+import com.netgrif.application.engine.objects.auth.domain.User;
+import com.netgrif.application.engine.objects.auth.domain.enums.UserState;
+import com.netgrif.application.engine.auth.service.interfaces.IRegistrationService;
+import com.netgrif.application.engine.auth.service.UserService;
+import com.netgrif.application.engine.auth.web.requestbodies.NewUserRequest;
+import com.netgrif.application.engine.auth.web.requestbodies.RegistrationRequest;
+import com.netgrif.application.engine.configuration.properties.ServerAuthProperties;
+import com.netgrif.application.engine.auth.service.GroupService;
+import com.netgrif.application.engine.adapter.spring.petrinet.service.ProcessRoleService;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+import java.time.LocalDateTime;
+import java.util.*;
+import java.util.stream.Collectors;
+
+@Slf4j
+@Service
+public class RegistrationService implements IRegistrationService {
+
+ @Autowired
+ protected BCryptPasswordEncoder bCryptPasswordEncoder;
+
+ @Autowired
+ private UserService userService;
+
+ @Autowired
+ private GroupService groupService;
+
+ @Autowired
+ private ProcessRoleService processRole;
+
+ @Autowired
+ private ServerAuthProperties serverAuthProperties;
+ @Autowired
+ private ProcessRoleService processRoleService;
+
+ @Override
+ @Transactional
+ @Scheduled(cron = "0 0 1 * * *")
+ public void removeExpiredUsers() {
+ log.info("Removing expired unactivated invited users");
+ userService.removeAllByStateAndExpirationDateBefore(UserState.INACTIVE, LocalDateTime.now(),null);
+ }
+
+ @Override
+ @Transactional
+ @Scheduled(cron = "0 0 1 * * *")
+ public void resetExpiredToken() {
+ log.info("Resetting expired user tokens");
+ List users = userService.findAllByStateAndExpirationDateBefore(UserState.BLOCKED, LocalDateTime.now(), null);
+ if (users == null || users.isEmpty()) {
+ log.info("There are none expired tokens. Everything is awesome.");
+ return;
+ }
+
+ users.forEach(user -> {
+ user.setToken(null);
+ user.setExpirationDate(null);
+ });
+ users = userService.saveUsers(users.stream().map(u -> (IUser) u).collect(Collectors.toList()));
+ log.info("Reset " + users.size() + " expired user tokens");
+ }
+
+ @Override
+ public void changePassword(RegisteredUser user, String newPassword) {
+ user.setPassword(newPassword);
+ encodeUserPassword(user);
+ userService.saveUser(user, null);
+ log.info("Changed password for user " + user.getEmail() + ".");
+ }
+
+ @Override
+ public boolean verifyToken(String token) {
+ try {
+ log.info("Verifying token:" + token);
+ String[] tokenParts = decodeToken(token);
+ User user = (User) userService.findByEmail(tokenParts[0], null);
+ return user != null && Objects.equals(user.getToken(), tokenParts[1]) && user.getExpirationDate().isAfter(LocalDateTime.now());
+ } catch (InvalidUserTokenException e) {
+ log.error(e.getMessage());
+ return false;
+ }
+ }
+
+ @Override
+ public void encodeUserPassword(RegisteredUser user) {
+ String pass = user.getPassword();
+ if (pass == null) {
+ throw new IllegalArgumentException("User has no password");
+ }
+ user.setPassword(bCryptPasswordEncoder.encode(pass));
+ }
+
+ @Override
+ public boolean stringMatchesUserPassword(RegisteredUser user, String passwordToCompare) {
+ return bCryptPasswordEncoder.matches(passwordToCompare, user.getPassword());
+ }
+
+ @Override
+ @Transactional
+ public User createNewUser(NewUserRequest newUser) {
+ User user = (User) userService.findByEmail(newUser.email, null);
+ if (user != null) {
+ if (user.isActive()) {
+ return null;
+ }
+ log.info("Renewing old user [" + newUser.email + "]");
+ } else {
+ user = new com.netgrif.application.engine.adapter.spring.auth.domain.User();
+ user.setEmail(newUser.email);
+ user.setUsername(newUser.email);
+ log.info("Creating new user [" + newUser.email + "]");
+ }
+ user.setToken(generateTokenKey());
+ user.setPassword("");
+ user.setExpirationDate(generateExpirationDate());
+ user.setState(UserState.INACTIVE);
+ userService.addDefaultAuthorities(user);
+
+ if (newUser.processRoles != null && !newUser.processRoles.isEmpty()) {
+ user.setProcessRoles(new HashSet<>(processRole.findByIds(newUser.processRoles)));
+ }
+ userService.addRole(user, processRoleService.getDefaultRole().getStringId());
+ user = (User) userService.saveUser(user, null);
+
+ if (newUser.groups != null && !newUser.groups.isEmpty()) {
+ for (String group : newUser.groups) {
+ groupService.addUser((IUser) user, group);
+ }
+ }
+
+ return user;
+ }
+
+ @Override
+ public RegisteredUser registerUser(RegistrationRequest registrationRequest) throws InvalidUserTokenException {
+ String email = decodeToken(registrationRequest.token)[0];
+ log.info("Registering user " + email);
+ RegisteredUser user = (RegisteredUser) userService.findByEmail(email, null);
+ if (user == null) {
+ return null;
+ }
+
+ user.setFirstName(registrationRequest.name);
+ user.setLastName(registrationRequest.surname);
+ user.setPassword(registrationRequest.password);
+
+ user.setToken(StringUtils.EMPTY);
+ user.setExpirationDate(null);
+ user.setState(UserState.ACTIVE);
+
+ return (RegisteredUser) userService.saveUser(user, null);
+ }
+
+ @Override
+ public RegisteredUser resetPassword(String email) {
+ log.info("Resetting password of " + email);
+ User user = (User) userService.findByEmail(email, null);
+ if (user == null || !user.isActive()) {
+ String state = user == null ? "Non-existing" : "Inactive";
+ log.info(state + " user [" + email + "] tried to reset his password");
+ return null;
+ }
+
+ user.setState(UserState.BLOCKED);
+ user.setPassword(null);
+ user.setToken(generateTokenKey());
+ user.setExpirationDate(generateExpirationDate());
+ return (RegisteredUser) userService.saveUser(user, null);
+ }
+
+ @Override
+ public RegisteredUser recover(String email, String newPassword) {
+ log.info("Recovering user " + email);
+ User user = (User) userService.findByEmail(email, null);
+ if (user == null) {
+ return null;
+ }
+ user.setState(UserState.ACTIVE);
+ user.setPassword(newPassword);
+ encodeUserPassword(user);
+ user.setToken(null);
+ user.setExpirationDate(null);
+
+ return (RegisteredUser) userService.saveUser(user, null);
+ }
+
+ @Override
+ public String generateTokenKey() {
+ return new BigInteger(256, new SecureRandom()).toString(32);
+ }
+
+ @Override
+ public String[] decodeToken(String token) throws InvalidUserTokenException {
+ if (token == null || token.isEmpty()) {
+ throw new InvalidUserTokenException(token);
+ }
+ byte[] decodedBytes;
+
+ try {
+ decodedBytes = Base64.getDecoder().decode(token);
+ } catch (IllegalArgumentException exception) {
+ throw new InvalidUserTokenException(token);
+ }
+ String decodedString = new String(decodedBytes);
+ String[] parts = decodedString.split(":");
+
+ if (parts.length != 2 || !parts[0].contains("@")) {
+ throw new InvalidUserTokenException(token);
+ }
+
+ return parts;
+ }
+
+ @Override
+ public String encodeToken(String email, String tokenKey) {
+ return Base64.getEncoder().encodeToString((email + ":" + tokenKey).getBytes());
+ }
+
+ @Override
+ public LocalDateTime generateExpirationDate() {
+ return LocalDateTime.now().plusDays(serverAuthProperties.getTokenValidityPeriod());
+ }
+
+ @Override
+ public boolean isPasswordSufficient(String password) {
+ return password.length() >= serverAuthProperties.getMinimalPasswordLength();
+ }
+}
diff --git a/application-engine/src/main/java/com/netgrif/application/engine/auth/service/UserDetailsServiceImpl.java b/application-engine/src/main/java/com/netgrif/application/engine/auth/service/UserDetailsServiceImpl.java
new file mode 100644
index 00000000000..80a6fb11fc5
--- /dev/null
+++ b/application-engine/src/main/java/com/netgrif/application/engine/auth/service/UserDetailsServiceImpl.java
@@ -0,0 +1,75 @@
+package com.netgrif.application.engine.auth.service;
+
+import com.netgrif.application.engine.adapter.spring.auth.domain.LoggedUserImpl;
+import com.netgrif.application.engine.auth.service.UserService;
+import com.netgrif.application.engine.objects.auth.domain.IUser;
+import com.netgrif.application.engine.objects.auth.domain.LoggedUser;
+import com.netgrif.application.engine.objects.auth.domain.User;
+import com.netgrif.application.engine.objects.auth.domain.enums.UserState;
+import com.netgrif.application.engine.auth.service.interfaces.ILoginAttemptService;
+import com.netgrif.application.engine.objects.event.events.user.UserLoginEvent;
+import jakarta.servlet.http.HttpServletRequest;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.ApplicationEventPublisher;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.core.userdetails.UserDetailsService;
+import org.springframework.security.core.userdetails.UsernameNotFoundException;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.Optional;
+
+@Service
+public class UserDetailsServiceImpl implements UserDetailsService {
+
+ private static final Logger logger = LoggerFactory.getLogger(UserDetailsServiceImpl.class);
+
+ @Autowired
+ protected UserService userService;
+
+ @Autowired
+ protected ApplicationEventPublisher publisher;
+
+ @Autowired
+ protected ILoginAttemptService loginAttemptService;
+
+ @Autowired
+ protected HttpServletRequest request;
+
+ @Override
+ @Transactional(readOnly = true)
+ public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
+ String ip = getClientIP();
+ if (loginAttemptService.isBlocked(ip)) {
+ logger.info("User " + email + " with IP Address " + ip + " is blocked.");
+ throw new RuntimeException("blocked");
+ }
+
+ LoggedUserImpl loggedUser = getLoggedUser(email);
+
+ publisher.publishEvent(new UserLoginEvent(loggedUser));
+
+ return loggedUser;
+ }
+
+ protected LoggedUserImpl getLoggedUser(String email) throws UsernameNotFoundException {
+ IUser user = userService.findByEmail(email, null);
+ if (user == null)
+ throw new UsernameNotFoundException("No user was found for login: " + email);
+ if (((User) user).getPassword() == null || user.getState() != UserState.ACTIVE)
+ throw new UsernameNotFoundException("User with login " + email + " cannot be logged in!");
+
+ return (LoggedUserImpl) userService.transformToLoggedUser(user);
+ }
+
+
+ protected String getClientIP() {
+ String xfHeader = request.getHeader("X-Forwarded-For");
+ if (xfHeader == null) {
+ return request.getRemoteAddr();
+ }
+ return xfHeader.split(",")[0];
+ }
+}
diff --git a/application-engine/src/main/java/com/netgrif/application/engine/auth/service/UserResourceHelperService.java b/application-engine/src/main/java/com/netgrif/application/engine/auth/service/UserResourceHelperService.java
new file mode 100644
index 00000000000..ba3c287634b
--- /dev/null
+++ b/application-engine/src/main/java/com/netgrif/application/engine/auth/service/UserResourceHelperService.java
@@ -0,0 +1,54 @@
+package com.netgrif.application.engine.auth.service;
+
+import com.netgrif.application.engine.objects.auth.domain.IUser;
+import com.netgrif.application.engine.objects.auth.domain.LoggedUser;
+import com.netgrif.application.engine.auth.service.interfaces.IUserResourceHelperService;
+import com.netgrif.application.engine.auth.web.responsebodies.User;
+import com.netgrif.application.engine.auth.web.responsebodies.UserResource;
+import com.netgrif.application.engine.impersonation.service.interfaces.IImpersonationService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.Locale;
+
+@Slf4j
+@Service
+public class UserResourceHelperService implements IUserResourceHelperService {
+
+ @Autowired
+ private UserService userService;
+
+ @Autowired
+ private UserFactory userFactory;
+
+ @Autowired
+ private IImpersonationService impersonationService;
+
+ @Override
+ public UserResource getResource(LoggedUser loggedUser, Locale locale, boolean small) {
+ IUser user = userService.findById(loggedUser.getId(), null);
+ User result = loggedUser.isImpersonating() ?
+ getLocalisedUser(user, getImpersonated(loggedUser, small), locale) :
+ getLocalisedUser(user, locale);
+ return new UserResource(result, "profile");
+ }
+
+ @Override
+ public User getLocalisedUser(IUser user, IUser impersonated, Locale locale) {
+ User localisedUser = getLocalisedUser(user, locale);
+ User impersonatedUser = userFactory.getUser(impersonated, locale);
+ localisedUser.setImpersonated(impersonatedUser);
+ return localisedUser;
+ }
+
+ @Override
+ public User getLocalisedUser(IUser user, Locale locale) {
+ return userFactory.getUser(user, locale);
+ }
+
+ protected IUser getImpersonated(LoggedUser loggedUser, boolean small) {
+ IUser impersonated = userService.findById(loggedUser.getImpersonated().getId(), null);
+ return impersonationService.reloadImpersonatedUserRoles(impersonated, loggedUser.getId());
+ }
+}
diff --git a/application-engine/src/main/java/com/netgrif/application/engine/auth/service/UserService.java b/application-engine/src/main/java/com/netgrif/application/engine/auth/service/UserService.java
new file mode 100755
index 00000000000..12aa1c641f5
--- /dev/null
+++ b/application-engine/src/main/java/com/netgrif/application/engine/auth/service/UserService.java
@@ -0,0 +1,354 @@
+//package com.netgrif.application.engine.auth.service;
+//
+//import com.netgrif.application.engine.objects.auth.domain.Authority;.*;
+//import com.netgrif.application.engine.objects.auth.domain.Authority;.repositories.AuthorityRepository;
+//import com.netgrif.application.engine.objects.auth.domain.Authority;.repositories.UserRepository;
+//import com.netgrif.application.engine.auth.service.interfaces.IRegistrationService;
+//import com.netgrif.application.engine.auth.web.requestbodies.UpdateUserRequest;
+//import com.netgrif.application.engine.event.events.user.UserRegistrationEvent;
+//import com.netgrif.application.engine.orgstructure.groups.config.GroupConfigurationProperties;
+//import com.netgrif.application.engine.auth.service.GroupService;
+//import com.netgrif.application.engine.adapter.spring.petrinet.service.ProcessRoleService;
+//import com.netgrif.application.engine.startup.runner.SystemUserRunner;
+//import com.netgrif.application.engine.objects.workflow.domain.ProcessResourceId;
+//import com.netgrif.application.engine.workflow.service.interfaces.IFilterImportExportService;
+//import com.querydsl.core.types.dsl.BooleanExpression;
+//import org.bson.types.ObjectId;
+//import org.springframework.beans.factory.annotation.Autowired;
+//import org.springframework.context.ApplicationEventPublisher;
+//import org.springframework.data.domain.Page;
+//import org.springframework.data.domain.Pageable;
+//import org.springframework.security.core.Authentication;
+//import org.springframework.security.core.context.SecurityContextHolder;
+//import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
+//
+//import java.util.*;
+//import java.util.stream.Collectors;
+//
+//public class UserService extends AbstractUserService {
+//
+// @Autowired
+// protected UserRepository userRepository;
+//
+// @Autowired
+// protected AuthorityRepository authorityRepository;
+//
+// @Autowired
+// protected ProcessRoleService processRoleService;
+//
+// @Autowired
+// protected ApplicationEventPublisher publisher;
+//
+// @Autowired
+// protected GroupService groupService;
+//
+// @Autowired
+// protected IRegistrationService registrationService;
+//
+// @Autowired
+// private BCryptPasswordEncoder bCryptPasswordEncoder;
+//
+// @Autowired
+// private GroupConfigurationProperties groupProperties;
+//
+// @Autowired
+// private IFilterImportExportService filterImportExportService;
+//
+// @Override
+// public IUser saveNewAndAuthenticate(IUser user) {
+// return saveNew(user, true);
+// }
+//
+// @Override
+// public IUser saveNew(IUser user) {
+// return saveNew(user, false);
+// }
+//
+// private IUser saveNew(IUser user, boolean login) {
+//
+// registrationService.encodeUserPassword((RegisteredUser) user);
+// addDefaultRole(user);
+// addDefaultAuthorities(user);
+//
+// User savedUser = userRepository.save((User) user);
+// filterImportExportService.createFilterImport(user);
+// filterImportExportService.createFilterExport(user);
+//
+// if (groupProperties.isDefaultEnabled())
+// groupService.createGroup(user);
+//
+// if (groupProperties.isSystemEnabled())
+// groupService.addUserToDefaultGroup(user);
+//
+// publisher.publishEvent(new UserRegistrationEvent(savedUser));
+//
+// return savedUser;
+// }
+//
+// @Override
+// public AnonymousUser saveNewAnonymous(AnonymousUser user) {
+// addAnonymousRole(user);
+// addAnonymousAuthorities(user);
+//
+// return userRepository.save(user);
+// }
+//
+// @Override
+// public User update(IUser user, UpdateUserRequest updates) {
+// User dbUser = (User) user;
+// if (updates.telNumber != null) {
+// dbUser.setTelNumber(updates.telNumber);
+// }
+// if (updates.avatar != null) {
+// dbUser.setAvatar(updates.avatar);
+// }
+// if (updates.name != null) {
+// dbUser.setName(updates.name);
+// }
+// if (updates.surname != null) {
+// dbUser.setSurname(updates.surname);
+// }
+// dbUser = userRepository.save(dbUser);
+// return dbUser;
+// }
+//
+// public void addDefaultRole(User user) {
+// user.addProcessRole(processRoleService.defaultRole());
+// }
+//
+// public void addAnonymousRole(User user) {
+// user.addProcessRole(processRoleService.anonymousRole());
+// }
+//
+// public void addDefaultAuthorities(User user) {
+// if (user.getAuthorities().isEmpty()) {
+// HashSet authorities = new HashSet();
+// authorities.add(authorityRepository.findByName(Authority.user));
+// user.setAuthorities(authorities);
+// }
+// }
+//
+// public void addAnonymousAuthorities(User user) {
+// if (user.getAuthorities().isEmpty()) {
+// HashSet authorities = new HashSet();
+// authorities.add(authorityRepository.findByName(Authority.anonymous));
+// user.setAuthorities(authorities);
+// }
+// }
+//
+// @Override
+// public IUser findByAuth(Authentication auth) {
+// return findByEmail(auth.getName(), false);
+// }
+//
+// @Override
+// public IUser save(IUser user) {
+// return userRepository.save((User) user);
+// }
+//
+// @Override
+// public IUser findById(String id, boolean small) {
+// Optional user = userRepository.findById(id);
+// if (user.isEmpty())
+// throw new IllegalArgumentException("Could not find user with id [" + id + "]");
+// return user.get();
+// }
+//
+// @Override
+// public IUser resolveById(String id, boolean small) {
+// return findById(id, small);
+// }
+//
+// @Override
+// public IUser findByEmail(String email, boolean small) {
+// return userRepository.findByEmail(email);
+// }
+//
+// @Override
+// public IUser findAnonymousByEmail(String email, boolean small) {
+// return findByEmail(email, small);
+// }
+//
+//
+// @Override
+// public List findAll(boolean small) {
+// return changeType(userRepository.findAll());
+//
+// }
+//
+// @Override
+// public Page findAllCoMembers(LoggedUser loggedUser, boolean small, Pageable pageable) {
+// Set members = groupService.getAllCoMembers(loggedUser.getSelfOrImpersonated().transformToUser());
+// members.add(loggedUser.getSelfOrImpersonated().getId());
+// Set objMembers = members.stream().map(ObjectId::new).collect(Collectors.toSet());
+// return changeType(userRepository.findAllBy_idInAndState(objMembers, UserState.ACTIVE, pageable), pageable);
+//
+// }
+//
+// @Override
+// public Page searchAllCoMembers(String query, LoggedUser loggedUser, Boolean small, Pageable pageable) {
+// Set members = groupService.getAllCoMembers(loggedUser.getSelfOrImpersonated().transformToUser());
+// members.add(loggedUser.getSelfOrImpersonated().getId());
+//
+// return changeType(userRepository.findAll(buildPredicate(members.stream().map(ObjectId::new)
+// .collect(Collectors.toSet()), query), pageable), pageable);
+//
+// }
+//
+// @Override
+// public Page searchAllCoMembers(String query, List roleIds, List negateRoleIds, LoggedUser loggedUser, Boolean small, Pageable pageable) {
+// if ((roleIds == null || roleIds.isEmpty()) && (negateRoleIds == null || negateRoleIds.isEmpty()))
+// return searchAllCoMembers(query, loggedUser, small, pageable);
+//
+// if (negateRoleIds == null) {
+// negateRoleIds = new ArrayList<>();
+// }
+//
+//
+// Set members = groupService.getAllCoMembers(loggedUser.getSelfOrImpersonated().transformToUser());
+// members.add(loggedUser.getSelfOrImpersonated().getId());
+// BooleanExpression predicate = buildPredicate(members.stream().map(ObjectId::new).collect(Collectors.toSet()), query);
+// if (!(roleIds == null || roleIds.isEmpty())) {
+// predicate = predicate.and(QUser.user.processRoles.any()._id.in(roleIds));
+// }
+// predicate = predicate.and(QUser.user.processRoles.any()._id.in(negateRoleIds).not());
+// Page users = userRepository.findAll(predicate, pageable);
+//
+// return changeType(users, pageable);
+// }
+//
+// private BooleanExpression buildPredicate(Set members, String query) {
+// BooleanExpression predicate = QUser.user
+// ._id.in(members)
+// .and(QUser.user.state.eq(UserState.ACTIVE));
+// for (String word : query.split(" ")) {
+// predicate = predicate
+// .andAnyOf(QUser.user.email.containsIgnoreCase(word),
+// QUser.user.name.containsIgnoreCase(word),
+// QUser.user.surname.containsIgnoreCase(word));
+// }
+// return predicate;
+// }
+//
+// @Override
+// public Page findAllActiveByProcessRoles(Set roleIds, boolean small, Pageable pageable) {
+// Page users = userRepository.findDistinctByStateAndProcessRoles__idIn(UserState.ACTIVE, new ArrayList<>(roleIds), pageable);
+// return changeType(users, pageable);
+// }
+//
+// @Override
+// public List findAllByProcessRoles(Set roleIds, boolean small) {
+// List users = userRepository.findAllByProcessRoles__idIn(new ArrayList<>(roleIds));
+// return changeType(users);
+// }
+//
+// @Override
+// public List findAllByIds(Set ids, boolean small) {
+// List users = userRepository.findAllBy_idIn(ids.stream().map(ObjectId::new).collect(Collectors.toSet()));
+// return changeType(users);
+// }
+//
+// @Override
+// public IUser assignAuthority(String userId, String authorityId) {
+// Optional user = userRepository.findById(userId);
+// Optional authority = authorityRepository.findById(authorityId);
+//
+// if (user.isEmpty())
+// throw new IllegalArgumentException("Could not find user with id [" + userId + "]");
+// if (authority.isEmpty())
+// throw new IllegalArgumentException("Could not find authority with id [" + authorityId + "]");
+//
+// user.get().addAuthority(authority.get());
+// authority.get().addUser(user.get());
+//
+// return userRepository.save(user.get());
+// }
+//
+// @Override
+// public IUser getLoggedOrSystem() {
+// try {
+// if (SecurityContextHolder.getContext().getAuthentication().getPrincipal() instanceof String) {
+// return getSystem();
+// }
+// return getLoggedUser();
+// } catch (NullPointerException e) {
+// return getSystem();
+// }
+// }
+//
+// @Override
+// public IUser getSystem() {
+// IUser system = userRepository.findByEmail(SystemUserRunner.SYSTEM_USER_EMAIL);
+// system.setProcessRoles(new HashSet<>(processRoleService.findAll()));
+// return system;
+// }
+//
+// @Override
+// public IUser getLoggedUser() {
+// LoggedUser loggedUser = getLoggedUserFromContext();
+// if (!loggedUser.isAnonymous()) {
+// IUser user = findByEmail(loggedUser.getEmail(), false);
+// if (loggedUser.isImpersonating()) {
+// // cannot be simply reloaded from DB, impersonated user holds a subset of roles and authorities.
+// // this reloads the impersonated user's roles as they are not complete (LoggedUser creates incomplete ProcessRole objects)
+// IUser impersonated = loggedUser.getImpersonated().transformToUser();
+// impersonated.setProcessRoles(processRoleService.findByIds(loggedUser.getImpersonated().getProcessRoles()));
+// user.setImpersonated(impersonated);
+// }
+// return user;
+// }
+// return loggedUser.transformToAnonymousUser();
+// }
+//
+// @Override
+// public LoggedUser getAnonymousLogged() {
+// if (SecurityContextHolder.getContext().getAuthentication().getPrincipal().equals(UserProperties.ANONYMOUS_AUTH_KEY)) {
+// return getLoggedUser().transformToLoggedUser();
+// }
+// return getLoggedUserFromContext();
+// }
+//
+// @Override
+// public LoggedUser getLoggedUserFromContext() {
+// return (LoggedUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
+// }
+//
+//// @Override
+//// public IUser addRole(IUser user, String roleStringId) {
+//// ProcessRole role = processRoleService.findById(roleStringId);
+//// user.addProcessRole(role);
+//// return userRepository.save(user);
+//// }
+////
+//// @Override
+//// public IUser removeRole(IUser user, String roleStringId) {
+//// ProcessRole role = processRoleService.findByImportId(roleStringId);
+//// user.removeProcessRole(role);
+//// return userRepository.save(user);
+//// }
+//
+// @Override
+// public void deleteUser(IUser user) {
+// User dbUser = (User) user;
+// if (!userRepository.findById(dbUser.getStringId()).isPresent())
+// throw new IllegalArgumentException("Could not find user with id [" + dbUser.get_id() + "]");
+// userRepository.delete(dbUser);
+// }
+//
+//
+//// private User loadProcessRoles(User user) {
+//// if (user == null)
+//// return null;
+//// user.setProcessRoles(processRoleRepository.findAllById(user.getUserProcessRoles()
+//// .stream().map(UserProcessRole::getRoleId).collect(Collectors.toList())));
+//// return user;
+//// }
+//
+// private User loadGroups(User user) {
+// if (user == null)
+// return null;
+// user.setNextGroups(this.groupService.getAllGroupsOfUser(user));
+// return user;
+// }
+//
+//}
diff --git a/src/main/java/com/netgrif/application/engine/auth/service/interfaces/IAuthorityService.java b/application-engine/src/main/java/com/netgrif/application/engine/auth/service/interfaces/IAuthorityService.java
similarity index 86%
rename from src/main/java/com/netgrif/application/engine/auth/service/interfaces/IAuthorityService.java
rename to application-engine/src/main/java/com/netgrif/application/engine/auth/service/interfaces/IAuthorityService.java
index dde34d1fef6..1f9d7663f9c 100644
--- a/src/main/java/com/netgrif/application/engine/auth/service/interfaces/IAuthorityService.java
+++ b/application-engine/src/main/java/com/netgrif/application/engine/auth/service/interfaces/IAuthorityService.java
@@ -1,6 +1,6 @@
package com.netgrif.application.engine.auth.service.interfaces;
-import com.netgrif.application.engine.auth.domain.Authority;
+import com.netgrif.application.engine.objects.auth.domain.Authority;
import java.util.List;
@@ -21,4 +21,4 @@ public interface IAuthorityService {
Authority getOne(String id);
List findAllByIds(List ids);
-}
\ No newline at end of file
+}
diff --git a/src/main/java/com/netgrif/application/engine/auth/service/interfaces/IAuthorizationService.java b/application-engine/src/main/java/com/netgrif/application/engine/auth/service/interfaces/IAuthorizationService.java
similarity index 100%
rename from src/main/java/com/netgrif/application/engine/auth/service/interfaces/IAuthorizationService.java
rename to application-engine/src/main/java/com/netgrif/application/engine/auth/service/interfaces/IAuthorizationService.java
diff --git a/application-engine/src/main/java/com/netgrif/application/engine/auth/service/interfaces/ILdapUserRefService.java b/application-engine/src/main/java/com/netgrif/application/engine/auth/service/interfaces/ILdapUserRefService.java
new file mode 100644
index 00000000000..9d3ef412ff2
--- /dev/null
+++ b/application-engine/src/main/java/com/netgrif/application/engine/auth/service/interfaces/ILdapUserRefService.java
@@ -0,0 +1,23 @@
+//package com.netgrif.application.engine.auth.service.interfaces;
+//
+//
+//import com.netgrif.application.engine.objects.auth.domain.IUser;
+//import com.netgrif.application.engine.ldap.domain.LdapUserRef;
+//import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
+//
+//import javax.naming.Name;
+//
+//@ConditionalOnExpression("${nae.ldap.enabled:false}")
+//public interface ILdapUserRefService {
+//
+// IUser createUser(LdapUserRef ldapUser);
+//
+// IUser updateById(Name id, IUser savedUser);
+//
+// LdapUserRef findById(Name id);
+//
+// LdapUserRef findUserByDn(String dn);
+//
+// LdapUserRef findUserByCn(String cn);
+//
+//}
diff --git a/src/main/java/com/netgrif/application/engine/auth/service/interfaces/ILoginAttemptService.java b/application-engine/src/main/java/com/netgrif/application/engine/auth/service/interfaces/ILoginAttemptService.java
similarity index 100%
rename from src/main/java/com/netgrif/application/engine/auth/service/interfaces/ILoginAttemptService.java
rename to application-engine/src/main/java/com/netgrif/application/engine/auth/service/interfaces/ILoginAttemptService.java
diff --git a/src/main/java/com/netgrif/application/engine/auth/service/interfaces/IRegistrationService.java b/application-engine/src/main/java/com/netgrif/application/engine/auth/service/interfaces/IRegistrationService.java
similarity index 94%
rename from src/main/java/com/netgrif/application/engine/auth/service/interfaces/IRegistrationService.java
rename to application-engine/src/main/java/com/netgrif/application/engine/auth/service/interfaces/IRegistrationService.java
index 4558765f277..d1e86190c47 100644
--- a/src/main/java/com/netgrif/application/engine/auth/service/interfaces/IRegistrationService.java
+++ b/application-engine/src/main/java/com/netgrif/application/engine/auth/service/interfaces/IRegistrationService.java
@@ -1,6 +1,6 @@
package com.netgrif.application.engine.auth.service.interfaces;
-import com.netgrif.application.engine.auth.domain.RegisteredUser;
+import com.netgrif.application.engine.objects.auth.domain.RegisteredUser;
import com.netgrif.application.engine.auth.service.InvalidUserTokenException;
import com.netgrif.application.engine.auth.web.requestbodies.NewUserRequest;
import com.netgrif.application.engine.auth.web.requestbodies.RegistrationRequest;
diff --git a/src/main/java/com/netgrif/application/engine/auth/service/interfaces/IUserResourceHelperService.java b/application-engine/src/main/java/com/netgrif/application/engine/auth/service/interfaces/IUserResourceHelperService.java
similarity index 78%
rename from src/main/java/com/netgrif/application/engine/auth/service/interfaces/IUserResourceHelperService.java
rename to application-engine/src/main/java/com/netgrif/application/engine/auth/service/interfaces/IUserResourceHelperService.java
index e62ee72c506..3ff460de86d 100644
--- a/src/main/java/com/netgrif/application/engine/auth/service/interfaces/IUserResourceHelperService.java
+++ b/application-engine/src/main/java/com/netgrif/application/engine/auth/service/interfaces/IUserResourceHelperService.java
@@ -1,7 +1,7 @@
package com.netgrif.application.engine.auth.service.interfaces;
-import com.netgrif.application.engine.auth.domain.IUser;
-import com.netgrif.application.engine.auth.domain.LoggedUser;
+import com.netgrif.application.engine.objects.auth.domain.IUser;
+import com.netgrif.application.engine.objects.auth.domain.LoggedUser;
import com.netgrif.application.engine.auth.web.responsebodies.User;
import com.netgrif.application.engine.auth.web.responsebodies.UserResource;
diff --git a/application-engine/src/main/java/com/netgrif/application/engine/auth/service/interfaces/IUserService.java b/application-engine/src/main/java/com/netgrif/application/engine/auth/service/interfaces/IUserService.java
new file mode 100644
index 00000000000..d9b513b4532
--- /dev/null
+++ b/application-engine/src/main/java/com/netgrif/application/engine/auth/service/interfaces/IUserService.java
@@ -0,0 +1,82 @@
+//package com.netgrif.application.engine.auth.service.interfaces;
+//
+//import com.netgrif.application.engine.objects.auth.domain.IUser;
+//import com.netgrif.application.engine.objects.auth.domain.IUser;
+//import com.netgrif.application.engine.objects.auth.domain.LoggedUser;
+//import com.netgrif.application.engine.objects.petrinet.domain.PetriNet;
+//import com.netgrif.application.engine.objects.petrinet.domain.roles.ProcessRole;
+//import com.netgrif.application.engine.objects.workflow.domain.ProcessResourceId;
+//import org.springframework.data.domain.Page;
+//import org.springframework.data.domain.Pageable;
+//import org.springframework.security.core.Authentication;
+//
+//import java.util.Collection;
+//import java.util.List;
+//import java.util.Set;
+//
+//public interface IUserService {
+//
+// IUser findByAuth(Authentication auth, String realmId);
+//
+// IUser saveUser(IUser user, String realmName);
+//
+// IUser saveNewAndAuthenticate(IUser user, String realmId);
+//
+// IUser saveNew(IUser user);
+//
+// AnonymousUser saveNewAnonymous(AnonymousUser user);
+//
+// IUser update(IUser user, IUser updates);
+//
+// IUser findById(String id, String realmId);
+//
+// IUser resolveById(String id, boolean small);
+//
+// IUser findUserByUsername(String username, String realmName);
+//
+// IUser findByEmail(String email, String realmId);
+//
+// List findAllUsers(String realmName);
+//
+// Page findAllCoMembers(LoggedUser loggedUser, Pageable pageable);
+//
+// List findAllByIds(Collection ids, String realmId);
+//
+// Page findAllActiveByProcessRoles(Set roleIds, Pageable pageable, String realmId);
+//
+// void addDefaultRole(IUser user);
+// void addAnonymousRole(IUser user);
+//
+// List findAllByProcessRoles(Set roleIds, String realmId);
+//
+// void addDefaultAuthorities(IUser user);
+//
+// IUser assignAuthority(String userId, String realmId, String authorityId);
+//
+// IUser getLoggedOrSystem();
+//
+// IUser getLoggedUser();
+//
+// IUser getSystem();
+//
+// LoggedUser getAnonymousLogged();
+//
+// LoggedUser getLoggedUserFromContext();
+//
+// IUser addRole(IUser user, String roleStringId);
+//
+// Page searchAllCoMembers(String query, LoggedUser principal, Pageable pageable);
+//
+// IUser removeRole(IUser user, String roleStringId);
+//
+// IUser removeRole(IUser user, ProcessRole processRole);
+//
+// void removeRoleOfDeletedPetriNet(PetriNet net, String realmId);
+//
+// void deleteUser(IUser user);
+//
+// Page searchAllCoMembers(String query, List roles, List negateRoleIds, LoggedUser principal, Pageable pageable);
+//
+// IUser createSystemUser();
+//
+//}
diff --git a/src/main/java/com/netgrif/application/engine/auth/web/AuthenticationController.java b/application-engine/src/main/java/com/netgrif/application/engine/auth/web/AuthenticationController.java
similarity index 85%
rename from src/main/java/com/netgrif/application/engine/auth/web/AuthenticationController.java
rename to application-engine/src/main/java/com/netgrif/application/engine/auth/web/AuthenticationController.java
index 9ff573d7c20..4bc297b71b5 100644
--- a/src/main/java/com/netgrif/application/engine/auth/web/AuthenticationController.java
+++ b/application-engine/src/main/java/com/netgrif/application/engine/auth/web/AuthenticationController.java
@@ -1,21 +1,20 @@
package com.netgrif.application.engine.auth.web;
-import com.netgrif.application.engine.auth.domain.LoggedUser;
-import com.netgrif.application.engine.auth.domain.RegisteredUser;
+import com.netgrif.application.engine.workflow.web.responsebodies.MessageResource;
+import com.netgrif.application.engine.objects.auth.domain.IUser;
+import com.netgrif.application.engine.objects.auth.domain.LoggedUser;
+import com.netgrif.application.engine.objects.auth.domain.RegisteredUser;
import com.netgrif.application.engine.auth.service.InvalidUserTokenException;
-import com.netgrif.application.engine.auth.service.UserDetailsServiceImpl;
import com.netgrif.application.engine.auth.service.interfaces.IRegistrationService;
-import com.netgrif.application.engine.auth.service.interfaces.IUserService;
+import com.netgrif.application.engine.auth.service.UserService;
import com.netgrif.application.engine.auth.web.requestbodies.ChangePasswordRequest;
import com.netgrif.application.engine.auth.web.requestbodies.NewUserRequest;
import com.netgrif.application.engine.auth.web.requestbodies.RegistrationRequest;
-import com.netgrif.application.engine.auth.web.responsebodies.IUserFactory;
-import com.netgrif.application.engine.auth.web.responsebodies.UserResource;
+import com.netgrif.application.engine.auth.service.UserFactory;
import com.netgrif.application.engine.configuration.properties.ServerAuthProperties;
import com.netgrif.application.engine.mail.interfaces.IMailAttemptService;
import com.netgrif.application.engine.mail.interfaces.IMailService;
import com.netgrif.application.engine.security.service.ISecurityContextService;
-import com.netgrif.application.engine.workflow.web.responsebodies.MessageResource;
import freemarker.template.TemplateException;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
@@ -25,15 +24,17 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.hateoas.MediaTypes;
+import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.*;
import java.io.IOException;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
-import java.util.Base64;
-import java.util.Locale;
+import java.util.*;
@Slf4j
@RestController
@@ -49,14 +50,11 @@ public class AuthenticationController {
@Autowired
private IRegistrationService registrationService;
- @Autowired
- private UserDetailsServiceImpl userDetailsService;
-
@Autowired
private IMailService mailService;
@Autowired
- private IUserService userService;
+ private UserService userService;
@Autowired
private IMailAttemptService mailAttemptService;
@@ -65,7 +63,7 @@ public class AuthenticationController {
private ServerAuthProperties serverAuthProperties;
@Autowired
- private IUserFactory userResponseFactory;
+ private UserFactory userResponseFactory;
@Autowired
private ISecurityContextService securityContextService;
@@ -139,8 +137,17 @@ public MessageResource verifyAuthToken(Authentication auth) {
@Operation(summary = "Login to the system", security = {@SecurityRequirement(name = "BasicAuth")})
@GetMapping(value = "/login", produces = MediaTypes.HAL_JSON_VALUE)
- public UserResource login(Authentication auth, Locale locale) {
- return new UserResource(userResponseFactory.getUser(userService.findByAuth(auth), locale), "profile");
+ public ResponseEntity> login(Authentication auth, Locale locale) {
+ log.info("login");
+ log.debug("locale: {}", locale);
+ log.debug("auth: {}", auth);
+
+ Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
+ if (authentication == null) {
+ return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
+ }
+ LoggedUser loggedUser = (LoggedUser) authentication.getPrincipal();
+ return ResponseEntity.ok(userResponseFactory.getUser(userService.findById(loggedUser.getId(), null), locale));
}
@Operation(summary = "Reset password")
@@ -184,8 +191,8 @@ public MessageResource recoverAccount(@RequestBody RegistrationRequest request)
@PostMapping(value = "/changePassword", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaTypes.HAL_JSON_VALUE)
public MessageResource changePassword(Authentication auth, @RequestBody ChangePasswordRequest request) {
try {
- RegisteredUser user = (RegisteredUser) userService.findByEmail(request.login, false);
- if (user == null || request.password == null || request.newPassword == null) {
+ Optional user = userService.findUserByUsername(request.login, null);
+ if (user.isEmpty() || request.password == null || request.newPassword == null) {
return MessageResource.errorMessage("Incorrect login!");
}
@@ -195,8 +202,8 @@ public MessageResource changePassword(Authentication auth, @RequestBody ChangePa
}
String password = new String(Base64.getDecoder().decode(request.password));
- if (registrationService.stringMatchesUserPassword(user, password)) {
- registrationService.changePassword(user, newPassword);
+ if (registrationService.stringMatchesUserPassword((RegisteredUser) user.get(), password)) {
+ registrationService.changePassword(((RegisteredUser) user.get()), newPassword);
securityContextService.saveToken(((LoggedUser) auth.getPrincipal()).getId());
securityContextService.reloadSecurityContext((LoggedUser) auth.getPrincipal());
@@ -210,4 +217,4 @@ public MessageResource changePassword(Authentication auth, @RequestBody ChangePa
return MessageResource.errorMessage("There has been a problem!");
}
}
-}
\ No newline at end of file
+}
diff --git a/application-engine/src/main/java/com/netgrif/application/engine/auth/web/PublicUserController.java b/application-engine/src/main/java/com/netgrif/application/engine/auth/web/PublicUserController.java
new file mode 100644
index 00000000000..b473cd1ba53
--- /dev/null
+++ b/application-engine/src/main/java/com/netgrif/application/engine/auth/web/PublicUserController.java
@@ -0,0 +1,147 @@
+package com.netgrif.application.engine.auth.web;
+
+import com.netgrif.application.engine.auth.service.PreferencesService;
+import com.netgrif.application.engine.auth.web.requestbodies.PreferencesRequest;
+import com.netgrif.application.engine.auth.web.responsebodies.*;
+import com.netgrif.application.engine.objects.auth.domain.LoggedUser;
+import com.netgrif.application.engine.objects.preferences.Preferences;
+import com.netgrif.application.engine.workflow.web.responsebodies.MessageResource;
+import com.netgrif.application.engine.workflow.web.responsebodies.ResourceLinkAssembler;
+import com.netgrif.application.engine.objects.auth.domain.IUser;
+import com.netgrif.application.engine.auth.service.UserService;
+import com.netgrif.application.engine.auth.web.requestbodies.UserSearchRequestBody;
+import com.netgrif.application.engine.objects.workflow.domain.ProcessResourceId;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.responses.ApiResponses;
+import io.swagger.v3.oas.annotations.security.SecurityRequirement;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.ObjectFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageImpl;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.web.PagedResourcesAssembler;
+import org.springframework.hateoas.Link;
+import org.springframework.hateoas.MediaTypes;
+import org.springframework.hateoas.PagedModel;
+import org.springframework.hateoas.server.mvc.WebMvcLinkBuilder;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.security.core.Authentication;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+import java.util.Locale;
+import java.util.stream.Collectors;
+
+@Slf4j
+@RestController
+@ConditionalOnProperty(
+ value = "nae.public.user.web.enabled",
+ havingValue = "true",
+ matchIfMissing = true
+)
+@Tag(name = "Public User Controller")
+@RequestMapping("/api/public/user")
+public class PublicUserController {
+
+ @Autowired
+ private UserService userService;
+
+ @Autowired
+ private PreferencesService preferencesService;
+
+ @Operation(summary = "Get logged user", description = "Retrieves information of currently logged user")
+ @ApiResponses(value = {
+ @ApiResponse(responseCode = "200", description = "User retrieved successfully"),
+ @ApiResponse(responseCode = "400", description = "Invalid user data"),
+ @ApiResponse(responseCode = "500", description = "Internal server error")
+ })
+ @GetMapping(value = "/me", produces = MediaType.APPLICATION_JSON_VALUE)
+ public ResponseEntity getLoggedUser(Authentication auth) {
+ LoggedUser loggedUser = (LoggedUser) auth.getPrincipal();
+ IUser user;
+ try {
+ user = userService.findById(loggedUser.getId(), loggedUser.getRealmId());
+ if (user == null) {
+ return ResponseEntity
+ .status(HttpStatus.UNAUTHORIZED).build();
+ }
+ } catch (IllegalArgumentException e) {
+ log.error("Could not find user with id [{}]", loggedUser.getId(), e);
+ return ResponseEntity.status(HttpStatus.BAD_REQUEST).build();
+ }
+
+ return ResponseEntity.ok(User.createUser(user));
+ }
+
+ @ApiResponses(value = {
+ @ApiResponse(responseCode = "200", description = "User retrieved successfully"),
+ @ApiResponse(responseCode = "400", description = "Invalid user data"),
+ @ApiResponse(responseCode = "500", description = "Internal server error")
+ })
+ @Operation(summary = "Generic user search", security = {@SecurityRequirement(name = "X-Auth-Token")})
+ @PostMapping(value = "/search", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
+ public ResponseEntity> search(@RequestBody UserSearchRequestBody query, Pageable pageable, Authentication auth) {
+ List roles = query.getRoles() == null ? null : query.getRoles().stream().map(ProcessResourceId::new).toList();
+ List negativeRoles = query.getNegativeRoles() == null ? null : query.getNegativeRoles().stream().map(ProcessResourceId::new).toList();
+ Page users = userService.searchAllCoMembers(query.getFulltext(),
+ roles,
+ negativeRoles,
+ (LoggedUser) auth.getPrincipal(), pageable);
+ return ResponseEntity.ok(changeToResponse(users, pageable));
+ }
+
+ @Operation(summary = "Get logged user's preferences", security = {@SecurityRequirement(name = "X-Auth-Token")})
+ @ApiResponses(value = {
+ @ApiResponse(responseCode = "200", description = "Returns preferences of logged user"),
+ @ApiResponse(responseCode = "403", description = "Caller doesn't fulfill the authorisation requirements"),
+ @ApiResponse(responseCode = "500", description = "Internal server error")
+ })
+ @GetMapping(value = "/preferences", produces = MediaType.APPLICATION_JSON_VALUE)
+ public ResponseEntity preferences(Authentication auth) {
+ String userId = ((LoggedUser) auth.getPrincipal()).getId();
+ Preferences preferences = preferencesService.get(userId);
+
+ if (preferences == null) {
+ preferences = new com.netgrif.application.engine.adapter.spring.preferences.Preferences(userId);
+ }
+ PreferencesResource preferencesResource = PreferencesResource.withPreferences(preferences);
+
+ return ResponseEntity.ok(preferencesResource);
+ }
+
+
+ @Operation(summary = "Set preferences of logged user", security = {@SecurityRequirement(name = "X-Auth-Token")})
+ @ApiResponses(value = {
+ @ApiResponse(responseCode = "200", description = "Saves preferences of logged user"),
+ @ApiResponse(responseCode = "400", description = "Preferences data are invalid"),
+ @ApiResponse(responseCode = "403", description = "Caller doesn't fulfill the authorisation requirements"),
+ @ApiResponse(responseCode = "500", description = "Internal server error")
+ })
+ @PostMapping(value = "/preferences", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
+ public ResponseEntity savePreferences(@RequestBody PreferencesRequest preferences, Authentication auth) {
+ try {
+ String userId = ((LoggedUser) auth.getPrincipal()).getId();
+ preferences.setUserId(userId);
+ preferencesService.save(preferences.toPreferences());
+ return ResponseEntity.ok("User preferences saved");
+ } catch (Exception e) {
+ log.error("Saving user preferences failed", e);
+ return ResponseEntity.badRequest().body("Saving user preferences failed");
+ }
+ }
+
+ private Page changeToResponse(Page users, Pageable pageable) {
+ return new PageImpl<>(changeType(users.getContent()), pageable, users.getTotalElements());
+ }
+
+ public List changeType(List users) {
+ return users.stream().map(User::createUser).toList();
+ }
+
+}
diff --git a/application-engine/src/main/java/com/netgrif/application/engine/auth/web/UserController.java b/application-engine/src/main/java/com/netgrif/application/engine/auth/web/UserController.java
new file mode 100644
index 00000000000..d5dda0d26bc
--- /dev/null
+++ b/application-engine/src/main/java/com/netgrif/application/engine/auth/web/UserController.java
@@ -0,0 +1,338 @@
+package com.netgrif.application.engine.auth.web;
+
+import com.netgrif.application.engine.adapter.spring.common.web.responsebodies.ResponseMessage;
+import com.netgrif.application.engine.adapter.spring.petrinet.service.ProcessRoleService;
+import com.netgrif.application.engine.auth.service.*;
+import com.netgrif.application.engine.auth.web.requestbodies.PreferencesRequest;
+import com.netgrif.application.engine.auth.web.requestbodies.UserCreateRequest;
+import com.netgrif.application.engine.auth.web.requestbodies.UserSearchRequestBody;
+import com.netgrif.application.engine.auth.web.responsebodies.PreferencesResource;
+import com.netgrif.application.engine.auth.web.responsebodies.User;
+import com.netgrif.application.engine.objects.auth.domain.Authority;
+import com.netgrif.application.engine.objects.auth.domain.IUser;
+import com.netgrif.application.engine.objects.auth.domain.LoggedUser;
+import com.netgrif.application.engine.objects.auth.domain.Realm;
+import com.netgrif.application.engine.objects.preferences.Preferences;
+import com.netgrif.application.engine.objects.workflow.domain.ProcessResourceId;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.responses.ApiResponses;
+import io.swagger.v3.oas.annotations.security.SecurityRequirement;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageImpl;
+import org.springframework.data.domain.Pageable;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.security.core.Authentication;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.*;
+import java.util.stream.Collectors;
+
+
+@Slf4j
+@RestController
+@RequestMapping("api/users")
+@Tag(name = "UserController")
+@ConditionalOnProperty(
+ value = "nae.user.web.enabled",
+ havingValue = "true",
+ matchIfMissing = true
+)
+@RequiredArgsConstructor
+public class UserController {
+
+ private final UserService userService;
+ private final ProcessRoleService processRoleService;
+ private final PreferencesService preferencesService;
+ private final AuthorityService authorityService;
+ private final RealmService realmService;
+ private final UserFactory userFactory;
+
+ @Operation(summary = "Create a new user", description = "Creates a new user in the realm specified by id.")
+ @ApiResponses(value = {
+ @ApiResponse(responseCode = "201", description = "User successfully created"),
+ @ApiResponse(responseCode = "400", description = "Invalid user data"),
+ @ApiResponse(responseCode = "409", description = "Conflict – user already exists"),
+ @ApiResponse(responseCode = "500", description = "Internal server error")
+ })
+ @PostMapping("/{realmId}")
+ public ResponseEntity createUser(@PathVariable String realmId, @RequestBody UserCreateRequest request, Locale locale) {
+ try {
+ if (!realmExists(realmId)) {
+ log.error("Realm with id [{}] not found", realmId);
+ return ResponseEntity.badRequest().build();
+ }
+ if (userService.findUserByUsername(request.getUsername(), realmId).isPresent()) {
+ log.error("User with username [{}] already exists in realm [{}]", request.getUsername(), realmId);
+ return ResponseEntity.status(HttpStatus.CONFLICT).build();
+ }
+ IUser user = userService.createUser(
+ request.getUsername(),
+ request.getEmail(),
+ request.getFirstName(),
+ request.getLastName(),
+ request.getPassword(),
+ realmId
+ );
+ log.info("New user with username [{}] has been created in realm [{}]", request.getUsername(), realmId);
+ return ResponseEntity.status(HttpStatus.CREATED).body(userFactory.getUser(user, locale));
+ } catch (Exception e) {
+ log.error("Failed to create user", e);
+ return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
+ }
+ }
+
+ @Operation(summary = "Get page of users from realm", description = "Retrieves page of users from defined realm")
+ @ApiResponses(value = {
+ @ApiResponse(responseCode = "200", description = "User retrieved successfully"),
+ @ApiResponse(responseCode = "400", description = "Invalid user data"),
+ @ApiResponse(responseCode = "500", description = "Internal server error")
+ })
+ @GetMapping("/{realmId}/all")
+ public ResponseEntity> getAllUsers(@PathVariable String realmId, Pageable pageable, Locale locale) {
+ if (!realmExists(realmId)) {
+ log.error("Realm with id [{}] not found", realmId);
+ return ResponseEntity.badRequest().build();
+ }
+ Page users = userService.findAllUsers(realmId, pageable);
+ return ResponseEntity.ok(changeToResponse(users, pageable, locale));
+ }
+
+ @Operation(summary = "Get logged user", description = "Retrieves information of currently logged user")
+ @ApiResponses(value = {
+ @ApiResponse(responseCode = "200", description = "User retrieved successfully"),
+ @ApiResponse(responseCode = "400", description = "Invalid user data"),
+ @ApiResponse(responseCode = "500", description = "Internal server error")
+ })
+ @GetMapping(value = "/me", produces = MediaType.APPLICATION_JSON_VALUE)
+ public ResponseEntity getLoggedUser(Authentication auth, Locale locale) {
+ LoggedUser loggedUser = (LoggedUser) auth.getPrincipal();
+ IUser user;
+ try {
+ user = userService.findById(loggedUser.getId(), loggedUser.getRealmId());
+ if (user == null) {
+ return ResponseEntity
+ .status(HttpStatus.UNAUTHORIZED).build();
+ }
+ } catch (IllegalArgumentException e) {
+ log.error("Could not find user with id [{}]", loggedUser.getId(), e);
+ return ResponseEntity.status(HttpStatus.BAD_REQUEST).build();
+ }
+
+ return ResponseEntity.ok(userFactory.getUser(user, locale));
+ }
+
+ @ApiResponses(value = {
+ @ApiResponse(responseCode = "200", description = "User retrieved successfully"),
+ @ApiResponse(responseCode = "400", description = "Invalid user data"),
+ @ApiResponse(responseCode = "500", description = "Internal server error")
+ })
+ @Operation(summary = "Generic user search", security = {@SecurityRequirement(name = "X-Auth-Token")})
+ @PostMapping(value = "/search", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
+ public ResponseEntity> search(@RequestBody UserSearchRequestBody query, Pageable pageable, Authentication auth, Locale locale) {
+ List roles = query.getRoles() == null ? null : query.getRoles().stream().map(ProcessResourceId::new).toList();
+ List negativeRoles = query.getNegativeRoles() == null ? null : query.getNegativeRoles().stream().map(ProcessResourceId::new).toList();
+ Page users = userService.searchAllCoMembers(query.getFulltext(),
+ roles,
+ negativeRoles,
+ (LoggedUser) auth.getPrincipal(), pageable);
+ return ResponseEntity.ok(changeToResponse(users, pageable, locale));
+ }
+
+ @Operation(summary = "Get user by id", description = "Retrieves information of user defined by given id")
+ @ApiResponses(value = {
+ @ApiResponse(responseCode = "200", description = "User retrieved successfully"),
+ @ApiResponse(responseCode = "400", description = "User with given id does not exist in given realm"),
+ @ApiResponse(responseCode = "401", description = "User trying to retrieved information is not admin"),
+ @ApiResponse(responseCode = "500", description = "Internal server error")
+ })
+ @GetMapping(value = "/{realmId}/{id}", produces = MediaType.APPLICATION_JSON_VALUE)
+ public ResponseEntity getUser(@PathVariable("realmId") String realmId, @PathVariable("id") String userId, Locale locale) {
+ LoggedUser actualUser = userService.getLoggedUserFromContext();
+ LoggedUser loggedUser = actualUser.getSelfOrImpersonated();
+ if (!loggedUser.isAdmin() && !Objects.equals(loggedUser.getId(), userId)) {
+ log.info("User [{}] trying to get another user with ID [{}]", actualUser.getUsername(), userId);
+ return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
+ }
+ IUser user;
+ try {
+ user = userService.findById(userId, realmId);
+ } catch (IllegalArgumentException e) {
+ return ResponseEntity.status(HttpStatus.BAD_REQUEST).build();
+ }
+ return ResponseEntity.ok(userFactory.getUser(user, locale));
+ }
+
+// todo step 2, only used in test on frontend
+// @Operation(summary = "Update user", security = {@SecurityRequirement(name = "X-Auth-Token")})
+// @PostMapping(value = "/update", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
+// public ResponseEntity updateUser(@RequestBody UpdateUserRequest updates, Authentication auth, Locale locale) {
+
+ /// / todo should this be kept? not relevant anymore?
+// if (!serverAuthProperties.isEnableProfileEdit()) {
+// return null;
+// }
+// LoggedUser loggedUser = (LoggedUser) auth.getPrincipal();
+// String userId = updates.getStringId();
+// IUser user;
+// try {
+// user = userService.findById(userId, updatedUser.getRealmId());
+// } catch (IllegalArgumentException e) {
+// log.error("Could not find user with id [{}]", userId, e);
+// return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(null);
+// }
+// user = userService.update(user, updates.getUpdatedUser());
+// securityContextService.saveToken(userId);
+// if (Objects.equals(loggedUser.getId(), userId)) {
+// loggedUser.setFirstName(user.getFirstName());
+// loggedUser.setLastName(user.getLastName());
+// securityContextService.reloadSecurityContext(loggedUser);
+// }
+// log.info("Updating user " + user.getEmail() + " with data " + updatedUser);
+// return ResponseEntity.ok(User.createUser(user));
+// }
+
+// todo not used on front, is it needed?
+// @Operation(summary = "Get all users with specified roles", security = {@SecurityRequirement(name = "X-Auth-Token")})
+// @PostMapping(value = "/role", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
+// public ResponseEntity> getAllWithRole(@RequestBody Set roleIds, Pageable pageable, Locale locale) {
+// Set roleResourceIds = roleIds == null ? null : roleIds.stream().map(ProcessResourceId::new).collect(Collectors.toSet());
+// Page page = userService.findAllActiveByProcessRoles(roleResourceIds, pageable);
+// return ResponseEntity.ok();
+// }
+ @Operation(summary = "Assign roles to the user", description = "Caller must have the ADMIN role", security = {@SecurityRequirement(name = "X-Auth-Token")})
+ @PutMapping(value = "/{realmId}/{id}/roles", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
+ @ApiResponses(value = {
+ @ApiResponse(responseCode = "200", description = "Selected roles assigned successfully"),
+ @ApiResponse(responseCode = "400", description = "Requested roles or user with defined id does not exist"),
+ @ApiResponse(responseCode = "403", description = "Caller doesn't fulfill the authorisation requirements"),
+ @ApiResponse(responseCode = "500", description = "Internal server error")
+ })
+ public ResponseEntity assignRolesToUser(@PathVariable("realmId") String realmId, @PathVariable("id") String userId, @RequestBody Set roleIds, Authentication auth) {
+ try {
+ IUser user = userService.findById(userId, realmId);
+ processRoleService.assignRolesToUser(user, roleIds.stream().map(ProcessResourceId::new).collect(Collectors.toSet()), (LoggedUser) auth.getPrincipal());
+ log.info("Process roles {} assigned to user with id [{}]", roleIds, userId);
+ return ResponseEntity.ok(ResponseMessage.createSuccessMessage("Selected roles assigned to user " + userId));
+ } catch (IllegalArgumentException e) {
+ String message = "Assigning roles to user [" + userId + "] has failed!";
+ log.error(message, e);
+ return ResponseEntity.badRequest().body(ResponseMessage.createErrorMessage("Assigning roles to user " + userId + " has failed!"));
+ }
+ }
+
+ @PreAuthorize("@authorizationService.hasAuthority('ADMIN')")
+ @Operation(summary = "Assign negative roles to the user", description = "Caller must have the ADMIN role", security = {@SecurityRequirement(name = "X-Auth-Token")})
+ @PutMapping(value = "/{realmId}/{id}/negativeRole", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
+ @ApiResponses(value = {
+ @ApiResponse(responseCode = "200", description = "Selected negative roles assigned successfully"),
+ @ApiResponse(responseCode = "400", description = "Requested roles or user with defined id does not exist"),
+ @ApiResponse(responseCode = "403", description = "Caller doesn't fulfill the authorisation requirements"),
+ @ApiResponse(responseCode = "500", description = "Internal server error")
+ })
+ public ResponseEntity assignNegativeRolesToUser(@PathVariable("realmId") String realmId, @PathVariable("id") String userId, @RequestBody Set roleIds, Authentication auth) {
+ try {
+ IUser user = userService.findById(userId, realmId);
+ processRoleService.assignNegativeRolesToUser(user, roleIds.stream().map(ProcessResourceId::new).collect(Collectors.toSet()), (LoggedUser) auth.getPrincipal());
+ log.info("Negative process roles {} assigned to user [{}]", roleIds, userId);
+ return ResponseEntity.ok(ResponseMessage.createSuccessMessage("Selected negative roles assigned to user " + userId));
+ } catch (IllegalArgumentException e) {
+ log.error("Assigning negative roles to user with id [{}] has failed!", userId, e);
+ return ResponseEntity.badRequest().body(ResponseMessage.createErrorMessage("Assigning negative roles to user " + userId + " has failed!"));
+ }
+ }
+
+ @PreAuthorize("@authorizationService.hasAuthority('ADMIN')")
+ @Operation(summary = "Get all authorities of the system",
+ description = "Caller must have the ADMIN role",
+ security = {@SecurityRequirement(name = "X-Auth-Token")})
+ @GetMapping(value = "/authority", produces = MediaType.APPLICATION_JSON_VALUE)
+ @ApiResponses(value = {
+ @ApiResponse(responseCode = "200", description = "OK"),
+ @ApiResponse(responseCode = "403", description = "Caller doesn't fulfill the authorisation requirements"),
+ @ApiResponse(responseCode = "500", description = "Internal server error")
+ })
+ public ResponseEntity> getAllAuthorities() {
+ return ResponseEntity.ok(authorityService.findAll());
+ }
+
+ @PreAuthorize("@authorizationService.hasAuthority('ADMIN')")
+ @Operation(summary = "Assign authority to the user",
+ description = "Caller must have the ADMIN role",
+ security = {@SecurityRequirement(name = "X-Auth-Token")})
+ @ApiResponses(value = {
+ @ApiResponse(responseCode = "200", description = "Authority was assigned to user successfully"),
+ @ApiResponse(responseCode = "400", description = "Authority with given id or user with given id does not exist"),
+ @ApiResponse(responseCode = "403", description = "Caller doesn't fulfill the authorisation requirements"),
+ @ApiResponse(responseCode = "500", description = "Internal server error")
+ })
+ @PostMapping(value = "/{realmId}/{id}/authority", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
+ public ResponseEntity assignAuthorityToUser(@PathVariable("realmId") String realmId, @PathVariable("id") String userId, @RequestBody String authorityId) {
+ try {
+ userService.assignAuthority(userId, realmId, authorityId);
+ } catch (IllegalArgumentException e) {
+ log.error("Assigning authority to user [{}] has failed!", userId, e);
+ return ResponseEntity.badRequest().body(ResponseMessage.createSuccessMessage("Assigning authority to user " + userId + " has failed!"));
+ }
+ return ResponseEntity.ok(ResponseMessage.createErrorMessage("Authority was assigned to user successfully"));
+ }
+
+ @Operation(summary = "Get logged user's preferences", security = {@SecurityRequirement(name = "X-Auth-Token")})
+ @ApiResponses(value = {
+ @ApiResponse(responseCode = "200", description = "Returns preferences of logged user"),
+ @ApiResponse(responseCode = "403", description = "Caller doesn't fulfill the authorisation requirements"),
+ @ApiResponse(responseCode = "500", description = "Internal server error")
+ })
+ @GetMapping(value = "/preferences", produces = MediaType.APPLICATION_JSON_VALUE)
+ public ResponseEntity preferences(Authentication auth) {
+ String userId = ((LoggedUser) auth.getPrincipal()).getId();
+ Preferences preferences = preferencesService.get(userId);
+
+ if (preferences == null) {
+ preferences = new com.netgrif.application.engine.adapter.spring.preferences.Preferences(userId);
+ }
+ PreferencesResource preferencesResource = PreferencesResource.withPreferences(preferences);
+
+ return ResponseEntity.ok(preferencesResource);
+ }
+
+ @Operation(summary = "Set preferences of logged user", security = {@SecurityRequirement(name = "X-Auth-Token")})
+ @ApiResponses(value = {
+ @ApiResponse(responseCode = "200", description = "Saves preferences of logged user"),
+ @ApiResponse(responseCode = "400", description = "Preferences data are invalid"),
+ @ApiResponse(responseCode = "403", description = "Caller doesn't fulfill the authorisation requirements"),
+ @ApiResponse(responseCode = "500", description = "Internal server error")
+ })
+ @PostMapping(value = "/preferences", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
+ public ResponseEntity savePreferences(@RequestBody PreferencesRequest preferences, Authentication auth) {
+ try {
+ String userId = ((LoggedUser) auth.getPrincipal()).getId();
+ preferences.setUserId(userId);
+ preferencesService.save(preferences.toPreferences());
+ return ResponseEntity.ok(ResponseMessage.createSuccessMessage("User preferences saved"));
+ } catch (Exception e) {
+ log.error("Saving user preferences failed", e);
+ return ResponseEntity.badRequest().body(ResponseMessage.createErrorMessage("Saving user preferences failed"));
+ }
+ }
+
+ private Page changeToResponse(Page users, Pageable pageable, Locale locale) {
+ return new PageImpl<>(changeType(users.getContent(), locale), pageable, users.getTotalElements());
+ }
+
+ public List changeType(List users, Locale locale) {
+ return users.stream().map(u -> userFactory.getUser(u, locale)).toList();
+ }
+
+ private boolean realmExists(String realmId) {
+ Optional realm = realmService.getRealmById(realmId);
+ return realm.isPresent();
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/netgrif/application/engine/auth/web/UserControllerAdvice.java b/application-engine/src/main/java/com/netgrif/application/engine/auth/web/UserControllerAdvice.java
similarity index 100%
rename from src/main/java/com/netgrif/application/engine/auth/web/UserControllerAdvice.java
rename to application-engine/src/main/java/com/netgrif/application/engine/auth/web/UserControllerAdvice.java
diff --git a/src/main/java/com/netgrif/application/engine/auth/web/requestbodies/ChangePasswordRequest.java b/application-engine/src/main/java/com/netgrif/application/engine/auth/web/requestbodies/ChangePasswordRequest.java
similarity index 100%
rename from src/main/java/com/netgrif/application/engine/auth/web/requestbodies/ChangePasswordRequest.java
rename to application-engine/src/main/java/com/netgrif/application/engine/auth/web/requestbodies/ChangePasswordRequest.java
diff --git a/src/main/java/com/netgrif/application/engine/auth/web/requestbodies/NewUserRequest.java b/application-engine/src/main/java/com/netgrif/application/engine/auth/web/requestbodies/NewUserRequest.java
similarity index 100%
rename from src/main/java/com/netgrif/application/engine/auth/web/requestbodies/NewUserRequest.java
rename to application-engine/src/main/java/com/netgrif/application/engine/auth/web/requestbodies/NewUserRequest.java
diff --git a/src/main/java/com/netgrif/application/engine/auth/web/requestbodies/RegistrationRequest.java b/application-engine/src/main/java/com/netgrif/application/engine/auth/web/requestbodies/RegistrationRequest.java
similarity index 100%
rename from src/main/java/com/netgrif/application/engine/auth/web/requestbodies/RegistrationRequest.java
rename to application-engine/src/main/java/com/netgrif/application/engine/auth/web/requestbodies/RegistrationRequest.java
diff --git a/application-engine/src/main/java/com/netgrif/application/engine/auth/web/requestbodies/UpdateUserRequest.java b/application-engine/src/main/java/com/netgrif/application/engine/auth/web/requestbodies/UpdateUserRequest.java
new file mode 100644
index 00000000000..e2f12db51a7
--- /dev/null
+++ b/application-engine/src/main/java/com/netgrif/application/engine/auth/web/requestbodies/UpdateUserRequest.java
@@ -0,0 +1,352 @@
+package com.netgrif.application.engine.auth.web.requestbodies;
+
+import com.netgrif.application.engine.objects.auth.domain.*;
+import com.netgrif.application.engine.objects.auth.domain.enums.UserState;
+import com.netgrif.application.engine.objects.petrinet.domain.roles.ProcessRole;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.time.LocalDateTime;
+import java.util.Map;
+import java.util.Set;
+
+@Setter
+@Getter
+public class UpdateUserRequest implements IUser, Serializable {
+
+ @Serial
+ private static final long serialVersionUID = 3681503301565489613L;
+
+ public String telNumber;
+
+ public String avatar;
+
+ public String name;
+
+ public String surname;
+
+ public UpdateUserRequest() {
+ }
+
+ @Override
+ public String getEmail() {
+ return "";
+ }
+
+ @Override
+ public void setEmail(String s) {
+
+ }
+
+ @Override
+ public String getRealmId() {
+ return "";
+ }
+
+ @Override
+ public void setRealmId(String s) {
+
+ }
+
+ @Override
+ public String getUsername() {
+ return "";
+ }
+
+ @Override
+ public void setUsername(String s) {
+
+ }
+
+ @Override
+ public String getFirstName() {
+ return "";
+ }
+
+ @Override
+ public void setFirstName(String s) {
+
+ }
+
+ @Override
+ public String getLastName() {
+ return "";
+ }
+
+ @Override
+ public void setLastName(String s) {
+
+ }
+
+ @Override
+ public String getFullName() {
+ return "";
+ }
+
+ @Override
+ public UserState getState() {
+ return null;
+ }
+
+ @Override
+ public void setState(UserState userState) {
+
+ }
+
+ @Override
+ public LoggedUser transformToLoggedUser() {
+ return null;
+ }
+
+ @Override
+ public Author transformToAuthor() {
+ return null;
+ }
+
+ @Override
+ public boolean isActive() {
+ return false;
+ }
+
+ @Override
+ public boolean isImpersonating() {
+ return false;
+ }
+
+ @Override
+ public LocalDateTime getCreatedAt() {
+ return null;
+ }
+
+ @Override
+ public Map> getAttributes() {
+ return Map.of();
+ }
+
+ @Override
+ public boolean isEnabled() {
+ return false;
+ }
+
+ @Override
+ public boolean isEmailVerified() {
+ return false;
+ }
+
+ @Override
+ public IUser getSelfOrImpersonated() {
+ return null;
+ }
+
+ @Override
+ public IUser getImpersonated() {
+ return null;
+ }
+
+ @Override
+ public void setImpersonated(IUser iUser) {
+
+ }
+
+ @Override
+ public void enableMFA(String s, String s1, int i) {
+
+ }
+
+ @Override
+ public void disableMFA(String s) {
+
+ }
+
+ @Override
+ public Set getEnabledMFAMethods() {
+ return Set.of();
+ }
+
+ @Override
+ public boolean isMFAEnabled(String s) {
+ return false;
+ }
+
+ @Override
+ public void activateMFA(String s, String s1) {
+
+ }
+
+ @Override
+ public void activateMFA(String s, String s1, boolean b) {
+
+ }
+
+ @Override
+ public boolean validateRequiredAttributes() {
+ return false;
+ }
+
+ @Override
+ public Credential getCredential(String s) {
+ return null;
+ }
+
+ @Override
+ public Object getCredentialValue(String s) {
+ return null;
+ }
+
+ @Override
+ public void setCredential(String s, String s1, int i, boolean b) {
+
+ }
+
+ @Override
+ public void addCredential(Credential> credential) {
+
+ }
+
+ @Override
+ public void setCredentialProperty(String s, String s1, Object o) {
+
+ }
+
+ @Override
+ public Object getCredentialProperty(String s, String s1) {
+ return null;
+ }
+
+ @Override
+ public void removeCredential(String s) {
+
+ }
+
+ @Override
+ public boolean hasCredential(String s) {
+ return false;
+ }
+
+ @Override
+ public String getStringId() {
+ return "";
+ }
+
+ @Override
+ public Set getAuthorities() {
+ return Set.of();
+ }
+
+ @Override
+ public void setAuthorities(Set set) {
+
+ }
+
+ @Override
+ public Set getProcessRoles() {
+ return Set.of();
+ }
+
+ @Override
+ public Set getNegativeProcessRoles() {
+ return Set.of();
+ }
+
+ @Override
+ public void setNegativeProcessRoles(Set processRoles) {
+
+ }
+
+ @Override
+ public void setProcessRoles(Set set) {
+
+ }
+
+ @Override
+ public Set getGroupIds() {
+ return Set.of();
+ }
+
+ @Override
+ public Set getGroups() {
+ return Set.of();
+ }
+
+ @Override
+ public void setGroupIds(Set set) {
+
+ }
+
+ @Override
+ public void addGroupId(String s) {
+
+ }
+
+ @Override
+ public void removeGroupId(String s) {
+
+ }
+
+ @Override
+ public void addAuthority(Authority authority) {
+
+ }
+
+ @Override
+ public void removeAuthority(Authority authority) {
+
+ }
+
+ @Override
+ public void addProcessRole(ProcessRole processRole) {
+
+ }
+
+ @Override
+ public void removeProcessRole(ProcessRole processRole) {
+
+ }
+
+ @Override
+ public void addNegativeProcessRole(ProcessRole role) {
+
+ }
+
+ @Override
+ public void removeNegativeProcessRole(ProcessRole role) {
+
+ }
+
+ @Override
+ public void setAttribute(String s, Object o, boolean b) {
+
+ }
+
+ @Override
+ public Object getAttributeValue(String s) {
+ return null;
+ }
+
+ @Override
+ public void removeAttribute(String s) {
+
+ }
+
+ @Override
+ public boolean isAttributeSet(String s) {
+ return false;
+ }
+
+ @Override
+ public Attribute> getAttribute(String s) {
+ return null;
+ }
+
+ @Override
+ public String toString() {
+ return "UpdateUserRequest{" +
+ "telNumber='" + telNumber + '\'' +
+ ", avatar='" + avatar + '\'' +
+ ", name='" + name + '\'' +
+ ", surname='" + surname + '\'' +
+ '}';
+ }
+}
diff --git a/application-engine/src/main/java/com/netgrif/application/engine/auth/web/requestbodies/UserSearchRequestBody.java b/application-engine/src/main/java/com/netgrif/application/engine/auth/web/requestbodies/UserSearchRequestBody.java
new file mode 100644
index 00000000000..8317cb49181
--- /dev/null
+++ b/application-engine/src/main/java/com/netgrif/application/engine/auth/web/requestbodies/UserSearchRequestBody.java
@@ -0,0 +1,15 @@
+//package com.netgrif.application.engine.auth.web.requestbodies;
+//
+//import lombok.Data;
+//
+//import java.util.List;
+//
+//@Data
+//public class UserSearchRequestBody {
+//
+// private String fulltext;
+//
+// private List roles;
+//
+// private List negativeRoles;
+//}
\ No newline at end of file
diff --git a/application-engine/src/main/java/com/netgrif/application/engine/auth/web/responsebodies/AuthoritiesResources.java b/application-engine/src/main/java/com/netgrif/application/engine/auth/web/responsebodies/AuthoritiesResources.java
new file mode 100644
index 00000000000..3762f54057b
--- /dev/null
+++ b/application-engine/src/main/java/com/netgrif/application/engine/auth/web/responsebodies/AuthoritiesResources.java
@@ -0,0 +1,17 @@
+//package com.netgrif.application.engine.auth.web.responsebodies;
+//
+//
+//import com.netgrif.application.engine.objects.auth.domain.Authority;
+//import com.netgrif.application.engine.auth.web.UserController;
+//import org.springframework.hateoas.CollectionModel;
+//import org.springframework.hateoas.server.mvc.WebMvcLinkBuilder;
+//
+//public class AuthoritiesResources extends CollectionModel {
+// public AuthoritiesResources(Iterable content) {
+// super(content);
+// }
+//
+// public AuthoritiesResources() {
+// }
+//
+//}
diff --git a/application-engine/src/main/java/com/netgrif/application/engine/auth/web/responsebodies/IProcessRoleFactory.java b/application-engine/src/main/java/com/netgrif/application/engine/auth/web/responsebodies/IProcessRoleFactory.java
new file mode 100644
index 00000000000..3302cc2b4fc
--- /dev/null
+++ b/application-engine/src/main/java/com/netgrif/application/engine/auth/web/responsebodies/IProcessRoleFactory.java
@@ -0,0 +1,7 @@
+//package com.netgrif.application.engine.auth.web.responsebodies;
+//
+//import java.util.Locale;
+//
+//public interface IProcessRoleFactory {
+// ProcessRole getProcessRole(com.netgrif.application.engine.objects.petrinet.domain.roles.ProcessRole role, Locale locale);
+//}
diff --git a/application-engine/src/main/java/com/netgrif/application/engine/auth/web/responsebodies/IUserFactory.java b/application-engine/src/main/java/com/netgrif/application/engine/auth/web/responsebodies/IUserFactory.java
new file mode 100644
index 00000000000..a6514d7dc2d
--- /dev/null
+++ b/application-engine/src/main/java/com/netgrif/application/engine/auth/web/responsebodies/IUserFactory.java
@@ -0,0 +1,20 @@
+//package com.netgrif.application.engine.auth.web.responsebodies;
+//
+//import com.netgrif.application.engine.objects.auth.domain.IUser;
+//
+//import java.util.Locale;
+//
+//public interface UserFactory {
+// /**
+// * @param user the domain User object we want to send to frontend
+// * @param locale the locale for translations
+// * @return a full version of the user response object, that has all of its attributes set
+// */
+// User getUser(IUser user, Locale locale);
+//
+// /**
+// * @param user the domain User object we want to send to frontend
+// * @return a small version of the user response object, that has its large attributes (roles, groups, authorities...) cleared
+// */
+// User getSmallUser(IUser user);
+//}
diff --git a/application-engine/src/main/java/com/netgrif/application/engine/auth/web/responsebodies/ProcessRole.java b/application-engine/src/main/java/com/netgrif/application/engine/auth/web/responsebodies/ProcessRole.java
new file mode 100644
index 00000000000..46cf1061692
--- /dev/null
+++ b/application-engine/src/main/java/com/netgrif/application/engine/auth/web/responsebodies/ProcessRole.java
@@ -0,0 +1,36 @@
+//package com.netgrif.application.engine.auth.web.responsebodies;
+//
+//import lombok.Data;
+//
+//import java.util.Locale;
+//
+//@Data
+//public class ProcessRole {
+//
+// private String stringId;
+//
+// private String name;
+//
+// private String description;
+//
+// private String importId;
+//
+// // net attributes are set in the Factory service
+// private String netImportId;
+//
+// private String netVersion;
+//
+// private String netStringId;
+//
+// /**
+// * The constructor doesn't set attributes regarding the Petri net.
+// *
+// * Use the ProcessRoleFactory to create instances that have these attributes set.
+// */
+// public ProcessRole(com.netgrif.application.engine.objects.petrinet.domain.roles.ProcessRole role, Locale locale) {
+// stringId = role.getStringId();
+// name = role.getLocalisedName(locale);
+// description = role.getDescription();
+// importId = role.getImportId();
+// }
+//}
diff --git a/application-engine/src/main/java/com/netgrif/application/engine/auth/web/responsebodies/ProcessRoleFactoryImpl.java b/application-engine/src/main/java/com/netgrif/application/engine/auth/web/responsebodies/ProcessRoleFactoryImpl.java
new file mode 100644
index 00000000000..ff647c0d5fc
--- /dev/null
+++ b/application-engine/src/main/java/com/netgrif/application/engine/auth/web/responsebodies/ProcessRoleFactoryImpl.java
@@ -0,0 +1,35 @@
+package com.netgrif.application.engine.auth.web.responsebodies;
+
+import com.netgrif.application.engine.adapter.spring.petrinet.web.responsebodies.ProcessRole;
+import com.netgrif.application.engine.auth.service.ProcessRoleFactory;
+import com.netgrif.application.engine.objects.petrinet.domain.PetriNet;
+import com.netgrif.application.engine.petrinet.service.interfaces.IPetriNetService;
+import org.bson.types.ObjectId;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.Locale;
+
+@Service
+public class ProcessRoleFactoryImpl implements ProcessRoleFactory {
+
+ @Autowired
+ private IPetriNetService petriNetService;
+
+ @Override
+ public ProcessRole getProcessRole(com.netgrif.application.engine.objects.petrinet.domain.roles.ProcessRole role, Locale locale) {
+ /*if (!role.getStringId().equals(userProcessRole.getRoleId())) {
+ throw new IllegalArgumentException(String.format("ProcessRole StringId (%s) and UserProcessRole roleId (%s) must match!", role.getStringId(), userProcessRole.getRoleId()));
+ }*/
+ if (!role.isGlobal()) {
+ ProcessRole result = new ProcessRole(role, locale);
+ PetriNet net = petriNetService.get(new ObjectId(role.getProcessId()));
+ result.setNetStringId(net.getStringId());
+ result.setNetImportId(net.getImportId());
+ result.setNetVersion(net.getVersion().toString());
+ return result;
+ }
+ return new ProcessRole(role, locale);
+ }
+
+}
diff --git a/application-engine/src/main/java/com/netgrif/application/engine/auth/web/responsebodies/User.java b/application-engine/src/main/java/com/netgrif/application/engine/auth/web/responsebodies/User.java
new file mode 100644
index 00000000000..9cdbbc913ca
--- /dev/null
+++ b/application-engine/src/main/java/com/netgrif/application/engine/auth/web/responsebodies/User.java
@@ -0,0 +1,67 @@
+//package com.netgrif.application.engine.auth.web.responsebodies;
+//
+//import com.netgrif.application.engine.objects.auth.domain.Authority;
+//import com.netgrif.application.engine.objects.auth.domain.Group;
+//import com.netgrif.application.engine.objects.auth.domain.IUser;
+//import lombok.Data;
+//
+//import java.util.Set;
+//import java.util.stream.Collectors;
+//
+//@Data
+//public class User {
+//
+// private String id;
+//
+// private String email;
+//
+// private String telNumber;
+//
+// private String avatar;
+//
+// private String name;
+//
+// private String surname;
+//
+// private String fullName;
+//
+// private Set authorities;
+//
+// // process roles are set with the factory
+// private Set processRoles;
+//
+// private Set nextGroups;
+//
+// private User impersonated;
+//
+// protected User(IUser user) {
+// id = user.getStringId();
+// email = user.getEmail();
+// avatar = user.getAvatar();
+// name = user.getFirstName();
+// surname = user.getLastName();
+// fullName = user.getFullName();
+// }
+//
+// /**
+// * This static method doesn't set attributes regarding the ProcessRoles
+// *
+// * Use the UserFactory service to create instances that have these attributes set.
+// */
+// public static User createSmallUser(IUser user) {
+// return new User(user);
+// }
+//
+// /**
+// * This static method doesn't set attributes regarding the ProcessRoles
+// *
+// * Use the UserFactory service to create instances that have these attributes set.
+// */
+// public static User createUser(IUser user) {
+// User result = new User(user);
+// result.setTelNumber(user.getTelNumber());
+// result.setAuthorities(user.getAuthorities());
+// result.setNextGroups(user.getGroups().stream().map(Group::getStringId).collect(Collectors.toSet()));
+// return result;
+// }
+//}
diff --git a/application-engine/src/main/java/com/netgrif/application/engine/auth/web/responsebodies/UserFactory.java b/application-engine/src/main/java/com/netgrif/application/engine/auth/web/responsebodies/UserFactory.java
new file mode 100644
index 00000000000..2bb66eaf760
--- /dev/null
+++ b/application-engine/src/main/java/com/netgrif/application/engine/auth/web/responsebodies/UserFactory.java
@@ -0,0 +1,45 @@
+//package com.netgrif.application.engine.auth.web.responsebodies;
+//
+//import com.netgrif.application.engine.objects.auth.domain.IUser;
+//import com.netgrif.application.engine.adapter.spring.petrinet.service.ProcessRoleService;
+//import org.springframework.beans.factory.annotation.Autowired;
+//
+//import java.util.Locale;
+//import java.util.stream.Collectors;
+//
+//public class UserFactory implements UserFactory {
+//
+// @Autowired
+// private ProcessRoleService processRoleService;
+//
+// @Autowired
+// private IProcessRoleFactory processRoleFactory;
+//
+// @Override
+// public User getUser(IUser user, Locale locale) {
+// User result = getUser(user);
+//
+// String defaultRoleId = processRoleService.defaultRole().getStringId();
+// String anonymousRoleId = processRoleService.anonymousRole().getStringId();
+// result.setProcessRoles(user.getProcessRoles().stream().map(processRole -> {
+// if (processRole.getStringId().equals(defaultRoleId)) {
+// return new ProcessRole(processRole, locale);
+// }
+// if (processRole.getStringId().equals(anonymousRoleId)) {
+// return new ProcessRole(processRole, locale);
+// }
+// return processRoleFactory.getProcessRole(processRole, locale);
+// }).collect(Collectors.toSet()));
+//
+// return result;
+// }
+//
+// @Override
+// public User getSmallUser(IUser user) {
+// return User.createSmallUser(user);
+// }
+//
+// protected User getUser(IUser user) {
+// return User.createUser(user);
+// }
+//}
diff --git a/application-engine/src/main/java/com/netgrif/application/engine/auth/web/responsebodies/UserResource.java b/application-engine/src/main/java/com/netgrif/application/engine/auth/web/responsebodies/UserResource.java
new file mode 100644
index 00000000000..da82aaab178
--- /dev/null
+++ b/application-engine/src/main/java/com/netgrif/application/engine/auth/web/responsebodies/UserResource.java
@@ -0,0 +1,15 @@
+package com.netgrif.application.engine.auth.web.responsebodies;
+
+
+import org.springframework.hateoas.EntityModel;
+
+import java.util.ArrayList;
+
+public class UserResource extends EntityModel {
+
+ public UserResource(User content, String selfRel) {
+ super(content, new ArrayList<>());
+ }
+
+
+}
diff --git a/src/main/java/com/netgrif/application/engine/auth/web/responsebodies/UserResourceAssembler.java b/application-engine/src/main/java/com/netgrif/application/engine/auth/web/responsebodies/UserResourceAssembler.java
similarity index 80%
rename from src/main/java/com/netgrif/application/engine/auth/web/responsebodies/UserResourceAssembler.java
rename to application-engine/src/main/java/com/netgrif/application/engine/auth/web/responsebodies/UserResourceAssembler.java
index 2e1187481ea..4795077b0cc 100644
--- a/src/main/java/com/netgrif/application/engine/auth/web/responsebodies/UserResourceAssembler.java
+++ b/application-engine/src/main/java/com/netgrif/application/engine/auth/web/responsebodies/UserResourceAssembler.java
@@ -1,6 +1,7 @@
package com.netgrif.application.engine.auth.web.responsebodies;
-import com.netgrif.application.engine.auth.domain.IUser;
+import com.netgrif.application.engine.auth.service.UserFactory;
+import com.netgrif.application.engine.objects.auth.domain.IUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.hateoas.server.RepresentationModelAssembler;
@@ -9,7 +10,7 @@
public class UserResourceAssembler implements RepresentationModelAssembler {
@Autowired
- private IUserFactory userFactory;
+ private UserFactory userFactory;
private Locale locale;
private String selfRel;
@@ -33,6 +34,6 @@ public UserResource toModel(IUser entity) {
throw new IllegalStateException("You must initialize the UserResourceAssembler before calling the toResource method! To initialize the assembler call the initialize method.");
}
- return new UserResource(small ? userFactory.getSmallUser(entity) : userFactory.getUser(entity, locale), selfRel);
+ return new UserResource(userFactory.getUser(entity, locale), selfRel);
}
-}
\ No newline at end of file
+}
diff --git a/src/main/java/com/netgrif/application/engine/business/IPostalCodeService.java b/application-engine/src/main/java/com/netgrif/application/engine/business/IPostalCodeService.java
similarity index 100%
rename from src/main/java/com/netgrif/application/engine/business/IPostalCodeService.java
rename to application-engine/src/main/java/com/netgrif/application/engine/business/IPostalCodeService.java
diff --git a/src/main/java/com/netgrif/application/engine/business/PostalCode.java b/application-engine/src/main/java/com/netgrif/application/engine/business/PostalCode.java
similarity index 100%
rename from src/main/java/com/netgrif/application/engine/business/PostalCode.java
rename to application-engine/src/main/java/com/netgrif/application/engine/business/PostalCode.java
diff --git a/src/main/java/com/netgrif/application/engine/business/PostalCodeRepository.java b/application-engine/src/main/java/com/netgrif/application/engine/business/PostalCodeRepository.java
similarity index 100%
rename from src/main/java/com/netgrif/application/engine/business/PostalCodeRepository.java
rename to application-engine/src/main/java/com/netgrif/application/engine/business/PostalCodeRepository.java
diff --git a/src/main/java/com/netgrif/application/engine/business/PostalCodeService.java b/application-engine/src/main/java/com/netgrif/application/engine/business/PostalCodeService.java
similarity index 100%
rename from src/main/java/com/netgrif/application/engine/business/PostalCodeService.java
rename to application-engine/src/main/java/com/netgrif/application/engine/business/PostalCodeService.java
diff --git a/src/main/java/com/netgrif/application/engine/business/qr/IQrService.java b/application-engine/src/main/java/com/netgrif/application/engine/business/qr/IQrService.java
similarity index 100%
rename from src/main/java/com/netgrif/application/engine/business/qr/IQrService.java
rename to application-engine/src/main/java/com/netgrif/application/engine/business/qr/IQrService.java
diff --git a/src/main/java/com/netgrif/application/engine/business/qr/QrCode.java b/application-engine/src/main/java/com/netgrif/application/engine/business/qr/QrCode.java
similarity index 100%
rename from src/main/java/com/netgrif/application/engine/business/qr/QrCode.java
rename to application-engine/src/main/java/com/netgrif/application/engine/business/qr/QrCode.java
diff --git a/src/main/java/com/netgrif/application/engine/business/qr/QrService.java b/application-engine/src/main/java/com/netgrif/application/engine/business/qr/QrService.java
similarity index 100%
rename from src/main/java/com/netgrif/application/engine/business/qr/QrService.java
rename to application-engine/src/main/java/com/netgrif/application/engine/business/qr/QrService.java
diff --git a/src/main/java/com/netgrif/application/engine/configuration/AbstractSecurityConfiguration.java b/application-engine/src/main/java/com/netgrif/application/engine/configuration/AbstractSecurityConfiguration.java
similarity index 98%
rename from src/main/java/com/netgrif/application/engine/configuration/AbstractSecurityConfiguration.java
rename to application-engine/src/main/java/com/netgrif/application/engine/configuration/AbstractSecurityConfiguration.java
index 72afaaded7c..cb97acabb2e 100644
--- a/src/main/java/com/netgrif/application/engine/configuration/AbstractSecurityConfiguration.java
+++ b/application-engine/src/main/java/com/netgrif/application/engine/configuration/AbstractSecurityConfiguration.java
@@ -9,7 +9,7 @@
import com.netgrif.application.engine.configuration.properties.enumeration.XFrameOptionsMode;
import com.netgrif.application.engine.configuration.properties.enumeration.XXSSProtection;
import com.netgrif.application.engine.configuration.security.SessionUtilsProperties;
-import com.netgrif.application.engine.ldap.filters.LoginAttemptsFilter;
+//import com.netgrif.application.engine.ldap.filters.LoginAttemptsFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
@@ -235,7 +235,7 @@ protected void configureSession(HttpSecurity http) throws Exception {
protected void configureFilters(HttpSecurity http) {
if (sessionUtilsProperties.isEnabledFilter()) {
- http.addFilterBefore(new LoginAttemptsFilter(), ChannelProcessingFilter.class);
+// http.addFilterBefore(new LoginAttemptsFilter(), ChannelProcessingFilter.class);
}
}
diff --git a/src/main/java/com/netgrif/application/engine/configuration/CacheConfiguration.java b/application-engine/src/main/java/com/netgrif/application/engine/configuration/CacheConfiguration.java
similarity index 100%
rename from src/main/java/com/netgrif/application/engine/configuration/CacheConfiguration.java
rename to application-engine/src/main/java/com/netgrif/application/engine/configuration/CacheConfiguration.java
diff --git a/src/main/java/com/netgrif/application/engine/configuration/ElasticCaseSearchConfiguration.java b/application-engine/src/main/java/com/netgrif/application/engine/configuration/ElasticCaseSearchConfiguration.java
similarity index 100%
rename from src/main/java/com/netgrif/application/engine/configuration/ElasticCaseSearchConfiguration.java
rename to application-engine/src/main/java/com/netgrif/application/engine/configuration/ElasticCaseSearchConfiguration.java
diff --git a/src/main/java/com/netgrif/application/engine/configuration/ElasticServiceConfiguration.java b/application-engine/src/main/java/com/netgrif/application/engine/configuration/ElasticServiceConfiguration.java
similarity index 100%
rename from src/main/java/com/netgrif/application/engine/configuration/ElasticServiceConfiguration.java
rename to application-engine/src/main/java/com/netgrif/application/engine/configuration/ElasticServiceConfiguration.java
diff --git a/src/main/java/com/netgrif/application/engine/configuration/ElasticTaskExecutorConfiguration.java b/application-engine/src/main/java/com/netgrif/application/engine/configuration/ElasticTaskExecutorConfiguration.java
similarity index 100%
rename from src/main/java/com/netgrif/application/engine/configuration/ElasticTaskExecutorConfiguration.java
rename to application-engine/src/main/java/com/netgrif/application/engine/configuration/ElasticTaskExecutorConfiguration.java
diff --git a/application-engine/src/main/java/com/netgrif/application/engine/configuration/ElasticsearchConfiguration.java b/application-engine/src/main/java/com/netgrif/application/engine/configuration/ElasticsearchConfiguration.java
new file mode 100644
index 00000000000..ab50bcb5875
--- /dev/null
+++ b/application-engine/src/main/java/com/netgrif/application/engine/configuration/ElasticsearchConfiguration.java
@@ -0,0 +1,108 @@
+package com.netgrif.application.engine.configuration;
+
+import com.netgrif.application.engine.configuration.properties.UriProperties;
+import com.netgrif.application.engine.workflow.service.CaseEventHandler;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.*;
+import org.springframework.data.elasticsearch.client.ClientConfiguration;
+import org.springframework.data.elasticsearch.repository.config.EnableElasticsearchRepositories;
+
+@Configuration
+@EnableElasticsearchRepositories(excludeFilters = {
+ @ComponentScan.Filter(
+ type = FilterType.REGEX,
+ pattern = "com\\.netgrif\\.application\\.engine\\.module\\..*"
+ )
+})
+public class ElasticsearchConfiguration extends org.springframework.data.elasticsearch.client.elc.ElasticsearchConfiguration {
+
+ @Value("${spring.data.elasticsearch.url}")
+ private String url;
+
+ @Value("${spring.data.elasticsearch.searchport}")
+ private int port;
+
+ @Value("${spring.data.elasticsearch.index.petriNet}")
+ private String petriNetIndex;
+
+ @Value("${spring.data.elasticsearch.index.case}")
+ private String caseIndex;
+
+ @Value("${spring.data.elasticsearch.index.task}")
+ private String taskIndex;
+
+ @Value("${spring.data.elasticsearch.reindex}")
+ private String cron;
+
+ private final UriProperties uriProperties;
+
+ public ElasticsearchConfiguration(UriProperties uriProperties) {
+ this.uriProperties = uriProperties;
+ }
+
+ @Bean
+ public String springElasticsearchReindex() {
+ return cron;
+ }
+
+ @Bean
+ public String elasticPetriNetIndex() {
+ return petriNetIndex;
+ }
+
+ @Bean
+ public String elasticCaseIndex() {
+ return caseIndex;
+ }
+
+ @Bean
+ public String elasticTaskIndex() {
+ return taskIndex;
+ }
+
+ @Bean
+ public String elasticUriIndex() {
+ return uriProperties.getIndex();
+ }
+
+// @Bean
+// public ElasticsearchClient elasticsearchClient(RestClient elasticSearchRestClient) {
+// ElasticsearchTransport transport = new RestClientTransport(
+// elasticSearchRestClient,
+// new JacksonJsonpMapper()
+// );
+// return new ElasticsearchClient(transport);
+// }
+//
+// @Bean
+// public ElasticsearchTemplate elasticsearchTemplate(ElasticsearchClient elasticsearchClient) {
+// return new ElasticsearchTemplate(elasticsearchClient);
+// }
+
+ @Bean
+ public CaseEventHandler caseEventHandler() {
+ return new CaseEventHandler();
+ }
+
+ @Override
+ public ClientConfiguration clientConfiguration() {
+ return ClientConfiguration.builder()
+ .connectedTo(url + ":" + port)
+ .build();
+ }
+
+// @Bean
+// @Primary
+// public ElasticsearchOperations elasticsearchOperations(ElasticsearchConverter elasticsearchConverter, ElasticsearchClient elasticsearchClient) {
+// ElasticsearchOperations elasticsearchOperations = super.elasticsearchOperations(elasticsearchConverter, elasticsearchClient);
+// IndexOperations indexOperations = elasticsearchOperations.indexOps(EventLog.class);
+// elasticsearchClient.indices().
+// CreateIndexRequest createIndexRequest = CreateIndexRequest.of(b -> b
+// .index("event_log").m
+// );
+// CreateIndexResponse response = elasticsearchClient.indices().create(createIndexRequest);
+// }
+// return elasticsearchOperations;
+// }
+
+}
diff --git a/src/main/java/com/netgrif/application/engine/configuration/EncryptionConfiguration.java b/application-engine/src/main/java/com/netgrif/application/engine/configuration/EncryptionConfiguration.java
similarity index 100%
rename from src/main/java/com/netgrif/application/engine/configuration/EncryptionConfiguration.java
rename to application-engine/src/main/java/com/netgrif/application/engine/configuration/EncryptionConfiguration.java
diff --git a/application-engine/src/main/java/com/netgrif/application/engine/configuration/FaviconConfiguration.java b/application-engine/src/main/java/com/netgrif/application/engine/configuration/FaviconConfiguration.java
new file mode 100644
index 00000000000..50a5579e4b1
--- /dev/null
+++ b/application-engine/src/main/java/com/netgrif/application/engine/configuration/FaviconConfiguration.java
@@ -0,0 +1,31 @@
+package com.netgrif.application.engine.configuration;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.io.ClassPathResource;
+import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping;
+import org.springframework.web.servlet.resource.ResourceHttpRequestHandler;
+
+import java.util.Arrays;
+import java.util.Collections;
+
+@Configuration
+public class FaviconConfiguration {
+
+ // TODO 2025-04-23 Favicon naozaj už nie je treba
+// @Bean
+// public SimpleUrlHandlerMapping myFaviconHandlerMapping() {
+// SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping();
+// mapping.setOrder(Integer.MIN_VALUE);
+// mapping.setUrlMap(Collections.singletonMap("/favicon.ico", myFaviconRequestHandler()));
+// return mapping;
+// }
+//
+// @Bean
+// protected ResourceHttpRequestHandler myFaviconRequestHandler() {
+// ResourceHttpRequestHandler requestHandler = new ResourceHttpRequestHandler();
+// requestHandler.setLocations(Arrays.asList(new ClassPathResource("/")));
+// return requestHandler;
+// }
+
+}
diff --git a/application-engine/src/main/java/com/netgrif/application/engine/configuration/LdapUserServiceConfiguration.java b/application-engine/src/main/java/com/netgrif/application/engine/configuration/LdapUserServiceConfiguration.java
new file mode 100644
index 00000000000..555303ec49c
--- /dev/null
+++ b/application-engine/src/main/java/com/netgrif/application/engine/configuration/LdapUserServiceConfiguration.java
@@ -0,0 +1,25 @@
+//package com.netgrif.application.engine.configuration;
+//
+//import com.netgrif.application.engine.auth.service.LdapUserDetailsService;
+//import com.netgrif.application.engine.auth.service.UserService;
+//import com.netgrif.application.engine.ldap.service.LdapUserService;
+//import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
+//import org.springframework.context.annotation.Bean;
+//import org.springframework.context.annotation.Configuration;
+//import org.springframework.security.core.userdetails.UserDetailsService;
+//
+//@Configuration
+//@ConditionalOnExpression("${nae.ldap.enabled:false}")
+//public class LdapUserServiceConfiguration {
+//
+// @Bean
+// public IUserService userService() {
+// return new LdapUserService();
+// }
+//
+// @Bean
+// public UserDetailsService userDetailsService() {
+// return new LdapUserDetailsService();
+// }
+//
+//}
diff --git a/application-engine/src/main/java/com/netgrif/application/engine/configuration/LoadModule.java b/application-engine/src/main/java/com/netgrif/application/engine/configuration/LoadModule.java
new file mode 100644
index 00000000000..a8302c0fecc
--- /dev/null
+++ b/application-engine/src/main/java/com/netgrif/application/engine/configuration/LoadModule.java
@@ -0,0 +1,26 @@
+package com.netgrif.application.engine.configuration;
+
+import lombok.Data;
+
+@Data
+public class LoadModule {
+
+ private String name;
+ private String version;
+ private String description;
+ private String author;
+
+ private String groupId;
+ private String artifactId;
+ private String url;
+ private String scmConnection;
+ private String scmUrl;
+ private String buildTime;
+
+ private String license;
+ private String organization;
+ private String organizationUrl;
+ private String issueSystem;
+ private String issueUrl;
+ private String buildJdk;
+}
diff --git a/application-engine/src/main/java/com/netgrif/application/engine/configuration/LoadedModulesEndpoint.java b/application-engine/src/main/java/com/netgrif/application/engine/configuration/LoadedModulesEndpoint.java
new file mode 100644
index 00000000000..05148555689
--- /dev/null
+++ b/application-engine/src/main/java/com/netgrif/application/engine/configuration/LoadedModulesEndpoint.java
@@ -0,0 +1,157 @@
+package com.netgrif.application.engine.configuration;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
+import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
+import org.springframework.cache.annotation.Cacheable;
+import org.springframework.stereotype.Component;
+
+import java.io.InputStream;
+import java.net.URL;
+import java.util.*;
+import java.util.jar.Attributes;
+import java.util.jar.Manifest;
+
+@Slf4j
+@Component
+@Endpoint(id = "loadedModules")
+public class LoadedModulesEndpoint {
+
+ private static final String CACHE_NAME = "loadedModules";
+ private static final String MANIFEST_PATH = "META-INF/MANIFEST.MF";
+ private static final String NAME = "Netgrif-Name";
+ private static final String VERSION = "Netgrif-Version";
+ private static final String AUTHOR = "Netgrif-Author";
+ private static final String DESCRIPTION = "Netgrif-Description";
+ private static final String GROUP_ID = "Netgrif-GroupId";
+ private static final String ARTIFACT_ID = "Netgrif-ArtifactId";
+ private static final String NETGRIF_URL = "Netgrif-Url";
+ private static final String SCM_CONNECTION = "Netgrif-SCM-Connection";
+ private static final String SCM_URL = "Netgrif-SCM-URL";
+ private static final String BUILD_TIME = "Netgrif-BuildTime";
+ private static final String LICENSE = "Netgrif-License";
+ private static final String ORGANIZATION = "Netgrif-Organization";
+ private static final String ORGANIZATION_URL = "Netgrif-OrganizationUrl";
+ private static final String ISSUE_SYSTEM = "Netgrif-IssueSystem";
+ private static final String ISSUE_URL = "Netgrif-IssueUrl";
+ private static final String BUILD_JDK = "Netgrif-BuildJdk";
+
+ @ReadOperation
+ @Cacheable(CACHE_NAME)
+ public List getLoadedModules() {
+ log.debug("Starting module manifest search...");
+ List manifests = findAllManifests();
+ log.debug("Found {} manifests on classpath", manifests.size());
+
+ if (manifests.isEmpty()) {
+ log.error("No manifests found in classpath! Check your dependencies and classloader setup.");
+ }
+
+ List modules = new ArrayList<>();
+ for (Manifest manifest : manifests) {
+ extractModuleFromManifest(manifest).ifPresent(module -> {
+ log.trace("Loaded module: {}", module);
+ modules.add(module);
+ });
+ }
+
+ log.info("Loaded {} modules with Netgrif attributes", modules.size());
+ return modules;
+ }
+
+ private List findAllManifests() {
+ List