diff --git a/.github/workflows/dependencies.yaml b/.github/workflows/dependencies.yaml index 8c6a1323d5..3002a3ddf7 100644 --- a/.github/workflows/dependencies.yaml +++ b/.github/workflows/dependencies.yaml @@ -46,13 +46,13 @@ jobs: run: mvn org.eclipse.dash:license-tool-plugin:license-check -Ddash.summary=DEPENDENCIES_BACKEND - name: Run install - uses: borales/actions-yarn@v4 + uses: borales/actions-yarn@v5 with: cmd: install dir: 'frontend' - name: Generate FE Dependencies file - uses: borales/actions-yarn@v4 + uses: borales/actions-yarn@v5 with: cmd: run dependencies:generate dir: 'frontend' @@ -76,7 +76,7 @@ jobs: if: ${{ env.were_files_changed }} == 'true' - name: Create pull request - uses: peter-evans/create-pull-request@v5 + uses: peter-evans/create-pull-request@v6 with: add-paths: | DEPENDENCIES_BACKEND diff --git a/.github/workflows/docker-image-main_backend.yml b/.github/workflows/docker-image-main_backend.yml index 06a68c699f..9728b83c4c 100644 --- a/.github/workflows/docker-image-main_backend.yml +++ b/.github/workflows/docker-image-main_backend.yml @@ -90,7 +90,7 @@ jobs: env: DOCKER_HUB_USER: ${{ secrets.DOCKER_HUB_USER }} if: env.DOCKER_HUB_USER != '' - uses: peter-evans/dockerhub-description@v3 + uses: peter-evans/dockerhub-description@v4 with: username: ${{ secrets.DOCKER_HUB_USER }} password: ${{ secrets.DOCKER_HUB_TOKEN }} diff --git a/.github/workflows/docker-image-main_frontend.yml b/.github/workflows/docker-image-main_frontend.yml index 4e6a240b0d..ab934c8aa6 100644 --- a/.github/workflows/docker-image-main_frontend.yml +++ b/.github/workflows/docker-image-main_frontend.yml @@ -84,7 +84,7 @@ jobs: tags: ${{ env.DOCKER_HUB_REGISTRY_NAMESPACE }}/${{ env.FRONTEND_IMAGE_DOCKER_HUB }}:${{ github.sha }} - name: Update Docker Hub description - uses: peter-evans/dockerhub-description@v3 + uses: peter-evans/dockerhub-description@v4 env: DOCKER_HUB_USER: ${{ secrets.DOCKER_HUB_USER }} if: env.DOCKER_HUB_USER != '' diff --git a/.github/workflows/docker-image-tag-release.yaml b/.github/workflows/docker-image-tag-release.yaml index 3d4ee12648..763cdb91e2 100644 --- a/.github/workflows/docker-image-tag-release.yaml +++ b/.github/workflows/docker-image-tag-release.yaml @@ -90,7 +90,7 @@ jobs: env: DOCKER_HUB_USER: ${{ secrets.DOCKER_HUB_USER }} if: env.DOCKER_HUB_USER != '' - uses: peter-evans/dockerhub-description@v3 + uses: peter-evans/dockerhub-description@v4 with: username: ${{ secrets.DOCKER_HUB_USER }} password: ${{ secrets.DOCKER_HUB_TOKEN }} @@ -115,7 +115,7 @@ jobs: cache: 'maven' - name: Cache maven packages - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.m2 key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }} @@ -164,7 +164,7 @@ jobs: env: DOCKER_HUB_USER: ${{ secrets.DOCKER_HUB_USER }} if: env.DOCKER_HUB_USER != '' - uses: peter-evans/dockerhub-description@v3 + uses: peter-evans/dockerhub-description@v4 with: username: ${{ secrets.DOCKER_HUB_USER }} password: ${{ secrets.DOCKER_HUB_TOKEN }} diff --git a/.github/workflows/e2e-tests-xray_frontend.yml b/.github/workflows/e2e-tests-xray_frontend.yml index 15f69ec5ca..19b2e4f0d3 100644 --- a/.github/workflows/e2e-tests-xray_frontend.yml +++ b/.github/workflows/e2e-tests-xray_frontend.yml @@ -52,7 +52,7 @@ jobs: node-version: 18.x - name: Run yarn install - uses: Borales/actions-yarn@v4.2.0 + uses: Borales/actions-yarn@v5 with: cmd: install # will run `yarn install` command diff --git a/.github/workflows/eclipse-dash.yml b/.github/workflows/eclipse-dash.yml index 405160f6ce..9cac16af8a 100644 --- a/.github/workflows/eclipse-dash.yml +++ b/.github/workflows/eclipse-dash.yml @@ -67,7 +67,7 @@ jobs: distribution: 'temurin' - name: Cache maven packages - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.m2 key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }} @@ -82,3 +82,4 @@ jobs: uses: actions/upload-artifact@v4 with: path: DEPENDENCIES_BACKEND + overwrite: true diff --git a/.github/workflows/publish-documentation.yaml b/.github/workflows/publish-documentation.yaml index 53e72b4b84..ca4fae9b7c 100644 --- a/.github/workflows/publish-documentation.yaml +++ b/.github/workflows/publish-documentation.yaml @@ -51,7 +51,7 @@ jobs: node-version: 16 - name: Cache maven packages - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.m2 key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }} diff --git a/.github/workflows/pull-request_backend.yml b/.github/workflows/pull-request_backend.yml index 6fbb4ad5a3..0e538b9cc5 100644 --- a/.github/workflows/pull-request_backend.yml +++ b/.github/workflows/pull-request_backend.yml @@ -79,7 +79,7 @@ jobs: check_name: "Unit Test Results" - name: Cache SonarCloud packages - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.sonar/cache key: ${{ runner.os }}-sonar diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 1b0cef9597..2125733ca7 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -62,7 +62,7 @@ jobs: json -I -f frontend/package.json -e "this.version='${{ github.ref_name }}'" - name: Prepare Helm release - uses: peter-evans/create-pull-request@v5 + uses: peter-evans/create-pull-request@v6 with: commit-message: "chore(release): Prepare release for Helm version ${{ env.HELM_VERSION }}" branch: chore/prepare-helm-release-${{ env.HELM_VERSION }} diff --git a/.github/workflows/sonar-scan-backend.yml b/.github/workflows/sonar-scan-backend.yml index 7db2f3fb4a..7bc1a5e2c6 100644 --- a/.github/workflows/sonar-scan-backend.yml +++ b/.github/workflows/sonar-scan-backend.yml @@ -45,7 +45,7 @@ jobs: cache: 'maven' - name: Cache SonarCloud packages - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.sonar/cache key: ${{ runner.os }}-sonar diff --git a/.github/workflows/spotbugs.yml b/.github/workflows/spotbugs.yml index 08af93805d..87aed7bcde 100644 --- a/.github/workflows/spotbugs.yml +++ b/.github/workflows/spotbugs.yml @@ -53,7 +53,7 @@ jobs: distribution: 'temurin' - name: Cache maven packages - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.m2 key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }} diff --git a/.github/workflows/trivy.yml b/.github/workflows/trivy.yml index 536c1b1534..aa01a2d20c 100644 --- a/.github/workflows/trivy.yml +++ b/.github/workflows/trivy.yml @@ -72,7 +72,7 @@ jobs: run: docker build -t localhost:5000/traceability-foss:fe_${{ github.sha }} -f ./frontend/Dockerfile . - name: Run Trivy vulnerability scanner - uses: aquasecurity/trivy-action@0.16.1 + uses: aquasecurity/trivy-action@0.17.0 with: trivyignores: "./.github/workflows/.trivyignore" image-ref: 'localhost:5000/traceability-foss:fe_${{ github.sha }}' @@ -132,7 +132,7 @@ jobs: ref: ${{needs.prepare-env.outputs.check_sha}} - name: Run Trivy vulnerability scanner in repo mode - uses: aquasecurity/trivy-action@0.16.1 + uses: aquasecurity/trivy-action@0.17.0 with: trivyignores: "./.github/workflows/.trivyignore" scan-type: "config" @@ -178,7 +178,7 @@ jobs: tags: localhost:5000/traceability-foss:trivy - name: Run Trivy vulnerability scanner - uses: aquasecurity/trivy-action@0.16.1 + uses: aquasecurity/trivy-action@0.17.0 with: image-ref: localhost:5000/traceability-foss:trivy trivyignores: "./.github/workflows/.trivyignore" diff --git a/.github/workflows/xray-cucumber.yaml b/.github/workflows/xray-cucumber.yaml index 4f6076ffe4..ac8fe253ff 100644 --- a/.github/workflows/xray-cucumber.yaml +++ b/.github/workflows/xray-cucumber.yaml @@ -36,7 +36,7 @@ jobs: distribution: 'temurin' - name: Cache maven packages - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.m2 key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }} diff --git a/CHANGELOG.md b/CHANGELOG.md index a9a46ea784..0ade097a27 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,10 +8,23 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [UNRELEASED - DD.MM.YYYY] ### Added +- added tombstone icon to parts table and error description in parts detail view +- Endpoint (assets/import/report/{importJobId}) for retrieving import report ### Changed +- actions/chache bumped from v3 to v4 +- borales/actions-yarn bumped from v4 to v5 +- peter-evans/create-pull-request bumped from v5 to v6 +- peter-evans/dockerhub-description bumped from v3 to v4 +- aquasecurity/trivy-action bumped from 0.16.1 to 0.17.0 +- sonar-maven-plugin bumped from 3.9.1.2184 to 3.10.0.2594 +- rest-assured bumped from 5.3.2 to 5.4.0 +- testcontainer-postgresql bumped from 1.19.1 to 1.19.4 +- tomcat-embed-websocket bumped from 10.1.16 to 10.1.18 +- IrsCallbackController is now validating jobId to prevent log injections from unwanted usage ### Removed +- Investigations/Alerts for assets_as_planned parts ## [10.3.0 - 05.02.2024] diff --git a/COMPATIBILITY_MATRIX.md b/COMPATIBILITY_MATRIX.md index d24e6dd0a9..a17019e77f 100644 --- a/COMPATIBILITY_MATRIX.md +++ b/COMPATIBILITY_MATRIX.md @@ -11,19 +11,22 @@ #### Helm Version 1.3.21 -| Dependency | Name of Service | Version | Helm | Comments | -|-------------------|------------------------------|---------------|-------|-----------------------------------------------------------------------------------| -| EDC | edc-postgresql | 12.1.6 | 2.0.0 | Enterprise Data Connector for PostgreSQL | -| IRS | irs-helm | 4.0.1 | 6.9.1 | Helm charts for Item Relationship Service | -| EDC | tractusx-connector | 0.5.3 | 2.0.0 | Connector for Data Transfer and Registration | -| Discovery Service | discovery service | 1.16.0 | 0.1.0 | Service for discovering and registering artifacts | -| Portal | portal | 1.7.0 | 1.7.0 | Web portal for interacting with Trace-X | -| SD-Factory | SD-Factory | 2.1.7 | 2.1.8 | Service Discovery Factory for managing dependencies | -| Wallet | wallet | 0.3.0 | 0.3.0 | Secure storage for sensitive information | -| SDE | Simple Data Exchanger (SDE) | 2.3.3 | 0.1.3 | Standalone service for companies to provide data in the Eclipse Tractus-X network | -| Aspect Model | SerialPart | [1.0.0,1.1.0] | - | | -| Aspect Model | Batch | [1.0.0,2.0.0] | - | | -| Aspect Model | PartAsPlanned | [1.0.0,1.0.1] | - | | -| Aspect Model | PartSiteInformationAsPlanned | [1.0.0] | - | | -| Aspect Model | JustInSequencePart | [1.0.0] | - | | -| Aspect Model | TractionBatteryCode | [1.0.0] | - | | +| Dependency | Name of Service | Version | Helm | Comments | +|-------------------|------------------------------|---------------------------------|-------|-----------------------------------------------------------------------------------| +| EDC | edc-postgresql | 12.1.6 | 2.0.0 | Enterprise Data Connector for PostgreSQL | +| IRS | irs-helm | 4.0.1 | 6.9.1 | Helm charts for Item Relationship Service | +| EDC | tractusx-connector | 0.5.3 | 2.0.0 | Connector for Data Transfer and Registration | +| Discovery Service | discovery service | 1.16.0 | 0.1.0 | Service for discovering and registering artifacts | +| Portal | portal | 1.7.0 | 1.7.0 | Web portal for interacting with Trace-X | +| SD-Factory | SD-Factory | 2.1.7 | 2.1.8 | Service Discovery Factory for managing dependencies | +| Wallet | wallet | 0.3.0 | 0.3.0 | Secure storage for sensitive information | +| SDE | Simple Data Exchanger (SDE) | 2.3.3 | 0.1.3 | Standalone service for companies to provide data in the Eclipse Tractus-X network | +| Aspect Model | SerialPart | [1.0.0,1.1.0,2.0.0,3.0.0) | - | | +| Aspect Model | Batch | [1.0.1,1.0.2,2.0.0,2.0.1,3.0.0) | - | | +| Aspect Model | PartAsPlanned | [1.0.0,1.0.1,2.0.0) | - | | +| Aspect Model | PartSiteInformationAsPlanned | [1.0.0] | - | | +| Aspect Model | JustInSequencePart | [1.0.0,2.0.0,3.0.0) | - | | +| Aspect Model | TractionBatteryCode | [1.0.0] | - | | +| Aspect Model | SingleLevelUsageAsBuilt | [1.0.1] | - | | +| Aspect Model | SingleLevelBomAsBuilt | [1.0.0, 2.0.0) | - | | +| Aspect Model | SingleLevelBomAsPlanned | [1.0.1, 1.1.0) | - | | diff --git a/DEPENDENCIES_BACKEND b/DEPENDENCIES_BACKEND index 3a727148ed..a0341d19fb 100644 --- a/DEPENDENCIES_BACKEND +++ b/DEPENDENCIES_BACKEND @@ -22,6 +22,8 @@ maven/mavencentral/com.fasterxml/classmate/1.5.1, Apache-2.0, approved, clearlyd maven/mavencentral/com.github.docker-java/docker-java-api/3.3.0, Apache-2.0, approved, #10346 maven/mavencentral/com.github.docker-java/docker-java-transport-zerodep/3.3.0, Apache-2.0 AND (Apache-2.0 AND BSD-3-Clause), approved, #7946 maven/mavencentral/com.github.docker-java/docker-java-transport/3.3.0, Apache-2.0, approved, #7942 +maven/mavencentral/com.github.java-json-tools.jackson-coreutils/jackson-coreutils-equivalence/2.0, , restricted, clearlydefined +maven/mavencentral/com.github.java-json-tools.jackson-coreutils/jackson-coreutils/2.0, , restricted, clearlydefined maven/mavencentral/com.github.java-json-tools/btf/1.3, Apache-2.0 OR LGPL-3.0-or-later, approved, #2721 maven/mavencentral/com.github.java-json-tools/jackson-coreutils-equivalence/1.0, LGPL-3.0 OR Apache-2.0, approved, clearlydefined maven/mavencentral/com.github.java-json-tools/jackson-coreutils/2.0, Apache-2.0 OR LGPL-3.0-or-later, approved, #2719 @@ -111,10 +113,13 @@ maven/mavencentral/io.opentelemetry/opentelemetry-api/1.29.0, Apache-2.0, approv maven/mavencentral/io.opentelemetry/opentelemetry-context/1.25.0, Apache-2.0, approved, clearlydefined maven/mavencentral/io.opentelemetry/opentelemetry-context/1.29.0, Apache-2.0, approved, #10090 maven/mavencentral/io.rest-assured/json-path/5.3.2, Apache-2.0, approved, #9261 +maven/mavencentral/io.rest-assured/json-path/5.4.0, Apache-2.0, approved, #12042 maven/mavencentral/io.rest-assured/json-schema-validator/5.4.0, Apache-2.0, approved, clearlydefined maven/mavencentral/io.rest-assured/rest-assured-common/5.3.2, Apache-2.0, approved, #9264 -maven/mavencentral/io.rest-assured/rest-assured/5.3.2, Apache-2.0, approved, #9262 +maven/mavencentral/io.rest-assured/rest-assured-common/5.4.0, Apache-2.0, approved, #12039 +maven/mavencentral/io.rest-assured/rest-assured/5.4.0, Apache-2.0, approved, #12040 maven/mavencentral/io.rest-assured/xml-path/5.3.2, Apache-2.0, approved, #9267 +maven/mavencentral/io.rest-assured/xml-path/5.4.0, Apache-2.0, approved, #12038 maven/mavencentral/io.smallrye/jandex/3.0.5, Apache-2.0, approved, clearlydefined maven/mavencentral/io.swagger.core.v3/swagger-annotations-jakarta/2.2.8, Apache-2.0, approved, #5947 maven/mavencentral/io.swagger.core.v3/swagger-annotations/2.2.16, Apache-2.0, approved, #11362 @@ -156,11 +161,11 @@ maven/mavencentral/org.apache.commons/commons-compress/1.23.0, Apache-2.0 AND BS maven/mavencentral/org.apache.commons/commons-lang3/3.11, Apache-2.0, approved, CQ22642 maven/mavencentral/org.apache.commons/commons-lang3/3.12.0, Apache-2.0, approved, clearlydefined maven/mavencentral/org.apache.commons/commons-text/1.10.0, Apache-2.0, approved, clearlydefined -maven/mavencentral/org.apache.groovy/groovy-json/4.0.11, Apache-2.0, approved, #7411 +maven/mavencentral/org.apache.groovy/groovy-json/4.0.16, Apache-2.0, approved, #7411 maven/mavencentral/org.apache.groovy/groovy-json/4.0.17, Apache-2.0, approved, #7411 -maven/mavencentral/org.apache.groovy/groovy-xml/4.0.11, Apache-2.0, approved, #10179 +maven/mavencentral/org.apache.groovy/groovy-xml/4.0.16, Apache-2.0, approved, #10179 maven/mavencentral/org.apache.groovy/groovy-xml/4.0.17, Apache-2.0, approved, #10179 -maven/mavencentral/org.apache.groovy/groovy/4.0.11, Apache-2.0 AND BSD-3-Clause AND MIT, approved, #1742 +maven/mavencentral/org.apache.groovy/groovy/4.0.16, Apache-2.0 AND BSD-3-Clause AND MIT, approved, #1742 maven/mavencentral/org.apache.groovy/groovy/4.0.17, Apache-2.0 AND BSD-3-Clause AND MIT, approved, #1742 maven/mavencentral/org.apache.httpcomponents/httpclient/4.5.13, Apache-2.0 AND LicenseRef-Public-Domain, approved, CQ23527 maven/mavencentral/org.apache.httpcomponents/httpcore/4.4.13, Apache-2.0, approved, CQ23528 @@ -169,12 +174,9 @@ maven/mavencentral/org.apache.httpcomponents/httpmime/4.5.13, Apache-2.0, approv maven/mavencentral/org.apache.logging.log4j/log4j-api/2.20.0, Apache-2.0, approved, clearlydefined maven/mavencentral/org.apache.logging.log4j/log4j-to-slf4j/2.20.0, Apache-2.0, approved, #8799 maven/mavencentral/org.apache.mina/mina-core/2.1.6, Apache-2.0, approved, #3289 -maven/mavencentral/org.apache.tomcat.embed/tomcat-embed-core/10.1.16, Apache-2.0 AND (EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0) AND (CDDL-1.0 OR GPL-2.0-only WITH Classpath-exception-2.0) AND W3C AND CC0-1.0, approved, #5949 maven/mavencentral/org.apache.tomcat.embed/tomcat-embed-core/10.1.18, Apache-2.0 AND (EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0) AND (CDDL-1.0 OR GPL-2.0-only WITH Classpath-exception-2.0) AND W3C AND CC0-1.0, approved, #5949 maven/mavencentral/org.apache.tomcat.embed/tomcat-embed-el/10.1.18, Apache-2.0, approved, #6997 -maven/mavencentral/org.apache.tomcat.embed/tomcat-embed-websocket/10.1.16, Apache-2.0, approved, #7920 maven/mavencentral/org.apache.tomcat.embed/tomcat-embed-websocket/10.1.18, Apache-2.0, approved, #7920 -maven/mavencentral/org.apache.tomcat/tomcat-annotations-api/10.1.16, Apache-2.0, approved, #8196 maven/mavencentral/org.apache.tomcat/tomcat-annotations-api/10.1.18, Apache-2.0, approved, #8196 maven/mavencentral/org.apiguardian/apiguardian-api/1.1.2, Apache-2.0, approved, clearlydefined maven/mavencentral/org.aspectj/aspectjweaver/1.9.21, Apache-2.0 AND BSD-3-Clause AND EPL-1.0 AND BSD-3-Clause AND Apache-1.1, approved, #7695 @@ -434,8 +436,8 @@ maven/mavencentral/org.springframework/spring-web/6.0.16, Apache-2.0, approved, maven/mavencentral/org.springframework/spring-webmvc/6.0.16, Apache-2.0, approved, #5944 maven/mavencentral/org.testcontainers/database-commons/1.18.3, MIT, approved, clearlydefined maven/mavencentral/org.testcontainers/jdbc/1.18.3, MIT, approved, clearlydefined -maven/mavencentral/org.testcontainers/junit-jupiter/1.19.1, MIT, approved, #10344 -maven/mavencentral/org.testcontainers/postgresql/1.19.1, MIT, approved, #10350 +maven/mavencentral/org.testcontainers/junit-jupiter/1.19.4, MIT, approved, #10344 +maven/mavencentral/org.testcontainers/postgresql/1.19.4, MIT, approved, #10350 maven/mavencentral/org.testcontainers/testcontainers/1.18.3, MIT, approved, #7938 maven/mavencentral/org.thymeleaf/thymeleaf-spring6/3.1.2.RELEASE, Apache-2.0, approved, #10581 maven/mavencentral/org.thymeleaf/thymeleaf/3.1.2.RELEASE, Apache-2.0, approved, CQ23960 diff --git a/DEPENDENCIES_FRONTEND b/DEPENDENCIES_FRONTEND index 3957d86058..82a111570d 100644 --- a/DEPENDENCIES_FRONTEND +++ b/DEPENDENCIES_FRONTEND @@ -460,7 +460,7 @@ npm/npmjs/-/has-flag/4.0.0, MIT, approved, clearlydefined npm/npmjs/-/has-property-descriptors/1.0.1, MIT, approved, #11098 npm/npmjs/-/has-proto/1.0.1, MIT, approved, #6175 npm/npmjs/-/has-symbols/1.0.3, MIT, approved, clearlydefined -npm/npmjs/-/has-tostringtag/1.0.0, MIT, approved, clearlydefined +npm/npmjs/-/has-tostringtag/1.0.0, MIT, approved, #13161 npm/npmjs/-/has-unicode/2.0.1, ISC, approved, clearlydefined npm/npmjs/-/has/1.0.3, MIT, approved, #10930 npm/npmjs/-/hasown/2.0.0, MIT, approved, #11097 @@ -662,7 +662,7 @@ npm/npmjs/-/lru-cache/7.18.3, MIT AND ISC, approved, #7614 npm/npmjs/-/lru-cache/9.1.1, ISC AND MIT, approved, #8054 npm/npmjs/-/luxon/3.2.1, MIT, approved, clearlydefined npm/npmjs/-/lz-string/1.5.0, MIT AND WTFPL, approved, #8398 -npm/npmjs/-/magic-string/0.30.1, MIT, approved, clearlydefined +npm/npmjs/-/magic-string/0.30.1, MIT, approved, #13189 npm/npmjs/-/make-dir/2.1.0, MIT, approved, clearlydefined npm/npmjs/-/make-dir/3.1.0, MIT, approved, clearlydefined npm/npmjs/-/make-error/1.3.6, ISC, approved, clearlydefined diff --git a/docs/src/docs/arc42/building-block-view/level-1.adoc b/docs/src/docs/arc42/building-block-view/level-1.adoc index c81d6cfa97..4cba2f908a 100644 --- a/docs/src/docs/arc42/building-block-view/level-1.adoc +++ b/docs/src/docs/arc42/building-block-view/level-1.adoc @@ -27,6 +27,9 @@ include::../../../uml-diagrams/arc42/building-block-view/building-block-view.pum |*RegistryController* |The *RegistryController* provides a REST Interface for retrieving the data from parts registry. +|*ImportController* +|The *ImportController* provides a REST Interface for importing assets and publishing them in the Catena-X network. + |*AssetRepository* |The *AssetRepository* is a component responsible for storing and getting assets from database. diff --git a/docs/src/docs/arc42/runtime-view/data-provisioning.adoc b/docs/src/docs/arc42/runtime-view/data-provisioning.adoc index ebf2c0d76e..7c331d2046 100644 --- a/docs/src/docs/arc42/runtime-view/data-provisioning.adoc +++ b/docs/src/docs/arc42/runtime-view/data-provisioning.adoc @@ -32,3 +32,7 @@ The backend is able to persist the data in the DTR / EDC and allows to use IRS f include::../../../uml-diagrams/arc42/runtime-view/data-provisioning/trace-x-data-import-interface-modul3-sequence.puml[] .... + +TODO: Add all scenarios for data-provisioning + +include::data-provisioning/return-import-report.adoc[leveloffset=+1] diff --git a/docs/src/docs/arc42/runtime-view/data-provisioning/return-import-report.adoc b/docs/src/docs/arc42/runtime-view/data-provisioning/return-import-report.adoc new file mode 100644 index 0000000000..2f1ede3fd1 --- /dev/null +++ b/docs/src/docs/arc42/runtime-view/data-provisioning/return-import-report.adoc @@ -0,0 +1,16 @@ += Scenario 1: Receive import report + +This section describes what happens when the user wants to get a report of the imported assets associated to a importJobId. +In this example, the user requests an import report. + +[plantuml,target=import-report-receive,format=svg] +.... +include::../../../../uml-diagrams/arc42/runtime-view/data-provisioning/import-report-receive.puml[] +.... + +==== Overview + +When a user requests an import report, TraceX-FOSS checks if the user has an adequate role ('ROLE_ADMIN', 'ROLE_SUPERVISOR'). +If yes, then the endpoint returns an import report to the given importJobId. + +If the importJobId is not known to Trace-X, an HTTP 404 error is returned. diff --git a/docs/src/uml-diagrams/arc42/runtime-view/data-provisioning/import-report-receive.puml b/docs/src/uml-diagrams/arc42/runtime-view/data-provisioning/import-report-receive.puml new file mode 100644 index 0000000000..16ef51edae --- /dev/null +++ b/docs/src/uml-diagrams/arc42/runtime-view/data-provisioning/import-report-receive.puml @@ -0,0 +1,39 @@ +@startuml +skinparam monochrome true +skinparam shadowing false +autonumber "[000]" + +actor TraceXApiConsumer +activate TraceXApiConsumer + +box "Trace-X FOSS" #LightGrey +participant TraceXAPI +activate TraceXAPI +participant ImportController +activate ImportController +participant ImportService +activate ImportService +participant ImportJobRepository +activate ImportJobRepository +participant JpaImportJobRepository +activate JpaImportJobRepository +database TracexDatabase + +TraceXApiConsumer -> TraceXAPI : GET /assets/import/report/{importJobId} +TraceXAPI -> ImportController : getImportReport +ImportController -> ImportService : getImportJob(importJobId) +ImportService -> ImportJobRepository: getImportJob(importJobId) +ImportJobRepository -> JpaImportJobRepository: getReferenceById(importJobId) +JpaImportJobRepository -> TracexDatabase : find import job with associated assets + +JpaImportJobRepository <-- TracexDatabase +ImportJobRepository <-- JpaImportJobRepository +ImportService <-- ImportJobRepository +ImportController <-- ImportService +TraceXAPI <-- ImportController +TraceXApiConsumer <-- TraceXAPI : map ImportJob to ImportReportResponse + + + + +@enduml diff --git a/frontend/src/app/mocks/services/parts-mock/partsAsBuilt/partsAsBuilt.model.ts b/frontend/src/app/mocks/services/parts-mock/partsAsBuilt/partsAsBuilt.model.ts index f0173c3c83..073a91e323 100644 --- a/frontend/src/app/mocks/services/parts-mock/partsAsBuilt/partsAsBuilt.model.ts +++ b/frontend/src/app/mocks/services/parts-mock/partsAsBuilt/partsAsBuilt.model.ts @@ -182,7 +182,17 @@ export const mockBmwAssets = [ 'sentQualityInvestigationIdsInStatusActive': [], 'receivedQualityInvestigationIdsInStatusActive': [], 'importState': 'PERSISTENT', - 'importNote': 'This is a test import note.' + 'importNote': 'This is a test import note.', + 'tombstone': `\t\t{ +\t\t\t"catenaXId": "urn:uuid:68c9b1bf-b2c1-456a-883c-2aac5f5cb5f4", +\t\t\t"endpointURL": null, +\t\t\t"processingError": { +\t\t\t\t"processStep": "BpdmRequest", +\t\t\t\t"errorDetail": "Cannot find ManufacturerId for CatenaXId: urn:uuid:68c9b1bf-b2c1-456a-883c-2aac5f5cb5f4", +\t\t\t\t"lastAttempt": "2022-11-08T08:37:18.724609316Z", +\t\t\t\t"retryCounter": 0 +\t\t\t} +\t\t}` }, { 'id': 'urn:uuid:1be6ec59-40fb-4993-9836-acb0e284fa01', @@ -216,7 +226,17 @@ export const mockBmwAssets = [ 'sentQualityInvestigationIdsInStatusActive': [], 'receivedQualityInvestigationIdsInStatusActive': [], 'importState': 'PERSISTENT', - 'importNote': 'This is a test import note.' + 'importNote': 'This is a test import note.', + 'tombstone': `\t\t{ +\t\t\t"catenaXId": "urn:uuid:68c9b1bf-b2c1-456a-883c-2aac5f5cb5f4", +\t\t\t"endpointURL": null, +\t\t\t"processingError": { +\t\t\t\t"processStep": "BpdmRequest", +\t\t\t\t"errorDetail": "Cannot find ManufacturerId for CatenaXId: urn:uuid:68c9b1bf-b2c1-456a-883c-2aac5f5cb5f4", +\t\t\t\t"lastAttempt": "2022-11-08T08:37:18.724609316Z", +\t\t\t\t"retryCounter": 0 +\t\t\t} +\t\t}` }, { 'id': 'urn:uuid:d8030bbf-a874-49fb-b2e1-7610f0ccad12', diff --git a/frontend/src/app/mocks/services/parts-mock/partsAsPlanned/partsAsPlanned.model.ts b/frontend/src/app/mocks/services/parts-mock/partsAsPlanned/partsAsPlanned.model.ts index 91b2e78521..54ae54e139 100644 --- a/frontend/src/app/mocks/services/parts-mock/partsAsPlanned/partsAsPlanned.model.ts +++ b/frontend/src/app/mocks/services/parts-mock/partsAsPlanned/partsAsPlanned.model.ts @@ -100,7 +100,17 @@ export const mockBmwAsPlannedAssets = [ }, ], 'importState': 'PERSISTENT', - 'importNote': 'This is a test import note.' + 'importNote': 'This is a test import note.', + 'tombstone': `\t\t{ +\t\t\t"catenaXId": "urn:uuid:68c9b1bf-b2c1-456a-883c-2aac5f5cb5f4", +\t\t\t"endpointURL": null, +\t\t\t"processingError": { +\t\t\t\t"processStep": "BpdmRequest", +\t\t\t\t"errorDetail": "Cannot find ManufacturerId for CatenaXId: urn:uuid:68c9b1bf-b2c1-456a-883c-2aac5f5cb5f4", +\t\t\t\t"lastAttempt": "2022-11-08T08:37:18.724609316Z", +\t\t\t\t"retryCounter": 0 +\t\t\t} +\t\t}` }, { 'id': 'urn:uuid:4a5e9ff6-2d5c-4510-a90e-d55af3ba502f', diff --git a/frontend/src/app/modules/page/parts/model/parts.model.ts b/frontend/src/app/modules/page/parts/model/parts.model.ts index 1ec460d586..0247cda5cc 100644 --- a/frontend/src/app/modules/page/parts/model/parts.model.ts +++ b/frontend/src/app/modules/page/parts/model/parts.model.ts @@ -74,6 +74,7 @@ export interface Part { importNote?: string; importState?: ImportState; + tombStoneErrorDetail?: string; } export interface PartResponse { @@ -98,7 +99,8 @@ export interface PartResponse { sentQualityInvestigationIdsInStatusActive: string[], receivedQualityInvestigationIdsInStatusActive: string[] importNote?: string, - importState?: ImportState + importState?: ImportState, + tombstone?: string, } export type PartsResponse = PaginationResponse; diff --git a/frontend/src/app/modules/shared/assembler/parts.assembler.spec.ts b/frontend/src/app/modules/shared/assembler/parts.assembler.spec.ts index dc385c2251..e8c9df1d34 100644 --- a/frontend/src/app/modules/shared/assembler/parts.assembler.spec.ts +++ b/frontend/src/app/modules/shared/assembler/parts.assembler.spec.ts @@ -130,6 +130,7 @@ describe('PartsAssembler', () => { nameAtCustomer: nameAtCustomer, manufacturingDate: manufacturingDate, manufacturingCountry: manufacturingCountry, + tombStoneErrorDetail: null, }); @@ -293,6 +294,7 @@ describe('PartsAssembler', () => { describe('mapForAssetStateView', () => { const importState = 'importState'; const importNote = 'importNote'; + const tombStoneErrorDetail = 'Error'; it('should clean up data for asset state view', done => { const data = { importState, importNote, test: '' } as unknown as Part; of({ data }) @@ -311,6 +313,15 @@ describe('PartsAssembler', () => { done(); }); }); + it('should clean up data for asset state view with tombStoneErrorDetail', done => { + const data = { importState, importNote, tombStoneErrorDetail } as unknown as Part; + of({ data }) + .pipe(PartsAssembler.mapPartForAssetStateDetailsView()) + .subscribe(result => { + expect(result).toEqual({ data: { importState, importNote, tombStoneErrorDetail } as unknown as Part }); + done(); + }); + }); }); diff --git a/frontend/src/app/modules/shared/assembler/parts.assembler.ts b/frontend/src/app/modules/shared/assembler/parts.assembler.ts index 563debaa67..db8cbeebb3 100644 --- a/frontend/src/app/modules/shared/assembler/parts.assembler.ts +++ b/frontend/src/app/modules/shared/assembler/parts.assembler.ts @@ -121,8 +121,8 @@ export class PartsAssembler { receivedActiveInvestigations: partResponse.receivedQualityInvestigationIdsInStatusActive, importNote: partResponse.importNote, - importState: partResponse.importState - + importState: partResponse.importState, + tombStoneErrorDetail: partResponse.tombstone ? JSON.parse(partResponse.tombstone)?.processingError?.errorDetail : null, }; } @@ -234,8 +234,13 @@ export class PartsAssembler { return; } - const { importNote, importState } = viewData.data; - return { data: {importNote, importState} as Part}; + const { importNote, importState, tombStoneErrorDetail } = viewData.data; + + if(!viewData.data.tombStoneErrorDetail) { + return {data: {importNote, importState} as Part}; + } else { + return { data: {importNote, importState, tombStoneErrorDetail} as Part}; + } }) } diff --git a/frontend/src/app/modules/shared/components/card-list/card-list.component.html b/frontend/src/app/modules/shared/components/card-list/card-list.component.html index c45529f56a..5ee20ef421 100644 --- a/frontend/src/app/modules/shared/components/card-list/card-list.component.html +++ b/frontend/src/app/modules/shared/components/card-list/card-list.component.html @@ -24,7 +24,7 @@ {{ title }} -
+

{{ 'partDetail.' + item.key | i18n }}

@@ -40,6 +40,13 @@
+ +
+
+ {{item.value}} +
+
+

{{ item.value | autoFormat }}

diff --git a/frontend/src/app/modules/shared/components/parts-table/parts-table.component.html b/frontend/src/app/modules/shared/components/parts-table/parts-table.component.html index 807057769b..73ead38b33 100644 --- a/frontend/src/app/modules/shared/components/parts-table/parts-table.component.html +++ b/frontend/src/app/modules/shared/components/parts-table/parts-table.component.html @@ -153,6 +153,7 @@

{{ 'table.noResultFound' | i18n }}

+
{{ 'table.noResultFound' | i18n }} color="primary" > + + nearby_error + +
diff --git a/frontend/src/app/modules/shared/service/parts.service.ts b/frontend/src/app/modules/shared/service/parts.service.ts index 25d9d0493e..e6618a32df 100644 --- a/frontend/src/app/modules/shared/service/parts.service.ts +++ b/frontend/src/app/modules/shared/service/parts.service.ts @@ -93,11 +93,16 @@ export class PartsService { } public getPart(id: string): Observable { + if(!id || typeof id !== 'string') { + throw new Error('invalid ID'); + } + + const encodedId = encodeURIComponent(id); - let resultsAsBuilt = this.apiService.get(`${ this.url }/assets/as-built/${ id }`) + let resultsAsBuilt = this.apiService.get(`${ this.url }/assets/as-built/${ encodedId }`) .pipe(map(part => PartsAssembler.assemblePart(part, MainAspectType.AS_BUILT))); - let resultsAsPlanned = this.apiService.get(`${ this.url }/assets/as-planned/${ id }`) + let resultsAsPlanned = this.apiService.get(`${ this.url }/assets/as-planned/${ encodedId }`) .pipe(map(part => PartsAssembler.assemblePart(part, MainAspectType.AS_PLANNED))); return resultsAsBuilt || resultsAsPlanned; diff --git a/frontend/src/assets/locales/de/common.json b/frontend/src/assets/locales/de/common.json index d7d404dc42..b616b26164 100644 --- a/frontend/src/assets/locales/de/common.json +++ b/frontend/src/assets/locales/de/common.json @@ -65,6 +65,7 @@ "publish": "Veröffentlichen" }, "table": { + "tombStone": "Grabstein", "noResultFound": "KEINE ERGEBNISSE GEFUNDEN.", "tryAgain": "Bitte versuchen Sie es später noch einmal.", "selectPageSize": "Seite für segmentierte Elemente auswählen", diff --git a/frontend/src/assets/locales/de/partDetail.json b/frontend/src/assets/locales/de/partDetail.json index 255d878da4..1e182a05fa 100644 --- a/frontend/src/assets/locales/de/partDetail.json +++ b/frontend/src/assets/locales/de/partDetail.json @@ -1,5 +1,6 @@ { "partDetail": { + "tombStoneErrorDetail": "Grabstein Fehlerbeschreibung", "relations": "Beziehungen", "overview": "Übersicht", "manufacturerData": "Herstellerdaten", diff --git a/frontend/src/assets/locales/en/common.json b/frontend/src/assets/locales/en/common.json index a97306e724..f0de35c61f 100644 --- a/frontend/src/assets/locales/en/common.json +++ b/frontend/src/assets/locales/en/common.json @@ -65,6 +65,7 @@ "publish": "Publish" }, "table": { + "tombStone": "Tombstone", "noResultFound": "NO RESULTS FOUND.", "tryAgain": "Please try again later.", "selectPageSize": "Select page of periodic elements", diff --git a/frontend/src/assets/locales/en/partDetail.json b/frontend/src/assets/locales/en/partDetail.json index c46b3c8e43..c1a322f4af 100644 --- a/frontend/src/assets/locales/en/partDetail.json +++ b/frontend/src/assets/locales/en/partDetail.json @@ -1,5 +1,6 @@ { "partDetail": { + "tombStoneErrorDetail": "Tombstone Error details", "relations": "Relations", "overview": "Overview", "manufacturerData": "Manufacturer data", diff --git a/pom.xml b/pom.xml index 7dda5d4ee1..d731696ba6 100644 --- a/pom.xml +++ b/pom.xml @@ -60,7 +60,7 @@ SPDX-License-Identifier: Apache-2.0 4.8.3.0 3.1.3 3.4.5 - 3.9.1.2184 + 3.10.0.2594 3.2.5 3.2.5 4.0.0-M11 @@ -72,6 +72,7 @@ SPDX-License-Identifier: Apache-2.0 2.5.8 4.4.0 12.3 + 10.1.18 3.1.0 9.4.3.0 2.0.2 @@ -87,8 +88,8 @@ SPDX-License-Identifier: Apache-2.0 2.15.0 0.9.3 1.1.0 - 1.19.1 - 5.3.2 + 1.19.4 + 5.4.0 2.0.4 3.24.2 diff --git a/tx-backend/openapi/traceability-foss-backend.json b/tx-backend/openapi/traceability-foss-backend.json index ece3299649..388d545579 100644 --- a/tx-backend/openapi/traceability-foss-backend.json +++ b/tx-backend/openapi/traceability-foss-backend.json @@ -47,18 +47,20 @@ } } }, - "415" : { - "description" : "Unsupported media type", + "200" : { + "description" : "Returns the paged result found", "content" : { "application/json" : { "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" + "maxItems" : 2147483647, + "minItems" : 0, + "type" : "array" } } } }, - "500" : { - "description" : "Internal server error.", + "401" : { + "description" : "Authorization failed.", "content" : { "application/json" : { "schema" : { @@ -77,20 +79,18 @@ } } }, - "200" : { - "description" : "Returns the paged result found", + "429" : { + "description" : "Too many requests.", "content" : { "application/json" : { "schema" : { - "maxItems" : 2147483647, - "minItems" : 0, - "type" : "array" + "$ref" : "#/components/schemas/ErrorResponse" } } } }, - "400" : { - "description" : "Bad request.", + "500" : { + "description" : "Internal server error.", "content" : { "application/json" : { "schema" : { @@ -99,8 +99,8 @@ } } }, - "401" : { - "description" : "Authorization failed.", + "400" : { + "description" : "Bad request.", "content" : { "application/json" : { "schema" : { @@ -109,8 +109,8 @@ } } }, - "429" : { - "description" : "Too many requests.", + "415" : { + "description" : "Unsupported media type", "content" : { "application/json" : { "schema" : { @@ -151,20 +151,18 @@ "required" : true }, "responses" : { - "200" : { - "description" : "Returns the paged result found for BpnEdcMapping", + "403" : { + "description" : "Forbidden.", "content" : { "application/json" : { "schema" : { - "maxItems" : 2147483647, - "minItems" : 0, - "type" : "array" + "$ref" : "#/components/schemas/ErrorResponse" } } } }, - "403" : { - "description" : "Forbidden.", + "401" : { + "description" : "Authorization failed.", "content" : { "application/json" : { "schema" : { @@ -173,8 +171,8 @@ } } }, - "415" : { - "description" : "Unsupported media type", + "404" : { + "description" : "Not found.", "content" : { "application/json" : { "schema" : { @@ -183,8 +181,8 @@ } } }, - "500" : { - "description" : "Internal server error.", + "429" : { + "description" : "Too many requests.", "content" : { "application/json" : { "schema" : { @@ -193,8 +191,8 @@ } } }, - "404" : { - "description" : "Not found.", + "500" : { + "description" : "Internal server error.", "content" : { "application/json" : { "schema" : { @@ -203,18 +201,20 @@ } } }, - "400" : { - "description" : "Bad request.", + "200" : { + "description" : "Returns the paged result found for BpnEdcMapping", "content" : { "application/json" : { "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" + "maxItems" : 2147483647, + "minItems" : 0, + "type" : "array" } } } }, - "401" : { - "description" : "Authorization failed.", + "400" : { + "description" : "Bad request.", "content" : { "application/json" : { "schema" : { @@ -223,8 +223,8 @@ } } }, - "429" : { - "description" : "Too many requests.", + "415" : { + "description" : "Unsupported media type", "content" : { "application/json" : { "schema" : { @@ -265,20 +265,18 @@ "required" : true }, "responses" : { - "200" : { - "description" : "Returns the paged result found for BpnEdcMapping", + "403" : { + "description" : "Forbidden.", "content" : { "application/json" : { "schema" : { - "maxItems" : 2147483647, - "minItems" : 0, - "type" : "array" + "$ref" : "#/components/schemas/ErrorResponse" } } } }, - "403" : { - "description" : "Forbidden.", + "401" : { + "description" : "Authorization failed.", "content" : { "application/json" : { "schema" : { @@ -287,8 +285,8 @@ } } }, - "415" : { - "description" : "Unsupported media type", + "404" : { + "description" : "Not found.", "content" : { "application/json" : { "schema" : { @@ -297,8 +295,8 @@ } } }, - "500" : { - "description" : "Internal server error.", + "429" : { + "description" : "Too many requests.", "content" : { "application/json" : { "schema" : { @@ -307,8 +305,8 @@ } } }, - "404" : { - "description" : "Not found.", + "500" : { + "description" : "Internal server error.", "content" : { "application/json" : { "schema" : { @@ -317,18 +315,20 @@ } } }, - "400" : { - "description" : "Bad request.", + "200" : { + "description" : "Returns the paged result found for BpnEdcMapping", "content" : { "application/json" : { "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" + "maxItems" : 2147483647, + "minItems" : 0, + "type" : "array" } } } }, - "401" : { - "description" : "Authorization failed.", + "400" : { + "description" : "Bad request.", "content" : { "application/json" : { "schema" : { @@ -337,8 +337,8 @@ } } }, - "429" : { - "description" : "Too many requests.", + "415" : { + "description" : "Unsupported media type", "content" : { "application/json" : { "schema" : { @@ -386,8 +386,8 @@ } } }, - "415" : { - "description" : "Unsupported media type", + "401" : { + "description" : "Authorization failed.", "content" : { "application/json" : { "schema" : { @@ -396,8 +396,8 @@ } } }, - "500" : { - "description" : "Internal server error.", + "404" : { + "description" : "Not found.", "content" : { "application/json" : { "schema" : { @@ -406,14 +406,8 @@ } } }, - "200" : { - "description" : "Returns the paged result found", - "content" : { - "application/json" : {} - } - }, - "404" : { - "description" : "Not found.", + "429" : { + "description" : "Too many requests.", "content" : { "application/json" : { "schema" : { @@ -422,8 +416,8 @@ } } }, - "400" : { - "description" : "Bad request.", + "500" : { + "description" : "Internal server error.", "content" : { "application/json" : { "schema" : { @@ -432,8 +426,14 @@ } } }, - "401" : { - "description" : "Authorization failed.", + "200" : { + "description" : "Returns the paged result found", + "content" : { + "application/json" : {} + } + }, + "400" : { + "description" : "Bad request.", "content" : { "application/json" : { "schema" : { @@ -442,8 +442,8 @@ } } }, - "429" : { - "description" : "Too many requests.", + "415" : { + "description" : "Unsupported media type", "content" : { "application/json" : { "schema" : { @@ -499,8 +499,14 @@ } } }, - "415" : { - "description" : "Unsupported media type", + "204" : { + "description" : "No Content.", + "content" : { + "application/json" : {} + } + }, + "401" : { + "description" : "Authorization failed.", "content" : { "application/json" : { "schema" : { @@ -509,8 +515,8 @@ } } }, - "500" : { - "description" : "Internal server error.", + "404" : { + "description" : "Not found.", "content" : { "application/json" : { "schema" : { @@ -519,8 +525,8 @@ } } }, - "404" : { - "description" : "Not found.", + "429" : { + "description" : "Too many requests.", "content" : { "application/json" : { "schema" : { @@ -529,8 +535,8 @@ } } }, - "400" : { - "description" : "Bad request.", + "500" : { + "description" : "Internal server error.", "content" : { "application/json" : { "schema" : { @@ -545,14 +551,8 @@ "application/json" : {} } }, - "204" : { - "description" : "No Content.", - "content" : { - "application/json" : {} - } - }, - "401" : { - "description" : "Authorization failed.", + "400" : { + "description" : "Bad request.", "content" : { "application/json" : { "schema" : { @@ -561,8 +561,8 @@ } } }, - "429" : { - "description" : "Too many requests.", + "415" : { + "description" : "Unsupported media type", "content" : { "application/json" : { "schema" : { @@ -610,8 +610,8 @@ } } }, - "415" : { - "description" : "Unsupported media type", + "401" : { + "description" : "Authorization failed.", "content" : { "application/json" : { "schema" : { @@ -620,8 +620,8 @@ } } }, - "500" : { - "description" : "Internal server error.", + "404" : { + "description" : "Not found.", "content" : { "application/json" : { "schema" : { @@ -630,8 +630,8 @@ } } }, - "404" : { - "description" : "Not found.", + "429" : { + "description" : "Too many requests.", "content" : { "application/json" : { "schema" : { @@ -640,8 +640,8 @@ } } }, - "400" : { - "description" : "Bad request.", + "500" : { + "description" : "Internal server error.", "content" : { "application/json" : { "schema" : { @@ -650,28 +650,28 @@ } } }, - "201" : { - "description" : "Created.", + "400" : { + "description" : "Bad request.", "content" : { "application/json" : { "schema" : { - "$ref" : "#/components/schemas/QualityNotificationIdResponse" + "$ref" : "#/components/schemas/ErrorResponse" } } } }, - "401" : { - "description" : "Authorization failed.", + "201" : { + "description" : "Created.", "content" : { "application/json" : { "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" + "$ref" : "#/components/schemas/QualityNotificationIdResponse" } } } }, - "429" : { - "description" : "Too many requests.", + "415" : { + "description" : "Unsupported media type", "content" : { "application/json" : { "schema" : { @@ -730,8 +730,11 @@ } } }, - "415" : { - "description" : "Unsupported media type", + "204" : { + "description" : "No content." + }, + "401" : { + "description" : "Authorization failed.", "content" : { "application/json" : { "schema" : { @@ -740,8 +743,11 @@ } } }, - "500" : { - "description" : "Internal server error.", + "200" : { + "description" : "Ok." + }, + "404" : { + "description" : "Not found.", "content" : { "application/json" : { "schema" : { @@ -750,14 +756,8 @@ } } }, - "200" : { - "description" : "Ok." - }, - "204" : { - "description" : "No content." - }, - "404" : { - "description" : "Not found.", + "429" : { + "description" : "Too many requests.", "content" : { "application/json" : { "schema" : { @@ -766,8 +766,8 @@ } } }, - "400" : { - "description" : "Bad request.", + "500" : { + "description" : "Internal server error.", "content" : { "application/json" : { "schema" : { @@ -776,8 +776,8 @@ } } }, - "401" : { - "description" : "Authorization failed.", + "400" : { + "description" : "Bad request.", "content" : { "application/json" : { "schema" : { @@ -786,8 +786,8 @@ } } }, - "429" : { - "description" : "Too many requests.", + "415" : { + "description" : "Unsupported media type", "content" : { "application/json" : { "schema" : { @@ -846,18 +846,11 @@ } } }, - "415" : { - "description" : "Unsupported media type", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } + "204" : { + "description" : "No content." }, - "500" : { - "description" : "Internal server error.", + "401" : { + "description" : "Authorization failed.", "content" : { "application/json" : { "schema" : { @@ -869,9 +862,6 @@ "200" : { "description" : "Ok." }, - "204" : { - "description" : "No content." - }, "404" : { "description" : "Not found.", "content" : { @@ -882,8 +872,8 @@ } } }, - "400" : { - "description" : "Bad request.", + "429" : { + "description" : "Too many requests.", "content" : { "application/json" : { "schema" : { @@ -892,8 +882,8 @@ } } }, - "401" : { - "description" : "Authorization failed.", + "500" : { + "description" : "Internal server error.", "content" : { "application/json" : { "schema" : { @@ -902,8 +892,18 @@ } } }, - "429" : { - "description" : "Too many requests.", + "400" : { + "description" : "Bad request.", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/ErrorResponse" + } + } + } + }, + "415" : { + "description" : "Unsupported media type", "content" : { "application/json" : { "schema" : { @@ -952,8 +952,8 @@ } } }, - "415" : { - "description" : "Unsupported media type", + "401" : { + "description" : "Authorization failed.", "content" : { "application/json" : { "schema" : { @@ -962,8 +962,11 @@ } } }, - "500" : { - "description" : "Internal server error.", + "200" : { + "description" : "Ok." + }, + "404" : { + "description" : "Not found.", "content" : { "application/json" : { "schema" : { @@ -972,11 +975,8 @@ } } }, - "200" : { - "description" : "Ok." - }, - "404" : { - "description" : "Not found.", + "429" : { + "description" : "Too many requests.", "content" : { "application/json" : { "schema" : { @@ -985,11 +985,8 @@ } } }, - "204" : { - "description" : "No content." - }, - "400" : { - "description" : "Bad request.", + "500" : { + "description" : "Internal server error.", "content" : { "application/json" : { "schema" : { @@ -998,8 +995,11 @@ } } }, - "401" : { - "description" : "Authorization failed.", + "204" : { + "description" : "No content." + }, + "400" : { + "description" : "Bad request.", "content" : { "application/json" : { "schema" : { @@ -1008,8 +1008,8 @@ } } }, - "429" : { - "description" : "Too many requests.", + "415" : { + "description" : "Unsupported media type", "content" : { "application/json" : { "schema" : { @@ -1058,8 +1058,8 @@ } } }, - "415" : { - "description" : "Unsupported media type", + "401" : { + "description" : "Authorization failed.", "content" : { "application/json" : { "schema" : { @@ -1068,8 +1068,11 @@ } } }, - "500" : { - "description" : "Internal server error.", + "200" : { + "description" : "Ok." + }, + "404" : { + "description" : "Not found.", "content" : { "application/json" : { "schema" : { @@ -1078,11 +1081,8 @@ } } }, - "200" : { - "description" : "Ok." - }, - "404" : { - "description" : "Not found.", + "429" : { + "description" : "Too many requests.", "content" : { "application/json" : { "schema" : { @@ -1091,11 +1091,8 @@ } } }, - "204" : { - "description" : "No content." - }, - "400" : { - "description" : "Bad request.", + "500" : { + "description" : "Internal server error.", "content" : { "application/json" : { "schema" : { @@ -1104,8 +1101,11 @@ } } }, - "401" : { - "description" : "Authorization failed.", + "204" : { + "description" : "No content." + }, + "400" : { + "description" : "Bad request.", "content" : { "application/json" : { "schema" : { @@ -1114,8 +1114,8 @@ } } }, - "429" : { - "description" : "Too many requests.", + "415" : { + "description" : "Unsupported media type", "content" : { "application/json" : { "schema" : { @@ -1163,8 +1163,8 @@ } } }, - "415" : { - "description" : "Unsupported media type", + "401" : { + "description" : "Authorization failed.", "content" : { "application/json" : { "schema" : { @@ -1173,8 +1173,8 @@ } } }, - "500" : { - "description" : "Internal server error.", + "404" : { + "description" : "Not found.", "content" : { "application/json" : { "schema" : { @@ -1183,8 +1183,8 @@ } } }, - "404" : { - "description" : "Not found.", + "429" : { + "description" : "Too many requests.", "content" : { "application/json" : { "schema" : { @@ -1193,30 +1193,30 @@ } } }, - "200" : { - "description" : "Returns the paged result found for Asset", + "500" : { + "description" : "Internal server error.", "content" : { "application/json" : { "schema" : { - "maxItems" : 2147483647, - "minItems" : 0, - "type" : "array" + "$ref" : "#/components/schemas/ErrorResponse" } } } }, - "400" : { - "description" : "Bad request.", + "200" : { + "description" : "Returns the paged result found for Asset", "content" : { "application/json" : { "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" + "maxItems" : 2147483647, + "minItems" : 0, + "type" : "array" } } } }, - "401" : { - "description" : "Authorization failed.", + "400" : { + "description" : "Bad request.", "content" : { "application/json" : { "schema" : { @@ -1225,8 +1225,8 @@ } } }, - "429" : { - "description" : "Too many requests.", + "415" : { + "description" : "Unsupported media type", "content" : { "application/json" : { "schema" : { @@ -1274,8 +1274,8 @@ } } }, - "415" : { - "description" : "Unsupported media type", + "401" : { + "description" : "Authorization failed.", "content" : { "application/json" : { "schema" : { @@ -1284,8 +1284,8 @@ } } }, - "500" : { - "description" : "Internal server error.", + "404" : { + "description" : "Not found.", "content" : { "application/json" : { "schema" : { @@ -1294,8 +1294,8 @@ } } }, - "404" : { - "description" : "Not found.", + "429" : { + "description" : "Too many requests.", "content" : { "application/json" : { "schema" : { @@ -1304,8 +1304,8 @@ } } }, - "400" : { - "description" : "Bad request.", + "500" : { + "description" : "Internal server error.", "content" : { "application/json" : { "schema" : { @@ -1314,28 +1314,28 @@ } } }, - "201" : { - "description" : "Created.", + "400" : { + "description" : "Bad request.", "content" : { "application/json" : { "schema" : { - "$ref" : "#/components/schemas/CreateNotificationContractResponse" + "$ref" : "#/components/schemas/ErrorResponse" } } } }, - "401" : { - "description" : "Authorization failed.", + "201" : { + "description" : "Created.", "content" : { "application/json" : { "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" + "$ref" : "#/components/schemas/CreateNotificationContractResponse" } } } }, - "429" : { - "description" : "Too many requests.", + "415" : { + "description" : "Unsupported media type", "content" : { "application/json" : { "schema" : { @@ -1374,6 +1374,9 @@ "required" : true }, "responses" : { + "204" : { + "description" : "No Content." + }, "403" : { "description" : "Forbidden.", "content" : { @@ -1384,8 +1387,8 @@ } } }, - "415" : { - "description" : "Unsupported media type", + "401" : { + "description" : "Authorization failed.", "content" : { "application/json" : { "schema" : { @@ -1394,8 +1397,8 @@ } } }, - "500" : { - "description" : "Internal server error.", + "404" : { + "description" : "Not found.", "content" : { "application/json" : { "schema" : { @@ -1404,11 +1407,8 @@ } } }, - "204" : { - "description" : "No Content." - }, - "404" : { - "description" : "Not found.", + "429" : { + "description" : "Too many requests.", "content" : { "application/json" : { "schema" : { @@ -1417,8 +1417,8 @@ } } }, - "400" : { - "description" : "Bad request.", + "500" : { + "description" : "Internal server error.", "content" : { "application/json" : { "schema" : { @@ -1433,8 +1433,8 @@ "application/json" : {} } }, - "401" : { - "description" : "Authorization failed.", + "400" : { + "description" : "Bad request.", "content" : { "application/json" : { "schema" : { @@ -1443,8 +1443,8 @@ } } }, - "429" : { - "description" : "Too many requests.", + "415" : { + "description" : "Unsupported media type", "content" : { "application/json" : { "schema" : { @@ -1490,6 +1490,9 @@ } }, "responses" : { + "204" : { + "description" : "No Content." + }, "403" : { "description" : "Forbidden.", "content" : { @@ -1500,8 +1503,8 @@ } } }, - "415" : { - "description" : "Unsupported media type", + "401" : { + "description" : "Authorization failed.", "content" : { "application/json" : { "schema" : { @@ -1510,8 +1513,8 @@ } } }, - "500" : { - "description" : "Internal server error.", + "404" : { + "description" : "Not found.", "content" : { "application/json" : { "schema" : { @@ -1520,11 +1523,8 @@ } } }, - "204" : { - "description" : "No Content." - }, - "404" : { - "description" : "Not found.", + "429" : { + "description" : "Too many requests.", "content" : { "application/json" : { "schema" : { @@ -1533,8 +1533,8 @@ } } }, - "400" : { - "description" : "Bad request.", + "500" : { + "description" : "Internal server error.", "content" : { "application/json" : { "schema" : { @@ -1549,8 +1549,8 @@ "application/json" : {} } }, - "401" : { - "description" : "Authorization failed.", + "400" : { + "description" : "Bad request.", "content" : { "application/json" : { "schema" : { @@ -1559,8 +1559,8 @@ } } }, - "429" : { - "description" : "Too many requests.", + "415" : { + "description" : "Unsupported media type", "content" : { "application/json" : { "schema" : { @@ -1608,8 +1608,8 @@ } } }, - "415" : { - "description" : "Unsupported media type", + "401" : { + "description" : "Authorization failed.", "content" : { "application/json" : { "schema" : { @@ -1618,8 +1618,8 @@ } } }, - "500" : { - "description" : "Internal server error.", + "404" : { + "description" : "Not found.", "content" : { "application/json" : { "schema" : { @@ -1628,8 +1628,8 @@ } } }, - "404" : { - "description" : "Not found.", + "429" : { + "description" : "Too many requests.", "content" : { "application/json" : { "schema" : { @@ -1638,8 +1638,8 @@ } } }, - "400" : { - "description" : "Bad request.", + "500" : { + "description" : "Internal server error.", "content" : { "application/json" : { "schema" : { @@ -1648,11 +1648,8 @@ } } }, - "201" : { - "description" : "Created." - }, - "401" : { - "description" : "Authorization failed.", + "400" : { + "description" : "Bad request.", "content" : { "application/json" : { "schema" : { @@ -1661,8 +1658,11 @@ } } }, - "429" : { - "description" : "Too many requests.", + "201" : { + "description" : "Created." + }, + "415" : { + "description" : "Unsupported media type", "content" : { "application/json" : { "schema" : { @@ -1710,8 +1710,8 @@ } } }, - "415" : { - "description" : "Unsupported media type", + "401" : { + "description" : "Authorization failed.", "content" : { "application/json" : { "schema" : { @@ -1720,8 +1720,8 @@ } } }, - "500" : { - "description" : "Internal server error.", + "404" : { + "description" : "Not found.", "content" : { "application/json" : { "schema" : { @@ -1730,20 +1730,18 @@ } } }, - "200" : { - "description" : "Returns the paged result found for Asset", + "429" : { + "description" : "Too many requests.", "content" : { "application/json" : { "schema" : { - "maxItems" : 2147483647, - "minItems" : 0, - "type" : "array" + "$ref" : "#/components/schemas/ErrorResponse" } } } }, - "404" : { - "description" : "Not found.", + "500" : { + "description" : "Internal server error.", "content" : { "application/json" : { "schema" : { @@ -1752,18 +1750,20 @@ } } }, - "400" : { - "description" : "Bad request.", + "200" : { + "description" : "Returns the paged result found for Asset", "content" : { "application/json" : { "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" + "maxItems" : 2147483647, + "minItems" : 0, + "type" : "array" } } } }, - "401" : { - "description" : "Authorization failed.", + "400" : { + "description" : "Bad request.", "content" : { "application/json" : { "schema" : { @@ -1772,8 +1772,8 @@ } } }, - "429" : { - "description" : "Too many requests.", + "415" : { + "description" : "Unsupported media type", "content" : { "application/json" : { "schema" : { @@ -1821,8 +1821,8 @@ } } }, - "415" : { - "description" : "Unsupported media type", + "401" : { + "description" : "Authorization failed.", "content" : { "application/json" : { "schema" : { @@ -1831,8 +1831,8 @@ } } }, - "500" : { - "description" : "Internal server error.", + "404" : { + "description" : "Not found.", "content" : { "application/json" : { "schema" : { @@ -1841,8 +1841,8 @@ } } }, - "404" : { - "description" : "Not found.", + "429" : { + "description" : "Too many requests.", "content" : { "application/json" : { "schema" : { @@ -1851,8 +1851,8 @@ } } }, - "400" : { - "description" : "Bad request.", + "500" : { + "description" : "Internal server error.", "content" : { "application/json" : { "schema" : { @@ -1861,11 +1861,8 @@ } } }, - "201" : { - "description" : "Created." - }, - "401" : { - "description" : "Authorization failed.", + "400" : { + "description" : "Bad request.", "content" : { "application/json" : { "schema" : { @@ -1874,8 +1871,11 @@ } } }, - "429" : { - "description" : "Too many requests.", + "201" : { + "description" : "Created." + }, + "415" : { + "description" : "Unsupported media type", "content" : { "application/json" : { "schema" : { @@ -1923,8 +1923,8 @@ } } }, - "415" : { - "description" : "Unsupported media type", + "401" : { + "description" : "Authorization failed.", "content" : { "application/json" : { "schema" : { @@ -1933,8 +1933,8 @@ } } }, - "500" : { - "description" : "Internal server error.", + "404" : { + "description" : "Not found.", "content" : { "application/json" : { "schema" : { @@ -1943,8 +1943,8 @@ } } }, - "404" : { - "description" : "Not found.", + "429" : { + "description" : "Too many requests.", "content" : { "application/json" : { "schema" : { @@ -1953,30 +1953,30 @@ } } }, - "200" : { - "description" : "Returns the paged result found for Asset", + "500" : { + "description" : "Internal server error.", "content" : { "application/json" : { "schema" : { - "maxItems" : 2147483647, - "minItems" : 0, - "type" : "array" + "$ref" : "#/components/schemas/ErrorResponse" } } } }, - "400" : { - "description" : "Bad request.", + "200" : { + "description" : "Returns the paged result found for Asset", "content" : { "application/json" : { "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" + "maxItems" : 2147483647, + "minItems" : 0, + "type" : "array" } } } }, - "401" : { - "description" : "Authorization failed.", + "400" : { + "description" : "Bad request.", "content" : { "application/json" : { "schema" : { @@ -1985,8 +1985,8 @@ } } }, - "429" : { - "description" : "Too many requests.", + "415" : { + "description" : "Unsupported media type", "content" : { "application/json" : { "schema" : { @@ -2034,8 +2034,8 @@ } } }, - "415" : { - "description" : "Unsupported media type", + "401" : { + "description" : "Authorization failed.", "content" : { "application/json" : { "schema" : { @@ -2044,8 +2044,8 @@ } } }, - "500" : { - "description" : "Internal server error.", + "404" : { + "description" : "Not found.", "content" : { "application/json" : { "schema" : { @@ -2054,8 +2054,8 @@ } } }, - "404" : { - "description" : "Not found.", + "429" : { + "description" : "Too many requests.", "content" : { "application/json" : { "schema" : { @@ -2064,8 +2064,8 @@ } } }, - "400" : { - "description" : "Bad request.", + "500" : { + "description" : "Internal server error.", "content" : { "application/json" : { "schema" : { @@ -2074,28 +2074,28 @@ } } }, - "201" : { - "description" : "Created.", + "400" : { + "description" : "Bad request.", "content" : { "application/json" : { "schema" : { - "$ref" : "#/components/schemas/QualityNotificationIdResponse" + "$ref" : "#/components/schemas/ErrorResponse" } } } }, - "401" : { - "description" : "Authorization failed.", + "201" : { + "description" : "Created.", "content" : { "application/json" : { "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" + "$ref" : "#/components/schemas/QualityNotificationIdResponse" } } } }, - "429" : { - "description" : "Too many requests.", + "415" : { + "description" : "Unsupported media type", "content" : { "application/json" : { "schema" : { @@ -2154,8 +2154,11 @@ } } }, - "415" : { - "description" : "Unsupported media type", + "204" : { + "description" : "No content." + }, + "401" : { + "description" : "Authorization failed.", "content" : { "application/json" : { "schema" : { @@ -2164,8 +2167,8 @@ } } }, - "500" : { - "description" : "Internal server error.", + "404" : { + "description" : "Not found.", "content" : { "application/json" : { "schema" : { @@ -2174,11 +2177,8 @@ } } }, - "204" : { - "description" : "No content." - }, - "404" : { - "description" : "Not found.", + "429" : { + "description" : "Too many requests.", "content" : { "application/json" : { "schema" : { @@ -2187,8 +2187,8 @@ } } }, - "400" : { - "description" : "Bad request.", + "500" : { + "description" : "Internal server error.", "content" : { "application/json" : { "schema" : { @@ -2197,8 +2197,8 @@ } } }, - "401" : { - "description" : "Authorization failed.", + "400" : { + "description" : "Bad request.", "content" : { "application/json" : { "schema" : { @@ -2207,8 +2207,8 @@ } } }, - "429" : { - "description" : "Too many requests.", + "415" : { + "description" : "Unsupported media type", "content" : { "application/json" : { "schema" : { @@ -2267,8 +2267,11 @@ } } }, - "415" : { - "description" : "Unsupported media type", + "204" : { + "description" : "No content." + }, + "401" : { + "description" : "Authorization failed.", "content" : { "application/json" : { "schema" : { @@ -2277,8 +2280,11 @@ } } }, - "500" : { - "description" : "Internal server error.", + "200" : { + "description" : "Ok." + }, + "404" : { + "description" : "Not found.", "content" : { "application/json" : { "schema" : { @@ -2287,14 +2293,8 @@ } } }, - "200" : { - "description" : "Ok." - }, - "204" : { - "description" : "No content." - }, - "404" : { - "description" : "Not found.", + "429" : { + "description" : "Too many requests.", "content" : { "application/json" : { "schema" : { @@ -2303,8 +2303,8 @@ } } }, - "400" : { - "description" : "Bad request.", + "500" : { + "description" : "Internal server error.", "content" : { "application/json" : { "schema" : { @@ -2313,8 +2313,8 @@ } } }, - "401" : { - "description" : "Authorization failed.", + "400" : { + "description" : "Bad request.", "content" : { "application/json" : { "schema" : { @@ -2323,8 +2323,8 @@ } } }, - "429" : { - "description" : "Too many requests.", + "415" : { + "description" : "Unsupported media type", "content" : { "application/json" : { "schema" : { @@ -2373,8 +2373,8 @@ } } }, - "415" : { - "description" : "Unsupported media type", + "401" : { + "description" : "Authorization failed.", "content" : { "application/json" : { "schema" : { @@ -2383,8 +2383,11 @@ } } }, - "500" : { - "description" : "Internal server error.", + "200" : { + "description" : "Ok." + }, + "404" : { + "description" : "Not found.", "content" : { "application/json" : { "schema" : { @@ -2393,11 +2396,8 @@ } } }, - "200" : { - "description" : "Ok." - }, - "404" : { - "description" : "Not found.", + "429" : { + "description" : "Too many requests.", "content" : { "application/json" : { "schema" : { @@ -2406,11 +2406,8 @@ } } }, - "204" : { - "description" : "No content." - }, - "400" : { - "description" : "Bad request.", + "500" : { + "description" : "Internal server error.", "content" : { "application/json" : { "schema" : { @@ -2419,8 +2416,11 @@ } } }, - "401" : { - "description" : "Authorization failed.", + "204" : { + "description" : "No content." + }, + "400" : { + "description" : "Bad request.", "content" : { "application/json" : { "schema" : { @@ -2429,8 +2429,8 @@ } } }, - "429" : { - "description" : "Too many requests.", + "415" : { + "description" : "Unsupported media type", "content" : { "application/json" : { "schema" : { @@ -2479,18 +2479,8 @@ } } }, - "415" : { - "description" : "Unsupported media type", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "500" : { - "description" : "Internal server error.", + "401" : { + "description" : "Authorization failed.", "content" : { "application/json" : { "schema" : { @@ -2512,11 +2502,18 @@ } } }, - "204" : { - "description" : "No content." + "429" : { + "description" : "Too many requests.", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/ErrorResponse" + } + } + } }, - "400" : { - "description" : "Bad request.", + "500" : { + "description" : "Internal server error.", "content" : { "application/json" : { "schema" : { @@ -2525,8 +2522,11 @@ } } }, - "401" : { - "description" : "Authorization failed.", + "204" : { + "description" : "No content." + }, + "400" : { + "description" : "Bad request.", "content" : { "application/json" : { "schema" : { @@ -2535,8 +2535,8 @@ } } }, - "429" : { - "description" : "Too many requests.", + "415" : { + "description" : "Unsupported media type", "content" : { "application/json" : { "schema" : { @@ -2584,8 +2584,8 @@ } } }, - "415" : { - "description" : "Unsupported media type", + "401" : { + "description" : "Authorization failed.", "content" : { "application/json" : { "schema" : { @@ -2594,8 +2594,8 @@ } } }, - "500" : { - "description" : "Internal server error.", + "404" : { + "description" : "Not found.", "content" : { "application/json" : { "schema" : { @@ -2604,19 +2604,18 @@ } } }, - "200" : { - "description" : "Returns the paged result found for Asset", + "429" : { + "description" : "Too many requests.", "content" : { "application/json" : { "schema" : { - "maxItems" : 2147483647, - "type" : "array" + "$ref" : "#/components/schemas/ErrorResponse" } } } }, - "404" : { - "description" : "Not found.", + "500" : { + "description" : "Internal server error.", "content" : { "application/json" : { "schema" : { @@ -2635,18 +2634,19 @@ } } }, - "401" : { - "description" : "Authorization failed.", + "200" : { + "description" : "Returns the paged result found for Asset", "content" : { "application/json" : { "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" + "maxItems" : 2147483647, + "type" : "array" } } } }, - "429" : { - "description" : "Too many requests.", + "415" : { + "description" : "Unsupported media type", "content" : { "application/json" : { "schema" : { @@ -2694,8 +2694,8 @@ } } }, - "415" : { - "description" : "Unsupported media type", + "401" : { + "description" : "Authorization failed.", "content" : { "application/json" : { "schema" : { @@ -2704,8 +2704,18 @@ } } }, - "500" : { - "description" : "Internal server error.", + "404" : { + "description" : "Not found.", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/ErrorResponse" + } + } + } + }, + "429" : { + "description" : "Too many requests.", "content" : { "application/json" : { "schema" : { @@ -2868,8 +2878,8 @@ } } }, - "404" : { - "description" : "Not found.", + "500" : { + "description" : "Internal server error.", "content" : { "application/json" : { "schema" : { @@ -2888,18 +2898,8 @@ } } }, - "401" : { - "description" : "Authorization failed.", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "429" : { - "description" : "Too many requests.", + "415" : { + "description" : "Unsupported media type", "content" : { "application/json" : { "schema" : { @@ -2955,18 +2955,8 @@ } } }, - "415" : { - "description" : "Unsupported media type", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "500" : { - "description" : "Internal server error.", + "401" : { + "description" : "Authorization failed.", "content" : { "application/json" : { "schema" : { @@ -3139,8 +3129,8 @@ } } }, - "400" : { - "description" : "Bad request.", + "429" : { + "description" : "Too many requests.", "content" : { "application/json" : { "schema" : { @@ -3149,8 +3139,8 @@ } } }, - "401" : { - "description" : "Authorization failed.", + "500" : { + "description" : "Internal server error.", "content" : { "application/json" : { "schema" : { @@ -3159,8 +3149,18 @@ } } }, - "429" : { - "description" : "Too many requests.", + "400" : { + "description" : "Bad request.", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/ErrorResponse" + } + } + } + }, + "415" : { + "description" : "Unsupported media type", "content" : { "application/json" : { "schema" : { @@ -3208,66 +3208,6 @@ } } }, - "415" : { - "description" : "Unsupported media type", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "500" : { - "description" : "Internal server error.", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "404" : { - "description" : "Not found.", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "400" : { - "description" : "Bad request.", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "401" : { - "description" : "Authorization failed.", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "429" : { - "description" : "Too many requests.", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, "200" : { "description" : "Returns the assets found", "content" : { @@ -3421,6 +3361,66 @@ } } } + }, + "401" : { + "description" : "Authorization failed.", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/ErrorResponse" + } + } + } + }, + "404" : { + "description" : "Not found.", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/ErrorResponse" + } + } + } + }, + "429" : { + "description" : "Too many requests.", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/ErrorResponse" + } + } + } + }, + "500" : { + "description" : "Internal server error.", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/ErrorResponse" + } + } + } + }, + "400" : { + "description" : "Bad request.", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/ErrorResponse" + } + } + } + }, + "415" : { + "description" : "Unsupported media type", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/ErrorResponse" + } + } + } } }, "security" : [ @@ -3469,8 +3469,28 @@ } } }, - "415" : { - "description" : "Unsupported media type", + "401" : { + "description" : "Authorization failed.", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/ErrorResponse" + } + } + } + }, + "404" : { + "description" : "Not found.", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/ErrorResponse" + } + } + } + }, + "429" : { + "description" : "Too many requests.", "content" : { "application/json" : { "schema" : { @@ -3489,8 +3509,8 @@ } } }, - "404" : { - "description" : "Not found.", + "400" : { + "description" : "Bad request.", "content" : { "application/json" : { "schema" : { @@ -3653,28 +3673,8 @@ } } }, - "400" : { - "description" : "Bad request.", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "401" : { - "description" : "Authorization failed.", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "429" : { - "description" : "Too many requests.", + "415" : { + "description" : "Unsupported media type", "content" : { "application/json" : { "schema" : { @@ -3712,8 +3712,8 @@ } } }, - "415" : { - "description" : "Unsupported media type", + "401" : { + "description" : "Authorization failed.", "content" : { "application/json" : { "schema" : { @@ -3722,8 +3722,8 @@ } } }, - "500" : { - "description" : "Internal server error.", + "404" : { + "description" : "Not found.", "content" : { "application/json" : { "schema" : { @@ -3732,11 +3732,8 @@ } } }, - "202" : { - "description" : "Created registry reload job." - }, - "404" : { - "description" : "Not found.", + "429" : { + "description" : "Too many requests.", "content" : { "application/json" : { "schema" : { @@ -3745,8 +3742,8 @@ } } }, - "400" : { - "description" : "Bad request.", + "500" : { + "description" : "Internal server error.", "content" : { "application/json" : { "schema" : { @@ -3755,8 +3752,11 @@ } } }, - "401" : { - "description" : "Authorization failed.", + "202" : { + "description" : "Created registry reload job." + }, + "400" : { + "description" : "Bad request.", "content" : { "application/json" : { "schema" : { @@ -3765,8 +3765,8 @@ } } }, - "429" : { - "description" : "Too many requests.", + "415" : { + "description" : "Unsupported media type", "content" : { "application/json" : { "schema" : { @@ -3804,8 +3804,8 @@ } } }, - "415" : { - "description" : "Unsupported media type", + "401" : { + "description" : "Authorization failed.", "content" : { "application/json" : { "schema" : { @@ -3814,12 +3814,12 @@ } } }, - "500" : { - "description" : "Internal server error.", + "200" : { + "description" : "Returns the policies", "content" : { - "application/json" : { + "*/*" : { "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" + "$ref" : "#/components/schemas/PolicyResponse" } } } @@ -3834,8 +3834,8 @@ } } }, - "400" : { - "description" : "Bad request.", + "429" : { + "description" : "Too many requests.", "content" : { "application/json" : { "schema" : { @@ -3844,18 +3844,18 @@ } } }, - "200" : { - "description" : "Returns the policies", + "500" : { + "description" : "Internal server error.", "content" : { - "*/*" : { + "application/json" : { "schema" : { - "$ref" : "#/components/schemas/PolicyResponse" + "$ref" : "#/components/schemas/ErrorResponse" } } } }, - "401" : { - "description" : "Authorization failed.", + "400" : { + "description" : "Bad request.", "content" : { "application/json" : { "schema" : { @@ -3864,8 +3864,8 @@ } } }, - "429" : { - "description" : "Too many requests.", + "415" : { + "description" : "Unsupported media type", "content" : { "application/json" : { "schema" : { @@ -3914,18 +3914,8 @@ } } }, - "415" : { - "description" : "Unsupported media type", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "500" : { - "description" : "Internal server error.", + "401" : { + "description" : "Authorization failed.", "content" : { "application/json" : { "schema" : { @@ -3960,8 +3950,8 @@ } } }, - "400" : { - "description" : "Bad request.", + "429" : { + "description" : "Too many requests.", "content" : { "application/json" : { "schema" : { @@ -3970,8 +3960,8 @@ } } }, - "401" : { - "description" : "Authorization failed.", + "500" : { + "description" : "Internal server error.", "content" : { "application/json" : { "schema" : { @@ -3980,8 +3970,18 @@ } } }, - "429" : { - "description" : "Too many requests.", + "400" : { + "description" : "Bad request.", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/ErrorResponse" + } + } + } + }, + "415" : { + "description" : "Unsupported media type", "content" : { "application/json" : { "schema" : { @@ -4049,18 +4049,119 @@ } ], "responses" : { - "403" : { - "description" : "Forbidden.", + "403" : { + "description" : "Forbidden.", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/ErrorResponse" + } + } + } + }, + "401" : { + "description" : "Authorization failed.", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/ErrorResponse" + } + } + } + }, + "404" : { + "description" : "Not found.", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/ErrorResponse" + } + } + } + }, + "429" : { + "description" : "Too many requests.", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/ErrorResponse" + } + } + } + }, + "500" : { + "description" : "Internal server error.", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/ErrorResponse" + } + } + } + }, + "400" : { + "description" : "Bad request.", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/ErrorResponse" + } + } + } + }, + "200" : { + "description" : "Returns a distinct filter values for given fieldName.", + "content" : { + "application/json" : { + "schema" : { + "maxItems" : 2147483647, + "minItems" : 0, + "type" : "array" + } + } + } + }, + "415" : { + "description" : "Unsupported media type", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security" : [ + { + "oAuth2" : [ + "profile email" + ] + } + ] + } + }, + "/dashboard" : { + "get" : { + "tags" : [ + "Dashboard" + ], + "summary" : "Returns dashboard related data", + "description" : "The endpoint can return limited data based on the user role", + "operationId" : "dashboard", + "responses" : { + "200" : { + "description" : "Returns dashboard data", "content" : { "application/json" : { "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" + "$ref" : "#/components/schemas/DashboardResponse" } } } }, - "415" : { - "description" : "Unsupported media type", + "403" : { + "description" : "Forbidden.", "content" : { "application/json" : { "schema" : { @@ -4069,8 +4170,8 @@ } } }, - "500" : { - "description" : "Internal server error.", + "401" : { + "description" : "Authorization failed.", "content" : { "application/json" : { "schema" : { @@ -4079,20 +4180,18 @@ } } }, - "200" : { - "description" : "Returns a distinct filter values for given fieldName.", + "404" : { + "description" : "Not found.", "content" : { "application/json" : { "schema" : { - "maxItems" : 2147483647, - "minItems" : 0, - "type" : "array" + "$ref" : "#/components/schemas/ErrorResponse" } } } }, - "404" : { - "description" : "Not found.", + "429" : { + "description" : "Too many requests.", "content" : { "application/json" : { "schema" : { @@ -4101,8 +4200,8 @@ } } }, - "400" : { - "description" : "Bad request.", + "500" : { + "description" : "Internal server error.", "content" : { "application/json" : { "schema" : { @@ -4111,8 +4210,8 @@ } } }, - "401" : { - "description" : "Authorization failed.", + "400" : { + "description" : "Bad request.", "content" : { "application/json" : { "schema" : { @@ -4121,8 +4220,8 @@ } } }, - "429" : { - "description" : "Too many requests.", + "415" : { + "description" : "Unsupported media type", "content" : { "application/json" : { "schema" : { @@ -4141,15 +4240,29 @@ ] } }, - "/dashboard" : { + "/assets/import/report/{importJobId}" : { "get" : { "tags" : [ - "Dashboard" + "ImportReport", + "AssetsImport" + ], + "summary" : "report of the imported assets", + "description" : "This endpoint returns information about the imported assets to Trace-X.", + "operationId" : "importReport", + "parameters" : [ + { + "name" : "importJobId", + "in" : "path", + "required" : true, + "schema" : { + "type" : "string" + } + } ], - "summary" : "Returns dashboard related data", - "description" : "The endpoint can return limited data based on the user role", - "operationId" : "dashboard", "responses" : { + "204" : { + "description" : "No Content." + }, "403" : { "description" : "Forbidden.", "content" : { @@ -4160,8 +4273,8 @@ } } }, - "415" : { - "description" : "Unsupported media type", + "401" : { + "description" : "Authorization failed.", "content" : { "application/json" : { "schema" : { @@ -4170,8 +4283,8 @@ } } }, - "500" : { - "description" : "Internal server error.", + "404" : { + "description" : "Not found.", "content" : { "application/json" : { "schema" : { @@ -4180,18 +4293,18 @@ } } }, - "200" : { - "description" : "Returns dashboard data", + "429" : { + "description" : "Too many requests.", "content" : { "application/json" : { "schema" : { - "$ref" : "#/components/schemas/DashboardResponse" + "$ref" : "#/components/schemas/ErrorResponse" } } } }, - "404" : { - "description" : "Not found.", + "500" : { + "description" : "Internal server error.", "content" : { "application/json" : { "schema" : { @@ -4200,18 +4313,18 @@ } } }, - "400" : { - "description" : "Bad request.", + "200" : { + "description" : "OK.", "content" : { "application/json" : { "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" + "$ref" : "#/components/schemas/ImportReportResponse" } } } }, - "401" : { - "description" : "Authorization failed.", + "400" : { + "description" : "Bad request.", "content" : { "application/json" : { "schema" : { @@ -4220,8 +4333,8 @@ } } }, - "429" : { - "description" : "Too many requests.", + "415" : { + "description" : "Unsupported media type", "content" : { "application/json" : { "schema" : { @@ -4436,8 +4549,8 @@ } } }, - "415" : { - "description" : "Unsupported media type", + "401" : { + "description" : "Authorization failed.", "content" : { "application/json" : { "schema" : { @@ -4446,8 +4559,8 @@ } } }, - "500" : { - "description" : "Internal server error.", + "404" : { + "description" : "Not found.", "content" : { "application/json" : { "schema" : { @@ -4456,8 +4569,8 @@ } } }, - "404" : { - "description" : "Not found.", + "429" : { + "description" : "Too many requests.", "content" : { "application/json" : { "schema" : { @@ -4466,8 +4579,8 @@ } } }, - "400" : { - "description" : "Bad request.", + "500" : { + "description" : "Internal server error.", "content" : { "application/json" : { "schema" : { @@ -4476,8 +4589,8 @@ } } }, - "401" : { - "description" : "Authorization failed.", + "400" : { + "description" : "Bad request.", "content" : { "application/json" : { "schema" : { @@ -4486,8 +4599,8 @@ } } }, - "429" : { - "description" : "Too many requests.", + "415" : { + "description" : "Unsupported media type", "content" : { "application/json" : { "schema" : { @@ -4567,8 +4680,8 @@ } } }, - "415" : { - "description" : "Unsupported media type", + "401" : { + "description" : "Authorization failed.", "content" : { "application/json" : { "schema" : { @@ -4577,8 +4690,8 @@ } } }, - "500" : { - "description" : "Internal server error.", + "404" : { + "description" : "Not found.", "content" : { "application/json" : { "schema" : { @@ -4587,20 +4700,18 @@ } } }, - "200" : { - "description" : "Returns a distinct filter values for given fieldName.", + "429" : { + "description" : "Too many requests.", "content" : { "application/json" : { "schema" : { - "maxItems" : 2147483647, - "minItems" : 0, - "type" : "array" + "$ref" : "#/components/schemas/ErrorResponse" } } } }, - "404" : { - "description" : "Not found.", + "500" : { + "description" : "Internal server error.", "content" : { "application/json" : { "schema" : { @@ -4619,18 +4730,20 @@ } } }, - "401" : { - "description" : "Authorization failed.", + "200" : { + "description" : "Returns a distinct filter values for given fieldName.", "content" : { "application/json" : { "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" + "maxItems" : 2147483647, + "minItems" : 0, + "type" : "array" } } } }, - "429" : { - "description" : "Too many requests.", + "415" : { + "description" : "Unsupported media type", "content" : { "application/json" : { "schema" : { @@ -4678,8 +4791,8 @@ } } }, - "415" : { - "description" : "Unsupported media type", + "401" : { + "description" : "Authorization failed.", "content" : { "application/json" : { "schema" : { @@ -4688,8 +4801,8 @@ } } }, - "500" : { - "description" : "Internal server error.", + "404" : { + "description" : "Not found.", "content" : { "application/json" : { "schema" : { @@ -4698,8 +4811,18 @@ } } }, - "404" : { - "description" : "Not found.", + "429" : { + "description" : "Too many requests.", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/ErrorResponse" + } + } + } + }, + "500" : { + "description" : "Internal server error.", "content" : { "application/json" : { "schema" : { @@ -4872,18 +4995,8 @@ } } }, - "401" : { - "description" : "Authorization failed.", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "429" : { - "description" : "Too many requests.", + "415" : { + "description" : "Unsupported media type", "content" : { "application/json" : { "schema" : { @@ -4939,8 +5052,8 @@ } } }, - "415" : { - "description" : "Unsupported media type", + "401" : { + "description" : "Authorization failed.", "content" : { "application/json" : { "schema" : { @@ -4949,8 +5062,8 @@ } } }, - "500" : { - "description" : "Internal server error.", + "404" : { + "description" : "Not found.", "content" : { "application/json" : { "schema" : { @@ -4959,8 +5072,8 @@ } } }, - "404" : { - "description" : "Not found.", + "429" : { + "description" : "Too many requests.", "content" : { "application/json" : { "schema" : { @@ -4969,8 +5082,8 @@ } } }, - "400" : { - "description" : "Bad request.", + "500" : { + "description" : "Internal server error.", "content" : { "application/json" : { "schema" : { @@ -5138,8 +5251,8 @@ } } }, - "401" : { - "description" : "Authorization failed.", + "400" : { + "description" : "Bad request.", "content" : { "application/json" : { "schema" : { @@ -5148,8 +5261,8 @@ } } }, - "429" : { - "description" : "Too many requests.", + "415" : { + "description" : "Unsupported media type", "content" : { "application/json" : { "schema" : { @@ -5229,8 +5342,8 @@ } } }, - "415" : { - "description" : "Unsupported media type", + "401" : { + "description" : "Authorization failed.", "content" : { "application/json" : { "schema" : { @@ -5239,8 +5352,8 @@ } } }, - "500" : { - "description" : "Internal server error.", + "404" : { + "description" : "Not found.", "content" : { "application/json" : { "schema" : { @@ -5249,20 +5362,18 @@ } } }, - "200" : { - "description" : "Returns a distinct filter values for given fieldName.", + "429" : { + "description" : "Too many requests.", "content" : { "application/json" : { "schema" : { - "maxItems" : 2147483647, - "minItems" : 0, - "type" : "array" + "$ref" : "#/components/schemas/ErrorResponse" } } } }, - "404" : { - "description" : "Not found.", + "500" : { + "description" : "Internal server error.", "content" : { "application/json" : { "schema" : { @@ -5281,18 +5392,20 @@ } } }, - "401" : { - "description" : "Authorization failed.", + "200" : { + "description" : "Returns a distinct filter values for given fieldName.", "content" : { "application/json" : { "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" + "maxItems" : 2147483647, + "minItems" : 0, + "type" : "array" } } } }, - "429" : { - "description" : "Too many requests.", + "415" : { + "description" : "Unsupported media type", "content" : { "application/json" : { "schema" : { @@ -5330,8 +5443,8 @@ } } }, - "415" : { - "description" : "Unsupported media type", + "401" : { + "description" : "Authorization failed.", "content" : { "application/json" : { "schema" : { @@ -5340,8 +5453,8 @@ } } }, - "500" : { - "description" : "Internal server error.", + "404" : { + "description" : "Not found.", "content" : { "application/json" : { "schema" : { @@ -5350,20 +5463,18 @@ } } }, - "200" : { - "description" : "Returns the assets found", + "429" : { + "description" : "Too many requests.", "content" : { "application/json" : { "schema" : { - "maxItems" : 2147483647, - "minItems" : 0, - "type" : "array" + "$ref" : "#/components/schemas/ErrorResponse" } } } }, - "404" : { - "description" : "Not found.", + "500" : { + "description" : "Internal server error.", "content" : { "application/json" : { "schema" : { @@ -5372,18 +5483,20 @@ } } }, - "400" : { - "description" : "Bad request.", + "200" : { + "description" : "Returns the assets found", "content" : { "application/json" : { "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" + "maxItems" : 2147483647, + "minItems" : 0, + "type" : "array" } } } }, - "401" : { - "description" : "Authorization failed.", + "400" : { + "description" : "Bad request.", "content" : { "application/json" : { "schema" : { @@ -5392,8 +5505,8 @@ } } }, - "429" : { - "description" : "Too many requests.", + "415" : { + "description" : "Unsupported media type", "content" : { "application/json" : { "schema" : { @@ -5441,26 +5554,6 @@ } } }, - "415" : { - "description" : "Unsupported media type", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "500" : { - "description" : "Internal server error.", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, "200" : { "description" : "Returns the asset by childId", "content" : { @@ -5615,6 +5708,16 @@ } } }, + "401" : { + "description" : "Authorization failed.", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/ErrorResponse" + } + } + } + }, "404" : { "description" : "Not found.", "content" : { @@ -5625,8 +5728,8 @@ } } }, - "400" : { - "description" : "Bad request.", + "429" : { + "description" : "Too many requests.", "content" : { "application/json" : { "schema" : { @@ -5635,8 +5738,8 @@ } } }, - "401" : { - "description" : "Authorization failed.", + "500" : { + "description" : "Internal server error.", "content" : { "application/json" : { "schema" : { @@ -5645,8 +5748,18 @@ } } }, - "429" : { - "description" : "Too many requests.", + "400" : { + "description" : "Bad request.", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/ErrorResponse" + } + } + } + }, + "415" : { + "description" : "Unsupported media type", "content" : { "application/json" : { "schema" : { @@ -5695,18 +5808,8 @@ } } }, - "415" : { - "description" : "Unsupported media type", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" - } - } - } - }, - "500" : { - "description" : "Internal server error.", + "401" : { + "description" : "Authorization failed.", "content" : { "application/json" : { "schema" : { @@ -5740,8 +5843,8 @@ } } }, - "400" : { - "description" : "Bad request.", + "429" : { + "description" : "Too many requests.", "content" : { "application/json" : { "schema" : { @@ -5750,8 +5853,8 @@ } } }, - "401" : { - "description" : "Authorization failed.", + "500" : { + "description" : "Internal server error.", "content" : { "application/json" : { "schema" : { @@ -5760,8 +5863,18 @@ } } }, - "429" : { - "description" : "Too many requests.", + "400" : { + "description" : "Bad request.", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/ErrorResponse" + } + } + } + }, + "415" : { + "description" : "Unsupported media type", "content" : { "application/json" : { "schema" : { @@ -5839,8 +5952,8 @@ } } }, - "415" : { - "description" : "Unsupported media type", + "401" : { + "description" : "Authorization failed.", "content" : { "application/json" : { "schema" : { @@ -5849,8 +5962,8 @@ } } }, - "500" : { - "description" : "Internal server error.", + "404" : { + "description" : "Not found.", "content" : { "application/json" : { "schema" : { @@ -5859,20 +5972,18 @@ } } }, - "200" : { - "description" : "Returns a distinct filter values for given fieldName.", + "429" : { + "description" : "Too many requests.", "content" : { "application/json" : { "schema" : { - "maxItems" : 2147483647, - "minItems" : 0, - "type" : "array" + "$ref" : "#/components/schemas/ErrorResponse" } } } }, - "404" : { - "description" : "Not found.", + "500" : { + "description" : "Internal server error.", "content" : { "application/json" : { "schema" : { @@ -5891,18 +6002,20 @@ } } }, - "401" : { - "description" : "Authorization failed.", + "200" : { + "description" : "Returns a distinct filter values for given fieldName.", "content" : { "application/json" : { "schema" : { - "$ref" : "#/components/schemas/ErrorResponse" + "maxItems" : 2147483647, + "minItems" : 0, + "type" : "array" } } } }, - "429" : { - "description" : "Too many requests.", + "415" : { + "description" : "Unsupported media type", "content" : { "application/json" : { "schema" : { @@ -5940,8 +6053,8 @@ } } }, - "415" : { - "description" : "Unsupported media type", + "401" : { + "description" : "Authorization failed.", "content" : { "application/json" : { "schema" : { @@ -5950,8 +6063,11 @@ } } }, - "500" : { - "description" : "Internal server error.", + "200" : { + "description" : "Ok." + }, + "404" : { + "description" : "Not found.", "content" : { "application/json" : { "schema" : { @@ -5960,11 +6076,8 @@ } } }, - "200" : { - "description" : "Ok." - }, - "404" : { - "description" : "Not found.", + "429" : { + "description" : "Too many requests.", "content" : { "application/json" : { "schema" : { @@ -5973,8 +6086,8 @@ } } }, - "400" : { - "description" : "Bad request.", + "500" : { + "description" : "Internal server error.", "content" : { "application/json" : { "schema" : { @@ -5986,8 +6099,8 @@ "204" : { "description" : "No Content." }, - "401" : { - "description" : "Authorization failed.", + "400" : { + "description" : "Bad request.", "content" : { "application/json" : { "schema" : { @@ -5996,8 +6109,8 @@ } } }, - "429" : { - "description" : "Too many requests.", + "415" : { + "description" : "Unsupported media type", "content" : { "application/json" : { "schema" : { @@ -6045,8 +6158,8 @@ } } }, - "415" : { - "description" : "Unsupported media type", + "401" : { + "description" : "Authorization failed.", "content" : { "application/json" : { "schema" : { @@ -6055,8 +6168,8 @@ } } }, - "500" : { - "description" : "Internal server error.", + "404" : { + "description" : "Not found.", "content" : { "application/json" : { "schema" : { @@ -6065,11 +6178,8 @@ } } }, - "200" : { - "description" : "Okay" - }, - "404" : { - "description" : "Not found.", + "429" : { + "description" : "Too many requests.", "content" : { "application/json" : { "schema" : { @@ -6078,8 +6188,8 @@ } } }, - "400" : { - "description" : "Bad request.", + "500" : { + "description" : "Internal server error.", "content" : { "application/json" : { "schema" : { @@ -6091,8 +6201,11 @@ "204" : { "description" : "Deleted." }, - "401" : { - "description" : "Authorization failed.", + "200" : { + "description" : "Okay" + }, + "400" : { + "description" : "Bad request.", "content" : { "application/json" : { "schema" : { @@ -6101,8 +6214,8 @@ } } }, - "429" : { - "description" : "Too many requests.", + "415" : { + "description" : "Unsupported media type", "content" : { "application/json" : { "schema" : { @@ -6807,6 +6920,76 @@ } } }, + "ImportJobResponse" : { + "type" : "object", + "properties" : { + "importId" : { + "type" : "string", + "example" : "456a952e-05eb-40dc-a6f2-9c2cb9c1387f" + }, + "startedOn" : { + "maxLength" : 50, + "type" : "string", + "example" : "2099-02-21T21:27:10.734950Z" + }, + "completedOn" : { + "maxLength" : 50, + "type" : "string", + "example" : "2099-02-21T21:27:10.734950Z" + }, + "importJobStatusResponse" : { + "type" : "string", + "enum" : [ + "INITIALIZING", + "RUNNING", + "CANCELLED", + "COMPLETED" + ] + } + } + }, + "ImportReportResponse" : { + "type" : "object", + "properties" : { + "importJobResponse" : { + "$ref" : "#/components/schemas/ImportJobResponse" + }, + "importedAssetResponse" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/ImportedAssetResponse" + } + } + } + }, + "ImportedAssetResponse" : { + "type" : "object", + "properties" : { + "catenaxId" : { + "type" : "string", + "example" : "urn:uuid:7eeeac86-7b69-444d-81e6-655d0f1513bd}" + }, + "importStateResponse" : { + "type" : "string", + "enum" : [ + "TRANSIENT", + "PERSISTENT", + "ERROR", + "IN_SYNCHRONIZATION", + "UNSET" + ] + }, + "importedOn" : { + "maxLength" : 50, + "type" : "string", + "example" : "2099-02-21T21:27:10.734950Z" + }, + "importMessage" : { + "type" : "string", + "example" : "Asset created successfully in transient state." + } + } + }, "AlertResponse" : { "type" : "object", "properties" : { @@ -6911,6 +7094,7 @@ "type" : "oauth2", "flows" : { "clientCredentials" : { + "tokenUrl" : "localhost", "scopes" : { "profile email" : "" } diff --git a/tx-backend/pom.xml b/tx-backend/pom.xml index e1f461005a..86672de4f2 100644 --- a/tx-backend/pom.xml +++ b/tx-backend/pom.xml @@ -207,7 +207,7 @@ SPDX-License-Identifier: Apache-2.0 org.apache.tomcat.embed tomcat-embed-websocket - 10.1.16 + ${tomcat-embed-websocket.version} org.springframework.cloud diff --git a/tx-backend/src/main/java/org/eclipse/tractusx/traceability/assets/application/importpoc/ImportService.java b/tx-backend/src/main/java/org/eclipse/tractusx/traceability/assets/application/importpoc/ImportService.java index 08924372c2..519c9ac29f 100644 --- a/tx-backend/src/main/java/org/eclipse/tractusx/traceability/assets/application/importpoc/ImportService.java +++ b/tx-backend/src/main/java/org/eclipse/tractusx/traceability/assets/application/importpoc/ImportService.java @@ -21,11 +21,19 @@ import org.eclipse.tractusx.traceability.assets.domain.base.model.AssetBase; +import org.eclipse.tractusx.traceability.assets.domain.importpoc.model.ImportJob; import org.springframework.web.multipart.MultipartFile; - import java.util.Map; public interface ImportService { - Map importAssets(MultipartFile file); + Map importAssets(MultipartFile file, ImportJob importJob); + + ImportJob createJob(); + + void completeJob(ImportJob importJob); + + void cancelJob(ImportJob importJob); + + ImportJob getImportJob(String importJobId); } diff --git a/tx-backend/src/main/java/org/eclipse/tractusx/traceability/assets/application/importpoc/mapper/ImportJobResponseMapper.java b/tx-backend/src/main/java/org/eclipse/tractusx/traceability/assets/application/importpoc/mapper/ImportJobResponseMapper.java new file mode 100644 index 0000000000..ce5619da6b --- /dev/null +++ b/tx-backend/src/main/java/org/eclipse/tractusx/traceability/assets/application/importpoc/mapper/ImportJobResponseMapper.java @@ -0,0 +1,51 @@ +/******************************************************************************** + * Copyright (c) 2024 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ +package org.eclipse.tractusx.traceability.assets.application.importpoc.mapper; + +import assets.importpoc.ImportJobStatusResponse; +import assets.importpoc.ImportReportResponse; +import assets.response.base.response.ImportStateResponse; +import org.eclipse.tractusx.traceability.assets.domain.importpoc.model.ImportJob; + +import java.util.List; +import java.util.stream.Stream; + +public class ImportJobResponseMapper { + public static ImportReportResponse from(ImportJob importJob) { + + ImportReportResponse.ImportJobResponse importJobResponse = + new ImportReportResponse.ImportJobResponse( + importJob.getId().toString(), + importJob.getStartedOn().toString(), + importJob.getCompletedOn().toString(), + ImportJobStatusResponse.valueOf(importJob.getStatus().toString())); + + List importedAssets = + Stream.concat(importJob.getAssetAsBuilt().stream(), importJob.getAssetAsPlanned().stream()) + .map( + asset -> new ImportReportResponse.ImportedAssetResponse( + asset.getId(), + ImportStateResponse.valueOf(asset.getImportState().toString()), + importJob.getStartedOn().toString(), + asset.getImportNote() + ) + ).toList(); + return new ImportReportResponse(importJobResponse, importedAssets); + } +} diff --git a/tx-backend/src/main/java/org/eclipse/tractusx/traceability/assets/application/importpoc/rest/ImportController.java b/tx-backend/src/main/java/org/eclipse/tractusx/traceability/assets/application/importpoc/rest/ImportController.java index 879449b82b..0a1064cf5e 100644 --- a/tx-backend/src/main/java/org/eclipse/tractusx/traceability/assets/application/importpoc/rest/ImportController.java +++ b/tx-backend/src/main/java/org/eclipse/tractusx/traceability/assets/application/importpoc/rest/ImportController.java @@ -21,6 +21,7 @@ import assets.importpoc.ErrorResponse; +import assets.importpoc.ImportReportResponse; import assets.importpoc.ImportResponse; import assets.importpoc.ImportStateMessage; import assets.importpoc.ValidationResponse; @@ -36,13 +37,17 @@ import lombok.extern.slf4j.Slf4j; import org.eclipse.tractusx.traceability.assets.application.importpoc.ImportService; import org.eclipse.tractusx.traceability.assets.application.importpoc.PublishService; +import org.eclipse.tractusx.traceability.assets.application.importpoc.mapper.ImportJobResponseMapper; import org.eclipse.tractusx.traceability.assets.application.importpoc.validation.JsonFileValidator; import org.eclipse.tractusx.traceability.assets.domain.base.model.AssetBase; import org.eclipse.tractusx.traceability.assets.domain.importpoc.exception.ImportException; +import org.eclipse.tractusx.traceability.assets.domain.importpoc.model.ImportJob; 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.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; @@ -128,27 +133,32 @@ public class ImportController { @PostMapping(value = "/import", consumes = MediaType.MULTIPART_FORM_DATA_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) public ResponseEntity importJson(@RequestPart("file") MultipartFile file) { log.info("Received request to import assets."); + ImportJob importJob = importService.createJob(); + List jsonSchemaErrors = jsonFileValidator.isValid(file); ValidationResponse validationResponse = new ValidationResponse(jsonSchemaErrors); if (!jsonSchemaErrors.isEmpty()) { log.warn("Asset import request cannot be processed. Errors: {}", validationResponse); + importService.cancelJob(importJob); return ResponseEntity .badRequest() - .body(new ImportResponse(validationResponse)); + .body(new ImportResponse(importJob.getId().toString(), validationResponse)); } + Map resultMap = null; try { - resultMap = importService.importAssets(file); + resultMap = importService.importAssets(file, importJob); } catch (ImportException e) { log.info("Could not import data", e); + importService.cancelJob(importJob); List validationErrors = new ArrayList<>(); validationErrors.add(e.getMessage()); ValidationResponse importErrorResponse = new ValidationResponse(validationErrors); return ResponseEntity .badRequest() - .body(new ImportResponse(importErrorResponse)); + .body(new ImportResponse(importJob.getId().toString(), importErrorResponse)); } List importStateMessages = resultMap.entrySet().stream() @@ -158,10 +168,78 @@ public ResponseEntity importJson(@RequestPart("file") MultipartF ).toList(); log.info("Successfully imported {} assets.", importStateMessages.size()); - ImportResponse importResponse = new ImportResponse(importStateMessages); + importService.completeJob(importJob); + ImportResponse importResponse = new ImportResponse(importJob.getId().toString(), importStateMessages); return ResponseEntity.ok(importResponse); } + + @Operation(operationId = "importReport", + summary = "report of the imported assets", + tags = {"ImportReport"}, + description = "This endpoint returns information about the imported assets to Trace-X.", + security = @SecurityRequirement(name = "oAuth2", scopes = "profile email")) + @ApiResponses(value = { + @ApiResponse( + responseCode = "200", + description = "OK.", + content = @Content( + mediaType = "application/json", + schema = @Schema(implementation = ImportReportResponse.class))), + @ApiResponse( + responseCode = "204", + description = "No Content.", + content = @Content()), + @ApiResponse( + responseCode = "400", + description = "Bad request.", + content = @Content( + mediaType = "application/json", + schema = @Schema(implementation = ErrorResponse.class))), + @ApiResponse( + responseCode = "401", + description = "Authorization failed.", + content = @Content( + mediaType = "application/json", + schema = @Schema(implementation = ErrorResponse.class))), + @ApiResponse( + responseCode = "403", + description = "Forbidden.", + content = @Content( + mediaType = "application/json", + schema = @Schema(implementation = ErrorResponse.class))), + @ApiResponse( + responseCode = "404", + description = "Not found.", + content = @Content( + mediaType = "application/json", + schema = @Schema(implementation = ErrorResponse.class))), + @ApiResponse( + responseCode = "415", + description = "Unsupported media type", + content = @Content( + mediaType = "application/json", + schema = @Schema(implementation = ErrorResponse.class))), + @ApiResponse( + responseCode = "429", + description = "Too many requests.", + content = @Content( + mediaType = "application/json", + schema = @Schema(implementation = ErrorResponse.class))), + @ApiResponse( + responseCode = "500", + description = "Internal server error.", + content = @Content( + mediaType = "application/json", + schema = @Schema(implementation = ErrorResponse.class)))}) + + @GetMapping(value = "/import/report/{importJobId}", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity getImportReport(@PathVariable("importJobId") String importJobId) { + ImportJob importJob = importService.getImportJob(importJobId); + ImportReportResponse importReportResponse = ImportJobResponseMapper.from(importJob); + return ResponseEntity.status(HttpStatus.OK).body(importReportResponse); + } + @Operation(operationId = "publishAssets", summary = "asset publish", tags = {"AssetsPublish"}, diff --git a/tx-backend/src/main/java/org/eclipse/tractusx/traceability/assets/domain/base/model/AssetBase.java b/tx-backend/src/main/java/org/eclipse/tractusx/traceability/assets/domain/base/model/AssetBase.java index 5f35621a34..a1a45c813d 100644 --- a/tx-backend/src/main/java/org/eclipse/tractusx/traceability/assets/domain/base/model/AssetBase.java +++ b/tx-backend/src/main/java/org/eclipse/tractusx/traceability/assets/domain/base/model/AssetBase.java @@ -67,13 +67,15 @@ public class AssetBase { private String policyId; public BomLifecycle getBomLifecycle() { - if(semanticDataModel.equals(SERIALPART) || semanticDataModel.equals(BATCH) || semanticDataModel.equals(JUSTINSEQUENCE)){ + if (semanticDataModel.equals(SERIALPART) || semanticDataModel.equals(BATCH) || semanticDataModel.equals(JUSTINSEQUENCE)) { return BomLifecycle.AS_BUILT; } else { return BomLifecycle.AS_PLANNED; } } - public boolean isOwnAsset(final String bpn){ + + public boolean isOwnAsset(final String bpn) { return bpn.equals(manufacturerId); } + } diff --git a/tx-backend/src/main/java/org/eclipse/tractusx/traceability/assets/domain/base/model/ImportNote.java b/tx-backend/src/main/java/org/eclipse/tractusx/traceability/assets/domain/base/model/ImportNote.java index b2a0dc5597..969e71ab18 100644 --- a/tx-backend/src/main/java/org/eclipse/tractusx/traceability/assets/domain/base/model/ImportNote.java +++ b/tx-backend/src/main/java/org/eclipse/tractusx/traceability/assets/domain/base/model/ImportNote.java @@ -23,5 +23,6 @@ public class ImportNote { public static final String TRANSIENT_UPDATED = "Asset updated successfully in transient state."; public static final String PERSISTENT_NO_UPDATE = "Asset in sync with digital twin registry. Twin will not be updated."; public static final String PERSISTED = "Asset created/updated successfully in persistant state."; + public static final String IN_SYNCHRONIZATION = "Twin in sync with digital twin registry. Twin will not be updated."; } diff --git a/tx-backend/src/main/java/org/eclipse/tractusx/traceability/assets/domain/base/model/ImportState.java b/tx-backend/src/main/java/org/eclipse/tractusx/traceability/assets/domain/base/model/ImportState.java index fb0e1b9e6d..82e83a9fd7 100644 --- a/tx-backend/src/main/java/org/eclipse/tractusx/traceability/assets/domain/base/model/ImportState.java +++ b/tx-backend/src/main/java/org/eclipse/tractusx/traceability/assets/domain/base/model/ImportState.java @@ -20,5 +20,5 @@ public enum ImportState { - TRANSIENT, PERSISTENT, ERROR, IN_SYNCHRONIZATION, UNSET; + TRANSIENT, PERSISTENT, ERROR, IN_SYNCHRONIZATION, UNSET } diff --git a/tx-backend/src/main/java/org/eclipse/tractusx/traceability/assets/domain/importpoc/exception/ImportException.java b/tx-backend/src/main/java/org/eclipse/tractusx/traceability/assets/domain/importpoc/exception/ImportException.java index 74914b972e..9f043dabfe 100644 --- a/tx-backend/src/main/java/org/eclipse/tractusx/traceability/assets/domain/importpoc/exception/ImportException.java +++ b/tx-backend/src/main/java/org/eclipse/tractusx/traceability/assets/domain/importpoc/exception/ImportException.java @@ -22,4 +22,8 @@ public class ImportException extends RuntimeException{ public ImportException(String message) { super(message); } + + public ImportException(String message, Exception e) { + super(message, e); + } } diff --git a/tx-backend/src/main/java/org/eclipse/tractusx/traceability/assets/domain/importpoc/exception/ImportJobNotFoundException.java b/tx-backend/src/main/java/org/eclipse/tractusx/traceability/assets/domain/importpoc/exception/ImportJobNotFoundException.java new file mode 100644 index 0000000000..0544bbd0d8 --- /dev/null +++ b/tx-backend/src/main/java/org/eclipse/tractusx/traceability/assets/domain/importpoc/exception/ImportJobNotFoundException.java @@ -0,0 +1,26 @@ +/******************************************************************************** + * Copyright (c) 2024 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ +package org.eclipse.tractusx.traceability.assets.domain.importpoc.exception; + +public class ImportJobNotFoundException extends RuntimeException { + + public ImportJobNotFoundException(String message, Exception e) { + super(message, e); + } +} diff --git a/tx-backend/src/main/java/org/eclipse/tractusx/traceability/assets/domain/importpoc/model/ImportJob.java b/tx-backend/src/main/java/org/eclipse/tractusx/traceability/assets/domain/importpoc/model/ImportJob.java new file mode 100644 index 0000000000..cdf9af14fc --- /dev/null +++ b/tx-backend/src/main/java/org/eclipse/tractusx/traceability/assets/domain/importpoc/model/ImportJob.java @@ -0,0 +1,52 @@ +/******************************************************************************** + * Copyright (c) 2024 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ +package org.eclipse.tractusx.traceability.assets.domain.importpoc.model; + + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.extern.slf4j.Slf4j; +import org.eclipse.tractusx.traceability.assets.domain.base.model.AssetBase; + +import java.time.Instant; +import java.util.List; +import java.util.UUID; + +@Slf4j +@AllArgsConstructor +@Data +@Builder +public class ImportJob { + + private UUID id; + private Instant startedOn; + private Instant completedOn; + private ImportJobStatus status; + private List assetAsBuilt; + private List assetAsPlanned; + + public List getAssetAsBuilt() { + return assetAsBuilt == null ? List.of() : assetAsBuilt; + } + + public List getAssetAsPlanned() { + return assetAsPlanned == null ? List.of() : assetAsPlanned; + } +} diff --git a/tx-backend/src/main/java/org/eclipse/tractusx/traceability/assets/domain/importpoc/model/ImportJobStatus.java b/tx-backend/src/main/java/org/eclipse/tractusx/traceability/assets/domain/importpoc/model/ImportJobStatus.java new file mode 100644 index 0000000000..b72523d1e1 --- /dev/null +++ b/tx-backend/src/main/java/org/eclipse/tractusx/traceability/assets/domain/importpoc/model/ImportJobStatus.java @@ -0,0 +1,25 @@ +/******************************************************************************** + * Copyright (c) 2024 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ +package org.eclipse.tractusx.traceability.assets.domain.importpoc.model; + +public enum ImportJobStatus { + + INITIALIZING, RUNNING, CANCELLED, COMPLETED + +} diff --git a/tx-backend/src/main/java/org/eclipse/tractusx/traceability/assets/domain/importpoc/repository/ImportJobRepository.java b/tx-backend/src/main/java/org/eclipse/tractusx/traceability/assets/domain/importpoc/repository/ImportJobRepository.java new file mode 100644 index 0000000000..7450e1125a --- /dev/null +++ b/tx-backend/src/main/java/org/eclipse/tractusx/traceability/assets/domain/importpoc/repository/ImportJobRepository.java @@ -0,0 +1,31 @@ +/******************************************************************************** + * Copyright (c) 2024 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ +package org.eclipse.tractusx.traceability.assets.domain.importpoc.repository; + +import org.eclipse.tractusx.traceability.assets.domain.importpoc.model.ImportJob; +import org.eclipse.tractusx.traceability.assets.infrastructure.importJob.model.ImportJobEntity; + +public interface ImportJobRepository { + + ImportJob createJob(); + + void save(ImportJobEntity importJobEntity); + + ImportJob getImportJob(String importJobId); +} diff --git a/tx-backend/src/main/java/org/eclipse/tractusx/traceability/assets/domain/importpoc/service/ImportServiceImpl.java b/tx-backend/src/main/java/org/eclipse/tractusx/traceability/assets/domain/importpoc/service/ImportServiceImpl.java index 137b66baed..fa17b553c2 100644 --- a/tx-backend/src/main/java/org/eclipse/tractusx/traceability/assets/domain/importpoc/service/ImportServiceImpl.java +++ b/tx-backend/src/main/java/org/eclipse/tractusx/traceability/assets/domain/importpoc/service/ImportServiceImpl.java @@ -27,11 +27,17 @@ import org.eclipse.tractusx.traceability.assets.domain.asplanned.repository.AssetAsPlannedRepository; import org.eclipse.tractusx.traceability.assets.domain.base.model.AssetBase; import org.eclipse.tractusx.traceability.assets.domain.importpoc.exception.ImportException; +import org.eclipse.tractusx.traceability.assets.domain.importpoc.model.ImportJob; +import org.eclipse.tractusx.traceability.assets.domain.importpoc.model.ImportJobStatus; import org.eclipse.tractusx.traceability.assets.domain.importpoc.model.ImportRequest; +import org.eclipse.tractusx.traceability.assets.domain.importpoc.repository.ImportJobRepository; import org.eclipse.tractusx.traceability.assets.domain.importpoc.repository.SubmodelPayloadRepository; +import org.eclipse.tractusx.traceability.assets.infrastructure.importJob.model.ImportJobEntity; import org.eclipse.tractusx.traceability.common.properties.TraceabilityProperties; import org.springframework.stereotype.Service; import org.springframework.web.multipart.MultipartFile; + +import java.time.Instant; import java.util.Collection; import java.util.LinkedHashMap; import java.util.List; @@ -50,14 +56,14 @@ public class ImportServiceImpl implements ImportService { private final TraceabilityProperties traceabilityProperties; private final MappingStrategyFactory strategyFactory; private final SubmodelPayloadRepository submodelPayloadRepository; + private final ImportJobRepository importJobRepository; @Override - public Map importAssets(MultipartFile file) { + public Map importAssets(MultipartFile file, ImportJob importJob) { try { ImportRequest importRequest = objectMapper.readValue(file.getBytes(), ImportRequest.class); - Map> assetToUploadByBomLifecycle = importRequest.assets() .stream() @@ -77,6 +83,10 @@ public Map importAssets(MultipartFile file) { List persistedAsBuilt = assetAsBuiltRepository.saveAllIfNotInIRSSyncAndUpdateImportStateAndNote(assetToUploadByBomLifecycle.get(BomLifecycle.AS_BUILT)); List persistedAsPlanned = assetAsPlannedRepository.saveAllIfNotInIRSSyncAndUpdateImportStateAndNote(assetToUploadByBomLifecycle.get(BomLifecycle.AS_PLANNED)); + importJob.setAssetAsBuilt(persistedAsBuilt); + importJob.setAssetAsPlanned(persistedAsPlanned); + importJobRepository.save(ImportJobEntity.from(importJob)); + List expectedAssetsToBePersisted = assetToUploadByBomLifecycle.values().stream().flatMap(Collection::stream).toList(); List persistedAssets = Stream.concat(persistedAsBuilt.stream(), persistedAsPlanned.stream()).toList(); @@ -84,11 +94,37 @@ public Map importAssets(MultipartFile file) { return compareForUploadResult(expectedAssetsToBePersisted, persistedAssets); } catch (Exception e) { - throw new ImportException(e.getMessage()); + throw new ImportException(e.getMessage(), e); } } + @Override + public ImportJob createJob() { + return importJobRepository.createJob(); + } + @Override + public void completeJob(ImportJob importJob) { + ImportJobEntity importJobEntity = ImportJobEntity.from(importJob); + importJobEntity.setCompletedOn(Instant.now()); + importJobEntity.setImportJobStatus(ImportJobStatus.COMPLETED); + importJobRepository.save(importJobEntity); + log.info("Successfully completed import job {}", importJob.getId()); + } + + @Override + public void cancelJob(ImportJob importJob) { + ImportJobEntity importJobEntity = ImportJobEntity.from(importJob); + importJobEntity.setCompletedOn(Instant.now()); + importJobEntity.setImportJobStatus(ImportJobStatus.CANCELLED); + importJobRepository.save(importJobEntity); + log.info("Cancelling import job {}", importJob.getId()); + } + + @Override + public ImportJob getImportJob(String importJobId) { + return importJobRepository.getImportJob(importJobId); + } private void saveRawDataForPersistedAssets(List persistedAssets, ImportRequest importRequest) { diff --git a/tx-backend/src/main/java/org/eclipse/tractusx/traceability/assets/domain/importpoc/service/PublishServiceImpl.java b/tx-backend/src/main/java/org/eclipse/tractusx/traceability/assets/domain/importpoc/service/PublishServiceImpl.java index ceb5fa55b1..e9e02f1405 100644 --- a/tx-backend/src/main/java/org/eclipse/tractusx/traceability/assets/domain/importpoc/service/PublishServiceImpl.java +++ b/tx-backend/src/main/java/org/eclipse/tractusx/traceability/assets/domain/importpoc/service/PublishServiceImpl.java @@ -25,6 +25,7 @@ import org.eclipse.tractusx.traceability.assets.domain.asplanned.repository.AssetAsPlannedRepository; import org.eclipse.tractusx.traceability.assets.domain.base.AssetRepository; import org.eclipse.tractusx.traceability.assets.domain.base.model.AssetBase; +import org.eclipse.tractusx.traceability.assets.domain.base.model.ImportNote; import org.eclipse.tractusx.traceability.assets.domain.base.model.ImportState; import org.eclipse.tractusx.traceability.assets.domain.importpoc.exception.PublishAssetException; import org.springframework.stereotype.Service; @@ -64,6 +65,7 @@ private void updateAssetWithStatusAndPolicy(String policyId, List assetI .filter(this::validTransientState) .map(asset -> { asset.setImportState(ImportState.IN_SYNCHRONIZATION); + asset.setImportNote(ImportNote.IN_SYNCHRONIZATION); asset.setPolicyId(policyId); return asset; }).toList(); diff --git a/tx-backend/src/main/java/org/eclipse/tractusx/traceability/assets/infrastructure/asbuilt/model/AssetAsBuiltEntity.java b/tx-backend/src/main/java/org/eclipse/tractusx/traceability/assets/infrastructure/asbuilt/model/AssetAsBuiltEntity.java index f17e068ba9..e90b5a03b0 100644 --- a/tx-backend/src/main/java/org/eclipse/tractusx/traceability/assets/infrastructure/asbuilt/model/AssetAsBuiltEntity.java +++ b/tx-backend/src/main/java/org/eclipse/tractusx/traceability/assets/infrastructure/asbuilt/model/AssetAsBuiltEntity.java @@ -91,6 +91,7 @@ public class AssetAsBuiltEntity extends AssetBaseEntity { @OneToMany(mappedBy = "assetAsBuilt", fetch = FetchType.EAGER) private List submodels; + public static AssetAsBuiltEntity from(AssetBase asset) { ManufacturingInfo manufacturingInfo = ManufacturingInfo.from(asset.getDetailAspectModels()); TractionBatteryCode tractionBatteryCodeObj = TractionBatteryCode.from(asset.getDetailAspectModels()); diff --git a/tx-backend/src/main/java/org/eclipse/tractusx/traceability/assets/infrastructure/asplanned/model/AssetAsPlannedEntity.java b/tx-backend/src/main/java/org/eclipse/tractusx/traceability/assets/infrastructure/asplanned/model/AssetAsPlannedEntity.java index 22680babee..2cc33fdd01 100644 --- a/tx-backend/src/main/java/org/eclipse/tractusx/traceability/assets/infrastructure/asplanned/model/AssetAsPlannedEntity.java +++ b/tx-backend/src/main/java/org/eclipse/tractusx/traceability/assets/infrastructure/asplanned/model/AssetAsPlannedEntity.java @@ -69,15 +69,6 @@ public class AssetAsPlannedEntity extends AssetBaseEntity { @CollectionTable(name = "assets_as_planned_childs", joinColumns = {@JoinColumn(name = "asset_as_planned_id")}) private List childDescriptors; - @ManyToMany(mappedBy = "assetsAsPlanned") - private List investigations = new ArrayList<>(); - - @ManyToMany(mappedBy = "assetsAsPlanned") - private List alerts = new ArrayList<>(); - - @OneToMany(mappedBy = "assetAsPlanned", fetch = FetchType.EAGER) - private List submodels; - @Builder @NoArgsConstructor @AllArgsConstructor @@ -88,6 +79,11 @@ public static class ChildDescription { private String idShort; } + @OneToMany(mappedBy = "assetAsPlanned", fetch = FetchType.EAGER) + private List submodels; + + + public static AssetAsPlannedEntity from(AssetBase asset) { List detailAspectModels = asset.getDetailAspectModels(); AsPlannedInfo asPlannedInfo = AsPlannedInfo.from(detailAspectModels); @@ -138,10 +134,6 @@ public static AssetBase toDomain(AssetAsPlannedEntity entity) { .toList()) .qualityType(entity.getQualityType()) .detailAspectModels(DetailAspectModel.from(entity)) - .sentQualityAlerts(emptyIfNull(entity.alerts).stream().filter(alert -> NotificationSideBaseEntity.SENDER.equals(alert.getSide())).map(AlertEntity::toDomain).toList()) - .receivedQualityAlerts(emptyIfNull(entity.alerts).stream().filter(alert -> NotificationSideBaseEntity.RECEIVER.equals(alert.getSide())).map(AlertEntity::toDomain).toList()) - .sentQualityInvestigations(emptyIfNull(entity.investigations).stream().filter(alert -> NotificationSideBaseEntity.SENDER.equals(alert.getSide())).map(InvestigationEntity::toDomain).toList()) - .receivedQualityInvestigations(emptyIfNull(entity.investigations).stream().filter(alert -> NotificationSideBaseEntity.RECEIVER.equals(alert.getSide())).map(InvestigationEntity::toDomain).toList()) .importState(entity.getImportState()) .importNote(entity.getImportNote()) .policyId(entity.getPolicyId()) diff --git a/tx-backend/src/main/java/org/eclipse/tractusx/traceability/assets/infrastructure/base/irs/IrsCallbackController.java b/tx-backend/src/main/java/org/eclipse/tractusx/traceability/assets/infrastructure/base/irs/IrsCallbackController.java index 328abe5f70..3bd3ec8e28 100644 --- a/tx-backend/src/main/java/org/eclipse/tractusx/traceability/assets/infrastructure/base/irs/IrsCallbackController.java +++ b/tx-backend/src/main/java/org/eclipse/tractusx/traceability/assets/infrastructure/base/irs/IrsCallbackController.java @@ -20,10 +20,8 @@ package org.eclipse.tractusx.traceability.assets.infrastructure.base.irs; import assets.importpoc.ErrorResponse; -import assets.response.asbuilt.AssetAsBuiltResponse; import io.swagger.v3.oas.annotations.Hidden; import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.media.ArraySchema; import io.swagger.v3.oas.annotations.media.Content; import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.responses.ApiResponse; @@ -50,51 +48,54 @@ public class IrsCallbackController { description = "The endpoint retrieves the information about a job which has been completed recently.", security = @SecurityRequirement(name = "oAuth2", scopes = "profile email")) @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "Retrieves job id in completed state."), - @ApiResponse( - responseCode = "400", - description = "Bad request.", - content = @Content( - mediaType = "application/json", - schema = @Schema(implementation = ErrorResponse.class))), - @ApiResponse( - responseCode = "401", - description = "Authorization failed.", - content = @Content( - mediaType = "application/json", - schema = @Schema(implementation = ErrorResponse.class))), + @ApiResponse( + responseCode = "400", + description = "Bad request.", + content = @Content( + mediaType = "application/json", + schema = @Schema(implementation = ErrorResponse.class))), + @ApiResponse( + responseCode = "401", + description = "Authorization failed.", + content = @Content( + mediaType = "application/json", + schema = @Schema(implementation = ErrorResponse.class))), - @ApiResponse( - responseCode = "403", - description = "Forbidden.", - content = @Content( - mediaType = "application/json", - schema = @Schema(implementation = ErrorResponse.class))), - @ApiResponse( - responseCode = "404", - description = "Not found.", - content = @Content( - mediaType = "application/json", - schema = @Schema(implementation = ErrorResponse.class))), - @ApiResponse( - responseCode = "415", - description = "Unsupported media type", - content = @Content( - mediaType = "application/json", - schema = @Schema(implementation = ErrorResponse.class))), - @ApiResponse( - responseCode = "429", - description = "Too many requests.", - content = @Content( - mediaType = "application/json", - schema = @Schema(implementation = ErrorResponse.class))), - @ApiResponse( - responseCode = "500", - description = "Internal server error.", - content = @Content( - mediaType = "application/json", - schema = @Schema(implementation = ErrorResponse.class)))}) + @ApiResponse( + responseCode = "403", + description = "Forbidden.", + content = @Content( + mediaType = "application/json", + schema = @Schema(implementation = ErrorResponse.class))), + @ApiResponse( + responseCode = "404", + description = "Not found.", + content = @Content( + mediaType = "application/json", + schema = @Schema(implementation = ErrorResponse.class))), + @ApiResponse( + responseCode = "415", + description = "Unsupported media type", + content = @Content( + mediaType = "application/json", + schema = @Schema(implementation = ErrorResponse.class))), + @ApiResponse( + responseCode = "429", + description = "Too many requests.", + content = @Content( + mediaType = "application/json", + schema = @Schema(implementation = ErrorResponse.class))), + @ApiResponse( + responseCode = "500", + description = "Internal server error.", + content = @Content( + mediaType = "application/json", + schema = @Schema(implementation = ErrorResponse.class)))}) @GetMapping("/irs/job/callback") void handleIrsJobCallback(@RequestParam("id") String jobId, @RequestParam("state") String jobState) { - irsRepository.handleJobFinishedCallback(jobId, jobState); + // Security measurment for injection + if (jobId.matches("^[a-zA-Z0-9_-]*$")) { + irsRepository.handleJobFinishedCallback(jobId, jobState); + } } } diff --git a/tx-backend/src/main/java/org/eclipse/tractusx/traceability/assets/infrastructure/base/irs/IrsClient.java b/tx-backend/src/main/java/org/eclipse/tractusx/traceability/assets/infrastructure/base/irs/IrsClient.java index 14b1f17476..ad5cf0d1f2 100644 --- a/tx-backend/src/main/java/org/eclipse/tractusx/traceability/assets/infrastructure/base/irs/IrsClient.java +++ b/tx-backend/src/main/java/org/eclipse/tractusx/traceability/assets/infrastructure/base/irs/IrsClient.java @@ -18,7 +18,6 @@ ********************************************************************************/ package org.eclipse.tractusx.traceability.assets.infrastructure.base.irs; -import com.fasterxml.jackson.databind.ObjectMapper; import lombok.extern.slf4j.Slf4j; import org.eclipse.tractusx.irs.edc.client.policy.OperatorType; import org.eclipse.tractusx.traceability.assets.infrastructure.base.irs.model.request.RegisterJobRequest; @@ -39,10 +38,8 @@ @Component public class IrsClient { - private final RestTemplate irsAdminTemplate; - private final ObjectMapper objectMapper; private final RestTemplate irsRegularTemplate; private final TraceabilityProperties traceabilityProperties; @@ -51,11 +48,10 @@ public class IrsClient { public IrsClient(RestTemplate irsAdminTemplate, RestTemplate irsRegularTemplate, - TraceabilityProperties traceabilityProperties, ObjectMapper objectMapper) { + TraceabilityProperties traceabilityProperties) { this.irsAdminTemplate = irsAdminTemplate; this.irsRegularTemplate = irsRegularTemplate; this.traceabilityProperties = traceabilityProperties; - this.objectMapper = objectMapper; } public List getPolicies() { @@ -83,4 +79,5 @@ public JobDetailResponse getJobDetailResponse(String jobId) { return irsRegularTemplate.exchange("/irs/jobs/" + jobId, HttpMethod.GET, null, new ParameterizedTypeReference() { }).getBody(); } + } diff --git a/tx-backend/src/main/java/org/eclipse/tractusx/traceability/assets/infrastructure/base/irs/IrsService.java b/tx-backend/src/main/java/org/eclipse/tractusx/traceability/assets/infrastructure/base/irs/IrsService.java index ed0d0f381a..9142a17690 100644 --- a/tx-backend/src/main/java/org/eclipse/tractusx/traceability/assets/infrastructure/base/irs/IrsService.java +++ b/tx-backend/src/main/java/org/eclipse/tractusx/traceability/assets/infrastructure/base/irs/IrsService.java @@ -88,15 +88,12 @@ public void handleJobFinishedCallback(String jobId, String state) { if (!Objects.equals(state, JobDetailResponse.JOB_STATUS_COMPLETED)) { return; } - JobDetailResponse jobResponse = this.irsClient.getJobDetailResponse(jobId); + final JobDetailResponse jobResponse = this.irsClient.getJobDetailResponse(jobId); + long runtime = (jobResponse.jobStatus().lastModifiedOn().getTime() - jobResponse.jobStatus().startedOn().getTime()) / 1000; log.info("IRS call for globalAssetId: {} finished with status: {}, runtime {} s.", jobResponse.jobStatus().globalAssetId(), jobResponse.jobStatus().state(), runtime); - try { - log.info("Received HTTP Response: {}", objectMapper.writeValueAsString(jobResponse)); - } catch (Exception e) { - log.warn("Unable to log IRS Response", e); - } + if (jobResponse.isCompleted()) { try { // TODO exception will be often thrown probably because two transactions try to commit same primary key - check if we need to update it here @@ -135,8 +132,9 @@ void saveOrUpdateAssets(AssetCallbackRepository repository, AssetBase asset) { @Override public void createIrsPolicyIfMissing() { log.info("Check if irs policy exists"); - List irsPolicies = this.irsClient.getPolicies(); - log.info("Irs has following policies: {}", irsPolicies); + final List irsPolicies = this.irsClient.getPolicies(); + final List irsPoliciesIds = irsPolicies.stream().map(PolicyResponse::policyId).toList(); + log.info("Irs has following policies: {}", irsPoliciesIds); log.info("Required constraints from application yaml are : {}", traceabilityProperties.getRightOperand()); @@ -170,7 +168,7 @@ private void createMissingPolicies() { private void checkAndUpdatePolicy(PolicyResponse requiredPolicy) { if (isPolicyExpired(requiredPolicy)) { - log.info("IRS Policy {} has outdated validity updating new ttl {}", traceabilityProperties.getRightOperand(), requiredPolicy); + log.info("IRS Policy {} has outdated validity updating new ttl", traceabilityProperties.getRightOperand()); this.irsClient.deletePolicy(); this.irsClient.registerPolicy(); } diff --git a/tx-backend/src/main/java/org/eclipse/tractusx/traceability/assets/infrastructure/importJob/model/ImportJobEntity.java b/tx-backend/src/main/java/org/eclipse/tractusx/traceability/assets/infrastructure/importJob/model/ImportJobEntity.java new file mode 100644 index 0000000000..219bc8b98d --- /dev/null +++ b/tx-backend/src/main/java/org/eclipse/tractusx/traceability/assets/infrastructure/importJob/model/ImportJobEntity.java @@ -0,0 +1,92 @@ +/******************************************************************************** + * Copyright (c) 2024 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ +package org.eclipse.tractusx.traceability.assets.infrastructure.importJob.model; + +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.JoinTable; +import jakarta.persistence.OneToMany; +import jakarta.persistence.Table; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.experimental.SuperBuilder; +import org.eclipse.tractusx.traceability.assets.domain.importpoc.model.ImportJob; +import org.eclipse.tractusx.traceability.assets.domain.importpoc.model.ImportJobStatus; +import org.eclipse.tractusx.traceability.assets.infrastructure.asbuilt.model.AssetAsBuiltEntity; +import org.eclipse.tractusx.traceability.assets.infrastructure.asplanned.model.AssetAsPlannedEntity; + +import java.time.Instant; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import java.util.stream.Collectors; + +@Getter +@Setter +@NoArgsConstructor +@Entity +@SuperBuilder +@Table(name = "import_job", schema = "public") +public class ImportJobEntity { + @Id + @GeneratedValue(strategy = GenerationType.UUID) + private String id; + private Instant startedOn; + private Instant completedOn; + @Enumerated(EnumType.STRING) + private ImportJobStatus importJobStatus; + + @OneToMany(fetch = FetchType.LAZY) + @JoinTable(name = "import_job_assets_as_built", joinColumns = @JoinColumn(name = "import_job_id"), inverseJoinColumns = @JoinColumn(name = "asset_as_built_id")) + private List assetsAsBuilt; + + @OneToMany(fetch = FetchType.LAZY) + @JoinTable(name = "import_job_assets_as_planned", joinColumns = @JoinColumn(name = "import_job_id"), inverseJoinColumns = @JoinColumn(name = "asset_as_planned_id")) + private List assetsAsPlanned; + + public static ImportJobEntity from(ImportJob importJob) { + return ImportJobEntity.builder() + .id(importJob.getId().toString()) + .startedOn(importJob.getStartedOn()) + .completedOn(importJob.getCompletedOn()) + .importJobStatus(importJob.getStatus()) + .assetsAsBuilt(importJob.getAssetAsBuilt().stream().map(AssetAsBuiltEntity::from).collect(Collectors.toCollection(ArrayList::new))) + .assetsAsPlanned(importJob.getAssetAsPlanned().stream().map(AssetAsPlannedEntity::from).collect(Collectors.toCollection(ArrayList::new))) + .build(); + + } + + public ImportJob toDomain() { + return ImportJob.builder() + .id(UUID.fromString(id)) + .startedOn(startedOn) + .completedOn(completedOn) + .status(importJobStatus) + .assetAsBuilt(assetsAsBuilt.stream().map(AssetAsBuiltEntity::toDomain).toList()) + .assetAsPlanned(assetsAsPlanned.stream().map(AssetAsPlannedEntity::toDomain).toList()) + .build(); + } +} diff --git a/tx-backend/src/main/java/org/eclipse/tractusx/traceability/assets/infrastructure/importJob/repository/ImportJobRepositoryImpl.java b/tx-backend/src/main/java/org/eclipse/tractusx/traceability/assets/infrastructure/importJob/repository/ImportJobRepositoryImpl.java new file mode 100644 index 0000000000..dbac85ae58 --- /dev/null +++ b/tx-backend/src/main/java/org/eclipse/tractusx/traceability/assets/infrastructure/importJob/repository/ImportJobRepositoryImpl.java @@ -0,0 +1,70 @@ +/******************************************************************************** + * Copyright (c) 2024 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ +package org.eclipse.tractusx.traceability.assets.infrastructure.importJob.repository; + +import jakarta.persistence.EntityNotFoundException; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.eclipse.tractusx.traceability.assets.domain.importpoc.exception.ImportJobNotFoundException; +import org.eclipse.tractusx.traceability.assets.domain.importpoc.model.ImportJob; +import org.eclipse.tractusx.traceability.assets.domain.importpoc.model.ImportJobStatus; +import org.eclipse.tractusx.traceability.assets.domain.importpoc.repository.ImportJobRepository; +import org.eclipse.tractusx.traceability.assets.infrastructure.importJob.model.ImportJobEntity; +import org.springframework.stereotype.Component; + +import java.time.Instant; +import java.util.ArrayList; + +@RequiredArgsConstructor +@Component +@Slf4j +public class ImportJobRepositoryImpl implements ImportJobRepository { + + private final JpaImportJobRepository importJobRepository; + + @Override + public ImportJob createJob() { + log.info("Creating importJob..."); + ImportJobEntity importJob = ImportJobEntity + .builder() + .startedOn(Instant.now()) + .importJobStatus(ImportJobStatus.RUNNING) + .assetsAsBuilt(new ArrayList<>()) + .assetsAsPlanned(new ArrayList<>()) + .build(); + importJobRepository.save(importJob); + log.info("Successfully created importJob {}", importJob.getId()); + return importJob.toDomain(); + } + + @Override + public void save(ImportJobEntity importJobEntity) { + importJobRepository.save(importJobEntity); + } + + @Override + public ImportJob getImportJob(String importJobId) { + try { + ImportJobEntity importJobEntity = importJobRepository.getReferenceById(importJobId); + return importJobEntity.toDomain(); + } catch (EntityNotFoundException entityNotFoundException) { + throw new ImportJobNotFoundException("Could not find import job with id " + importJobId, entityNotFoundException); + } + } +} diff --git a/tx-backend/src/main/java/org/eclipse/tractusx/traceability/assets/infrastructure/importJob/repository/JpaImportJobRepository.java b/tx-backend/src/main/java/org/eclipse/tractusx/traceability/assets/infrastructure/importJob/repository/JpaImportJobRepository.java new file mode 100644 index 0000000000..d542883d53 --- /dev/null +++ b/tx-backend/src/main/java/org/eclipse/tractusx/traceability/assets/infrastructure/importJob/repository/JpaImportJobRepository.java @@ -0,0 +1,29 @@ +/******************************************************************************** + * Copyright (c) 2024 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ +package org.eclipse.tractusx.traceability.assets.infrastructure.importJob.repository; + +import org.eclipse.tractusx.traceability.assets.infrastructure.importJob.model.ImportJobEntity; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; +import org.springframework.stereotype.Repository; + +@Repository +public interface JpaImportJobRepository extends JpaRepository, JpaSpecificationExecutor { + +} diff --git a/tx-backend/src/main/java/org/eclipse/tractusx/traceability/common/config/ErrorHandlingConfig.java b/tx-backend/src/main/java/org/eclipse/tractusx/traceability/common/config/ErrorHandlingConfig.java index 6bdb4c1350..eea36aff70 100644 --- a/tx-backend/src/main/java/org/eclipse/tractusx/traceability/common/config/ErrorHandlingConfig.java +++ b/tx-backend/src/main/java/org/eclipse/tractusx/traceability/common/config/ErrorHandlingConfig.java @@ -32,6 +32,7 @@ import org.eclipse.tractusx.traceability.assets.application.importpoc.validation.exception.JsonFileProcessingException; import org.eclipse.tractusx.traceability.assets.domain.asbuilt.exception.AssetNotFoundException; import org.eclipse.tractusx.traceability.assets.domain.importpoc.exception.ImportException; +import org.eclipse.tractusx.traceability.assets.domain.importpoc.exception.ImportJobNotFoundException; import org.eclipse.tractusx.traceability.assets.domain.importpoc.exception.PublishAssetException; import org.eclipse.tractusx.traceability.bpn.domain.model.BpnNotFoundException; import org.eclipse.tractusx.traceability.common.domain.ParseLocalDateException; @@ -44,6 +45,7 @@ import org.eclipse.tractusx.traceability.qualitynotification.domain.alert.model.exception.AlertNotFoundException; import org.eclipse.tractusx.traceability.qualitynotification.domain.investigation.model.exception.InvestigationIllegalUpdate; import org.eclipse.tractusx.traceability.qualitynotification.domain.investigation.model.exception.InvestigationNotFoundException; +import org.eclipse.tractusx.traceability.qualitynotification.domain.investigation.model.exception.NotificationNotSupportedException; import org.eclipse.tractusx.traceability.qualitynotification.domain.investigation.model.exception.InvestigationReceiverBpnMismatchException; import org.eclipse.tractusx.traceability.qualitynotification.domain.investigation.model.exception.InvestigationStatusTransitionNotAllowed; import org.eclipse.tractusx.traceability.qualitynotification.domain.investigation.model.exception.NotificationStatusTransitionNotAllowed; @@ -132,6 +134,13 @@ ResponseEntity handleInvestigationNotFoundException(Investigation .body(new ErrorResponse(exception.getMessage())); } + @ExceptionHandler(NotificationNotSupportedException.class) + ResponseEntity handleInvestigationNotSupportedException(NotificationNotSupportedException exception) { + log.warn("handleInvestigationNotSupportedException", exception); + return ResponseEntity.status(HttpStatus.BAD_REQUEST) + .body(new ErrorResponse(exception.getMessage())); + } + @ExceptionHandler(AlertNotFoundException.class) ResponseEntity handleAlertNotFoundException(AlertNotFoundException exception) { log.warn("handleAlertNotFoundException", exception); @@ -294,4 +303,12 @@ public ResponseEntity handleMethodArgumentTypeMismatchException(f return ResponseEntity.status(HttpStatus.BAD_REQUEST) .body(new ErrorResponse(exception.getMessage())); } + + @ExceptionHandler(ImportJobNotFoundException.class) + public ResponseEntity handleImportJobNotFoundException(final ImportJobNotFoundException exception) { + log.error("ImportJobNotFoundException exception", exception); + + return ResponseEntity.status(HttpStatus.NOT_FOUND) + .body(new ErrorResponse(exception.getMessage())); + } } diff --git a/tx-backend/src/main/java/org/eclipse/tractusx/traceability/common/config/OpenApiConfig.java b/tx-backend/src/main/java/org/eclipse/tractusx/traceability/common/config/OpenApiConfig.java index 1fb3a1aee1..483aca2db8 100644 --- a/tx-backend/src/main/java/org/eclipse/tractusx/traceability/common/config/OpenApiConfig.java +++ b/tx-backend/src/main/java/org/eclipse/tractusx/traceability/common/config/OpenApiConfig.java @@ -45,7 +45,7 @@ public OpenAPI baseOpenAPI() { .flows(new OAuthFlows().clientCredentials( new OAuthFlow().scopes( new Scopes().addString( - "profile email", ""))))); + "profile email", "")).tokenUrl("localhost")))); return new OpenAPI() .components(components) .addSecurityItem(new SecurityRequirement().addList("oAuth2", "profile email")) diff --git a/tx-backend/src/main/java/org/eclipse/tractusx/traceability/qualitynotification/domain/base/service/HttpCallService.java b/tx-backend/src/main/java/org/eclipse/tractusx/traceability/qualitynotification/domain/base/service/HttpCallService.java index 0b051fb44c..536411016d 100644 --- a/tx-backend/src/main/java/org/eclipse/tractusx/traceability/qualitynotification/domain/base/service/HttpCallService.java +++ b/tx-backend/src/main/java/org/eclipse/tractusx/traceability/qualitynotification/domain/base/service/HttpCallService.java @@ -31,7 +31,6 @@ import static java.lang.String.format; -// TODO - either refactor this class to use feignClient with a common httpClient or remove it once IRS-Lib is done @Slf4j @Component public class HttpCallService { @@ -43,12 +42,11 @@ public HttpCallService(RestTemplate edcNotificationTemplate) { } - public void sendRequest(EdcNotificationRequest request) { + public void sendRequest(final EdcNotificationRequest request) { HttpEntity entity = new HttpEntity<>(request.getBody(), request.getHeaders()); try { var response = edcNotificationTemplate.exchange(request.getUrl(), HttpMethod.POST, entity, new ParameterizedTypeReference<>() { }); - log.info("Control plane responded with response: {}", response); log.info("Control plane responded with status: {}", response.getStatusCode()); if (!response.getStatusCode().is2xxSuccessful()) { throw new BadRequestException(format("Control plane responded with: %s", response.getStatusCode())); diff --git a/tx-backend/src/main/java/org/eclipse/tractusx/traceability/qualitynotification/domain/base/service/NotificationPublisherService.java b/tx-backend/src/main/java/org/eclipse/tractusx/traceability/qualitynotification/domain/base/service/NotificationPublisherService.java index 60a32f0424..6a27f5f742 100644 --- a/tx-backend/src/main/java/org/eclipse/tractusx/traceability/qualitynotification/domain/base/service/NotificationPublisherService.java +++ b/tx-backend/src/main/java/org/eclipse/tractusx/traceability/qualitynotification/domain/base/service/NotificationPublisherService.java @@ -24,9 +24,6 @@ import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.eclipse.tractusx.traceability.assets.domain.asbuilt.repository.AssetAsBuiltRepository; -import org.eclipse.tractusx.traceability.assets.domain.asbuilt.service.AssetAsBuiltServiceImpl; -import org.eclipse.tractusx.traceability.assets.domain.asplanned.repository.AssetAsPlannedRepository; -import org.eclipse.tractusx.traceability.assets.domain.asplanned.service.AssetAsPlannedServiceImpl; import org.eclipse.tractusx.traceability.assets.domain.base.model.AssetBase; import org.eclipse.tractusx.traceability.bpn.domain.service.BpnRepository; import org.eclipse.tractusx.traceability.common.model.BPN; @@ -39,6 +36,7 @@ import org.eclipse.tractusx.traceability.qualitynotification.domain.base.model.QualityNotificationSide; import org.eclipse.tractusx.traceability.qualitynotification.domain.base.model.QualityNotificationStatus; import org.eclipse.tractusx.traceability.qualitynotification.domain.base.model.exception.QualityNotificationIllegalUpdate; +import org.eclipse.tractusx.traceability.qualitynotification.domain.investigation.model.exception.NotificationNotSupportedException; import org.springframework.stereotype.Service; import java.time.Clock; @@ -64,9 +62,6 @@ public class NotificationPublisherService { private final TraceabilityProperties traceabilityProperties; private final EdcNotificationService edcNotificationService; private final AssetAsBuiltRepository assetAsBuiltRepository; - private final AssetAsPlannedRepository assetAsPlannedRepository; - private final AssetAsBuiltServiceImpl assetAsBuiltService; - private final AssetAsPlannedServiceImpl assetAsPlannedService; private final BpnRepository bpnRepository; private final Clock clock; @@ -87,25 +82,15 @@ public QualityNotification startInvestigation(List assetIds, String desc QualityNotification notification = QualityNotification.startNotification(clock.instant(), applicationBPN, description); if (isAsBuilt) { Map> assetsAsBuiltBPNMap = assetAsBuiltRepository.getAssetsById(assetIds).stream().collect(groupingBy(AssetBase::getManufacturerId)); - assetsAsBuiltBPNMap .entrySet() .stream() - .map(it -> createInvestigation(applicationBPN, receiverBpn, description, targetDate, severity, it)) + .map(it -> createQualityNotificationMessage(applicationBPN, receiverBpn, description, targetDate, severity, it)) .forEach(notification::addNotification); return notification; } else { - Map> assetsAsPlannedBPNMap = assetAsPlannedRepository.getAssetsById(assetIds).stream().collect(groupingBy(AssetBase::getManufacturerId)); - - assetsAsPlannedBPNMap - .entrySet() - .stream() - .map(it -> createInvestigation(applicationBPN, receiverBpn, description, targetDate, severity, it)) - .forEach(notification::addNotification); - return notification; + throw new NotificationNotSupportedException(); } - - } @@ -122,11 +107,11 @@ public QualityNotification startInvestigation(List assetIds, String desc public QualityNotification startAlert(List assetIds, String description, Instant targetDate, QualityNotificationSeverity severity, String receiverBpn, boolean isAsBuilt) { BPN applicationBPN = traceabilityProperties.getBpn(); QualityNotification notification = QualityNotification.startNotification(clock.instant(), applicationBPN, description); - List assets = new ArrayList<>(); + List assets; if (isAsBuilt) { - assets.addAll(assetAsBuiltRepository.getAssetsById(assetIds)); + assets = new ArrayList<>(assetAsBuiltRepository.getAssetsById(assetIds)); } else { - assets.addAll(assetAsPlannedRepository.getAssetsById(assetIds)); + throw new NotificationNotSupportedException(); } @@ -136,7 +121,7 @@ public QualityNotification startAlert(List assetIds, String description, return notification; } - private QualityNotificationMessage createInvestigation(BPN applicationBpn, String receiverBpn, String description, Instant targetDate, QualityNotificationSeverity severity, Map.Entry> asset) { + private QualityNotificationMessage createQualityNotificationMessage(BPN applicationBpn, String receiverBpn, String description, Instant targetDate, QualityNotificationSeverity severity, Map.Entry> asset) { final String notificationId = UUID.randomUUID().toString(); final String messageId = UUID.randomUUID().toString(); return QualityNotificationMessage.builder() diff --git a/tx-backend/src/main/java/org/eclipse/tractusx/traceability/qualitynotification/domain/investigation/model/exception/NotificationNotSupportedException.java b/tx-backend/src/main/java/org/eclipse/tractusx/traceability/qualitynotification/domain/investigation/model/exception/NotificationNotSupportedException.java new file mode 100644 index 0000000000..7ecf55bb8a --- /dev/null +++ b/tx-backend/src/main/java/org/eclipse/tractusx/traceability/qualitynotification/domain/investigation/model/exception/NotificationNotSupportedException.java @@ -0,0 +1,27 @@ +/******************************************************************************** + * Copyright (c) 2024 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +package org.eclipse.tractusx.traceability.qualitynotification.domain.investigation.model.exception; + +public class NotificationNotSupportedException extends RuntimeException { + + public NotificationNotSupportedException() { + super("Notification not supported for parts as planned"); + } +} diff --git a/tx-backend/src/main/java/org/eclipse/tractusx/traceability/qualitynotification/infrastructure/alert/model/AlertEntity.java b/tx-backend/src/main/java/org/eclipse/tractusx/traceability/qualitynotification/infrastructure/alert/model/AlertEntity.java index 913e92932d..e427e2eeda 100644 --- a/tx-backend/src/main/java/org/eclipse/tractusx/traceability/qualitynotification/infrastructure/alert/model/AlertEntity.java +++ b/tx-backend/src/main/java/org/eclipse/tractusx/traceability/qualitynotification/infrastructure/alert/model/AlertEntity.java @@ -62,13 +62,6 @@ public class AlertEntity extends NotificationBaseEntity { ) public List assets; - @ManyToMany(cascade = CascadeType.ALL) - @JoinTable( - name = "assets_as_planned_alerts", - joinColumns = @JoinColumn(name = "alert_id"), - inverseJoinColumns = @JoinColumn(name = "asset_id") - ) - private List assetsAsPlanned; @OneToMany(mappedBy = "alert") private List notifications; diff --git a/tx-backend/src/main/java/org/eclipse/tractusx/traceability/qualitynotification/infrastructure/alert/model/AlertNotificationEntity.java b/tx-backend/src/main/java/org/eclipse/tractusx/traceability/qualitynotification/infrastructure/alert/model/AlertNotificationEntity.java index 222c7d3bb1..577b67977c 100644 --- a/tx-backend/src/main/java/org/eclipse/tractusx/traceability/qualitynotification/infrastructure/alert/model/AlertNotificationEntity.java +++ b/tx-backend/src/main/java/org/eclipse/tractusx/traceability/qualitynotification/infrastructure/alert/model/AlertNotificationEntity.java @@ -32,7 +32,6 @@ import lombok.Setter; import lombok.experimental.SuperBuilder; import org.eclipse.tractusx.traceability.assets.infrastructure.asbuilt.model.AssetAsBuiltEntity; -import org.eclipse.tractusx.traceability.assets.infrastructure.asplanned.model.AssetAsPlannedEntity; import org.eclipse.tractusx.traceability.qualitynotification.domain.base.model.QualityNotificationAffectedPart; import org.eclipse.tractusx.traceability.qualitynotification.domain.base.model.QualityNotificationMessage; import org.eclipse.tractusx.traceability.qualitynotification.domain.base.model.QualityNotificationStatus; @@ -63,14 +62,6 @@ public class AlertNotificationEntity extends QualityNotificationMessageBaseEntit ) private List assets; - @ManyToMany(cascade = CascadeType.ALL) - @JoinTable( - name = "asset_as_planned_alert_notifications", - joinColumns = @JoinColumn(name = "alert_notification_id"), - inverseJoinColumns = @JoinColumn(name = "asset_id") - ) - private List assetsAsPlanned; - public static QualityNotificationMessage toDomain(AlertNotificationEntity alertNotificationEntity) { return QualityNotificationMessage.builder() .id(alertNotificationEntity.getId()) @@ -99,8 +90,7 @@ public static QualityNotificationMessage toDomain(AlertNotificationEntity alertN public static AlertNotificationEntity from(AlertEntity alertEntity, QualityNotificationMessage qualityNotificationMessage, - List notificationAssets, - List assetAsPlannedEntitiesByAlert) { + List notificationAssets) { return AlertNotificationEntity .builder() .id(qualityNotificationMessage.getId()) @@ -111,7 +101,6 @@ public static AlertNotificationEntity from(AlertEntity alertEntity, .sendTo(qualityNotificationMessage.getSendTo()) .sendToName(qualityNotificationMessage.getSendToName()) .assets(notificationAssets) - .assetsAsPlanned(assetAsPlannedEntitiesByAlert) .notificationReferenceId(qualityNotificationMessage.getNotificationReferenceId()) .targetDate(qualityNotificationMessage.getTargetDate()) .severity(qualityNotificationMessage.getSeverity()) diff --git a/tx-backend/src/main/java/org/eclipse/tractusx/traceability/qualitynotification/infrastructure/alert/repository/AlertsRepositoryImpl.java b/tx-backend/src/main/java/org/eclipse/tractusx/traceability/qualitynotification/infrastructure/alert/repository/AlertsRepositoryImpl.java index 2ab2ccc8f2..6ee78cf2d5 100644 --- a/tx-backend/src/main/java/org/eclipse/tractusx/traceability/qualitynotification/infrastructure/alert/repository/AlertsRepositoryImpl.java +++ b/tx-backend/src/main/java/org/eclipse/tractusx/traceability/qualitynotification/infrastructure/alert/repository/AlertsRepositoryImpl.java @@ -68,8 +68,6 @@ public class AlertsRepositoryImpl implements AlertRepository { private final JpaAssetAsBuiltRepository assetAsBuiltRepository; - private final JpaAssetAsPlannedRepository assetAsPlannedRepository; - private final JpaAlertNotificationRepository notificationRepository; private final Clock clock; @@ -107,16 +105,15 @@ public QualityNotificationId updateQualityNotificationEntity(QualityNotification public QualityNotificationId saveQualityNotificationEntity(QualityNotification alert) { List assetAsBuiltEntities = getAssetAsBuiltEntitiesByAlert(alert); - List assetAsPlannedEntities = getAssetAsPlannedEntitiesByAlert(alert); - if (assetAsBuiltEntities.isEmpty() && assetAsPlannedEntities.isEmpty()) { + if (assetAsBuiltEntities.isEmpty()) { throw new IllegalArgumentException("No assets found for %s asset ids".formatted(String.join(", ", alert.getAssetIds()))); } AlertEntity alertEntity = AlertEntity.from(alert, assetAsBuiltEntities); jpaAlertRepository.save(alertEntity); alert.getNotifications() - .forEach(notification -> handleNotificationCreate(alertEntity, notification, assetAsBuiltEntities, assetAsPlannedEntities)); + .forEach(notification -> handleNotificationCreate(alertEntity, notification, assetAsBuiltEntities)); return new QualityNotificationId(alertEntity.getId()); } @@ -171,8 +168,7 @@ private void handleNotificationUpdate(AlertEntity alertEntity, QualityNotificati } else { log.info("handleNotificationUpdate::new notification with id {} for alert with id {}", notification.getId(), alert.getNotificationId()); List assetAsBuiltEntitiesByAlert = getAssetAsBuiltEntitiesByAlert(alert); - List assetAsPlannedEntitiesByAlert = getAssetAsPlannedEntitiesByAlert(alert); - handleNotificationCreate(alertEntity, notification, assetAsBuiltEntitiesByAlert, assetAsPlannedEntitiesByAlert); + handleNotificationCreate(alertEntity, notification, assetAsBuiltEntitiesByAlert); } } @@ -182,13 +178,9 @@ private List getAssetAsBuiltEntitiesByAlert(QualityNotificat return assetAsBuiltRepository.findByIdIn(alert.getAssetIds()); } - private List getAssetAsPlannedEntitiesByAlert(QualityNotification alert) { - return assetAsPlannedRepository.findByIdIn(alert.getAssetIds()); - } - private void handleNotificationCreate(AlertEntity alertEntity, QualityNotificationMessage notificationDomain, - List assetEntities, List assetAsPlannedEntitiesByAlert) { - AlertNotificationEntity notificationEntity = toNotificationEntity(alertEntity, notificationDomain, assetEntities, assetAsPlannedEntitiesByAlert); + List assetEntities) { + AlertNotificationEntity notificationEntity = toNotificationEntity(alertEntity, notificationDomain, assetEntities); AlertNotificationEntity savedEntity = notificationRepository.save(notificationEntity); log.info("Successfully persisted alert notification entity {}", savedEntity); } @@ -207,14 +199,13 @@ private void handleNotificationUpdate(AlertNotificationEntity notificationEntity } - private AlertNotificationEntity toNotificationEntity(AlertEntity alertEntity, QualityNotificationMessage notification, List alertAssets, List assetAsPlannedEntitiesByAlert) { + private AlertNotificationEntity toNotificationEntity(AlertEntity alertEntity, QualityNotificationMessage notification, List alertAssets) { List filteredAsBuiltAssets = filterNotificationAssets(notification, alertAssets); - List filteredAsPlannedAssets = filterNotificationAssets(notification, assetAsPlannedEntitiesByAlert); - if (filteredAsBuiltAssets.isEmpty() && filteredAsPlannedAssets.isEmpty()) { + if (filteredAsBuiltAssets.isEmpty()) { throw new IllegalStateException(" with id %s has no notification assets".formatted(alertEntity.getId())); } - return AlertNotificationEntity.from(alertEntity, notification, filteredAsBuiltAssets, filteredAsPlannedAssets); + return AlertNotificationEntity.from(alertEntity, notification, filteredAsBuiltAssets); } private List filterNotificationAssets(QualityNotificationMessage notification, List assets) { diff --git a/tx-backend/src/main/java/org/eclipse/tractusx/traceability/qualitynotification/infrastructure/investigation/model/InvestigationEntity.java b/tx-backend/src/main/java/org/eclipse/tractusx/traceability/qualitynotification/infrastructure/investigation/model/InvestigationEntity.java index 1232aad6e2..9efbb3dbf2 100644 --- a/tx-backend/src/main/java/org/eclipse/tractusx/traceability/qualitynotification/infrastructure/investigation/model/InvestigationEntity.java +++ b/tx-backend/src/main/java/org/eclipse/tractusx/traceability/qualitynotification/infrastructure/investigation/model/InvestigationEntity.java @@ -33,7 +33,6 @@ import lombok.Setter; import lombok.experimental.SuperBuilder; import org.eclipse.tractusx.traceability.assets.infrastructure.asbuilt.model.AssetAsBuiltEntity; -import org.eclipse.tractusx.traceability.assets.infrastructure.asplanned.model.AssetAsPlannedEntity; import org.eclipse.tractusx.traceability.common.model.BPN; import org.eclipse.tractusx.traceability.qualitynotification.domain.base.model.QualityNotification; import org.eclipse.tractusx.traceability.qualitynotification.domain.base.model.QualityNotificationId; @@ -64,13 +63,6 @@ public class InvestigationEntity extends NotificationBaseEntity { ) private List assets; - @ManyToMany(cascade = CascadeType.ALL) - @JoinTable( - name = "assets_as_planned_investigations", - joinColumns = @JoinColumn(name = "investigation_id"), - inverseJoinColumns = @JoinColumn(name = "asset_id") - ) - private List assetsAsPlanned; @OneToMany(mappedBy = "investigation") private List notifications; @@ -104,8 +96,6 @@ public static QualityNotification toDomain(InvestigationEntity investigationEnti public static InvestigationEntity from(QualityNotification qualityNotification, List assetEntities) { return InvestigationEntity.builder() .assets(assetEntities) - // TODO clarify how to handle assetsAsPlanned - .assetsAsPlanned(null) .bpn(qualityNotification.getBpn()) .description(qualityNotification.getDescription()) .status(NotificationStatusBaseEntity.fromStringValue(qualityNotification.getNotificationStatus().name())) diff --git a/tx-backend/src/main/java/org/eclipse/tractusx/traceability/qualitynotification/infrastructure/investigation/model/InvestigationNotificationEntity.java b/tx-backend/src/main/java/org/eclipse/tractusx/traceability/qualitynotification/infrastructure/investigation/model/InvestigationNotificationEntity.java index 69bee1f0cd..e56b9f5502 100644 --- a/tx-backend/src/main/java/org/eclipse/tractusx/traceability/qualitynotification/infrastructure/investigation/model/InvestigationNotificationEntity.java +++ b/tx-backend/src/main/java/org/eclipse/tractusx/traceability/qualitynotification/infrastructure/investigation/model/InvestigationNotificationEntity.java @@ -63,15 +63,6 @@ public class InvestigationNotificationEntity extends QualityNotificationMessageB ) private List assets; - @ManyToMany(cascade = CascadeType.ALL) - @JoinTable( - name = "assets_as_planned_notifications", - joinColumns = @JoinColumn(name = "notification_id"), - inverseJoinColumns = @JoinColumn(name = "asset_id") - ) - private List assetsAsPlanned; - - public static QualityNotificationMessage toDomain(InvestigationNotificationEntity investigationNotificationEntity) { return QualityNotificationMessage.builder() .id(investigationNotificationEntity.getId()) diff --git a/tx-backend/src/main/resources/db/migration/V12__add_import_report.sql b/tx-backend/src/main/resources/db/migration/V12__add_import_report.sql new file mode 100644 index 0000000000..c0ba6ca7dc --- /dev/null +++ b/tx-backend/src/main/resources/db/migration/V12__add_import_report.sql @@ -0,0 +1,34 @@ +-- public.import_job definition + +-- Drop table + +-- Drop TABLE public.import_job + +CREATE TABLE public.import_job +( + id varchar(255) NOT NULL, + started_on timestamp NULL, + completed_on timestamp NULL, + import_job_status varchar(255) NOT NULL, + asset_as_built_id VARCHAR(255) NULL, + asset_as_planned_id VARCHAR(255) NULL, + CONSTRAINT import_job_pkey PRIMARY KEY (id), + CONSTRAINT fk_asset_as_planned_import_job FOREIGN KEY (asset_as_planned_id) REFERENCES public.assets_as_planned (id) +); + + +CREATE TABLE public.import_job_assets_as_built +( + import_job_id VARCHAR(255) NOT NULL, + asset_as_built_id VARCHAR(255) NOT NULL, + CONSTRAINT fk_import_job FOREIGN KEY (import_job_id) REFERENCES public.import_job (id), + CONSTRAINT fk_assets_as_built FOREIGN KEY (asset_as_built_id) REFERENCES public.assets_as_built (id) +); + +CREATE TABLE public.import_job_assets_as_planned +( + import_job_id VARCHAR(255) NOT NULL, + asset_as_planned_id VARCHAR(255) NOT NULL, + CONSTRAINT fk_import_job FOREIGN KEY (import_job_id) REFERENCES public.import_job (id), + CONSTRAINT fk_assets_as_planned FOREIGN KEY (asset_as_planned_id) REFERENCES public.assets_as_planned (id) +); diff --git a/tx-backend/src/main/resources/db/migration/V13__remove_investigation_alert_asset-as-planned.sql b/tx-backend/src/main/resources/db/migration/V13__remove_investigation_alert_asset-as-planned.sql new file mode 100644 index 0000000000..2268254277 --- /dev/null +++ b/tx-backend/src/main/resources/db/migration/V13__remove_investigation_alert_asset-as-planned.sql @@ -0,0 +1,4 @@ +DROP TABLE public.asset_as_planned_alert_notifications; +DROP TABLE public.assets_as_planned_alerts; +DROP TABLE public.assets_as_planned_investigations; +DROP TABLE public.assets_as_planned_notifications; diff --git a/tx-backend/src/main/resources/db/migration/V6__create_submodelPayload_table.sql b/tx-backend/src/main/resources/db/migration/V6__create_submodelPayload_table.sql index a2113bebca..493c63fc9f 100644 --- a/tx-backend/src/main/resources/db/migration/V6__create_submodelPayload_table.sql +++ b/tx-backend/src/main/resources/db/migration/V6__create_submodelPayload_table.sql @@ -6,8 +6,8 @@ CREATE TABLE public.submodel_payload ( - id varchar(255) NOT NULL, - json varchar NULL, + id varchar(255) NOT NULL, + json varchar NULL, CONSTRAINT submodel_payload_pkey PRIMARY KEY (id) ); diff --git a/tx-backend/src/test/java/org/eclipse/tractusx/traceability/assets/domain/importpoc/service/ImportServiceImplTest.java b/tx-backend/src/test/java/org/eclipse/tractusx/traceability/assets/domain/importpoc/service/ImportServiceImplTest.java index f06fc46ba2..e236d34a32 100644 --- a/tx-backend/src/test/java/org/eclipse/tractusx/traceability/assets/domain/importpoc/service/ImportServiceImplTest.java +++ b/tx-backend/src/test/java/org/eclipse/tractusx/traceability/assets/domain/importpoc/service/ImportServiceImplTest.java @@ -22,6 +22,9 @@ import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import org.eclipse.tractusx.traceability.assets.domain.asbuilt.repository.AssetAsBuiltRepository; import org.eclipse.tractusx.traceability.assets.domain.asplanned.repository.AssetAsPlannedRepository; +import org.eclipse.tractusx.traceability.assets.domain.importpoc.model.ImportJob; +import org.eclipse.tractusx.traceability.assets.domain.importpoc.model.ImportJobStatus; +import org.eclipse.tractusx.traceability.assets.domain.importpoc.repository.ImportJobRepository; import org.eclipse.tractusx.traceability.assets.domain.importpoc.repository.SubmodelPayloadRepository; import org.eclipse.tractusx.traceability.common.model.BPN; import org.eclipse.tractusx.traceability.common.properties.TraceabilityProperties; @@ -35,6 +38,9 @@ import java.io.IOException; import java.io.InputStream; +import java.time.Instant; +import java.util.List; +import java.util.UUID; import static org.mockito.ArgumentMatchers.anyList; import static org.mockito.Mockito.times; @@ -56,13 +62,15 @@ class ImportServiceImplTest { @Mock private TraceabilityProperties traceabilityProperties; + @Mock + private ImportJobRepository importJobRepository; @BeforeEach public void testSetup() { ObjectMapper objectMapper = new ObjectMapper(); objectMapper.registerModule(new JavaTimeModule()); - importService = new ImportServiceImpl(objectMapper, assetAsPlannedRepository, assetAsBuiltRepository, traceabilityProperties, new MappingStrategyFactory(), submodelPayloadRepository); + importService = new ImportServiceImpl(objectMapper, assetAsPlannedRepository, assetAsBuiltRepository, traceabilityProperties, new MappingStrategyFactory(), submodelPayloadRepository, importJobRepository); } @@ -79,7 +87,7 @@ void testImportRequestSuccessful() throws IOException { ); when(traceabilityProperties.getBpn()).thenReturn(BPN.of("BPNL00000003CML1")); - importService.importAssets(multipartFile); + importService.importAssets(multipartFile, new ImportJob(UUID.randomUUID(), Instant.now(), null, ImportJobStatus.RUNNING, List.of(), List.of())); verify(assetAsBuiltRepository, times(1)).saveAllIfNotInIRSSyncAndUpdateImportStateAndNote(anyList()); verify(assetAsPlannedRepository, times(1)).saveAllIfNotInIRSSyncAndUpdateImportStateAndNote(anyList()); } diff --git a/tx-backend/src/test/java/org/eclipse/tractusx/traceability/integration/assets/AssetAsPlannedControllerByIdIT.java b/tx-backend/src/test/java/org/eclipse/tractusx/traceability/integration/assets/AssetAsPlannedControllerByIdIT.java index 6f6e477531..59df8df19a 100644 --- a/tx-backend/src/test/java/org/eclipse/tractusx/traceability/integration/assets/AssetAsPlannedControllerByIdIT.java +++ b/tx-backend/src/test/java/org/eclipse/tractusx/traceability/integration/assets/AssetAsPlannedControllerByIdIT.java @@ -74,58 +74,6 @@ private static Stream requests() { ); } - @Test - void givenAlertsForAsset_whenCallAssetById_thenReturnProperCount() throws JoseException { - // Given - assetsSupport.defaultAssetsAsPlannedStored(); - AssetAsPlannedEntity asset = jpaAssetAsPlannedRepository.findById("urn:uuid:0733946c-59c6-41ae-9570-cb43a6e4da01").orElseThrow(); - alertsSupport.storeAlertWithStatusAndAssets(CREATED, null, List.of(asset)); - alertsSupport.storeAlertWithStatusAndAssets(SENT, null, List.of(asset)); - alertsSupport.storeAlertWithStatusAndAssets(RECEIVED, null, List.of(asset)); - alertsSupport.storeAlertWithStatusAndAssets(ACKNOWLEDGED, null, List.of(asset)); - alertsSupport.storeAlertWithStatusAndAssets(ACCEPTED, null, List.of(asset)); - alertsSupport.storeAlertWithStatusAndAssets(DECLINED, null, List.of(asset)); - alertsSupport.storeAlertWithStatusAndAssets(CANCELED, null, List.of(asset)); - alertsSupport.storeAlertWithStatusAndAssets(CLOSED, null, List.of(asset)); - - // When - given() - .header(oAuth2Support.jwtAuthorization(ADMIN)) - .contentType(ContentType.JSON) - .when() - .get("/api/assets/as-planned/urn:uuid:0733946c-59c6-41ae-9570-cb43a6e4da01") - .then() - .log().all() - .statusCode(200) - .assertThat() - .body("receivedQualityAlertIdsInStatusActive", hasSize(6)); - } - - @Test - void givenInvestigationsForAsset_whenCallAssetById_thenReturnProperCount() throws JoseException { - // Given - assetsSupport.defaultAssetsAsPlannedStored(); - AssetAsPlannedEntity asset = jpaAssetAsPlannedRepository.findById("urn:uuid:0733946c-59c6-41ae-9570-cb43a6e4da01").orElseThrow(); - investigationsSupport.storeInvestigationWithStatusAndAssets(CREATED, null, List.of(asset)); - investigationsSupport.storeInvestigationWithStatusAndAssets(SENT, null, List.of(asset)); - investigationsSupport.storeInvestigationWithStatusAndAssets(RECEIVED, null, List.of(asset)); - investigationsSupport.storeInvestigationWithStatusAndAssets(ACKNOWLEDGED, null, List.of(asset)); - investigationsSupport.storeInvestigationWithStatusAndAssets(ACCEPTED, null, List.of(asset)); - investigationsSupport.storeInvestigationWithStatusAndAssets(DECLINED, null, List.of(asset)); - investigationsSupport.storeInvestigationWithStatusAndAssets(CANCELED, null, List.of(asset)); - investigationsSupport.storeInvestigationWithStatusAndAssets(CLOSED, null, List.of(asset)); - - // When - given() - .header(oAuth2Support.jwtAuthorization(ADMIN)) - .contentType(ContentType.JSON) - .when() - .get("/api/assets/as-planned/urn:uuid:0733946c-59c6-41ae-9570-cb43a6e4da01") - .then() - .statusCode(200) - .assertThat() - .body("receivedQualityInvestigationIdsInStatusActive", hasSize(6)); - } @Test void shouldReturnAssetsForAuthenticatedUserWithRole() throws JoseException { diff --git a/tx-backend/src/test/java/org/eclipse/tractusx/traceability/integration/assets/infrastructure/base/IrsCallbackControllerIT.java b/tx-backend/src/test/java/org/eclipse/tractusx/traceability/integration/assets/infrastructure/base/IrsCallbackControllerIT.java index 19a79cdc40..62936b7913 100644 --- a/tx-backend/src/test/java/org/eclipse/tractusx/traceability/integration/assets/infrastructure/base/IrsCallbackControllerIT.java +++ b/tx-backend/src/test/java/org/eclipse/tractusx/traceability/integration/assets/infrastructure/base/IrsCallbackControllerIT.java @@ -98,6 +98,32 @@ void givenNoAssets_whenCallbackReceivedForAsPlanned_thenSaveThem() { assetsSupport.assertAssetAsPlannedSize(2); } + @Test + void givenInvalidJobId_whenCallbackReceivedForAsPlanned_thenNothingSynchronized() { + // given + oAuth2ApiSupport.oauth2ApiReturnsTechnicalUserToken(); + irsApiSupport.irsJobDetailsAsPlanned(); + String invalidJobId = "irs/admin/test/ID"; + String jobState = "COMPLETED"; + + // when + given() + .contentType(ContentType.JSON) + .log().all() + .when() + .param("id", invalidJobId) + .param("state", jobState) + .get("/api/irs/job/callback") + .then() + .log().all() + .statusCode(200); + + // then + assertThat(bpnSupportRepository.findAll()).isEmpty(); + assetsSupport.assertAssetAsBuiltSize(0); + assetsSupport.assertAssetAsPlannedSize(0); + } + @Test void givenAssetExist_whenCallbackReceived_thenUpdateIt() { // given diff --git a/tx-backend/src/test/java/org/eclipse/tractusx/traceability/integration/common/support/AlertsSupport.java b/tx-backend/src/test/java/org/eclipse/tractusx/traceability/integration/common/support/AlertsSupport.java index 10a2f2b20a..291eb4a7b9 100644 --- a/tx-backend/src/test/java/org/eclipse/tractusx/traceability/integration/common/support/AlertsSupport.java +++ b/tx-backend/src/test/java/org/eclipse/tractusx/traceability/integration/common/support/AlertsSupport.java @@ -74,7 +74,6 @@ public Long storeAlertWithStatusAndAssets(NotificationStatusBaseEntity status, L Long alertId = storedAlert(entity); AlertEntity savedAlert = jpaAlertRepository.findById(alertId).get(); savedAlert.setAssets(assetsAsBuilt); - savedAlert.setAssetsAsPlanned(assetsAsPlanned); jpaAlertRepository.save(savedAlert); return alertId; } diff --git a/tx-backend/src/test/java/org/eclipse/tractusx/traceability/integration/common/support/DatabaseSupport.java b/tx-backend/src/test/java/org/eclipse/tractusx/traceability/integration/common/support/DatabaseSupport.java index 26cd437eac..8b96e0dc05 100644 --- a/tx-backend/src/test/java/org/eclipse/tractusx/traceability/integration/common/support/DatabaseSupport.java +++ b/tx-backend/src/test/java/org/eclipse/tractusx/traceability/integration/common/support/DatabaseSupport.java @@ -29,17 +29,15 @@ public class DatabaseSupport { private static final List TABLES = List.of(new String[]{ "submodel_payload", + "import_job_assets_as_built", + "import_job_assets_as_planned", "assets_as_built_childs", "assets_as_built_parents", "assets_as_built_notifications", "assets_as_built_investigations", "asset_as_built_alert_notifications", - "asset_as_planned_alert_notifications", "assets_as_built_alerts", "assets_as_planned_childs", - "assets_as_planned_notifications", - "assets_as_planned_investigations", - "assets_as_planned_alerts", "alert_notification", "alert", "assets_as_built", @@ -47,7 +45,8 @@ public class DatabaseSupport { "bpn_storage", "investigation_notification", "investigation", - "traction_battery_code_subcomponent" + "traction_battery_code_subcomponent", + "import_job" }); diff --git a/tx-backend/src/test/java/org/eclipse/tractusx/traceability/integration/common/support/InvestigationsSupport.java b/tx-backend/src/test/java/org/eclipse/tractusx/traceability/integration/common/support/InvestigationsSupport.java index 55c18e7a36..2e96c5225f 100644 --- a/tx-backend/src/test/java/org/eclipse/tractusx/traceability/integration/common/support/InvestigationsSupport.java +++ b/tx-backend/src/test/java/org/eclipse/tractusx/traceability/integration/common/support/InvestigationsSupport.java @@ -70,7 +70,6 @@ public Long storeInvestigationWithStatusAndAssets(NotificationStatusBaseEntity s Long alertId = storedInvestigation(entity); InvestigationEntity savedInvestigation = jpaInvestigationRepository.findById(alertId).get(); savedInvestigation.setAssets(assetsAsBuilt); - savedInvestigation.setAssetsAsPlanned(assetsAsPlanned); jpaInvestigationRepository.save(savedInvestigation); return alertId; } diff --git a/tx-backend/src/test/java/org/eclipse/tractusx/traceability/integration/importdata/ImportControllerIT.java b/tx-backend/src/test/java/org/eclipse/tractusx/traceability/integration/importdata/ImportControllerIT.java index cc7f63dd01..4bf70adae7 100644 --- a/tx-backend/src/test/java/org/eclipse/tractusx/traceability/integration/importdata/ImportControllerIT.java +++ b/tx-backend/src/test/java/org/eclipse/tractusx/traceability/integration/importdata/ImportControllerIT.java @@ -19,6 +19,7 @@ package org.eclipse.tractusx.traceability.integration.importdata; +import assets.importpoc.ImportReportResponse; import assets.importpoc.ImportResponse; import assets.importpoc.ImportStateMessage; import assets.importpoc.request.RegisterAssetRequest; @@ -75,6 +76,7 @@ void givenValidFile_whenImportData_thenValidationShouldPass() throws JoseExcepti .extract().as(ImportResponse.class); assertThat(result.validationResult().validationErrors()).isEmpty(); + assertThat(result.jobId()).isNotEmpty(); assertThat(result.importStateMessage()).containsExactlyInAnyOrder( new ImportStateMessage("urn:uuid:0733946c-59c6-41ae-9570-cb43a6e4eb01", true), new ImportStateMessage("urn:uuid:0733946c-59c6-41ae-9570-cb43a6e4c79e", true), @@ -117,6 +119,7 @@ void givenValidFileWithAsBuiltOnly_whenImportData_thenValidationShouldPass() thr .extract().as(ImportResponse.class); assertThat(result.validationResult().validationErrors()).isEmpty(); + assertThat(result.jobId()).isNotEmpty(); assertThat(result.importStateMessage()).containsExactlyInAnyOrder( new ImportStateMessage("urn:uuid:6b2296cc-26c0-4f38-8a22-092338c36111", true) ); @@ -142,6 +145,7 @@ void givenValidFileWithAsPlannedOnly_whenImportData_thenValidationShouldPass() t .extract().as(ImportResponse.class); assertThat(result.validationResult().validationErrors()).isEmpty(); + assertThat(result.jobId()).isNotEmpty(); assertThat(result.importStateMessage()).containsExactlyInAnyOrder( new ImportStateMessage("urn:uuid:0733946c-59c6-41ae-9570-cb43a6e4eb01", true) ); @@ -179,6 +183,7 @@ void givenValidFile_whenImportDataButAssetExistInPersistentImportState_thenValid .extract().as(ImportResponse.class); assertThat(result.validationResult().validationErrors()).isEmpty(); + assertThat(result.jobId()).isNotEmpty(); assertThat(result.importStateMessage()).containsExactlyInAnyOrder( new ImportStateMessage("urn:uuid:0733946c-59c6-41ae-9570-cb43a6e4eb01", true), new ImportStateMessage("urn:uuid:0733946c-59c6-41ae-9570-cb43a6e4c79e", true), @@ -232,6 +237,7 @@ void givenValidFile_whenImportDataButAssetExistInTransientImportState_thenValida .extract().as(ImportResponse.class); assertThat(result.validationResult().validationErrors()).isEmpty(); + assertThat(result.jobId()).isNotEmpty(); assertThat(result.importStateMessage()).containsExactlyInAnyOrder( new ImportStateMessage("urn:uuid:0733946c-59c6-41ae-9570-cb43a6e4eb01", true), new ImportStateMessage("urn:uuid:0733946c-59c6-41ae-9570-cb43a6e4c79e", true), @@ -275,6 +281,7 @@ void givenInvalidFile_whenImportData_thenValidationShouldNotPass() throws JoseEx // then assertThat(result.importStateMessage()).isEmpty(); + assertThat(result.jobId()).isNotEmpty(); assertThat(result.validationResult().validationErrors()) .containsExactlyInAnyOrder( "Missing property aspectType", @@ -300,10 +307,11 @@ void givenInvalidFile_whenImportDataWithBadStructure_thenValidationShouldNotPass .extract().as(ImportResponse.class); assertThat(result.importStateMessage()).isEmpty(); + assertThat(result.jobId()).isNotEmpty(); assertThat(result.validationResult().validationErrors()) .containsExactlyInAnyOrder( "Could not find assets" - ); + ); } @Test @@ -323,7 +331,8 @@ void givenValidFile_whenImportDataWithWrongBPN_thenValidationShouldNotPass() thr .body("validationResult.validationErrors", Matchers.contains( List.of( "At least one asset does not match the application bpn BPNL00000003AXS3" - ).toArray())); + ).toArray())) + .body("jobId", Matchers.notNullValue()); } @Test @@ -343,7 +352,8 @@ void givenInvalidFileExtension_whenImportData_thenValidationShouldPass() throws .body("validationResult.validationErrors", Matchers.contains( List.of( "Supported file is *.json" - ).toArray())); + ).toArray())) + .body("jobId", Matchers.notNullValue()); } @Test @@ -363,7 +373,8 @@ void givenInvalidAspect_whenImportData_thenValidationShouldNotPass() throws Jose .body("validationResult.validationErrors", Matchers.contains( List.of( "'urn:bamm:io.catenax.serial_part:1.1.1#NOT_SUPPORTED_NAME' is not supported" - ).toArray())); + ).toArray())) + .body("jobId", Matchers.notNullValue()); } @Test @@ -433,4 +444,51 @@ void givenInvalidAssetID_whenPublishData_thenStatusCode404() throws JoseExceptio assertNull(asset.getPolicyId()); assertEquals(asset.getImportState(), ImportState.TRANSIENT); } + + @Test + void givenValidFile_whenImportData_thenReportShouldBeReturned() throws JoseException { + + // given + String path = getClass().getResource("/testdata/importfiles/validImportFile.json").getFile(); + File file = new File(path); + ImportResponse result = given() + .header(oAuth2Support.jwtAuthorization(JwtRole.ADMIN)) + .when() + .multiPart(file) + .post("/api/assets/import") + .then() + .statusCode(200) + .extract().as(ImportResponse.class); + + // when + ImportReportResponse importReportResponse = given() + .header(oAuth2Support.jwtAuthorization(JwtRole.ADMIN)) + .contentType(ContentType.JSON) + .when() + .pathParam("importJobId", result.jobId()) + .get("/api/assets/import/report/{importJobId}") + .then() + .log().all() + .statusCode(200) + .extract().as(ImportReportResponse.class); + + // then + assertEquals(result.jobId(), importReportResponse.importJobResponse().importId()); + assertEquals(18, importReportResponse.importedAssetResponse().size()); + + } + + @Test + void givenUnknownImportJobId_thenStatusCode404() throws JoseException { + // given/when/then + given().header(oAuth2Support.jwtAuthorization(JwtRole.ADMIN)) + .contentType(ContentType.JSON) + .when() + .pathParam("importJobId", "I do not exist") + .get("/api/assets/import/report/{importJobId}") + .then() + .log().all() + .statusCode(404); + } + } diff --git a/tx-backend/src/test/java/org/eclipse/tractusx/traceability/integration/qualitynotification/alert/PublisherAlertsControllerIT.java b/tx-backend/src/test/java/org/eclipse/tractusx/traceability/integration/qualitynotification/alert/PublisherAlertsControllerIT.java index ccfe27894d..bd12f4d4de 100644 --- a/tx-backend/src/test/java/org/eclipse/tractusx/traceability/integration/qualitynotification/alert/PublisherAlertsControllerIT.java +++ b/tx-backend/src/test/java/org/eclipse/tractusx/traceability/integration/qualitynotification/alert/PublisherAlertsControllerIT.java @@ -172,60 +172,6 @@ void shouldStartAlert() throws JsonProcessingException, JoseException { .body("content", Matchers.hasSize(1)); } - @Test - void shouldStartAlertForAsPlanned() throws JsonProcessingException, JoseException { - // given - List partIds = List.of( - "urn:uuid:0733946c-59c6-41ae-9570-cb43a6e4da01" // BPN: BPNL00000003CML1 - ); - String description = "at least 15 characters long investigation description"; - QualityNotificationSeverityRequest severity = QualityNotificationSeverityRequest.MINOR; - String receiverBpn = "BPN"; - - assetsSupport.defaultAssetsAsPlannedStored(); - - val request = StartQualityNotificationRequest.builder() - .partIds(partIds) - .description(description) - .severity(severity) - .receiverBpn(receiverBpn) - .isAsBuilt(false) - .build(); - - // when - given() - .contentType(ContentType.JSON) - .body(objectMapper.writeValueAsString(request)) - .header(oAuth2Support.jwtAuthorization(SUPERVISOR)) - .when() - .post("/api/alerts") - .then() - .statusCode(201) - .body("id", Matchers.isA(Number.class)); - - partIds.forEach( - partId -> { - AssetBase asset = assetAsPlannedRepository.getAssetById(partId); - assertThat(asset).isNotNull(); - } - ); - - alertNotificationsSupport.assertAlertNotificationsSize(1); - - // when/then - given() - .header(oAuth2Support.jwtAuthorization(SUPERVISOR)) - .body(new PageableFilterRequest(new OwnPageable(0, 10, Collections.emptyList()), null)) - .contentType(ContentType.JSON) - .when() - .post("/api/alerts/filter") - .then() - .statusCode(200) - .body("page", Matchers.is(0)) - .body("pageSize", Matchers.is(10)) - .body("content", Matchers.hasSize(1)); - } - @Test void givenMissingSeverity_whenStartAlert_thenBadRequest() throws JsonProcessingException, JoseException { // given diff --git a/tx-backend/src/test/java/org/eclipse/tractusx/traceability/qualitynotification/domain/service/NotificationPublisherServiceTest.java b/tx-backend/src/test/java/org/eclipse/tractusx/traceability/qualitynotification/domain/service/NotificationPublisherServiceTest.java index f503b3160d..1a93677bbf 100644 --- a/tx-backend/src/test/java/org/eclipse/tractusx/traceability/qualitynotification/domain/service/NotificationPublisherServiceTest.java +++ b/tx-backend/src/test/java/org/eclipse/tractusx/traceability/qualitynotification/domain/service/NotificationPublisherServiceTest.java @@ -35,6 +35,7 @@ import org.eclipse.tractusx.traceability.qualitynotification.domain.base.model.exception.QualityNotificationIllegalUpdate; import org.eclipse.tractusx.traceability.qualitynotification.domain.base.service.EdcNotificationService; import org.eclipse.tractusx.traceability.qualitynotification.domain.base.service.NotificationPublisherService; +import org.eclipse.tractusx.traceability.qualitynotification.domain.investigation.model.exception.NotificationNotSupportedException; import org.eclipse.tractusx.traceability.testdata.AssetTestDataFactory; import org.eclipse.tractusx.traceability.testdata.InvestigationTestDataFactory; import org.junit.jupiter.api.DisplayName; @@ -104,6 +105,16 @@ void testStartInvestigationSuccessful() { verify(assetRepository).getAssetsById(Arrays.asList("asset-1", "asset-2")); } + @Test + void testThrowNotificationNotSupportedException() { + // Given + String description = "Test investigation"; + String receiverBpn = "someReceiverBpn"; + + // Then + assertThrows(NotificationNotSupportedException.class, () -> notificationPublisherService.startInvestigation(Arrays.asList("asset-1", "asset-2"), description, Instant.parse("2022-03-01T12:00:00Z"), QualityNotificationSeverity.MINOR, receiverBpn, false)); + } + @Test void testStartAlertSuccessful() { // Given diff --git a/tx-models/src/main/java/assets/importpoc/ImportJobStatusResponse.java b/tx-models/src/main/java/assets/importpoc/ImportJobStatusResponse.java new file mode 100644 index 0000000000..d062784040 --- /dev/null +++ b/tx-models/src/main/java/assets/importpoc/ImportJobStatusResponse.java @@ -0,0 +1,26 @@ +/******************************************************************************** + * Copyright (c) 2024 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ +package assets.importpoc; + +import io.swagger.annotations.ApiModel; + +@ApiModel +public enum ImportJobStatusResponse { + INITIALIZING, RUNNING, CANCELLED, COMPLETED +} diff --git a/tx-models/src/main/java/assets/importpoc/ImportReportResponse.java b/tx-models/src/main/java/assets/importpoc/ImportReportResponse.java new file mode 100644 index 0000000000..c17a0d39da --- /dev/null +++ b/tx-models/src/main/java/assets/importpoc/ImportReportResponse.java @@ -0,0 +1,54 @@ +/******************************************************************************** + * Copyright (c) 2024 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ +package assets.importpoc; + +import assets.response.base.response.ImportStateResponse; +import io.swagger.v3.oas.annotations.media.Schema; + +import java.util.List; + +@Schema +public record ImportReportResponse( + ImportJobResponse importJobResponse, + List importedAssetResponse) { + + @Schema + public record ImportJobResponse( + @Schema(example = "456a952e-05eb-40dc-a6f2-9c2cb9c1387f") + String importId, + @Schema(example = "2099-02-21T21:27:10.734950Z", maxLength = 50) + String startedOn, + @Schema(example = "2099-02-21T21:27:10.734950Z", maxLength = 50) + String completedOn, + @Schema + ImportJobStatusResponse importJobStatusResponse) { + } + + @Schema + public record ImportedAssetResponse( + @Schema(example = "urn:uuid:7eeeac86-7b69-444d-81e6-655d0f1513bd}") + String catenaxId, + @Schema + ImportStateResponse importStateResponse, + @Schema(example = "2099-02-21T21:27:10.734950Z", maxLength = 50) + String importedOn, + @Schema(example = "Asset created successfully in transient state.") + String importMessage) { + } +} diff --git a/tx-models/src/main/java/assets/importpoc/ImportResponse.java b/tx-models/src/main/java/assets/importpoc/ImportResponse.java index 2abc4acfd3..5bda73d202 100644 --- a/tx-models/src/main/java/assets/importpoc/ImportResponse.java +++ b/tx-models/src/main/java/assets/importpoc/ImportResponse.java @@ -21,15 +21,16 @@ import java.util.List; public record ImportResponse( + String jobId, List importStateMessage, ValidationResponse validationResult) { - public ImportResponse(List importStateMessages) { - this(importStateMessages, ValidationResponse.emptyValidationResult()); + public ImportResponse(String jobId, List importStateMessages) { + this(jobId, importStateMessages, ValidationResponse.emptyValidationResult()); } - public ImportResponse(ValidationResponse importStateMessages) { - this(List.of(), importStateMessages); + public ImportResponse(String jobId, ValidationResponse importStateMessages) { + this(jobId, List.of(), importStateMessages); } } diff --git a/tx-models/src/main/java/assets/response/base/response/ImportStateResponse.java b/tx-models/src/main/java/assets/response/base/response/ImportStateResponse.java index fa8492d559..a84b2580c4 100644 --- a/tx-models/src/main/java/assets/response/base/response/ImportStateResponse.java +++ b/tx-models/src/main/java/assets/response/base/response/ImportStateResponse.java @@ -18,6 +18,9 @@ ********************************************************************************/ package assets.response.base.response; +import io.swagger.annotations.ApiModel; + +@ApiModel public enum ImportStateResponse { TRANSIENT, PERSISTENT, ERROR, IN_SYNCHRONIZATION, UNSET;