diff --git a/.devops/code-review-pipelines.yml b/.devops/code-review-pipelines.yml deleted file mode 100644 index 1ddfe5910..000000000 --- a/.devops/code-review-pipelines.yml +++ /dev/null @@ -1,64 +0,0 @@ -# Maven -# Build your Java project and run tests with Apache Maven. -# Add steps that analyze code, save build artifacts, deploy, and more: -# https://docs.microsoft.com/azure/devops/pipelines/languages/java - -# Automatically triggered on PR -# https://docs.microsoft.com/en-us/azure/devops/pipelines/yaml-schema?view=azure-devops&tabs=schema%2Cparameter-schema#pr-trigger -trigger: - - main -pr: - - main - -pool: - vmImage: 'ubuntu-latest' - -variables: - MAVEN_CACHE_FOLDER: $(Pipeline.Workspace)/.m2/repository - MAVEN_OPTS: '-Dmaven.repo.local=$(MAVEN_CACHE_FOLDER)' - -steps: - - task: Cache@2 - inputs: - key: 'maven | "$(Agent.OS)" | pom.xml' - restoreKeys: | - maven | "$(Agent.OS)" - maven - path: $(MAVEN_CACHE_FOLDER) - displayName: Cache Maven local repo - - - task: SonarCloudPrepare@1 - displayName: 'Prepare SonarCloud analysis configuration' - inputs: - SonarCloud: '$(SONARCLOUD_SERVICE_CONN)' - organization: '$(SONARCLOUD_ORG)' - scannerMode: Other - extraProperties: | - sonar.projectKey=$(SONARCLOUD_PROJECT_KEY) - sonar.projectName=$(SONARCLOUD_PROJECT_NAME) - sonar.coverage.exclusions=**/config/*,**/*Mock*,**/model/**,**/entity/* - sonar.cpd.exclusions=**/model/**,**/entity/* - - - - task: Maven@3 - displayName: 'Run Junit Test' - inputs: - mavenPomFile: 'pom.xml' - mavenOptions: '-Xmx3072m $(MAVEN_OPTS)' - mavenVersionOption: 'Default' - mavenAuthenticateFeed: false - javaHomeOption: 'JDKVersion' - jdkVersionOption: '1.11' - publishJUnitResults: true - testResultsFiles: '**/surefire-reports/TEST-*.xml' - goals: 'clean verify' - sonarQubeRunAnalysis: true - codeCoverageToolOption: 'JaCoCo' - effectivePomSkip: false - isJacocoCoverageReportXML: true - sqMavenPluginVersionChoice: 'latest' - - - task: SonarCloudPublish@1 - displayName: 'Publish SonarCloud results on build summary' - inputs: - pollingTimeoutSec: '300' diff --git a/.devops/deploy-pipelines-standard.yml b/.devops/deploy-pipelines-standard.yml deleted file mode 100644 index e134ac589..000000000 --- a/.devops/deploy-pipelines-standard.yml +++ /dev/null @@ -1,298 +0,0 @@ -parameters: - - name: ENV - displayName: Target Environment - type: string - default: dev - values: - - dev - - uat - - prod - - name: SEMVER - displayName: "When packing a release, define the version bump to apply. Use only buildNumber or skip for manual deployment" - type: string - values: - - major - - minor - - patch - - buildNumber - - skip - default: skip - - name: TEST - displayName: Run tests - type: boolean - default: false - -variables: - ${{ if eq(parameters['ENV'], 'dev') }}: - AZURE_SUBSCRIPTION: $(DEV_AZURE_SUBSCRIPTION) - RESOURCE_GROUP: $(DEV_WEB_APP_RESOURCE_GROUP_NAME) - APP_NAME: $(DEV_WEB_APP_NAME) - STAGE: "d" - dockerRegistryServiceConnection: $(DEV_CONTAINER_REGISTRY) - dockerNamespace: $(DEV_CONTAINER_NAMESPACE) - - ${{ if eq(parameters['ENV'], 'uat') }}: - AZURE_SUBSCRIPTION: $(UAT_AZURE_SUBSCRIPTION) - RESOURCE_GROUP: $(UAT_WEB_APP_RESOURCE_GROUP_NAME) - APP_NAME: $(UAT_WEB_APP_NAME) - STAGE: "u" - dockerRegistryServiceConnection: $(UAT_CONTAINER_REGISTRY) - dockerNamespace: $(UAT_CONTAINER_NAMESPACE) - - ${{ if eq(parameters['ENV'], 'prod') }}: - AZURE_SUBSCRIPTION: $(PROD_AZURE_SUBSCRIPTION) - RESOURCE_GROUP: $(PROD_WEB_APP_RESOURCE_GROUP_NAME) - APP_NAME: $(PROD_WEB_APP_NAME) - STAGE: "p" - dockerRegistryServiceConnection: $(PROD_CONTAINER_REGISTRY) - dockerNamespace: $(PROD_CONTAINER_NAMESPACE) - - ${{ if eq(variables['Build.SourceBranchName'], 'merge') }}: - SOURCE_BRANCH: "main" # force to main branch - ${{ if ne(variables['Build.SourceBranchName'], 'merge') }}: - SOURCE_BRANCH: ${{ variables['Build.SourceBranchName'] }} - - - - MAVEN_CACHE_FOLDER: $(Pipeline.Workspace)/.m2/repository - MAVEN_OPTS: "-Dmaven.repo.local=$(MAVEN_CACHE_FOLDER)" - title: "" - sha: "" - tag: "" - -# Only manual triggers -trigger: none -pr: none - -pool: - vmImage: ubuntu-latest - -stages: - - # Create a release on GitHub - - stage: release_service - condition: ne('${{ parameters.SEMVER }}', 'skip') - pool: - vmImage: "ubuntu-latest" - jobs: - - job: releaseService - steps: - - checkout: self - clean: true - persistCredentials: true - - - script: | - git checkout $(SOURCE_BRANCH) - - - script: | - git config --global user.name "$(GIT_USERNAME)" - git config --global user.email "$(GIT_EMAIL)" - - - template: azure-templates/maven-versioning.yml - parameters: - semver: "${{ parameters.SEMVER }}" - - - task: Bash@3 - name: pomversion - inputs: - targetType: "inline" - script: | - version=$(mvn -f pom.xml help:evaluate -Dexpression=project.version -q -DforceStdout) - echo "##vso[task.setvariable variable=next;isOutput=true]$version" - failOnStderr: true - - - script: | - git add pom.xml - git commit -m "Bump version [skip ci]" - git push origin $(SOURCE_BRANCH) - - - - script: | - HEAD_SHA=$(git rev-parse HEAD) - TAG="$(pomversion.next)" - TITLE="Release $(pomversion.next)" - echo "##vso[task.setvariable variable=title]$TITLE" - echo "##vso[task.setvariable variable=sha]$HEAD_SHA" - echo "##vso[task.setvariable variable=tag]$TAG" - - - script: | - echo $(tag) - echo $(title) - echo $(sha) - - - # create new release - - task: GitHubRelease@0 - inputs: - gitHubConnection: $(GITHUB_CONNECTION) - repositoryName: $(Build.Repository.Name) - action: create - target: $(sha) - tagSource: manual - tag: $(tag) - title: $(title) - addChangelog: true - - # Deploy on Azure - - stage: deploy - condition: not(failed('releaseService')) - pool: - vmImage: "ubuntu-latest" - jobs: - - job: deployJava - steps: - - - script: | - echo ${{variables['Build.SourceBranchName']}} - echo $(SOURCE_BRANCH) - echo $(TEST) - - - checkout: self - clean: true - persistCredentials: true - submodules: true - - - script: | - echo "Checkout on $(SOURCE_BRANCH)" - git checkout $(SOURCE_BRANCH) - displayName: Checkout on source branch - - # - task: Bash@3 - # name: application_properties - # inputs: - # targetType: "inline" - # script: | - # cp src/main/resources/application-azure-$(STAGE).properties src/main/resources/application.properties - # cat src/main/resources/application.properties - # failOnStderr: true - - - task: Cache@2 - inputs: - key: 'maven | "$(Agent.OS)" | pom.xml' - restoreKeys: | - maven | "$(Agent.OS)" - maven - path: $(MAVEN_CACHE_FOLDER) - displayName: Set Maven Cache - - - task: Bash@3 - # When the maven task is installed, mvn can be used in a script - name: pomversion - inputs: - targetType: "inline" - script: | - version=$(mvn -f pom.xml help:evaluate -Dexpression=project.version -q -DforceStdout) - echo "##vso[task.setvariable variable=next;isOutput=true]$version" - failOnStderr: true - - - task: Maven@3 - inputs: - mavenPomFile: 'pom.xml' - publishJUnitResults: false - javaHomeOption: 'JDKVersion' - jdkVersionOption: '1.11' - mavenVersionOption: 'Default' - mavenOptions: '-Xmx3072m $(MAVEN_OPTS)' - mavenAuthenticateFeed: false - effectivePomSkip: false - sonarQubeRunAnalysis: false - - - task: Docker@2 - displayName: Build and push an image to container registry - inputs: - containerRegistry: '$(dockerRegistryServiceConnection)' - repository: '$(IMAGE_REPOSITORY)' - command: 'buildAndPush' - tags: | - $(Build.BuildId) - latest - $(pomversion.next) - - # deploy project-fn - - task: AzureFunctionAppContainer@1 - displayName: Deploy Function App [DEV] - inputs: - azureSubscription: $(AZURE_SUBSCRIPTION) - appName: "${{variables.DEV_WEB_APP_NAME}}-fn-project" - imageName: "${{variables.DEV_CONTAINER_NAMESPACE}}/project:$(Build.BuildId)" - slotName: production - - - script: | - echo "##vso[task.setvariable variable=version;isOutput=true]$(pomversion.next)" - name: dockerTag - - - # Run test - - stage: test - # run this stage only if 'test' is enabled - condition: and(not(failed('deployJava')), eq('${{ parameters.TEST }}', 'true')) - pool: - vmImage: "ubuntu-latest" - jobs: - # is needed to wait for startup of application - - job: waitStartup - pool: Server - steps: - - task: Delay@1 - inputs: - delayForMinutes: '10' - - # - job: integrationTests - # dependsOn: waitStartup - # steps: - # - script: | - # git checkout $(SOURCE_BRANCH) - - # - script: | - # yarn global add newman - # displayName: 'newman installation' - - # - script: | - # newman run api-test/Project.postman_collection.json --environment=api-test/Azure.postman_environment.json --reporters cli,junit --reporter-junit-export Results/api-config-TEST.xml --verbose - # displayName: 'Run api test' - # continueOnError: false - - # - task: PublishTestResults@2 - # condition: always() - # inputs: - # testResultsFormat: 'JUnit' - # testResultsFiles: '**/*-TEST.xml' - # searchFolder: '$(System.DefaultWorkingDirectory)' - - - job: deployUAT - dependsOn: integrationTests - variables: - version: $[ stageDependencies.deploy.deployJava.outputs['dockerTag.version'] ] - steps: - - task: Maven@3 - inputs: - mavenPomFile: 'pom.xml' - publishJUnitResults: false - javaHomeOption: 'JDKVersion' - jdkVersionOption: '1.11' - mavenVersionOption: 'Default' - mavenOptions: '-Xmx3072m $(MAVEN_OPTS)' - mavenAuthenticateFeed: false - effectivePomSkip: false - sonarQubeRunAnalysis: false - - - task: Docker@2 - displayName: Build and push an image to UAT container registry - inputs: - containerRegistry: '$(UAT_CONTAINER_REGISTRY)' - repository: '$(IMAGE_REPOSITORY)' - command: 'buildAndPush' - tags: | - $(Build.BuildId) - latest - $(version) - - # deploy project-fn - - task: AzureFunctionAppContainer@1 - displayName: Deploy Function App [UAT] - condition: in('${{ parameters.ENV }}', 'uat') - inputs: - azureSubscription: $(AZURE_SUBSCRIPTION) - appName: "${{variables.UAT_WEB_APP_NAME}}-fn-project}" - imageName: "${{variables.UAT_CONTAINER_NAMESPACE}}/project:$(Build.BuildId)" - slotName: production \ No newline at end of file diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 000000000..ec5ce6ea5 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,118 @@ +**/.dockerignore +**/.git +apps/onboarding-ms/.idea/.gitignore +**/bin +**/docker-compose* +**/Dockerfile* +**/node_modules +**/npm-debug.log +**/obj +**/secrets.dev.yaml +**/values.dev.yaml +LICENSE +README.md + +**/.idea +.idea +**/.mvn +.mvn + +**/target + +# Created by .ignore support plugin (hsz.mobi) +### Maven template +target/ +pom.xml.tag +pom.xml.releaseBackup +pom.xml.versionsBackup +pom.xml.next +release.properties +dependency-reduced-pom.xml +buildNumber.properties +.mvn/timing.properties +.mvn/wrapper/maven-wrapper.jar +### Java template +# Compiled class file +*.class + +# Log file +*.log + +# BlueJ files +*.ctxt + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +# Package Files # +*.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* +### JetBrains template +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/modules.xml +# .idea/*.iml +# .idea/modules + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests diff --git a/.github/labeler.yml b/.github/labeler.yml new file mode 100644 index 000000000..c8c2a7d4d --- /dev/null +++ b/.github/labeler.yml @@ -0,0 +1,16 @@ +functions: +- apps/onboarding-functions/** + +onboarding-ms: +- apps/onboarding-ms/** + +libs: +- libs/** + +ops: +- .github/** +- infra/** +- .identity/** + +docs: +- README.md \ No newline at end of file diff --git a/.github/workflows/assignee.yml b/.github/workflows/assignee.yml deleted file mode 100644 index 061191788..000000000 --- a/.github/workflows/assignee.yml +++ /dev/null @@ -1,26 +0,0 @@ -name: Auto Assign - -# Controls when the workflow will run -on: - # Triggers the workflow on push or pull request events but only for the main branch - pull_request_target: - branches: - - main - types: [ opened, reopened ] - - # Allows you to run this workflow manually from the Actions tab - workflow_dispatch: - -# A workflow run is made up of one or more jobs that can run sequentially or in parallel -jobs: - build: - # The type of runner that the job will run on - runs-on: ubuntu-latest - - # Steps represent a sequence of tasks that will be executed as part of the job - steps: - - name: Assign Me - # You may pin to the exact commit or the version. - uses: kentaro-m/auto-assign-action@v1.2.1 - with: - configuration-path: '.github/auto_assign.yml' diff --git a/.github/workflows/check_pr.yml b/.github/workflows/check_pr.yml new file mode 100644 index 000000000..f591e94d2 --- /dev/null +++ b/.github/workflows/check_pr.yml @@ -0,0 +1,56 @@ +name: Check PR + +# Controls when the workflow will run +on: + pull_request: + branches: + - develop + types: + - opened + - synchronize + - reopened + +permissions: + pull-requests: write + +# A workflow run is made up of one or more jobs that can run sequentially or in parallel +jobs: + + labeler: + name: Add label to PR based on the paths of files being changed + runs-on: ubuntu-latest + steps: + - uses: actions/labeler@ac9175f8a1f3625fd0d4fb234536d26811351594 # pin@v4 + + check_pr_size: + name: Check PR size doesn't break set limit + runs-on: ubuntu-latest + steps: + # checkout your code with your git history + - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # pin@v3 + with: + fetch-depth: 0 + + - name: Get total lines changed + run: | + size=$(git diff --stat origin/develop --diff-filter=d \ + | grep -v .lock \ + | awk -F"|" '{ print $2 }' \ + | awk '{ print $1 }' \ + | sed '/^$/d' \ + | paste -sd+ - \ + | bc) + + echo "size=${size}" >> $GITHUB_ENV + echo "" + echo "Total lines changed (note: *.lock files are excluded from this count): " + echo $size + shell: bash + - run: | + if [[ $size -gt 500 ]] + then + echo "Warning - total lines changed is greater than 500." + echo "Please consider breaking this PR down." + exit 1 + fi + shell: bash diff --git a/.github/workflows/code_review_functions.yml b/.github/workflows/code_review_functions.yml new file mode 100644 index 000000000..8eb910598 --- /dev/null +++ b/.github/workflows/code_review_functions.yml @@ -0,0 +1,45 @@ +name: Code Review onboarding-functions + +on: + pull_request: + branches: + - main + - develop + types: + - opened + - synchronize + - reopened + paths: + - 'apps/onboarding-functions/**' + + workflow_dispatch: + +jobs: + + code-review: + runs-on: ubuntu-latest + permissions: + packages: read + id-token: write + steps: + - name: Setup Maven Action + uses: s4u/setup-maven-action@fa2c7e4517ed008b1f73e7e0195a9eecf5582cd4 # pin@v1.11.0 + with: + checkout-fetch-depth: 0 + java-version: 17 + java-distribution: 'temurin' + maven-version: '3.9.5' + cache-enabled: true + + - name: Build and analyze on Pull Requests + shell: bash + run: mvn --projects :test-coverage --also-make verify -Ponboarding-functions,report,coverage + -Dsonar.organization=pagopa + -Dsonar.projectKey=pagopa_selfcare-onboarding + -Dsonar.token=${{ secrets.SONAR_TOKEN }} + -Dsonar.pullrequest.key=${{ github.event.pull_request.number }} + -Dsonar.pullrequest.branch=${{ github.head_ref }} + -Dsonar.pullrequest.base=refs/remotes/origin/${{ github.base_ref }} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} \ No newline at end of file diff --git a/.github/workflows/code_review_libs.yml b/.github/workflows/code_review_libs.yml new file mode 100644 index 000000000..898374161 --- /dev/null +++ b/.github/workflows/code_review_libs.yml @@ -0,0 +1,45 @@ +name: Code Review Libs + +on: + pull_request: + branches: + - main + - develop + types: + - opened + - synchronize + - reopened + paths: + - 'libs/**' + + workflow_dispatch: + +jobs: + + code-review: + runs-on: ubuntu-latest + permissions: + packages: read + id-token: write + steps: + - name: Setup Maven Action + uses: s4u/setup-maven-action@fa2c7e4517ed008b1f73e7e0195a9eecf5582cd4 # pin@v1.11.0 + with: + checkout-fetch-depth: 0 + java-version: 17 + java-distribution: 'temurin' + maven-version: '3.9.5' + cache-enabled: true + + - name: Build and analyze on Pull Requests + shell: bash + run: mvn --projects :test-coverage --also-make verify -Ponboarding-sdk,report,coverage + -Dsonar.organization=pagopa + -Dsonar.projectKey=pagopa_selfcare-onboarding + -Dsonar.token=${{ secrets.SONAR_TOKEN }} + -Dsonar.pullrequest.key=${{ github.event.pull_request.number }} + -Dsonar.pullrequest.branch=${{ github.head_ref }} + -Dsonar.pullrequest.base=refs/remotes/origin/${{ github.base_ref }} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} \ No newline at end of file diff --git a/.github/workflows/code_review_ms.yml b/.github/workflows/code_review_ms.yml new file mode 100644 index 000000000..ebe33e844 --- /dev/null +++ b/.github/workflows/code_review_ms.yml @@ -0,0 +1,47 @@ +name: Code Review onboarding-ms + +# Controls when the workflow will run +on: + pull_request: + branches: + - main + - develop + types: + - opened + - synchronize + - reopened + paths: + - 'apps/onboarding-ms/**' + + workflow_dispatch: + + +jobs: + + code-review: + runs-on: ubuntu-latest + permissions: + packages: read + id-token: write + steps: + - name: Setup Maven Action + uses: s4u/setup-maven-action@fa2c7e4517ed008b1f73e7e0195a9eecf5582cd4 # pin@v1.11.0 + with: + checkout-fetch-depth: 0 + java-version: 17 + java-distribution: 'temurin' + maven-version: '3.9.5' + cache-enabled: true + + - name: Build and analyze on Pull Requests + shell: bash + run: mvn --projects :test-coverage --also-make verify -Ponboarding-ms,report,coverage + -Dsonar.organization=pagopa + -Dsonar.projectKey=pagopa_selfcare-onboarding + -Dsonar.token=${{ secrets.SONAR_TOKEN }} + -Dsonar.pullrequest.key=${{ github.event.pull_request.number }} + -Dsonar.pullrequest.branch=${{ github.head_ref }} + -Dsonar.pullrequest.base=refs/remotes/origin/${{ github.base_ref }} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} \ No newline at end of file diff --git a/.github/workflows/code_review_onboarding_ms.yml b/.github/workflows/code_review_onboarding_ms.yml deleted file mode 100644 index 5349ddfc4..000000000 --- a/.github/workflows/code_review_onboarding_ms.yml +++ /dev/null @@ -1,42 +0,0 @@ -name: Code Review onboarding-ms - -# Controls when the workflow will run -on: - pull_request: - branches: - - main - - develop - types: - - opened - - synchronize - - reopened - paths: - - 'onboarding-ms/**' - - # Allows you to run this workflow manually from the Actions tab - workflow_dispatch: - -permissions: - id-token: write - contents: read - deployments: write - -# A workflow run is made up of one or more jobs that can run sequentially or in parallel -jobs: - code-review: - name: Code Review Onboarding-ms - # The type of runner that the job will run on - runs-on: ubuntu-latest - - # Steps represent a sequence of tasks that will be executed as part of the job - steps: - - uses: actions/checkout@v4 - - - name: Set up JDK 17 - uses: actions/setup-java@v3 - with: - java-version: 17 - distribution: 'temurin' - - - name: Launch unit test with Maven - run: mvn test --file onboarding-ms/pom.xml \ No newline at end of file diff --git a/.github/workflows/deploy_onboarding_functions.yml b/.github/workflows/deploy_onboarding_functions.yml new file mode 100644 index 000000000..7abc6dcb9 --- /dev/null +++ b/.github/workflows/deploy_onboarding_functions.yml @@ -0,0 +1,70 @@ +name: Deploy onboarding functions + +on: + pull_request: + branches: + - develop + - main + types: [closed] + paths: + - "apps/onboarding-functions/**" + - "apps/pom.xml" + + workflow_dispatch: + inputs: + environment: + required: true + type: choice + description: Select the Environment + options: + - dev + - uat + - prod + +env: + ENV_NAME: "${{ inputs.environment != null && inputs.environment || (github.base_ref == 'main' && 'prod' || (github.base_ref == 'develop' && 'uat' || 'dev')) }}" + +jobs: + build: + name: Build Onboarding Functions + runs-on: ubuntu-latest + if: ${{ (github.event_name == 'workflow_dispatch' || github.event.pull_request.merged == true) }} + environment: "${{ inputs.environment != null && inputs.environment || (github.base_ref == 'main' && 'prod' || (github.base_ref == 'develop' && 'uat' || 'dev')) }}-cd" + permissions: + packages: write + contents: write + id-token: write + + steps: + - name: Setup Maven Action + uses: s4u/setup-maven-action@fa2c7e4517ed008b1f73e7e0195a9eecf5582cd4 # pin@v1.11.0 + with: + checkout-fetch-depth: 0 + checkout-ref: ${{ github.ref_name }} + java-version: 17 + java-distribution: 'temurin' + maven-version: '3.9.5' + cache-enabled: true + + - name: "Build Functions and dependencies" + shell: bash + run: mvn --projects :onboarding-functions --also-make package install -DskipTests + -Dquarkus.azure-functions.app-name=${{ vars.AZURE_ONBOARDING_FN_APP_NAME }} + + - name: Log in to Azure + uses: azure/login@92a5484dfaf04ca78a94597f4f19fea633851fa2 + with: + client-id: ${{ secrets.AZURE_CLIENT_ID_CD }} + tenant-id: ${{ secrets.AZURE_TENANT_ID }} + subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} + + - name: "Deploy Functions" + shell: bash + run: mvn -f apps/onboarding-functions/pom.xml quarkus:deploy + -Dquarkus.azure-functions.app-name=${{ vars.AZURE_ONBOARDING_FN_APP_NAME }} + -Dquarkus.azure-functions.subscription-id=${{ secrets.AZURE_SUBSCRIPTION_ID }} + -Dquarkus.azure-functions.resource-group=${{ vars.AZURE_ONBOARDING_FN_RESOURCE_GROUP }} + -Dquarkus.azure-functions.region=westeurope + -Dquarkus.azure-functions.app-service-plan-name=${{ vars.AZURE_ONBOARDING_FN_SERVICE_PLAN }} + -Dquarkus.azure-functions.runtime.java-version=17 + diff --git a/.github/workflows/deploy_onboarding_ms.yml b/.github/workflows/deploy_onboarding_ms.yml index 8af63b216..29798f37f 100644 --- a/.github/workflows/deploy_onboarding_ms.yml +++ b/.github/workflows/deploy_onboarding_ms.yml @@ -1,15 +1,15 @@ -name: Deploy onboarding-ms +name: Deploy onboarding ms -# Controls when the workflow will run on: pull_request: branches: - develop - types: [ closed ] + - main + types: [closed] paths: - - 'onboarding-ms/**' + - "apps/onboarding-ms/**" + - "apps/pom.xml" - # Allows you to run this workflow manually from the Actions tab workflow_dispatch: inputs: environment: @@ -21,64 +21,53 @@ on: - uat - prod -permissions: - packages: write - contents: write - issues: write - id-token: write - deployments: write +env: + DIR: "./infra/container_apps/onboarding-ms" + # This condition (that unfortunately must be replicated for the first job) + # sets the environment depending on the current context for manually + # started workflows, it picks up the value coming from the UI; otherwise, + # it sets prod or uat depending on the current branch. + # Ternary operator is not supported + ENV_NAME: "${{ inputs.environment != null && inputs.environment || (github.base_ref == 'main' && 'prod' || (github.base_ref == 'develop' && 'uat' || 'dev')) }}" -# A workflow run is made up of one or more jobs that can run sequentially or in parallel jobs: - setup: - name: Setup - # The type of runner that the job will run on + build: + name: Build Onboarding Microservice runs-on: ubuntu-latest + if: ${{ (github.event_name == 'workflow_dispatch' || github.event.pull_request.merged == true) }} + environment: "${{ inputs.environment != null && inputs.environment || (github.base_ref == 'main' && 'prod' || (github.base_ref == 'develop' && 'uat' || 'dev')) }}-ci" outputs: - environment: ${{ steps.setvars.outputs.environment }} + environment: ${{ steps.setenv.outputs.environment }} + short_sha: ${{ steps.setsha.outputs.short_sha }} + permissions: + packages: write + contents: write + id-token: write - # Steps represent a sequence of tasks that will be executed as part of the job - steps: - - name: pull request rejected - if: github.event_name == 'pull_request' && github.event.action == 'closed' && github.event.pull_request.merged != true - run: | - echo "❌ PR was closed without a merge" - exit 1 - - - name: Set variables - id: setvars - run: | - if [[ "${{inputs.environment}}" != null ]] - then - echo "environment=${{inputs.environment}}" >> $GITHUB_OUTPUT - - else - if [[ "${{github.base_ref}}" == "master" || "${{github.ref}}" == "refs/heads/master" ]]; then - echo "environment=prod" >> $GITHUB_OUTPUT - fi - - if [[ "${{github.base_ref}}" == "develop" || "${{github.ref}}" == "refs/heads/develop" ]]; then - echo "environment=dev" >> $GITHUB_OUTPUT - fi - fi - - image: - needs: [ setup ] - name: Build and Push Docker Image - runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 + name: Checkout with: ref: ${{ github.ref_name }} - - name: Set up JDK 17 - uses: actions/setup-java@v3 - with: - java-version: 17 - distribution: 'temurin' + # this workaround is necessary to pass the environment value to the next job + # unexpectly, global env vars cannot be read to set the environment and I don't + # want to repeat that complex expression (already repeated twice) + - name: Read Environment + id: setenv + shell: bash + run: | + echo "environment=$ENV_NAME" >> $GITHUB_OUTPUT - - name: Build project with Maven - run: mvn -B package --file onboarding-ms/pom.xml + # github doesn't provide a short sha anymore + - name: Set Short Git Commit SHA + id: setsha + run: | + calculatedSha=$(git rev-parse --short ${{ github.sha }}) + echo "short_sha=sha-$calculatedSha" >> $GITHUB_OUTPUT + + - name: Setup Docker buildx + uses: docker/setup-buildx-action@v3.0.0 - name: Login to GitHub Container Registry uses: docker/login-action@v3 @@ -87,99 +76,111 @@ jobs: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - - name: Docker meta + - name: Docker Meta id: meta uses: docker/metadata-action@v4.3.0 with: images: ghcr.io/${{ github.repository }}-ms tags: | - latest + type=raw,value=latest,enable={{is_default_branch}} type=ref,event=branch type=sha - - - name: Build and push + labels: + org.opencontainers.image.title=${{ github.repository }}-ms + org.opencontainers.image.description=SelfCare onboarding microservice + org.opencontainers.image.authors=PagoPA + org.opencontainers.image.url=github.com/pagopa/${{ github.repository }} + org.opencontainers.image.source=https://github.com/${{ github.repository }} + + - name: Build and Push Image uses: docker/build-push-action@v5 with: - context: ./onboarding-ms - file: ./onboarding-ms/src/main/docker/Dockerfile.jvm + context: . + file: ./apps/onboarding-ms/Dockerfile push: true tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} secrets: | GH_TOKEN=${{ secrets.READ_PACKAGES_TOKEN }} + cache-from: type=gha + cache-to: type=gha,mode=min - deploy: - name: Deploy to container app - runs-on: ubuntu-latest - needs: [setup,image] - if: "${{needs.setup.outputs.environment != 'dev'}}" - environment: ${{needs.setup.outputs.environment}} - - env: - YAML_FILE_PATH: '${{ github.workspace }}/onboarding-ms/deploy-image-container-app.yaml' - - steps: - # Log in to Azure CLI - - name: Log in to Azure - uses: azure/login@v1 - with: - client-id: ${{ secrets.CLIENT_ID }} - tenant-id: ${{ secrets.TENANT_ID }} - subscription-id: ${{ secrets.SUBSCRIPTION_ID }} - - - name: Update values in YAML configuration file - shell: pwsh + - name: Set Terraform Version + id: set-terraform-version run: | - (Get-Content ${{ env.YAML_FILE_PATH }}).Replace('$SUBSCRIPTION_ID$', '${{ secrets.SUBSCRIPTION_ID }}') | Set-Content ${{ env.YAML_FILE_PATH }} - (Get-Content ${{ env.YAML_FILE_PATH }}).Replace('$RESOURCE_GROUP$', '${{ vars.CONTAINER_APP_SELC_ENVIRONMENT_RESOURCE_GROUP_NAME }}') | Set-Content ${{ env.YAML_FILE_PATH }} - (Get-Content ${{ env.YAML_FILE_PATH }}).Replace('$CONTAINER_APP_ENV$', '${{ vars.CONTAINER_APP_SELC_ENVIRONMENT_NAME }}') | Set-Content ${{ env.YAML_FILE_PATH }} - (Get-Content ${{ env.YAML_FILE_PATH }}).Replace('$JWT_PUBLIC_KEY$', '${{ secrets.JWT_PUBLIC_KEY }}') | Set-Content ${{ env.YAML_FILE_PATH }} + echo "terraform_version=$(cat .terraform-version)" >> $GITHUB_OUTPUT + - uses: hashicorp/setup-terraform@v2 + name: Setup Terraform + with: + terraform_version: ${{ steps.set-terraform-version.outputs.terraform_version}} - # Build and deploy the container app - - name: Build and deploy Container App - uses: azure/container-apps-deploy-action@v1 + - name: Terraform Plan + uses: pagopa/terraform-preapply-azure-action@54ded8cda3437c3f6a9f46baf69cb321ce82f5cd + with: + client_id: ${{ secrets.AZURE_CLIENT_ID_CI }} + tenant_id: ${{ secrets.AZURE_TENANT_ID }} + subscription_id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} + dir: ${{ env.DIR }} + azure_environment: ${{ steps.setenv.outputs.environment }} + env: + TF_VAR_image_tag: ${{ steps.setsha.outputs.short_sha }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: "Upload Terraform Plan as Artifact" + uses: actions/upload-artifact@v3 with: - containerAppName: selc-onboarding-ms - containerAppEnvironment: ${{ vars.CONTAINER_APP_SELC_ENVIRONMENT_NAME }} - resourceGroup: ${{ vars.CONTAINER_APP_SELC_ENVIRONMENT_RESOURCE_GROUP_NAME }} - yamlConfigPath: ${{ env.YAML_FILE_PATH }} + name: tfplan + path: ${{ env.DIR }}/tfplan-${{ steps.setenv.outputs.environment }}-${{ github.sha }} + if-no-files-found: error + retention-days: 1 - deploy_dev: - name: Deploy to container app DEV + deploy: + name: Deploy microservice runs-on: ubuntu-latest - needs: [setup,image] - if: "${{needs.setup.outputs.environment == 'uat'}}" - environment: dev - - env: - YAML_FILE_PATH: '${{ github.workspace }}/onboarding-ms/deploy-image-container-app.yaml' + needs: [build] + environment: ${{ needs.build.outputs.environment }}-cd + permissions: + id-token: write steps: - # Log in to Azure CLI - - name: Log in to Azure - uses: azure/login@v1 + - uses: actions/checkout@v4 + name: Checkout with: - client-id: ${{ secrets.CLIENT_ID }} - tenant-id: ${{ secrets.TENANT_ID }} - subscription-id: ${{ secrets.SUBSCRIPTION_ID }} + ref: ${{ github.ref_name }} - - name: Update values in YAML configuration file - shell: pwsh - run: | - (Get-Content ${{ env.YAML_FILE_PATH }}).Replace('$SUBSCRIPTION_ID$', '${{ secrets.SUBSCRIPTION_ID }}') | Set-Content ${{ env.YAML_FILE_PATH }} - (Get-Content ${{ env.YAML_FILE_PATH }}).Replace('$RESOURCE_GROUP$', '${{ vars.CONTAINER_APP_SELC_ENVIRONMENT_RESOURCE_GROUP_NAME }}') | Set-Content ${{ env.YAML_FILE_PATH }} - (Get-Content ${{ env.YAML_FILE_PATH }}).Replace('$CONTAINER_APP_ENV$', '${{ vars.CONTAINER_APP_SELC_ENVIRONMENT_NAME }}') | Set-Content ${{ env.YAML_FILE_PATH }} - (Get-Content ${{ env.YAML_FILE_PATH }}).Replace('$JWT_PUBLIC_KEY$', '${{ secrets.JWT_PUBLIC_KEY }}') | Set-Content ${{ env.YAML_FILE_PATH }} - (Get-Content ${{ env.YAML_FILE_PATH }}).Replace('$MONGODB_CONNECTION_URI$', '${{ secrets.MONGODB_CONNECTION_URI }}') | Set-Content ${{ env.YAML_FILE_PATH }} + - name: Download Terraform Plan as Artifact + uses: actions/download-artifact@v3 + with: + name: tfplan + path: ${{ env.DIR }} + - name: Retrieve Terraform Modules from Cache + id: cache-terraform-modules + uses: actions/cache@6fd2d4538ca777f67fccddb233cf1a8ff1339012 + with: + path: ${{ env.DIR }}/.terraform + key: terraform-${{ env.DIR }}-${{ github.sha }} + restore-keys: | + terraform-${{ env.DIR }} - # Build and deploy the container app - - name: Build and deploy Container App - uses: azure/container-apps-deploy-action@v1 + - name: Set Terraform Version + id: set-terraform-version + run: | + echo "terraform_version=$(cat .terraform-version)" >> $GITHUB_OUTPUT + + - uses: hashicorp/setup-terraform@v2 + name: Setup Terraform with: - containerAppName: selc-onboarding-ms - containerAppEnvironment: ${{ vars.CONTAINER_APP_SELC_ENVIRONMENT_NAME }} - resourceGroup: ${{ vars.CONTAINER_APP_SELC_ENVIRONMENT_RESOURCE_GROUP_NAME }} - yamlConfigPath: ${{ env.YAML_FILE_PATH }} + terraform_version: ${{ steps.set-terraform-version.outputs.terraform_version}} + - name: Terraform Apply + uses: pagopa/terraform-apply-azure-action@87efc4aa9b093b99ae5fd1915977e29cd80861ab + with: + client_id: ${{ secrets.AZURE_CLIENT_ID_CD }} + tenant_id: ${{ secrets.AZURE_TENANT_ID }} + subscription_id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} + dir: ${{ env.DIR }} + azure_environment: ${{ needs.build.outputs.environment }} + env: + TF_VAR_image_tag: ${{ needs.build.outputs.short_sha }} diff --git a/.github/workflows/release_onboarding_sdk.yml b/.github/workflows/release_onboarding_sdk.yml new file mode 100644 index 000000000..d95570a53 --- /dev/null +++ b/.github/workflows/release_onboarding_sdk.yml @@ -0,0 +1,38 @@ +name: Release onboarding sdk + +on: + workflow_dispatch: + + +jobs: + setup: + name: Release + runs-on: ubuntu-latest + permissions: + packages: write + steps: + - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # pin@v3 + with: + ref: ${{ github.ref_name }} + + - name: Set up JDK 17 + uses: actions/setup-java@0ab4596768b603586c0de567f2430c30f5b0d2b0 # pin@v3 + with: + distribution: 'temurin' + java-version: '17' + cache: maven + + - uses: s4u/maven-settings-action@60912582505985be4cc55d2b890eb32767f8de5f # pin@v2.8.0 + with: + servers: '[{"id": "selfcare-github", "username": "${{ github.actor }}", "password": "${{ secrets.GITHUB_TOKEN }}"}]' + + - name: Build with Maven + run: mvn --projects :onboarding-libs --also-make-dependents clean package -DskipTests + shell: bash + + - name: Deploy to GitHub Package Registry + run: | + mvn -B deploy -f libs/pom.xml + shell: bash + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file diff --git a/.identity/env/dev/terraform.tfvars b/.identity/env/dev/terraform.tfvars index d3559fcec..58a56578e 100644 --- a/.identity/env/dev/terraform.tfvars +++ b/.identity/env/dev/terraform.tfvars @@ -27,16 +27,22 @@ cd_github_federations = [ ] environment_ci_roles = { - subscription = ["Reader"] + subscription = [ + "Reader", + "Key Vault Secrets User" + ] resource_groups = { "terraform-state-rg" = [ - "Storage Blob Data Reader" + "Storage Blob Data Contributor" ] } } environment_cd_roles = { - subscription = ["Reader"] + subscription = [ + "Reader", + "Contributor" + ] resource_groups = { "terraform-state-rg" = [ "Storage Blob Data Contributor" @@ -50,7 +56,7 @@ github_repository_environment_ci = { } github_repository_environment_cd = { - protected_branches = true + protected_branches = false custom_branch_policies = false reviewers_teams = ["selfcare-contributors"] } diff --git a/.identity/env/prod/terraform.tfvars b/.identity/env/prod/terraform.tfvars index 445664ab1..ee46633dd 100644 --- a/.identity/env/prod/terraform.tfvars +++ b/.identity/env/prod/terraform.tfvars @@ -27,16 +27,22 @@ cd_github_federations = [ ] environment_ci_roles = { - subscription = ["Reader"] + subscription = [ + "Reader", + "Key Vault Secrets User" + ] resource_groups = { "terraform-state-rg" = [ - "Storage Blob Data Reader" + "Storage Blob Data Contributor" ] } } environment_cd_roles = { - subscription = ["Reader"] + subscription = [ + "Reader", + "Contributor" + ] resource_groups = { "terraform-state-rg" = [ "Storage Blob Data Contributor" diff --git a/.identity/env/uat/terraform.tfvars b/.identity/env/uat/terraform.tfvars index 3af2c803a..c96743206 100644 --- a/.identity/env/uat/terraform.tfvars +++ b/.identity/env/uat/terraform.tfvars @@ -27,16 +27,22 @@ cd_github_federations = [ ] environment_ci_roles = { - subscription = ["Reader"] + subscription = [ + "Reader", + "Key Vault Secrets User" + ] resource_groups = { "terraform-state-rg" = [ - "Storage Blob Data Reader" + "Storage Blob Data Contributor" ] } } environment_cd_roles = { - subscription = ["Reader"] + subscription = [ + "Reader", + "Contributor" + ] resource_groups = { "terraform-state-rg" = [ "Storage Blob Data Contributor" diff --git a/.identity/github_environment_cd.tf b/.identity/github_environment_cd.tf index ee2efe7c3..96869a71d 100644 --- a/.identity/github_environment_cd.tf +++ b/.identity/github_environment_cd.tf @@ -12,9 +12,13 @@ resource "github_repository_environment" "github_repository_environment_cd" { ) } } - deployment_branch_policy { - protected_branches = var.github_repository_environment_cd.protected_branches - custom_branch_policies = var.github_repository_environment_cd.custom_branch_policies + + dynamic "deployment_branch_policy" { + for_each = var.github_repository_environment_cd.protected_branches ? [1] : [] + content { + protected_branches = var.github_repository_environment_cd.protected_branches + custom_branch_policies = var.github_repository_environment_cd.custom_branch_policies + } } } diff --git a/.identity/github_managed_identity_ci.tf b/.identity/github_managed_identity_ci.tf index e1e0d0684..13f4fcc90 100644 --- a/.identity/github_managed_identity_ci.tf +++ b/.identity/github_managed_identity_ci.tf @@ -15,4 +15,20 @@ module "identity_ci" { } tags = var.tags +} + +resource "azurerm_key_vault_access_policy" "github_identity_ci_policy" { + key_vault_id = data.azurerm_key_vault.key_vault.id + tenant_id = data.azurerm_client_config.current.tenant_id + object_id = module.identity_ci.identity_principal_id + + secret_permissions = [ + "Get", + "List", + ] + + certificate_permissions = [ + "Get", + "List" + ] } \ No newline at end of file diff --git a/.java-version b/.java-version deleted file mode 100644 index b4de39476..000000000 --- a/.java-version +++ /dev/null @@ -1 +0,0 @@ -11 diff --git a/CODEOWNERS b/CODEOWNERS index 04a422742..3e6a4b0ff 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -1,3 +1,10 @@ # see https://help.github.com/en/articles/about-code-owners#example-of-a-codeowners-file +# Default owner * @pagopa/selfcare-contributors + +# Code owner for the applications +/apps/onboarding-ms/* @pagopa/selfcare-contributors +/apps/onboarding-functions/* @pagopa/selfcare-contributors + + diff --git a/README.md b/README.md index b8611da43..7630899e9 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,59 @@ # Selfcare Onboarding -Repository that contains backend services for selfcare onboarding. +This repo structure and build monorepo with Apache Maven for selfcare onboarding domain. + +Applications under apps/ depend on shared code under libs/. test-coverage/ is used to assess the test coverage of the entire project. + + +``` +. + +├── apps +│   ├── onboarding-functions +│   └── onboarding-ms +└── libs +    ├── onboarding-sdk-pom +    ├── onboarding-sdk-common +    ├── onboarding-sdk-azure-storage +    ├── onboarding-sdk-product +    ├── onboarding-sdk-crypto +└── test-coverage +``` + +Look at single README module for more information. + +## Infrastructure + +The [`.infra/`] sub folder contains terraform files for deploying infrastructure such as container apps or functions in Azure. + + +## Continous integration + +The [`.github/`] sub folder contains a self-contained ci-stack for building the monorepo with Github Actions. + +## Usage + +```shell script +mvn clean package install +``` + +## Maven basic actions for monorep + +Maven is really not a monorepo-*native* build tool (e.g. lacks +trustworthy incremental builds, can only build java code natively, is recursive and +struggles with partial repo checkouts) but can be made good use of with some tricks +and usage of a couple of lesser known command line switches. + +| Action | in working directory | with Maven | +|:---------------------------------------------------------------------------------------------------|:----------------------:|:-----------------------------------------------------------------------------------| +| Build the world | `.` | `mvn clean package -DskipTests` | +| Run `onboarding-ms` | `.` | `java -jar apps/onboarding-ms/target/onboarding-ms-1.0.0-SNAPSHOT.jar` | +| Build and test the world | `.` | `mvn clean package` | +| Build the world | `./apps/onboarding-ms` | `mvn --file ../.. clean package -DskipTests` | +| Build `onboarding-ms` and its dependencies | `.` | `mvn --projects :onboarding-ms --also-make clean package -DskipTests` | +| Build `onboarding-ms` and its dependencies | `./apps/onboarding-ms` | `mvn --file ../.. --projects :onboarding-ms --also-make clean package -DskipTests` | +| Build `onboarding-sdk` and its dependents (aka. reverse dependencies or *rdeps* in Bazel parlance) | `.` | `mvn --projects :onboarding-sdk-pom --also-make-dependents clean package -DskipTests` | +| Print dependencies of `onboarding-sdk` | `./apps/onboarding-ms` | `mvn dependency:list` | +| Change version of `onboarding-sdk` | `.` | `mvn versions:set -DnewVersion=0.1.2 --projects :onboarding-sdk-pom ` | +| Persist version of `onboarding-sdk` | `.` | `mvn versions:commit ` | + diff --git a/onboarding-functions/.gitignore b/apps/onboarding-functions/.gitignore similarity index 100% rename from onboarding-functions/.gitignore rename to apps/onboarding-functions/.gitignore diff --git a/apps/onboarding-functions/README.md b/apps/onboarding-functions/README.md new file mode 100644 index 000000000..fa1abdfbd --- /dev/null +++ b/apps/onboarding-functions/README.md @@ -0,0 +1,89 @@ +# Onboarding Functions + +Repository that contains Azure functions designed for onboarding asynchronous flow activities. +These functions handle all asynchronous activities related to preparing and completing the onboarding process. Indeed, they are activated by the onboarding microservice upon receiving an onboarding request. + +1. StartOnboardingOrchestration: + +It is triggered by http request at GET or POST `/api/StartOnboardingOrchestration?onboardingId={onboardingId}` where onboardingId is a reference to onboarding which you want to process. + +### Contract Signature + +You can enable the signature inside contracts when there are builded setting PAGOPA_SIGNATURE_SOURCE env (default value is `disabled`) as `local` if you want to use Pkcs7HashSignService or `aruba` for ArubaPkcs7HashSignService. Look at this [README](https://github.com/pagopa/selfcare-onboarding/tree/develop/libs/onboarding-sdk-crypto#readme) for more informations. + + +## Running locally + + +### Install the Azure Functions Core Tools + +Follow this [guide](https://learn.microsoft.com/en-us/azure/azure-functions/functions-run-local?tabs=macos%2Cisolated-process%2Cnode-v4%2Cpython-v2%2Chttp-trigger%2Ccontainer-apps&pivots=programming-language-java) for recommended way to install Core Tools on the operating system of your local development computer. + +### Configuration Properties + +Before running you must set these properties as environment variables. + + +| **Property** | **Environment Variable** | **Default** | **Required** | +|------------------------------------------------------------------------|----------------------------|-------------|:------------:| +| quarkus.mongodb.connection-string
| MONGODB_CONNECTION_URI | | yes | +| quarkus.openapi-generator.user_registry_json.auth.api_key.api-key
| USER_REGISTRY_API_KEY | | yes | +| quarkus.rest-client."*.user_registry_json.api.UserApi".url
| USER_REGISTRY_URL | | yes | + +### Storage emulator: Azurite + +Use the Azurite emulator for local Azure Storage development. Once installed, you must create `selc-d-contracts-blob` and `selc-d-product` container. Inside last one you have to put products.json file. + +([guide](https://learn.microsoft.com/en-us/azure/storage/common/storage-use-azurite?tabs=visual-studio)) + +### Install dependencies + +At project root you must install dependencies: + +```shell script +./mvnw install +``` + +### Packaging + +The application can be packaged using: +```shell script +./mvnw package +``` + +It produces the `onboarding-functions-1.0.0-SNAPSHOT.jar` file in the `target/` directory. + +### Start application + +```shell script +./mvnw package quarkus:run +``` + +If you want enable debugging you must add -DenableDebug + +```shell script +./mvnw quarkus:run -DenableDebug +``` +You can follow this guide for debugging application in IntelliJ https://www.jetbrains.com/help/idea/tutorial-remote-debug.html + +## Deploy + +### Configuration Properties + +Before deploy you must set these properties as environment variables. + + +| **Property** | **Environment Variable** | **Default** | **Required** | +|----------------------------------------------------|------------------------------|-------------|:------------:| +| quarkus.azure-functions.app-name
| AZURE_APP_NAME | | no | +| quarkus.azure-functions.subscription-id
| AZURE_SUBSCRIPTION_ID | | no | +| quarkus.azure-functions.resource-group
| AZURE_RESOURCE_GROUP | | no | +| quarkus.azure-functions.app-insights-key
| AZURE_APP_INSIGHTS_KEY | | no | +| quarkus.azure-functions.app-service-plan-name
| AZURE_APP_SERVICE_PLAN_NAME | | no | + + +## Related Guides + +- Azure Functions ([guide](https://quarkus.io/guides/azure-functions)): Write Microsoft Azure functions + + diff --git a/apps/onboarding-functions/host.json b/apps/onboarding-functions/host.json new file mode 100644 index 000000000..c0dfb483d --- /dev/null +++ b/apps/onboarding-functions/host.json @@ -0,0 +1,18 @@ +{ + "version": "2.0", + "logging": { + "logLevel": { + "DurableTask.AzureStorage": "Warning", + "DurableTask.Core": "Warning" + } + }, + "extensions": { + "durableTask": { + "hubName": "JavaTestHub" + } + }, + "extensionBundle": { + "id": "Microsoft.Azure.Functions.ExtensionBundle", + "version": "[4.*, 4.8.1)" + } +} diff --git a/apps/onboarding-functions/pom.xml b/apps/onboarding-functions/pom.xml new file mode 100644 index 000000000..5d08e4b8f --- /dev/null +++ b/apps/onboarding-functions/pom.xml @@ -0,0 +1,241 @@ + + + 4.0.0 + + it.pagopa.selfcare + onboarding-apps + 0.0.1 + + + onboarding-functions + 1.0.0-SNAPSHOT + + + 3.11.0 + 17 + UTF-8 + UTF-8 + quarkus-bom + io.quarkus.platform + 3.5.1 + true + 3.1.2 + 0.1.3 + 1.5.5.Final + + + + + + ${quarkus.platform.group-id} + ${quarkus.platform.artifact-id} + ${quarkus.platform.version} + pom + import + + + + + + io.quarkus + quarkus-azure-functions + + + io.quarkus + quarkus-arc + + + com.microsoft.azure.functions + azure-functions-java-library + + + com.microsoft + durabletask-azure-functions + 1.4.0 + + + io.quarkus + quarkus-mongodb-panache + + + com.fasterxml.jackson.core + jackson-databind + + + io.quarkus + quarkus-mailer + + + it.pagopa.selfcare + onboarding-sdk-azure-storage + ${onboarding-sdk.version} + + + it.pagopa.selfcare + onboarding-sdk-product + ${onboarding-sdk.version} + + + it.pagopa.selfcare + onboarding-sdk-common + ${onboarding-sdk.version} + + + it.pagopa.selfcare + onboarding-sdk-crypto + ${onboarding-sdk.version} + + + org.apache.commons + commons-text + compile + + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + + + io.quarkus + quarkus-resteasy-multipart + + + io.quarkus + quarkus-rest-client-jackson + + + io.quarkus + quarkus-resteasy-jackson + + + + + com.openhtmltopdf + openhtmltopdf-core + 1.0.10 + + + + org.mapstruct + mapstruct + ${mapstruct.version} + + + + com.openhtmltopdf + openhtmltopdf-pdfbox + 1.0.10 + + + + com.openhtmltopdf + openhtmltopdf-svg-support + 1.0.10 + + + xalan + serializer + + + xalan + xalan + + + + + + org.jsoup + jsoup + 1.16.1 + + + + + com.openhtmltopdf + openhtmltopdf-slf4j + 1.0.10 + + + org.digidoc4j.dss + dss-document + 5.11.1.d4j.1 + + + io.quarkiverse.openapi.generator + quarkus-openapi-generator + 2.2.10 + + + + + io.quarkus + quarkus-junit5 + test + + + io.quarkus + quarkus-junit5-mockito + test + + + io.rest-assured + rest-assured + test + + + org.mockito + mockito-core + test + + + io.quarkus + quarkus-jacoco + test + + + + + + ${quarkus.platform.group-id} + quarkus-maven-plugin + ${quarkus.platform.version} + true + + + + build + generate-code + generate-code-tests + + + + + + maven-compiler-plugin + ${compiler-plugin.version} + + + -parameters + + + + org.mapstruct + mapstruct-processor + ${mapstruct.version} + + + + + + maven-surefire-plugin + ${surefire-plugin.version} + + + org.jboss.logmanager.LogManager + ${maven.home} + + + + + + diff --git a/onboarding-functions/src/integrationTest/java/org/acme/FunctionIT.java b/apps/onboarding-functions/src/integrationTest/java/org/acme/FunctionIT.java similarity index 100% rename from onboarding-functions/src/integrationTest/java/org/acme/FunctionIT.java rename to apps/onboarding-functions/src/integrationTest/java/org/acme/FunctionIT.java diff --git a/onboarding-functions/src/main/docker/Dockerfile.jvm b/apps/onboarding-functions/src/main/docker/Dockerfile.jvm similarity index 100% rename from onboarding-functions/src/main/docker/Dockerfile.jvm rename to apps/onboarding-functions/src/main/docker/Dockerfile.jvm diff --git a/onboarding-functions/src/main/docker/Dockerfile.legacy-jar b/apps/onboarding-functions/src/main/docker/Dockerfile.legacy-jar similarity index 100% rename from onboarding-functions/src/main/docker/Dockerfile.legacy-jar rename to apps/onboarding-functions/src/main/docker/Dockerfile.legacy-jar diff --git a/onboarding-functions/src/main/docker/Dockerfile.native b/apps/onboarding-functions/src/main/docker/Dockerfile.native similarity index 100% rename from onboarding-functions/src/main/docker/Dockerfile.native rename to apps/onboarding-functions/src/main/docker/Dockerfile.native diff --git a/onboarding-functions/src/main/docker/Dockerfile.native-micro b/apps/onboarding-functions/src/main/docker/Dockerfile.native-micro similarity index 100% rename from onboarding-functions/src/main/docker/Dockerfile.native-micro rename to apps/onboarding-functions/src/main/docker/Dockerfile.native-micro diff --git a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/client/auth/AuthenticationPropagationHeadersFactory.java b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/client/auth/AuthenticationPropagationHeadersFactory.java new file mode 100644 index 000000000..de8d1ca77 --- /dev/null +++ b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/client/auth/AuthenticationPropagationHeadersFactory.java @@ -0,0 +1,16 @@ +package it.pagopa.selfcare.onboarding.client.auth; + +import jakarta.ws.rs.core.MultivaluedMap; +import org.eclipse.microprofile.rest.client.ext.ClientHeadersFactory; + +import java.util.List; + +public class AuthenticationPropagationHeadersFactory implements ClientHeadersFactory { + + @Override + public MultivaluedMap update(MultivaluedMap incomingHeaders, MultivaluedMap clientOutgoingHeaders) { + String bearerToken = System.getenv("JWT_BEARER_TOKEN"); + clientOutgoingHeaders.put("Authorization", List.of("Bearer " + bearerToken)); + return clientOutgoingHeaders; + } +} \ No newline at end of file diff --git a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/config/AzureStorageConfig.java b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/config/AzureStorageConfig.java new file mode 100644 index 000000000..0af86496f --- /dev/null +++ b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/config/AzureStorageConfig.java @@ -0,0 +1,15 @@ +package it.pagopa.selfcare.onboarding.config; + +import io.smallrye.config.ConfigMapping; + +@ConfigMapping(prefix = "onboarding-functions.blob-storage") +public interface AzureStorageConfig { + + String connectionStringContract(); + String connectionStringProduct(); + String containerContract(); + String containerProduct(); + String contractPath(); + String productFilepath(); + +} diff --git a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/config/MailTemplatePathConfig.java b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/config/MailTemplatePathConfig.java new file mode 100644 index 000000000..e24c5be06 --- /dev/null +++ b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/config/MailTemplatePathConfig.java @@ -0,0 +1,23 @@ +package it.pagopa.selfcare.onboarding.config; + +import io.smallrye.config.ConfigMapping; + +@ConfigMapping(prefix = "onboarding-functions.mail-template.path.onboarding") +public interface MailTemplatePathConfig { + + String completePath(); + String completePathFd(); + String completePathPt(); + + String autocompletePath(); + + String delegationNotificationPath(); + + String registrationPath(); + + String onboardingApprovePath(); + + String rejectPath(); + String registrationRequestPath(); + String registrationApprovePath(); +} diff --git a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/config/MailTemplatePlaceholdersConfig.java b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/config/MailTemplatePlaceholdersConfig.java new file mode 100644 index 000000000..cc8aace79 --- /dev/null +++ b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/config/MailTemplatePlaceholdersConfig.java @@ -0,0 +1,31 @@ +package it.pagopa.selfcare.onboarding.config; + +import io.smallrye.config.ConfigMapping; + +@ConfigMapping(prefix = "onboarding-functions.mail-template.placeholders.onboarding") +public interface MailTemplatePlaceholdersConfig { + + String userName(); + String userSurname(); + String productName(); + String institutionDescription(); + + String adminLink(); + String completeSelfcareName(); + String completeProductName(); + String completeSelfcarePlaceholder(); + + String confirmTokenName(); + String confirmTokenPlaceholder(); + String rejectTokenName(); + String rejectTokenPlaceholder(); + String notificationProductName(); + String notificationRequesterName(); + String notificationRequesterSurname(); + + String rejectOnboardingUrlPlaceholder(); + String rejectOnboardingUrlValue(); + String rejectProductName(); + + +} diff --git a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/config/OnboardingFunctionConfig.java b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/config/OnboardingFunctionConfig.java new file mode 100644 index 000000000..530eda610 --- /dev/null +++ b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/config/OnboardingFunctionConfig.java @@ -0,0 +1,86 @@ +package it.pagopa.selfcare.onboarding.config; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import io.quarkus.arc.DefaultBean; +import io.quarkus.arc.properties.IfBuildProperty; +import io.vertx.core.json.jackson.DatabindCodec; +import it.pagopa.selfcare.azurestorage.AzureBlobClientDefault; +import it.pagopa.selfcare.azurestorage.AzureBlobClient; +import it.pagopa.selfcare.onboarding.crypto.*; +import it.pagopa.selfcare.onboarding.exception.GenericOnboardingException; +import it.pagopa.selfcare.product.service.ProductService; +import it.pagopa.selfcare.product.service.ProductServiceDefault; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.enterprise.inject.Produces; + +import java.io.IOException; +import java.io.InputStream; + +@ApplicationScoped +public class OnboardingFunctionConfig { + + + + @Produces + public ObjectMapper objectMapper(){ + ObjectMapper mapper = DatabindCodec.mapper(); + //mapper.registerModule(new ParameterNamesModule(JsonCreator.Mode.PROPERTIES)); // mandatory config + + mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + + mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);// custom config + mapper.registerModule(new JavaTimeModule()); // custom config + mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); // custom config + // mapper.registerModule(new Jdk8Module()); // custom config + return mapper; + } + + @ApplicationScoped + public AzureBlobClient azureBobClientContract(AzureStorageConfig azureStorageConfig){ + return new AzureBlobClientDefault(azureStorageConfig.connectionStringContract(), azureStorageConfig.containerContract()); + } + + @ApplicationScoped + public ProductService productService(AzureStorageConfig azureStorageConfig){ + AzureBlobClient azureBlobClient = new AzureBlobClientDefault(azureStorageConfig.connectionStringProduct(), azureStorageConfig.containerProduct()); + String productJsonString = azureBlobClient.getFileAsText(azureStorageConfig.productFilepath()); + try { + return new ProductServiceDefault(productJsonString, objectMapper()); + } catch (JsonProcessingException e) { + throw new GenericOnboardingException("Found an issue when trying to serialize product json string!!"); + } + } + + @Produces + @IfBuildProperty(name = "onboarding-functions.pagopa-signature.source", stringValue = "aruba") + public Pkcs7HashSignService arubaPkcs7HashSignService(){ + return new ArubaPkcs7HashSignServiceImpl(new ArubaSignServiceImpl()); + } + + + @Produces + @IfBuildProperty(name = "onboarding-functions.pagopa-signature.source", stringValue = "disabled") + public Pkcs7HashSignService disabledPkcs7HashSignService(){ + return new Pkcs7HashSignService(){ + @Override + public byte[] sign(InputStream inputStream) throws IOException { + return new byte[0]; + } + }; + } + @Produces + @DefaultBean + public Pkcs7HashSignService pkcs7HashSignService(){ + return new Pkcs7HashSignServiceImpl(); + } + @Produces + public PadesSignService padesSignService(Pkcs7HashSignService pkcs7HashSignService){ + return new PadesSignServiceImpl(pkcs7HashSignService); + } + +} diff --git a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/config/PagoPaSignatureConfig.java b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/config/PagoPaSignatureConfig.java new file mode 100644 index 000000000..98a24edd8 --- /dev/null +++ b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/config/PagoPaSignatureConfig.java @@ -0,0 +1,18 @@ +package it.pagopa.selfcare.onboarding.config; + + +import io.smallrye.config.ConfigMapping; + +@ConfigMapping(prefix = "onboarding-functions.pagopa-signature") +public interface PagoPaSignatureConfig { + + String source(); + + String signer(); + + String location(); + + boolean applyOnboardingEnabled(); + + String applyOnboardingTemplateReason(); +} diff --git a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/config/PurgeConfig.java b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/config/PurgeConfig.java new file mode 100644 index 000000000..8cea1cb55 --- /dev/null +++ b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/config/PurgeConfig.java @@ -0,0 +1,13 @@ +package it.pagopa.selfcare.onboarding.config; + +import io.smallrye.config.ConfigMapping; + +@ConfigMapping(prefix = "onboarding-functions.purge") +public interface PurgeConfig { + + Long completedFrom(); + Long completedTo(); + Long allFrom(); + Long allTo(); + +} diff --git a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/config/RetryPolicyConfig.java b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/config/RetryPolicyConfig.java new file mode 100644 index 000000000..24bd4a9dc --- /dev/null +++ b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/config/RetryPolicyConfig.java @@ -0,0 +1,12 @@ +package it.pagopa.selfcare.onboarding.config; + +import io.smallrye.config.ConfigMapping; + +@ConfigMapping(prefix = "onboarding-functions.retry") +public interface RetryPolicyConfig { + + Integer maxAttempts(); + Long firstRetryInterval(); + Double backoffCoefficient(); + +} diff --git a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/entity/Billing.java b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/entity/Billing.java new file mode 100644 index 000000000..ec4fc4ecc --- /dev/null +++ b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/entity/Billing.java @@ -0,0 +1,32 @@ +package it.pagopa.selfcare.onboarding.entity; + + +public class Billing { + private String vatNumber; + private String recipientCode; + private boolean publicServices; + + public String getVatNumber() { + return vatNumber; + } + + public void setVatNumber(String vatNumber) { + this.vatNumber = vatNumber; + } + + public String getRecipientCode() { + return recipientCode; + } + + public void setRecipientCode(String recipientCode) { + this.recipientCode = recipientCode; + } + + public boolean isPublicServices() { + return publicServices; + } + + public void setPublicServices(boolean publicServices) { + this.publicServices = publicServices; + } +} diff --git a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/entity/DataProtectionOfficer.java b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/entity/DataProtectionOfficer.java new file mode 100644 index 000000000..6393cc56e --- /dev/null +++ b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/entity/DataProtectionOfficer.java @@ -0,0 +1,32 @@ +package it.pagopa.selfcare.onboarding.entity; + + +public class DataProtectionOfficer { + private String address; + private String email; + private String pec; + + public String getAddress() { + return address; + } + + public void setAddress(String address) { + this.address = address; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public String getPec() { + return pec; + } + + public void setPec(String pec) { + this.pec = pec; + } +} diff --git a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/entity/GeographicTaxonomy.java b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/entity/GeographicTaxonomy.java new file mode 100644 index 000000000..34100ba26 --- /dev/null +++ b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/entity/GeographicTaxonomy.java @@ -0,0 +1,22 @@ +package it.pagopa.selfcare.onboarding.entity; + +public class GeographicTaxonomy { + private String code; + private String desc; + + public String getCode() { + return code; + } + + public String getDesc() { + return desc; + } + + public void setCode(String code) { + this.code = code; + } + + public void setDesc(String desc) { + this.desc = desc; + } +} diff --git a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/entity/Institution.java b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/entity/Institution.java new file mode 100644 index 000000000..1abcf75e0 --- /dev/null +++ b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/entity/Institution.java @@ -0,0 +1,224 @@ +package it.pagopa.selfcare.onboarding.entity; + +import it.pagopa.selfcare.onboarding.common.InstitutionPaSubunitType; +import it.pagopa.selfcare.onboarding.common.InstitutionType; +import it.pagopa.selfcare.onboarding.common.Origin; + +import java.util.List; + +public class Institution { + + private String id; + private InstitutionType institutionType; + private String taxCode; + private String subunitCode; + private InstitutionPaSubunitType subunitType; + + private Origin origin; + private String city; + private String country; + private String county; + private String description; + private String digitalAddress; + private String address; + private String zipCode; + + private List geographicTaxonomies; + + private String rea; + private String shareCapital; + private String businessRegisterPlace; + + private String supportEmail; + private String supportPhone; + + private boolean imported; + + private PaymentServiceProvider paymentServiceProvider; + private DataProtectionOfficer dataProtectionOfficer; + private String parentDescription; + + public InstitutionType getInstitutionType() { + return institutionType; + } + + public void setInstitutionType(InstitutionType institutionType) { + this.institutionType = institutionType; + } + + public String getTaxCode() { + return taxCode; + } + + public void setTaxCode(String taxCode) { + this.taxCode = taxCode; + } + + public String getSubunitCode() { + return subunitCode; + } + + public void setSubunitCode(String subunitCode) { + this.subunitCode = subunitCode; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getDigitalAddress() { + return digitalAddress; + } + + public void setDigitalAddress(String digitalAddress) { + this.digitalAddress = digitalAddress; + } + + public String getAddress() { + return address; + } + + public void setAddress(String address) { + this.address = address; + } + + public String getZipCode() { + return zipCode; + } + + public void setZipCode(String zipCode) { + this.zipCode = zipCode; + } + + public List getGeographicTaxonomies() { + return geographicTaxonomies; + } + + public void setGeographicTaxonomies(List geographicTaxonomies) { + this.geographicTaxonomies = geographicTaxonomies; + } + + public String getRea() { + return rea; + } + + public void setRea(String rea) { + this.rea = rea; + } + + public String getShareCapital() { + return shareCapital; + } + + public void setShareCapital(String shareCapital) { + this.shareCapital = shareCapital; + } + + public String getBusinessRegisterPlace() { + return businessRegisterPlace; + } + + public void setBusinessRegisterPlace(String businessRegisterPlace) { + this.businessRegisterPlace = businessRegisterPlace; + } + + public String getSupportEmail() { + return supportEmail; + } + + public void setSupportEmail(String supportEmail) { + this.supportEmail = supportEmail; + } + + public String getSupportPhone() { + return supportPhone; + } + + public void setSupportPhone(String supportPhone) { + this.supportPhone = supportPhone; + } + + public boolean isImported() { + return imported; + } + + public void setImported(boolean imported) { + this.imported = imported; + } + + public PaymentServiceProvider getPaymentServiceProvider() { + return paymentServiceProvider; + } + + public void setPaymentServiceProvider(PaymentServiceProvider paymentServiceProvider) { + this.paymentServiceProvider = paymentServiceProvider; + } + + public DataProtectionOfficer getDataProtectionOfficer() { + return dataProtectionOfficer; + } + + public void setDataProtectionOfficer(DataProtectionOfficer dataProtectionOfficer) { + this.dataProtectionOfficer = dataProtectionOfficer; + } + + public Origin getOrigin() { + return origin; + } + + public void setOrigin(Origin origin) { + this.origin = origin; + } + + public InstitutionPaSubunitType getSubunitType() { + return subunitType; + } + + public void setSubunitType(InstitutionPaSubunitType subunitType) { + this.subunitType = subunitType; + } + + public String getCity() { + return city; + } + + public void setCity(String city) { + this.city = city; + } + + public String getCountry() { + return country; + } + + public void setCountry(String country) { + this.country = country; + } + + public String getCounty() { + return county; + } + + public void setCounty(String county) { + this.county = county; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getParentDescription() { + return parentDescription; + } + + public void setParentDescription(String parentDescription) { + this.parentDescription = parentDescription; + } +} diff --git a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/entity/MailTemplate.java b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/entity/MailTemplate.java new file mode 100644 index 000000000..6444490a7 --- /dev/null +++ b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/entity/MailTemplate.java @@ -0,0 +1,26 @@ +package it.pagopa.selfcare.onboarding.entity; + + +import java.nio.charset.StandardCharsets; +import java.util.Base64; + +public class MailTemplate { + private String subject; + private String body; + + public String getSubject() { + return new String(Base64.getDecoder().decode(subject), StandardCharsets.UTF_8); + } + + public String getBody() { + return new String(Base64.getDecoder().decode(body), StandardCharsets.UTF_8); + } + + public void setBody(String body) { + this.body = body; + } + + public void setSubject(String subject) { + this.subject = subject; + } +} diff --git a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/entity/Onboarding.java b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/entity/Onboarding.java new file mode 100644 index 000000000..85cb8b5d2 --- /dev/null +++ b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/entity/Onboarding.java @@ -0,0 +1,128 @@ +package it.pagopa.selfcare.onboarding.entity; + + +import io.quarkus.mongodb.panache.common.MongoEntity; +import it.pagopa.selfcare.onboarding.common.OnboardingStatus; +import it.pagopa.selfcare.onboarding.common.WorkflowType; +import org.bson.types.ObjectId; + +import java.time.LocalDateTime; +import java.util.List; + + +@MongoEntity(collection="onboardings") +public class Onboarding { + + private ObjectId id; + + private String onboardingId; + private String productId; + private WorkflowType workflowType; + private Institution institution; + private List users; + private String pricingPlan; + private Billing billing; + private Boolean signContract; + + + private LocalDateTime expiringDate; + + private OnboardingStatus status; + private String userRequestUid; + + public ObjectId getId() { + return id; + } + + public void setId(ObjectId id) { + this.id = id; + } + + public String getProductId() { + return productId; + } + + public void setProductId(String productId) { + this.productId = productId; + } + + public Institution getInstitution() { + return institution; + } + + public void setInstitution(Institution institution) { + this.institution = institution; + } + + public List getUsers() { + return users; + } + + public void setUsers(List users) { + this.users = users; + } + + public String getPricingPlan() { + return pricingPlan; + } + + public void setPricingPlan(String pricingPlan) { + this.pricingPlan = pricingPlan; + } + + public Billing getBilling() { + return billing; + } + + public void setBilling(Billing billing) { + this.billing = billing; + } + + public Boolean getSignContract() { + return signContract; + } + + public void setSignContract(Boolean signContract) { + this.signContract = signContract; + } + + public LocalDateTime getExpiringDate() { + return expiringDate; + } + + public void setExpiringDate(LocalDateTime expiringDate) { + this.expiringDate = expiringDate; + } + + public OnboardingStatus getStatus() { + return status; + } + + public void setStatus(OnboardingStatus status) { + this.status = status; + } + + public String getOnboardingId() { + return onboardingId; + } + + public void setOnboardingId(String onboardingId) { + this.onboardingId = onboardingId; + } + + public String getUserRequestUid() { + return userRequestUid; + } + + public void setUserRequestUid(String userRequestUid) { + this.userRequestUid = userRequestUid; + } + + public WorkflowType getWorkflowType() { + return workflowType; + } + + public void setWorkflowType(WorkflowType workflowType) { + this.workflowType = workflowType; + } +} diff --git a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/entity/PaymentServiceProvider.java b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/entity/PaymentServiceProvider.java new file mode 100644 index 000000000..89c4b8fe6 --- /dev/null +++ b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/entity/PaymentServiceProvider.java @@ -0,0 +1,50 @@ +package it.pagopa.selfcare.onboarding.entity; + + +public class PaymentServiceProvider { + private String abiCode; + private String businessRegisterNumber; + private String legalRegisterNumber; + private String legalRegisterName; + private boolean vatNumberGroup; + + public String getAbiCode() { + return abiCode; + } + + public void setAbiCode(String abiCode) { + this.abiCode = abiCode; + } + + public String getBusinessRegisterNumber() { + return businessRegisterNumber; + } + + public void setBusinessRegisterNumber(String businessRegisterNumber) { + this.businessRegisterNumber = businessRegisterNumber; + } + + public String getLegalRegisterNumber() { + return legalRegisterNumber; + } + + public void setLegalRegisterNumber(String legalRegisterNumber) { + this.legalRegisterNumber = legalRegisterNumber; + } + + public String getLegalRegisterName() { + return legalRegisterName; + } + + public void setLegalRegisterName(String legalRegisterName) { + this.legalRegisterName = legalRegisterName; + } + + public boolean isVatNumberGroup() { + return vatNumberGroup; + } + + public void setVatNumberGroup(boolean vatNumberGroup) { + this.vatNumberGroup = vatNumberGroup; + } +} diff --git a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/entity/Token.java b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/entity/Token.java new file mode 100644 index 000000000..e92bf7436 --- /dev/null +++ b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/entity/Token.java @@ -0,0 +1,132 @@ +package it.pagopa.selfcare.onboarding.entity; + +import io.quarkus.mongodb.panache.common.MongoEntity; +import it.pagopa.selfcare.onboarding.common.TokenType; +import org.bson.types.ObjectId; + +import java.time.LocalDateTime; + + +@MongoEntity(collection="tokens") +public class Token { + + private ObjectId id; + private TokenType type; + private String onboardingId; + private String productId; + private String checksum; + private String contractVersion; + private String contractTemplate; + private String contractSigned; + private String contractFilename; + //@Indexed + private LocalDateTime createdAt; + private LocalDateTime updatedAt; + private LocalDateTime deletedAt; + private LocalDateTime activatedAt; + + public ObjectId getId() { + return id; + } + + public void setId(ObjectId id) { + this.id = id; + } + + public TokenType getType() { + return type; + } + + public void setType(TokenType type) { + this.type = type; + } + + public String getProductId() { + return productId; + } + + public void setProductId(String productId) { + this.productId = productId; + } + + public String getChecksum() { + return checksum; + } + + public void setChecksum(String checksum) { + this.checksum = checksum; + } + + public String getContractVersion() { + return contractVersion; + } + + public void setContractVersion(String contractVersion) { + this.contractVersion = contractVersion; + } + + public String getContractTemplate() { + return contractTemplate; + } + + public void setContractTemplate(String contractTemplate) { + this.contractTemplate = contractTemplate; + } + + public String getContractSigned() { + return contractSigned; + } + + public void setContractSigned(String contractSigned) { + this.contractSigned = contractSigned; + } + + public LocalDateTime getCreatedAt() { + return createdAt; + } + + public void setCreatedAt(LocalDateTime createdAt) { + this.createdAt = createdAt; + } + + public LocalDateTime getUpdatedAt() { + return updatedAt; + } + + public void setUpdatedAt(LocalDateTime updatedAt) { + this.updatedAt = updatedAt; + } + + public LocalDateTime getDeletedAt() { + return deletedAt; + } + + public void setDeletedAt(LocalDateTime deletedAt) { + this.deletedAt = deletedAt; + } + + public LocalDateTime getActivatedAt() { + return activatedAt; + } + + public void setActivatedAt(LocalDateTime activatedAt) { + this.activatedAt = activatedAt; + } + + public String getOnboardingId() { + return onboardingId; + } + + public void setOnboardingId(String onboardingId) { + this.onboardingId = onboardingId; + } + + public String getContractFilename() { + return contractFilename; + } + + public void setContractFilename(String contractFilename) { + this.contractFilename = contractFilename; + } +} + diff --git a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/entity/User.java b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/entity/User.java new file mode 100644 index 000000000..b9969eaf3 --- /dev/null +++ b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/entity/User.java @@ -0,0 +1,35 @@ +package it.pagopa.selfcare.onboarding.entity; + + +import it.pagopa.selfcare.onboarding.common.PartyRole; + +public class User { + + private String id; + private PartyRole role; + private String productRole; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public PartyRole getRole() { + return role; + } + + public void setRole(PartyRole role) { + this.role = role; + } + + public String getProductRole() { + return productRole; + } + + public void setProductRole(String productRole) { + this.productRole = productRole; + } +} diff --git a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/exception/FunctionOrchestratedException.java b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/exception/FunctionOrchestratedException.java new file mode 100644 index 000000000..df853c7a7 --- /dev/null +++ b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/exception/FunctionOrchestratedException.java @@ -0,0 +1,8 @@ +package it.pagopa.selfcare.onboarding.exception; + +public class FunctionOrchestratedException extends RuntimeException { + + public FunctionOrchestratedException(Exception e) { + super(e); + } +} diff --git a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/exception/GenericOnboardingException.java b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/exception/GenericOnboardingException.java new file mode 100644 index 000000000..866ca18d1 --- /dev/null +++ b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/exception/GenericOnboardingException.java @@ -0,0 +1,20 @@ +package it.pagopa.selfcare.onboarding.exception; + +public class GenericOnboardingException extends RuntimeException { + + private final String code; + + public GenericOnboardingException(String message, String code) { + super(message); + this.code = code; + } + + public GenericOnboardingException(String message) { + super(message); + this.code = "0000"; + } + + public String getCode() { + return code; + } +} diff --git a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/exception/ResourceNotFoundException.java b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/exception/ResourceNotFoundException.java new file mode 100644 index 000000000..e696c94c4 --- /dev/null +++ b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/exception/ResourceNotFoundException.java @@ -0,0 +1,19 @@ +package it.pagopa.selfcare.onboarding.exception; + + +public class ResourceNotFoundException extends RuntimeException { + + private final String code; + public ResourceNotFoundException(String message, String code) { + super(message); + this.code = code; + } + public ResourceNotFoundException(String message) { + super(message); + this.code = "0000"; + } + + public String getCode() { + return code; + } +} diff --git a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/functions/CommonFunctions.java b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/functions/CommonFunctions.java new file mode 100644 index 000000000..58718301c --- /dev/null +++ b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/functions/CommonFunctions.java @@ -0,0 +1,67 @@ +package it.pagopa.selfcare.onboarding.functions; + +import com.microsoft.azure.functions.ExecutionContext; +import com.microsoft.azure.functions.annotation.FunctionName; +import com.microsoft.azure.functions.annotation.TimerTrigger; +import com.microsoft.durabletask.OrchestrationRuntimeStatus; +import com.microsoft.durabletask.PurgeInstanceCriteria; +import com.microsoft.durabletask.PurgeResult; +import com.microsoft.durabletask.azurefunctions.DurableActivityTrigger; +import com.microsoft.durabletask.azurefunctions.DurableClientContext; +import com.microsoft.durabletask.azurefunctions.DurableClientInput; +import it.pagopa.selfcare.onboarding.common.OnboardingStatus; +import it.pagopa.selfcare.onboarding.config.PurgeConfig; +import it.pagopa.selfcare.onboarding.functions.utils.SaveOnboardingStatusInput; +import it.pagopa.selfcare.onboarding.service.OnboardingService; + +import java.time.Duration; +import java.time.Instant; +import java.util.List; +import java.util.concurrent.TimeoutException; + +public class CommonFunctions { + + public static final String FORMAT_LOGGER_ONBOARDING_STRING = "%s: %s"; + public static final String SAVE_ONBOARDING_STATUS_ACTIVITY = "SaveOnboardingStatus"; + + private final OnboardingService service; + + private final PurgeConfig purgeConfig; + + public CommonFunctions(OnboardingService service, PurgeConfig purgeConfig) { + this.service = service; + this.purgeConfig = purgeConfig; + } + + @FunctionName(SAVE_ONBOARDING_STATUS_ACTIVITY) + public void savePendingState(@DurableActivityTrigger(name = "onboardingString") String saveOnboardingStatusInputString, final ExecutionContext context) { + SaveOnboardingStatusInput saveOnboardingStatusInput = SaveOnboardingStatusInput.readJsonString(saveOnboardingStatusInputString); + context.getLogger().info(String.format(FORMAT_LOGGER_ONBOARDING_STRING, SAVE_ONBOARDING_STATUS_ACTIVITY, saveOnboardingStatusInput.getOnboardingId())); + service.savePendingState(saveOnboardingStatusInput.getOnboardingId(), OnboardingStatus.valueOf(saveOnboardingStatusInput.getStatus())); + } + + @FunctionName("PurgeInstancesCompleted") + public void purgeInstances( + @TimerTrigger(name = "purgeTimer", schedule = "0 0 11 * * *") String timerInfo, + @DurableClientInput(name = "durableContext") DurableClientContext durableContext, + ExecutionContext context) throws TimeoutException { + PurgeInstanceCriteria criteria = new PurgeInstanceCriteria() + .setCreatedTimeFrom(Instant.now().minus(Duration.ofDays(purgeConfig.completedFrom()))) + .setCreatedTimeTo(Instant.now().minus(Duration.ofDays(purgeConfig.completedTo()))) + .setRuntimeStatusList(List.of(OrchestrationRuntimeStatus.COMPLETED)); + PurgeResult result = durableContext.getClient().purgeInstances(criteria); + context.getLogger().info(String.format("Purged %d instance(s)", result.getDeletedInstanceCount())); + } + + @FunctionName("PurgeInstancesAll") + public void purgeInstancesAll( + @TimerTrigger(name = "purgeTimer", schedule = "0 0 12 * * *") String timerInfo, + @DurableClientInput(name = "durableContext") DurableClientContext durableContext, + ExecutionContext context) throws TimeoutException { + PurgeInstanceCriteria criteria = new PurgeInstanceCriteria() + .setCreatedTimeFrom(Instant.now().minus(Duration.ofDays(purgeConfig.allFrom()))) + .setCreatedTimeTo(Instant.now().minus(Duration.ofDays(purgeConfig.allTo()))); + PurgeResult result = durableContext.getClient().purgeInstances(criteria); + context.getLogger().info(String.format("Purged %d instance(s)", result.getDeletedInstanceCount())); + } +} diff --git a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/functions/OnboardingCompletionFunctions.java b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/functions/OnboardingCompletionFunctions.java new file mode 100644 index 000000000..0e8fdc7c5 --- /dev/null +++ b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/functions/OnboardingCompletionFunctions.java @@ -0,0 +1,123 @@ +package it.pagopa.selfcare.onboarding.functions; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.microsoft.azure.functions.ExecutionContext; +import com.microsoft.azure.functions.HttpMethod; +import com.microsoft.azure.functions.HttpRequestMessage; +import com.microsoft.azure.functions.HttpResponseMessage; +import com.microsoft.azure.functions.annotation.AuthorizationLevel; +import com.microsoft.azure.functions.annotation.FunctionName; +import com.microsoft.azure.functions.annotation.HttpTrigger; +import com.microsoft.durabletask.DurableTaskClient; +import com.microsoft.durabletask.RetryPolicy; +import com.microsoft.durabletask.TaskOptions; +import com.microsoft.durabletask.TaskOrchestrationContext; +import com.microsoft.durabletask.azurefunctions.DurableActivityTrigger; +import com.microsoft.durabletask.azurefunctions.DurableClientContext; +import com.microsoft.durabletask.azurefunctions.DurableClientInput; +import com.microsoft.durabletask.azurefunctions.DurableOrchestrationTrigger; +import it.pagopa.selfcare.onboarding.common.OnboardingStatus; +import it.pagopa.selfcare.onboarding.config.RetryPolicyConfig; +import it.pagopa.selfcare.onboarding.entity.Onboarding; +import it.pagopa.selfcare.onboarding.exception.ResourceNotFoundException; +import it.pagopa.selfcare.onboarding.functions.utils.SaveOnboardingStatusInput; +import it.pagopa.selfcare.onboarding.service.CompletionService; +import it.pagopa.selfcare.onboarding.service.OnboardingService; + +import java.time.Duration; +import java.util.Optional; + +import static it.pagopa.selfcare.onboarding.functions.CommonFunctions.FORMAT_LOGGER_ONBOARDING_STRING; +import static it.pagopa.selfcare.onboarding.functions.CommonFunctions.SAVE_ONBOARDING_STATUS_ACTIVITY; +import static it.pagopa.selfcare.onboarding.utils.Utils.getOnboardingString; +import static it.pagopa.selfcare.onboarding.utils.Utils.readOnboardingValue; + +public class OnboardingCompletionFunctions { + + public static final String CREATED_NEW_ONBOARDING_COMPLETION_ORCHESTRATION_WITH_INSTANCE_ID_MSG = "Created new Onboarding completion orchestration with instance ID = "; + + public static final String ONBOARDING_COMPLETION_ACTIVITY = "OnboardingCompletion"; + public static final String CREATE_INSTITUTION_ACTIVITY = "CreateInstitution"; + public static final String CREATE_ONBOARDING_ACTIVITY = "CreateOnboarding"; + public static final String SEND_MAIL_COMPLETION_ACTIVITY = "SendMailCompletion"; + private final OnboardingService service; + + private final CompletionService completionService; + + private final ObjectMapper objectMapper; + private final TaskOptions optionsRetry; + + public OnboardingCompletionFunctions(OnboardingService service, CompletionService completionService, ObjectMapper objectMapper, RetryPolicyConfig retryPolicyConfig) { + this.service = service; + this.completionService = completionService; + this.objectMapper = objectMapper; + + final int maxAttempts = retryPolicyConfig.maxAttempts(); + final Duration firstRetryInterval = Duration.ofSeconds(retryPolicyConfig.firstRetryInterval()); + RetryPolicy retryPolicy = new RetryPolicy(maxAttempts, firstRetryInterval); + retryPolicy.setBackoffCoefficient(retryPolicyConfig.backoffCoefficient()); + optionsRetry = new TaskOptions(retryPolicy); + } + + /** + * This HTTP-triggered function starts the orchestration. + */ + @FunctionName("StartOnboardingCompletionOrchestration") + public HttpResponseMessage startOrchestration( + @HttpTrigger(name = "req", methods = {HttpMethod.GET, HttpMethod.POST}, authLevel = AuthorizationLevel.FUNCTION) HttpRequestMessage> request, + @DurableClientInput(name = "durableContext") DurableClientContext durableContext, + final ExecutionContext context) { + context.getLogger().info("StartOnboardingCompletionOrchestration trigger processed a request."); + + final String onboardingId = request.getQueryParameters().get("onboardingId"); + + DurableTaskClient client = durableContext.getClient(); + String instanceId = client.scheduleNewOrchestrationInstance(ONBOARDING_COMPLETION_ACTIVITY, onboardingId); + context.getLogger().info(String.format("%s %s", CREATED_NEW_ONBOARDING_COMPLETION_ORCHESTRATION_WITH_INSTANCE_ID_MSG, instanceId)); + + return durableContext.createCheckStatusResponse(request, instanceId); + } + + /** + * This is the orchestrator function, which can schedule activity functions, create durable timers, + * or wait for external events in a way that's completely fault-tolerant. + */ + @FunctionName(ONBOARDING_COMPLETION_ACTIVITY) + public void onboardingCompletionOrchestrator( + @DurableOrchestrationTrigger(name = "taskOrchestrationContext") TaskOrchestrationContext ctx) { + String onboardingId = ctx.getInput(String.class); + Onboarding onboarding = service.getOnboarding(onboardingId) + .orElseThrow(() -> new ResourceNotFoundException(String.format("Onboarding with id %s not found!", onboardingId))); + String onboardingString = getOnboardingString(objectMapper, onboarding); + + //CreateInstitution activity return an institutionId that is used by CreateOnboarding activity + String institutionId = ctx.callActivity(CREATE_INSTITUTION_ACTIVITY, onboardingString, optionsRetry, String.class).await(); + onboarding.getInstitution().setId(institutionId); + onboardingString = getOnboardingString(objectMapper, onboarding); + + ctx.callActivity(CREATE_ONBOARDING_ACTIVITY, onboardingString, optionsRetry, String.class).await(); + ctx.callActivity(SEND_MAIL_COMPLETION_ACTIVITY, onboardingString, optionsRetry, String.class).await(); + + //Last activity consist of saving pending status + String saveOnboardingStatusInput = SaveOnboardingStatusInput.buildAsJsonString(onboardingId, OnboardingStatus.COMPLETED.name()); + ctx.callActivity(SAVE_ONBOARDING_STATUS_ACTIVITY, saveOnboardingStatusInput, optionsRetry, String.class).await(); + } + + @FunctionName(CREATE_INSTITUTION_ACTIVITY) + public String createInstitutionAndPersistInstitutionId(@DurableActivityTrigger(name = "onboardingString") String onboardingString, final ExecutionContext context) { + context.getLogger().info(String.format(FORMAT_LOGGER_ONBOARDING_STRING, CREATE_INSTITUTION_ACTIVITY, onboardingString)); + return completionService.createInstitutionAndPersistInstitutionId(readOnboardingValue(objectMapper, onboardingString)); + } + + @FunctionName(CREATE_ONBOARDING_ACTIVITY) + public void createOnboarding(@DurableActivityTrigger(name = "onboardingString") String onboardingString, final ExecutionContext context) { + context.getLogger().info(String.format(FORMAT_LOGGER_ONBOARDING_STRING, CREATE_ONBOARDING_ACTIVITY, onboardingString)); + completionService.persistOnboarding(readOnboardingValue(objectMapper, onboardingString)); + } + + @FunctionName(SEND_MAIL_COMPLETION_ACTIVITY) + public void sendMailCompletion(@DurableActivityTrigger(name = "onboardingString") String onboardingString, final ExecutionContext context) { + context.getLogger().info(String.format(FORMAT_LOGGER_ONBOARDING_STRING, SEND_MAIL_COMPLETION_ACTIVITY, onboardingString)); + completionService.sendCompletedEmail(readOnboardingValue(objectMapper, onboardingString)); + } +} diff --git a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/functions/OnboardingFunctions.java b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/functions/OnboardingFunctions.java new file mode 100644 index 000000000..4ee7fd659 --- /dev/null +++ b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/functions/OnboardingFunctions.java @@ -0,0 +1,203 @@ +package it.pagopa.selfcare.onboarding.functions; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.microsoft.azure.functions.ExecutionContext; +import com.microsoft.azure.functions.HttpMethod; +import com.microsoft.azure.functions.HttpRequestMessage; +import com.microsoft.azure.functions.HttpResponseMessage; +import com.microsoft.azure.functions.annotation.AuthorizationLevel; +import com.microsoft.azure.functions.annotation.FunctionName; +import com.microsoft.azure.functions.annotation.HttpTrigger; +import com.microsoft.durabletask.DurableTaskClient; +import com.microsoft.durabletask.RetryPolicy; +import com.microsoft.durabletask.TaskOptions; +import com.microsoft.durabletask.TaskOrchestrationContext; +import com.microsoft.durabletask.azurefunctions.DurableActivityTrigger; +import com.microsoft.durabletask.azurefunctions.DurableClientContext; +import com.microsoft.durabletask.azurefunctions.DurableClientInput; +import com.microsoft.durabletask.azurefunctions.DurableOrchestrationTrigger; +import it.pagopa.selfcare.onboarding.common.OnboardingStatus; +import it.pagopa.selfcare.onboarding.common.WorkflowType; +import it.pagopa.selfcare.onboarding.config.RetryPolicyConfig; +import it.pagopa.selfcare.onboarding.entity.Onboarding; +import it.pagopa.selfcare.onboarding.exception.ResourceNotFoundException; +import it.pagopa.selfcare.onboarding.functions.utils.SaveOnboardingStatusInput; +import it.pagopa.selfcare.onboarding.service.OnboardingService; + +import java.time.Duration; +import java.util.Optional; + +import static it.pagopa.selfcare.onboarding.functions.CommonFunctions.FORMAT_LOGGER_ONBOARDING_STRING; +import static it.pagopa.selfcare.onboarding.functions.CommonFunctions.SAVE_ONBOARDING_STATUS_ACTIVITY; +import static it.pagopa.selfcare.onboarding.utils.Utils.getOnboardingString; +import static it.pagopa.selfcare.onboarding.utils.Utils.readOnboardingValue; + +/** + * Azure Functions with HTTP Trigger integrated with Quarkus + */ +public class OnboardingFunctions { + public static final String CREATED_NEW_ONBOARDING_ORCHESTRATION_WITH_INSTANCE_ID_MSG = "Created new Onboarding orchestration with instance ID = "; + public static final String SAVE_TOKEN_WITH_CONTRACT_ACTIVITY_NAME = "SaveTokenWithContract"; + public static final String BUILD_CONTRACT_ACTIVITY_NAME = "BuildContract"; + public static final String SEND_MAIL_REGISTRATION_WITH_CONTRACT_ACTIVITY = "SendMailRegistrationWithContract"; + + public static final String SEND_MAIL_REGISTRATION_WITH_CONTRACT_WHEN_APPROVE_ACTIVITY = "SendMailRegistrationWithContractWhenApprove"; + public static final String SEND_MAIL_REGISTRATION_REQUEST_ACTIVITY = "SendMailRegistrationRequest"; + public static final String SEND_MAIL_REGISTRATION_APPROVE_ACTIVITY = "SendMailRegistrationApprove"; + public static final String SEND_MAIL_ONBOARDING_APPROVE_ACTIVITY = "SendMailOnboardingApprove"; + public static final String SEND_MAIL_CONFIRMATION_ACTIVITY = "SendMailConfirmation"; + + private final OnboardingService service; + + private final ObjectMapper objectMapper; + private final TaskOptions optionsRetry; + + public OnboardingFunctions(OnboardingService service, ObjectMapper objectMapper, RetryPolicyConfig retryPolicyConfig) { + this.service = service; + this.objectMapper = objectMapper; + + final int maxAttempts = retryPolicyConfig.maxAttempts(); + final Duration firstRetryInterval = Duration.ofSeconds(retryPolicyConfig.firstRetryInterval()); + RetryPolicy retryPolicy = new RetryPolicy(maxAttempts, firstRetryInterval); + retryPolicy.setBackoffCoefficient(retryPolicyConfig.backoffCoefficient()); + optionsRetry = new TaskOptions(retryPolicy); + } + + /** + * This HTTP-triggered function starts the orchestration. + */ + @FunctionName("StartOnboardingOrchestration") + public HttpResponseMessage startOrchestration( + @HttpTrigger(name = "req", methods = {HttpMethod.GET, HttpMethod.POST}, authLevel = AuthorizationLevel.FUNCTION) HttpRequestMessage> request, + @DurableClientInput(name = "durableContext") DurableClientContext durableContext, + final ExecutionContext context) { + context.getLogger().info("StartOnboardingOrchestration trigger processed a request."); + + final String onboardingId = request.getQueryParameters().get("onboardingId"); + + DurableTaskClient client = durableContext.getClient(); + String instanceId = client.scheduleNewOrchestrationInstance("Onboardings", onboardingId); + context.getLogger().info(String.format("%s %s", CREATED_NEW_ONBOARDING_ORCHESTRATION_WITH_INSTANCE_ID_MSG, instanceId)); + + return durableContext.createCheckStatusResponse(request, instanceId); + } + + /** + * This is the orchestrator function, which can schedule activity functions, create durable timers, + * or wait for external events in a way that's completely fault-tolerant. + */ + @FunctionName("Onboardings") + public void onboardingsOrchestrator( + @DurableOrchestrationTrigger(name = "taskOrchestrationContext") TaskOrchestrationContext ctx) { + String onboardingId = ctx.getInput(String.class); + Onboarding onboarding = service.getOnboarding(onboardingId) + .orElseThrow(() -> new ResourceNotFoundException(String.format("Onboarding with id %s not found!", onboardingId))); + String onboardingString = getOnboardingString(objectMapper, onboarding); + + switch (onboarding.getWorkflowType()) { + case CONTRACT_REGISTRATION -> workflowContractRegistration(ctx, onboardingString); + case FOR_APPROVE -> workflowForApprove(ctx, onboardingString, onboarding.getStatus()); + case FOR_APPROVE_PT -> workflowRegistrationRequestAndApprove(ctx, onboardingString); + case CONFIRMATION -> workflowForConfirmation(ctx, onboardingString); + } + + //Last activity consist of saving pending status + OnboardingStatus nextStatus = nextProcessOnboardingStatus(onboarding.getStatus(), onboarding.getWorkflowType()); + String saveOnboardingStatusInput = SaveOnboardingStatusInput.buildAsJsonString(onboardingId, nextStatus.name()); + + ctx.callActivity(SAVE_ONBOARDING_STATUS_ACTIVITY, saveOnboardingStatusInput, optionsRetry, String.class).await(); + } + + private void workflowContractRegistration(TaskOrchestrationContext ctx, String onboardingString){ + ctx.callActivity(BUILD_CONTRACT_ACTIVITY_NAME, onboardingString, optionsRetry, String.class).await(); + ctx.callActivity(SAVE_TOKEN_WITH_CONTRACT_ACTIVITY_NAME, onboardingString, optionsRetry, String.class).await(); + ctx.callActivity(SEND_MAIL_REGISTRATION_WITH_CONTRACT_ACTIVITY, onboardingString, optionsRetry, String.class).await(); + } + + private void workflowForApprove(TaskOrchestrationContext ctx, String onboardingString, OnboardingStatus onboardingStatus){ + if (OnboardingStatus.REQUEST.equals(onboardingStatus)) { + ctx.callActivity(SEND_MAIL_ONBOARDING_APPROVE_ACTIVITY, onboardingString, optionsRetry, String.class).await(); + } else if (OnboardingStatus.TO_BE_VALIDATED.equals(onboardingStatus)) { + ctx.callActivity(BUILD_CONTRACT_ACTIVITY_NAME, onboardingString, optionsRetry, String.class).await(); + ctx.callActivity(SAVE_TOKEN_WITH_CONTRACT_ACTIVITY_NAME, onboardingString, optionsRetry, String.class).await(); + ctx.callActivity(SEND_MAIL_REGISTRATION_WITH_CONTRACT_WHEN_APPROVE_ACTIVITY, onboardingString, optionsRetry, String.class).await(); + } + } + + private void workflowRegistrationRequestAndApprove(TaskOrchestrationContext ctx, String onboardingString){ + ctx.callActivity(SEND_MAIL_REGISTRATION_REQUEST_ACTIVITY, onboardingString, optionsRetry, String.class).await(); + ctx.callActivity(SEND_MAIL_REGISTRATION_APPROVE_ACTIVITY, onboardingString, optionsRetry, String.class).await(); + } + + private void workflowForConfirmation(TaskOrchestrationContext ctx, String onboardingString){ + ctx.callActivity(SEND_MAIL_CONFIRMATION_ACTIVITY, onboardingString, optionsRetry, String.class).await(); + } + + /** + * This is the activity function that gets invoked by the orchestrator function. + */ + @FunctionName(BUILD_CONTRACT_ACTIVITY_NAME) + public void buildContract(@DurableActivityTrigger(name = "onboardingString") String onboardingString, final ExecutionContext context) { + context.getLogger().info(String.format(FORMAT_LOGGER_ONBOARDING_STRING, BUILD_CONTRACT_ACTIVITY_NAME, onboardingString)); + service.createContract(readOnboardingValue(objectMapper, onboardingString)); + } + + /** + * This is the activity function that gets invoked by the orchestrator function. + */ + @FunctionName(SAVE_TOKEN_WITH_CONTRACT_ACTIVITY_NAME) + public void saveToken(@DurableActivityTrigger(name = "onboardingString") String onboardingString, final ExecutionContext context) { + context.getLogger().info(String.format(FORMAT_LOGGER_ONBOARDING_STRING, SAVE_TOKEN_WITH_CONTRACT_ACTIVITY_NAME, onboardingString)); + service.saveTokenWithContract(readOnboardingValue(objectMapper, onboardingString)); + } + + /** + * This is the activity function that gets invoked by the orchestrator function. + */ + @FunctionName(SEND_MAIL_REGISTRATION_WITH_CONTRACT_ACTIVITY) + public void sendMailRegistrationWithContract(@DurableActivityTrigger(name = "onboardingString") String onboardingString, final ExecutionContext context) { + context.getLogger().info(String.format(FORMAT_LOGGER_ONBOARDING_STRING, SEND_MAIL_REGISTRATION_WITH_CONTRACT_ACTIVITY, onboardingString)); + service.sendMailRegistrationWithContract(readOnboardingValue(objectMapper, onboardingString)); + } + @FunctionName(SEND_MAIL_REGISTRATION_WITH_CONTRACT_WHEN_APPROVE_ACTIVITY) + public void sendMailRegistrationWithContractWhenApprove(@DurableActivityTrigger(name = "onboardingString") String onboardingString, final ExecutionContext context) { + context.getLogger().info(String.format(FORMAT_LOGGER_ONBOARDING_STRING, SEND_MAIL_REGISTRATION_WITH_CONTRACT_WHEN_APPROVE_ACTIVITY, onboardingString)); + service.sendMailRegistrationWithContractWhenApprove(readOnboardingValue(objectMapper, onboardingString)); + } + + @FunctionName(SEND_MAIL_REGISTRATION_REQUEST_ACTIVITY) + public void sendMailRegistration(@DurableActivityTrigger(name = "onboardingString") String onboardingString, final ExecutionContext context) { + context.getLogger().info(String.format(FORMAT_LOGGER_ONBOARDING_STRING, SEND_MAIL_REGISTRATION_REQUEST_ACTIVITY, onboardingString)); + service.sendMailRegistration(readOnboardingValue(objectMapper, onboardingString)); + } + + @FunctionName(SEND_MAIL_REGISTRATION_APPROVE_ACTIVITY) + public void sendMailRegistrationApprove(@DurableActivityTrigger(name = "onboardingString") String onboardingString, final ExecutionContext context) { + context.getLogger().info(String.format(FORMAT_LOGGER_ONBOARDING_STRING, SEND_MAIL_REGISTRATION_APPROVE_ACTIVITY, onboardingString)); + service.sendMailRegistrationApprove(readOnboardingValue(objectMapper, onboardingString)); + } + + @FunctionName(SEND_MAIL_ONBOARDING_APPROVE_ACTIVITY) + public void sendMailOnboardingApprove(@DurableActivityTrigger(name = "onboardingString") String onboardingString, final ExecutionContext context) { + context.getLogger().info(String.format(FORMAT_LOGGER_ONBOARDING_STRING, SEND_MAIL_ONBOARDING_APPROVE_ACTIVITY, onboardingString)); + service.sendMailOnboardingApprove(readOnboardingValue(objectMapper, onboardingString)); + } + + /** + * This is the activity function that gets invoked by the orchestrator function. + */ + @FunctionName(SEND_MAIL_CONFIRMATION_ACTIVITY) + public String sendMailConfirmation(@DurableActivityTrigger(name = "onboardingString") String onboardingString, final ExecutionContext context) { + context.getLogger().info(String.format(FORMAT_LOGGER_ONBOARDING_STRING, SEND_MAIL_CONFIRMATION_ACTIVITY, onboardingString)); + return onboardingString; + } + + private OnboardingStatus nextProcessOnboardingStatus(OnboardingStatus previous, WorkflowType workflowType) { + if(OnboardingStatus.REQUEST.equals(previous) && + (WorkflowType.FOR_APPROVE.equals(workflowType) || WorkflowType.FOR_APPROVE_PT.equals(workflowType))) { + return OnboardingStatus.TO_BE_VALIDATED; + } + + return OnboardingStatus.PENDING; + } +} diff --git a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/functions/utils/SaveOnboardingStatusInput.java b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/functions/utils/SaveOnboardingStatusInput.java new file mode 100644 index 000000000..db4ce9c01 --- /dev/null +++ b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/functions/utils/SaveOnboardingStatusInput.java @@ -0,0 +1,60 @@ +package it.pagopa.selfcare.onboarding.functions.utils; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; + +public class SaveOnboardingStatusInput { + + private String status; + private String onboardingId; + + public String getOnboardingId() { + return onboardingId; + } + + public String getStatus() { + return status; + } + + public void setOnboardingId(String onboardingId) { + this.onboardingId = onboardingId; + } + + public void setStatus(String status) { + this.status = status; + } + + public static SaveOnboardingStatusInput build(String onboardingId, String status) { + SaveOnboardingStatusInput statusInput = new SaveOnboardingStatusInput(); + statusInput.setStatus(status); + statusInput.setOnboardingId(onboardingId); + return statusInput; + } + + public static String buildAsJsonString(String onboardingId, String status) { + SaveOnboardingStatusInput statusInput = new SaveOnboardingStatusInput(); + statusInput.setStatus(status); + statusInput.setOnboardingId(onboardingId); + return jsonString(statusInput); + } + + public static String jsonString(SaveOnboardingStatusInput entity) { + + String jsonString; + try { + jsonString = new ObjectMapper().writeValueAsString(entity); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + return jsonString; + } + + + public static SaveOnboardingStatusInput readJsonString(String jsonString) { + try { + return new ObjectMapper().readValue(jsonString, SaveOnboardingStatusInput.class); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + } +} diff --git a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/mapper/InstitutionMapper.java b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/mapper/InstitutionMapper.java new file mode 100644 index 000000000..cb95b2817 --- /dev/null +++ b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/mapper/InstitutionMapper.java @@ -0,0 +1,15 @@ +package it.pagopa.selfcare.onboarding.mapper; + +import it.pagopa.selfcare.onboarding.entity.GeographicTaxonomy; +import it.pagopa.selfcare.onboarding.entity.Institution; +import org.mapstruct.Mapper; +import org.openapi.quarkus.core_json.model.GeoTaxonomies; +import org.openapi.quarkus.core_json.model.InstitutionRequest; + +@Mapper(componentModel = "cdi") +public interface InstitutionMapper { + + InstitutionRequest toInstitutionRequest(Institution institution); + + GeoTaxonomies toGeographicTaxonomy(GeographicTaxonomy geoTaxonomies); +} diff --git a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/mapper/UserMapper.java b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/mapper/UserMapper.java new file mode 100644 index 000000000..37528a9c9 --- /dev/null +++ b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/mapper/UserMapper.java @@ -0,0 +1,17 @@ +package it.pagopa.selfcare.onboarding.mapper; + +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.openapi.quarkus.core_json.model.Person; +import org.openapi.quarkus.user_registry_json.model.UserResource; + +@Mapper(componentModel = "cdi") +public interface UserMapper { + + @Mapping(source = "email.value", target = "email") + @Mapping(source = "name.value", target = "name") + @Mapping(source = "fiscalCode", target = "taxCode") + @Mapping(source = "familyName.value", target = "surname") + Person toPerson(UserResource userResource); + +} diff --git a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/repository/OnboardingRepository.java b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/repository/OnboardingRepository.java new file mode 100644 index 000000000..7223b63c6 --- /dev/null +++ b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/repository/OnboardingRepository.java @@ -0,0 +1,10 @@ +package it.pagopa.selfcare.onboarding.repository; + +import io.quarkus.mongodb.panache.PanacheMongoRepository; +import it.pagopa.selfcare.onboarding.entity.Onboarding; +import jakarta.enterprise.context.ApplicationScoped; + +@ApplicationScoped +public class OnboardingRepository implements PanacheMongoRepository { + +} diff --git a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/repository/TokenRepository.java b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/repository/TokenRepository.java new file mode 100644 index 000000000..bf88fa92b --- /dev/null +++ b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/repository/TokenRepository.java @@ -0,0 +1,17 @@ +package it.pagopa.selfcare.onboarding.repository; + +import io.quarkus.mongodb.panache.PanacheMongoRepository; +import it.pagopa.selfcare.onboarding.entity.Token; +import jakarta.enterprise.context.ApplicationScoped; + +import java.util.Optional; + +@ApplicationScoped +public class TokenRepository implements PanacheMongoRepository { + + public static final String ONBOARDING_ID_FIELD = "onboardingId"; + + public Optional findByOnboardingId(String onboardingId) { + return find(ONBOARDING_ID_FIELD, onboardingId).firstResultOptional(); + } +} diff --git a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/service/CompletionService.java b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/service/CompletionService.java new file mode 100644 index 000000000..888e847cf --- /dev/null +++ b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/service/CompletionService.java @@ -0,0 +1,12 @@ +package it.pagopa.selfcare.onboarding.service; + +import it.pagopa.selfcare.onboarding.entity.Onboarding; + +public interface CompletionService { + + String createInstitutionAndPersistInstitutionId(Onboarding onboarding); + + void persistOnboarding(Onboarding onboarding); + + void sendCompletedEmail(Onboarding onboarding); +} diff --git a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/service/CompletionServiceDefault.java b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/service/CompletionServiceDefault.java new file mode 100644 index 000000000..398436abd --- /dev/null +++ b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/service/CompletionServiceDefault.java @@ -0,0 +1,197 @@ +package it.pagopa.selfcare.onboarding.service; + +import it.pagopa.selfcare.onboarding.common.InstitutionType; +import it.pagopa.selfcare.onboarding.common.Origin; +import it.pagopa.selfcare.onboarding.entity.Institution; +import it.pagopa.selfcare.onboarding.entity.Onboarding; +import it.pagopa.selfcare.onboarding.entity.Token; +import it.pagopa.selfcare.onboarding.exception.GenericOnboardingException; +import it.pagopa.selfcare.onboarding.mapper.InstitutionMapper; +import it.pagopa.selfcare.onboarding.mapper.UserMapper; +import it.pagopa.selfcare.onboarding.repository.OnboardingRepository; +import it.pagopa.selfcare.onboarding.repository.TokenRepository; +import it.pagopa.selfcare.product.entity.Product; +import it.pagopa.selfcare.product.service.ProductService; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; +import org.apache.commons.lang3.StringUtils; +import org.eclipse.microprofile.rest.client.inject.RestClient; +import org.openapi.quarkus.core_json.api.InstitutionApi; +import org.openapi.quarkus.core_json.model.*; +import org.openapi.quarkus.user_registry_json.api.UserApi; +import org.openapi.quarkus.user_registry_json.model.CertifiableFieldResourceOfstring; +import org.openapi.quarkus.user_registry_json.model.UserResource; +import org.openapi.quarkus.user_registry_json.model.WorkContactResource; + +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.stream.Collectors; + +import static it.pagopa.selfcare.onboarding.common.PartyRole.MANAGER; +import static it.pagopa.selfcare.onboarding.common.ProductId.PROD_INTEROP; +import static it.pagopa.selfcare.onboarding.service.OnboardingService.USERS_FIELD_LIST; +import static it.pagopa.selfcare.onboarding.service.OnboardingService.USERS_WORKS_FIELD_LIST; +import static it.pagopa.selfcare.onboarding.utils.PdfMapper.workContactsKey; + +@ApplicationScoped +public class CompletionServiceDefault implements CompletionService { + + + @RestClient + @Inject + InstitutionApi institutionApi; + @RestClient + @Inject + UserApi userRegistryApi; + + @Inject + InstitutionMapper institutionMapper; + + @Inject + OnboardingRepository onboardingRepository; + + @Inject + TokenRepository tokenRepository; + + @Inject + UserMapper userMapper; + @Inject + NotificationService notificationService; + @Inject + ProductService productService; + + @Override + public String createInstitutionAndPersistInstitutionId(Onboarding onboarding) { + + Institution institution = onboarding.getInstitution(); + + InstitutionsResponse institutionsResponse = institutionApi.getInstitutionsUsingGET(institution.getTaxCode(), institution.getSubunitCode(), null, null); + if(Objects.nonNull(institutionsResponse.getInstitutions()) && institutionsResponse.getInstitutions().size() > 1){ + throw new GenericOnboardingException("List of institutions is ambiguous, it is empty or has more than one element!!"); + } + + InstitutionResponse institutionResponse = + Objects.isNull(institutionsResponse.getInstitutions()) || institutionsResponse.getInstitutions().isEmpty() + ? createInstitution(institution, onboarding.getProductId()) + : institutionsResponse.getInstitutions().get(0); + + onboardingRepository + .update("institution.id", institutionResponse.getId()) + .where("_id", onboarding.getOnboardingId()); + + return institutionResponse.getId(); + } + + /** + * Function that creates institution based on institution type and Origin, + * Origin indicates which is the indexes where data come from, for ex. IPA comes from index of Pubbliche Amministrazioni + * Look at https://pagopa.atlassian.net/wiki/spaces/SCP/pages/708804909/Glossario for more information about institution type and indexes + */ + private InstitutionResponse createInstitution(Institution institution, String productId) { + + if(InstitutionType.SA.equals(institution.getInstitutionType()) + && Origin.ANAC.equals(institution.getOrigin())) { + + return institutionApi.createInstitutionFromAnacUsingPOST(institutionMapper.toInstitutionRequest(institution)); + } + + if(InstitutionType.AS.equals(institution.getInstitutionType()) + && Origin.IVASS.equals(institution.getOrigin())) { + + return institutionApi.createInstitutionFromIvassUsingPOST(institutionMapper.toInstitutionRequest(institution)); + } + + if(InstitutionType.PG.equals(institution.getInstitutionType()) && + (Origin.INFOCAMERE.equals(institution.getOrigin()) || Origin.ADE.equals(institution.getOrigin()))) { + + return institutionApi.createInstitutionFromInfocamereUsingPOST(institutionMapper.toInstitutionRequest(institution)); + } + + if(InstitutionType.PA.equals(institution.getInstitutionType()) || + InstitutionType.SA.equals(institution.getInstitutionType()) || + (isGspAndProdInterop(institution.getInstitutionType(), productId) + && Origin.IPA.equals(institution.getOrigin()))) { + + InstitutionFromIpaPost fromIpaPost = new InstitutionFromIpaPost(); + fromIpaPost.setTaxCode(institution.getTaxCode()); + fromIpaPost.setGeographicTaxonomies(Optional.ofNullable(institution.getGeographicTaxonomies()) + .map(geographicTaxonomies -> geographicTaxonomies.stream().map(institutionMapper::toGeographicTaxonomy).toList()) + .orElse(List.of())); + if(Objects.nonNull(institution.getSubunitType())) { + fromIpaPost.setSubunitCode(institution.getSubunitCode()); + fromIpaPost.setSubunitType(InstitutionFromIpaPost.SubunitTypeEnum.valueOf(institution.getSubunitType().name())); + } + return institutionApi.createInstitutionFromIpaUsingPOST(fromIpaPost); + } + + return institutionApi.createInstitutionUsingPOST1(institutionMapper.toInstitutionRequest(institution)); + } + + private boolean isGspAndProdInterop(InstitutionType institutionType, String productId) { + return InstitutionType.GSP == institutionType + && productId.equals(PROD_INTEROP.getValue()); + } + + @Override + public void sendCompletedEmail(Onboarding onboarding) { + + String workContractId = workContactsKey.apply(onboarding.getOnboardingId()); + + List destinationMails = onboarding.getUsers().stream() + .filter(user -> MANAGER.equals(user.getRole())) + .map(userToOnboard -> userRegistryApi.findByIdUsingGET(USERS_FIELD_LIST, userToOnboard.getId())) + .filter(user -> Objects.nonNull(user.getWorkContacts()) + && user.getWorkContacts().containsKey(workContractId)) + .map(user -> user.getWorkContacts().get(workContractId)) + .filter(workContract -> StringUtils.isNotBlank(workContract.getEmail().getValue())) + .map(workContract -> workContract.getEmail().getValue()) + .collect(Collectors.toList()); + + destinationMails.add(onboarding.getInstitution().getDigitalAddress()); + + Product product = productService.getProductIsValid(onboarding.getProductId()); + + notificationService.sendCompletedEmail(destinationMails, product, onboarding.getInstitution().getInstitutionType()); + } + + + @Override + public void persistOnboarding(Onboarding onboarding) { + //Prepare data for request + InstitutionOnboardingRequest onboardingRequest = new InstitutionOnboardingRequest(); + onboardingRequest.setUsers(onboarding.getUsers().stream() + .map(user -> { + UserResource userResource = userRegistryApi.findByIdUsingGET(USERS_WORKS_FIELD_LIST, user.getId()); + String mailWork = Optional.ofNullable(userResource.getWorkContacts()) + .map(worksContract -> worksContract.get(workContactsKey.apply(onboarding.getOnboardingId()))) + .map(WorkContactResource::getEmail) + .map(CertifiableFieldResourceOfstring::getValue) + .orElseThrow(() -> new GenericOnboardingException("Work contract not found!")); + Person person = userMapper.toPerson(userResource); + person.setEmail(mailWork); + person.setProductRole(user.getProductRole()); + person.setRole(Person.RoleEnum.valueOf(user.getRole().name())); + return person; + }) + .toList() + ); + onboardingRequest.pricingPlan(onboarding.getPricingPlan()); + onboardingRequest.productId(onboarding.getProductId()); + onboardingRequest.setTokenId(onboarding.getOnboardingId()); + + if(Objects.nonNull(onboarding.getBilling())) { + BillingRequest billingRequest = new BillingRequest(); + billingRequest.recipientCode(onboarding.getBilling().getRecipientCode()); + billingRequest.publicServices(onboarding.getBilling().isPublicServices()); + billingRequest.vatNumber(onboarding.getBilling().getVatNumber()); + onboardingRequest.billing(billingRequest); + } + + //If contract exists we send the path of the contract + Optional optToken = tokenRepository.findByOnboardingId(onboarding.getOnboardingId()); + optToken.ifPresent(token -> onboardingRequest.setContractPath(token.getContractSigned())); + + institutionApi.onboardingInstitutionUsingPOST(onboarding.getInstitution().getId(), onboardingRequest); + } +} diff --git a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/service/ContractService.java b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/service/ContractService.java new file mode 100644 index 000000000..d95dff953 --- /dev/null +++ b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/service/ContractService.java @@ -0,0 +1,16 @@ +package it.pagopa.selfcare.onboarding.service; + +import it.pagopa.selfcare.onboarding.entity.Onboarding; +import org.openapi.quarkus.user_registry_json.model.UserResource; + +import java.io.File; +import java.util.List; + +public interface ContractService { + File createContractPDF(String contractTemplatePath, Onboarding onboarding, UserResource manager, List users, String productName); + + File loadContractPDF(String contractTemplatePath, String onboardingId, String productName); + File retrieveContractNotSigned(String onboardingId, String productName); + + File getLogoFile(); +} diff --git a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/service/ContractServiceDefault.java b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/service/ContractServiceDefault.java new file mode 100644 index 000000000..cec9464b9 --- /dev/null +++ b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/service/ContractServiceDefault.java @@ -0,0 +1,216 @@ +package it.pagopa.selfcare.onboarding.service; + +import com.openhtmltopdf.pdfboxout.PdfRendererBuilder; +import com.openhtmltopdf.svgsupport.BatikSVGDrawer; +import it.pagopa.selfcare.azurestorage.AzureBlobClient; +import it.pagopa.selfcare.onboarding.common.InstitutionType; +import it.pagopa.selfcare.onboarding.config.AzureStorageConfig; +import it.pagopa.selfcare.onboarding.config.PagoPaSignatureConfig; +import it.pagopa.selfcare.onboarding.crypto.PadesSignService; +import it.pagopa.selfcare.onboarding.crypto.entity.SignatureInformation; +import it.pagopa.selfcare.onboarding.entity.Institution; +import it.pagopa.selfcare.onboarding.entity.Onboarding; +import it.pagopa.selfcare.onboarding.exception.GenericOnboardingException; +import it.pagopa.selfcare.onboarding.utils.ClassPathStream; +import jakarta.enterprise.context.ApplicationScoped; +import org.apache.commons.text.StringSubstitutor; +import org.eclipse.microprofile.config.inject.ConfigProperty; +import org.jsoup.Jsoup; +import org.jsoup.helper.W3CDom; +import org.openapi.quarkus.user_registry_json.model.UserResource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +import static it.pagopa.selfcare.onboarding.common.ProductId.*; +import static it.pagopa.selfcare.onboarding.utils.GenericError.GENERIC_ERROR; +import static it.pagopa.selfcare.onboarding.utils.GenericError.UNABLE_TO_DOWNLOAD_FILE; +import static it.pagopa.selfcare.onboarding.utils.PdfMapper.*; +import static it.pagopa.selfcare.onboarding.utils.Utils.CONTRACT_FILENAME_FUNC; + +@ApplicationScoped +public class ContractServiceDefault implements ContractService { + + + private static final Logger log = LoggerFactory.getLogger(ContractServiceDefault.class); + public static final String PAGOPA_SIGNATURE_DISABLED = "disabled"; + + private final AzureStorageConfig azureStorageConfig; + private final AzureBlobClient azureBlobClient; + private final PadesSignService padesSignService; + private final PagoPaSignatureConfig pagoPaSignatureConfig; + + private final String logoPath; + + + public ContractServiceDefault(AzureStorageConfig azureStorageConfig, + AzureBlobClient azureBlobClient, PadesSignService padesSignService, + PagoPaSignatureConfig pagoPaSignatureConfig, + @ConfigProperty(name = "onboarding-functions.logo-path") String logoPath) { + this.azureStorageConfig = azureStorageConfig; + this.azureBlobClient = azureBlobClient; + this.padesSignService = padesSignService; + this.pagoPaSignatureConfig = pagoPaSignatureConfig; + this.logoPath = logoPath; + } + + /** + * Creates a PDF contract document from a given contract template file and institution data. + * Based on @contractTemplatePath it loads contract template as test and replace placeholder using a map with institution information. + * Contract will be stored at parties/docs/{onboardingId}/{productName}_accordo_di_adesione.pdf + * + * @param contractTemplatePath The file path to the contract template. + * @param onboarding Information related to the onboarding process. + * @param manager A user resource representing a valid manager. + * @param users A list of user resources. + * @param productName Product's name of onboarding. + * @return A File object representing the created PDF contract document. + * @throws GenericOnboardingException If an error occurs during PDF generation. + */ + @Override + public File createContractPDF(String contractTemplatePath, Onboarding onboarding, UserResource manager, List users, String productName) { + + log.info("START - createContractPdf for template: {}", contractTemplatePath); + // Generate a unique filename for the PDF. + final String builder = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")) + "_" + UUID.randomUUID() + "_contratto_interoperabilita."; + final String productId = onboarding.getProductId(); + final Institution institution = onboarding.getInstitution(); + + try { + // Read the content of the contract template file. + String contractTemplateText = azureBlobClient.getFileAsText(contractTemplatePath); + // Create a temporary PDF file to store the contract. + Path temporaryPdfFile = Files.createTempFile(builder, ".pdf"); + // Prepare common data for the contract document. + Map data = setUpCommonData(manager, users, onboarding); + + // Customize data based on the product and institution type. + if (PROD_PAGOPA.getValue().equalsIgnoreCase(productId) && + InstitutionType.PSP == institution.getInstitutionType()) { + setupPSPData(data, manager, onboarding); + } else if (PROD_IO.getValue().equalsIgnoreCase(productId) + || PROD_IO_PREMIUM.getValue().equalsIgnoreCase(productId) + || PROD_IO_SIGN.getValue().equalsIgnoreCase(productId)) { + setupProdIOData(onboarding, data, manager); + } else if (PROD_PN.getValue().equalsIgnoreCase(productId)){ + setupProdPNData(data, institution, onboarding.getBilling()); + } else if (PROD_INTEROP.getValue().equalsIgnoreCase(productId)){ + setupSAProdInteropData(data, institution); + } + log.debug("data Map for PDF: {}", data); + fillPDFAsFile(temporaryPdfFile, contractTemplateText, data); + + // Define the filename and path for storage. + final String filename = CONTRACT_FILENAME_FUNC.apply(productName); + final String path = String.format("%s%s", azureStorageConfig.contractPath(), onboarding.getOnboardingId()); + + File signedPath = signPdf(temporaryPdfFile.toFile(), institution.getDescription(), productId); + azureBlobClient.uploadFile(path, filename, Files.readAllBytes(signedPath.toPath())); + + return signedPath; + } catch (IOException e) { + throw new GenericOnboardingException(String.format("Can not create contract PDF, message: %s", e.getMessage())); + } + } + + private File signPdf(File pdf, String institutionDescription, String productId) throws IOException { + if(PAGOPA_SIGNATURE_DISABLED.equals(pagoPaSignatureConfig.source())) { + log.info("Skipping PagoPA contract pdf sign due to global disabling"); + return pdf; + } + + String signReason = pagoPaSignatureConfig.applyOnboardingTemplateReason() + .replace("${institutionName}", institutionDescription) + .replace("${productName}", productId); + + log.info("Signing input file {} using reason {}", pdf.getName(), signReason); + Path signedPdf = Files.createTempFile("signed", ".pdf"); + padesSignService.padesSign(pdf, signedPdf.toFile(), buildSignatureInfo(signReason)); + return signedPdf.toFile(); + } + + private SignatureInformation buildSignatureInfo(String signReason) { + return new SignatureInformation( + pagoPaSignatureConfig.signer(), + pagoPaSignatureConfig.location(), + signReason + ); + } + + @Override + public File loadContractPDF(String contractTemplatePath, String onboardingId, String productName) { + try { + File pdf = azureBlobClient.getFileAsPdf(contractTemplatePath); + + final String filename = CONTRACT_FILENAME_FUNC.apply(productName); + final String path = String.format("%s/%s", azureStorageConfig.contractPath(), onboardingId); + azureBlobClient.uploadFile(path, filename, Files.readAllBytes(pdf.toPath())); + + return pdf; + } catch (IOException e) { + throw new GenericOnboardingException(String.format("Can not load contract PDF, message: %s", e.getMessage())); + } + } + + private void fillPDFAsFile(Path file, String contractTemplate, Map data) { + log.debug("Getting PDF for HTML template..."); + String html = StringSubstitutor.replace(contractTemplate, data); + PdfRendererBuilder builder = new PdfRendererBuilder(); + builder.useFastMode(); + builder.useProtocolsStreamImplementation(url -> { + URI fullUri; + try { + fullUri = new URI(url); + return new ClassPathStream(fullUri.getPath()); + } catch (URISyntaxException e) { + log.error("URISintaxException in ClassPathStreamFactory: ",e); + throw new GenericOnboardingException(GENERIC_ERROR.getMessage(), GENERIC_ERROR.getCode()); + } + }, "classpath"); + var doc = Jsoup.parse(html, "UTF-8"); + var dom = W3CDom.convert(doc); + builder.withW3cDocument(dom, null); + builder.useSVGDrawer(new BatikSVGDrawer()); + + try(FileOutputStream fileOutputStream = new FileOutputStream(file.toFile())) { + builder.toStream(fileOutputStream); + builder.run(); + } catch (IOException e){ + throw new GenericOnboardingException(e.getMessage()); + } + + log.debug("PDF stream properly retrieved"); + } + + @Override + public File retrieveContractNotSigned(String onboardingId, String productName) { + final String filename = CONTRACT_FILENAME_FUNC.apply(productName); + final String path = String.format("%s%s/%s", azureStorageConfig.contractPath(), onboardingId, filename); + return azureBlobClient.getFileAsPdf(path); + } + + @Override + public File getLogoFile() { + StringBuilder stringBuilder = new StringBuilder(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"))); + stringBuilder.append("_").append(UUID.randomUUID()).append("_logo"); + try { + Path path = Files.createTempFile(stringBuilder.toString(), ".png"); + Files.writeString(path, azureBlobClient.getFileAsText(logoPath)); + return path.toFile(); + } catch (IOException e) { + throw new IllegalArgumentException(String.format(UNABLE_TO_DOWNLOAD_FILE.getMessage(), logoPath)); + } + } +} diff --git a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/service/NotificationService.java b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/service/NotificationService.java new file mode 100644 index 000000000..f433b6fc1 --- /dev/null +++ b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/service/NotificationService.java @@ -0,0 +1,20 @@ +package it.pagopa.selfcare.onboarding.service; + + +import it.pagopa.selfcare.onboarding.common.InstitutionType; +import it.pagopa.selfcare.product.entity.Product; + +import java.util.List; + +public interface NotificationService { + + void sendMailRegistration(String institutionName, String destination, String name, String username, String productName); + + void sendMailRegistrationApprove(String institutionName, String name, String username, String productName, String onboardingId); + + void sendMailOnboardingApprove(String institutionName, String name, String username, String productName, String onboardingId); + + void sendMailRegistrationWithContract(String onboardingId, String destination, String name, String username, String productName); + + void sendCompletedEmail(List destinationMails, Product product, InstitutionType institutionType); +} diff --git a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/service/NotificationServiceDefault.java b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/service/NotificationServiceDefault.java new file mode 100644 index 000000000..0d666f1d8 --- /dev/null +++ b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/service/NotificationServiceDefault.java @@ -0,0 +1,226 @@ +package it.pagopa.selfcare.onboarding.service; + +import com.fasterxml.jackson.databind.ObjectMapper; +import io.quarkus.mailer.Mail; +import io.quarkus.mailer.Mailer; +import it.pagopa.selfcare.azurestorage.AzureBlobClient; +import it.pagopa.selfcare.onboarding.common.InstitutionType; +import it.pagopa.selfcare.onboarding.config.MailTemplatePathConfig; +import it.pagopa.selfcare.onboarding.config.MailTemplatePlaceholdersConfig; +import it.pagopa.selfcare.onboarding.entity.MailTemplate; +import it.pagopa.selfcare.onboarding.exception.GenericOnboardingException; +import it.pagopa.selfcare.product.entity.Product; +import jakarta.enterprise.context.ApplicationScoped; +import org.apache.commons.text.StringSubstitutor; +import org.eclipse.microprofile.config.inject.ConfigProperty; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.util.*; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; + +import static it.pagopa.selfcare.onboarding.common.ProductId.PROD_FD; +import static it.pagopa.selfcare.onboarding.common.ProductId.PROD_FD_GARANTITO; +import static it.pagopa.selfcare.onboarding.utils.GenericError.ERROR_DURING_COMPRESS_FILE; +import static it.pagopa.selfcare.onboarding.utils.GenericError.ERROR_DURING_SEND_MAIL; + + +@ApplicationScoped +public class NotificationServiceDefault implements NotificationService { + + private static final Logger log = LoggerFactory.getLogger(NotificationServiceDefault.class); + + public static final String PAGOPA_LOGO_FILENAME = "pagopa-logo.png"; + private final MailTemplatePlaceholdersConfig templatePlaceholdersConfig; + private final MailTemplatePathConfig templatePathConfig; + private final AzureBlobClient azureBlobClient; + private final ObjectMapper objectMapper; + private final ContractService contractService; + private final String senderMail; + private final Boolean destinationMailTest; + private final String destinationMailTestAddress; + + private final String notificationAdminMail; + private final Mailer mailer; + + public NotificationServiceDefault(MailTemplatePlaceholdersConfig templatePlaceholdersConfig, MailTemplatePathConfig templatePathConfig, + AzureBlobClient azureBlobClient, ObjectMapper objectMapper, Mailer mailer, ContractService contractService, + @ConfigProperty(name = "onboarding-functions.notification-admin-email") String notificationAdminMail, + @ConfigProperty(name = "onboarding-functions.sender-mail") String senderMail, + @ConfigProperty(name = "onboarding-functions.destination-mail-test") Boolean destinationMailTest, + @ConfigProperty(name = "onboarding-functions.destination-mail-test-address") String destinationMailTestAddress) { + this.templatePlaceholdersConfig = templatePlaceholdersConfig; + this.templatePathConfig = templatePathConfig; + this.azureBlobClient = azureBlobClient; + this.objectMapper = objectMapper; + this.contractService = contractService; + this.senderMail = senderMail; + this.destinationMailTest = destinationMailTest; + this.destinationMailTestAddress = destinationMailTestAddress; + this.notificationAdminMail = notificationAdminMail; + this.mailer = mailer; + } + + @Override + public void sendMailRegistration(String institutionName, String destination, String name, String username, String productName) { + + // Prepare data for email + Map mailParameters = new HashMap<>(); + mailParameters.put(templatePlaceholdersConfig.productName(), productName); + Optional.ofNullable(name).ifPresent(value -> mailParameters.put(templatePlaceholdersConfig.notificationRequesterName(), value)); + Optional.ofNullable(username).ifPresent(value -> mailParameters.put(templatePlaceholdersConfig.notificationRequesterSurname(), value)); + mailParameters.put(templatePlaceholdersConfig.institutionDescription(), institutionName); + + sendMailWithFile(List.of(destination), templatePathConfig.registrationRequestPath(), mailParameters, productName, null); + } + + @Override + public void sendMailRegistrationApprove(String institutionName, String name, String username, String productName, String onboardingId) { + sendMailOnboardingOrRegistrationApprove(institutionName, name, username, productName, onboardingId, templatePathConfig.registrationApprovePath()); + } + + @Override + public void sendMailOnboardingApprove(String institutionName, String name, String username, String productName, String onboardingId) { + sendMailOnboardingOrRegistrationApprove(institutionName, name, username, productName, onboardingId, templatePathConfig.onboardingApprovePath()); + } + + + private void sendMailOnboardingOrRegistrationApprove(String institutionName, String name, String username, String productName, String onboardingId, String templatePath) { + // Prepare data for email + Map mailParameters = new HashMap<>(); + mailParameters.put(templatePlaceholdersConfig.productName(), productName); + Optional.ofNullable(name).ifPresent(value -> mailParameters.put(templatePlaceholdersConfig.notificationRequesterName(), value)); + Optional.ofNullable(username).ifPresent(value -> mailParameters.put(templatePlaceholdersConfig.notificationRequesterSurname(), value)); + mailParameters.put(templatePlaceholdersConfig.institutionDescription(), institutionName); + StringBuilder adminApproveLink = new StringBuilder(templatePlaceholdersConfig.adminLink()); + mailParameters.put(templatePlaceholdersConfig.confirmTokenName(), adminApproveLink.append(onboardingId).toString()); + + sendMailWithFile(List.of(notificationAdminMail), templatePath, mailParameters, productName, null); + } + + @Override + public void sendMailRegistrationWithContract(String onboardingId, String destination, String name, String username, String productName) { + + // Retrieve PDF contract from storage + File contract = contractService.retrieveContractNotSigned(onboardingId, productName); + // Create ZIP file that contains contract + final String fileNamePdf = String.format("%s_accordo_adesione.pdf", productName); + final String fileNameZip = String.format("%s_accordo_adesione.zip", productName); + byte[] contractZipData = null; + + try { + byte[] contractData = Files.readAllBytes(contract.toPath()); + contractZipData = zipBytes(fileNamePdf, contractData); + } catch (IOException e) { + throw new RuntimeException(e); + } + + // Prepare data for email + Map mailParameters = new HashMap<>(); + mailParameters.put(templatePlaceholdersConfig.productName(), productName); + Optional.ofNullable(name).ifPresent(value -> mailParameters.put(templatePlaceholdersConfig.userName(), value)); + Optional.ofNullable(username).ifPresent(value -> mailParameters.put(templatePlaceholdersConfig.userSurname(), value)); + mailParameters.put(templatePlaceholdersConfig.rejectTokenName(), templatePlaceholdersConfig.rejectTokenPlaceholder() + onboardingId); + mailParameters.put(templatePlaceholdersConfig.confirmTokenName(), templatePlaceholdersConfig.confirmTokenPlaceholder() + onboardingId); + + FileMailData fileMailData = new FileMailData(); + fileMailData.contentType = "application/zip"; + fileMailData.data = contractZipData; + fileMailData.name = fileNameZip; + + sendMailWithFile(List.of(destination), templatePathConfig.registrationPath(), mailParameters, productName, fileMailData); + } + + @Override + public void sendCompletedEmail(List destinationMails, Product product, InstitutionType institutionType) { + + String templatePath; + + if(InstitutionType.PT.equals(institutionType)) { + templatePath = templatePathConfig.completePathPt(); + } else { + templatePath =product.getId().equals(PROD_FD.getValue()) || product.getId().equals(PROD_FD_GARANTITO.getValue()) + ? templatePathConfig.completePathFd() + : templatePathConfig.completePath(); + } + + byte[] logoData = null; + + try { + logoData = Files.readAllBytes(contractService.getLogoFile().toPath()); + } catch (IOException e) { + throw new GenericOnboardingException(e.getMessage()); + } + + Map mailParameter = new HashMap<>(); + mailParameter.put(templatePlaceholdersConfig.completeProductName(), product.getTitle()); + mailParameter.put(templatePlaceholdersConfig.completeSelfcareName(), templatePlaceholdersConfig.completeSelfcarePlaceholder()); + + FileMailData fileMailData = new FileMailData(); + fileMailData.contentType = "image/png"; + fileMailData.data = logoData; + fileMailData.name = PAGOPA_LOGO_FILENAME; + + sendMailWithFile(destinationMails, templatePath, mailParameter, product.getTitle(), fileMailData); + } + + private void sendMailWithFile(List destinationMail, String templateName, Map mailParameters, String prefixSubject, FileMailData fileMailData) { + try { + + // Dev mode send mail to test digital address + String destination = destinationMailTest + ? destinationMailTestAddress + : destinationMail.get(0); + + log.info("Sending mail to {}, with prefixSubject {}", destination, prefixSubject); + String template = azureBlobClient.getFileAsText(templateName); + MailTemplate mailTemplate = objectMapper.readValue(template, MailTemplate.class); + String html = StringSubstitutor.replace(mailTemplate.getBody(), mailParameters); + + final String subject = String.format("%s: %s", prefixSubject, mailTemplate.getSubject()); + + Mail mail = Mail + .withHtml(destination, subject, html) + .setFrom(senderMail); + + if(Objects.nonNull(fileMailData)) { + mail.addAttachment(fileMailData.name, fileMailData.data, fileMailData.contentType); + } + + mailer.send(mail); + + log.info("End of sending mail to {}, with subject {}", destination, subject); + } catch (Exception e) { + log.error(String.format("%s: %s", ERROR_DURING_SEND_MAIL, e.getMessage())); + throw new GenericOnboardingException(ERROR_DURING_SEND_MAIL.getMessage()); + } + } + + public byte[] zipBytes(String filename, byte[] data) { + try (ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ZipOutputStream zos = new ZipOutputStream(baos)) { + ZipEntry entry = new ZipEntry(filename); + + zos.putNextEntry(entry); + zos.write(data); + zos.closeEntry(); + zos.finish(); + return baos.toByteArray(); + } catch (IOException e) { + log.error(String.format(ERROR_DURING_COMPRESS_FILE.getMessage(), filename), e); + throw new RuntimeException(String.format(ERROR_DURING_COMPRESS_FILE.getMessage(), filename)); + } + } + + static class FileMailData { + byte[] data; + String name; + String contentType; + } + +} diff --git a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/service/OnboardingService.java b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/service/OnboardingService.java new file mode 100644 index 000000000..b3a75b25b --- /dev/null +++ b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/service/OnboardingService.java @@ -0,0 +1,210 @@ +package it.pagopa.selfcare.onboarding.service; + +import eu.europa.esig.dss.enumerations.DigestAlgorithm; +import eu.europa.esig.dss.model.DSSDocument; +import eu.europa.esig.dss.model.FileDocument; +import it.pagopa.selfcare.onboarding.common.OnboardingStatus; +import it.pagopa.selfcare.onboarding.common.PartyRole; +import it.pagopa.selfcare.onboarding.entity.Onboarding; +import it.pagopa.selfcare.onboarding.entity.Token; +import it.pagopa.selfcare.onboarding.entity.User; +import it.pagopa.selfcare.onboarding.exception.GenericOnboardingException; +import it.pagopa.selfcare.onboarding.common.TokenType; +import it.pagopa.selfcare.product.entity.Product; +import it.pagopa.selfcare.product.service.ProductService; +import it.pagopa.selfcare.onboarding.repository.OnboardingRepository; +import it.pagopa.selfcare.onboarding.repository.TokenRepository; +import it.pagopa.selfcare.onboarding.utils.GenericError; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; +import org.bson.types.ObjectId; +import org.eclipse.microprofile.rest.client.inject.RestClient; +import org.openapi.quarkus.user_registry_json.api.UserApi; +import org.openapi.quarkus.user_registry_json.model.CertifiableFieldResourceOfstring; +import org.openapi.quarkus.user_registry_json.model.UserResource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.time.LocalDateTime; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +import static it.pagopa.selfcare.onboarding.utils.Utils.CONTRACT_FILENAME_FUNC; + +@ApplicationScoped +public class OnboardingService { + + private static final Logger log = LoggerFactory.getLogger(OnboardingService.class); + + public static final String USERS_FIELD_LIST = "fiscalCode,familyName,name"; + public static final String USERS_WORKS_FIELD_LIST = "fiscalCode,familyName,name,workContacts"; + public static final String USER_REQUEST_DOES_NOT_FOUND = "User request does not found for onboarding %s"; + + @RestClient + @Inject + UserApi userRegistryApi; + @Inject + NotificationService notificationService; + @Inject + ContractService contractService; + @Inject + ProductService productService; + + @Inject + OnboardingRepository repository; + + @Inject + TokenRepository tokenRepository; + + public Optional getOnboarding(String onboardingId) { + return repository.findByIdOptional(new ObjectId(onboardingId)) + .map(onboarding -> { + onboarding.setOnboardingId(onboarding.getId().toString()); + return onboarding; + }); + } + + public void createContract(Onboarding onboarding) { + String validManagerId = getValidManagerId(onboarding.getUsers()); + UserResource manager = userRegistryApi.findByIdUsingGET(USERS_WORKS_FIELD_LIST,validManagerId); + + List delegates = onboarding.getUsers() + .stream() + .filter(userToOnboard -> PartyRole.MANAGER != userToOnboard.getRole()) + .map(userToOnboard -> userRegistryApi.findByIdUsingGET(USERS_WORKS_FIELD_LIST, userToOnboard.getId())).collect(Collectors.toList()); + + Product product = productService.getProductIsValid(onboarding.getProductId()); + contractService.createContractPDF(product.getContractTemplatePath(), onboarding, manager, delegates, product.getTitle()); + } + + public void loadContract(Onboarding onboarding) { + Product product = productService.getProductIsValid(onboarding.getProductId()); + contractService.loadContractPDF(product.getContractTemplatePath(), onboarding.getId().toHexString(), product.getTitle()); + } + public void saveTokenWithContract(Onboarding onboarding) { + + // Skip if token already exists + Optional optToken = tokenRepository.findByOnboardingId(onboarding.getOnboardingId()); + if(optToken.isPresent()) { + log.debug("Token has already exists for onboarding {}", onboarding.getId()); + return; + } + + Product product = productService.getProductIsValid(onboarding.getProductId()); + + // Load PDF contract and create digest + File contract = contractService.retrieveContractNotSigned(onboarding.getOnboardingId(), product.getTitle()); + DSSDocument document = new FileDocument(contract); + String digest = document.getDigest(DigestAlgorithm.SHA256); + + saveToken(onboarding, product, digest); + } + + private void saveToken(Onboarding onboarding, Product product, String digest) { + + log.debug("creating Token for onboarding {} ...", onboarding.getId()); + + // Persist token entity + Token token = new Token(); + token.setOnboardingId(onboarding.getOnboardingId()); + token.setContractTemplate(product.getContractTemplatePath()); + token.setContractVersion(product.getContractTemplateVersion()); + token.setContractFilename(CONTRACT_FILENAME_FUNC.apply(product.getTitle())); + token.setCreatedAt(LocalDateTime.now()); + token.setUpdatedAt(LocalDateTime.now()); + token.setProductId(onboarding.getProductId()); + token.setChecksum(digest); + token.setType(TokenType.INSTITUTION); + + tokenRepository.persist(token); + } + + public void sendMailRegistration(Onboarding onboarding) { + + SendMailInput sendMailInput = builderWithProductAndUserRequest(onboarding); + + notificationService.sendMailRegistration(onboarding.getInstitution().getDescription(), + onboarding.getInstitution().getDigitalAddress(), + sendMailInput.userRequestName, sendMailInput.userRequestSurname, + sendMailInput.product.getTitle()); + + } + + public void sendMailRegistrationWithContract(Onboarding onboarding) { + + SendMailInput sendMailInput = builderWithProductAndUserRequest(onboarding); + + notificationService.sendMailRegistrationWithContract(onboarding.getOnboardingId(), + onboarding.getInstitution().getDigitalAddress(), + sendMailInput.userRequestName, sendMailInput.userRequestSurname, + sendMailInput.product.getTitle()); + } + + public void sendMailRegistrationWithContractWhenApprove(Onboarding onboarding) { + + SendMailInput sendMailInput = builderWithProductAndUserRequest(onboarding); + + notificationService.sendMailRegistrationWithContract(onboarding.getOnboardingId(), + onboarding.getInstitution().getDigitalAddress(), + onboarding.getInstitution().getDescription(), "", + sendMailInput.product.getTitle()); + } + + public void sendMailRegistrationApprove(Onboarding onboarding) { + + SendMailInput sendMailInput = builderWithProductAndUserRequest(onboarding); + + notificationService.sendMailRegistrationApprove(onboarding.getInstitution().getDescription(), + sendMailInput.userRequestName, sendMailInput.userRequestSurname, + sendMailInput.product.getTitle(), + onboarding.getOnboardingId()); + + } + + public void sendMailOnboardingApprove(Onboarding onboarding) { + + SendMailInput sendMailInput = builderWithProductAndUserRequest(onboarding); + + notificationService.sendMailOnboardingApprove(onboarding.getInstitution().getDescription(), + sendMailInput.userRequestName, sendMailInput.userRequestSurname, + sendMailInput.product.getTitle(), + onboarding.getOnboardingId()); + } + + public String getValidManagerId(List users) { + log.debug("START - getOnboardingValidManager for users list size: {}", users.size()); + + return users.stream() + .filter(userToOnboard -> PartyRole.MANAGER == userToOnboard.getRole()) + .map(User::getId) + .findAny() + .orElseThrow(() -> new GenericOnboardingException(GenericError.MANAGER_NOT_FOUND_GENERIC_ERROR.getMessage(), + GenericError.MANAGER_NOT_FOUND_GENERIC_ERROR.getCode())); + } + + private SendMailInput builderWithProductAndUserRequest(Onboarding onboarding) { + SendMailInput sendMailInput = new SendMailInput(); + sendMailInput.product = productService.getProduct(onboarding.getProductId()); + + // Retrieve user request name and surname + UserResource userRequest = Optional.ofNullable(userRegistryApi.findByIdUsingGET(USERS_FIELD_LIST, onboarding.getUserRequestUid())) + .orElseThrow(() -> new GenericOnboardingException(String.format(USER_REQUEST_DOES_NOT_FOUND, onboarding.getId()))); + sendMailInput.userRequestName = Optional.ofNullable(userRequest.getName()).map(CertifiableFieldResourceOfstring::getValue).orElse(""); + sendMailInput.userRequestSurname = Optional.ofNullable(userRequest.getFamilyName()).map(CertifiableFieldResourceOfstring::getValue).orElse(""); + return sendMailInput; + } + + public void savePendingState(String onboardingId, OnboardingStatus status) { + repository + .update("status", status.name()) + .where("_id", onboardingId); + } + + static class SendMailInput { + Product product; + String userRequestName; + String userRequestSurname; + } +} diff --git a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/utils/ClassPathStream.java b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/utils/ClassPathStream.java new file mode 100644 index 000000000..207a0a7a7 --- /dev/null +++ b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/utils/ClassPathStream.java @@ -0,0 +1,28 @@ +package it.pagopa.selfcare.onboarding.utils; + +import com.openhtmltopdf.extend.FSStream; + +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.nio.charset.StandardCharsets; +import java.util.Objects; + +public class ClassPathStream implements FSStream { + + private final String uri; + + public ClassPathStream(String path) { + this.uri = path; + } + + @Override + public InputStream getStream() { + return this.getClass().getResourceAsStream(uri); + } + + @Override + public Reader getReader() { + return new InputStreamReader(Objects.requireNonNull(this.getClass().getResourceAsStream(uri)), StandardCharsets.UTF_8); + } +} diff --git a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/utils/GenericError.java b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/utils/GenericError.java new file mode 100644 index 000000000..497a9a717 --- /dev/null +++ b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/utils/GenericError.java @@ -0,0 +1,81 @@ +package it.pagopa.selfcare.onboarding.utils; + +public enum GenericError { + + + MANAGER_NOT_FOUND_GENERIC_ERROR("0033", "No onboarded managers"), + GET_USER_INSTITUTION_RELATIONSHIP_ERROR("0023", "Error while retrieving user relationships"), + GET_INSTITUTION_BY_ID_ERROR("0040", Constants.ERROR_WHILE_RETRIEVING_INSTITUTION_HAVING_EXTERNAL_ID), + GET_INSTITUTION_BY_EXTERNAL_ID_ERROR("0041", Constants.ERROR_WHILE_RETRIEVING_INSTITUTION_HAVING_EXTERNAL_ID), + INSTITUTION_MANAGER_ERROR("0042", Constants.ERROR_WHILE_RETRIEVING_INSTITUTION_HAVING_EXTERNAL_ID), + INSTITUTION_BILLING_ERROR("0044", Constants.ERROR_WHILE_RETRIEVING_INSTITUTION_HAVING_EXTERNAL_ID), + CREATE_INSTITUTION_ERROR("0037", "Error while creating requested institution"), + ONBOARDING_OPERATION_ERROR("0017", "Error while performing onboarding operation"), + CREATE_DELEGATION_ERROR("0027", "Error while creating requested delegation"), + ONBOARDING_VERIFICATION_ERROR("0015", "Error while verifying onboarding"), + GETTING_ONBOARDING_INFO_ERROR("0016", "Error while getting onboarding info"), + GET_PRODUCTS_ERROR("0031", "Error while getting products"), + CONTRACT_PATH_ERROR("0100", "Contract Path is required"), + MANAGER_EMAIL_NOT_FOUND("0101", "Manager email not found"), + VERIFY_TOKEN_FAILED("0041", "Something went wrong trying to verify token"), + + SIGNATURE_NOT_FOUND("002-1007", "No signature found"), + SIGNATURE_VALIDATION_ERROR("002-1004", "The tax code related to signature does not match anyone contained in the relationships"), + ORIGINAL_DOCUMENT_NOT_FOUND("002-1008", "Original document information not found"), + + INSTITUTION_NOT_ONBOARDED("002-1009", "Institution having externalId %s has already onboarded for product %s"), + DOCUMENT_VALIDATION_FAIL("002-1000", "Error trying to validate document, due: %s"), + INVALID_SIGNATURE_FORMS("002-1003", "Only CAdES signature form is admitted. Invalid signatures forms detected: %s"), + INVALIDATE_ONBOARDING_ERROR("0022", "Error while invalidating onboarding"), + CONFIRM_ONBOARDING_ERROR("0021", "Error while confirming onboarding"), + INVALID_DOCUMENT_SIGNATURE("002-1002", "Document signature is invalid"), + INVALID_CONTRACT_DIGEST("002-1001", "Invalid file digest"), + + INVALIDE_SIGNATURE_TAX_CODE_FORMAT("002-1005", "Invalid tax code format found in digital signature"), + TAX_CODE_NOT_FOUND_IN_SIGNATURE("002-1006", "No tax code has been found in digital signature"), + INVALID_SIGNATURE_TAX_CODE("002-1004", "The tax code related to signature does not match anyone contained in the relationships"), + UNABLE_TO_DOWNLOAD_FILE("1102", "Unable to download template %s"), + INVALID_SIGNATURE("002-1005", "Signature not valid: "), + ERROR_DURING_SEND_MAIL("0000", "Error during send mail"), + ERROR_DURING_UPLOAD_FILE("0000", "Error during upload file %s"), + + ERROR_DURING_DELETED_FILE("0000", "Error during deleted file %s"), + ERROR_DURING_DOWNLOAD_FILE("0000", "Error during download file %s"), + ERROR_DURING_COMPRESS_FILE("0000", "Error compressing the file %s"), + RETRIEVING_USER_RELATIONSHIP_ERROR("0023", "Error while retrieving user relationships"), + ACTIVATE_RELATIONSHIP_ERROR("0024", "Error while activating relationship"), + SUSPEND_RELATIONSHIP_ERROR("0025", "Error while suspending relationship"), + PUT_INSTITUTION_ERROR("0051", "Error while updating institution"), + ONBOARDING_SUBDELEGATES_ERROR("0019", "Error while onboarding subdelegates"), + ONBOARDING_OPERATORS_ERROR("0020", "Error while onboarding operators"), + ONBOARDING_LEGALS_ERROR("0018", "Error while onboarding legals"), + RETRIEVE_GEO_TAXONOMIES_ERROR("0050", "Error while retrieving institution geographic taxonomy"), + GET_RELATIONSHIP_ERROR("0028", "Error while getting relationship"), + CREATE_PERSON_ERROR("0009", "Error while creating person"), + GET_INSTITUTION_ATTRIBUTES_ERROR("0022", "Error while getting party attributes"), + GET_INSTITUTION_BY_GEOTAXONOMY_ERROR("0053", "Error while searching institutions related to given geoTaxonomies"), + GET_INSTITUTION_BY_PRODUCTID_ERROR("0053", "Error while searching institutions related to given productId"), + VERIFY_USER_ERROR("0000", "Error while searching institutions related to given productId"), + GET_USER_ERROR("0000", "Error while searching user given UserID"), + GENERIC_ERROR("0000", "Generic Error"); + private final String code; + private final String detail; + + + GenericError(String code, String detail) { + this.code = code; + this.detail = detail; + } + + public String getCode() { + return code; + } + + public String getMessage() { + return detail; + } + + private static class Constants { + public static final String ERROR_WHILE_RETRIEVING_INSTITUTION_HAVING_EXTERNAL_ID = "Error while retrieving institution having externalId %s"; + } +} diff --git a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/utils/PdfMapper.java b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/utils/PdfMapper.java new file mode 100644 index 000000000..2612ba2f9 --- /dev/null +++ b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/utils/PdfMapper.java @@ -0,0 +1,251 @@ +package it.pagopa.selfcare.onboarding.utils; + +import it.pagopa.selfcare.onboarding.common.InstitutionType; +import it.pagopa.selfcare.onboarding.common.Origin; +import it.pagopa.selfcare.onboarding.common.PricingPlan; +import it.pagopa.selfcare.onboarding.entity.Billing; +import it.pagopa.selfcare.onboarding.entity.GeographicTaxonomy; +import it.pagopa.selfcare.onboarding.entity.Institution; +import it.pagopa.selfcare.onboarding.entity.Onboarding; +import it.pagopa.selfcare.onboarding.exception.GenericOnboardingException; +import org.openapi.quarkus.user_registry_json.model.CertifiableFieldResourceOfstring; +import org.openapi.quarkus.user_registry_json.model.UserResource; + +import java.util.*; +import java.util.function.Function; + +import static it.pagopa.selfcare.onboarding.common.ProductId.PROD_IO; +import static it.pagopa.selfcare.onboarding.utils.GenericError.MANAGER_EMAIL_NOT_FOUND; + + +public class PdfMapper { + + private static final String[] PLAN_LIST = {"C1", "C2", "C3", "C4", "C5", "C6", "C7"}; + public static final String INSTITUTION_REA = "institutionREA"; + public static final String INSTITUTION_NAME = "institutionName"; + public static final String INSTITUTION_SHARE_CAPITAL = "institutionShareCapital"; + public static final String INSTITUTION_BUSINESS_REGISTER_PLACE = "institutionBusinessRegisterPlace"; + public static final String PRICING_PLAN_PREMIUM = "pricingPlanPremium"; + public static final String PRICING_PLAN_PREMIUM_CHECKBOX = "pricingPlanPremiumCheckbox"; + public static final String PRICING_PLAN_FAST_CHECKBOX = "pricingPlanFastCheckbox"; + public static final String PRICING_PLAN_BASE_CHECKBOX = "pricingPlanBaseCheckbox"; + public static final String PRICING_PLAN = "pricingPlan"; + public static final String INSTITUTION_REGISTER_LABEL_VALUE = "institutionRegisterLabelValue"; + + public static final Function workContactsKey = onboardingId -> String.format("obg_%s", onboardingId); + public static final String ORIGIN_ID_LABEL = "
  • codice di iscrizione all’Indice delle Pubbliche Amministrazioni e dei gestori di pubblici servizi (I.P.A.) ${originId}
  • "; + + + public static Map setUpCommonData(UserResource manager, List users, Onboarding onboarding) { + + Institution institution = onboarding.getInstitution(); + Billing billing = onboarding.getBilling(); + List geographicTaxonomies = Optional.ofNullable(onboarding.getInstitution().getGeographicTaxonomies()) + .map(geoTaxonomies -> geoTaxonomies.stream().map(GeographicTaxonomy::getDesc).toList()) + .orElse(List.of()); + + String mailManager = getMailManager(manager, onboarding.getOnboardingId()); + if (Objects.isNull(mailManager)) { + throw new GenericOnboardingException(MANAGER_EMAIL_NOT_FOUND.getMessage(), MANAGER_EMAIL_NOT_FOUND.getCode()); + } + + Map map = new HashMap<>(); + map.put(INSTITUTION_NAME, institution.getDescription()); + map.put("address", institution.getAddress()); + map.put("institutionTaxCode", institution.getTaxCode()); + map.put("zipCode", institution.getZipCode()); + map.put("managerName", getStringValue(manager.getName())); + map.put("managerSurname", getStringValue(manager.getFamilyName())); + map.put("originId", Optional.ofNullable(institution.getOrigin()).map(Origin::name).orElse("")); + map.put("institutionMail", institution.getDigitalAddress()); + map.put("managerTaxCode", manager.getFiscalCode()); + map.put("managerEmail", mailManager); + map.put("delegates", delegatesToText(users, workContactsKey.apply(onboarding.getOnboardingId()))); + map.put("institutionType", decodeInstitutionType(institution.getInstitutionType())); + map.put("institutionVatNumber", Optional.ofNullable(billing).map(Billing::getVatNumber).orElse("")); + + if (!geographicTaxonomies.isEmpty()) { + map.put("institutionGeoTaxonomies", geographicTaxonomies); + } + + map.put("parentInfo", Objects.nonNull(institution.getParentDescription()) ? " ente centrale " + institution.getParentDescription() : ""); + return map; + } + + private static String getMailManager(UserResource manager, String onboardingId){ + if(Objects.isNull(manager.getWorkContacts()) + || !manager.getWorkContacts().containsKey(workContactsKey.apply(onboardingId))) { + return null; + } + + return Optional.ofNullable(manager.getWorkContacts() + .get(workContactsKey.apply(onboardingId)) + .getEmail()) + .map(CertifiableFieldResourceOfstring::getValue) + .orElse(null); + } + + public static void setupPSPData(Map map, UserResource validManager, Onboarding onboarding) { + Institution institution = onboarding.getInstitution(); + if (institution.getPaymentServiceProvider() != null) { + map.put("legalRegisterNumber", institution.getPaymentServiceProvider().getLegalRegisterNumber()); + map.put("legalRegisterName", institution.getPaymentServiceProvider().getLegalRegisterName()); + map.put("vatNumberGroup", institution.getPaymentServiceProvider().isVatNumberGroup() ? "partita iva di gruppo" : ""); + map.put("institutionRegister", institution.getPaymentServiceProvider().getBusinessRegisterNumber()); + map.put("institutionAbi", institution.getPaymentServiceProvider().getAbiCode()); + } + if (institution.getDataProtectionOfficer() != null) { + map.put("dataProtectionOfficerAddress", institution.getDataProtectionOfficer().getAddress()); + map.put("dataProtectionOfficerEmail", institution.getDataProtectionOfficer().getEmail()); + map.put("dataProtectionOfficerPec", institution.getDataProtectionOfficer().getPec()); + } + + Optional.ofNullable(getMailManager(validManager, onboarding.getOnboardingId())) + .ifPresent(mail -> map.put("managerPEC", mail)); + } + + public static void setupProdIOData(Onboarding onboarding, Map map, UserResource validManager) { + final Institution institution = onboarding.getInstitution(); + final InstitutionType institutionType = institution.getInstitutionType(); + + map.put("institutionTypeCode", institution.getInstitutionType()); + decodePricingPlan(onboarding.getPricingPlan(), onboarding.getProductId(), map); + + map.put("originIdLabelValue", Origin.IPA.equals(institution.getOrigin()) ? ORIGIN_ID_LABEL : ""); + + addInstitutionRegisterLabelValue(institution, map); + if (onboarding.getBilling() != null) { + map.put("institutionRecipientCode",onboarding.getBilling().getRecipientCode()); + } + + String underscore = "_______________"; + map.put("GPSinstitutionName", InstitutionType.GSP == institutionType ? institution.getDescription() : underscore); + map.put("GPSmanagerName", InstitutionType.GSP == institutionType ? getStringValue(validManager.getName()) : underscore); + map.put("GPSmanagerSurname", InstitutionType.GSP == institutionType ? getStringValue(validManager.getFamilyName()) : underscore); + map.put("GPSmanagerTaxCode", InstitutionType.GSP == institutionType ? validManager.getFiscalCode() : underscore); + + map.put(INSTITUTION_REA, Optional.ofNullable(institution.getRea()).orElse(underscore)); + map.put(INSTITUTION_SHARE_CAPITAL, Optional.ofNullable(institution.getShareCapital()).orElse(underscore)); + map.put(INSTITUTION_BUSINESS_REGISTER_PLACE, Optional.ofNullable(institution.getBusinessRegisterPlace()).orElse(underscore)); + + addPricingPlan(onboarding.getPricingPlan(), map); + } + + public static void setupSAProdInteropData(Map map, Institution institution) { + + String underscore = "_______________"; + map.put(INSTITUTION_REA, Optional.ofNullable(institution.getRea()).orElse(underscore)); + map.put(INSTITUTION_SHARE_CAPITAL, Optional.ofNullable(institution.getShareCapital()).orElse(underscore)); + map.put(INSTITUTION_BUSINESS_REGISTER_PLACE, Optional.ofNullable(institution.getBusinessRegisterPlace()).orElse(underscore)); + //override originId to not fill ipa code in case of SA + if(InstitutionType.SA.equals(institution.getInstitutionType())) + map.put("originId", underscore); + } + + public static void setupProdPNData(Map map, Institution institution, Billing billing) { + + addInstitutionRegisterLabelValue(institution, map); + if (billing != null) { + map.put("institutionRecipientCode", billing.getRecipientCode()); + } + } + + + private static void addPricingPlan(String pricingPlan, Map map) { + if (Objects.nonNull(pricingPlan) && Arrays.stream(PLAN_LIST).anyMatch(s -> s.equalsIgnoreCase(pricingPlan))) { + map.put(PRICING_PLAN_PREMIUM, pricingPlan.replace("C", "")); + map.put(PRICING_PLAN_PREMIUM_CHECKBOX, "X"); + } else { + map.put(PRICING_PLAN_PREMIUM, ""); + map.put(PRICING_PLAN_PREMIUM_CHECKBOX, ""); + } + + map.put("pricingPlanPremiumBase", Optional.ofNullable(pricingPlan).orElse("")); + + if (Objects.nonNull(pricingPlan) && "C0".equalsIgnoreCase(pricingPlan)) { + map.put(PRICING_PLAN_PREMIUM_CHECKBOX, "X"); + } else { + map.put(PRICING_PLAN_PREMIUM_CHECKBOX, ""); + } + } + + private static void addInstitutionRegisterLabelValue(Institution institution, Map map) { + if (institution.getPaymentServiceProvider() != null + && Objects.nonNull(institution.getPaymentServiceProvider().getBusinessRegisterNumber())) { + map.put("number", institution.getPaymentServiceProvider().getBusinessRegisterNumber()); + map.put(INSTITUTION_REGISTER_LABEL_VALUE, "
  • codice di iscrizione all’Indice delle Pubbliche Amministrazioni e dei gestori di pubblici servizi (I.P.A.) ${number}
  • \n"); + } else { + map.put(INSTITUTION_REGISTER_LABEL_VALUE, ""); + } + } + + private static void decodePricingPlan(String pricingPlan, String productId, Map map) { + if (PricingPlan.FA.name().equals(pricingPlan)) { + map.put(PRICING_PLAN_FAST_CHECKBOX, "X"); + map.put(PRICING_PLAN_BASE_CHECKBOX, ""); + map.put(PRICING_PLAN_PREMIUM_CHECKBOX, ""); + map.put(PRICING_PLAN, PricingPlan.FA.getValue()); + return; + } + if (PROD_IO.getValue().equalsIgnoreCase(productId)) { + map.put(PRICING_PLAN_FAST_CHECKBOX, ""); + map.put(PRICING_PLAN_BASE_CHECKBOX, "X"); + map.put(PRICING_PLAN_PREMIUM_CHECKBOX, ""); + map.put(PRICING_PLAN, PricingPlan.BASE.getValue()); + } else { + map.put(PRICING_PLAN_FAST_CHECKBOX, ""); + map.put(PRICING_PLAN_BASE_CHECKBOX, ""); + map.put(PRICING_PLAN_PREMIUM_CHECKBOX, "X"); + map.put(PRICING_PLAN, PricingPlan.PREMIUM.getValue()); + } + } + + private static String decodeInstitutionType(InstitutionType institutionType) { + switch (institutionType) { + case PA: + return "Pubblica Amministrazione"; + case GSP: + return "Gestore di servizi pubblici"; + case PT: + return "Partner tecnologico"; + case SCP: + return "Società a controllo pubblico"; + case PSP: + return "Prestatori Servizi di Pagamento"; + default: + return ""; + + } + } + + private static String delegatesToText(List users, String workContractId) { + StringBuilder builder = new StringBuilder(); + users.forEach(user -> { + builder + .append("
    ") + .append("

    Nome e Cognome: ") + .append(getStringValue(user.getName())).append(" ") + .append(getStringValue(user.getFamilyName())) + .append(" 

    \n") + .append("

    Codice Fiscale: ") + .append(user.getFiscalCode()) + .append("

    \n") + .append("

    Amm.ne/Ente/Società:

    \n") + .append("

    Qualifica/Posizione:

    \n") + .append("

    e-mail: "); + + if (Objects.nonNull(user.getWorkContacts()) && user.getWorkContacts().containsKey(workContractId)) { + builder.append(getStringValue(user.getWorkContacts().get(workContractId).getEmail())); + } + + builder.append(" 

    \n") + .append("

    PEC:  

    \n") + .append("
    "); + }); + return builder.toString(); + } + + private static String getStringValue(CertifiableFieldResourceOfstring resourceOfString) { + return Optional.ofNullable(resourceOfString).map(CertifiableFieldResourceOfstring::getValue).orElse(""); + } +} diff --git a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/utils/Utils.java b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/utils/Utils.java new file mode 100644 index 000000000..21eb3ae6a --- /dev/null +++ b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/utils/Utils.java @@ -0,0 +1,38 @@ +package it.pagopa.selfcare.onboarding.utils; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import it.pagopa.selfcare.onboarding.entity.Onboarding; +import it.pagopa.selfcare.onboarding.exception.FunctionOrchestratedException; +import org.apache.commons.lang3.StringUtils; + +import java.util.function.Function; + +public class Utils { + + public static final String PDF_FORMAT_FILENAME = "%s_accordo_adesione.pdf"; + + public static final Function CONTRACT_FILENAME_FUNC = + productName -> String.format(PDF_FORMAT_FILENAME, StringUtils.stripAccents(productName.replaceAll("\\s+","_"))); + + + + public static Onboarding readOnboardingValue(ObjectMapper objectMapper, String onboardingString) { + try { + return objectMapper.readValue(onboardingString, Onboarding.class); + } catch (JsonProcessingException e) { + throw new FunctionOrchestratedException(e); + } + } + + public static String getOnboardingString(ObjectMapper objectMapper, Onboarding onboarding) { + + String onboardingString; + try { + onboardingString = objectMapper.writeValueAsString(onboarding); + } catch (JsonProcessingException e) { + throw new FunctionOrchestratedException(e); + } + return onboardingString; + } +} diff --git a/apps/onboarding-functions/src/main/openapi/core.json b/apps/onboarding-functions/src/main/openapi/core.json new file mode 100644 index 000000000..9a817aab6 --- /dev/null +++ b/apps/onboarding-functions/src/main/openapi/core.json @@ -0,0 +1,8099 @@ +{ + "openapi" : "3.0.3", + "info" : { + "title" : "selc-ms-core", + "version" : "1.0-SNAPSHOT" + }, + "servers" : [ { + "url" : "{url}:{port}{basePath}", + "variables" : { + "url" : { + "default" : "http://localhost" + }, + "port" : { + "default" : "80" + }, + "basePath" : { + "default" : "" + } + } + } ], + "tags" : [ { + "name" : "Delegation", + "description" : "Delegation Controller" + }, { + "name" : "External", + "description" : "External Controller" + }, { + "name" : "Institution", + "description" : "Institution Controller" + }, { + "name" : "Management", + "description" : "Management Controller" + }, { + "name" : "Migration", + "description" : "Crud Controller" + }, { + "name" : "Onboarding", + "description" : "Onboarding Controller" + }, { + "name" : "Persons", + "description" : "User Controller" + }, { + "name" : "Token", + "description" : "Token Controller" + }, { + "name" : "scheduler", + "description" : "Scheduler Controller" + } ], + "paths" : { + "/migration/institution" : { + "post" : { + "tags" : [ "Migration" ], + "summary" : "${swagger.mscore.migration.save.institution}", + "description" : "${swagger.mscore.migration.save.institution}", + "operationId" : "createInstitutionUsingPOST", + "requestBody" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/MigrationInstitution" + } + } + } + }, + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/Institution" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "409" : { + "description" : "Conflict", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/migration/institution/{id}" : { + "get" : { + "tags" : [ "Migration" ], + "summary" : "${swagger.mscore.migration.findbyid.institution}", + "description" : "${swagger.mscore.migration.findbyid.institution}", + "operationId" : "findInstitutionByIdUsingGET", + "parameters" : [ { + "name" : "id", + "in" : "path", + "description" : "id", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/Institution" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + }, + "delete" : { + "tags" : [ "Migration" ], + "summary" : "${swagger.mscore.migration.delete.institution}", + "description" : "${swagger.mscore.migration.delete.institution}", + "operationId" : "deleteInstitutionUsingDELETE", + "parameters" : [ { + "name" : "id", + "in" : "path", + "description" : "id", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "204" : { + "description" : "No Content", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/Institution" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "409" : { + "description" : "Conflict", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/migration/institutions" : { + "get" : { + "tags" : [ "Migration" ], + "summary" : "${swagger.mscore.migration.find.institution}", + "description" : "${swagger.mscore.migration.find.institution}", + "operationId" : "findInstitutionsUsingGET", + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "application/json" : { + "schema" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/Institution" + } + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/migration/token" : { + "post" : { + "tags" : [ "Migration" ], + "summary" : "${swagger.mscore.migration.save.token}", + "description" : "${swagger.mscore.migration.save.token}", + "operationId" : "createTokenUsingPOST", + "requestBody" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/MigrationToken" + } + } + } + }, + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/Token" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "409" : { + "description" : "Conflict", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/migration/token/{id}" : { + "get" : { + "tags" : [ "Migration" ], + "summary" : "${swagger.mscore.migration.findbyid.token}", + "description" : "${swagger.mscore.migration.findbyid.token}", + "operationId" : "findTokenByIdUsingGET", + "parameters" : [ { + "name" : "id", + "in" : "path", + "description" : "id", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/Token" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + }, + "delete" : { + "tags" : [ "Migration" ], + "summary" : "${swagger.mscore.migration.delete.token}", + "description" : "${swagger.mscore.migration.delete.token}", + "operationId" : "deleteTokenUsingDELETE", + "parameters" : [ { + "name" : "id", + "in" : "path", + "description" : "id", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "204" : { + "description" : "No Content", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/Token" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "409" : { + "description" : "Conflict", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/migration/tokens" : { + "get" : { + "tags" : [ "Migration" ], + "summary" : "${swagger.mscore.migration.find.token}", + "description" : "${swagger.mscore.migration.find.token}", + "operationId" : "findTokensUsingGET", + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "application/json" : { + "schema" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/Token" + } + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/migration/user" : { + "post" : { + "tags" : [ "Migration" ], + "summary" : "${swagger.mscore.migration.save.user}", + "description" : "${swagger.mscore.migration.save.user}", + "operationId" : "createUserUsingPOST", + "requestBody" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/MigrationOnboardedUser" + } + } + } + }, + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/OnboardedUser" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "409" : { + "description" : "Conflict", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/migration/user/{id}" : { + "get" : { + "tags" : [ "Migration" ], + "summary" : "${swagger.mscore.migration.findbyid.user}", + "description" : "${swagger.mscore.migration.findbyid.user}", + "operationId" : "findUserByIdUsingGET", + "parameters" : [ { + "name" : "id", + "in" : "path", + "description" : "id", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/OnboardedUser" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + }, + "delete" : { + "tags" : [ "Migration" ], + "summary" : "${swagger.mscore.migration.delete.user}", + "description" : "${swagger.mscore.migration.delete.user}", + "operationId" : "deleteUserUsingDELETE", + "parameters" : [ { + "name" : "id", + "in" : "path", + "description" : "id", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "204" : { + "description" : "No Content", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/OnboardedUser" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "409" : { + "description" : "Conflict", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/migration/users" : { + "get" : { + "tags" : [ "Migration" ], + "summary" : "${swagger.mscore.migration.find.token}", + "description" : "${swagger.mscore.migration.find.token}", + "operationId" : "findUsersUsingGET", + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "application/json" : { + "schema" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/OnboardedUser" + } + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/delegations" : { + "get" : { + "tags" : [ "Delegation", "external-v2", "support" ], + "summary" : "Retrieve institution's delegations", + "description" : "Retrieve institution's delegations", + "operationId" : "getDelegationsUsingGET", + "parameters" : [ { + "name" : "institutionId", + "in" : "query", + "description" : "The internal identifier of the institution", + "required" : false, + "style" : "form", + "schema" : { + "type" : "string" + } + }, { + "name" : "brokerId", + "in" : "query", + "description" : "The internal identifier of the institution", + "required" : false, + "style" : "form", + "schema" : { + "type" : "string" + } + }, { + "name" : "productId", + "in" : "query", + "description" : "Product's unique identifier", + "required" : false, + "style" : "form", + "schema" : { + "type" : "string" + } + }, { + "name" : "mode", + "in" : "query", + "description" : "Mode (full or normal) to retreieve institution's delegations", + "required" : false, + "style" : "form", + "schema" : { + "type" : "string", + "enum" : [ "FULL", "NORMAL" ] + } + } ], + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "application/json" : { + "schema" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/DelegationResponse" + } + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + }, + "post" : { + "tags" : [ "Delegation" ], + "summary" : "Create an association between institution id and technical partner", + "description" : "Create an association between institution id and technical partner", + "operationId" : "createDelegationUsingPOST", + "requestBody" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/DelegationRequest" + } + } + } + }, + "responses" : { + "201" : { + "description" : "Created", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/DelegationResponse" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "409" : { + "description" : "Conflict", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/delegations/from-taxcode" : { + "post" : { + "tags" : [ "Delegation" ], + "summary" : "Create an association between institution and technical partner using taxCode for both instead of internal id. It is useful when we don't know institution's internal id.", + "description" : "Create an association between institution and technical partner using taxCode for both instead of internal id. It is useful when we don't know institution's internal id.", + "operationId" : "createDelegationFromInstitutionsTaxCodeUsingPOST", + "requestBody" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/DelegationRequestFromTaxcode" + } + } + } + }, + "responses" : { + "201" : { + "description" : "Created", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/DelegationResponse" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "409" : { + "description" : "Conflict", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/external/institutions" : { + "get" : { + "tags" : [ "External" ], + "summary" : "Gets the corresponding institution using internal institution id", + "description" : "Gets the corresponding institution using internal institution id", + "operationId" : "retrieveInstitutionByIdsUsingGET", + "parameters" : [ { + "name" : "ids", + "in" : "query", + "description" : "List of Institution to onboard", + "required" : true, + "style" : "form", + "explode" : true, + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "application/json" : { + "schema" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/InstitutionResponse" + } + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/external/institutions/pn-pg" : { + "post" : { + "tags" : [ "External" ], + "summary" : "create an institution (PG) using external institution id fetching data from info-camere", + "description" : "create an institution (PG) using external institution id fetching data from info-camere", + "operationId" : "createPnPgInstitutionUsingPOST", + "requestBody" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/CreatePnPgInstitutionRequest" + } + } + } + }, + "responses" : { + "201" : { + "description" : "Created", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/InstitutionPnPgResponse" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "409" : { + "description" : "Conflict", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/external/institutions/{externalId}" : { + "get" : { + "tags" : [ "External" ], + "summary" : "Gets institution using external institution id", + "description" : "Gets institution using external institution id", + "operationId" : "getByExternalIdUsingGET", + "parameters" : [ { + "name" : "externalId", + "in" : "path", + "description" : "Institution's unique external identifier", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/InstitutionResponse" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/external/institutions/{externalId}/geotaxonomies" : { + "get" : { + "tags" : [ "External" ], + "summary" : "retrieves the geographic taxonomies related to Institution.", + "description" : "retrieves the geographic taxonomies related to Institution.", + "operationId" : "retrieveInstitutionGeoTaxonomiesByExternalIdUsingGET", + "parameters" : [ { + "name" : "externalId", + "in" : "path", + "description" : "Institution's unique external identifier", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "application/json" : { + "schema" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/GeographicTaxonomies" + } + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/external/institutions/{externalId}/products" : { + "get" : { + "tags" : [ "External" ], + "summary" : "retrieves the products related to Institution", + "description" : "retrieves the products related to Institution", + "operationId" : "retrieveInstitutionProductsByExternalIdUsingGET", + "parameters" : [ { + "name" : "externalId", + "in" : "path", + "description" : "Institution's unique external identifier", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + }, { + "name" : "states", + "in" : "query", + "description" : "states", + "required" : false, + "style" : "form", + "explode" : true, + "schema" : { + "type" : "string", + "enum" : [ "ACTIVE", "DELETED", "PENDING", "REJECTED", "SUSPENDED", "TOBEVALIDATED" ] + } + } ], + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/OnboardedProducts" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/external/institutions/{externalId}/products/{productId}/billing" : { + "get" : { + "tags" : [ "External" ], + "summary" : "retrieves the billing data related to the institution even if the current user is not related to the institution/product", + "description" : "retrieves the billing data related to the institution even if the current user is not related to the institution/product", + "operationId" : "getBillingInstitutionByExternalIdUsingGET", + "parameters" : [ { + "name" : "externalId", + "in" : "path", + "description" : "Institution's unique external identifier", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + }, { + "name" : "productId", + "in" : "path", + "description" : "Product's unique identifier", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/InstitutionBillingResponse" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/external/institutions/{externalId}/products/{productId}/manager" : { + "get" : { + "tags" : [ "External" ], + "summary" : "retrieves the manager related to the institution even if the current user is not related to the institution/product", + "description" : "retrieves the manager related to the institution even if the current user is not related to the institution/product", + "operationId" : "getManagerInstitutionByExternalIdUsingGET", + "parameters" : [ { + "name" : "externalId", + "in" : "path", + "description" : "Institution's unique external identifier", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + }, { + "name" : "productId", + "in" : "path", + "description" : "Product's unique identifier", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/InstitutionManagerResponse" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/external/institutions/{externalId}/relationships" : { + "get" : { + "tags" : [ "External" ], + "summary" : "returns the relationships related to the institution", + "description" : "returns the relationships related to the institution", + "operationId" : "getUserInstitutionRelationshipsByExternalIdUsingGET", + "parameters" : [ { + "name" : "externalId", + "in" : "path", + "description" : "Institution's unique external identifier", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + }, { + "name" : "personId", + "in" : "query", + "description" : "personId", + "required" : false, + "style" : "form", + "schema" : { + "type" : "string" + } + }, { + "name" : "roles", + "in" : "query", + "description" : "roles", + "required" : false, + "style" : "form", + "explode" : true, + "schema" : { + "type" : "string", + "enum" : [ "DELEGATE", "MANAGER", "OPERATOR", "SUB_DELEGATE" ] + } + }, { + "name" : "states", + "in" : "query", + "description" : "states", + "required" : false, + "style" : "form", + "explode" : true, + "schema" : { + "type" : "string", + "enum" : [ "ACTIVE", "DELETED", "PENDING", "REJECTED", "SUSPENDED", "TOBEVALIDATED" ] + } + }, { + "name" : "products", + "in" : "query", + "description" : "products", + "required" : false, + "style" : "form", + "explode" : true, + "schema" : { + "type" : "string" + } + }, { + "name" : "productRoles", + "in" : "query", + "description" : "productRoles", + "required" : false, + "style" : "form", + "explode" : true, + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "application/json" : { + "schema" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/RelationshipResult" + } + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/institutions" : { + "get" : { + "tags" : [ "Institution", "external-v2", "support" ], + "summary" : "Gets institutions filtering by taxCode and/or subunitCode", + "description" : "Gets institutions filtering by taxCode and/or subunitCode", + "operationId" : "getInstitutionsUsingGET", + "parameters" : [ { + "name" : "taxCode", + "in" : "query", + "description" : "Institution's tax code", + "required" : false, + "style" : "form", + "schema" : { + "type" : "string" + } + }, { + "name" : "subunitCode", + "in" : "query", + "description" : "Institution's subunit code", + "required" : false, + "style" : "form", + "schema" : { + "type" : "string" + } + }, { + "name" : "origin", + "in" : "query", + "description" : "origin", + "required" : false, + "style" : "form", + "schema" : { + "type" : "string" + } + }, { + "name" : "originId", + "in" : "query", + "description" : "originId", + "required" : false, + "style" : "form", + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/InstitutionsResponse" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + }, + "post" : { + "tags" : [ "Institution" ], + "summary" : "create an institution using external institution id without fetching data from party-registry or info-camere", + "description" : "create an institution using external institution id without fetching data from party-registry or info-camere", + "operationId" : "createInstitutionUsingPOST_1", + "requestBody" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/InstitutionRequest" + } + } + } + }, + "responses" : { + "201" : { + "description" : "Created", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/InstitutionResponse" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "409" : { + "description" : "Conflict", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/institutions/from-anac" : { + "post" : { + "tags" : [ "Institution" ], + "summary" : "${swagger.mscore.institution.create.from-anac}", + "description" : "${swagger.mscore.institution.create.from-anac}", + "operationId" : "createInstitutionFromAnacUsingPOST", + "requestBody" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/InstitutionRequest" + } + } + } + }, + "responses" : { + "201" : { + "description" : "Created", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/InstitutionResponse" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "409" : { + "description" : "Conflict", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/institutions/from-infocamere" : { + "post" : { + "tags" : [ "Institution" ], + "summary" : "create an institution from infocamere registry", + "description" : "create an institution from infocamere registry", + "operationId" : "createInstitutionFromInfocamereUsingPOST", + "requestBody" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/InstitutionRequest" + } + } + } + }, + "responses" : { + "201" : { + "description" : "Created", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/InstitutionResponse" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "409" : { + "description" : "Conflict", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/institutions/from-ipa" : { + "post" : { + "tags" : [ "Institution" ], + "summary" : "create an institution from ipa registry", + "description" : "create an institution from ipa registry", + "operationId" : "createInstitutionFromIpaUsingPOST", + "requestBody" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/InstitutionFromIpaPost" + } + } + } + }, + "responses" : { + "201" : { + "description" : "Created", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/InstitutionResponse" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "409" : { + "description" : "Conflict", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/institutions/from-ivass" : { + "post" : { + "tags" : [ "Institution" ], + "summary" : "create an institution from ivass CSV", + "description" : "create an institution from ivass CSV", + "operationId" : "createInstitutionFromIvassUsingPOST", + "requestBody" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/InstitutionRequest" + } + } + } + }, + "responses" : { + "201" : { + "description" : "Created", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/InstitutionResponse" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "409" : { + "description" : "Conflict", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/institutions/from-pda" : { + "post" : { + "tags" : [ "Institution" ], + "summary" : "${swagger.mscore.institution.create.from-pda}", + "description" : "create an institution from ipa registry", + "operationId" : "createInstitutionFromPdaUsingPOST", + "requestBody" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/PdaInstitutionRequest" + } + } + } + }, + "responses" : { + "201" : { + "description" : "Created", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/InstitutionResponse" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "409" : { + "description" : "Conflict", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/institutions/insert/{externalId}" : { + "post" : { + "tags" : [ "Institution" ], + "summary" : "create an institution using external institution id without fetching data from party-registry or info-camere", + "description" : "create an institution using external institution id without fetching data from party-registry or info-camere", + "operationId" : "createInstitutionRawUsingPOST", + "parameters" : [ { + "name" : "externalId", + "in" : "path", + "description" : "Institution's unique external identifier", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + } ], + "requestBody" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/InstitutionRequest" + } + } + } + }, + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/InstitutionResponse" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "409" : { + "description" : "Conflict", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "deprecated" : true, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/institutions/onboarded/{productId}" : { + "post" : { + "tags" : [ "Institution" ], + "summary" : "Retrieve list of institution which logged user can onboard", + "description" : "Retrieve list of institution which logged user can onboard", + "operationId" : "getValidInstitutionToOnboardUsingPOST", + "parameters" : [ { + "name" : "productId", + "in" : "path", + "description" : "productId", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + } ], + "requestBody" : { + "content" : { + "application/json" : { + "schema" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/InstitutionToOnboard" + } + } + } + } + }, + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "application/json" : { + "schema" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/InstitutionToOnboard" + } + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "409" : { + "description" : "Conflict", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/institutions/pg" : { + "post" : { + "tags" : [ "Institution" ], + "summary" : "create an institution (PG) using external institution id fetching data from info-camere", + "description" : "create an institution (PG) using external institution id fetching data from info-camere", + "operationId" : "createPgInstitutionUsingPOST", + "requestBody" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/CreatePgInstitutionRequest" + } + } + } + }, + "responses" : { + "201" : { + "description" : "Created", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/InstitutionResponse" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "409" : { + "description" : "Conflict", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/institutions/products/{productId}" : { + "get" : { + "tags" : [ "Institution" ], + "summary" : "Gets institutions filtering onboardings by product id", + "description" : "Gets institutions filtering onboardings by product id", + "operationId" : "findFromProductUsingGET", + "parameters" : [ { + "name" : "productId", + "in" : "path", + "description" : "Product's unique identifier", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + }, { + "name" : "page", + "in" : "query", + "description" : "${swagger.mscore.page.number}", + "required" : false, + "style" : "form", + "schema" : { + "type" : "integer", + "format" : "int32" + } + }, { + "name" : "size", + "in" : "query", + "description" : "${swagger.mscore.page.size}", + "required" : false, + "style" : "form", + "schema" : { + "type" : "integer", + "format" : "int32" + } + } ], + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/InstitutionOnboardingListResponse" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/institutions/{externalId}" : { + "post" : { + "tags" : [ "Institution" ], + "summary" : "create an institution (PA) using external institution id fetching data from party-registry", + "description" : "create an institution (PA) using external institution id fetching data from party-registry", + "operationId" : "createInstitutionByExternalIdUsingPOST", + "parameters" : [ { + "name" : "externalId", + "in" : "path", + "description" : "Institution's unique external identifier", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "201" : { + "description" : "Created", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/InstitutionResponse" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "409" : { + "description" : "Conflict", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "deprecated" : true, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/institutions/{id}" : { + "get" : { + "tags" : [ "Institution", "external-v2" ], + "summary" : "Gets the corresponding institution using internal institution id", + "description" : "Gets the corresponding institution using internal institution id", + "operationId" : "retrieveInstitutionByIdUsingGET", + "parameters" : [ { + "name" : "id", + "in" : "path", + "description" : "The internal identifier of the institution", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/InstitutionResponse" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + }, + "put" : { + "tags" : [ "Institution" ], + "summary" : "update institution data of given institution", + "description" : "update institution data of given institution", + "operationId" : "updateInstitutionUsingPUT", + "parameters" : [ { + "name" : "id", + "in" : "path", + "description" : "The internal identifier of the institution", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + } ], + "requestBody" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/InstitutionPut" + } + } + } + }, + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/InstitutionResponse" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "403" : { + "description" : "Forbidden", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + }, + "head" : { + "tags" : [ "Management" ], + "summary" : "verify if Institution exists for a given ID", + "description" : "verify if Institution exists for a given ID", + "operationId" : "verifyInstitutionUsingHEAD", + "parameters" : [ { + "name" : "id", + "in" : "path", + "description" : "The internal identifier of the institution", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "204" : { + "description" : "No Content" + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "deprecated" : true, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/institutions/{id}/geotaxonomies" : { + "get" : { + "tags" : [ "Institution" ], + "summary" : "retrieves the geographic taxonomies this institution is related to", + "description" : "retrieves the geographic taxonomies this institution is related to", + "operationId" : "retrieveInstitutionGeoTaxonomiesUsingGET", + "parameters" : [ { + "name" : "id", + "in" : "path", + "description" : "The internal identifier of the institution", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "application/json" : { + "schema" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/GeographicTaxonomies" + } + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/institutions/{id}/onboarding" : { + "post" : { + "tags" : [ "Institution" ], + "summary" : "The service adds users to the registry if they are not present and associates them with the institution and product contained in the body", + "description" : "The service adds users to the registry if they are not present and associates them with the institution and product contained in the body", + "operationId" : "onboardingInstitutionUsingPOST", + "parameters" : [ { + "name" : "id", + "in" : "path", + "description" : "id", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + } ], + "requestBody" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/InstitutionOnboardingRequest" + } + } + } + }, + "responses" : { + "201" : { + "description" : "Created", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/InstitutionResponse" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "409" : { + "description" : "Conflict", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/institutions/{id}/products" : { + "get" : { + "tags" : [ "Institution" ], + "summary" : "retrieves the insistitution's related products.", + "description" : "retrieves the insistitution's related products.", + "operationId" : "retrieveInstitutionProductsUsingGET", + "parameters" : [ { + "name" : "id", + "in" : "path", + "description" : "The internal identifier of the institution", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + }, { + "name" : "states", + "in" : "query", + "description" : "List of Relationship state for filter products", + "required" : false, + "style" : "form", + "explode" : true, + "schema" : { + "type" : "string", + "enum" : [ "ACTIVE", "DELETED", "PENDING", "REJECTED", "SUSPENDED", "TOBEVALIDATED" ] + } + } ], + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/OnboardedProducts" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/institutions/{id}/relationships" : { + "get" : { + "tags" : [ "Institution" ], + "summary" : "returns the relationships related to the institution", + "description" : "returns the relationships related to the institution", + "operationId" : "getUserInstitutionRelationshipsUsingGET", + "parameters" : [ { + "name" : "id", + "in" : "path", + "description" : "The internal identifier of the institution", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + }, { + "name" : "personId", + "in" : "query", + "description" : "personId", + "required" : false, + "style" : "form", + "schema" : { + "type" : "string" + } + }, { + "name" : "roles", + "in" : "query", + "description" : "roles", + "required" : false, + "style" : "form", + "explode" : true, + "schema" : { + "type" : "string", + "enum" : [ "DELEGATE", "MANAGER", "OPERATOR", "SUB_DELEGATE" ] + } + }, { + "name" : "states", + "in" : "query", + "description" : "states", + "required" : false, + "style" : "form", + "explode" : true, + "schema" : { + "type" : "string", + "enum" : [ "ACTIVE", "DELETED", "PENDING", "REJECTED", "SUSPENDED", "TOBEVALIDATED" ] + } + }, { + "name" : "products", + "in" : "query", + "description" : "products", + "required" : false, + "style" : "form", + "explode" : true, + "schema" : { + "type" : "string" + } + }, { + "name" : "productRoles", + "in" : "query", + "description" : "productRoles", + "required" : false, + "style" : "form", + "explode" : true, + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "application/json" : { + "schema" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/RelationshipResult" + } + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/institutions/{institutionId}/onboardings" : { + "get" : { + "tags" : [ "Institution", "external-v2" ], + "summary" : "${swagger.mscore.institution.info}", + "description" : "${swagger.mscore.institution.info}", + "operationId" : "getOnboardingsInstitutionUsingGET", + "parameters" : [ { + "name" : "institutionId", + "in" : "path", + "description" : "The internal identifier of the institution", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + }, { + "name" : "productId", + "in" : "query", + "description" : "productId", + "required" : false, + "style" : "form", + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/OnboardingsResponse" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/institutions/{institutionId}/products/{productId}/createdAt" : { + "put" : { + "tags" : [ "Institution" ], + "summary" : "The service updates the createdAt field for the institution-product pair", + "description" : "The service updates the createdAt field for the institution-product pair", + "operationId" : "updateCreatedAtUsingPUT", + "parameters" : [ { + "name" : "institutionId", + "in" : "path", + "description" : "The internal identifier of the institution", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + }, { + "name" : "productId", + "in" : "path", + "description" : "Product's unique identifier", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + }, { + "name" : "createdAt", + "in" : "query", + "description" : "The createdAt date", + "required" : true, + "style" : "form", + "schema" : { + "type" : "string", + "format" : "date-time" + } + } ], + "responses" : { + "200" : { + "description" : "OK" + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "403" : { + "description" : "Forbidden", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/institutions/{institutionId}/users" : { + "get" : { + "tags" : [ "Institution", "support" ], + "summary" : "getInstitutionUsers", + "description" : "Retrieve institution's users", + "operationId" : "getInstitutionUsersUsingGET", + "parameters" : [ { + "name" : "institutionId", + "in" : "path", + "description" : "Institution's unique identifier", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "application/json" : { + "schema" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/UserInfoResponse" + } + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/institutions/{productId}/brokers/{institutionType}" : { + "get" : { + "tags" : [ "Institution" ], + "summary" : "Retrieve institution brokers", + "description" : "${swagger.mscore.institutions.getInstitutionBrokers}", + "operationId" : "getInstitutionBrokersUsingGET", + "parameters" : [ { + "name" : "productId", + "in" : "path", + "description" : "Product's unique identifier", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + }, { + "name" : "institutionType", + "in" : "path", + "description" : "Institution's type", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string", + "enum" : [ "AS", "GSP", "PA", "PG", "PSP", "PT", "SA", "SCP" ] + } + } ], + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "application/json" : { + "schema" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/BrokerResponse" + } + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/bulk/institutions" : { + "post" : { + "tags" : [ "Management" ], + "summary" : "Gets the corresponding institution using internal institution id", + "description" : "Gets the corresponding institution using internal institution id", + "operationId" : "retrieveInstitutionByIdsUsingPOST", + "requestBody" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/BulkPartiesSeed" + } + } + } + }, + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "*/*" : { + "schema" : { + "$ref" : "#/components/schemas/BulkInstitutions" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "409" : { + "description" : "Conflict", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/external/institutions/product/{productId}" : { + "get" : { + "tags" : [ "Management" ], + "summary" : "Retrieves Institutions by product ID", + "description" : "Retrieves Institutions by product ID", + "operationId" : "getInstitutionByProductIdUsingGET", + "parameters" : [ { + "name" : "productId", + "in" : "path", + "description" : "Product's unique identifier", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "204" : { + "description" : "No Content", + "content" : { + "*/*" : { + "schema" : { + "$ref" : "#/components/schemas/InstitutionListResponse" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "deprecated" : true, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/institutions/bygeotaxonomies" : { + "get" : { + "tags" : [ "Management" ], + "summary" : "Retrieves a collection of institutions having one or more geographic taxonomies", + "description" : "Retrieves a collection of institutions having one or more geographic taxonomies", + "operationId" : "getInstitutionByGeotaxonomiesUsingGET", + "parameters" : [ { + "name" : "geoTaxonomies", + "in" : "query", + "description" : "Comma separated list of the geographic taxonomies to search", + "required" : true, + "style" : "form", + "schema" : { + "type" : "string" + } + }, { + "name" : "searchMode", + "in" : "query", + "description" : "The search mode to perform, as default 'any'", + "required" : false, + "style" : "form", + "schema" : { + "type" : "string", + "enum" : [ "ALL", "ANY", "EXACT" ] + } + } ], + "responses" : { + "204" : { + "description" : "No Content", + "content" : { + "*/*" : { + "schema" : { + "$ref" : "#/components/schemas/InstitutionListResponse" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "deprecated" : true, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/institutions/{id}/attributes" : { + "get" : { + "tags" : [ "Management" ], + "summary" : "returns the attributes of the identified institution, if any.", + "description" : "returns the attributes of the identified institution, if any.", + "operationId" : "getInstitutionAttributesUsingGET", + "parameters" : [ { + "name" : "id", + "in" : "path", + "description" : "The internal identifier of the institution", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "204" : { + "description" : "No Content", + "content" : { + "*/*" : { + "schema" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/AttributesResponse" + } + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "deprecated" : true, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/management/external/institutions/{externalId}" : { + "get" : { + "tags" : [ "Management" ], + "summary" : "Gets institution using external institution id", + "description" : "Gets institution using external institution id", + "operationId" : "getInstitutionByExternalIdUsingGET", + "parameters" : [ { + "name" : "externalId", + "in" : "path", + "description" : "Institution's unique external identifier", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "204" : { + "description" : "No Content", + "content" : { + "*/*" : { + "schema" : { + "$ref" : "#/components/schemas/InstitutionManagementResponse" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "deprecated" : true, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/management/institutions/{id}" : { + "get" : { + "tags" : [ "Management" ], + "summary" : "Gets the corresponding institution using internal institution id", + "description" : "Gets the corresponding institution using internal institution id", + "operationId" : "getInstitutionByInternalIdUsingGET", + "parameters" : [ { + "name" : "id", + "in" : "path", + "description" : "The internal identifier of the institution", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "204" : { + "description" : "No Content", + "content" : { + "*/*" : { + "schema" : { + "$ref" : "#/components/schemas/InstitutionManagementResponse" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "deprecated" : true, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/persons/{id}" : { + "get" : { + "tags" : [ "Management" ], + "summary" : "Retrieves Person by ID", + "description" : "Retrieves Person by ID", + "operationId" : "getUserUsingGET", + "parameters" : [ { + "name" : "id", + "in" : "path", + "description" : "User's unique identifier (uuid)", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "*/*" : { + "schema" : { + "$ref" : "#/components/schemas/PersonId" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "deprecated" : true, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + }, + "head" : { + "tags" : [ "Management" ], + "summary" : "verify if a Person exists for a given ID", + "description" : "verify if a Person exists for a given ID", + "operationId" : "verifyUserUsingHEAD", + "parameters" : [ { + "name" : "id", + "in" : "path", + "description" : "User's unique identifier (uuid)", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "200" : { + "description" : "OK" + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "deprecated" : true, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/relationships" : { + "get" : { + "tags" : [ "Management" ], + "summary" : "Return a list of relationships", + "description" : "Return a list of relationships", + "operationId" : "getInstitutionRelationshipsUsingGET", + "parameters" : [ { + "name" : "from", + "in" : "query", + "description" : "from", + "required" : false, + "style" : "form", + "schema" : { + "type" : "string" + } + }, { + "name" : "to", + "in" : "query", + "description" : "to", + "required" : false, + "style" : "form", + "schema" : { + "type" : "string" + } + }, { + "name" : "roles", + "in" : "query", + "description" : "roles", + "required" : false, + "style" : "form", + "explode" : true, + "schema" : { + "type" : "string", + "enum" : [ "DELEGATE", "MANAGER", "OPERATOR", "SUB_DELEGATE" ] + } + }, { + "name" : "states", + "in" : "query", + "description" : "states", + "required" : false, + "style" : "form", + "explode" : true, + "schema" : { + "type" : "string", + "enum" : [ "ACTIVE", "DELETED", "PENDING", "REJECTED", "SUSPENDED", "TOBEVALIDATED" ] + } + }, { + "name" : "products", + "in" : "query", + "description" : "products", + "required" : false, + "style" : "form", + "explode" : true, + "schema" : { + "type" : "string" + } + }, { + "name" : "productRoles", + "in" : "query", + "description" : "productRoles", + "required" : false, + "style" : "form", + "explode" : true, + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "204" : { + "description" : "No Content", + "content" : { + "*/*" : { + "schema" : { + "$ref" : "#/components/schemas/RelationshipsManagement" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "deprecated" : true, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/tokens/{tokenId}" : { + "get" : { + "tags" : [ "Management" ], + "summary" : "retrieve a token relationship", + "description" : "retrieve a token relationship", + "operationId" : "getTokenUsingGET", + "parameters" : [ { + "name" : "tokenId", + "in" : "path", + "description" : "contract's unique identifier", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "*/*" : { + "schema" : { + "$ref" : "#/components/schemas/TokenResponse" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "deprecated" : true, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/onboarding" : { + "head" : { + "tags" : [ "Onboarding" ], + "summary" : "verify if onboardedProduct is already onboarded for institution", + "description" : "verify if onboardedProduct is already onboarded for institution", + "operationId" : "verifyOnboardingInfoUsingHEAD", + "parameters" : [ { + "name" : "taxCode", + "in" : "query", + "description" : "Institution's tax code", + "required" : true, + "style" : "form", + "schema" : { + "type" : "string" + } + }, { + "name" : "subunitCode", + "in" : "query", + "description" : "Institution's subunit code", + "required" : false, + "style" : "form", + "schema" : { + "type" : "string" + } + }, { + "name" : "productId", + "in" : "query", + "description" : "Product's unique identifier", + "required" : true, + "style" : "form", + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "204" : { + "description" : "No Content" + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/onboarding/approve/{tokenId}" : { + "post" : { + "tags" : [ "Onboarding" ], + "summary" : "approve an onboarding reuqest by an operator review", + "description" : "approve an onboarding reuqest by an operator review", + "operationId" : "approveOnboardingUsingPOST", + "parameters" : [ { + "name" : "tokenId", + "in" : "path", + "description" : "contract's unique identifier", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "204" : { + "description" : "No Content" + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "409" : { + "description" : "Conflict", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/onboarding/complete/{tokenId}" : { + "post" : { + "tags" : [ "Onboarding" ], + "summary" : "complete an onboarding request", + "description" : "complete an onboarding request", + "operationId" : "completeOnboardingUsingPOST", + "parameters" : [ { + "name" : "tokenId", + "in" : "path", + "description" : "contract's unique identifier", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + } ], + "requestBody" : { + "content" : { + "multipart/form-data" : { + "schema" : { + "required" : [ "contract" ], + "type" : "object", + "properties" : { + "contract" : { + "type" : "string", + "description" : "contract", + "format" : "binary" + } + } + } + } + } + }, + "responses" : { + "204" : { + "description" : "No Content" + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "409" : { + "description" : "Conflict", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + }, + "delete" : { + "tags" : [ "Onboarding" ], + "summary" : "invalidate an onboarding request", + "description" : "invalidate an onboarding request", + "operationId" : "invalidateOnboardingUsingDELETE", + "parameters" : [ { + "name" : "tokenId", + "in" : "path", + "description" : "contract's unique identifier", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "204" : { + "description" : "No Content" + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "409" : { + "description" : "Conflict", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/onboarding/info" : { + "get" : { + "tags" : [ "Onboarding" ], + "summary" : "returns onboarding info", + "description" : "returns onboarding info", + "operationId" : "onboardingInfoUsingGET", + "parameters" : [ { + "name" : "institutionId", + "in" : "query", + "description" : "The internal identifier of the institution", + "required" : false, + "style" : "form", + "schema" : { + "type" : "string" + } + }, { + "name" : "institutionExternalId", + "in" : "query", + "description" : "Institution's unique external identifier", + "required" : false, + "style" : "form", + "schema" : { + "type" : "string" + } + }, { + "name" : "states", + "in" : "query", + "description" : "List of Relationship state for filter products", + "required" : false, + "style" : "form", + "explode" : true, + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "*/*" : { + "schema" : { + "$ref" : "#/components/schemas/OnboardingInfoResponse" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/onboarding/institution" : { + "post" : { + "tags" : [ "Onboarding" ], + "summary" : "Responsible for saving the association between an institution and a product. It also creates occurrences in the Users collection as part of this process.", + "description" : "Responsible for saving the association between an institution and a product. It also creates occurrences in the Users collection as part of this process.", + "operationId" : "onboardingInstitutionUsingPOST_1", + "requestBody" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/OnboardingInstitutionRequest" + } + } + } + }, + "responses" : { + "204" : { + "description" : "No Content" + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "409" : { + "description" : "Conflict", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/onboarding/institution/complete" : { + "post" : { + "tags" : [ "Onboarding" ], + "summary" : "update institution and users data without adding a new token", + "description" : "update institution and users data without adding a new token", + "operationId" : "onboardingInstitutionCompleteUsingPOST", + "requestBody" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/OnboardingInstitutionRequest" + } + } + } + }, + "responses" : { + "204" : { + "description" : "No Content" + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "409" : { + "description" : "Conflict", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/onboarding/institution/{externalId}/products/{productId}" : { + "head" : { + "tags" : [ "Onboarding" ], + "summary" : "verify if onboardedProduct is already onboarded for institution", + "description" : "verify if onboardedProduct is already onboarded for institution", + "operationId" : "verifyOnboardingInfoUsingHEAD_1", + "parameters" : [ { + "name" : "externalId", + "in" : "path", + "description" : "Institution's unique external identifier", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + }, { + "name" : "productId", + "in" : "path", + "description" : "Product's unique identifier", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "204" : { + "description" : "No Content" + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/onboarding/legals" : { + "post" : { + "tags" : [ "Onboarding" ], + "summary" : "performs legals onboarding on an already existing institution", + "description" : "performs legals onboarding on an already existing institution", + "operationId" : "onboardingInstitutionLegalsUsingPOST", + "requestBody" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/OnboardingInstitutionLegalsRequest" + } + } + } + }, + "responses" : { + "204" : { + "description" : "No Content" + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "409" : { + "description" : "Conflict", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/onboarding/operators" : { + "post" : { + "tags" : [ "Onboarding" ], + "summary" : "performs operators onboarding on an already existing institution", + "description" : "performs operators onboarding on an already existing institution", + "operationId" : "onboardingInstitutionOperatorsUsingPOST", + "requestBody" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/OnboardingInstitutionOperatorsRequest" + } + } + } + }, + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "*/*" : { + "schema" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/RelationshipResult" + } + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "409" : { + "description" : "Conflict", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/onboarding/reject/{tokenId}" : { + "delete" : { + "tags" : [ "Onboarding" ], + "summary" : "invalidate an onboarding request by an operator review", + "description" : "invalidate an onboarding request by an operator review", + "operationId" : "onboardingRejectUsingDELETE", + "parameters" : [ { + "name" : "tokenId", + "in" : "path", + "description" : "contract's unique identifier", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "204" : { + "description" : "No Content" + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "409" : { + "description" : "Conflict", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/onboarding/relationship/{relationshipId}/document" : { + "get" : { + "tags" : [ "Onboarding" ], + "summary" : "retrieve the contractDocument related to a relationship", + "description" : "retrieve the contractDocument related to a relationship", + "operationId" : "getOnboardingDocumentUsingGET", + "parameters" : [ { + "name" : "relationshipId", + "in" : "path", + "description" : "UserBinding's unique identifier", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "*/*" : { + "schema" : { + "type" : "string", + "format" : "byte" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/onboarding/subdelegates" : { + "post" : { + "tags" : [ "Onboarding" ], + "summary" : "performs subdelegates onboarding on an already existing institution", + "description" : "performs subdelegates onboarding on an already existing institution", + "operationId" : "onboardingInstitutionSubDelegateUsingPOST", + "requestBody" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/OnboardingInstitutionOperatorsRequest" + } + } + } + }, + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "*/*" : { + "schema" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/RelationshipResult" + } + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "409" : { + "description" : "Conflict", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/onboarding/users" : { + "post" : { + "tags" : [ "Onboarding", "support" ], + "summary" : "The service adds users to the registry if they are not present and associates them with the institution and product contained in the body", + "description" : "The service adds users to the registry if they are not present and associates them with the institution and product contained in the body", + "operationId" : "onboardingInstitutionUsersUsingPOST", + "requestBody" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/OnboardingInstitutionUsersRequest" + } + } + } + }, + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "*/*" : { + "schema" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/RelationshipResult" + } + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "409" : { + "description" : "Conflict", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/onboarding/{tokenId}/consume" : { + "post" : { + "tags" : [ "Onboarding" ], + "summary" : "Consume token onboarding request without digest verification ", + "description" : "Consume token onboarding request without digest verification ", + "operationId" : "consumeTokenUsingPOST", + "parameters" : [ { + "name" : "tokenId", + "in" : "path", + "description" : "contract's unique identifier", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + } ], + "requestBody" : { + "content" : { + "multipart/form-data" : { + "schema" : { + "required" : [ "contract" ], + "type" : "object", + "properties" : { + "contract" : { + "type" : "string", + "description" : "contract", + "format" : "binary" + } + } + } + } + } + }, + "responses" : { + "204" : { + "description" : "No Content" + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "409" : { + "description" : "Conflict", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/scheduler" : { + "post" : { + "tags" : [ "scheduler" ], + "summary" : "start", + "description" : "Service to start scheduler to resend old messages to DL", + "operationId" : "startUsingPOST", + "parameters" : [ { + "name" : "size", + "in" : "query", + "description" : "size", + "required" : false, + "style" : "form", + "schema" : { + "type" : "integer", + "format" : "int32" + } + }, { + "name" : "productsFilter", + "in" : "query", + "description" : "productsFilter", + "required" : true, + "style" : "form", + "explode" : true, + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "200" : { + "description" : "OK" + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "409" : { + "description" : "Conflict", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/tokens/products/{productId}" : { + "get" : { + "tags" : [ "Token", "external-v2" ], + "summary" : "${swagger.mscore.tokens.findFromProduct}", + "description" : "${swagger.mscore.tokens.findFromProduct}", + "operationId" : "findFromProductUsingGET_1", + "parameters" : [ { + "name" : "productId", + "in" : "path", + "description" : "Product's unique identifier", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + }, { + "name" : "page", + "in" : "query", + "description" : "${swagger.mscore.page.number}", + "required" : false, + "style" : "form", + "schema" : { + "type" : "integer", + "format" : "int32" + } + }, { + "name" : "size", + "in" : "query", + "description" : "${swagger.mscore.page.size}", + "required" : false, + "style" : "form", + "schema" : { + "type" : "integer", + "format" : "int32" + } + } ], + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "*/*" : { + "schema" : { + "$ref" : "#/components/schemas/TokenListResponse" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/tokens/token" : { + "get" : { + "tags" : [ "Token" ], + "summary" : "Retrieve token given the institution's and product ids", + "operationId" : "getTokenUsingGET_1", + "parameters" : [ { + "name" : "institutionId", + "in" : "query", + "description" : "Institution's unique internal identifier", + "required" : true, + "style" : "form", + "schema" : { + "type" : "string" + } + }, { + "name" : "productId", + "in" : "query", + "description" : "Product's unique identifier", + "required" : true, + "style" : "form", + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "*/*" : { + "schema" : { + "$ref" : "#/components/schemas/TokenResource" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/tokens/{tokenId}/verify" : { + "post" : { + "tags" : [ "Token" ], + "summary" : "Verify if the token is already consumed", + "description" : "Verify if the token is already consumed", + "operationId" : "verifyTokenUsingPOST", + "parameters" : [ { + "name" : "tokenId", + "in" : "path", + "description" : "contract's unique identifier", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "*/*" : { + "schema" : { + "$ref" : "#/components/schemas/TokenResponse" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "409" : { + "description" : "Conflict", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/relationships/{relationshipId}" : { + "get" : { + "tags" : [ "Persons" ], + "summary" : "Gets the corresponding relationship", + "description" : "Gets the corresponding relationship", + "operationId" : "getRelationshipUsingGET", + "parameters" : [ { + "name" : "relationshipId", + "in" : "path", + "description" : "UserBinding's unique identifier", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "*/*" : { + "schema" : { + "$ref" : "#/components/schemas/RelationshipResult" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + }, + "delete" : { + "tags" : [ "Persons" ], + "summary" : "Given a relationship identifier, it deletes the corresponding relationship", + "description" : "Given a relationship identifier, it deletes the corresponding relationship", + "operationId" : "deleteRelationshipUsingDELETE", + "parameters" : [ { + "name" : "relationshipId", + "in" : "path", + "description" : "UserBinding's unique identifier", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "204" : { + "description" : "No Content" + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "409" : { + "description" : "Conflict", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/relationships/{relationshipId}/activate" : { + "post" : { + "tags" : [ "Persons" ], + "summary" : "Activate the relationship", + "description" : "Activate the relationship", + "operationId" : "activateRelationshipUsingPOST", + "parameters" : [ { + "name" : "relationshipId", + "in" : "path", + "description" : "UserBinding's unique identifier", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "204" : { + "description" : "No Content" + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "409" : { + "description" : "Conflict", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/relationships/{relationshipId}/suspend" : { + "post" : { + "tags" : [ "Persons" ], + "summary" : "Suspend the relationship", + "description" : "Suspend the relationship", + "operationId" : "suspendRelationshipUsingPOST", + "parameters" : [ { + "name" : "relationshipId", + "in" : "path", + "description" : "UserBinding's unique identifier", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "204" : { + "description" : "No Content" + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "409" : { + "description" : "Conflict", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/users/{id}" : { + "get" : { + "tags" : [ "Persons", "external-v2", "support" ], + "summary" : "Retrieves user given userId and optional ProductId", + "description" : "Retrieves user given userId and optional ProductId", + "operationId" : "getUserInfoUsingGET", + "parameters" : [ { + "name" : "id", + "in" : "path", + "description" : "User's unique identifier", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + }, { + "name" : "productId", + "in" : "query", + "description" : "Product's unique identifier", + "required" : false, + "style" : "form", + "schema" : { + "type" : "string" + } + }, { + "name" : "institutionId", + "in" : "query", + "description" : "The internal identifier of the institution", + "required" : false, + "style" : "form", + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "*/*" : { + "schema" : { + "$ref" : "#/components/schemas/UserResponse" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/users/{id}/update" : { + "post" : { + "tags" : [ "Persons" ], + "summary" : "Service to send notification when user data get's updated", + "description" : "Service to send notification when user data get's updated", + "operationId" : "updateUserUsingPOST", + "parameters" : [ { + "name" : "id", + "in" : "path", + "description" : "User's unique identifier", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + }, { + "name" : "institutionId", + "in" : "query", + "description" : "The internal identifier of the institution", + "required" : true, + "style" : "form", + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "204" : { + "description" : "No Content" + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "409" : { + "description" : "Conflict", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/users/{userId}/institution-products" : { + "get" : { + "tags" : [ "Persons" ], + "summary" : "returns onboarding info", + "description" : "returns onboarding info", + "operationId" : "getInstitutionProductsInfoUsingGET", + "parameters" : [ { + "name" : "userId", + "in" : "path", + "description" : "UserBinding's unique identifier", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + }, { + "name" : "institutionId", + "in" : "query", + "description" : "The internal identifier of the institution", + "required" : false, + "style" : "form", + "schema" : { + "type" : "string" + } + }, { + "name" : "states", + "in" : "query", + "description" : "List of Relationship state for filter products", + "required" : false, + "style" : "form", + "explode" : true, + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "*/*" : { + "schema" : { + "$ref" : "#/components/schemas/OnboardingInfoResponse" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/users/{userId}/institutions/{institutionId}/products/{productId}" : { + "delete" : { + "tags" : [ "Persons" ], + "summary" : "Delete logically the association institution and product", + "description" : "Delete logically the association institution and product", + "operationId" : "deleteProductsUsingDELETE", + "parameters" : [ { + "name" : "userId", + "in" : "path", + "description" : "UserBinding's unique identifier", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + }, { + "name" : "institutionId", + "in" : "path", + "description" : "The internal identifier of the institution", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + }, { + "name" : "productId", + "in" : "path", + "description" : "Product's unique identifier", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "200" : { + "description" : "OK" + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "409" : { + "description" : "Conflict", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/users/{userId}/products" : { + "get" : { + "tags" : [ "Persons" ], + "summary" : "Retrieves products info and role which the user is enabled", + "description" : "Retrieves products info and role which the user is enabled", + "operationId" : "getUserProductsInfoUsingGET", + "parameters" : [ { + "name" : "userId", + "in" : "path", + "description" : "UserBinding's unique identifier", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + }, { + "name" : "institutionId", + "in" : "query", + "description" : "The internal identifier of the institution", + "required" : false, + "style" : "form", + "schema" : { + "type" : "string" + } + }, { + "name" : "states", + "in" : "query", + "description" : "List of Relationship state for filter products", + "required" : false, + "style" : "form", + "explode" : true, + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "*/*" : { + "schema" : { + "$ref" : "#/components/schemas/UserProductsResponse" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + } + }, + "components" : { + "schemas" : { + "Attributes" : { + "title" : "Attributes", + "type" : "object", + "properties" : { + "code" : { + "type" : "string" + }, + "description" : { + "type" : "string" + }, + "origin" : { + "type" : "string" + } + } + }, + "AttributesRequest" : { + "title" : "AttributesRequest", + "type" : "object", + "properties" : { + "code" : { + "type" : "string" + }, + "description" : { + "type" : "string" + }, + "origin" : { + "type" : "string" + } + } + }, + "AttributesResponse" : { + "title" : "AttributesResponse", + "type" : "object", + "properties" : { + "code" : { + "type" : "string" + }, + "description" : { + "type" : "string" + }, + "origin" : { + "type" : "string" + } + } + }, + "Billing" : { + "title" : "Billing", + "type" : "object", + "properties" : { + "publicServices" : { + "type" : "boolean" + }, + "recipientCode" : { + "type" : "string" + }, + "vatNumber" : { + "type" : "string" + } + } + }, + "BillingRequest" : { + "title" : "BillingRequest", + "type" : "object", + "properties" : { + "publicServices" : { + "type" : "boolean" + }, + "recipientCode" : { + "type" : "string" + }, + "vatNumber" : { + "type" : "string" + } + } + }, + "BillingResponse" : { + "title" : "BillingResponse", + "type" : "object", + "properties" : { + "publicServices" : { + "type" : "boolean" + }, + "recipientCode" : { + "type" : "string" + }, + "vatNumber" : { + "type" : "string" + } + } + }, + "BrokerResponse" : { + "title" : "BrokerResponse", + "type" : "object", + "properties" : { + "description" : { + "type" : "string" + }, + "id" : { + "type" : "string" + }, + "numberOfDelegations" : { + "type" : "integer", + "format" : "int32" + } + } + }, + "BulkInstitution" : { + "title" : "BulkInstitution", + "type" : "object", + "properties" : { + "address" : { + "type" : "string" + }, + "attributes" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/AttributesResponse" + } + }, + "description" : { + "type" : "string" + }, + "digitalAddress" : { + "type" : "string" + }, + "externalId" : { + "type" : "string" + }, + "id" : { + "type" : "string" + }, + "institutionType" : { + "type" : "string", + "enum" : [ "AS", "GSP", "PA", "PG", "PSP", "PT", "SA", "SCP" ] + }, + "origin" : { + "type" : "string" + }, + "originId" : { + "type" : "string" + }, + "products" : { + "type" : "object", + "additionalProperties" : { + "$ref" : "#/components/schemas/BulkProduct" + } + }, + "taxCode" : { + "type" : "string" + }, + "zipCode" : { + "type" : "string" + } + } + }, + "BulkInstitutions" : { + "title" : "BulkInstitutions", + "type" : "object", + "properties" : { + "found" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/BulkInstitution" + } + }, + "notFound" : { + "type" : "array", + "items" : { + "type" : "string" + } + } + } + }, + "BulkPartiesSeed" : { + "title" : "BulkPartiesSeed", + "type" : "object", + "properties" : { + "partyIdentifiers" : { + "type" : "array", + "items" : { + "type" : "string" + } + } + } + }, + "BulkProduct" : { + "title" : "BulkProduct", + "type" : "object", + "properties" : { + "billing" : { + "$ref" : "#/components/schemas/BillingResponse" + }, + "pricingPlan" : { + "type" : "string" + }, + "product" : { + "type" : "string" + }, + "status" : { + "type" : "string", + "enum" : [ "ACTIVE", "DELETED", "PENDING", "REJECTED", "SUSPENDED", "TOBEVALIDATED" ] + } + } + }, + "BusinessData" : { + "title" : "BusinessData", + "type" : "object", + "properties" : { + "businessRegisterPlace" : { + "type" : "string" + }, + "rea" : { + "type" : "string" + }, + "shareCapital" : { + "type" : "string" + } + } + }, + "Contract" : { + "title" : "Contract", + "type" : "object", + "properties" : { + "path" : { + "type" : "string" + }, + "version" : { + "type" : "string" + } + } + }, + "ContractRequest" : { + "title" : "ContractRequest", + "type" : "object", + "properties" : { + "path" : { + "type" : "string" + }, + "version" : { + "type" : "string" + } + } + }, + "CreatePgInstitutionRequest" : { + "title" : "CreatePgInstitutionRequest", + "type" : "object", + "properties" : { + "description" : { + "type" : "string" + }, + "existsInRegistry" : { + "type" : "boolean" + }, + "taxId" : { + "type" : "string" + } + } + }, + "CreatePnPgInstitutionRequest" : { + "title" : "CreatePnPgInstitutionRequest", + "type" : "object", + "properties" : { + "description" : { + "type" : "string" + }, + "taxId" : { + "type" : "string" + } + } + }, + "DataProtectionOfficer" : { + "title" : "DataProtectionOfficer", + "type" : "object", + "properties" : { + "address" : { + "type" : "string" + }, + "email" : { + "type" : "string" + }, + "pec" : { + "type" : "string" + } + } + }, + "DataProtectionOfficerRequest" : { + "title" : "DataProtectionOfficerRequest", + "type" : "object", + "properties" : { + "address" : { + "type" : "string" + }, + "email" : { + "type" : "string" + }, + "pec" : { + "type" : "string" + } + } + }, + "DataProtectionOfficerResponse" : { + "title" : "DataProtectionOfficerResponse", + "type" : "object", + "properties" : { + "address" : { + "type" : "string" + }, + "email" : { + "type" : "string" + }, + "pec" : { + "type" : "string" + } + } + }, + "DelegationRequest" : { + "title" : "DelegationRequest", + "type" : "object", + "properties" : { + "from" : { + "type" : "string" + }, + "institutionFromName" : { + "type" : "string" + }, + "institutionToName" : { + "type" : "string" + }, + "productId" : { + "type" : "string" + }, + "to" : { + "type" : "string" + }, + "type" : { + "type" : "string", + "enum" : [ "AOO", "PT" ] + } + } + }, + "DelegationRequestFromTaxcode" : { + "title" : "DelegationRequestFromTaxcode", + "type" : "object", + "properties" : { + "fromSubunitCode" : { + "type" : "string" + }, + "fromTaxCode" : { + "type" : "string" + }, + "institutionFromName" : { + "type" : "string" + }, + "institutionToName" : { + "type" : "string" + }, + "productId" : { + "type" : "string" + }, + "toSubunitCode" : { + "type" : "string" + }, + "toTaxCode" : { + "type" : "string" + }, + "type" : { + "type" : "string", + "enum" : [ "AOO", "PT" ] + } + } + }, + "DelegationResponse" : { + "title" : "DelegationResponse", + "type" : "object", + "properties" : { + "brokerId" : { + "type" : "string" + }, + "brokerName" : { + "type" : "string" + }, + "brokerTaxCode" : { + "type" : "string" + }, + "brokerType" : { + "type" : "string" + }, + "id" : { + "type" : "string" + }, + "institutionId" : { + "type" : "string" + }, + "institutionName" : { + "type" : "string" + }, + "institutionRootName" : { + "type" : "string" + }, + "institutionType" : { + "type" : "string", + "enum" : [ "AS", "GSP", "PA", "PG", "PSP", "PT", "SA", "SCP" ] + }, + "productId" : { + "type" : "string" + }, + "taxCode" : { + "type" : "string" + }, + "type" : { + "type" : "string", + "enum" : [ "AOO", "PT" ] + } + } + }, + "GeoTaxonomies" : { + "title" : "GeoTaxonomies", + "type" : "object", + "properties" : { + "code" : { + "type" : "string" + }, + "desc" : { + "type" : "string" + } + } + }, + "GeographicTaxonomies" : { + "title" : "GeographicTaxonomies", + "type" : "object", + "properties" : { + "code" : { + "type" : "string" + }, + "country" : { + "type" : "string" + }, + "country_abbreviation" : { + "type" : "string" + }, + "desc" : { + "type" : "string" + }, + "enabled" : { + "type" : "boolean" + }, + "istat_code" : { + "type" : "string" + }, + "province_abbreviation" : { + "type" : "string" + }, + "province_id" : { + "type" : "string" + }, + "region_id" : { + "type" : "string" + } + } + }, + "Institution" : { + "title" : "Institution", + "type" : "object", + "properties" : { + "address" : { + "type" : "string" + }, + "attributes" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/Attributes" + } + }, + "billing" : { + "$ref" : "#/components/schemas/Billing" + }, + "businessRegisterPlace" : { + "type" : "string" + }, + "city" : { + "type" : "string" + }, + "country" : { + "type" : "string" + }, + "county" : { + "type" : "string" + }, + "createdAt" : { + "type" : "string", + "format" : "date-time" + }, + "dataProtectionOfficer" : { + "$ref" : "#/components/schemas/DataProtectionOfficer" + }, + "description" : { + "type" : "string" + }, + "digitalAddress" : { + "type" : "string" + }, + "externalId" : { + "type" : "string" + }, + "geographicTaxonomies" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/InstitutionGeographicTaxonomies" + } + }, + "id" : { + "type" : "string" + }, + "imported" : { + "type" : "boolean" + }, + "institutionType" : { + "type" : "string", + "enum" : [ "AS", "GSP", "PA", "PG", "PSP", "PT", "SA", "SCP" ] + }, + "istatCode" : { + "type" : "string" + }, + "onboarding" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/Onboarding" + } + }, + "origin" : { + "type" : "string" + }, + "originId" : { + "type" : "string" + }, + "paAttributes" : { + "$ref" : "#/components/schemas/PaAttributes" + }, + "parentDescription" : { + "type" : "string" + }, + "paymentServiceProvider" : { + "$ref" : "#/components/schemas/PaymentServiceProvider" + }, + "rea" : { + "type" : "string" + }, + "rootParentId" : { + "type" : "string" + }, + "shareCapital" : { + "type" : "string" + }, + "subunitCode" : { + "type" : "string" + }, + "subunitType" : { + "type" : "string" + }, + "supportEmail" : { + "type" : "string" + }, + "supportPhone" : { + "type" : "string" + }, + "taxCode" : { + "type" : "string" + }, + "updatedAt" : { + "type" : "string", + "format" : "date-time" + }, + "zipCode" : { + "type" : "string" + } + } + }, + "InstitutionBillingResponse" : { + "title" : "InstitutionBillingResponse", + "type" : "object", + "properties" : { + "address" : { + "type" : "string" + }, + "aooParentCode" : { + "type" : "string" + }, + "billing" : { + "$ref" : "#/components/schemas/BillingResponse" + }, + "description" : { + "type" : "string" + }, + "digitalAddress" : { + "type" : "string" + }, + "externalId" : { + "type" : "string" + }, + "institutionId" : { + "type" : "string" + }, + "institutionType" : { + "type" : "string", + "enum" : [ "AS", "GSP", "PA", "PG", "PSP", "PT", "SA", "SCP" ] + }, + "origin" : { + "type" : "string", + "enum" : [ "ADE", "ANAC", "INFOCAMERE", "IPA", "IVASS", "MOCK", "SELC", "UNKNOWN" ] + }, + "originId" : { + "type" : "string" + }, + "pricingPlan" : { + "type" : "string" + }, + "subunitCode" : { + "type" : "string" + }, + "subunitType" : { + "type" : "string" + }, + "taxCode" : { + "type" : "string" + }, + "zipCode" : { + "type" : "string" + } + } + }, + "InstitutionFromIpaPost" : { + "title" : "InstitutionFromIpaPost", + "type" : "object", + "properties" : { + "geographicTaxonomies" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/GeoTaxonomies" + } + }, + "subunitCode" : { + "type" : "string" + }, + "subunitType" : { + "type" : "string", + "enum" : [ "AOO", "UO" ] + }, + "taxCode" : { + "type" : "string" + } + } + }, + "InstitutionGeographicTaxonomies" : { + "title" : "InstitutionGeographicTaxonomies", + "type" : "object", + "properties" : { + "code" : { + "type" : "string" + }, + "desc" : { + "type" : "string" + } + } + }, + "InstitutionListResponse" : { + "title" : "InstitutionListResponse", + "type" : "object", + "properties" : { + "items" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/InstitutionManagementResponse" + } + } + } + }, + "InstitutionManagementResponse" : { + "title" : "InstitutionManagementResponse", + "type" : "object", + "properties" : { + "address" : { + "type" : "string" + }, + "aooParentCode" : { + "type" : "string" + }, + "attributes" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/AttributesResponse" + } + }, + "businessRegisterPlace" : { + "type" : "string" + }, + "createdAt" : { + "type" : "string", + "format" : "date-time" + }, + "dataProtectionOfficer" : { + "$ref" : "#/components/schemas/DataProtectionOfficerResponse" + }, + "description" : { + "type" : "string" + }, + "digitalAddress" : { + "type" : "string" + }, + "externalId" : { + "type" : "string" + }, + "geographicTaxonomies" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/GeoTaxonomies" + } + }, + "id" : { + "type" : "string" + }, + "imported" : { + "type" : "boolean" + }, + "institutionType" : { + "type" : "string", + "enum" : [ "AS", "GSP", "PA", "PG", "PSP", "PT", "SA", "SCP" ] + }, + "origin" : { + "type" : "string" + }, + "originId" : { + "type" : "string" + }, + "paymentServiceProvider" : { + "$ref" : "#/components/schemas/PaymentServiceProviderResponse" + }, + "products" : { + "type" : "object", + "additionalProperties" : { + "$ref" : "#/components/schemas/ProductsManagement" + } + }, + "rea" : { + "type" : "string" + }, + "shareCapital" : { + "type" : "string" + }, + "subunitCode" : { + "type" : "string" + }, + "subunitType" : { + "type" : "string" + }, + "supportEmail" : { + "type" : "string" + }, + "supportPhone" : { + "type" : "string" + }, + "taxCode" : { + "type" : "string" + }, + "updatedAt" : { + "type" : "string", + "format" : "date-time" + }, + "zipCode" : { + "type" : "string" + } + } + }, + "InstitutionManagerResponse" : { + "title" : "InstitutionManagerResponse", + "type" : "object", + "properties" : { + "billing" : { + "$ref" : "#/components/schemas/BillingResponse" + }, + "createdAt" : { + "type" : "string", + "format" : "date-time" + }, + "from" : { + "type" : "string" + }, + "id" : { + "type" : "string" + }, + "institutionUpdate" : { + "$ref" : "#/components/schemas/InstitutionUpdateResponse" + }, + "pricingPlan" : { + "type" : "string" + }, + "product" : { + "$ref" : "#/components/schemas/ProductInfo" + }, + "role" : { + "type" : "string" + }, + "state" : { + "type" : "string", + "enum" : [ "ACTIVE", "DELETED", "PENDING", "REJECTED", "SUSPENDED", "TOBEVALIDATED" ] + }, + "to" : { + "type" : "string" + }, + "updatedAt" : { + "type" : "string", + "format" : "date-time" + } + } + }, + "InstitutionOnboardingListResponse" : { + "title" : "InstitutionOnboardingListResponse", + "type" : "object", + "properties" : { + "items" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/InstitutionOnboardingResponse" + } + } + } + }, + "InstitutionOnboardingRequest" : { + "title" : "InstitutionOnboardingRequest", + "type" : "object", + "properties" : { + "billing" : { + "$ref" : "#/components/schemas/BillingRequest" + }, + "contractPath" : { + "type" : "string" + }, + "pricingPlan" : { + "type" : "string" + }, + "productId" : { + "type" : "string" + }, + "tokenId" : { + "type" : "string" + }, + "users" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/Person" + } + } + } + }, + "InstitutionOnboardingResponse" : { + "title" : "InstitutionOnboardingResponse", + "type" : "object", + "properties" : { + "address" : { + "type" : "string" + }, + "aooParentCode" : { + "type" : "string" + }, + "attributes" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/AttributesResponse" + } + }, + "businessRegisterPlace" : { + "type" : "string" + }, + "createdAt" : { + "type" : "string", + "format" : "date-time" + }, + "dataProtectionOfficer" : { + "$ref" : "#/components/schemas/DataProtectionOfficerResponse" + }, + "description" : { + "type" : "string" + }, + "digitalAddress" : { + "type" : "string" + }, + "externalId" : { + "type" : "string" + }, + "geographicTaxonomies" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/GeoTaxonomies" + } + }, + "id" : { + "type" : "string" + }, + "imported" : { + "type" : "boolean" + }, + "institutionType" : { + "type" : "string", + "enum" : [ "AS", "GSP", "PA", "PG", "PSP", "PT", "SA", "SCP" ] + }, + "onboardings" : { + "type" : "object", + "additionalProperties" : { + "$ref" : "#/components/schemas/OnboardingResponse" + } + }, + "origin" : { + "type" : "string" + }, + "originId" : { + "type" : "string" + }, + "paymentServiceProvider" : { + "$ref" : "#/components/schemas/PaymentServiceProviderResponse" + }, + "rea" : { + "type" : "string" + }, + "shareCapital" : { + "type" : "string" + }, + "subunitCode" : { + "type" : "string" + }, + "subunitType" : { + "type" : "string" + }, + "supportEmail" : { + "type" : "string" + }, + "supportPhone" : { + "type" : "string" + }, + "taxCode" : { + "type" : "string" + }, + "updatedAt" : { + "type" : "string", + "format" : "date-time" + }, + "zipCode" : { + "type" : "string" + } + } + }, + "InstitutionPnPgResponse" : { + "title" : "InstitutionPnPgResponse", + "type" : "object", + "properties" : { + "id" : { + "type" : "string" + } + } + }, + "InstitutionProduct" : { + "title" : "InstitutionProduct", + "type" : "object", + "properties" : { + "id" : { + "type" : "string" + }, + "state" : { + "type" : "string", + "enum" : [ "ACTIVE", "DELETED", "PENDING", "REJECTED", "SUSPENDED", "TOBEVALIDATED" ] + } + } + }, + "InstitutionProducts" : { + "title" : "InstitutionProducts", + "type" : "object", + "properties" : { + "institutionId" : { + "type" : "string" + }, + "institutionName" : { + "type" : "string" + }, + "institutionRootName" : { + "type" : "string" + }, + "products" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/Product" + } + } + } + }, + "InstitutionPut" : { + "title" : "InstitutionPut", + "type" : "object", + "properties" : { + "description" : { + "type" : "string" + }, + "digitalAddress" : { + "type" : "string" + }, + "geographicTaxonomyCodes" : { + "type" : "array", + "items" : { + "type" : "string" + } + } + } + }, + "InstitutionRequest" : { + "title" : "InstitutionRequest", + "type" : "object", + "properties" : { + "address" : { + "type" : "string" + }, + "attributes" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/AttributesRequest" + } + }, + "billing" : { + "$ref" : "#/components/schemas/BillingRequest" + }, + "businessRegisterPlace" : { + "type" : "string" + }, + "city" : { + "type" : "string" + }, + "country" : { + "type" : "string" + }, + "county" : { + "type" : "string" + }, + "createdAt" : { + "type" : "string", + "format" : "date-time" + }, + "dataProtectionOfficer" : { + "$ref" : "#/components/schemas/DataProtectionOfficerRequest" + }, + "description" : { + "type" : "string" + }, + "digitalAddress" : { + "type" : "string" + }, + "externalId" : { + "type" : "string" + }, + "geographicTaxonomies" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/GeoTaxonomies" + } + }, + "id" : { + "type" : "string" + }, + "imported" : { + "type" : "boolean" + }, + "institutionType" : { + "type" : "string", + "enum" : [ "AS", "GSP", "PA", "PG", "PSP", "PT", "SA", "SCP" ] + }, + "onboarding" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/OnboardingRequest" + } + }, + "origin" : { + "type" : "string" + }, + "originId" : { + "type" : "string" + }, + "paymentServiceProvider" : { + "$ref" : "#/components/schemas/PaymentServiceProviderRequest" + }, + "rea" : { + "type" : "string" + }, + "shareCapital" : { + "type" : "string" + }, + "supportEmail" : { + "type" : "string" + }, + "supportPhone" : { + "type" : "string" + }, + "taxCode" : { + "type" : "string" + }, + "updatedAt" : { + "type" : "string", + "format" : "date-time" + }, + "zipCode" : { + "type" : "string" + } + } + }, + "InstitutionResponse" : { + "title" : "InstitutionResponse", + "type" : "object", + "properties" : { + "address" : { + "type" : "string" + }, + "aooParentCode" : { + "type" : "string" + }, + "attributes" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/AttributesResponse" + } + }, + "businessRegisterPlace" : { + "type" : "string" + }, + "city" : { + "type" : "string" + }, + "country" : { + "type" : "string" + }, + "county" : { + "type" : "string" + }, + "createdAt" : { + "type" : "string", + "format" : "date-time" + }, + "dataProtectionOfficer" : { + "$ref" : "#/components/schemas/DataProtectionOfficerResponse" + }, + "description" : { + "type" : "string" + }, + "digitalAddress" : { + "type" : "string" + }, + "externalId" : { + "type" : "string" + }, + "geographicTaxonomies" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/GeoTaxonomies" + } + }, + "id" : { + "type" : "string" + }, + "imported" : { + "type" : "boolean" + }, + "institutionType" : { + "type" : "string", + "enum" : [ "AS", "GSP", "PA", "PG", "PSP", "PT", "SA", "SCP" ] + }, + "onboarding" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/OnboardedProductResponse" + } + }, + "origin" : { + "type" : "string" + }, + "originId" : { + "type" : "string" + }, + "paymentServiceProvider" : { + "$ref" : "#/components/schemas/PaymentServiceProviderResponse" + }, + "rea" : { + "type" : "string" + }, + "rootParent" : { + "$ref" : "#/components/schemas/RootParentResponse" + }, + "shareCapital" : { + "type" : "string" + }, + "subunitCode" : { + "type" : "string" + }, + "subunitType" : { + "type" : "string" + }, + "supportEmail" : { + "type" : "string" + }, + "supportPhone" : { + "type" : "string" + }, + "taxCode" : { + "type" : "string" + }, + "updatedAt" : { + "type" : "string", + "format" : "date-time" + }, + "zipCode" : { + "type" : "string" + } + } + }, + "InstitutionToOnboard" : { + "title" : "InstitutionToOnboard", + "type" : "object", + "properties" : { + "cfImpresa" : { + "type" : "string" + }, + "denominazione" : { + "type" : "string" + } + } + }, + "InstitutionUpdate" : { + "title" : "InstitutionUpdate", + "type" : "object", + "properties" : { + "address" : { + "type" : "string" + }, + "businessRegisterPlace" : { + "type" : "string" + }, + "city" : { + "type" : "string" + }, + "country" : { + "type" : "string" + }, + "county" : { + "type" : "string" + }, + "dataProtectionOfficer" : { + "$ref" : "#/components/schemas/DataProtectionOfficer" + }, + "description" : { + "type" : "string" + }, + "digitalAddress" : { + "type" : "string" + }, + "geographicTaxonomies" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/InstitutionGeographicTaxonomies" + } + }, + "imported" : { + "type" : "boolean" + }, + "institutionType" : { + "type" : "string", + "enum" : [ "AS", "GSP", "PA", "PG", "PSP", "PT", "SA", "SCP" ] + }, + "ivassCode" : { + "type" : "string" + }, + "paymentServiceProvider" : { + "$ref" : "#/components/schemas/PaymentServiceProvider" + }, + "rea" : { + "type" : "string" + }, + "shareCapital" : { + "type" : "string" + }, + "supportEmail" : { + "type" : "string" + }, + "supportPhone" : { + "type" : "string" + }, + "taxCode" : { + "type" : "string" + }, + "zipCode" : { + "type" : "string" + } + } + }, + "InstitutionUpdateRequest" : { + "title" : "InstitutionUpdateRequest", + "type" : "object", + "properties" : { + "address" : { + "type" : "string" + }, + "businessRegisterPlace" : { + "type" : "string" + }, + "city" : { + "type" : "string" + }, + "country" : { + "type" : "string" + }, + "county" : { + "type" : "string" + }, + "dataProtectionOfficer" : { + "$ref" : "#/components/schemas/DataProtectionOfficerRequest" + }, + "description" : { + "type" : "string" + }, + "digitalAddress" : { + "type" : "string" + }, + "geographicTaxonomyCodes" : { + "type" : "array", + "items" : { + "type" : "string" + } + }, + "imported" : { + "type" : "boolean" + }, + "institutionType" : { + "type" : "string", + "enum" : [ "AS", "GSP", "PA", "PG", "PSP", "PT", "SA", "SCP" ] + }, + "ivassCode" : { + "type" : "string" + }, + "paymentServiceProvider" : { + "$ref" : "#/components/schemas/PaymentServiceProviderRequest" + }, + "rea" : { + "type" : "string" + }, + "shareCapital" : { + "type" : "string" + }, + "supportEmail" : { + "type" : "string" + }, + "supportPhone" : { + "type" : "string" + }, + "taxCode" : { + "type" : "string" + }, + "zipCode" : { + "type" : "string" + } + } + }, + "InstitutionUpdateResponse" : { + "title" : "InstitutionUpdateResponse", + "type" : "object", + "properties" : { + "address" : { + "type" : "string" + }, + "aooParentCode" : { + "type" : "string" + }, + "businessRegisterPlace" : { + "type" : "string" + }, + "city" : { + "type" : "string" + }, + "country" : { + "type" : "string" + }, + "county" : { + "type" : "string" + }, + "dataProtectionOfficer" : { + "$ref" : "#/components/schemas/DataProtectionOfficerResponse" + }, + "description" : { + "type" : "string" + }, + "digitalAddress" : { + "type" : "string" + }, + "geographicTaxonomyCodes" : { + "type" : "array", + "items" : { + "type" : "string" + } + }, + "imported" : { + "type" : "boolean" + }, + "institutionType" : { + "type" : "string", + "enum" : [ "AS", "GSP", "PA", "PG", "PSP", "PT", "SA", "SCP" ] + }, + "paymentServiceProvider" : { + "$ref" : "#/components/schemas/PaymentServiceProviderResponse" + }, + "rea" : { + "type" : "string" + }, + "shareCapital" : { + "type" : "string" + }, + "subunitCode" : { + "type" : "string" + }, + "subunitType" : { + "type" : "string" + }, + "supportEmail" : { + "type" : "string" + }, + "supportPhone" : { + "type" : "string" + }, + "taxCode" : { + "type" : "string" + }, + "zipCode" : { + "type" : "string" + } + } + }, + "InstitutionsResponse" : { + "title" : "InstitutionsResponse", + "type" : "object", + "properties" : { + "institutions" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/InstitutionResponse" + } + } + } + }, + "LegalsResponse" : { + "title" : "LegalsResponse", + "type" : "object", + "properties" : { + "env" : { + "type" : "string", + "enum" : [ "COLL", "DEV", "PROD", "ROOT" ] + }, + "partyId" : { + "type" : "string" + }, + "relationshipId" : { + "type" : "string" + }, + "role" : { + "type" : "string", + "enum" : [ "DELEGATE", "MANAGER", "OPERATOR", "SUB_DELEGATE" ] + } + } + }, + "MigrationInstitution" : { + "title" : "MigrationInstitution", + "type" : "object", + "properties" : { + "address" : { + "type" : "string" + }, + "attributes" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/Attributes" + } + }, + "billing" : { + "$ref" : "#/components/schemas/Billing" + }, + "businessRegisterPlace" : { + "type" : "string" + }, + "createdAt" : { + "type" : "string", + "format" : "date-time" + }, + "dataProtectionOfficer" : { + "$ref" : "#/components/schemas/DataProtectionOfficer" + }, + "description" : { + "type" : "string" + }, + "digitalAddress" : { + "type" : "string" + }, + "externalId" : { + "type" : "string" + }, + "geographicTaxonomies" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/InstitutionGeographicTaxonomies" + } + }, + "id" : { + "type" : "string" + }, + "imported" : { + "type" : "boolean" + }, + "institutionType" : { + "type" : "string", + "enum" : [ "AS", "GSP", "PA", "PG", "PSP", "PT", "SA", "SCP" ] + }, + "onboarding" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/Onboarding" + } + }, + "origin" : { + "type" : "string" + }, + "originId" : { + "type" : "string" + }, + "paymentServiceProvider" : { + "$ref" : "#/components/schemas/PaymentServiceProvider" + }, + "rea" : { + "type" : "string" + }, + "shareCapital" : { + "type" : "string" + }, + "supportEmail" : { + "type" : "string" + }, + "supportPhone" : { + "type" : "string" + }, + "taxCode" : { + "type" : "string" + }, + "updatedAt" : { + "type" : "string", + "format" : "date-time" + }, + "zipCode" : { + "type" : "string" + } + } + }, + "MigrationOnboardedUser" : { + "title" : "MigrationOnboardedUser", + "type" : "object", + "properties" : { + "bindings" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/UserBinding" + } + }, + "createdAt" : { + "type" : "string", + "format" : "date-time" + }, + "id" : { + "type" : "string" + } + } + }, + "MigrationToken" : { + "title" : "MigrationToken", + "type" : "object", + "properties" : { + "checksum" : { + "type" : "string" + }, + "closedAt" : { + "type" : "string", + "format" : "date-time" + }, + "contractSigned" : { + "type" : "string" + }, + "contractTemplate" : { + "type" : "string" + }, + "contractVersion" : { + "type" : "string" + }, + "createdAt" : { + "type" : "string", + "format" : "date-time" + }, + "expiringDate" : { + "type" : "string", + "format" : "date-time" + }, + "id" : { + "type" : "string" + }, + "institutionId" : { + "type" : "string" + }, + "institutionUpdate" : { + "$ref" : "#/components/schemas/InstitutionUpdate" + }, + "productId" : { + "type" : "string" + }, + "status" : { + "type" : "string", + "enum" : [ "ACTIVE", "DELETED", "PENDING", "REJECTED", "SUSPENDED", "TOBEVALIDATED" ] + }, + "type" : { + "type" : "string", + "enum" : [ "INSTITUTION", "LEGALS" ] + }, + "updatedAt" : { + "type" : "string", + "format" : "date-time" + }, + "users" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/TokenUser" + } + } + } + }, + "OnboardedInstitutionResponse" : { + "title" : "OnboardedInstitutionResponse", + "type" : "object", + "properties" : { + "address" : { + "type" : "string" + }, + "aooParentCode" : { + "type" : "string" + }, + "attributes" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/AttributesResponse" + } + }, + "billing" : { + "$ref" : "#/components/schemas/Billing" + }, + "businessData" : { + "$ref" : "#/components/schemas/BusinessData" + }, + "dataProtectionOfficer" : { + "$ref" : "#/components/schemas/DataProtectionOfficerResponse" + }, + "description" : { + "type" : "string" + }, + "digitalAddress" : { + "type" : "string" + }, + "externalId" : { + "type" : "string" + }, + "geographicTaxonomies" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/GeoTaxonomies" + } + }, + "id" : { + "type" : "string" + }, + "institutionType" : { + "type" : "string", + "enum" : [ "AS", "GSP", "PA", "PG", "PSP", "PT", "SA", "SCP" ] + }, + "origin" : { + "type" : "string" + }, + "originId" : { + "type" : "string" + }, + "parentDescription" : { + "type" : "string" + }, + "paymentServiceProvider" : { + "$ref" : "#/components/schemas/PaymentServiceProviderResponse" + }, + "pricingPlan" : { + "type" : "string" + }, + "productInfo" : { + "$ref" : "#/components/schemas/ProductInfo" + }, + "role" : { + "type" : "string", + "enum" : [ "DELEGATE", "MANAGER", "OPERATOR", "SUB_DELEGATE" ] + }, + "rootParentId" : { + "type" : "string" + }, + "state" : { + "type" : "string" + }, + "subunitCode" : { + "type" : "string" + }, + "subunitType" : { + "type" : "string" + }, + "supportContact" : { + "$ref" : "#/components/schemas/SupportContact" + }, + "taxCode" : { + "type" : "string" + }, + "zipCode" : { + "type" : "string" + } + } + }, + "OnboardedProduct" : { + "title" : "OnboardedProduct", + "type" : "object", + "properties" : { + "contract" : { + "type" : "string" + }, + "createdAt" : { + "type" : "string", + "format" : "date-time" + }, + "env" : { + "type" : "string", + "enum" : [ "COLL", "DEV", "PROD", "ROOT" ] + }, + "productId" : { + "type" : "string" + }, + "productRole" : { + "type" : "string" + }, + "relationshipId" : { + "type" : "string" + }, + "role" : { + "type" : "string", + "enum" : [ "DELEGATE", "MANAGER", "OPERATOR", "SUB_DELEGATE" ] + }, + "status" : { + "type" : "string", + "enum" : [ "ACTIVE", "DELETED", "PENDING", "REJECTED", "SUSPENDED", "TOBEVALIDATED" ] + }, + "tokenId" : { + "type" : "string" + }, + "updatedAt" : { + "type" : "string", + "format" : "date-time" + } + } + }, + "OnboardedProductResponse" : { + "title" : "OnboardedProductResponse", + "type" : "object", + "properties" : { + "billing" : { + "$ref" : "#/components/schemas/BillingResponse" + }, + "createdAt" : { + "type" : "string", + "format" : "date-time" + }, + "productId" : { + "type" : "string" + }, + "status" : { + "type" : "string", + "enum" : [ "ACTIVE", "DELETED", "PENDING", "REJECTED", "SUSPENDED", "TOBEVALIDATED" ] + }, + "updatedAt" : { + "type" : "string", + "format" : "date-time" + } + } + }, + "OnboardedProducts" : { + "title" : "OnboardedProducts", + "type" : "object", + "properties" : { + "products" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/InstitutionProduct" + } + } + } + }, + "OnboardedUser" : { + "title" : "OnboardedUser", + "type" : "object", + "properties" : { + "bindings" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/UserBinding" + } + }, + "createdAt" : { + "type" : "string", + "format" : "date-time" + }, + "id" : { + "type" : "string" + } + } + }, + "Onboarding" : { + "title" : "Onboarding", + "type" : "object", + "properties" : { + "billing" : { + "$ref" : "#/components/schemas/Billing" + }, + "closedAt" : { + "type" : "string", + "format" : "date-time" + }, + "contract" : { + "type" : "string" + }, + "createdAt" : { + "type" : "string", + "format" : "date-time" + }, + "pricingPlan" : { + "type" : "string" + }, + "productId" : { + "type" : "string" + }, + "status" : { + "type" : "string", + "enum" : [ "ACTIVE", "DELETED", "PENDING", "REJECTED", "SUSPENDED", "TOBEVALIDATED" ] + }, + "tokenId" : { + "type" : "string" + }, + "updatedAt" : { + "type" : "string", + "format" : "date-time" + } + } + }, + "OnboardingImportContract" : { + "title" : "OnboardingImportContract", + "type" : "object", + "properties" : { + "contractType" : { + "type" : "string" + }, + "createdAt" : { + "type" : "string", + "format" : "date-time" + }, + "fileName" : { + "type" : "string" + }, + "filePath" : { + "type" : "string" + } + } + }, + "OnboardingInfoResponse" : { + "title" : "OnboardingInfoResponse", + "type" : "object", + "properties" : { + "institutions" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/OnboardedInstitutionResponse" + } + }, + "userId" : { + "type" : "string" + } + } + }, + "OnboardingInstitutionLegalsRequest" : { + "title" : "OnboardingInstitutionLegalsRequest", + "type" : "object", + "properties" : { + "contract" : { + "$ref" : "#/components/schemas/ContractRequest" + }, + "institutionExternalId" : { + "type" : "string" + }, + "institutionId" : { + "type" : "string" + }, + "productId" : { + "type" : "string" + }, + "productName" : { + "type" : "string" + }, + "signContract" : { + "type" : "boolean" + }, + "users" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/Person" + } + } + } + }, + "OnboardingInstitutionOperatorsRequest" : { + "title" : "OnboardingInstitutionOperatorsRequest", + "type" : "object", + "properties" : { + "institutionId" : { + "type" : "string" + }, + "productId" : { + "type" : "string" + }, + "productTitle" : { + "type" : "string" + }, + "users" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/Person" + } + } + } + }, + "OnboardingInstitutionRequest" : { + "title" : "OnboardingInstitutionRequest", + "type" : "object", + "properties" : { + "billing" : { + "$ref" : "#/components/schemas/BillingRequest" + }, + "contract" : { + "$ref" : "#/components/schemas/ContractRequest" + }, + "contractImported" : { + "$ref" : "#/components/schemas/OnboardingImportContract" + }, + "institutionExternalId" : { + "type" : "string" + }, + "institutionUpdate" : { + "$ref" : "#/components/schemas/InstitutionUpdateRequest" + }, + "pricingPlan" : { + "type" : "string" + }, + "productId" : { + "type" : "string" + }, + "productName" : { + "type" : "string" + }, + "sendCompleteOnboardingEmail" : { + "type" : "boolean", + "description" : "Parameter that allows you to specify whether following completion of onboarding you want to receive an email", + "example" : false + }, + "signContract" : { + "type" : "boolean" + }, + "users" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/Person" + } + } + } + }, + "OnboardingInstitutionUsersRequest" : { + "title" : "OnboardingInstitutionUsersRequest", + "type" : "object", + "properties" : { + "institutionSubunitCode" : { + "type" : "string" + }, + "institutionTaxCode" : { + "type" : "string" + }, + "productId" : { + "type" : "string" + }, + "sendCreateUserNotificationEmail" : { + "type" : "boolean" + }, + "users" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/Person" + } + } + } + }, + "OnboardingRequest" : { + "title" : "OnboardingRequest", + "type" : "object", + "properties" : { + "billingRequest" : { + "$ref" : "#/components/schemas/Billing" + }, + "contract" : { + "$ref" : "#/components/schemas/Contract" + }, + "contractCreatedAt" : { + "type" : "string", + "format" : "date-time" + }, + "contractFilePath" : { + "type" : "string" + }, + "institutionExternalId" : { + "type" : "string" + }, + "institutionUpdate" : { + "$ref" : "#/components/schemas/InstitutionUpdate" + }, + "pricingPlan" : { + "type" : "string" + }, + "productId" : { + "type" : "string" + }, + "productName" : { + "type" : "string" + }, + "sendCompleteOnboardingEmail" : { + "type" : "boolean" + }, + "signContract" : { + "type" : "boolean" + }, + "tokenType" : { + "type" : "string", + "enum" : [ "INSTITUTION", "LEGALS" ] + }, + "users" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/UserToOnboard" + } + } + } + }, + "OnboardingResponse" : { + "title" : "OnboardingResponse", + "type" : "object", + "properties" : { + "billing" : { + "$ref" : "#/components/schemas/BillingResponse" + }, + "closedAt" : { + "type" : "string", + "format" : "date-time" + }, + "contract" : { + "type" : "string" + }, + "createdAt" : { + "type" : "string", + "format" : "date-time" + }, + "pricingPlan" : { + "type" : "string" + }, + "productId" : { + "type" : "string" + }, + "status" : { + "type" : "string", + "enum" : [ "ACTIVE", "DELETED", "PENDING", "REJECTED", "SUSPENDED", "TOBEVALIDATED" ] + }, + "tokenId" : { + "type" : "string" + }, + "updatedAt" : { + "type" : "string", + "format" : "date-time" + } + } + }, + "OnboardingsResponse" : { + "title" : "OnboardingsResponse", + "type" : "object", + "properties" : { + "onboardings" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/OnboardingResponse" + } + } + } + }, + "PaAttributes" : { + "title" : "PaAttributes", + "type" : "object", + "properties" : { + "aooParentCode" : { + "type" : "string" + } + } + }, + "PaymentServiceProvider" : { + "title" : "PaymentServiceProvider", + "type" : "object", + "properties" : { + "abiCode" : { + "type" : "string" + }, + "businessRegisterNumber" : { + "type" : "string" + }, + "legalRegisterName" : { + "type" : "string" + }, + "legalRegisterNumber" : { + "type" : "string" + }, + "vatNumberGroup" : { + "type" : "boolean" + } + } + }, + "PaymentServiceProviderRequest" : { + "title" : "PaymentServiceProviderRequest", + "type" : "object", + "properties" : { + "abiCode" : { + "type" : "string" + }, + "businessRegisterNumber" : { + "type" : "string" + }, + "legalRegisterName" : { + "type" : "string" + }, + "legalRegisterNumber" : { + "type" : "string" + }, + "vatNumberGroup" : { + "type" : "boolean" + } + } + }, + "PaymentServiceProviderResponse" : { + "title" : "PaymentServiceProviderResponse", + "type" : "object", + "properties" : { + "abiCode" : { + "type" : "string" + }, + "businessRegisterNumber" : { + "type" : "string" + }, + "legalRegisterName" : { + "type" : "string" + }, + "legalRegisterNumber" : { + "type" : "string" + }, + "vatNumberGroup" : { + "type" : "boolean" + } + } + }, + "PdaInstitutionRequest" : { + "title" : "PdaInstitutionRequest", + "type" : "object", + "properties" : { + "billing" : { + "$ref" : "#/components/schemas/BillingRequest" + }, + "description" : { + "type" : "string" + }, + "injectionInstitutionType" : { + "type" : "string" + }, + "taxCode" : { + "type" : "string" + } + } + }, + "Person" : { + "title" : "Person", + "type" : "object", + "properties" : { + "email" : { + "type" : "string" + }, + "env" : { + "type" : "string", + "enum" : [ "COLL", "DEV", "PROD", "ROOT" ] + }, + "id" : { + "type" : "string" + }, + "name" : { + "type" : "string" + }, + "productRole" : { + "type" : "string" + }, + "role" : { + "type" : "string", + "enum" : [ "DELEGATE", "MANAGER", "OPERATOR", "SUB_DELEGATE" ] + }, + "roleLabel" : { + "type" : "string" + }, + "surname" : { + "type" : "string" + }, + "taxCode" : { + "type" : "string" + } + } + }, + "PersonId" : { + "title" : "PersonId", + "type" : "object", + "properties" : { + "id" : { + "type" : "string" + } + } + }, + "Problem" : { + "title" : "Problem", + "type" : "object", + "properties" : { + "errors" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/ProblemError" + } + }, + "status" : { + "type" : "integer", + "format" : "int32" + } + } + }, + "ProblemError" : { + "title" : "ProblemError", + "type" : "object" + }, + "Product" : { + "title" : "Product", + "type" : "object", + "properties" : { + "contract" : { + "type" : "string" + }, + "createdAt" : { + "type" : "string", + "format" : "date-time" + }, + "env" : { + "type" : "string", + "enum" : [ "COLL", "DEV", "PROD", "ROOT" ] + }, + "productId" : { + "type" : "string" + }, + "productRole" : { + "type" : "string" + }, + "role" : { + "type" : "string", + "enum" : [ "DELEGATE", "MANAGER", "OPERATOR", "SUB_DELEGATE" ] + }, + "status" : { + "type" : "string", + "enum" : [ "ACTIVE", "DELETED", "PENDING", "REJECTED", "SUSPENDED", "TOBEVALIDATED" ] + }, + "tokenId" : { + "type" : "string" + }, + "updatedAt" : { + "type" : "string", + "format" : "date-time" + } + } + }, + "ProductInfo" : { + "title" : "ProductInfo", + "type" : "object", + "properties" : { + "createdAt" : { + "type" : "string", + "format" : "date-time" + }, + "id" : { + "type" : "string" + }, + "role" : { + "type" : "string" + }, + "status" : { + "type" : "string" + } + } + }, + "ProductsManagement" : { + "title" : "ProductsManagement", + "type" : "object", + "properties" : { + "billing" : { + "$ref" : "#/components/schemas/BillingResponse" + }, + "pricingPlan" : { + "type" : "string" + }, + "product" : { + "type" : "string" + } + } + }, + "RelationshipResult" : { + "title" : "RelationshipResult", + "type" : "object", + "properties" : { + "billing" : { + "$ref" : "#/components/schemas/BillingResponse" + }, + "createdAt" : { + "type" : "string", + "format" : "date-time" + }, + "from" : { + "type" : "string" + }, + "id" : { + "type" : "string" + }, + "institutionUpdate" : { + "$ref" : "#/components/schemas/InstitutionUpdateResponse" + }, + "pricingPlan" : { + "type" : "string" + }, + "product" : { + "$ref" : "#/components/schemas/ProductInfo" + }, + "role" : { + "type" : "string", + "enum" : [ "DELEGATE", "MANAGER", "OPERATOR", "SUB_DELEGATE" ] + }, + "state" : { + "type" : "string", + "enum" : [ "ACTIVE", "DELETED", "PENDING", "REJECTED", "SUSPENDED", "TOBEVALIDATED" ] + }, + "to" : { + "type" : "string" + }, + "tokenId" : { + "type" : "string" + }, + "updatedAt" : { + "type" : "string", + "format" : "date-time" + } + } + }, + "RelationshipsManagement" : { + "title" : "RelationshipsManagement", + "type" : "object", + "properties" : { + "items" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/RelationshipResult" + } + } + } + }, + "RootParentResponse" : { + "title" : "RootParentResponse", + "type" : "object", + "properties" : { + "description" : { + "type" : "string" + }, + "id" : { + "type" : "string" + } + } + }, + "SupportContact" : { + "title" : "SupportContact", + "type" : "object", + "properties" : { + "supportEmail" : { + "type" : "string" + }, + "supportPhone" : { + "type" : "string" + } + } + }, + "Token" : { + "title" : "Token", + "type" : "object", + "properties" : { + "activatedAt" : { + "type" : "string", + "format" : "date-time" + }, + "checksum" : { + "type" : "string" + }, + "contentType" : { + "type" : "string" + }, + "contractSigned" : { + "type" : "string" + }, + "contractTemplate" : { + "type" : "string" + }, + "contractVersion" : { + "type" : "string" + }, + "createdAt" : { + "type" : "string", + "format" : "date-time" + }, + "deletedAt" : { + "type" : "string", + "format" : "date-time" + }, + "expiringDate" : { + "type" : "string", + "format" : "date-time" + }, + "id" : { + "type" : "string" + }, + "institutionId" : { + "type" : "string" + }, + "institutionUpdate" : { + "$ref" : "#/components/schemas/InstitutionUpdate" + }, + "productId" : { + "type" : "string" + }, + "status" : { + "type" : "string", + "enum" : [ "ACTIVE", "DELETED", "PENDING", "REJECTED", "SUSPENDED", "TOBEVALIDATED" ] + }, + "type" : { + "type" : "string", + "enum" : [ "INSTITUTION", "LEGALS" ] + }, + "updatedAt" : { + "type" : "string", + "format" : "date-time" + }, + "users" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/TokenUser" + } + } + } + }, + "TokenListResponse" : { + "title" : "TokenListResponse", + "type" : "object", + "properties" : { + "items" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/TokenResponse" + } + } + } + }, + "TokenResource" : { + "title" : "TokenResource", + "type" : "object", + "properties" : { + "checksum" : { + "type" : "string" + }, + "closedAt" : { + "type" : "string", + "format" : "date-time" + }, + "contractSigned" : { + "type" : "string" + }, + "contractTemplate" : { + "type" : "string" + }, + "contractVersion" : { + "type" : "string" + }, + "createdAt" : { + "type" : "string", + "format" : "date-time" + }, + "expiringDate" : { + "type" : "string", + "format" : "date-time" + }, + "id" : { + "type" : "string" + }, + "institutionId" : { + "type" : "string" + }, + "institutionUpdate" : { + "$ref" : "#/components/schemas/InstitutionUpdate" + }, + "productId" : { + "type" : "string" + }, + "status" : { + "type" : "string", + "enum" : [ "ACTIVE", "DELETED", "PENDING", "REJECTED", "SUSPENDED", "TOBEVALIDATED" ] + }, + "type" : { + "type" : "string", + "enum" : [ "INSTITUTION", "LEGALS" ] + }, + "updatedAt" : { + "type" : "string", + "format" : "date-time" + }, + "users" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/TokenUser" + } + } + } + }, + "TokenResponse" : { + "title" : "TokenResponse", + "type" : "object", + "properties" : { + "checksum" : { + "type" : "string" + }, + "closedAt" : { + "type" : "string", + "format" : "date-time" + }, + "contentType" : { + "type" : "string" + }, + "contractSigned" : { + "type" : "string" + }, + "contractTemplate" : { + "type" : "string" + }, + "contractVersion" : { + "type" : "string" + }, + "createdAt" : { + "type" : "string", + "format" : "date-time" + }, + "expiringDate" : { + "type" : "string", + "format" : "date-time" + }, + "id" : { + "type" : "string" + }, + "institutionId" : { + "type" : "string" + }, + "institutionUpdate" : { + "$ref" : "#/components/schemas/InstitutionUpdate" + }, + "legals" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/LegalsResponse" + } + }, + "productId" : { + "type" : "string" + }, + "status" : { + "type" : "string", + "enum" : [ "ACTIVE", "DELETED", "PENDING", "REJECTED", "SUSPENDED", "TOBEVALIDATED" ] + }, + "updatedAt" : { + "type" : "string", + "format" : "date-time" + }, + "users" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/TokenUser" + } + } + } + }, + "TokenUser" : { + "title" : "TokenUser", + "type" : "object", + "properties" : { + "role" : { + "type" : "string", + "enum" : [ "DELEGATE", "MANAGER", "OPERATOR", "SUB_DELEGATE" ] + }, + "userId" : { + "type" : "string" + } + } + }, + "UserBinding" : { + "title" : "UserBinding", + "type" : "object", + "properties" : { + "institutionId" : { + "type" : "string" + }, + "institutionName" : { + "type" : "string" + }, + "institutionRootName" : { + "type" : "string" + }, + "products" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/OnboardedProduct" + } + } + } + }, + "UserInfoResponse" : { + "title" : "UserInfoResponse", + "type" : "object", + "properties" : { + "email" : { + "type" : "string" + }, + "id" : { + "type" : "string" + }, + "name" : { + "type" : "string" + }, + "products" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/OnboardedProduct" + } + }, + "surname" : { + "type" : "string" + }, + "taxCode" : { + "type" : "string" + } + } + }, + "UserProductsResponse" : { + "title" : "UserProductsResponse", + "type" : "object", + "properties" : { + "bindings" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/InstitutionProducts" + } + }, + "id" : { + "type" : "string" + } + } + }, + "UserResponse" : { + "title" : "UserResponse", + "type" : "object", + "properties" : { + "email" : { + "type" : "string" + }, + "id" : { + "type" : "string" + }, + "name" : { + "type" : "string" + }, + "surname" : { + "type" : "string" + }, + "taxCode" : { + "type" : "string" + } + } + }, + "UserToOnboard" : { + "title" : "UserToOnboard", + "type" : "object", + "properties" : { + "email" : { + "type" : "string" + }, + "env" : { + "type" : "string", + "enum" : [ "COLL", "DEV", "PROD", "ROOT" ] + }, + "id" : { + "type" : "string" + }, + "name" : { + "type" : "string" + }, + "productRole" : { + "type" : "string" + }, + "role" : { + "type" : "string", + "enum" : [ "DELEGATE", "MANAGER", "OPERATOR", "SUB_DELEGATE" ] + }, + "roleLabel" : { + "type" : "string" + }, + "surname" : { + "type" : "string" + }, + "taxCode" : { + "type" : "string" + } + } + } + }, + "securitySchemes" : { + "bearerAuth" : { + "type" : "http", + "description" : "A bearer token in the format of a JWS and conformed to the specifications included in [RFC8725](https://tools.ietf.org/html/RFC8725)", + "scheme" : "bearer", + "bearerFormat" : "JWT" + } + } + } +} \ No newline at end of file diff --git a/onboarding-ms/src/main/openapi/user_registry.json b/apps/onboarding-functions/src/main/openapi/user_registry.json similarity index 100% rename from onboarding-ms/src/main/openapi/user_registry.json rename to apps/onboarding-functions/src/main/openapi/user_registry.json diff --git a/apps/onboarding-functions/src/main/resources/application.properties b/apps/onboarding-functions/src/main/resources/application.properties new file mode 100644 index 000000000..af51f06fc --- /dev/null +++ b/apps/onboarding-functions/src/main/resources/application.properties @@ -0,0 +1,115 @@ +quarkus.log.category."it.pagopa.selfcare.onboarding".level=DEBUG + +quarkus.mongodb.connection-string = ${MONGODB_CONNECTION_URI} +quarkus.mongodb.database = selcOnboarding + +quarkus.index-dependency.commons.group-id=it.pagopa.selfcare +quarkus.index-dependency.commons.artifact-id=selc-commons-base + +quarkus.index-dependency.onboarding.group-id=it.pagopa.selfcare +quarkus.index-dependency.onboarding.artifact-id=onboarding-sdk-common + +## RETRY POLICY FUNCTION ## +# Max number of attempts: The maximum number of attempts. If set to 1, there will be no retry. +# First retry interval: The amount of time to wait before the first retry attempt. +# Backoff coefficient: The coefficient used to determine rate of increase of backoff. Defaults to 1. +onboarding-functions.retry.max-attempts = 5 +onboarding-functions.retry.first-retry-interval = 30 +onboarding-functions.retry.backoff-coefficient = 5 + +## PURGE FUNCTION ## +# configuration for the start and end dates of the two functions +onboarding-functions.purge.completed-from = 60 +onboarding-functions.purge.completed-to = 30 +onboarding-functions.purge.all-from = 150 +onboarding-functions.purge.all-to = 120 + +## REST CLIENT # + +quarkus.openapi-generator.user_registry_json.auth.api_key.api-key = ${USER_REGISTRY_API_KEY:example-api-key} +quarkus.rest-client."org.openapi.quarkus.user_registry_json.api.UserApi".url=${USER_REGISTRY_URL:http://localhost:8080} + +quarkus.openapi-generator.codegen.spec.core_json.enable-security-generation=false +quarkus.openapi-generator.codegen.spec.core_json.additional-api-type-annotations=@org.eclipse.microprofile.rest.client.annotation.RegisterClientHeaders(it.pagopa.selfcare.onboarding.client.auth.AuthenticationPropagationHeadersFactory.class) +quarkus.rest-client."org.openapi.quarkus.core_json.api.InstitutionApi".url=${MS_CORE_URL:http://localhost:8080} + +## AZURE STORAGE ## + +onboarding-functions.blob-storage.container-contract=${STORAGE_CONTAINER_CONTRACT:selc-d-contracts-blob} +onboarding-functions.blob-storage.container-product=${STORAGE_CONTAINER_PRODUCT:selc-d-product} +onboarding-functions.blob-storage.contract-path = parties/docs/ +onboarding-functions.blob-storage.product-filepath = products.json +onboarding-functions.blob-storage.connection-string-contract = ${BLOB_STORAGE_CONN_STRING_CONTRACT:UseDevelopmentStorage=true;} +onboarding-functions.blob-storage.connection-string-product = ${BLOB_STORAGE_CONN_STRING_PRODUCT:UseDevelopmentStorage=true;} + + +## MAIL +onboarding-functions.sender-mail = ${MAIL_SENDER_ADDRESS:test@test.it} +onboarding-functions.destination-mail-test = ${MAIL_DESTINATION_TEST:true} +onboarding-functions.destination-mail-test-address = ${MAIL_DESTINATION_TEST_ADDRESS:test@test.it} +onboarding-functions.notification-admin-email = ${ADDRESS_EMAIL_NOTIFICATION_ADMIN:default} + +onboarding-functions.logo-path = ${PAGOPA_LOGO_URL:resources/logo.png} + +## MAIL TEMPLATE +onboarding-functions.mail-template.path.onboarding.complete-path = ${MAIL_TEMPLATE_COMPLETE_PATH:contracts/template/mail/onboarding-complete/1.0.0.json} +onboarding-functions.mail-template.path.onboarding.complete-path-fd = ${MAIL_TEMPLATE_FD_COMPLETE_NOTIFICATION_PATH:contracts/template/mail/onboarding-complete-fd/1.0.0.json} +onboarding-functions.mail-template.path.onboarding.complete-path-pt = ${MAIL_TEMPLATE_PT_COMPLETE_PATH:contracts/template/mail/onboarding-complete-pt/1.0.0.json} + +onboarding-functions.mail-template.path.onboarding.autocomplete-path = ${MAIL_TEMPLATE_AUTOCOMPLETE_PATH:default} +onboarding-functions.mail-template.path.onboarding.delegation-notification-path = ${MAIL_TEMPLATE_DELEGATION_NOTIFICATION_PATH:default} +onboarding-functions.mail-template.path.onboarding.registration-path = ${MAIL_TEMPLATE_REGISTRATION_PATH:contracts/template/mail/1.0.0.json} + +onboarding-functions.mail-template.path.onboarding.onboarding-approve-path = ${MAIL_TEMPLATE_NOTIFICATION_PATH:default} +onboarding-functions.mail-template.path.onboarding.registration-request-path = ${MAIL_TEMPLATE_REGISTRATION_REQUEST_PT_PATH:contracts/template/mail/registration-request-pt/1.0.0.json} +onboarding-functions.mail-template.path.onboarding.registration-approve-path = ${MAIL_TEMPLATE_REGISTRATION_NOTIFICATION_ADMIN_PATH:contracts/template/mail/registration-notification-admin/1.0.0.json} + +onboarding-functions.mail-template.path.onboarding.reject-path = ${MAIL_TEMPLATE_REJECT_PATH:default} + +## MAIL PLACEHOLDERS +onboarding-functions.mail-template.placeholders.onboarding.user-name = requesterName +onboarding-functions.mail-template.placeholders.onboarding.user-surname = requesterSurname +onboarding-functions.mail-template.placeholders.onboarding.product-name = productName +onboarding-functions.mail-template.placeholders.onboarding.institution-description = institutionName +onboarding-functions.mail-template.placeholders.onboarding.admin-link = ${SELFCARE_ADMIN_NOTIFICATION_URL:https://dev.selfcare.pagopa.it/dashboard/admin/onboarding/} + +onboarding-functions.mail-template.placeholders.onboarding.complete-selfcare-name = selfcareURL +onboarding-functions.mail-template.placeholders.onboarding.complete-product-name = productName +onboarding-functions.mail-template.placeholders.onboarding.complete-selfcare-placeholder= ${SELFCARE_URL:https://selfcare.pagopa.it} + +onboarding-functions.mail-template.placeholders.onboarding.confirm-token-name= confirmTokenURL +onboarding-functions.mail-template.placeholders.onboarding.confirm-token-placeholder = ${MAIL_ONBOARDING_CONFIRMATION_LINK:https://dev.selfcare.pagopa.it/onboarding/confirm?jwt=} + +onboarding-functions.mail-template.placeholders.onboarding.reject-token-placeholder = ${MAIL_ONBOARDING_REJECTION_LINK:https://dev.selfcare.pagopa.it/onboarding/cancel?jwt=} +onboarding-functions.mail-template.placeholders.onboarding.reject-token-name = rejectTokenURL + +onboarding-functions.mail-template.placeholders.onboarding.notification-product-name = productName +onboarding-functions.mail-template.placeholders.onboarding.notification-requester-name = requesterName +onboarding-functions.mail-template.placeholders.onboarding.notification-requester-surname = requesterSurname + +onboarding-functions.mail-template.placeholders.onboarding.reject-product-name=productName +onboarding-functions.mail-template.placeholders.onboarding.reject-onboarding-url-placeholder=onboardingUrl +onboarding-functions.mail-template.placeholders.onboarding.reject-onboarding-url-value=${MAIL_ONBOARDING_URL:https://dev.selfcare.pagopa.it/onboarding/} + +## MAIL SERVER +quarkus.mailer.host=${MAIL_SERVER_HOST:smtp.gmail.com} +quarkus.mailer.port=${MAIL_SERVER_PORT:587} +quarkus.mailer.username=${MAIL_SERVER_USERNAME:} +quarkus.mailer.password=${MAIL_SERVER_PASSWORD:} +quarkus.mailer.auth-methods=${MAIL_SERVER_SMTP_AUTH:LOGIN} +quarkus.mailer.start-tls=${MAIL_SERVER_SMTP_TLS_ENABLE:REQUIRED} + +#aws.ses.secret-id=${AWS_SES_ACCESS_KEY_ID:secret-id-example} +#aws.ses.secret-key=${AWS_SES_SECRET_ACCESS_KEY:secret-key-example} +#aws.ses.region=${AWS_SES_REGION:eu-south-1} + +## SIGNATURE +# You can enable the signature inside contracts when there are builded setting PAGOPA_SIGNATURE_SOURCE env (default value is `disabled`) as `local` if you want to use Pkcs7HashSignService or `aruba` for ArubaPkcs7HashSignService +onboarding-functions.pagopa-signature.source=${PAGOPA_SIGNATURE_SOURCE:disabled} +onboarding-functions.pagopa-signature.signer=${PAGOPA_SIGNATURE_SIGNER:PagoPA S.p.A.} +onboarding-functions.pagopa-signature.location=${PAGOPA_SIGNATURE_LOCATION:Roma} +onboarding-functions.pagopa-signature.apply-onboarding-enabled=${PAGOPA_SIGNATURE_ONBOARDING_ENABLED:false} +onboarding-functions.pagopa-signature.apply-onboarding-template-reason=${PAGOPA_SIGNATURE_ONBOARDING_REASON_TEMPLATE:Firma contratto adesione prodotto} + +## Jacoco +quarkus.jacoco.includes=it/pagopa/selfcare/onboarding/*,it/pagopa/selfcare/onboarding/service/**,it/pagopa/selfcare/onboarding/repository/** diff --git a/onboarding-functions/src/test/java/org/acme/HttpResponseMessageMock.java b/apps/onboarding-functions/src/test/java/it/pagopa/selfcare/onboarding/HttpResponseMessageMock.java similarity index 98% rename from onboarding-functions/src/test/java/org/acme/HttpResponseMessageMock.java rename to apps/onboarding-functions/src/test/java/it/pagopa/selfcare/onboarding/HttpResponseMessageMock.java index 75891d483..d8ba89bab 100644 --- a/onboarding-functions/src/test/java/org/acme/HttpResponseMessageMock.java +++ b/apps/onboarding-functions/src/test/java/it/pagopa/selfcare/onboarding/HttpResponseMessageMock.java @@ -1,4 +1,4 @@ -package org.acme; +package it.pagopa.selfcare.onboarding; import com.microsoft.azure.functions.HttpResponseMessage; import com.microsoft.azure.functions.HttpStatus; diff --git a/apps/onboarding-functions/src/test/java/it/pagopa/selfcare/onboarding/OnboardingCompletionFunctionsTest.java b/apps/onboarding-functions/src/test/java/it/pagopa/selfcare/onboarding/OnboardingCompletionFunctionsTest.java new file mode 100644 index 000000000..e642f9d22 --- /dev/null +++ b/apps/onboarding-functions/src/test/java/it/pagopa/selfcare/onboarding/OnboardingCompletionFunctionsTest.java @@ -0,0 +1,178 @@ +package it.pagopa.selfcare.onboarding; + +import com.microsoft.azure.functions.ExecutionContext; +import com.microsoft.azure.functions.HttpRequestMessage; +import com.microsoft.azure.functions.HttpResponseMessage; +import com.microsoft.azure.functions.HttpStatus; +import com.microsoft.durabletask.DurableTaskClient; +import com.microsoft.durabletask.Task; +import com.microsoft.durabletask.TaskOrchestrationContext; +import com.microsoft.durabletask.azurefunctions.DurableClientContext; +import io.quarkus.test.InjectMock; +import io.quarkus.test.junit.QuarkusTest; +import it.pagopa.selfcare.onboarding.entity.Institution; +import it.pagopa.selfcare.onboarding.entity.Onboarding; +import it.pagopa.selfcare.onboarding.exception.ResourceNotFoundException; +import it.pagopa.selfcare.onboarding.functions.OnboardingCompletionFunctions; +import it.pagopa.selfcare.onboarding.service.CompletionService; +import it.pagopa.selfcare.onboarding.service.OnboardingService; +import jakarta.inject.Inject; +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Mockito; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; + +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; +import java.util.logging.Logger; + +import static it.pagopa.selfcare.onboarding.functions.CommonFunctions.SAVE_ONBOARDING_STATUS_ACTIVITY; +import static it.pagopa.selfcare.onboarding.functions.OnboardingCompletionFunctions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; + +@QuarkusTest +public class OnboardingCompletionFunctionsTest { + + + @Inject + OnboardingCompletionFunctions function; + + @InjectMock + OnboardingService service; + + @InjectMock + CompletionService completionService; + + final String onboardinString = "{\"onboardingId\":\"onboardingId\"}"; + + /** + * Unit test for HttpTriggerJava method. + */ + @Test + public void testHttpTriggerJava() { + // Setup + @SuppressWarnings("unchecked") + final HttpRequestMessage> req = mock(HttpRequestMessage.class); + final HttpResponseMessage res = mock(HttpResponseMessage.class); + + final Map queryParams = new HashMap<>(); + final String onboardingId = "onboardingId"; + queryParams.put("onboardingId", onboardingId); + doReturn(queryParams).when(req).getQueryParameters(); + + final Optional queryBody = Optional.empty(); + doReturn(queryBody).when(req).getBody(); + + doAnswer(new Answer() { + @Override + public HttpResponseMessage.Builder answer(InvocationOnMock invocation) { + HttpStatus status = (HttpStatus) invocation.getArguments()[0]; + return new HttpResponseMessageMock.HttpResponseMessageBuilderMock().status(status); + } + }).when(req).createResponseBuilder(any(HttpStatus.class)); + + final ExecutionContext context = mock(ExecutionContext.class); + doReturn(Logger.getGlobal()).when(context).getLogger(); + + final DurableClientContext durableContext = mock(DurableClientContext.class); + final DurableTaskClient client = mock(DurableTaskClient.class); + final String scheduleNewOrchestrationInstance = "scheduleNewOrchestrationInstance"; + doReturn(client).when(durableContext).getClient(); + doReturn(scheduleNewOrchestrationInstance).when(client).scheduleNewOrchestrationInstance(ONBOARDING_COMPLETION_ACTIVITY, onboardingId); + doReturn(res).when(durableContext).createCheckStatusResponse(any(), any()); + + // Invoke + function.startOrchestration(req, durableContext, context); + + // Verify + ArgumentCaptor captorInstanceId = ArgumentCaptor.forClass(String.class); + Mockito.verify(durableContext, times(1)) + .createCheckStatusResponse(any(), captorInstanceId.capture()); + assertEquals(scheduleNewOrchestrationInstance, captorInstanceId.getValue()); + } + + + + @Test + void onboardingsOrchestrator_thorwExceptionIfOnboardingNotPresent() { + final String onboardingId = "onboardingId"; + TaskOrchestrationContext orchestrationContext = mock(TaskOrchestrationContext.class); + when(orchestrationContext.getInput(String.class)).thenReturn(onboardingId); + when(service.getOnboarding(onboardingId)).thenReturn(Optional.empty()); + assertThrows(ResourceNotFoundException.class, () -> function.onboardingCompletionOrchestrator(orchestrationContext)); + } + + + @Test + void onboardingCompletionOrchestrator() { + Onboarding onboarding = new Onboarding(); + onboarding.setOnboardingId("onboardingId"); + onboarding.setInstitution(new Institution()); + + TaskOrchestrationContext orchestrationContext = mockTaskOrchestrationContext(onboarding); + + function.onboardingCompletionOrchestrator(orchestrationContext); + + ArgumentCaptor captorActivity = ArgumentCaptor.forClass(String.class); + Mockito.verify(orchestrationContext, times(4)) + .callActivity(captorActivity.capture(), any(), any(),any()); + assertEquals(CREATE_INSTITUTION_ACTIVITY, captorActivity.getAllValues().get(0)); + assertEquals(CREATE_ONBOARDING_ACTIVITY, captorActivity.getAllValues().get(1)); + assertEquals(SEND_MAIL_COMPLETION_ACTIVITY, captorActivity.getAllValues().get(2)); + assertEquals(SAVE_ONBOARDING_STATUS_ACTIVITY, captorActivity.getAllValues().get(3)); + } + + + @Test + void createInstitutionAndPersistInstitutionId() { + ExecutionContext executionContext = mock(ExecutionContext.class); + when(executionContext.getLogger()).thenReturn(Logger.getGlobal()); + when(completionService.createInstitutionAndPersistInstitutionId(any())) + .thenReturn("id"); + + function.createInstitutionAndPersistInstitutionId(onboardinString, executionContext); + + Mockito.verify(completionService, times(1)) + .createInstitutionAndPersistInstitutionId(any()); + } + + @Test + void sendCompletedEmail() { + ExecutionContext executionContext = mock(ExecutionContext.class); + when(executionContext.getLogger()).thenReturn(Logger.getGlobal()); + doNothing().when(completionService).sendCompletedEmail(any()); + + function.sendMailCompletion(onboardinString, executionContext); + + Mockito.verify(completionService, times(1)) + .sendCompletedEmail(any()); + } + + @Test + void createOnboarding() { + ExecutionContext executionContext = mock(ExecutionContext.class); + when(executionContext.getLogger()).thenReturn(Logger.getGlobal()); + doNothing().when(completionService).persistOnboarding(any()); + + function.createOnboarding(onboardinString, executionContext); + + Mockito.verify(completionService, times(1)) + .persistOnboarding(any()); + } + + TaskOrchestrationContext mockTaskOrchestrationContext(Onboarding onboarding) { + TaskOrchestrationContext orchestrationContext = mock(TaskOrchestrationContext.class); + when(orchestrationContext.getInput(String.class)).thenReturn(onboarding.getOnboardingId()); + when(service.getOnboarding(onboarding.getOnboardingId())).thenReturn(Optional.of(onboarding)); + + Task task = mock(Task.class); + when(orchestrationContext.callActivity(any(),any(),any(),any())).thenReturn(task); + when(task.await()).thenReturn(onboardinString); + return orchestrationContext; + } +} diff --git a/apps/onboarding-functions/src/test/java/it/pagopa/selfcare/onboarding/OnboardingFunctionsTest.java b/apps/onboarding-functions/src/test/java/it/pagopa/selfcare/onboarding/OnboardingFunctionsTest.java new file mode 100644 index 000000000..bef2f9ec2 --- /dev/null +++ b/apps/onboarding-functions/src/test/java/it/pagopa/selfcare/onboarding/OnboardingFunctionsTest.java @@ -0,0 +1,297 @@ +package it.pagopa.selfcare.onboarding; + +import com.microsoft.azure.functions.ExecutionContext; +import com.microsoft.azure.functions.HttpRequestMessage; +import com.microsoft.azure.functions.HttpResponseMessage; +import com.microsoft.azure.functions.HttpStatus; +import com.microsoft.durabletask.DurableTaskClient; +import com.microsoft.durabletask.Task; +import com.microsoft.durabletask.TaskOrchestrationContext; +import com.microsoft.durabletask.azurefunctions.DurableClientContext; +import io.quarkus.test.InjectMock; +import io.quarkus.test.junit.QuarkusTest; +import it.pagopa.selfcare.onboarding.common.OnboardingStatus; +import it.pagopa.selfcare.onboarding.common.WorkflowType; +import it.pagopa.selfcare.onboarding.entity.Onboarding; +import it.pagopa.selfcare.onboarding.exception.ResourceNotFoundException; +import it.pagopa.selfcare.onboarding.functions.OnboardingFunctions; +import it.pagopa.selfcare.onboarding.service.OnboardingService; +import jakarta.inject.Inject; +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Mockito; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; + +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; +import java.util.logging.Logger; + +import static it.pagopa.selfcare.onboarding.functions.CommonFunctions.SAVE_ONBOARDING_STATUS_ACTIVITY; +import static it.pagopa.selfcare.onboarding.functions.OnboardingFunctions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; + + +/** + * Unit test for Function class. + */ +@QuarkusTest +public class OnboardingFunctionsTest { + + @Inject + OnboardingFunctions function; + + @InjectMock + OnboardingService service; + + final String onboardinString = "{\"onboardingId\":\"onboardingId\"}"; + + /** + * Unit test for HttpTriggerJava method. + */ + @Test + public void testHttpTriggerJava() throws Exception { + // Setup + @SuppressWarnings("unchecked") + final HttpRequestMessage> req = mock(HttpRequestMessage.class); + final HttpResponseMessage res = mock(HttpResponseMessage.class); + + final Map queryParams = new HashMap<>(); + final String onboardingId = "onboardingId"; + queryParams.put("onboardingId", onboardingId); + doReturn(queryParams).when(req).getQueryParameters(); + + final Optional queryBody = Optional.empty(); + doReturn(queryBody).when(req).getBody(); + + doAnswer(new Answer() { + @Override + public HttpResponseMessage.Builder answer(InvocationOnMock invocation) { + HttpStatus status = (HttpStatus) invocation.getArguments()[0]; + return new HttpResponseMessageMock.HttpResponseMessageBuilderMock().status(status); + } + }).when(req).createResponseBuilder(any(HttpStatus.class)); + + final ExecutionContext context = mock(ExecutionContext.class); + doReturn(Logger.getGlobal()).when(context).getLogger(); + + final DurableClientContext durableContext = mock(DurableClientContext.class); + final DurableTaskClient client = mock(DurableTaskClient.class); + final String scheduleNewOrchestrationInstance = "scheduleNewOrchestrationInstance"; + doReturn(client).when(durableContext).getClient(); + doReturn(scheduleNewOrchestrationInstance).when(client).scheduleNewOrchestrationInstance("Onboardings",onboardingId); + doReturn(res).when(durableContext).createCheckStatusResponse(any(), any()); + + // Invoke + function.startOrchestration(req, durableContext, context); + + // Verify + ArgumentCaptor captorInstanceId = ArgumentCaptor.forClass(String.class); + Mockito.verify(durableContext, times(1)) + .createCheckStatusResponse(any(), captorInstanceId.capture()); + assertEquals(scheduleNewOrchestrationInstance, captorInstanceId.getValue()); + } + + @Test + void onboardingsOrchestrator_thorwExceptionIfOnboardingNotPresent() { + final String onboardingId = "onboardingId"; + TaskOrchestrationContext orchestrationContext = mock(TaskOrchestrationContext.class); + when(orchestrationContext.getInput(String.class)).thenReturn(onboardingId); + when(service.getOnboarding(onboardingId)).thenReturn(Optional.empty()); + assertThrows(ResourceNotFoundException.class, () -> function.onboardingsOrchestrator(orchestrationContext)); + } + + @Test + void onboardingsOrchestratorContractRegistration() { + Onboarding onboarding = new Onboarding(); + onboarding.setOnboardingId("onboardingId"); + onboarding.setWorkflowType(WorkflowType.CONTRACT_REGISTRATION); + + TaskOrchestrationContext orchestrationContext = mockTaskOrchestrationContext(onboarding); + + function.onboardingsOrchestrator(orchestrationContext); + + Mockito.verify(orchestrationContext, times(4)) + .callActivity(any(), any(), any(),any()); + + ArgumentCaptor captorActivity = ArgumentCaptor.forClass(String.class); + Mockito.verify(orchestrationContext, times(4)) + .callActivity(captorActivity.capture(), any(), any(),any()); + assertEquals(BUILD_CONTRACT_ACTIVITY_NAME, captorActivity.getAllValues().get(0)); + assertEquals(SAVE_TOKEN_WITH_CONTRACT_ACTIVITY_NAME, captorActivity.getAllValues().get(1)); + assertEquals(SEND_MAIL_REGISTRATION_WITH_CONTRACT_ACTIVITY, captorActivity.getAllValues().get(2)); + assertEquals(SAVE_ONBOARDING_STATUS_ACTIVITY, captorActivity.getAllValues().get(3)); + } + + @Test + void onboardingsOrchestratorForApprove() { + Onboarding onboarding = new Onboarding(); + onboarding.setOnboardingId("onboardingId"); + onboarding.setStatus(OnboardingStatus.REQUEST); + onboarding.setWorkflowType(WorkflowType.FOR_APPROVE); + + TaskOrchestrationContext orchestrationContext = mockTaskOrchestrationContext(onboarding); + + function.onboardingsOrchestrator(orchestrationContext); + + ArgumentCaptor captorActivity = ArgumentCaptor.forClass(String.class); + Mockito.verify(orchestrationContext, times(2)) + .callActivity(captorActivity.capture(), any(), any(),any()); + assertEquals(SEND_MAIL_ONBOARDING_APPROVE_ACTIVITY, captorActivity.getAllValues().get(0)); + assertEquals(SAVE_ONBOARDING_STATUS_ACTIVITY, captorActivity.getAllValues().get(1)); + } + + @Test + void onboardingsOrchestratorForApproveWhenToBeValidated() { + Onboarding onboarding = new Onboarding(); + onboarding.setOnboardingId("onboardingId"); + onboarding.setStatus(OnboardingStatus.TO_BE_VALIDATED); + onboarding.setWorkflowType(WorkflowType.FOR_APPROVE); + + TaskOrchestrationContext orchestrationContext = mockTaskOrchestrationContext(onboarding); + + function.onboardingsOrchestrator(orchestrationContext); + + ArgumentCaptor captorActivity = ArgumentCaptor.forClass(String.class); + Mockito.verify(orchestrationContext, times(4)) + .callActivity(captorActivity.capture(), any(), any(),any()); + assertEquals(BUILD_CONTRACT_ACTIVITY_NAME, captorActivity.getAllValues().get(0)); + assertEquals(SAVE_TOKEN_WITH_CONTRACT_ACTIVITY_NAME, captorActivity.getAllValues().get(1)); + assertEquals(SEND_MAIL_REGISTRATION_WITH_CONTRACT_WHEN_APPROVE_ACTIVITY, captorActivity.getAllValues().get(2)); + assertEquals(SAVE_ONBOARDING_STATUS_ACTIVITY, captorActivity.getAllValues().get(3)); + } + + @Test + void onboardingsOrchestratorConfirmation() { + Onboarding onboarding = new Onboarding(); + onboarding.setOnboardingId("onboardingId"); + onboarding.setWorkflowType(WorkflowType.CONFIRMATION); + + TaskOrchestrationContext orchestrationContext = mockTaskOrchestrationContext(onboarding); + + function.onboardingsOrchestrator(orchestrationContext); + + ArgumentCaptor captorActivity = ArgumentCaptor.forClass(String.class); + Mockito.verify(orchestrationContext, times(2)) + .callActivity(captorActivity.capture(), any(), any(),any()); + assertEquals(SEND_MAIL_CONFIRMATION_ACTIVITY, captorActivity.getAllValues().get(0)); + assertEquals(SAVE_ONBOARDING_STATUS_ACTIVITY, captorActivity.getAllValues().get(1)); + } + + @Test + void onboardingsOrchestratorRegistrationRequestApprove() { + Onboarding onboarding = new Onboarding(); + onboarding.setOnboardingId("onboardingId"); + onboarding.setWorkflowType(WorkflowType.FOR_APPROVE_PT); + + TaskOrchestrationContext orchestrationContext = mockTaskOrchestrationContext(onboarding); + + function.onboardingsOrchestrator(orchestrationContext); + + ArgumentCaptor captorActivity = ArgumentCaptor.forClass(String.class); + Mockito.verify(orchestrationContext, times(3)) + .callActivity(captorActivity.capture(), any(), any(),any()); + assertEquals(SEND_MAIL_REGISTRATION_REQUEST_ACTIVITY, captorActivity.getAllValues().get(0)); + assertEquals(SEND_MAIL_REGISTRATION_APPROVE_ACTIVITY, captorActivity.getAllValues().get(1)); + assertEquals(SAVE_ONBOARDING_STATUS_ACTIVITY, captorActivity.getAllValues().get(2)); + } + + TaskOrchestrationContext mockTaskOrchestrationContext(Onboarding onboarding) { + TaskOrchestrationContext orchestrationContext = mock(TaskOrchestrationContext.class); + when(orchestrationContext.getInput(String.class)).thenReturn(onboarding.getOnboardingId()); + when(service.getOnboarding(onboarding.getOnboardingId())).thenReturn(Optional.of(onboarding)); + + Task task = mock(Task.class); + when(orchestrationContext.callActivity(any(),any(),any(),any())).thenReturn(task); + when(task.await()).thenReturn("example"); + return orchestrationContext; + } + + @Test + void buildContract() { + ExecutionContext executionContext = mock(ExecutionContext.class); + when(executionContext.getLogger()).thenReturn(Logger.getGlobal()); + doNothing().when(service).createContract(any()); + + function.buildContract(onboardinString, executionContext); + + Mockito.verify(service, times(1)) + .createContract(any()); + } + + @Test + void saveToken() { + ExecutionContext executionContext = mock(ExecutionContext.class); + when(executionContext.getLogger()).thenReturn(Logger.getGlobal()); + doNothing().when(service).saveTokenWithContract(any()); + + function.saveToken(onboardinString, executionContext); + + Mockito.verify(service, times(1)) + .saveTokenWithContract(any()); + } + + @Test + void sendMailRegistrationWithContract() { + ExecutionContext executionContext = mock(ExecutionContext.class); + when(executionContext.getLogger()).thenReturn(Logger.getGlobal()); + doNothing().when(service).sendMailRegistrationWithContract(any()); + + function.sendMailRegistrationWithContract(onboardinString, executionContext); + + Mockito.verify(service, times(1)) + .sendMailRegistrationWithContract(any()); + } + + @Test + void sendMailRegistration() { + ExecutionContext executionContext = mock(ExecutionContext.class); + when(executionContext.getLogger()).thenReturn(Logger.getGlobal()); + doNothing().when(service).sendMailRegistration(any()); + + function.sendMailRegistration(onboardinString, executionContext); + + Mockito.verify(service, times(1)) + .sendMailRegistration(any()); + } + + @Test + void sendMailRegistrationApprove() { + ExecutionContext executionContext = mock(ExecutionContext.class); + when(executionContext.getLogger()).thenReturn(Logger.getGlobal()); + doNothing().when(service).sendMailRegistrationApprove(any()); + + function.sendMailRegistrationApprove(onboardinString, executionContext); + + Mockito.verify(service, times(1)) + .sendMailRegistrationApprove(any()); + } + + @Test + void sendMailOnboardingApprove() { + ExecutionContext executionContext = mock(ExecutionContext.class); + when(executionContext.getLogger()).thenReturn(Logger.getGlobal()); + doNothing().when(service).sendMailOnboardingApprove(any()); + + function.sendMailOnboardingApprove(onboardinString, executionContext); + + Mockito.verify(service, times(1)) + .sendMailOnboardingApprove(any()); + } + + @Test + void sendMailRegistrationWithContractWhenApprove() { + ExecutionContext executionContext = mock(ExecutionContext.class); + when(executionContext.getLogger()).thenReturn(Logger.getGlobal()); + doNothing().when(service).sendMailRegistrationWithContractWhenApprove(any()); + + function.sendMailRegistrationWithContractWhenApprove(onboardinString, executionContext); + + Mockito.verify(service, times(1)) + .sendMailRegistrationWithContractWhenApprove(any()); + } +} diff --git a/apps/onboarding-functions/src/test/java/it/pagopa/selfcare/onboarding/repository/TokenRepositoryTest.java b/apps/onboarding-functions/src/test/java/it/pagopa/selfcare/onboarding/repository/TokenRepositoryTest.java new file mode 100644 index 000000000..a0f29be4e --- /dev/null +++ b/apps/onboarding-functions/src/test/java/it/pagopa/selfcare/onboarding/repository/TokenRepositoryTest.java @@ -0,0 +1,34 @@ +package it.pagopa.selfcare.onboarding.repository; + +import io.quarkus.mongodb.panache.PanacheQuery; +import io.quarkus.test.InjectMock; +import io.quarkus.test.junit.QuarkusTest; +import it.pagopa.selfcare.onboarding.entity.Token; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +import java.util.Optional; + +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +@QuarkusTest +public class TokenRepositoryTest { + @InjectMock + TokenRepository tokenRepository; + + @Test + void findByOnboardingId() { + final String onboardingId = "onboardingId"; + PanacheQuery panacheQuery = mock(PanacheQuery.class); + when(panacheQuery.firstResultOptional()).thenReturn(Optional.of(new Token())); + Mockito.when(tokenRepository.find(TokenRepository.ONBOARDING_ID_FIELD, onboardingId)) + .thenReturn(panacheQuery); + + // Instruct mockito to call real method that you are testing + Mockito.when(tokenRepository.findByOnboardingId(onboardingId)).thenCallRealMethod(); + Optional token = tokenRepository.findByOnboardingId(onboardingId); + assertTrue(token.isPresent()); + } +} diff --git a/apps/onboarding-functions/src/test/java/it/pagopa/selfcare/onboarding/service/CompletionServiceDefaultTest.java b/apps/onboarding-functions/src/test/java/it/pagopa/selfcare/onboarding/service/CompletionServiceDefaultTest.java new file mode 100644 index 000000000..a89163279 --- /dev/null +++ b/apps/onboarding-functions/src/test/java/it/pagopa/selfcare/onboarding/service/CompletionServiceDefaultTest.java @@ -0,0 +1,333 @@ +package it.pagopa.selfcare.onboarding.service; + +import io.quarkus.mongodb.panache.common.PanacheUpdate; +import io.quarkus.test.InjectMock; +import io.quarkus.test.junit.QuarkusTest; +import it.pagopa.selfcare.onboarding.common.InstitutionPaSubunitType; +import it.pagopa.selfcare.onboarding.common.InstitutionType; +import it.pagopa.selfcare.onboarding.common.Origin; +import it.pagopa.selfcare.onboarding.common.PartyRole; +import it.pagopa.selfcare.onboarding.entity.*; +import it.pagopa.selfcare.onboarding.exception.GenericOnboardingException; +import it.pagopa.selfcare.onboarding.repository.OnboardingRepository; +import it.pagopa.selfcare.onboarding.repository.TokenRepository; +import it.pagopa.selfcare.product.entity.Product; +import it.pagopa.selfcare.product.service.ProductService; +import jakarta.inject.Inject; +import org.bson.types.ObjectId; +import org.eclipse.microprofile.rest.client.inject.RestClient; +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Mockito; +import org.openapi.quarkus.core_json.api.InstitutionApi; +import org.openapi.quarkus.core_json.model.InstitutionFromIpaPost; +import org.openapi.quarkus.core_json.model.InstitutionOnboardingRequest; +import org.openapi.quarkus.core_json.model.InstitutionResponse; +import org.openapi.quarkus.core_json.model.InstitutionsResponse; +import org.openapi.quarkus.user_registry_json.api.UserApi; +import org.openapi.quarkus.user_registry_json.model.CertifiableFieldResourceOfstring; +import org.openapi.quarkus.user_registry_json.model.UserResource; +import org.openapi.quarkus.user_registry_json.model.WorkContactResource; + +import java.util.*; + +import static it.pagopa.selfcare.onboarding.service.OnboardingService.USERS_WORKS_FIELD_LIST; +import static it.pagopa.selfcare.onboarding.utils.PdfMapper.workContactsKey; +import static it.pagopa.selfcare.onboarding.service.OnboardingService.USERS_FIELD_LIST; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.Mockito.*; + +@QuarkusTest +public class CompletionServiceDefaultTest { + + public static final String MANAGER_WORKCONTRACT_MAIL = "mail@mail.it"; + @Inject + CompletionServiceDefault completionServiceDefault; + + @InjectMock + OnboardingRepository onboardingRepository; + @InjectMock + TokenRepository tokenRepository; + @InjectMock + NotificationService notificationService; + @InjectMock + ProductService productService; + + @RestClient + @InjectMock + InstitutionApi institutionApi; + @RestClient + @InjectMock + UserApi userRegistryApi; + + final String productId = "productId"; + + @Test + void createInstitutionAndPersistInstitutionId_shouldThrowExceptionIfMoreInstitutions() { + Onboarding onboarding = createOnboarding(); + + InstitutionsResponse response = new InstitutionsResponse(); + response.setInstitutions(List.of(new InstitutionResponse(), new InstitutionResponse())); + when(institutionApi.getInstitutionsUsingGET(onboarding.getInstitution().getTaxCode(), + onboarding.getInstitution().getSubunitCode(), null, null)) + .thenReturn(response); + + assertThrows(GenericOnboardingException.class, () -> completionServiceDefault.createInstitutionAndPersistInstitutionId(onboarding)); + } + + @Test + void createInstitutionAndPersistInstitutionId_foundInstitution() { + Onboarding onboarding = createOnboarding(); + + InstitutionsResponse response = new InstitutionsResponse(); + InstitutionResponse institutionResponse = new InstitutionResponse(); + institutionResponse.setId("actual-id"); + response.setInstitutions(List.of(institutionResponse)); + when(institutionApi.getInstitutionsUsingGET(onboarding.getInstitution().getTaxCode(), + onboarding.getInstitution().getSubunitCode(), null, null)) + .thenReturn(response); + + mockOnboardingUpdateAndExecuteCreateInstitution(onboarding, institutionResponse); + } + + void mockOnboardingUpdateAndExecuteCreateInstitution(Onboarding onboarding, InstitutionResponse institutionResponse){ + PanacheUpdate panacheUpdateMock = mock(PanacheUpdate.class); + when(panacheUpdateMock.where("_id", onboarding.getOnboardingId())) + .thenReturn(Long.valueOf(1)); + when(onboardingRepository.update("institution.id", institutionResponse.getId())) + .thenReturn(panacheUpdateMock); + + completionServiceDefault.createInstitutionAndPersistInstitutionId(onboarding); + + verify(onboardingRepository, times(1)) + .update("institution.id", institutionResponse.getId()); + } + + @Test + void createInstitutionAndPersistInstitutionId_notFoundInstitutionAndCreateSaAnac() { + Onboarding onboarding = createOnboarding(); + + Institution institutionSa = new Institution(); + institutionSa.setInstitutionType(InstitutionType.SA); + institutionSa.setOrigin(Origin.ANAC); + onboarding.setInstitution(institutionSa); + + InstitutionsResponse response = new InstitutionsResponse(); + when(institutionApi.getInstitutionsUsingGET(onboarding.getInstitution().getTaxCode(), + onboarding.getInstitution().getSubunitCode(), null, null)) + .thenReturn(response); + + InstitutionResponse institutionResponse = dummyInstitutionResponse(); + when(institutionApi.createInstitutionFromAnacUsingPOST(any())).thenReturn(institutionResponse); + + mockOnboardingUpdateAndExecuteCreateInstitution(onboarding, institutionResponse); + } + + @Test + void createInstitutionAndPersistInstitutionId_notFoundInstitutionAndCreateAsIvass() { + Onboarding onboarding = createOnboarding(); + + Institution institution = new Institution(); + institution.setInstitutionType(InstitutionType.AS); + institution.setOrigin(Origin.IVASS); + onboarding.setInstitution(institution); + + InstitutionsResponse response = new InstitutionsResponse(); + when(institutionApi.getInstitutionsUsingGET(onboarding.getInstitution().getTaxCode(), + onboarding.getInstitution().getSubunitCode(), null, null)) + .thenReturn(response); + + InstitutionResponse institutionResponse = dummyInstitutionResponse(); + when(institutionApi.createInstitutionFromIvassUsingPOST(any())).thenReturn(institutionResponse); + + mockOnboardingUpdateAndExecuteCreateInstitution(onboarding, institutionResponse); + } + @Test + void createInstitutionAndPersistInstitutionId_notFoundInstitutionAndCreatePgAde() { + Onboarding onboarding = createOnboarding(); + + Institution institution = new Institution(); + institution.setInstitutionType(InstitutionType.PG); + institution.setOrigin(Origin.ADE); + onboarding.setInstitution(institution); + + InstitutionsResponse response = new InstitutionsResponse(); + when(institutionApi.getInstitutionsUsingGET(onboarding.getInstitution().getTaxCode(), + onboarding.getInstitution().getSubunitCode(), null, null)) + .thenReturn(response); + + InstitutionResponse institutionResponse = dummyInstitutionResponse(); + when(institutionApi.createInstitutionFromInfocamereUsingPOST(any())).thenReturn(institutionResponse); + + mockOnboardingUpdateAndExecuteCreateInstitution(onboarding, institutionResponse); + } + @Test + void createInstitutionAndPersistInstitutionId_notFoundInstitutionAndCreatePa() { + Onboarding onboarding = createOnboarding(); + + Institution institution = new Institution(); + institution.setInstitutionType(InstitutionType.PA); + institution.setSubunitType(InstitutionPaSubunitType.AOO); + institution.setSubunitCode("code"); + onboarding.setInstitution(institution); + + InstitutionsResponse response = new InstitutionsResponse(); + when(institutionApi.getInstitutionsUsingGET(onboarding.getInstitution().getTaxCode(), + onboarding.getInstitution().getSubunitCode(), null, null)) + .thenReturn(response); + + InstitutionResponse institutionResponse = dummyInstitutionResponse(); + when(institutionApi.createInstitutionFromIpaUsingPOST(any())).thenReturn(institutionResponse); + + mockOnboardingUpdateAndExecuteCreateInstitution(onboarding, institutionResponse); + + ArgumentCaptor captor = ArgumentCaptor.forClass(InstitutionFromIpaPost.class); + verify(institutionApi, times(1)) + .createInstitutionFromIpaUsingPOST(captor.capture()); + assertEquals(institution.getTaxCode(), captor.getValue().getTaxCode()); + assertEquals(institution.getSubunitCode(), captor.getValue().getSubunitCode()); + } + + @Test + void persistOnboarding_workContractsNotFound() { + Onboarding onboarding = createOnboarding(); + + User manager = new User(); + manager.setId("id"); + manager.setRole(PartyRole.MANAGER); + onboarding.setUsers(List.of(manager)); + + when(userRegistryApi.findByIdUsingGET(USERS_WORKS_FIELD_LIST, manager.getId())) + .thenReturn(new UserResource()); + + assertThrows(GenericOnboardingException.class, () -> completionServiceDefault.persistOnboarding(onboarding)); + } + + @Test + void persistOnboarding() { + Onboarding onboarding = createOnboarding(); + + User manager = new User(); + manager.setId("id"); + manager.setRole(PartyRole.MANAGER); + onboarding.setUsers(List.of(manager)); + + UserResource userResource = dummyUserResource(onboarding.getOnboardingId()); + + when(userRegistryApi.findByIdUsingGET(USERS_WORKS_FIELD_LIST, manager.getId())) + .thenReturn(userResource); + when(institutionApi.onboardingInstitutionUsingPOST(any(), any())) + .thenReturn(new InstitutionResponse()); + Token token = new Token(); + token.setContractSigned("contract-signed-path"); + when(tokenRepository.findByOnboardingId(onboarding.getOnboardingId())) + .thenReturn(Optional.of(token)); + + completionServiceDefault.persistOnboarding(onboarding); + + ArgumentCaptor captor = ArgumentCaptor.forClass(InstitutionOnboardingRequest.class); + verify(institutionApi, times(1)) + .onboardingInstitutionUsingPOST(any(), captor.capture()); + + verify(tokenRepository, times(1)) + .findByOnboardingId(onboarding.getOnboardingId()); + + InstitutionOnboardingRequest actual = captor.getValue(); + assertEquals(onboarding.getProductId(), actual.getProductId()); + assertEquals(onboarding.getPricingPlan(), actual.getPricingPlan()); + assertEquals(1, actual.getUsers().size()); + assertEquals(MANAGER_WORKCONTRACT_MAIL, actual.getUsers().get(0).getEmail()); + assertEquals(manager.getRole().name(), actual.getUsers().get(0).getRole().name()); + assertEquals(token.getContractSigned(), actual.getContractPath()); + } + + @Test + void sendCompletedEmail() { + + UserResource userResource = new UserResource(); + userResource.setId(UUID.randomUUID()); + Map map = new HashMap<>(); + userResource.setWorkContacts(map); + Product product = createDummyProduct(); + Onboarding onboarding = createOnboarding(); + + User user = new User(); + user.setRole(PartyRole.MANAGER); + user.setId("user-id"); + onboarding.setUsers(List.of(user)); + + when(productService.getProduct(onboarding.getProductId())) + .thenReturn(product); + when(userRegistryApi.findByIdUsingGET(USERS_FIELD_LIST, user.getId())) + .thenReturn(userResource); + doNothing().when(notificationService).sendCompletedEmail(any(), any(), any()); + + completionServiceDefault.sendCompletedEmail(onboarding); + + Mockito.verify(notificationService, times(1)) + .sendCompletedEmail(any(), any(), any()); + } + + private InstitutionResponse dummyInstitutionResponse() { + InstitutionResponse response = new InstitutionResponse(); + response.setId("response-id"); + return response; + } + + + private Onboarding createOnboarding() { + Onboarding onboarding = new Onboarding(); + onboarding.setId(ObjectId.get()); + onboarding.setOnboardingId(onboarding.getId().toHexString()); + onboarding.setProductId(productId); + onboarding.setPricingPlan("pricingPlan"); + onboarding.setUsers(List.of()); + onboarding.setInstitution(new Institution()); + onboarding.setUserRequestUid("example-uid"); + + Billing billing = new Billing(); + billing.setPublicServices(true); + billing.setRecipientCode("example"); + billing.setVatNumber("example"); + onboarding.setBilling(billing); + return onboarding; + } + + private Product createDummyProduct() { + Product product = new Product(); + product.setContractTemplatePath("example"); + product.setContractTemplateVersion("version"); + product.setTitle("Title"); + product.setId(productId); + return product; + } + + private UserResource dummyUserResource(String onboardingId){ + UserResource userResource = new UserResource(); + userResource.setId(UUID.randomUUID()); + + CertifiableFieldResourceOfstring resourceOfName = new CertifiableFieldResourceOfstring(); + resourceOfName.setCertification(CertifiableFieldResourceOfstring.CertificationEnum.NONE); + resourceOfName.setValue("name"); + userResource.setName(resourceOfName); + + CertifiableFieldResourceOfstring resourceOfSurname = new CertifiableFieldResourceOfstring(); + resourceOfSurname.setCertification(CertifiableFieldResourceOfstring.CertificationEnum.NONE); + resourceOfSurname.setValue("surname"); + userResource.setFamilyName(resourceOfSurname); + + + CertifiableFieldResourceOfstring resourceOfMail = new CertifiableFieldResourceOfstring(); + resourceOfMail.setCertification(CertifiableFieldResourceOfstring.CertificationEnum.NONE); + resourceOfMail.setValue(MANAGER_WORKCONTRACT_MAIL); + WorkContactResource workContactResource = new WorkContactResource(); + workContactResource.email(resourceOfMail); + + Map map = new HashMap<>(); + map.put(workContactsKey.apply(onboardingId), workContactResource); + userResource.setWorkContacts(map); + return userResource; + } +} + diff --git a/apps/onboarding-functions/src/test/java/it/pagopa/selfcare/onboarding/service/ContractServiceDefaultTest.java b/apps/onboarding-functions/src/test/java/it/pagopa/selfcare/onboarding/service/ContractServiceDefaultTest.java new file mode 100644 index 000000000..c2ffca5e5 --- /dev/null +++ b/apps/onboarding-functions/src/test/java/it/pagopa/selfcare/onboarding/service/ContractServiceDefaultTest.java @@ -0,0 +1,196 @@ +package it.pagopa.selfcare.onboarding.service; + +import io.quarkus.test.InjectMock; +import io.quarkus.test.junit.QuarkusTest; +import it.pagopa.selfcare.azurestorage.AzureBlobClient; +import it.pagopa.selfcare.onboarding.common.InstitutionType; +import it.pagopa.selfcare.onboarding.config.AzureStorageConfig; +import it.pagopa.selfcare.onboarding.config.PagoPaSignatureConfig; +import it.pagopa.selfcare.onboarding.crypto.PadesSignService; +import it.pagopa.selfcare.onboarding.entity.Institution; +import it.pagopa.selfcare.onboarding.entity.Onboarding; +import jakarta.inject.Inject; +import org.bson.types.ObjectId; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Mockito; +import org.openapi.quarkus.user_registry_json.model.CertifiableFieldResourceOfstring; +import org.openapi.quarkus.user_registry_json.model.UserResource; +import org.openapi.quarkus.user_registry_json.model.WorkContactResource; + +import java.io.File; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +import static it.pagopa.selfcare.onboarding.utils.PdfMapper.workContactsKey; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; + +@QuarkusTest +class ContractServiceDefaultTest { + + @Inject + AzureStorageConfig azureStorageConfig; + + @InjectMock + AzureBlobClient azureBlobClient; + PadesSignService padesSignService; + + @Inject + ContractService contractService; + + @Inject + PagoPaSignatureConfig pagoPaSignatureConfig; + + + final static String productNameExample = "product-name"; + + @BeforeEach + void setup(){ + padesSignService = mock(PadesSignService.class); + contractService = new ContractServiceDefault(azureStorageConfig, azureBlobClient, padesSignService, pagoPaSignatureConfig, "logo- path"); + } + + + private Onboarding createOnboarding() { + Onboarding onboarding = new Onboarding(); + onboarding.setId(ObjectId.get()); + onboarding.setOnboardingId("example"); + onboarding.setProductId("productId"); + onboarding.setUsers(List.of()); + + Institution institution = new Institution(); + institution.setInstitutionType(InstitutionType.PSP); + institution.setDescription("42"); + + institution.setRea("rea"); + institution.setBusinessRegisterPlace("place"); + institution.setShareCapital("10000"); + onboarding.setInstitution(institution); + return onboarding; + } + + UserResource createDummyUserResource(String onboardingId) { + UserResource validManager = new UserResource(); + + CertifiableFieldResourceOfstring emailCert = new CertifiableFieldResourceOfstring(); + emailCert.setValue("email"); + WorkContactResource workContact = new WorkContactResource(); + workContact.setEmail(emailCert); + Map map = new HashMap<>(); + map.put(workContactsKey.apply(onboardingId), workContact); + + validManager.setWorkContacts(map); + return validManager; + } + + @Test + void createContractPDF() { + final String contractFilepath = "contract"; + final String contractHtml = "contract"; + final String productNameAccent = "Interoperabilità"; + + Onboarding onboarding = createOnboarding(); + UserResource manager = createDummyUserResource(onboarding.getOnboardingId()); + + Mockito.when(azureBlobClient.getFileAsText(contractFilepath)).thenReturn(contractHtml); + + Mockito.when(azureBlobClient.uploadFile(any(),any(),any())).thenReturn(contractHtml); + + File contract = contractService.createContractPDF(contractFilepath, onboarding, manager, List.of(), productNameAccent); + + assertNotNull(contract); + + ArgumentCaptor captorFilename = ArgumentCaptor.forClass(String.class); + verify(azureBlobClient, times(1)) + .uploadFile(any(),captorFilename.capture(),any()); + assertEquals("Interoperabilita_accordo_adesione.pdf", captorFilename.getValue()); + } + + @Test + void createContractPDFSA() { + final String contractFilepath = "contract"; + final String contractHtml = "contract"; + + Onboarding onboarding = createOnboarding(); + UserResource manager = createDummyUserResource(onboarding.getOnboardingId()); + onboarding.getInstitution().setInstitutionType(InstitutionType.SA); + + Mockito.when(azureBlobClient.getFileAsText(contractFilepath)).thenReturn(contractHtml); + + Mockito.when(azureBlobClient.uploadFile(any(),any(),any())).thenReturn(contractHtml); + + assertNotNull(contractService.createContractPDF(contractFilepath, onboarding, manager, List.of(), productNameExample)); + } + + @Test + void createContractPDFAndSigned() { + final String contractFilepath = "contract"; + final String contractHtml = "contract"; + + Onboarding onboarding = createOnboarding(); + UserResource manager = createDummyUserResource(onboarding.getOnboardingId()); + + PagoPaSignatureConfig pagoPaSignatureConfig = Mockito.spy(this.pagoPaSignatureConfig); + when(pagoPaSignatureConfig.source()).thenReturn("local"); + contractService = new ContractServiceDefault(azureStorageConfig, azureBlobClient, padesSignService, pagoPaSignatureConfig, "logo-path"); + + Mockito.when(azureBlobClient.getFileAsText(contractFilepath)).thenReturn(contractHtml); + + Mockito.doNothing().when(padesSignService).padesSign(any(),any(),any()); + + Mockito.when(azureBlobClient.uploadFile(any(),any(),any())).thenReturn(contractHtml); + + assertNotNull(contractService.createContractPDF(contractFilepath, onboarding, manager, List.of(), productNameExample)); + } + + + + @Test + void loadContractPDF() { + final String contractFilepath = "contract"; + final String contractHtml = "contract"; + + Onboarding onboarding = createOnboarding(); + + File pdf = new File(Objects.requireNonNull(getClass().getClassLoader().getResource("application.properties")).getFile()); + + Mockito.when(azureBlobClient.getFileAsPdf(contractFilepath)).thenReturn(pdf); + + Mockito.when(azureBlobClient.uploadFile(any(), any(), any())).thenReturn(contractHtml); + + assertNotNull(contractService.loadContractPDF(contractFilepath, onboarding.getId().toHexString(), productNameExample)); + } + + @Test + void retrieveContractNotSigned() { + + Onboarding onboarding = createOnboarding(); + + File pdf = mock(File.class); + Mockito.when(azureBlobClient.getFileAsPdf(any())).thenReturn(pdf); + + contractService.retrieveContractNotSigned(onboarding.getOnboardingId(), productNameExample); + + ArgumentCaptor filepathActual = ArgumentCaptor.forClass(String.class); + Mockito.verify(azureBlobClient, times(1)) + .getFileAsPdf(filepathActual.capture()); + assertTrue(filepathActual.getValue().contains(onboarding.getOnboardingId())); + assertTrue(filepathActual.getValue().contains(productNameExample)); + } + + + @Test + void getLogoFile() { + Mockito.when(azureBlobClient.getFileAsText(any())).thenReturn("example"); + + contractService.getLogoFile(); + + Mockito.verify(azureBlobClient, times(1)) + .getFileAsText(any()); + } +} diff --git a/apps/onboarding-functions/src/test/java/it/pagopa/selfcare/onboarding/service/NotificationServiceDefaultTest.java b/apps/onboarding-functions/src/test/java/it/pagopa/selfcare/onboarding/service/NotificationServiceDefaultTest.java new file mode 100644 index 000000000..fc6045db7 --- /dev/null +++ b/apps/onboarding-functions/src/test/java/it/pagopa/selfcare/onboarding/service/NotificationServiceDefaultTest.java @@ -0,0 +1,188 @@ +package it.pagopa.selfcare.onboarding.service; + +import com.fasterxml.jackson.databind.ObjectMapper; +import io.quarkus.mailer.Mail; +import io.quarkus.mailer.Mailer; +import io.quarkus.test.InjectMock; +import io.quarkus.test.junit.QuarkusTest; +import it.pagopa.selfcare.azurestorage.AzureBlobClient; +import it.pagopa.selfcare.onboarding.common.InstitutionType; +import it.pagopa.selfcare.onboarding.config.MailTemplatePathConfig; +import it.pagopa.selfcare.onboarding.config.MailTemplatePlaceholdersConfig; +import it.pagopa.selfcare.product.entity.Product; +import jakarta.inject.Inject; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Mockito; + +import java.io.File; +import java.util.List; +import java.util.Objects; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; + +@QuarkusTest +class NotificationServiceDefaultTest { + + @InjectMock + AzureBlobClient azureBlobClient; + @InjectMock + ContractService contractService; + @Inject + MailTemplatePlaceholdersConfig templatePlaceholdersConfig; + @Inject + MailTemplatePathConfig templatePathConfig; + @Inject + ObjectMapper objectMapper; + Mailer mailer; + NotificationServiceDefault notificationService; + + final String notificationAdminMail = "adminAddress"; + + @BeforeEach + void startup() { + mailer = mock(Mailer.class); + this.notificationService = new NotificationServiceDefault(templatePlaceholdersConfig, templatePathConfig, + azureBlobClient, objectMapper, mailer, contractService, notificationAdminMail, "senderMail", false, "destinationMailTestAddress"); + } + + @Test + void sendMailRegistrationWithContract() { + + final String mailTemplate = "{\"subject\":\"example\",\"body\":\"example\"}"; + + final String onboardingId = "onboardingId"; + final String destination = "test@test.it"; + final String productName = "productName"; + + final File file = new File(Objects.requireNonNull(getClass().getClassLoader().getResource("application.properties")).getFile()); + + Mockito.when(contractService.retrieveContractNotSigned(onboardingId, productName)) + .thenReturn(file); + + Mockito.when(azureBlobClient.getFileAsText(templatePathConfig.registrationPath())) + .thenReturn(mailTemplate); + Mockito.doNothing().when(mailer).send(any()); + + notificationService.sendMailRegistrationWithContract(onboardingId, destination,"","", productName); + + Mockito.verify(azureBlobClient, Mockito.times(1)) + .getFileAsText(any()); + + ArgumentCaptor mailArgumentCaptor = ArgumentCaptor.forClass(Mail.class); + Mockito.verify(mailer, Mockito.times(1)) + .send(mailArgumentCaptor.capture()); + assertEquals(destination, mailArgumentCaptor.getValue().getTo().get(0)); + } + + @Test + void sendMailRegistrationWithContract_shouldThrowException() { + final String onboardingId = "onboardingId"; + final String productName = "productName"; + final File file = mock(File.class); + Mockito.when(contractService.retrieveContractNotSigned(onboardingId, productName)).thenReturn(file); + assertThrows(RuntimeException.class, () -> notificationService.sendMailRegistrationWithContract(onboardingId, "example@pagopa.it","mario","rossi","prod-example")); + } + + @Test + void sendMailRegistration() { + + final String mailTemplate = "{\"subject\":\"example\",\"body\":\"example\"}"; + + final String onboardingId = "onboardingId"; + final String destination = "test@test.it"; + + Mockito.when(azureBlobClient.getFileAsText(templatePathConfig.registrationRequestPath())) + .thenReturn(mailTemplate); + + Mockito.doNothing().when(mailer).send(any()); + + notificationService.sendMailRegistration(onboardingId, destination,"","",""); + + Mockito.verify(azureBlobClient, Mockito.times(1)) + .getFileAsText(any()); + + ArgumentCaptor mailArgumentCaptor = ArgumentCaptor.forClass(Mail.class); + Mockito.verify(mailer, Mockito.times(1)) + .send(mailArgumentCaptor.capture()); + assertEquals(destination, mailArgumentCaptor.getValue().getTo().get(0)); + } + + @Test + void sendCompletedEmail() { + + final String mailTemplate = "{\"subject\":\"example\",\"body\":\"example\"}"; + + final String destination = "test@test.it"; + Product product = new Product(); + product.setTitle("productName"); + product.setId("prod-id"); + + final File file = new File(Objects.requireNonNull(getClass().getClassLoader().getResource("application.properties")).getFile()); + + Mockito.when(contractService.getLogoFile()).thenReturn(file); + + Mockito.when(azureBlobClient.getFileAsText(templatePathConfig.registrationPath())) + .thenReturn(mailTemplate); + Mockito.doNothing().when(mailer).send(any()); + + notificationService.sendCompletedEmail(List.of(destination), product, InstitutionType.PA); + + Mockito.verify(azureBlobClient, Mockito.times(1)) + .getFileAsText(any()); + + ArgumentCaptor mailArgumentCaptor = ArgumentCaptor.forClass(Mail.class); + Mockito.verify(mailer, Mockito.times(1)) + .send(mailArgumentCaptor.capture()); + assertEquals(destination, mailArgumentCaptor.getValue().getTo().get(0)); + } + + + @Test + void sendMailRegistrationApprove() { + + final String mailTemplate = "{\"subject\":\"example\",\"body\":\"example\"}"; + final String institutionName = "institutionName"; + + Mockito.when(azureBlobClient.getFileAsText(templatePathConfig.registrationApprovePath())) + .thenReturn(mailTemplate); + Mockito.doNothing().when(mailer).send(any()); + + notificationService.sendMailRegistrationApprove(institutionName, "name","username","product","token"); + + Mockito.verify(azureBlobClient, Mockito.times(1)) + .getFileAsText(any()); + + ArgumentCaptor mailArgumentCaptor = ArgumentCaptor.forClass(Mail.class); + Mockito.verify(mailer, Mockito.times(1)) + .send(mailArgumentCaptor.capture()); + assertEquals(notificationAdminMail, mailArgumentCaptor.getValue().getTo().get(0)); + } + + + @Test + void sendMailOnboardingApprove() { + + final String mailTemplate = "{\"subject\":\"example\",\"body\":\"example\"}"; + final String institutionName = "institutionName"; + + Mockito.when(azureBlobClient.getFileAsText(templatePathConfig.onboardingApprovePath())) + .thenReturn(mailTemplate); + Mockito.doNothing().when(mailer).send(any()); + + notificationService.sendMailOnboardingApprove(institutionName, "name","username","product","token"); + + Mockito.verify(azureBlobClient, Mockito.times(1)) + .getFileAsText(any()); + + ArgumentCaptor mailArgumentCaptor = ArgumentCaptor.forClass(Mail.class); + Mockito.verify(mailer, Mockito.times(1)) + .send(mailArgumentCaptor.capture()); + assertEquals(notificationAdminMail, mailArgumentCaptor.getValue().getTo().get(0)); + } + +} diff --git a/apps/onboarding-functions/src/test/java/it/pagopa/selfcare/onboarding/service/OnboardingServiceTest.java b/apps/onboarding-functions/src/test/java/it/pagopa/selfcare/onboarding/service/OnboardingServiceTest.java new file mode 100644 index 000000000..da5264d34 --- /dev/null +++ b/apps/onboarding-functions/src/test/java/it/pagopa/selfcare/onboarding/service/OnboardingServiceTest.java @@ -0,0 +1,378 @@ +package it.pagopa.selfcare.onboarding.service; + +import eu.europa.esig.dss.enumerations.DigestAlgorithm; +import eu.europa.esig.dss.model.DSSDocument; +import eu.europa.esig.dss.model.FileDocument; +import io.quarkus.test.InjectMock; +import io.quarkus.test.junit.QuarkusTest; +import it.pagopa.selfcare.onboarding.common.PartyRole; +import it.pagopa.selfcare.onboarding.entity.Institution; +import it.pagopa.selfcare.onboarding.entity.Onboarding; +import it.pagopa.selfcare.onboarding.entity.Token; +import it.pagopa.selfcare.onboarding.entity.User; +import it.pagopa.selfcare.onboarding.exception.GenericOnboardingException; +import it.pagopa.selfcare.product.entity.Product; +import it.pagopa.selfcare.product.service.ProductService; +import it.pagopa.selfcare.onboarding.repository.OnboardingRepository; +import it.pagopa.selfcare.onboarding.repository.TokenRepository; +import jakarta.inject.Inject; +import org.bson.types.ObjectId; +import org.eclipse.microprofile.rest.client.inject.RestClient; +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Mockito; +import org.openapi.quarkus.user_registry_json.api.UserApi; +import org.openapi.quarkus.user_registry_json.model.CertifiableFieldResourceOfstring; +import org.openapi.quarkus.user_registry_json.model.UserResource; + +import java.io.File; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.UUID; + +import static it.pagopa.selfcare.onboarding.service.OnboardingService.USERS_FIELD_LIST; +import static it.pagopa.selfcare.onboarding.service.OnboardingService.USERS_WORKS_FIELD_LIST; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; + +@QuarkusTest +class OnboardingServiceTest { + + @InjectMock + OnboardingRepository onboardingRepository; + @InjectMock + TokenRepository tokenRepository; + @RestClient + @InjectMock + UserApi userRegistryApi; + @InjectMock + NotificationService notificationService; + @InjectMock + ContractService contractService; + @InjectMock + ProductService productService; + + @Inject + OnboardingService onboardingService; + + final String productId = "productId"; + + private Onboarding createOnboarding() { + Onboarding onboarding = new Onboarding(); + onboarding.setId(ObjectId.get()); + onboarding.setOnboardingId(onboarding.getId().toHexString()); + onboarding.setProductId(productId); + onboarding.setUsers(List.of()); + Institution institution = new Institution(); + institution.setDescription("description"); + onboarding.setInstitution(institution); + onboarding.setUserRequestUid("example-uid"); + return onboarding; + } + + private UserResource createUserResource(){ + UserResource userResource = new UserResource(); + userResource.setId(UUID.randomUUID()); + + CertifiableFieldResourceOfstring resourceOfName = new CertifiableFieldResourceOfstring(); + resourceOfName.setCertification(CertifiableFieldResourceOfstring.CertificationEnum.NONE); + resourceOfName.setValue("name"); + userResource.setName(resourceOfName); + + CertifiableFieldResourceOfstring resourceOfSurname = new CertifiableFieldResourceOfstring(); + resourceOfSurname.setCertification(CertifiableFieldResourceOfstring.CertificationEnum.NONE); + resourceOfSurname.setValue("surname"); + userResource.setFamilyName(resourceOfSurname); + return userResource; + } + + @Test + void getOnboarding() { + Onboarding onboarding = createOnboarding(); + when(onboardingRepository.findByIdOptional(any())).thenReturn(Optional.of(onboarding)); + + Optional actual = onboardingService.getOnboarding(onboarding.getOnboardingId()); + assertTrue(actual.isPresent()); + assertEquals(onboarding.getOnboardingId(), actual.get().getOnboardingId()); + } + + @Test + void createContract_shouldThrowIfManagerNotfound() { + Onboarding onboarding = createOnboarding(); + assertThrows(GenericOnboardingException.class, () -> onboardingService.createContract(onboarding)); + } + + @Test + void createContract() { + + UserResource userResource = createUserResource(); + UserResource delegateResource = createUserResource(); + + Onboarding onboarding = createOnboarding(); + User manager = new User(); + manager.setId(userResource.getId().toString()); + manager.setRole(PartyRole.MANAGER); + User delegate = new User(); + delegate.setId(delegateResource.getId().toString()); + delegate.setRole(PartyRole.DELEGATE); + onboarding.setUsers(List.of(manager, delegate)); + + when(userRegistryApi.findByIdUsingGET(USERS_WORKS_FIELD_LIST,manager.getId())) + .thenReturn(userResource); + + when(userRegistryApi.findByIdUsingGET(USERS_WORKS_FIELD_LIST,delegate.getId())) + .thenReturn(delegateResource); + + when(productService.getProductIsValid(onboarding.getProductId())) + .thenReturn(new Product()); + + onboardingService.createContract(onboarding); + + Mockito.verify(userRegistryApi, Mockito.times(1)) + .findByIdUsingGET(USERS_WORKS_FIELD_LIST,manager.getId()); + + Mockito.verify(userRegistryApi, Mockito.times(1)) + .findByIdUsingGET(USERS_WORKS_FIELD_LIST,delegate.getId()); + + Mockito.verify(productService, Mockito.times(1)) + .getProductIsValid(onboarding.getProductId()); + } + + private Product createDummyProduct() { + Product product = new Product(); + product.setContractTemplatePath("example"); + product.setContractTemplateVersion("version"); + product.setTitle("Title"); + product.setId(productId); + return product; + } + @Test + void saveToken_shouldSkipIfTokenExists() { + Onboarding onboarding = createOnboarding(); + Token token = new Token(); + token.setId(ObjectId.get()); + + when(tokenRepository.findByOnboardingId(onboarding.getOnboardingId())) + .thenReturn(Optional.of(token)); + + onboardingService.saveTokenWithContract(onboarding); + + Mockito.verify(tokenRepository, Mockito.times(1)) + .findByOnboardingId(onboarding.getOnboardingId()); + Mockito.verifyNoMoreInteractions(tokenRepository); + } + + + @Test + void saveToken() { + Onboarding onboarding = createOnboarding(); + File contract = new File(Objects.requireNonNull(getClass().getClassLoader().getResource("application.properties")).getFile()); + DSSDocument document = new FileDocument(contract); + String digestExpected = document.getDigest(DigestAlgorithm.SHA256); + + Product productExpected = createDummyProduct(); + when(contractService.retrieveContractNotSigned(onboarding.getOnboardingId(), productExpected.getTitle())) + .thenReturn(contract); + when(productService.getProductIsValid(onboarding.getProductId())) + .thenReturn(productExpected); + + Mockito.doNothing().when(tokenRepository).persist(any(Token.class)); + + onboardingService.saveTokenWithContract(onboarding); + + + ArgumentCaptor tokenArgumentCaptor = ArgumentCaptor.forClass(Token.class); + Mockito.verify(tokenRepository, Mockito.times(1)) + .persist(tokenArgumentCaptor.capture()); + assertEquals(onboarding.getProductId(), tokenArgumentCaptor.getValue().getProductId()); + assertEquals(digestExpected, tokenArgumentCaptor.getValue().getChecksum()); + assertEquals(productExpected.getContractTemplatePath(), tokenArgumentCaptor.getValue().getContractTemplate()); + assertEquals(productExpected.getContractTemplateVersion(), tokenArgumentCaptor.getValue().getContractVersion()); + } + + @Test + void loadContract() { + + Onboarding onboarding = createOnboarding(); + Product product = createDummyProduct(); + + when(productService.getProductIsValid(onboarding.getProductId())) + .thenReturn(product); + + onboardingService.loadContract(onboarding); + + Mockito.verify(productService, Mockito.times(1)) + .getProductIsValid(onboarding.getProductId()); + Mockito.verify(contractService, Mockito.times(1)) + .loadContractPDF(product.getContractTemplatePath(), onboarding.getOnboardingId(), product.getTitle()); + } + + + @Test + void sendMailRegistrationWithContract() { + + Onboarding onboarding = createOnboarding(); + Product product = createDummyProduct(); + UserResource userResource = createUserResource(); + Token token = new Token(); + token.setId(ObjectId.get()); + + when(tokenRepository.findByOnboardingId(onboarding.getOnboardingId())) + .thenReturn(Optional.of(token)); + when(productService.getProduct(onboarding.getProductId())) + .thenReturn(product); + + when(userRegistryApi.findByIdUsingGET(USERS_FIELD_LIST, onboarding.getUserRequestUid())) + .thenReturn(userResource); + doNothing().when(notificationService) + .sendMailRegistrationWithContract(onboarding.getOnboardingId(), + onboarding.getInstitution().getDigitalAddress(), + userResource.getName().getValue(), userResource.getFamilyName().getValue(), + product.getTitle()); + + onboardingService.sendMailRegistrationWithContract(onboarding); + + Mockito.verify(notificationService, times(1)) + .sendMailRegistrationWithContract(onboarding.getOnboardingId(), + onboarding.getInstitution().getDigitalAddress(), + userResource.getName().getValue(), userResource.getFamilyName().getValue(), + product.getTitle()); + } + + + @Test + void sendMailRegistrationWithContractWhenApprove() { + + Onboarding onboarding = createOnboarding(); + Product product = createDummyProduct(); + UserResource userResource = createUserResource(); + Token token = new Token(); + token.setId(ObjectId.get()); + + when(tokenRepository.findByOnboardingId(onboarding.getOnboardingId())) + .thenReturn(Optional.of(token)); + when(productService.getProduct(onboarding.getProductId())) + .thenReturn(product); + + when(userRegistryApi.findByIdUsingGET(USERS_FIELD_LIST, onboarding.getUserRequestUid())) + .thenReturn(userResource); + doNothing().when(notificationService) + .sendMailRegistrationWithContract(onboarding.getOnboardingId(), + onboarding.getInstitution().getDigitalAddress(), + onboarding.getInstitution().getDescription(), "", + product.getTitle()); + + onboardingService.sendMailRegistrationWithContractWhenApprove(onboarding); + + Mockito.verify(notificationService, times(1)) + .sendMailRegistrationWithContract(onboarding.getOnboardingId(), + onboarding.getInstitution().getDigitalAddress(), + onboarding.getInstitution().getDescription(), "", + product.getTitle()); + } + + + @Test + void sendMailRegistrationWithContract_throwExceptionWhenTokenIsNotPresent() { + Onboarding onboarding = createOnboarding(); + when(tokenRepository.findByOnboardingId(onboarding.getOnboardingId())) + .thenReturn(Optional.empty()); + assertThrows(GenericOnboardingException.class, () -> onboardingService.sendMailRegistrationWithContract(onboarding)); + } + + + @Test + void sendMailRegistration() { + + UserResource userResource = createUserResource(); + Product product = createDummyProduct(); + Onboarding onboarding = createOnboarding(); + + when(productService.getProduct(onboarding.getProductId())) + .thenReturn(product); + when(userRegistryApi.findByIdUsingGET(USERS_FIELD_LIST, onboarding.getUserRequestUid())) + .thenReturn(userResource); + doNothing().when(notificationService).sendMailRegistration(onboarding.getInstitution().getDescription(), + onboarding.getInstitution().getDigitalAddress(), + userResource.getName().getValue(), userResource.getFamilyName().getValue(), + product.getTitle()); + + onboardingService.sendMailRegistration(onboarding); + + Mockito.verify(notificationService, times(1)) + .sendMailRegistration(onboarding.getInstitution().getDescription(), + onboarding.getInstitution().getDigitalAddress(), + userResource.getName().getValue(), userResource.getFamilyName().getValue(), + product.getTitle()); + } + + @Test + void sendMailRegistrationApprove() { + + Onboarding onboarding = createOnboarding(); + Product product = createDummyProduct(); + UserResource userResource = createUserResource(); + + when(productService.getProduct(onboarding.getProductId())) + .thenReturn(product); + when(userRegistryApi.findByIdUsingGET(USERS_FIELD_LIST, onboarding.getUserRequestUid())) + .thenReturn(userResource); + + doNothing().when(notificationService) + .sendMailRegistrationApprove(any(), any(), any(),any(),any()); + + onboardingService.sendMailRegistrationApprove(onboarding); + + Mockito.verify(notificationService, times(1)) + .sendMailRegistrationApprove(onboarding.getInstitution().getDescription(), + userResource.getName().getValue(), + userResource.getFamilyName().getValue(), + product.getTitle(), + onboarding.getOnboardingId()); + } + + + @Test + void sendMailRegistrationApprove_throwExceptionWhenTokenIsNotPresent() { + Onboarding onboarding = createOnboarding(); + when(tokenRepository.findByOnboardingId(onboarding.getOnboardingId())) + .thenReturn(Optional.empty()); + assertThrows(GenericOnboardingException.class, () -> onboardingService.sendMailRegistrationApprove(onboarding)); + } + + + @Test + void sendMailOnboardingApprove() { + + Onboarding onboarding = createOnboarding(); + Product product = createDummyProduct(); + UserResource userResource = createUserResource(); + + when(productService.getProduct(onboarding.getProductId())) + .thenReturn(product); + when(userRegistryApi.findByIdUsingGET(USERS_FIELD_LIST, onboarding.getUserRequestUid())) + .thenReturn(userResource); + doNothing().when(notificationService).sendMailOnboardingApprove(any(), any(), any(),any(),any()); + + onboardingService.sendMailOnboardingApprove(onboarding); + + + Mockito.verify(notificationService, times(1)) + .sendMailOnboardingApprove(onboarding.getInstitution().getDescription(), + userResource.getName().getValue(), + userResource.getFamilyName().getValue(), + product.getTitle(), + onboarding.getOnboardingId()); + } + + + @Test + void sendMailOnboardingApprove_throwExceptionWhenTokenIsNotPresent() { + Onboarding onboarding = createOnboarding(); + when(tokenRepository.findByOnboardingId(onboarding.getOnboardingId())) + .thenReturn(Optional.empty()); + assertThrows(GenericOnboardingException.class, () -> onboardingService.sendMailOnboardingApprove(onboarding)); + } +} diff --git a/apps/onboarding-functions/src/test/resources/application.properties b/apps/onboarding-functions/src/test/resources/application.properties new file mode 100644 index 000000000..3d05d6e62 --- /dev/null +++ b/apps/onboarding-functions/src/test/resources/application.properties @@ -0,0 +1,49 @@ +quarkus.azure-functions.app-name=example +quarkus.azure-functions.subscription-id=example +quarkus.azure-functions.resource-group=example +quarkus.azure-functions.region=example +quarkus.azure-functions.app-insights-key=example +quarkus.azure-functions.app-service-plan-name=example + +## MAIL AND MAIL TEMPLATE ## +onboarding-functions.sender-mail = ${MAIL_SENDER_ADDRESS:test@test.it} +onboarding-functions.notification-admin-email = default + +## MAIL TEMPLATE +onboarding-functions.mail-template.path.onboarding.complete-path = default +onboarding-functions.mail-template.path.onboarding.complete-path-fd = default + +onboarding-functions.mail-template.path.onboarding.autocomplete-path = default +onboarding-functions.mail-template.path.onboarding.delegation-notification-path = default +onboarding-functions.mail-template.path.onboarding.registration-path = default + +onboarding-functions.mail-template.path.onboarding.onboarding-approve-path = default +onboarding-functions.mail-template.path.onboarding.registration-request-path = default +onboarding-functions.mail-template.path.onboarding.registration-approve-path = default + +onboarding-functions.mail-template.path.onboarding.reject-path = default + +## MAIL PLACEHOLDERS +onboarding-functions.mail-template.placeholders.onboarding.user-name = requesterName +onboarding-functions.mail-template.placeholders.onboarding.user-surname = requesterSurname +onboarding-functions.mail-template.placeholders.onboarding.product-name = productName +onboarding-functions.mail-template.placeholders.onboarding.institution-description = institutionName +onboarding-functions.mail-template.placeholders.onboarding.admin-link = default + +onboarding-functions.mail-template.placeholders.onboarding.complete-selfcare-name = selfcareURL +onboarding-functions.mail-template.placeholders.onboarding.complete-product-name = productName +onboarding-functions.mail-template.placeholders.onboarding.complete-selfcare-placeholder= default + +onboarding-functions.mail-template.placeholders.onboarding.confirm-token-name= confirmTokenURL +onboarding-functions.mail-template.placeholders.onboarding.confirm-token-placeholder = default + +onboarding-functions.mail-template.placeholders.onboarding.reject-token-placeholder = default +onboarding-functions.mail-template.placeholders.onboarding.reject-token-name = rejectTokenURL + +onboarding-functions.mail-template.placeholders.onboarding.notification-product-name = productName +onboarding-functions.mail-template.placeholders.onboarding.notification-requester-name = requesterName +onboarding-functions.mail-template.placeholders.onboarding.notification-requester-surname = requesterSurname + +onboarding-functions.mail-template.placeholders.onboarding.reject-product-name=productName +onboarding-functions.mail-template.placeholders.onboarding.reject-onboarding-url-placeholder=onboardingUrl +onboarding-functions.mail-template.placeholders.onboarding.reject-onboarding-url-value=default diff --git a/onboarding-ms/.gitignore b/apps/onboarding-ms/.gitignore similarity index 100% rename from onboarding-ms/.gitignore rename to apps/onboarding-ms/.gitignore diff --git a/apps/onboarding-ms/Dockerfile b/apps/onboarding-ms/Dockerfile new file mode 100644 index 000000000..20885dfe5 --- /dev/null +++ b/apps/onboarding-ms/Dockerfile @@ -0,0 +1,38 @@ +# syntax=docker/dockerfile:1.6 +FROM maven:3-eclipse-temurin-17 AS builder + +WORKDIR /src +COPY --link ./pom.xml . + +WORKDIR /src/libs +COPY --link ./libs/ . + +WORKDIR /src/test-coverage +COPY --link ./test-coverage/pom.xml . + +WORKDIR /src/apps +COPY --link ./apps/pom.xml . + +WORKDIR /src/apps/onboarding-ms +COPY --link ./apps/onboarding-ms/pom.xml . +COPY ./apps/onboarding-ms/src/main/ ./src/main/ + +WORKDIR /src +RUN mvn --projects :onboarding-ms --also-make clean package -DskipTests + +FROM openjdk:17-jdk AS runtime + +ENV LANG='en_US.UTF-8' LANGUAGE='en_US:en' +ENV JAVA_OPTIONS="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager" + +WORKDIR /app + +COPY --from=builder /src/apps/onboarding-ms/target/quarkus-app/lib/ ./lib/ +COPY --from=builder /src/apps/onboarding-ms/target/quarkus-app/*.jar ./ +COPY --from=builder /src/apps/onboarding-ms/target/quarkus-app/app/ ./app/ +COPY --from=builder /src/apps/onboarding-ms/target/quarkus-app/quarkus/ ./quarkus/ + +EXPOSE 8080 +USER 1001 + +ENTRYPOINT ["sh", "-c", "java $JAVA_OPTIONS -jar /app/quarkus-run.jar"] diff --git a/apps/onboarding-ms/README.md b/apps/onboarding-ms/README.md new file mode 100644 index 000000000..9b5a2250d --- /dev/null +++ b/apps/onboarding-ms/README.md @@ -0,0 +1,89 @@ +# Microservice Onboarding + +Repository that contains backend services synch for selfcare onboarding. + +It implements CRUD operations for the 'onboarding' object and the business logic for the onboarding phase. During the onboarding process, the following activities are executed: + +1. Check for the presence of users associated with the onboarding and potentially add them to the point of sale (pdv). +2. Validate the requested product's suitability and verify eligible roles. +3. Verify if there is an existing onboarding record for that institution and product. + +After the data is saved, it invokes the function implemented by onboarding-functions to trigger asynchronous onboarding activities. + +### Disable starting async onboarding workflow + +````properties +env ONBOARDING_ORCHESTRATION_ENABLED=false. +```` +### Allowed onboarding product with status TESTING + +ONBOARDING_ALLOWED_INSTITUTIONS_PRODUCTS property permits onboarding for product with status TESTING. It can contain a map of entry with product as key and a list of taxcode as value. + +````properties +ONBOARDING_ALLOWED_INSTITUTIONS_PRODUCTS={'prod-interop': ['0123456789']}. +```` + +## Configuration Properties + +Before running you must set these properties as environment variables. + + +| **Property** | **Environment Variable** | **Default** | **Required** | +|--------------------------------------------------------|------------------------------------------|-------------|:------------:| +| quarkus.mongodb.connection-string
    | MONGODB-CONNECTION-STRING | | yes | +| mp.jwt.verify.publickey
    | JWT-PUBLIC-KEY | | yes | +| quarkus.rest-client."**.UserApi".api-key
    | USER-REGISTRY-API-KEY | | yes | +| quarkus.rest-client."**.UserApi".url
    | USER_REGISTRY_URL | | yes | +| quarkus.rest-client."**.CoreApi".url
    | MS_CORE_URL | | yes | +| quarkus.rest-client."**.AooApi".url
    | MS_PARTY_REGISTRY_URL | | yes | +| quarkus.rest-client."**.UoApi".url
    | MS_PARTY_REGISTRY_URL | | yes | +| quarkus.rest-client."**.OrchestrationApi".url
    | ONBOARDING_FUNCTIONS_URL | | yes | +| quarkus.rest-client."**.OrchestrationApi".api-key
    | ONBOARDING-FUNCTIONS-API-KEY | | yes | +| onboarding.institutions-allowed-list
    | ONBOARDING_ALLOWED_INSTITUTIONS_PRODUCTS | | no | + +> **_NOTE:_** properties that contains secret must have the same name of its secret as uppercase. + + +## Running the application in dev mode + +You can run your application in dev mode that enables live coding using: +```shell script +./mvnw compile quarkus:dev +``` + +For some endpoints + +> **_NOTE:_** Quarkus now ships with a Dev UI, which is available in dev mode only at http://localhost:8083/q/dev/. + +## Packaging and running the application + +The application can be packaged using: +```shell script +./mvnw package +``` +It produces the `quarkus-run.jar` file in the `target/quarkus-app/` directory. +Be aware that it’s not an _über-jar_ as the dependencies are copied into the `target/quarkus-app/lib/` directory. + +The application is now runnable using `java -jar target/quarkus-app/quarkus-run.jar`. + +If you want to build an _über-jar_, execute the following command: +```shell script +./mvnw package -Dquarkus.package.type=uber-jar +``` + +The application, packaged as an _über-jar_, is now runnable using `java -jar target/*-runner.jar`. + +## Related Guides + + +### RESTEasy Reactive + +Easily start your Reactive RESTful Web Services + +[Related guide section...](https://quarkus.io/guides/getting-started-reactive#reactive-jax-rs-resources) + +### OpenAPI Generator + +Rest client are generated using a quarkus' extension. + +[Related guide section...](hhttps://github.com/quarkiverse/quarkus-openapi-generator) diff --git a/onboarding-ms/pom.xml b/apps/onboarding-ms/pom.xml similarity index 57% rename from onboarding-ms/pom.xml rename to apps/onboarding-ms/pom.xml index b99420703..2c42b13cb 100644 --- a/onboarding-ms/pom.xml +++ b/apps/onboarding-ms/pom.xml @@ -4,10 +4,10 @@ 4.0.0 it.pagopa.selfcare - onboarding + onboarding-apps 0.0.1 - it.pagopa.selfcare + onboarding-ms 1.0.0-SNAPSHOT @@ -19,9 +19,11 @@ UTF-8 quarkus-bom io.quarkus.platform - 3.3.2 + 3.5.2 true 3.1.2 + 0.1.3 + 2.2.13 @@ -46,7 +48,7 @@ io.quarkiverse.openapi.generator quarkus-openapi-generator - 2.2.10 + ${quarkus-openapi-generator.version} io.quarkus @@ -85,6 +87,10 @@ io.quarkus quarkus-rest-client-reactive-jackson + + io.quarkus + quarkus-smallrye-health + org.mapstruct mapstruct @@ -103,16 +109,136 @@ io.quarkus quarkus-smallrye-openapi + + io.quarkus + quarkus-mongodb-panache + io.quarkus - quarkus-mongodb-client + quarkus-smallrye-context-propagation + + io.quarkus + quarkus-panache-mock + test + + + io.quarkus + quarkus-test-hibernate-reactive-panache + test + io.quarkus quarkus-jacoco test + + io.quarkus + quarkus-test-security-jwt + test + + + it.pagopa.selfcare + onboarding-sdk-common + ${onboarding-sdk.version} + + + + it.pagopa.selfcare + onboarding-sdk-azure-storage + ${onboarding-sdk.version} + + + it.pagopa.selfcare + onboarding-sdk-product + ${onboarding-sdk.version} + + + + + + eu.europa.ec.joinup.sd-dss + dss-test + 5.12.1 + test + + + + eu.europa.ec.joinup.sd-dss + dss-utils + 5.12.1 + + + eu.europa.ec.joinup.sd-dss + dss-model + 5.12.1 + compile + + + + eu.europa.ec.joinup.sd-dss + dss-service + 5.12.1 + + + + eu.europa.ec.joinup.sd-dss + dss-tsl-validation + 5.12.1 + + + + eu.europa.ec.joinup.sd-dss + dss-utils-google-guava + 5.12.1 + + + eu.europa.ec.joinup.sd-dss + dss-pades + 5.12.1 + + + eu.europa.ec.joinup.sd-dss + dss-pades-pdfbox + 5.12.1 + + + eu.europa.ec.joinup.sd-dss + dss-cades + 5.12.1 + + + eu.europa.ec.joinup.sd-dss + dss-utils-apache-commons + 5.12.1 + + + eu.europa.ec.joinup.sd-dss + dss-crl-parser-stream + 5.12.1 + + + + + javax.xml.bind + jaxb-api + 2.3.1 + + + + jakarta.activation + jakarta.activation-api + 2.1.0 + + + com.sun.xml.bind + jaxb-impl + 2.3.4 + + + + @@ -154,19 +280,14 @@ lombok-mapstruct-binding 0.2.0 + + io.quarkus + quarkus-panache-common + ${quarkus.platform.version} + - - maven-surefire-plugin - ${surefire-plugin.version} - - - org.jboss.logmanager.LogManager - ${maven.home} - - - maven-failsafe-plugin ${surefire-plugin.version} diff --git a/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/client/auth/AuthenticationPropagationHeadersFactory.java b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/client/auth/AuthenticationPropagationHeadersFactory.java new file mode 100644 index 000000000..f4cdbc908 --- /dev/null +++ b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/client/auth/AuthenticationPropagationHeadersFactory.java @@ -0,0 +1,22 @@ +package it.pagopa.selfcare.onboarding.client.auth; + +import jakarta.ws.rs.core.MultivaluedMap; +import org.eclipse.microprofile.rest.client.ext.ClientHeadersFactory; + +import java.util.List; + +public class AuthenticationPropagationHeadersFactory implements ClientHeadersFactory { + + @Override + public MultivaluedMap update(MultivaluedMap incomingHeaders, MultivaluedMap clientOutgoingHeaders) { + if(incomingHeaders.containsKey("Authorization")) { + List headerValue = incomingHeaders.get("Authorization"); + + if (headerValue != null) { + clientOutgoingHeaders.put("Authorization", headerValue); + } + + }; + return clientOutgoingHeaders; + } +} \ No newline at end of file diff --git a/onboarding-ms/src/main/java/it/pagopa/selfcare/conf/JacksonConfiguration.java b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/conf/JacksonConfiguration.java similarity index 91% rename from onboarding-ms/src/main/java/it/pagopa/selfcare/conf/JacksonConfiguration.java rename to apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/conf/JacksonConfiguration.java index 9f6aef669..471ed0d2d 100644 --- a/onboarding-ms/src/main/java/it/pagopa/selfcare/conf/JacksonConfiguration.java +++ b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/conf/JacksonConfiguration.java @@ -1,11 +1,10 @@ -package it.pagopa.selfcare.conf; +package it.pagopa.selfcare.onboarding.conf; import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; -import com.fasterxml.jackson.databind.cfg.ConstructorDetector; import com.fasterxml.jackson.datatype.jdk8.Jdk8Module; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import com.fasterxml.jackson.module.paramnames.ParameterNamesModule; diff --git a/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/conf/OnboardingMsConfig.java b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/conf/OnboardingMsConfig.java new file mode 100644 index 000000000..f72c849eb --- /dev/null +++ b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/conf/OnboardingMsConfig.java @@ -0,0 +1,42 @@ +package it.pagopa.selfcare.onboarding.conf; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import it.pagopa.selfcare.azurestorage.AzureBlobClient; +import it.pagopa.selfcare.azurestorage.AzureBlobClientDefault; +import it.pagopa.selfcare.product.service.ProductService; +import it.pagopa.selfcare.product.service.ProductServiceDefault; +import jakarta.enterprise.context.ApplicationScoped; +import org.eclipse.microprofile.config.inject.ConfigProperty; + +@ApplicationScoped +public class OnboardingMsConfig { + + @ConfigProperty(name = "onboarding-ms.blob-storage.container-product") + String containerProduct; + + @ConfigProperty(name = "onboarding-ms.blob-storage.filepath-product") + String filepathProduct; + + @ConfigProperty(name = "onboarding-ms.blob-storage.connection-string-product") + String connectionStringProduct; + + @ApplicationScoped + public ProductService productService(ObjectMapper objectMapper){ + AzureBlobClient azureBlobClient = new AzureBlobClientDefault(connectionStringProduct, containerProduct); + String productJsonString = azureBlobClient.getFileAsText(filepathProduct); + try { + return new ProductServiceDefault(productJsonString, objectMapper); + } catch (JsonProcessingException e) { + throw new IllegalArgumentException("Found an issue when trying to serialize product json string!!"); + } + } + + @ApplicationScoped + public AzureBlobClient azureBobClientContract(@ConfigProperty(name = "onboarding-ms.blob-storage.connection-string-contracts") + String connectionStringContracts, + @ConfigProperty(name = "onboarding-ms.blob-storage.container-contracts") + String containerContracts){ + return new AzureBlobClientDefault(connectionStringContracts, containerContracts); + } +} diff --git a/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/conf/TrustedListsCertificateSourceConfig.java b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/conf/TrustedListsCertificateSourceConfig.java new file mode 100644 index 000000000..d1e484fb7 --- /dev/null +++ b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/conf/TrustedListsCertificateSourceConfig.java @@ -0,0 +1,163 @@ +package it.pagopa.selfcare.onboarding.conf; + +import eu.europa.esig.dss.service.http.commons.CommonsDataLoader; +import eu.europa.esig.dss.service.http.commons.FileCacheDataLoader; +import eu.europa.esig.dss.spi.client.http.DSSFileLoader; +import eu.europa.esig.dss.spi.client.http.IgnoreDataLoader; +import eu.europa.esig.dss.spi.tsl.TrustedListsCertificateSource; +import eu.europa.esig.dss.spi.x509.CommonCertificateSource; +import eu.europa.esig.dss.tsl.alerts.LOTLAlert; +import eu.europa.esig.dss.tsl.alerts.TLAlert; +import eu.europa.esig.dss.tsl.alerts.detections.LOTLLocationChangeDetection; +import eu.europa.esig.dss.tsl.alerts.detections.OJUrlChangeDetection; +import eu.europa.esig.dss.tsl.alerts.detections.TLExpirationDetection; +import eu.europa.esig.dss.tsl.alerts.detections.TLSignatureErrorDetection; +import eu.europa.esig.dss.tsl.alerts.handlers.log.LogLOTLLocationChangeAlertHandler; +import eu.europa.esig.dss.tsl.alerts.handlers.log.LogOJUrlChangeAlertHandler; +import eu.europa.esig.dss.tsl.alerts.handlers.log.LogTLExpirationAlertHandler; +import eu.europa.esig.dss.tsl.alerts.handlers.log.LogTLSignatureErrorAlertHandler; +import eu.europa.esig.dss.tsl.cache.CacheCleaner; +import eu.europa.esig.dss.tsl.function.OfficialJournalSchemeInformationURI; +import eu.europa.esig.dss.tsl.job.TLValidationJob; +import eu.europa.esig.dss.tsl.source.LOTLSource; +import eu.europa.esig.dss.tsl.sync.AcceptAllStrategy; +import io.quarkus.arc.profile.IfBuildProfile; +import io.quarkus.arc.profile.UnlessBuildProfile; +import io.quarkus.runtime.Startup; +import io.smallrye.mutiny.Uni; +import jakarta.enterprise.context.ApplicationScoped; +import lombok.extern.slf4j.Slf4j; +import org.eclipse.microprofile.config.inject.ConfigProperty; + +import java.io.File; +import java.util.List; +import java.util.concurrent.Executors; + +@Slf4j +@Startup +@ApplicationScoped +public class TrustedListsCertificateSourceConfig { + + @ConfigProperty(name = "onboarding-ms.signature.eu-list-of-trusted-lists-url") + String euListOfTrustedListsURL; + @ConfigProperty(name = "onboarding-ms.signature.eu-official-journal-url") + String euOfficialJournalUrl; + + @Startup + @ApplicationScoped + @UnlessBuildProfile("test") + public TrustedListsCertificateSource generateTrustedListsCertificateSource() { + + TrustedListsCertificateSource trustedListsCertificateSource = new TrustedListsCertificateSource(); + LOTLSource europeanLOTL = getEuropeanLOTL(); + TLValidationJob validationJob = getJob(europeanLOTL); + validationJob.setTrustedListCertificateSource(trustedListsCertificateSource); + + /* It is an async execution, it avoid waiting 60s for the onlineRefresh to complete */ + Uni.createFrom().item(validationJob) + .onItem().invoke(TLValidationJob::onlineRefresh) + .runSubscriptionOn(Executors.newSingleThreadExecutor()) + .subscribe().with( + result -> log.info("TrustedListsCertificateSource online refresh success!!"), + failure -> log.error("Error on TrustedListsCertificateSource online refresh, message:" + failure.getMessage()) + ); + + return trustedListsCertificateSource; + } + + /* It is used for unit test, it does not perform onlineRefresh */ + @ApplicationScoped + @IfBuildProfile("test") + public TrustedListsCertificateSource generateTrustedListsCertificateSourceTest() { + + TrustedListsCertificateSource trustedListsCertificateSource = new TrustedListsCertificateSource(); + LOTLSource europeanLOTL = getEuropeanLOTL(); + TLValidationJob validationJob = getJob(europeanLOTL); + validationJob.setTrustedListCertificateSource(trustedListsCertificateSource); + return trustedListsCertificateSource; + } + + private LOTLSource getEuropeanLOTL() { + LOTLSource lotlSource = new LOTLSource(); + lotlSource.setUrl(euListOfTrustedListsURL); + lotlSource.setCertificateSource(new CommonCertificateSource()); + lotlSource.setSigningCertificatesAnnouncementPredicate( + new OfficialJournalSchemeInformationURI(euOfficialJournalUrl) + ); + lotlSource.setPivotSupport(true); + return lotlSource; + } + + private DSSFileLoader offlineLoader() { + FileCacheDataLoader offlineFileLoader = new FileCacheDataLoader(); + offlineFileLoader.setCacheExpirationTime(Long.MAX_VALUE); + offlineFileLoader.setDataLoader(new IgnoreDataLoader()); + offlineFileLoader.setFileCacheDirectory(tlCacheDirectory()); + return offlineFileLoader; + } + + private DSSFileLoader onlineLoader() { + FileCacheDataLoader onlineFileLoader = new FileCacheDataLoader(); + onlineFileLoader.setCacheExpirationTime(0); + onlineFileLoader.setDataLoader(new CommonsDataLoader()); + onlineFileLoader.setFileCacheDirectory(tlCacheDirectory()); + return onlineFileLoader; + } + + private CacheCleaner cacheCleaner() { + CacheCleaner cacheCleaner = new CacheCleaner(); + cacheCleaner.setCleanMemory(true); + cacheCleaner.setCleanFileSystem(true); + cacheCleaner.setDSSFileLoader(offlineLoader()); + return cacheCleaner; + } + + private File tlCacheDirectory() { + File rootFolder = new File(System.getProperty("java.io.tmpdir")); + File tslCache = new File(rootFolder, "dss-tsl-loader"); + if (tslCache.mkdirs()) { + log.debug("TL Cache folder : {}", tslCache.getAbsolutePath()); + } + return tslCache; + } + + private TLAlert tlSigningAlert() { + TLSignatureErrorDetection signingDetection = new TLSignatureErrorDetection(); + LogTLSignatureErrorAlertHandler handler = new LogTLSignatureErrorAlertHandler(); + return new TLAlert(signingDetection, handler); + } + + private TLAlert tlExpirationDetection() { + var expirationDetection = new TLExpirationDetection(); + var handler = new LogTLExpirationAlertHandler(); + return new TLAlert(expirationDetection, handler); + } + + private LOTLAlert ojUrlAlert(LOTLSource source) { + var ojUrlDetection = new OJUrlChangeDetection(source); + var handler = new LogOJUrlChangeAlertHandler(); + return new LOTLAlert(ojUrlDetection, handler); + } + + private LOTLAlert lotlLocationAlert(LOTLSource source) { + var lotlLocationDetection = new LOTLLocationChangeDetection(source); + var handler = new LogLOTLLocationChangeAlertHandler(); + return new LOTLAlert(lotlLocationDetection, handler); + } + + private TLValidationJob getJob(LOTLSource lotl) { + TLValidationJob job = new TLValidationJob(); + + job.setOfflineDataLoader(offlineLoader()); + job.setOnlineDataLoader(onlineLoader()); + job.setSynchronizationStrategy(new AcceptAllStrategy()); + job.setCacheCleaner(cacheCleaner()); + + job.setListOfTrustedListSources(lotl); + + job.setLOTLAlerts(List.of(ojUrlAlert(lotl), lotlLocationAlert(lotl))); + job.setTLAlerts(List.of(tlSigningAlert(), tlExpirationDetection())); + + return job; + } +} diff --git a/onboarding-ms/src/main/java/it/pagopa/selfcare/constants/CustomError.java b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/constants/CustomError.java similarity index 66% rename from onboarding-ms/src/main/java/it/pagopa/selfcare/constants/CustomError.java rename to apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/constants/CustomError.java index 322eedd36..649f271ee 100644 --- a/onboarding-ms/src/main/java/it/pagopa/selfcare/constants/CustomError.java +++ b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/constants/CustomError.java @@ -1,8 +1,12 @@ -package it.pagopa.selfcare.constants; +package it.pagopa.selfcare.onboarding.constants; public enum CustomError { - ROLES_NOT_ADMITTED_ERROR("0034","Roles %s are not admitted for this operation"); + DEFAULT_ERROR("0000", ""), + + ROLES_NOT_ADMITTED_ERROR("0034","Roles %s are not admitted for this operation"), + AOO_NOT_FOUND("0000","AOO %s not found"), + UO_NOT_FOUND("0000","UO %s not found"); private final String code; private final String detail; diff --git a/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/OnboardingController.java b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/OnboardingController.java new file mode 100644 index 000000000..ad15324ac --- /dev/null +++ b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/OnboardingController.java @@ -0,0 +1,169 @@ +package it.pagopa.selfcare.onboarding.controller; + +import io.quarkus.security.Authenticated; +import io.quarkus.security.identity.CurrentIdentityAssociation; +import io.smallrye.jwt.auth.principal.DefaultJWTCallerPrincipal; +import io.smallrye.mutiny.Uni; +import it.pagopa.selfcare.onboarding.controller.request.OnboardingDefaultRequest; +import it.pagopa.selfcare.onboarding.controller.request.OnboardingPaRequest; +import it.pagopa.selfcare.onboarding.controller.request.OnboardingPspRequest; +import it.pagopa.selfcare.onboarding.controller.response.OnboardingGet; +import it.pagopa.selfcare.onboarding.controller.response.OnboardingGetResponse; +import it.pagopa.selfcare.onboarding.controller.response.OnboardingResponse; +import it.pagopa.selfcare.onboarding.service.OnboardingService; +import jakarta.inject.Inject; +import jakarta.validation.Valid; +import jakarta.ws.rs.*; +import jakarta.ws.rs.core.Context; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response; +import jakarta.ws.rs.core.SecurityContext; +import lombok.AllArgsConstructor; +import org.apache.http.HttpStatus; +import org.eclipse.microprofile.openapi.annotations.Operation; +import org.jboss.resteasy.reactive.RestForm; + +import java.io.File; + +@Authenticated +@Path("/v1/onboarding") +@AllArgsConstructor +public class OnboardingController { + + @Inject + CurrentIdentityAssociation currentIdentityAssociation; + + private final OnboardingService onboardingService; + + @Operation(summary = "Perform default onboarding request, it is used for GSP/SA/AS institution type." + + "Users data will be saved on personal data vault if it doesn't already exist." + + "At the end, function triggers async activities related to onboarding based on institution type.") + @POST + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + public Uni onboarding(@Valid OnboardingDefaultRequest onboardingRequest, @Context SecurityContext ctx) { + return readUserIdFromToken(ctx) + .onItem().invoke(onboardingRequest::setUserRequestUid) + .onItem().transformToUni(ignore -> onboardingService.onboarding(onboardingRequest)); + } + + + @Operation(summary = "Perform onboarding request for PA institution type, it require billing.recipientCode in additition to default request" + + "Users data will be saved on personal data vault if it doesn't already exist." + + "At the end, function triggers async activities related to onboarding that consist of create contract and sending mail to institution's digital address.") + @POST + @Path("/pa") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + public Uni onboardingPa(@Valid OnboardingPaRequest onboardingRequest, @Context SecurityContext ctx) { + return readUserIdFromToken(ctx) + .onItem().invoke(onboardingRequest::setUserRequestUid) + .onItem().transformToUni(ignore -> onboardingService.onboardingPa(onboardingRequest)); + } + + @Operation(summary = "Perform onboarding request for PSP institution type." + + "Users data will be saved on personal data vault if it doesn't already exist." + + "At the end, function triggers async activities related to onboarding that consist of sending mail to Selfcare admin for approve request.") + @POST + @Path("/psp") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + public Uni onboardingPsp(@Valid OnboardingPspRequest onboardingRequest, @Context SecurityContext ctx) { + return readUserIdFromToken(ctx) + .onItem().invoke(onboardingRequest::setUserRequestUid) + .onItem().transformToUni(ignore -> onboardingService.onboardingPsp(onboardingRequest)); + } + + /** + * Onboarding pg may be excluded from the async onboarding flow + * Institutions may be saved without passing from onboarding + * + @POST + @Path("/pg") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + public Uni onboardingPg(@Valid OnboardingPgRequest onboardingRequest) { + return onboardingService.onboarding(onboardingMapper.toEntity(onboardingRequest)) + .map(onboardingMapper::toResponse); + }*/ + + + private Uni readUserIdFromToken(SecurityContext ctx) { + + return currentIdentityAssociation.getDeferredIdentity() + .onItem().transformToUni(identity -> { + if (ctx.getUserPrincipal() == null || !ctx.getUserPrincipal().getName().equals(identity.getPrincipal().getName())) { + return Uni.createFrom().failure(new InternalServerErrorException("Principal and JsonWebToken names do not match")); + } + + if(identity.getPrincipal() instanceof DefaultJWTCallerPrincipal jwtCallerPrincipal) { + String uid = jwtCallerPrincipal.getClaim("uid"); + return Uni.createFrom().item(uid); + } + + return Uni.createFrom().nullItem(); + }); + } + + + @Operation(summary = "Perform complete operation of an onboarding request receiving onboarding id and contract signed by hte institution." + + "It checks the contract's signature and upload the contract on an azure storage" + + "At the end, function triggers async activities related to complete onboarding " + + "that consist of create the institution, activate the onboarding and sending data to notification queue.") + + @PUT + @Path("/{onboardingId}/complete") + @Consumes(MediaType.MULTIPART_FORM_DATA) + public Uni complete(@PathParam(value = "onboardingId") String onboardingId, @RestForm("contract") File file) { + return onboardingService.complete(onboardingId, file) + .map(ignore -> Response + .status(HttpStatus.SC_NO_CONTENT) + .build()); + } + + @Operation(summary = "The API retrieves paged onboarding using optional filter, order by descending creation date") + @GET + @Produces(MediaType.APPLICATION_JSON) + public Uni getOnboardingWithFilter(@QueryParam(value = "productId") String productId, + @QueryParam(value = "taxCode") String taxCode, + @QueryParam(value = "from") String from, + @QueryParam(value = "to") String to, + @QueryParam(value = "status") String status, + @QueryParam(value = "page") @DefaultValue("0") Integer page, + @QueryParam(value = "size") @DefaultValue("20") Integer size) { + return onboardingService.onboardingGet(productId, taxCode, status, from, to, page, size); + } + + @PUT + @Path("/{onboardingId}/delete") + public Uni delete(@PathParam(value = "onboardingId") String onboardingId) { + return onboardingService.deleteOnboarding(onboardingId) + .map(ignore -> Response + .status(HttpStatus.SC_NO_CONTENT) + .build()); + } + + @Operation(summary = "Retrieve an onboarding record given its ID") + @GET + @Path("/{onboardingId}") + public Uni getById(@PathParam(value = "onboardingId") String onboardingId) { + return onboardingService.onboardingGet(onboardingId); + } + + @Operation(summary = "Retrieve an onboarding record given its ID adding to user sensitive information") + @GET + @Path("/{onboardingId}/withUserInfo") + public Uni getByIdWithUserInfo(@PathParam(value = "onboardingId") String onboardingId) { + return onboardingService.onboardingGetWithUserInfo(onboardingId); + } + @Operation(summary = "Returns an onboarding record by its ID only if its status is PENDING. " + + "This feature is crucial for ensuring that the onboarding process can be completed only when " + + "the onboarding status is appropriately set to PENDING.") + @GET + @Path("/{onboardingId}/pending") + public Uni getOnboardingPending(@PathParam(value = "onboardingId") String onboardingId) { + return onboardingService.onboardingPending(onboardingId); + } + + +} diff --git a/onboarding-ms/src/main/java/it/pagopa/selfcare/controller/request/BillingRequest.java b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/request/BillingPaRequest.java similarity index 75% rename from onboarding-ms/src/main/java/it/pagopa/selfcare/controller/request/BillingRequest.java rename to apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/request/BillingPaRequest.java index d0961c970..1cd1ba060 100644 --- a/onboarding-ms/src/main/java/it/pagopa/selfcare/controller/request/BillingRequest.java +++ b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/request/BillingPaRequest.java @@ -1,10 +1,10 @@ -package it.pagopa.selfcare.controller.request; +package it.pagopa.selfcare.onboarding.controller.request; import jakarta.validation.constraints.NotEmpty; import lombok.Data; @Data -public class BillingRequest { +public class BillingPaRequest { @NotEmpty(message = "vatNumber is required") private String vatNumber; @NotEmpty(message = "recipientCode is required") diff --git a/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/request/BillingRequest.java b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/request/BillingRequest.java new file mode 100644 index 000000000..7b4713d5c --- /dev/null +++ b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/request/BillingRequest.java @@ -0,0 +1,12 @@ +package it.pagopa.selfcare.onboarding.controller.request; + +import jakarta.validation.constraints.NotEmpty; +import lombok.Data; + +@Data +public class BillingRequest { + @NotEmpty(message = "vatNumber is required") + private String vatNumber; + private String recipientCode; + private boolean publicServices; +} diff --git a/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/request/BillingSaRequest.java b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/request/BillingSaRequest.java new file mode 100644 index 000000000..4ab9bf4c2 --- /dev/null +++ b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/request/BillingSaRequest.java @@ -0,0 +1,12 @@ +package it.pagopa.selfcare.onboarding.controller.request; + +import jakarta.validation.constraints.NotEmpty; +import lombok.Data; + +@Data +public class BillingSaRequest { + @NotEmpty(message = "vatNumber is required") + private String vatNumber; + private String recipientCode; + private boolean publicServices; +} diff --git a/onboarding-ms/src/main/java/it/pagopa/selfcare/controller/request/ContractRequest.java b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/request/ContractRequest.java similarity index 78% rename from onboarding-ms/src/main/java/it/pagopa/selfcare/controller/request/ContractRequest.java rename to apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/request/ContractRequest.java index 3269a577a..9e978de47 100644 --- a/onboarding-ms/src/main/java/it/pagopa/selfcare/controller/request/ContractRequest.java +++ b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/request/ContractRequest.java @@ -1,4 +1,4 @@ -package it.pagopa.selfcare.controller.request; +package it.pagopa.selfcare.onboarding.controller.request; import jakarta.validation.constraints.NotEmpty; import lombok.Data; diff --git a/onboarding-ms/src/main/java/it/pagopa/selfcare/controller/request/DataProtectionOfficerRequest.java b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/request/DataProtectionOfficerRequest.java similarity index 72% rename from onboarding-ms/src/main/java/it/pagopa/selfcare/controller/request/DataProtectionOfficerRequest.java rename to apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/request/DataProtectionOfficerRequest.java index cdf089f9a..f66634cb8 100644 --- a/onboarding-ms/src/main/java/it/pagopa/selfcare/controller/request/DataProtectionOfficerRequest.java +++ b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/request/DataProtectionOfficerRequest.java @@ -1,4 +1,4 @@ -package it.pagopa.selfcare.controller.request; +package it.pagopa.selfcare.onboarding.controller.request; import lombok.Data; diff --git a/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/request/GeographicTaxonomyDto.java b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/request/GeographicTaxonomyDto.java new file mode 100644 index 000000000..2af54c7fc --- /dev/null +++ b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/request/GeographicTaxonomyDto.java @@ -0,0 +1,9 @@ +package it.pagopa.selfcare.onboarding.controller.request; + +import lombok.Data; + +@Data +public class GeographicTaxonomyDto { + private String code; + private String desc; +} diff --git a/onboarding-ms/src/main/java/it/pagopa/selfcare/controller/request/InstitutionBaseRequest.java b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/request/InstitutionBaseRequest.java similarity index 63% rename from onboarding-ms/src/main/java/it/pagopa/selfcare/controller/request/InstitutionBaseRequest.java rename to apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/request/InstitutionBaseRequest.java index 0335c5593..964d7bf3f 100644 --- a/onboarding-ms/src/main/java/it/pagopa/selfcare/controller/request/InstitutionBaseRequest.java +++ b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/request/InstitutionBaseRequest.java @@ -1,7 +1,8 @@ -package it.pagopa.selfcare.controller.request; +package it.pagopa.selfcare.onboarding.controller.request; -import it.pagopa.selfcare.util.InstitutionPaSubunitType; -import it.pagopa.selfcare.util.InstitutionType; +import it.pagopa.selfcare.onboarding.common.InstitutionType; +import it.pagopa.selfcare.onboarding.common.Origin; +import it.pagopa.selfcare.onboarding.util.InstitutionPaSubunitType; import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.NotNull; import lombok.Data; @@ -17,13 +18,17 @@ public class InstitutionBaseRequest { private String taxCode; private String subunitCode; private InstitutionPaSubunitType subunitType; - + private Origin origin; + private String city; + private String country; + private String county; private String description; + @NotEmpty(message = "digitalAddress is required") private String digitalAddress; private String address; private String zipCode; - private List geographicTaxonomyCodes; + private List geographicTaxonomies; private String rea; private String shareCapital; diff --git a/onboarding-ms/src/main/java/it/pagopa/selfcare/controller/request/InstitutionPspRequest.java b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/request/InstitutionPspRequest.java similarity index 89% rename from onboarding-ms/src/main/java/it/pagopa/selfcare/controller/request/InstitutionPspRequest.java rename to apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/request/InstitutionPspRequest.java index f89823ca9..00800bb0d 100644 --- a/onboarding-ms/src/main/java/it/pagopa/selfcare/controller/request/InstitutionPspRequest.java +++ b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/request/InstitutionPspRequest.java @@ -1,4 +1,4 @@ -package it.pagopa.selfcare.controller.request; +package it.pagopa.selfcare.onboarding.controller.request; import jakarta.validation.Valid; import jakarta.validation.constraints.NotNull; diff --git a/onboarding-ms/src/main/java/it/pagopa/selfcare/controller/request/OnboardingBaseRequest.java b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/request/OnboardingBaseRequest.java similarity index 83% rename from onboarding-ms/src/main/java/it/pagopa/selfcare/controller/request/OnboardingBaseRequest.java rename to apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/request/OnboardingBaseRequest.java index 1010b94f6..ecda47165 100644 --- a/onboarding-ms/src/main/java/it/pagopa/selfcare/controller/request/OnboardingBaseRequest.java +++ b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/request/OnboardingBaseRequest.java @@ -1,4 +1,4 @@ -package it.pagopa.selfcare.controller.request; +package it.pagopa.selfcare.onboarding.controller.request; import jakarta.validation.constraints.NotEmpty; import lombok.Data; @@ -20,5 +20,6 @@ public class OnboardingBaseRequest { private OnboardingImportContract contractImported; private Boolean signContract; + private String userRequestUid; } diff --git a/onboarding-ms/src/main/java/it/pagopa/selfcare/controller/request/OnboardingDefaultRequest.java b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/request/OnboardingDefaultRequest.java similarity index 77% rename from onboarding-ms/src/main/java/it/pagopa/selfcare/controller/request/OnboardingDefaultRequest.java rename to apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/request/OnboardingDefaultRequest.java index aa5a5d201..c421202ca 100644 --- a/onboarding-ms/src/main/java/it/pagopa/selfcare/controller/request/OnboardingDefaultRequest.java +++ b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/request/OnboardingDefaultRequest.java @@ -1,11 +1,10 @@ -package it.pagopa.selfcare.controller.request; +package it.pagopa.selfcare.onboarding.controller.request; import jakarta.validation.Valid; import jakarta.validation.constraints.NotNull; import lombok.Data; import lombok.EqualsAndHashCode; -import java.util.List; @EqualsAndHashCode(callSuper = true) @Data @@ -14,6 +13,8 @@ public class OnboardingDefaultRequest extends OnboardingBaseRequest { @NotNull(message = "institutionData is required") @Valid private InstitutionBaseRequest institution; + @NotNull(message = "billing is required") + @Valid private BillingRequest billing; } diff --git a/onboarding-ms/src/main/java/it/pagopa/selfcare/controller/request/OnboardingImportContract.java b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/request/OnboardingImportContract.java similarity index 80% rename from onboarding-ms/src/main/java/it/pagopa/selfcare/controller/request/OnboardingImportContract.java rename to apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/request/OnboardingImportContract.java index e90be3668..cab71cde4 100644 --- a/onboarding-ms/src/main/java/it/pagopa/selfcare/controller/request/OnboardingImportContract.java +++ b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/request/OnboardingImportContract.java @@ -1,4 +1,4 @@ -package it.pagopa.selfcare.controller.request; +package it.pagopa.selfcare.onboarding.controller.request; import lombok.Data; diff --git a/onboarding-ms/src/main/java/it/pagopa/selfcare/controller/request/OnboardingPaRequest.java b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/request/OnboardingPaRequest.java similarity index 72% rename from onboarding-ms/src/main/java/it/pagopa/selfcare/controller/request/OnboardingPaRequest.java rename to apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/request/OnboardingPaRequest.java index c4b909ea6..afd614335 100644 --- a/onboarding-ms/src/main/java/it/pagopa/selfcare/controller/request/OnboardingPaRequest.java +++ b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/request/OnboardingPaRequest.java @@ -1,13 +1,10 @@ -package it.pagopa.selfcare.controller.request; +package it.pagopa.selfcare.onboarding.controller.request; import jakarta.validation.Valid; -import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.NotNull; import lombok.Data; import lombok.EqualsAndHashCode; -import java.util.List; - @EqualsAndHashCode(callSuper = true) @Data public class OnboardingPaRequest extends OnboardingBaseRequest { @@ -18,6 +15,6 @@ public class OnboardingPaRequest extends OnboardingBaseRequest { @NotNull(message = "billing is required") @Valid - private BillingRequest billing; + private BillingPaRequest billing; } diff --git a/onboarding-ms/src/main/java/it/pagopa/selfcare/controller/request/OnboardingPgRequest.java b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/request/OnboardingPgRequest.java similarity index 91% rename from onboarding-ms/src/main/java/it/pagopa/selfcare/controller/request/OnboardingPgRequest.java rename to apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/request/OnboardingPgRequest.java index 9e4f9b94b..55e61e3dd 100644 --- a/onboarding-ms/src/main/java/it/pagopa/selfcare/controller/request/OnboardingPgRequest.java +++ b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/request/OnboardingPgRequest.java @@ -1,4 +1,4 @@ -package it.pagopa.selfcare.controller.request; +package it.pagopa.selfcare.onboarding.controller.request; import jakarta.validation.constraints.Email; import jakarta.validation.constraints.NotBlank; diff --git a/onboarding-ms/src/main/java/it/pagopa/selfcare/controller/request/OnboardingPspRequest.java b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/request/OnboardingPspRequest.java similarity index 87% rename from onboarding-ms/src/main/java/it/pagopa/selfcare/controller/request/OnboardingPspRequest.java rename to apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/request/OnboardingPspRequest.java index d7023c0cb..c6577b73e 100644 --- a/onboarding-ms/src/main/java/it/pagopa/selfcare/controller/request/OnboardingPspRequest.java +++ b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/request/OnboardingPspRequest.java @@ -1,4 +1,4 @@ -package it.pagopa.selfcare.controller.request; +package it.pagopa.selfcare.onboarding.controller.request; import jakarta.validation.Valid; import jakarta.validation.constraints.NotNull; diff --git a/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/request/OnboardingSaRequest.java b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/request/OnboardingSaRequest.java new file mode 100644 index 000000000..4e120673d --- /dev/null +++ b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/request/OnboardingSaRequest.java @@ -0,0 +1,20 @@ +package it.pagopa.selfcare.onboarding.controller.request; + +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import lombok.EqualsAndHashCode; + + +@EqualsAndHashCode(callSuper = true) +@Data +public class OnboardingSaRequest extends OnboardingBaseRequest { + + @NotNull(message = "institutionData is required") + @Valid + private InstitutionBaseRequest institution; + @NotNull(message = "billing is required") + @Valid + private BillingSaRequest billing; + +} diff --git a/onboarding-ms/src/main/java/it/pagopa/selfcare/controller/request/PaymentServiceProviderRequest.java b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/request/PaymentServiceProviderRequest.java similarity index 81% rename from onboarding-ms/src/main/java/it/pagopa/selfcare/controller/request/PaymentServiceProviderRequest.java rename to apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/request/PaymentServiceProviderRequest.java index 89a0b89f0..bdfc788a4 100644 --- a/onboarding-ms/src/main/java/it/pagopa/selfcare/controller/request/PaymentServiceProviderRequest.java +++ b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/request/PaymentServiceProviderRequest.java @@ -1,4 +1,4 @@ -package it.pagopa.selfcare.controller.request; +package it.pagopa.selfcare.onboarding.controller.request; import lombok.Data; diff --git a/onboarding-ms/src/main/java/it/pagopa/selfcare/controller/request/ProductInfo.java b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/request/ProductInfo.java similarity index 82% rename from onboarding-ms/src/main/java/it/pagopa/selfcare/controller/request/ProductInfo.java rename to apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/request/ProductInfo.java index 2b74bb6ea..83a826394 100644 --- a/onboarding-ms/src/main/java/it/pagopa/selfcare/controller/request/ProductInfo.java +++ b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/request/ProductInfo.java @@ -1,4 +1,4 @@ -package it.pagopa.selfcare.controller.request; +package it.pagopa.selfcare.onboarding.controller.request; import com.fasterxml.jackson.annotation.JsonInclude; import lombok.Data; diff --git a/onboarding-ms/src/main/java/it/pagopa/selfcare/controller/request/SupportContact.java b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/request/SupportContact.java similarity index 80% rename from onboarding-ms/src/main/java/it/pagopa/selfcare/controller/request/SupportContact.java rename to apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/request/SupportContact.java index 2142da125..5e358efbf 100644 --- a/onboarding-ms/src/main/java/it/pagopa/selfcare/controller/request/SupportContact.java +++ b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/request/SupportContact.java @@ -1,4 +1,4 @@ -package it.pagopa.selfcare.controller.request; +package it.pagopa.selfcare.onboarding.controller.request; import lombok.AllArgsConstructor; import lombok.Data; diff --git a/onboarding-ms/src/main/java/it/pagopa/selfcare/controller/request/UserRequest.java b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/request/UserRequest.java similarity index 54% rename from onboarding-ms/src/main/java/it/pagopa/selfcare/controller/request/UserRequest.java rename to apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/request/UserRequest.java index 104cde93c..cefa5730a 100644 --- a/onboarding-ms/src/main/java/it/pagopa/selfcare/controller/request/UserRequest.java +++ b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/request/UserRequest.java @@ -1,9 +1,8 @@ -package it.pagopa.selfcare.controller.request; +package it.pagopa.selfcare.onboarding.controller.request; import com.fasterxml.jackson.annotation.JsonInclude; -import it.pagopa.selfcare.commons.base.security.PartyRole; +import it.pagopa.selfcare.onboarding.common.PartyRole; import jakarta.validation.Valid; -import jakarta.validation.constraints.NotEmpty; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -18,18 +17,12 @@ @NoArgsConstructor public class UserRequest { - @NotEmpty(message = "User internal id is required") - private String id; private String taxCode; private String name; private String surname; private String email; private PartyRole role; - /*private String productRole; - private Env env = Env.ROOT; - private String roleLabel;*/ + private String productRole; + //private Env env = Env.ROOT; - public UserRequest(String id) { - this.id = id; - } } diff --git a/onboarding-ms/src/main/java/it/pagopa/selfcare/controller/response/BillingResponse.java b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/response/BillingResponse.java similarity index 62% rename from onboarding-ms/src/main/java/it/pagopa/selfcare/controller/response/BillingResponse.java rename to apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/response/BillingResponse.java index 00b303c14..a97f75dd5 100644 --- a/onboarding-ms/src/main/java/it/pagopa/selfcare/controller/response/BillingResponse.java +++ b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/response/BillingResponse.java @@ -1,6 +1,5 @@ -package it.pagopa.selfcare.controller.response; +package it.pagopa.selfcare.onboarding.controller.response; -import jakarta.validation.constraints.NotEmpty; import lombok.Data; @Data diff --git a/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/response/ContractRequestResponse.java b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/response/ContractRequestResponse.java new file mode 100644 index 000000000..43e2198c6 --- /dev/null +++ b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/response/ContractRequestResponse.java @@ -0,0 +1,9 @@ +package it.pagopa.selfcare.onboarding.controller.response; + +import lombok.Data; + +@Data +public class ContractRequestResponse { + private String version; + private String path; +} diff --git a/onboarding-ms/src/main/java/it/pagopa/selfcare/controller/response/InstitutionResponse.java b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/response/InstitutionResponse.java similarity index 50% rename from onboarding-ms/src/main/java/it/pagopa/selfcare/controller/response/InstitutionResponse.java rename to apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/response/InstitutionResponse.java index 9bbb72059..16469e95a 100644 --- a/onboarding-ms/src/main/java/it/pagopa/selfcare/controller/response/InstitutionResponse.java +++ b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/response/InstitutionResponse.java @@ -1,9 +1,11 @@ -package it.pagopa.selfcare.controller.response; - -import it.pagopa.selfcare.controller.request.DataProtectionOfficerRequest; -import it.pagopa.selfcare.controller.request.PaymentServiceProviderRequest; -import it.pagopa.selfcare.util.InstitutionPaSubunitType; -import it.pagopa.selfcare.util.InstitutionType; +package it.pagopa.selfcare.onboarding.controller.response; + +import it.pagopa.selfcare.onboarding.common.InstitutionType; +import it.pagopa.selfcare.onboarding.common.Origin; +import it.pagopa.selfcare.onboarding.controller.request.DataProtectionOfficerRequest; +import it.pagopa.selfcare.onboarding.controller.request.GeographicTaxonomyDto; +import it.pagopa.selfcare.onboarding.controller.request.PaymentServiceProviderRequest; +import it.pagopa.selfcare.onboarding.util.InstitutionPaSubunitType; import lombok.Data; import java.util.List; @@ -16,13 +18,16 @@ public class InstitutionResponse { private String taxCode; private String subunitCode; private InstitutionPaSubunitType subunitType; - + private Origin origin; + private String city; + private String country; + private String county; private String description; private String digitalAddress; private String address; private String zipCode; - private List geographicTaxonomyCodes; + private List geographicTaxonomies; private String rea; private String shareCapital; diff --git a/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/response/OnboardingGet.java b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/response/OnboardingGet.java new file mode 100644 index 000000000..6007b8c37 --- /dev/null +++ b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/response/OnboardingGet.java @@ -0,0 +1,20 @@ +package it.pagopa.selfcare.onboarding.controller.response; + +import lombok.Data; + +import java.util.List; + +@Data +public class OnboardingGet { + private String id; + private String productId; + private String workflowType; + private InstitutionResponse institution; + private List users; + private String pricingPlan; + private BillingResponse billing; + private Boolean signContract; + + private String status; + private String userRequestUid; +} diff --git a/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/response/OnboardingGetResponse.java b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/response/OnboardingGetResponse.java new file mode 100644 index 000000000..eaa6ab4bb --- /dev/null +++ b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/response/OnboardingGetResponse.java @@ -0,0 +1,11 @@ +package it.pagopa.selfcare.onboarding.controller.response; + +import lombok.Data; + +import java.util.List; + +@Data +public class OnboardingGetResponse { + Long count; + List items; +} diff --git a/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/response/OnboardingImportContractResponse.java b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/response/OnboardingImportContractResponse.java new file mode 100644 index 000000000..9606310d5 --- /dev/null +++ b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/response/OnboardingImportContractResponse.java @@ -0,0 +1,13 @@ +package it.pagopa.selfcare.onboarding.controller.response; + +import lombok.Data; + +import java.time.OffsetDateTime; + +@Data +public class OnboardingImportContractResponse { + private String fileName; + private String filePath; + private String contractType; + private OffsetDateTime createdAt; +} diff --git a/onboarding-ms/src/main/java/it/pagopa/selfcare/controller/response/OnboardingResponse.java b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/response/OnboardingResponse.java similarity index 74% rename from onboarding-ms/src/main/java/it/pagopa/selfcare/controller/response/OnboardingResponse.java rename to apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/response/OnboardingResponse.java index 2521ac539..5c175c926 100644 --- a/onboarding-ms/src/main/java/it/pagopa/selfcare/controller/response/OnboardingResponse.java +++ b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/response/OnboardingResponse.java @@ -1,4 +1,4 @@ -package it.pagopa.selfcare.controller.response; +package it.pagopa.selfcare.onboarding.controller.response; import lombok.Data; @@ -8,10 +8,10 @@ public class OnboardingResponse { private InstitutionResponse institution; - private String productId; private String pricingPlan; private List users; private BillingResponse billing; + private String userRequestUid; } diff --git a/onboarding-ms/src/main/java/it/pagopa/selfcare/controller/response/UserResponse.java b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/response/UserResponse.java similarity index 65% rename from onboarding-ms/src/main/java/it/pagopa/selfcare/controller/response/UserResponse.java rename to apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/response/UserResponse.java index da68f1773..417d4dc76 100644 --- a/onboarding-ms/src/main/java/it/pagopa/selfcare/controller/response/UserResponse.java +++ b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/response/UserResponse.java @@ -1,6 +1,6 @@ -package it.pagopa.selfcare.controller.response; +package it.pagopa.selfcare.onboarding.controller.response; -import it.pagopa.selfcare.commons.base.security.PartyRole; +import it.pagopa.selfcare.onboarding.common.PartyRole; import lombok.Data; @Data diff --git a/onboarding-ms/src/main/java/it/pagopa/selfcare/entity/Billing.java b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/entity/Billing.java similarity index 64% rename from onboarding-ms/src/main/java/it/pagopa/selfcare/entity/Billing.java rename to apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/entity/Billing.java index faf1244d5..afd113eaf 100644 --- a/onboarding-ms/src/main/java/it/pagopa/selfcare/entity/Billing.java +++ b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/entity/Billing.java @@ -1,6 +1,5 @@ -package it.pagopa.selfcare.entity; +package it.pagopa.selfcare.onboarding.entity; -import jakarta.validation.constraints.NotEmpty; import lombok.Data; @Data diff --git a/onboarding-ms/src/main/java/it/pagopa/selfcare/entity/DataProtectionOfficer.java b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/entity/DataProtectionOfficer.java similarity index 75% rename from onboarding-ms/src/main/java/it/pagopa/selfcare/entity/DataProtectionOfficer.java rename to apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/entity/DataProtectionOfficer.java index 9f59a4e66..eba4c0e1e 100644 --- a/onboarding-ms/src/main/java/it/pagopa/selfcare/entity/DataProtectionOfficer.java +++ b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/entity/DataProtectionOfficer.java @@ -1,4 +1,4 @@ -package it.pagopa.selfcare.entity; +package it.pagopa.selfcare.onboarding.entity; import lombok.Data; diff --git a/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/entity/GeographicTaxonomy.java b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/entity/GeographicTaxonomy.java new file mode 100644 index 000000000..e34c9bae8 --- /dev/null +++ b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/entity/GeographicTaxonomy.java @@ -0,0 +1,9 @@ +package it.pagopa.selfcare.onboarding.entity; + +import lombok.Data; + +@Data +public class GeographicTaxonomy { + private String code; + private String desc; +} diff --git a/onboarding-ms/src/main/java/it/pagopa/selfcare/entity/Institution.java b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/entity/Institution.java similarity index 61% rename from onboarding-ms/src/main/java/it/pagopa/selfcare/entity/Institution.java rename to apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/entity/Institution.java index 45156e00a..ed9b11f2e 100644 --- a/onboarding-ms/src/main/java/it/pagopa/selfcare/entity/Institution.java +++ b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/entity/Institution.java @@ -1,7 +1,8 @@ -package it.pagopa.selfcare.entity; +package it.pagopa.selfcare.onboarding.entity; -import it.pagopa.selfcare.util.InstitutionPaSubunitType; -import it.pagopa.selfcare.util.InstitutionType; +import it.pagopa.selfcare.onboarding.common.InstitutionType; +import it.pagopa.selfcare.onboarding.common.Origin; +import it.pagopa.selfcare.onboarding.util.InstitutionPaSubunitType; import lombok.Data; import java.util.List; @@ -13,13 +14,16 @@ public class Institution { private String taxCode; private String subunitCode; private InstitutionPaSubunitType subunitType; - + private Origin origin; + private String city; + private String country; + private String county; private String description; private String digitalAddress; private String address; private String zipCode; - private List geographicTaxonomyCodes; + private List geographicTaxonomies; private String rea; private String shareCapital; @@ -32,4 +36,6 @@ public class Institution { private PaymentServiceProvider paymentServiceProvider; private DataProtectionOfficer dataProtectionOfficer; + + private String parentDescription; } diff --git a/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/entity/Onboarding.java b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/entity/Onboarding.java new file mode 100644 index 000000000..1d6cd03a8 --- /dev/null +++ b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/entity/Onboarding.java @@ -0,0 +1,40 @@ +package it.pagopa.selfcare.onboarding.entity; + +import io.quarkus.mongodb.panache.common.MongoEntity; +import io.quarkus.mongodb.panache.reactive.ReactivePanacheMongoEntity; +import it.pagopa.selfcare.onboarding.common.OnboardingStatus; +import it.pagopa.selfcare.onboarding.common.WorkflowType; +import it.pagopa.selfcare.onboarding.controller.request.ContractRequest; +import it.pagopa.selfcare.onboarding.controller.request.OnboardingImportContract; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.FieldNameConstants; +import org.bson.types.ObjectId; + +import java.time.LocalDateTime; +import java.util.List; + +@EqualsAndHashCode(callSuper = true) +@Data +@FieldNameConstants(asEnum = true) +@MongoEntity(collection="onboardings") +public class Onboarding extends ReactivePanacheMongoEntity { + + public ObjectId id; + + private String productId; + private WorkflowType workflowType; + private Institution institution; + private List users; + private String pricingPlan; + private Billing billing; + private ContractRequest contract; + private OnboardingImportContract contractImported; + private Boolean signContract; + + private LocalDateTime createdAt; + private LocalDateTime updatedAt; + private LocalDateTime expiringDate; + private OnboardingStatus status; + private String userRequestUid; +} diff --git a/onboarding-ms/src/main/java/it/pagopa/selfcare/entity/PaymentServiceProvider.java b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/entity/PaymentServiceProvider.java similarity index 84% rename from onboarding-ms/src/main/java/it/pagopa/selfcare/entity/PaymentServiceProvider.java rename to apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/entity/PaymentServiceProvider.java index 35b739928..a0bae7b69 100644 --- a/onboarding-ms/src/main/java/it/pagopa/selfcare/entity/PaymentServiceProvider.java +++ b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/entity/PaymentServiceProvider.java @@ -1,4 +1,4 @@ -package it.pagopa.selfcare.entity; +package it.pagopa.selfcare.onboarding.entity; import lombok.Data; diff --git a/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/entity/Product.java b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/entity/Product.java new file mode 100644 index 000000000..e805c16df --- /dev/null +++ b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/entity/Product.java @@ -0,0 +1,2 @@ +package it.pagopa.selfcare.onboarding.entity;public class Product { +} diff --git a/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/entity/Token.java b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/entity/Token.java new file mode 100644 index 000000000..b866e5e91 --- /dev/null +++ b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/entity/Token.java @@ -0,0 +1,33 @@ +package it.pagopa.selfcare.onboarding.entity; + +import io.quarkus.mongodb.panache.common.MongoEntity; +import io.quarkus.mongodb.panache.reactive.ReactivePanacheMongoEntity; +import it.pagopa.selfcare.onboarding.common.TokenType; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.bson.types.ObjectId; + +import java.time.LocalDateTime; + +@EqualsAndHashCode(callSuper = true) +@Data +@MongoEntity(collection="tokens") +public class Token extends ReactivePanacheMongoEntity { + + private ObjectId id; + private TokenType type; + private String onboardingId; + private String productId; + private String checksum; + private String contractVersion; + private String contractTemplate; + private String contractSigned; + private String contractFilename; + //@Indexed + private LocalDateTime createdAt; + private LocalDateTime updatedAt; + private LocalDateTime deletedAt; + private LocalDateTime activatedAt; + +} + diff --git a/onboarding-ms/src/main/java/it/pagopa/selfcare/entity/User.java b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/entity/User.java similarity index 51% rename from onboarding-ms/src/main/java/it/pagopa/selfcare/entity/User.java rename to apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/entity/User.java index a5f67af3b..e532cfe49 100644 --- a/onboarding-ms/src/main/java/it/pagopa/selfcare/entity/User.java +++ b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/entity/User.java @@ -1,9 +1,6 @@ -package it.pagopa.selfcare.entity; +package it.pagopa.selfcare.onboarding.entity; -import com.fasterxml.jackson.annotation.JsonInclude; -import it.pagopa.selfcare.commons.base.security.PartyRole; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotEmpty; +import it.pagopa.selfcare.onboarding.common.PartyRole; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -18,4 +15,5 @@ public class User { private String id; private PartyRole role; + private String ProductRole; } diff --git a/onboarding-ms/src/main/java/it/pagopa/selfcare/exception/InvalidRequestException.java b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/exception/InvalidRequestException.java similarity index 63% rename from onboarding-ms/src/main/java/it/pagopa/selfcare/exception/InvalidRequestException.java rename to apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/exception/InvalidRequestException.java index 8873d2f90..6db99d82b 100644 --- a/onboarding-ms/src/main/java/it/pagopa/selfcare/exception/InvalidRequestException.java +++ b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/exception/InvalidRequestException.java @@ -1,4 +1,4 @@ -package it.pagopa.selfcare.exception; +package it.pagopa.selfcare.onboarding.exception; public class InvalidRequestException extends RuntimeException{ private final String code; @@ -8,6 +8,11 @@ public InvalidRequestException(String message, String code) { this.code = code; } + public InvalidRequestException(String message) { + super(message); + this.code = "0000"; + } + public String getCode() { return code; } diff --git a/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/exception/OnboardingNotAllowedException.java b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/exception/OnboardingNotAllowedException.java new file mode 100644 index 000000000..fed93ea05 --- /dev/null +++ b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/exception/OnboardingNotAllowedException.java @@ -0,0 +1,15 @@ +package it.pagopa.selfcare.onboarding.exception; + +public class OnboardingNotAllowedException extends RuntimeException { + + private final String code; + + public OnboardingNotAllowedException(String message, String code) { + super(message); + this.code = code; + } + + public String getCode() { + return code; + } +} diff --git a/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/exception/ResourceNotFoundException.java b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/exception/ResourceNotFoundException.java new file mode 100644 index 000000000..fcbeff460 --- /dev/null +++ b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/exception/ResourceNotFoundException.java @@ -0,0 +1,19 @@ +package it.pagopa.selfcare.onboarding.exception; + +public class ResourceNotFoundException extends RuntimeException{ + private final String code; + + public ResourceNotFoundException(String message, String code) { + super(message); + this.code = code; + } + + public ResourceNotFoundException(String message) { + super(message); + this.code = "0000"; + } + + public String getCode() { + return code; + } +} diff --git a/onboarding-ms/src/main/java/it/pagopa/selfcare/exception/UpdateNotAllowedException.java b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/exception/UpdateNotAllowedException.java similarity index 76% rename from onboarding-ms/src/main/java/it/pagopa/selfcare/exception/UpdateNotAllowedException.java rename to apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/exception/UpdateNotAllowedException.java index 809333837..fcee21d9f 100644 --- a/onboarding-ms/src/main/java/it/pagopa/selfcare/exception/UpdateNotAllowedException.java +++ b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/exception/UpdateNotAllowedException.java @@ -1,4 +1,4 @@ -package it.pagopa.selfcare.exception; +package it.pagopa.selfcare.onboarding.exception; public class UpdateNotAllowedException extends RuntimeException { diff --git a/onboarding-ms/src/main/java/it/pagopa/selfcare/exception/handler/ExceptionHandler.java b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/exception/handler/ExceptionHandler.java similarity index 53% rename from onboarding-ms/src/main/java/it/pagopa/selfcare/exception/handler/ExceptionHandler.java rename to apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/exception/handler/ExceptionHandler.java index d7b154c54..5aae94ff2 100644 --- a/onboarding-ms/src/main/java/it/pagopa/selfcare/exception/handler/ExceptionHandler.java +++ b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/exception/handler/ExceptionHandler.java @@ -1,18 +1,14 @@ -package it.pagopa.selfcare.exception.handler; +package it.pagopa.selfcare.onboarding.exception.handler; -import it.pagopa.selfcare.exception.InvalidRequestException; -import jakarta.ws.rs.Produces; -import jakarta.ws.rs.core.MediaType; +import it.pagopa.selfcare.onboarding.exception.InvalidRequestException; +import it.pagopa.selfcare.onboarding.exception.OnboardingNotAllowedException; +import it.pagopa.selfcare.onboarding.exception.ResourceNotFoundException; import jakarta.ws.rs.core.Response; -import jakarta.ws.rs.ext.ExceptionMapper; -import jakarta.ws.rs.ext.Provider; import org.jboss.resteasy.reactive.RestResponse; import org.jboss.resteasy.reactive.server.ServerExceptionMapper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.Collections; - public class ExceptionHandler { @@ -24,10 +20,20 @@ public RestResponse toResponse(InvalidRequestException exception) { LOGGER.error("{}: {}", SOMETHING_HAS_GONE_WRONG_IN_THE_SERVER, exception.getMessage()); return RestResponse.status(Response.Status.BAD_REQUEST, exception.getMessage()); } + @ServerExceptionMapper + public RestResponse toResponse(OnboardingNotAllowedException exception) { + LOGGER.error("{}: {}", SOMETHING_HAS_GONE_WRONG_IN_THE_SERVER, exception.getMessage()); + return RestResponse.status(Response.Status.BAD_REQUEST, exception.getMessage()); + } @ServerExceptionMapper public RestResponse toResponse(Exception exception) { LOGGER.error("{}: {}", SOMETHING_HAS_GONE_WRONG_IN_THE_SERVER, exception.getMessage()); return RestResponse.status(Response.Status.INTERNAL_SERVER_ERROR, SOMETHING_HAS_GONE_WRONG_IN_THE_SERVER); } + @ServerExceptionMapper + public RestResponse toResponse(ResourceNotFoundException exception) { + LOGGER.error("{}: {}", SOMETHING_HAS_GONE_WRONG_IN_THE_SERVER, exception.getMessage()); + return RestResponse.status(Response.Status.NOT_FOUND, exception.getMessage()); + } } diff --git a/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/mapper/OnboardingMapper.java b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/mapper/OnboardingMapper.java new file mode 100644 index 000000000..eed469990 --- /dev/null +++ b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/mapper/OnboardingMapper.java @@ -0,0 +1,35 @@ +package it.pagopa.selfcare.onboarding.mapper; + +import it.pagopa.selfcare.onboarding.controller.request.OnboardingDefaultRequest; +import it.pagopa.selfcare.onboarding.controller.request.OnboardingPaRequest; +import it.pagopa.selfcare.onboarding.controller.request.OnboardingPspRequest; +import it.pagopa.selfcare.onboarding.controller.request.OnboardingSaRequest; +import it.pagopa.selfcare.onboarding.controller.response.OnboardingGet; +import it.pagopa.selfcare.onboarding.controller.response.OnboardingResponse; +import it.pagopa.selfcare.onboarding.entity.Onboarding; +import org.bson.types.ObjectId; +import org.mapstruct.*; + +@Mapper(componentModel = "cdi") +public interface OnboardingMapper { + + Onboarding toEntity(OnboardingPaRequest request); + Onboarding toEntity(OnboardingPspRequest request); + Onboarding toEntity(OnboardingDefaultRequest request); + Onboarding toEntity(OnboardingSaRequest request); + + //@Mapping(source = "taxCode", target = "institution.taxCode") + //@Mapping(source = "businessName", target = "institution.description") + //@Mapping(source = "digitalAddress", target = "institution.digitalAddress") + //Onboarding toEntity(OnboardingPgRequest request); + + OnboardingResponse toResponse(Onboarding onboarding); + + @Mapping(target = "id", expression = "java(objectIdToString(model.getId()))") + OnboardingGet toGetResponse(Onboarding model); + + @Named("objectIdToString") + default String objectIdToString(ObjectId objectId) { + return objectId.toHexString(); + } +} diff --git a/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/mapper/UserMapper.java b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/mapper/UserMapper.java new file mode 100644 index 000000000..75e4695b2 --- /dev/null +++ b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/mapper/UserMapper.java @@ -0,0 +1,18 @@ +package it.pagopa.selfcare.onboarding.mapper; + +import it.pagopa.selfcare.onboarding.controller.response.UserResponse; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.MappingTarget; +import org.openapi.quarkus.user_registry_json.model.UserResource; + +@Mapper(componentModel = "cdi") +public interface UserMapper { + + @Mapping(source = "name.value", target = "name") + @Mapping(source = "familyName.value", target = "surname") + @Mapping(source = "email.value", target = "email") + @Mapping(source = "fiscalCode", target = "taxCode") + void fillUserResponse(UserResource userResource, @MappingTarget UserResponse userResponse); + +} diff --git a/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/service/OnboardingService.java b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/service/OnboardingService.java new file mode 100644 index 000000000..18ff9afc7 --- /dev/null +++ b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/service/OnboardingService.java @@ -0,0 +1,38 @@ +package it.pagopa.selfcare.onboarding.service; + +import io.smallrye.mutiny.Uni; +import it.pagopa.selfcare.onboarding.controller.request.OnboardingDefaultRequest; +import it.pagopa.selfcare.onboarding.controller.request.OnboardingPaRequest; +import it.pagopa.selfcare.onboarding.controller.request.OnboardingPspRequest; +import it.pagopa.selfcare.onboarding.controller.request.OnboardingSaRequest; +import it.pagopa.selfcare.onboarding.controller.response.OnboardingGet; +import it.pagopa.selfcare.onboarding.controller.response.OnboardingGetResponse; +import it.pagopa.selfcare.onboarding.controller.response.OnboardingResponse; +import it.pagopa.selfcare.onboarding.entity.Onboarding; + +import java.io.File; + +public interface OnboardingService { + + Uni onboarding(OnboardingDefaultRequest onboardingRequest); + + Uni onboardingPsp(OnboardingPspRequest onboardingRequest); + + Uni onboardingSa(OnboardingSaRequest onboardingRequest); + + Uni onboardingPa(OnboardingPaRequest onboardingRequest); + + Uni complete(String tokenId, File contract); + + Uni completeWithoutSignatureVerification(String tokenId, File contract); + + Uni onboardingGet(String productId, String taxCode, String status, String from, String to, Integer page, Integer size); + + Uni deleteOnboarding(String onboardingId); + + Uni onboardingPending(String onboardingId); + + Uni onboardingGet(String onboardingId); + + Uni onboardingGetWithUserInfo(String onboardingId); +} diff --git a/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/service/OnboardingServiceDefault.java b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/service/OnboardingServiceDefault.java new file mode 100644 index 000000000..44baaf67a --- /dev/null +++ b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/service/OnboardingServiceDefault.java @@ -0,0 +1,631 @@ +package it.pagopa.selfcare.onboarding.service; + +import io.quarkus.mongodb.panache.common.reactive.Panache; +import io.quarkus.mongodb.panache.reactive.ReactivePanacheQuery; +import io.smallrye.mutiny.Multi; +import io.smallrye.mutiny.Uni; +import io.smallrye.mutiny.infrastructure.Infrastructure; +import io.smallrye.mutiny.tuples.Tuple2; +import io.smallrye.mutiny.unchecked.Unchecked; +import it.pagopa.selfcare.azurestorage.AzureBlobClient; +import it.pagopa.selfcare.onboarding.common.InstitutionType; +import it.pagopa.selfcare.onboarding.common.OnboardingStatus; +import it.pagopa.selfcare.onboarding.common.PartyRole; +import it.pagopa.selfcare.onboarding.common.WorkflowType; +import it.pagopa.selfcare.onboarding.constants.CustomError; +import it.pagopa.selfcare.onboarding.controller.request.*; +import it.pagopa.selfcare.onboarding.controller.response.OnboardingGet; +import it.pagopa.selfcare.onboarding.controller.response.OnboardingGetResponse; +import it.pagopa.selfcare.onboarding.controller.response.OnboardingResponse; +import it.pagopa.selfcare.onboarding.controller.response.UserResponse; +import it.pagopa.selfcare.onboarding.entity.Onboarding; +import it.pagopa.selfcare.onboarding.entity.Token; +import it.pagopa.selfcare.onboarding.entity.User; +import it.pagopa.selfcare.onboarding.exception.InvalidRequestException; +import it.pagopa.selfcare.onboarding.exception.OnboardingNotAllowedException; +import it.pagopa.selfcare.onboarding.exception.ResourceNotFoundException; +import it.pagopa.selfcare.onboarding.exception.UpdateNotAllowedException; +import it.pagopa.selfcare.onboarding.mapper.OnboardingMapper; +import it.pagopa.selfcare.onboarding.mapper.UserMapper; +import it.pagopa.selfcare.onboarding.service.strategy.OnboardingValidationStrategy; +import it.pagopa.selfcare.onboarding.util.InstitutionPaSubunitType; +import it.pagopa.selfcare.onboarding.util.QueryUtils; +import it.pagopa.selfcare.onboarding.util.SortEnum; +import it.pagopa.selfcare.product.entity.Product; +import it.pagopa.selfcare.product.entity.ProductRoleInfo; +import it.pagopa.selfcare.product.service.ProductService; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; +import jakarta.ws.rs.WebApplicationException; +import jakarta.ws.rs.core.Response; +import org.apache.commons.lang3.StringUtils; +import org.bson.Document; +import org.bson.types.ObjectId; +import org.eclipse.microprofile.config.inject.ConfigProperty; +import org.eclipse.microprofile.rest.client.inject.RestClient; +import org.jboss.resteasy.reactive.ClientWebApplicationException; +import org.openapi.quarkus.core_json.api.OnboardingApi; +import org.openapi.quarkus.onboarding_functions_json.api.OrchestrationApi; +import org.openapi.quarkus.party_registry_proxy_json.api.AooApi; +import org.openapi.quarkus.party_registry_proxy_json.api.UoApi; +import org.openapi.quarkus.user_registry_json.api.UserApi; +import org.openapi.quarkus.user_registry_json.model.*; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.time.LocalDateTime; +import java.time.OffsetDateTime; +import java.util.*; +import java.util.function.Function; +import java.util.stream.Collectors; + +import static it.pagopa.selfcare.onboarding.common.ProductId.PROD_INTEROP; +import static it.pagopa.selfcare.onboarding.constants.CustomError.*; +import static it.pagopa.selfcare.onboarding.util.GenericError.GENERIC_ERROR; +import static it.pagopa.selfcare.onboarding.util.GenericError.ONBOARDING_EXPIRED; + +@ApplicationScoped +public class OnboardingServiceDefault implements OnboardingService { + protected static final String ATLEAST_ONE_PRODUCT_ROLE_REQUIRED = "At least one Product role related to %s Party role is required"; + protected static final String MORE_THAN_ONE_PRODUCT_ROLE_AVAILABLE = "More than one Product role related to %s Party role is available. Cannot automatically set the Product role"; + private static final String ONBOARDING_NOT_ALLOWED_ERROR_MESSAGE_TEMPLATE = "Institution with external id '%s' is not allowed to onboard '%s' product"; + private static final String ONBOARDING_NOT_ALLOWED_ERROR_MESSAGE_NOT_DELEGABLE = "Institution with external id '%s' is not allowed to onboard '%s' product because it is not delegable"; + private static final String INVALID_OBJECTID = "Given onboardingId [%s] has wrong format"; + private static final String ONBOARDING_NOT_FOUND_OR_ALREADY_DELETED = "Onboarding with id %s not found or already deleted"; + public static final String UNABLE_TO_COMPLETE_THE_ONBOARDING_FOR_INSTITUTION_FOR_PRODUCT_DISMISSED = "Unable to complete the onboarding for institution with taxCode '%s' to product '%s', the product is dismissed."; + + public static final String USERS_FIELD_LIST = "fiscalCode,familyName,name,workContacts"; + public static final String USERS_FIELD_TAXCODE = "fiscalCode"; + public static final String UNABLE_TO_COMPLETE_THE_ONBOARDING_FOR_INSTITUTION_ALREADY_ONBOARDED = "Unable to complete the onboarding for institution with taxCode '%s' to product '%s' because is already onboarded."; + + + public static final Function workContactsKey = onboardingId -> String.format("obg_%s", onboardingId); + + @RestClient + @Inject + UserApi userRegistryApi; + + @RestClient + @Inject + OnboardingApi onboardingApi; + + @RestClient + @Inject + AooApi aooApi; + + @RestClient + @Inject + UoApi uoApi; + + @RestClient + @Inject + OrchestrationApi orchestrationApi; + + @Inject + OnboardingMapper onboardingMapper; + + @Inject + OnboardingValidationStrategy onboardingValidationStrategy; + @Inject + ProductService productService; + @Inject + SignatureService signatureService; + @Inject + AzureBlobClient azureBlobClient; + + @Inject + UserMapper userMapper; + + @ConfigProperty(name = "onboarding.expiring-date") + Integer onboardingExpireDate; + @ConfigProperty(name = "onboarding.orchestration.enabled") + Boolean onboardingOrchestrationEnabled; + @ConfigProperty(name = "onboarding-ms.signature.verify-enabled") + Boolean isVerifyEnabled; + @ConfigProperty(name = "onboarding-ms.blob-storage.path-contracts") + String pathContracts; + + @Override + public Uni onboarding(OnboardingDefaultRequest onboardingRequest) { + return fillUsersAndOnboarding(onboardingMapper.toEntity(onboardingRequest), onboardingRequest.getUsers()); + } + + @Override + public Uni onboardingPsp(OnboardingPspRequest onboardingRequest) { + return fillUsersAndOnboarding(onboardingMapper.toEntity(onboardingRequest), onboardingRequest.getUsers()); + } + + @Override + public Uni onboardingSa(OnboardingSaRequest onboardingRequest) { + return fillUsersAndOnboarding(onboardingMapper.toEntity(onboardingRequest), onboardingRequest.getUsers()); + } + + @Override + public Uni onboardingPa(OnboardingPaRequest onboardingRequest) { + return fillUsersAndOnboarding(onboardingMapper.toEntity(onboardingRequest), onboardingRequest.getUsers()); + } + + public Uni fillUsersAndOnboarding(Onboarding onboarding, List userRequests) { + onboarding.setExpiringDate(OffsetDateTime.now().plusDays(onboardingExpireDate).toLocalDateTime()); + onboarding.setCreatedAt(LocalDateTime.now()); + onboarding.setWorkflowType(getWorkflowType(onboarding)); + onboarding.setStatus(OnboardingStatus.REQUEST); + + return Panache.withTransaction(() -> Onboarding.persist(onboarding).replaceWith(onboarding) + .onItem().transformToUni(onboardingPersisted -> checkRoleAndRetrieveUsers(userRequests, onboardingPersisted.id.toHexString()) + .onItem().invoke(onboardingPersisted::setUsers).replaceWith(onboardingPersisted)) + .onItem().transformToUni(this::checkProductAndReturnOnboarding) + .onItem().transformToUni(this::addParentDescritpionForAooOrUo) + .onItem().transformToUni(this::persistAndStartOrchestrationOnboarding) + .onItem().transform(onboardingMapper::toResponse)); + } + + private Uni addParentDescritpionForAooOrUo(Onboarding onboarding) { + if (InstitutionType.PA == onboarding.getInstitution().getInstitutionType()) { + if (InstitutionPaSubunitType.AOO == onboarding.getInstitution().getSubunitType()) { + return addParentDescriptionForAOO(onboarding); + } else if (InstitutionPaSubunitType.UO == onboarding.getInstitution().getSubunitType()) { + return addParentDescriptionForUO(onboarding); + } + } + return Uni.createFrom().item(onboarding); + } + + private Uni addParentDescriptionForUO(Onboarding onboarding) { + return uoApi.findByUnicodeUsingGET1(onboarding.getInstitution().getSubunitCode(), null) + .onItem().invoke(uoResource -> onboarding.getInstitution().setParentDescription(uoResource.getDenominazioneEnte())) + .onFailure(WebApplicationException.class).recoverWithUni(ex -> ((WebApplicationException) ex).getResponse().getStatus() == 404 + ? Uni.createFrom().failure(new ResourceNotFoundException(String.format(UO_NOT_FOUND.getMessage(), onboarding.getInstitution().getSubunitCode()))) + : Uni.createFrom().failure(ex)) + .replaceWith(onboarding); + + } + + private Uni addParentDescriptionForAOO(Onboarding onboarding) { + return aooApi.findByUnicodeUsingGET(onboarding.getInstitution().getSubunitCode(), null) + .onItem().invoke(aooResource -> onboarding.getInstitution().setParentDescription(aooResource.getDenominazioneEnte())) + .onFailure(WebApplicationException.class).recoverWithUni(ex -> ((WebApplicationException) ex).getResponse().getStatus() == 404 + ? Uni.createFrom().failure(new ResourceNotFoundException(String.format(AOO_NOT_FOUND.getMessage(), onboarding.getInstitution().getSubunitCode()))) + : Uni.createFrom().failure(ex)) + .replaceWith(onboarding); + } + + public Uni persistAndStartOrchestrationOnboarding(Onboarding onboarding) { + final List onboardings = new ArrayList<>(); + onboardings.add(onboarding); + + if (Boolean.TRUE.equals(onboardingOrchestrationEnabled)) { + return Onboarding.persistOrUpdate(onboardings) + .onItem().transformToUni(saved -> orchestrationApi.apiStartOnboardingOrchestrationGet(onboarding.getId().toHexString()) + .replaceWith(onboarding)); + } else { + return Onboarding.persistOrUpdate(onboardings) + .replaceWith(onboarding); + } + } + + /** + * Identify which workflow must be trigger during onboarding process. + * Each workflow consist of different activities such as creating contract or sending appropriate mail. + * For more information look at ... + * + * @param onboarding actual onboarding request + * @return WorkflowType + */ + private WorkflowType getWorkflowType(Onboarding onboarding) { + InstitutionType institutionType = onboarding.getInstitution().getInstitutionType(); + if(InstitutionType.PT.equals(institutionType)){ + return WorkflowType.FOR_APPROVE_PT; + } + + if(InstitutionType.PA.equals(institutionType) + || isGspAndProdInterop(institutionType, onboarding.getProductId()) + || InstitutionType.SA.equals(institutionType) + || InstitutionType.AS.equals(institutionType)) { + return WorkflowType.CONTRACT_REGISTRATION; + } + + if(InstitutionType.PG.equals(institutionType)) { + return WorkflowType.CONFIRMATION; + } + + return WorkflowType.FOR_APPROVE; + } + + private boolean isGspAndProdInterop(InstitutionType institutionType, String productId) { + return InstitutionType.GSP == institutionType + && productId.equals(PROD_INTEROP.getValue()); + } + + private Uni product(String productId) { + return Uni.createFrom().item(() -> productService.getProductIsValid(productId)) + .runSubscriptionOn(Infrastructure.getDefaultWorkerPool()); + } + + public Uni checkProductAndReturnOnboarding(Onboarding onboarding) { + + return product(onboarding.getProductId()) + .onFailure().transform(ex -> new OnboardingNotAllowedException(String.format(UNABLE_TO_COMPLETE_THE_ONBOARDING_FOR_INSTITUTION_FOR_PRODUCT_DISMISSED, + onboarding.getInstitution().getTaxCode(), + onboarding.getProductId()), DEFAULT_ERROR.getCode())) + .onItem().transformToUni(product -> { + + /* if PT and product is not delegable, throw an exception */ + if(InstitutionType.PT == onboarding.getInstitution().getInstitutionType() && !product.isDelegable()) { + return Uni.createFrom().failure(new OnboardingNotAllowedException(String.format(ONBOARDING_NOT_ALLOWED_ERROR_MESSAGE_NOT_DELEGABLE, + onboarding.getInstitution().getTaxCode(), + onboarding.getProductId()), DEFAULT_ERROR.getCode())); + } + + validateProductRole(onboarding.getUsers(), Objects.nonNull(product.getParent()) + ? product.getParent().getRoleMappings() + : product.getRoleMappings()); + + return verifyAlreadyOnboardingForProductAndProductParent(onboarding, product); + }); + } + + private Uni verifyAlreadyOnboardingForProductAndProductParent(Onboarding onboarding, Product product) { + String institutionTaxCode = onboarding.getInstitution().getTaxCode(); + String institutionSubunitCode = onboarding.getInstitution().getSubunitCode(); + + return (Objects.nonNull(product.getParent()) + //If product has parent, I must verify if onboarding is present for parent and child + ? checkIfAlreadyOnboardingAndValidateAllowedMap(product.getParentId(), institutionTaxCode, institutionSubunitCode) + .onItem().transformToUni( ignore -> checkIfAlreadyOnboardingAndValidateAllowedMap(product.getId(), institutionTaxCode, institutionSubunitCode)) + //If product is a root, I must only verify if onboarding for root + : checkIfAlreadyOnboardingAndValidateAllowedMap(product.getId(), institutionTaxCode, institutionSubunitCode) + ).replaceWith(onboarding); + } + + private Uni checkIfAlreadyOnboardingAndValidateAllowedMap(String productId, String institutionTaxCode, String institutionSubuniCode) { + + if (!onboardingValidationStrategy.validate(productId, institutionTaxCode)) { + return Uni.createFrom().failure(new OnboardingNotAllowedException(String.format(ONBOARDING_NOT_ALLOWED_ERROR_MESSAGE_TEMPLATE, + institutionTaxCode, + productId), + DEFAULT_ERROR.getCode())); + } + + return onboardingApi.verifyOnboardingInfoUsingHEAD(institutionTaxCode, productId, institutionSubuniCode) + .onItem().failWith(() -> new InvalidRequestException(String.format(UNABLE_TO_COMPLETE_THE_ONBOARDING_FOR_INSTITUTION_ALREADY_ONBOARDED, + institutionTaxCode, productId), + DEFAULT_ERROR.getCode())) + .onFailure(ClientWebApplicationException.class).recoverWithUni(ex -> ((WebApplicationException)ex).getResponse().getStatus() == 404 + ? Uni.createFrom().item(Response.noContent().build()) + : Uni.createFrom().failure(new RuntimeException(ex.getMessage()))) + .replaceWith(Boolean.TRUE); + } + + private void validateProductRole(List users, Map roleMappings) { + try { + if(Objects.isNull(roleMappings) || roleMappings.isEmpty()) + throw new IllegalArgumentException("Role mappings is required"); + users.forEach(userInfo -> { + if(Objects.isNull(roleMappings.get(userInfo.getRole()))) + throw new IllegalArgumentException(String.format(ATLEAST_ONE_PRODUCT_ROLE_REQUIRED, userInfo.getRole())); + if(Objects.isNull((roleMappings.get(userInfo.getRole()).getRoles()))) + throw new IllegalArgumentException(String.format(ATLEAST_ONE_PRODUCT_ROLE_REQUIRED, userInfo.getRole())); + if(roleMappings.get(userInfo.getRole()).getRoles().size() != 1) + throw new IllegalArgumentException(String.format(MORE_THAN_ONE_PRODUCT_ROLE_AVAILABLE, userInfo.getRole())); + userInfo.setProductRole(roleMappings.get(userInfo.getRole()).getRoles().get(0).getCode()); + }); + } catch (IllegalArgumentException e){ + throw new OnboardingNotAllowedException(e.getMessage(), DEFAULT_ERROR.getCode()); + } + } + + public Uni> checkRoleAndRetrieveUsers(List users, String onboardingId) { + + List validRoles = List.of(PartyRole.MANAGER, PartyRole.DELEGATE); + + List usersNotValidRole = users.stream() + .filter(user -> !validRoles.contains(user.getRole())) + .toList(); + if (!usersNotValidRole.isEmpty()) { + String usersNotValidRoleString = usersNotValidRole.stream() + .map(user -> user.getRole().toString()) + .collect(Collectors.joining(",")); + return Uni.createFrom().failure( new InvalidRequestException(String.format(CustomError.ROLES_NOT_ADMITTED_ERROR.getMessage(), usersNotValidRoleString), + CustomError.ROLES_NOT_ADMITTED_ERROR.getCode())); + } + + return Multi.createFrom().iterable(users) + .onItem().transformToUni(user -> userRegistryApi + .searchUsingPOST(USERS_FIELD_LIST, new UserSearchDto().fiscalCode(user.getTaxCode())) + + /* retrieve userId, if found will eventually update some fields */ + .onItem().transformToUni(userResource -> createUpdateUserRequest(user, userResource, onboardingId) + .map(userUpdateRequest -> userRegistryApi.updateUsingPATCH(userResource.getId().toString(), userUpdateRequest) + .replaceWith(userResource.getId())) + .orElse(Uni.createFrom().item(userResource.getId()))) + /* if not found 404, will create new user */ + .onFailure(WebApplicationException.class).recoverWithUni(ex -> ((WebApplicationException)ex).getResponse().getStatus() == 404 + ? userRegistryApi.saveUsingPATCH(createSaveUserDto(user, onboardingId)).onItem().transform(UserId::getId) + : Uni.createFrom().failure(ex)) + .onItem().transform(userResourceId -> User.builder() + .id(userResourceId.toString()) + .role(user.getRole()) + .build()) + ) + .concatenate().collect().asList(); + } + + private SaveUserDto createSaveUserDto(UserRequest model, String onboardingId) { + SaveUserDto resource = new SaveUserDto(); + resource.setFiscalCode(model.getTaxCode()); + resource.setName(new CertifiableFieldResourceOfstring() + .value(model.getName()) + .certification(CertifiableFieldResourceOfstring.CertificationEnum.NONE)); + resource.setFamilyName(new CertifiableFieldResourceOfstring() + .value(model.getSurname()) + .certification(CertifiableFieldResourceOfstring.CertificationEnum.NONE)); + + if (Objects.nonNull(onboardingId)) { + WorkContactResource contact = new WorkContactResource(); + contact.setEmail(new CertifiableFieldResourceOfstring() + .value(model.getEmail()) + .certification(CertifiableFieldResourceOfstring.CertificationEnum.NONE)); + resource.setWorkContacts(Map.of(workContactsKey.apply(onboardingId), contact)); + } + return resource; + } + + protected static Optional createUpdateUserRequest(UserRequest user, UserResource foundUser, String onboardingId) { + Optional mutableUserFieldsDto = Optional.empty(); + if (isFieldToUpdate(foundUser.getName(), user.getName())) { + MutableUserFieldsDto dto = new MutableUserFieldsDto(); + dto.setName(new CertifiableFieldResourceOfstring() + .value(user.getName()) + .certification(CertifiableFieldResourceOfstring.CertificationEnum.NONE)); + mutableUserFieldsDto = Optional.of(dto); + } + if (isFieldToUpdate(foundUser.getFamilyName(), user.getSurname())) { + MutableUserFieldsDto dto = mutableUserFieldsDto.orElseGet(MutableUserFieldsDto::new); + dto.setFamilyName(new CertifiableFieldResourceOfstring() + .value(user.getSurname()) + .certification(CertifiableFieldResourceOfstring.CertificationEnum.NONE)); + mutableUserFieldsDto = Optional.of(dto); + } + + if (foundUser.getWorkContacts() == null + || !foundUser.getWorkContacts().containsKey(onboardingId) + || isFieldToUpdate(foundUser.getWorkContacts().get(onboardingId).getEmail(), user.getEmail())) { + MutableUserFieldsDto dto = mutableUserFieldsDto.orElseGet(MutableUserFieldsDto::new); + final WorkContactResource workContact = new WorkContactResource(); + workContact.setEmail(new CertifiableFieldResourceOfstring() + .value(user.getEmail()) + .certification(CertifiableFieldResourceOfstring.CertificationEnum.NONE)); + dto.setWorkContacts(Map.of(workContactsKey.apply(onboardingId), workContact)); + mutableUserFieldsDto = Optional.of(dto); + } + return mutableUserFieldsDto; + } + + private static boolean isFieldToUpdate(CertifiableFieldResourceOfstring certifiedField, String value) { + boolean isToUpdate = true; + if (certifiedField != null) { + boolean isNoneCertification = CertifiableFieldResourceOfstring.CertificationEnum.NONE.equals(certifiedField.getCertification()); + boolean isSameValue = isNoneCertification ? certifiedField.getValue().equals(value) : certifiedField.getValue().equalsIgnoreCase(value); + + if (isSameValue) { + isToUpdate = false; + } else if (!isNoneCertification) { + throw new UpdateNotAllowedException(String.format("Update user request not allowed because of value %s", value)); + } + } + return isToUpdate; + } + + @Override + public Uni complete(String onboardingId, File contract) { + + if (Boolean.TRUE.equals(isVerifyEnabled)) { + //Retrieve as Tuple: managers fiscal-code from user registry and contract digest + //At least, verify contract signature using both + Function> verification = onboarding -> Uni.combine().all() + .unis(retrieveOnboardingUserFiscalCodeList(onboarding), retrieveContractDigest(onboardingId)) + .asTuple() + .onItem().transform(inputSignatureVerification -> { + signatureService.verifySignature(contract, + inputSignatureVerification.getItem2(), + inputSignatureVerification.getItem1()); + return onboarding; + }); + + return complete(onboardingId, contract, verification); + } else { + return completeWithoutSignatureVerification(onboardingId, contract); + } + } + + @Override + public Uni completeWithoutSignatureVerification(String onboardingId, File contract) { + Function> verification = ignored -> Uni.createFrom().item(ignored); + return complete(onboardingId, contract, verification); + } + + private Uni complete(String onboardingId, File contract, Function> verificationContractSignature) { + + return retrieveOnboardingAndCheckIfExpired(onboardingId) + .onItem().transformToUni(verificationContractSignature::apply) + //Fail if onboarding exists for a product + .onItem().transformToUni(onboarding -> product(onboarding.getProductId()) + .onItem().transformToUni(product -> verifyAlreadyOnboardingForProductAndProductParent(onboarding, product)) + ) + //Upload contract on storage + .onItem().transformToUni(onboarding -> uploadSignedContractAndUpdateToken(onboardingId, contract) + .map(ignore -> onboarding)) + // Start async activity if onboardingOrchestrationEnabled is true + .onItem().transformToUni(onboarding -> onboardingOrchestrationEnabled + ? orchestrationApi.apiStartOnboardingCompletionOrchestrationGet(onboarding.getId().toHexString()) + .map(ignore -> onboarding) + : Uni.createFrom().item(onboarding)); + } + + private Uni uploadSignedContractAndUpdateToken(String onboardingId, File contract) { + return retrieveToken(onboardingId) + .onItem().transformToUni(token -> Uni.createFrom().item(Unchecked.supplier(() -> { + final String path = String.format("%s%s", pathContracts, onboardingId); + final String filename = String.format("signed_%s", token.getContractFilename()); + + try { + return azureBlobClient.uploadFile(path, filename, Files.readAllBytes(contract.toPath())); + } catch (IOException e) { + throw new OnboardingNotAllowedException(GENERIC_ERROR.getCode(), + "Error on upload contract for onboarding with id " + onboardingId); + } + })) + .runSubscriptionOn(Infrastructure.getDefaultWorkerPool()) + .onItem().transformToUni(filepath -> Token.update("contractSigned", filepath) + .where("_id", token.getId()) + .replaceWith(filepath)) + ); + } + + + private Uni retrieveOnboardingAndCheckIfExpired(String onboardingId) { + //Retrieve Onboarding if exists + return Onboarding.findByIdOptional(new ObjectId(onboardingId)) + .onItem().transformToUni(opt -> opt + //I must cast to Onboarding because findByIdOptional return a generic ReactiveEntity + .map(onboarding -> (Onboarding) onboarding) + //Check if onboarding is expired + .filter(onboarding -> !isOnboardingExpired(onboarding.getExpiringDate())) + .map(onboarding -> Uni.createFrom().item(onboarding)) + .orElse(Uni.createFrom().failure(new InvalidRequestException(String.format(ONBOARDING_EXPIRED.getMessage(), + onboardingId, ONBOARDING_EXPIRED.getCode()))))); + } + + public static boolean isOnboardingExpired(LocalDateTime dateTime) { + LocalDateTime now = LocalDateTime.now(); + return Objects.nonNull(dateTime) && (now.isEqual(dateTime) || now.isAfter(dateTime)); + } + + + + private Uni retrieveContractDigest(String onboardingId) { + return retrieveToken(onboardingId) + .map(Token::getChecksum); + } + private Uni retrieveToken(String onboardingId) { + return Token.list("onboardingId", onboardingId) + .map(tokens -> tokens.stream().findFirst() + .map(token -> (Token) token) + .orElseThrow()); + } + + private Uni> retrieveOnboardingUserFiscalCodeList(Onboarding onboarding) { + return Multi.createFrom().iterable(onboarding.getUsers().stream() + .filter(user -> PartyRole.MANAGER.equals(user.getRole())) + .map(User::getId) + .toList()) + .onItem().transformToUni(userId -> userRegistryApi.findByIdUsingGET(USERS_FIELD_TAXCODE, userId)) + .merge().collect().asList() + .onItem().transform(usersResource -> usersResource.stream().map(UserResource::getFiscalCode).toList()); + } + + @Override + public Uni onboardingGet(String productId, String taxCode, String status, String from, String to, Integer page, Integer size) { + Document sort = QueryUtils.buildSortDocument(Onboarding.Fields.createdAt.name(), SortEnum.DESC); + Map queryParameter = QueryUtils.createMapForOnboardingQueryParameter(productId, taxCode, status, from, to); + Document query = QueryUtils.buildQuery(queryParameter); + + return Uni.combine().all().unis( + runQuery(query, sort).page(page, size).list(), + runQuery(query, null).count() + ).asTuple() + .map(this::constructOnboardingGetResponse); + } + + private ReactivePanacheQuery runQuery(Document query, Document sort) { + return Onboarding.find(query, sort); + } + + private OnboardingGetResponse constructOnboardingGetResponse(Tuple2, Long> tuple) { + OnboardingGetResponse onboardingGetResponse = new OnboardingGetResponse(); + onboardingGetResponse.setCount(tuple.getItem2()); + onboardingGetResponse.setItems(convertOnboardingListToResponse(tuple.getItem1())); + return onboardingGetResponse; + } + + private List convertOnboardingListToResponse(List item1) { + return item1.stream() + .map(onboardingMapper::toGetResponse) + .toList(); + } + + @Override + public Uni deleteOnboarding(String onboardingId) { + return checkOnboardingIdFormat(onboardingId) + .onItem() + .transformToUni(id -> updateStatus(onboardingId, OnboardingStatus.DELETED)); + } + + /** + * Returns an onboarding record by its ID only if its status is PENDING. + * This feature is crucial for ensuring that the onboarding process can be completed only when + * the onboarding status is appropriately set to PENDING. + * @param onboardingId String + * @return OnboardingGet + */ + @Override + public Uni onboardingPending(String onboardingId) { + return onboardingGet(onboardingId) + .flatMap(onboardingGet -> OnboardingStatus.PENDING.name().equals(onboardingGet.getStatus()) + ? Uni.createFrom().item(onboardingGet) + : Uni.createFrom().failure(new ResourceNotFoundException(String.format("Onboarding with id %s not found or not in PENDING status!",onboardingId)))); + } + + @Override + public Uni onboardingGet(String onboardingId) { + return Onboarding.findByIdOptional(new ObjectId(onboardingId)) + .onItem().transformToUni(opt -> opt + //I must cast to Onboarding because findByIdOptional return a generic ReactiveEntity + .map(onboarding -> (Onboarding) onboarding) + .map(onboardingMapper::toGetResponse) + .map(onboardingGet -> Uni.createFrom().item(onboardingGet)) + .orElse(Uni.createFrom().failure(new ResourceNotFoundException(String.format("Onboarding with id %s not found!",onboardingId))))); + } + + @Override + public Uni onboardingGetWithUserInfo(String onboardingId) { + return onboardingGet(onboardingId) + .flatMap(onboardingGet -> fillOnboardingWithUserInfo(onboardingGet.getUsers(), workContactsKey.apply(onboardingId)) + .replaceWith(onboardingGet)); + } + + private Uni> fillOnboardingWithUserInfo(List users, String workContractId) { + return Multi.createFrom().iterable(users) + .onItem().transformToUni(userResponse -> userRegistryApi.findByIdUsingGET(USERS_FIELD_LIST ,userResponse.getId()) + .onItem().invoke(userResource -> userMapper.fillUserResponse(userResource, userResponse)) + .onItem().invoke(userResource -> Optional.ofNullable(userResource.getWorkContacts()) + .filter(map -> map.containsKey(workContractId)) + .map(map -> map.get(workContractId)) + .filter(workContract -> StringUtils.isNotBlank(workContract.getEmail().getValue())) + .map(workContract -> workContract.getEmail().getValue()) + .ifPresent(userResponse::setEmail)) + .replaceWith(userResponse) + ) + .merge().collect().asList(); + } + + private static Uni updateStatus(String onboardingId, OnboardingStatus onboardingStatus ) { + return Onboarding.update(Onboarding.Fields.status.name(), onboardingStatus) + .where("_id", onboardingId) + .onItem().transformToUni(updateItemCount -> { + if (updateItemCount == 0) { + return Uni.createFrom().failure(new InvalidRequestException(String.format(ONBOARDING_NOT_FOUND_OR_ALREADY_DELETED, onboardingId))); + } + return Uni.createFrom().item(updateItemCount); + }); + } + + private Uni checkOnboardingIdFormat(String onboardingId) { + if (!ObjectId.isValid(onboardingId)) { + return Uni.createFrom().failure(new InvalidRequestException(String.format(INVALID_OBJECTID, onboardingId))); + } + return Uni.createFrom().item(onboardingId); + } +} diff --git a/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/service/SignatureService.java b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/service/SignatureService.java new file mode 100644 index 000000000..28e139290 --- /dev/null +++ b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/service/SignatureService.java @@ -0,0 +1,8 @@ +package it.pagopa.selfcare.onboarding.service; + +import java.io.File; +import java.util.List; + +public interface SignatureService { + void verifySignature(File file, String checksum, List usersTaxCode); +} diff --git a/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/service/SignatureServiceDefault.java b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/service/SignatureServiceDefault.java new file mode 100644 index 000000000..3275d784a --- /dev/null +++ b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/service/SignatureServiceDefault.java @@ -0,0 +1,207 @@ +package it.pagopa.selfcare.onboarding.service; + +import eu.europa.esig.dss.diagnostic.CertificateWrapper; +import eu.europa.esig.dss.enumerations.DigestAlgorithm; +import eu.europa.esig.dss.enumerations.Indication; +import eu.europa.esig.dss.enumerations.SignatureForm; +import eu.europa.esig.dss.model.DSSDocument; +import eu.europa.esig.dss.model.InMemoryDocument; +import eu.europa.esig.dss.service.crl.OnlineCRLSource; +import eu.europa.esig.dss.service.ocsp.OnlineOCSPSource; +import eu.europa.esig.dss.spi.tsl.TrustedListsCertificateSource; +import eu.europa.esig.dss.spi.x509.aia.DefaultAIASource; +import eu.europa.esig.dss.validation.AdvancedSignature; +import eu.europa.esig.dss.validation.CertificateVerifier; +import eu.europa.esig.dss.validation.CommonCertificateVerifier; +import eu.europa.esig.dss.validation.SignedDocumentValidator; +import eu.europa.esig.dss.validation.reports.Reports; +import eu.europa.esig.validationreport.jaxb.SignatureValidationReportType; +import it.pagopa.selfcare.onboarding.exception.InvalidRequestException; +import jakarta.enterprise.context.ApplicationScoped; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; + +import java.io.File; +import java.nio.file.Files; +import java.util.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +import static it.pagopa.selfcare.onboarding.util.GenericError.*; + + +@Slf4j +@ApplicationScoped +public class SignatureServiceDefault implements SignatureService { + + private static final Integer CF_MATCHER_GROUP = 2; + private static final Pattern signatureRegex = Pattern.compile("(TINIT-)(.*)"); + + private final TrustedListsCertificateSource trustedListsCertificateSource; + + public SignatureServiceDefault(TrustedListsCertificateSource trustedListsCertificateSource) { + this.trustedListsCertificateSource = trustedListsCertificateSource; + } + + + public SignedDocumentValidator createDocumentValidator(byte[] bytes) { + + CertificateVerifier certificateVerifier = new CommonCertificateVerifier(); + certificateVerifier.setTrustedCertSources(trustedListsCertificateSource); + certificateVerifier.setAIASource(new DefaultAIASource()); + certificateVerifier.setOcspSource(new OnlineOCSPSource()); + certificateVerifier.setCrlSource(new OnlineCRLSource()); + try { + DSSDocument document = new InMemoryDocument(bytes); + SignedDocumentValidator documentValidator = SignedDocumentValidator.fromDocument(document); + documentValidator.setCertificateVerifier(certificateVerifier); + return documentValidator; + } catch (Exception e) { + log.error("Error message: {}", e.getMessage(), e); + throw new InvalidRequestException(DOCUMENT_VALIDATION_FAIL.getMessage(), DOCUMENT_VALIDATION_FAIL.getCode()); + } + } + + public void isDocumentSigned(SignedDocumentValidator documentValidator) { + if (documentValidator.getSignatures().isEmpty()) { + throw new InvalidRequestException(SIGNATURE_VALIDATION_ERROR.getMessage(), SIGNATURE_VALIDATION_ERROR.getCode()); + } + } + + public void verifyOriginalDocument(SignedDocumentValidator validator) { + List advancedSignatures = validator.getSignatures(); + List dssDocuments = new ArrayList<>(); + if (advancedSignatures != null && !advancedSignatures.isEmpty()) { + for (AdvancedSignature a : advancedSignatures) { + Optional.ofNullable(validator.getOriginalDocuments(a.getId())).ifPresent(dssDocuments::addAll); + } + } + if (dssDocuments.isEmpty()) { + throw new InvalidRequestException(ORIGINAL_DOCUMENT_NOT_FOUND.getMessage(), ORIGINAL_DOCUMENT_NOT_FOUND.getCode()); + } + } + + public Reports validateDocument(SignedDocumentValidator signedDocumentValidator) { + try { + return signedDocumentValidator.validateDocument(); + } catch (Exception e) { + throw new InvalidRequestException(String.format(DOCUMENT_VALIDATION_FAIL.getMessage(), e.getMessage()), DOCUMENT_VALIDATION_FAIL.getCode()); + } + } + + public void verifySignatureForm(SignedDocumentValidator validator) { + + String signatureFormErrors = validator.getSignatures().stream() + .map(AdvancedSignature::getSignatureForm) + .filter(signatureForm -> signatureForm != SignatureForm.CAdES) + .map(SignatureForm::toString) + .collect(Collectors.joining(",")); + + if (!StringUtils.isBlank(signatureFormErrors)) { + throw new InvalidRequestException(String.format(INVALID_SIGNATURE_FORMS.getMessage(), signatureFormErrors), + INVALID_SIGNATURE_FORMS.getCode()); + } + } + + public void verifySignature(Reports reports) { + List signatureValidationReportTypes = new ArrayList<>(); + + if (reports.getEtsiValidationReportJaxb() != null) { + signatureValidationReportTypes = reports.getEtsiValidationReportJaxb().getSignatureValidationReport(); + } + if (signatureValidationReportTypes.isEmpty() + || (!signatureValidationReportTypes.stream().allMatch(s -> s.getSignatureValidationStatus() != null + && Indication.TOTAL_PASSED == s.getSignatureValidationStatus().getMainIndication()))) { + throw new InvalidRequestException(INVALID_DOCUMENT_SIGNATURE.getMessage(), INVALID_DOCUMENT_SIGNATURE.getCode()); + } + } + + public void verifyDigest(SignedDocumentValidator validator, String checksum) { + List advancedSignatures = validator.getSignatures(); + + if (advancedSignatures != null && !advancedSignatures.isEmpty()) { + for (AdvancedSignature a : advancedSignatures) { + + List dssDocuments = validator.getOriginalDocuments(a.getId()); + if (!dssDocuments.stream().map(dssDocument -> dssDocument.getDigest(DigestAlgorithm.SHA256)) + .collect(Collectors.toList()).contains(checksum)) { + throw new InvalidRequestException(INVALID_CONTRACT_DIGEST.getMessage(), INVALID_CONTRACT_DIGEST.getCode()); + } + } + } + + } + + @Override + public void verifySignature(File file, String checksum, List usersTaxCode) { + try { + byte[] byteData = Files.readAllBytes(file.toPath()); + + SignedDocumentValidator validator = createDocumentValidator(byteData); + isDocumentSigned(validator); + verifyOriginalDocument(validator); + Reports reports = validateDocument(validator); + + verifySignatureForm(validator); + verifySignature(reports); + verifyDigest(validator, checksum); + verifyManagerTaxCode(reports, usersTaxCode); + + } catch (InvalidRequestException e) { + throw e; + } catch (Exception e) { + throw new InvalidRequestException(GENERIC_ERROR.getMessage(), GENERIC_ERROR.getCode()); + } + } + + public void verifyManagerTaxCode(Reports reports, List usersTaxCode) { + List signatureTaxCodes = extractSubjectSNCFs(reports); + if (signatureTaxCodes.isEmpty()) { + throw new InvalidRequestException(TAX_CODE_NOT_FOUND_IN_SIGNATURE.getMessage(), TAX_CODE_NOT_FOUND_IN_SIGNATURE.getCode()); + } + + List taxCodes = extractTaxCode(signatureTaxCodes); + + if (taxCodes.isEmpty() || !isSignedByLegal(usersTaxCode, taxCodes)) { + throw new InvalidRequestException(INVALID_SIGNATURE_TAX_CODE.getMessage(), INVALID_SIGNATURE_TAX_CODE.getCode()); + } + + } + + private List extractTaxCode(List signatureTaxCodes) { + List taxCode = new ArrayList<>(); + signatureTaxCodes.forEach(s -> { + Matcher matcher = signatureRegex.matcher(s); + if (matcher.matches()) { + taxCode.add(matcher.group(CF_MATCHER_GROUP)); + } + }); + return taxCode; + } + + private boolean isSignedByLegal(List usersTaxCode, List signatureTaxCodes) { + return !signatureTaxCodes.isEmpty() && !usersTaxCode.isEmpty() + && new HashSet<>(signatureTaxCodes).containsAll(usersTaxCode); + } + + private List extractSubjectSNCFs(Reports reports) { + if (reports.getDiagnosticData() != null && reports.getDiagnosticData().getUsedCertificates() != null) { + List subjectSNCFs = reports.getDiagnosticData().getUsedCertificates() + .stream().map(CertificateWrapper::getSubjectSerialNumber) + .filter(this::serialNumberMatch).collect(Collectors.toList()); + if (!subjectSNCFs.isEmpty()) { + return subjectSNCFs; + } + } + return Collections.emptyList(); + } + + private boolean serialNumberMatch(String s) { + if (!StringUtils.isEmpty(s)) { + return signatureRegex.matcher(s).matches(); + } + return false; + } + +} diff --git a/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/service/strategy/ConfigMapAllowedListOnboardingValidationStrategy.java b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/service/strategy/ConfigMapAllowedListOnboardingValidationStrategy.java new file mode 100644 index 000000000..8fbd8d572 --- /dev/null +++ b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/service/strategy/ConfigMapAllowedListOnboardingValidationStrategy.java @@ -0,0 +1,76 @@ +package it.pagopa.selfcare.onboarding.service.strategy; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import jakarta.enterprise.context.ApplicationScoped; +import lombok.extern.slf4j.Slf4j; +import org.eclipse.microprofile.config.inject.ConfigProperty; + +import java.util.*; + +/** + * It validate the onboarding request based on an allowed-list loaded from a property. + */ +@Slf4j +@ApplicationScoped +public class ConfigMapAllowedListOnboardingValidationStrategy implements OnboardingValidationStrategy { + + /** + * It represent, if present, the institutions and products allowed to be onboarded (i.e. an allowed-list). + * The {@code Map} has as key the product id and as values a list of institution external id allowed for that product + * A {@code *} value means "anything". + * If used, the '*' is the only value allowed for a given key. + */ + private final Optional>> institutionProductsAllowedMap; + + + public ConfigMapAllowedListOnboardingValidationStrategy(@ConfigProperty(name = "onboarding.institutions-allowed-list") Optional institutionProductsAllowedString) throws JsonProcessingException { + log.trace("Initializing {}", ConfigMapAllowedListOnboardingValidationStrategy.class.getSimpleName()); + log.debug("ConfigMapAllowedListOnboardingValidationStrategy institutionProductsAllowedMap = {}", institutionProductsAllowedString); + HashMap> institutionProductsAllowedMap = null; + + if(institutionProductsAllowedString.isPresent()) { + TypeReference>> typeRef = new TypeReference>>() {}; + institutionProductsAllowedMap = new ObjectMapper().readValue(institutionProductsAllowedString.get().replace("'","\""), typeRef); + validateSpecialcharecterUsage(institutionProductsAllowedMap); + } + this.institutionProductsAllowedMap = Optional.ofNullable(institutionProductsAllowedMap); + } + + + private void validateSpecialcharecterUsage(Map> allowedList) { + if (allowedList != null) { + allowedList.forEach((productId, institutionExternalIds) -> { + if (institutionExternalIds.size() > 1 + && institutionExternalIds.stream().anyMatch("*"::equals)) { + throw new IllegalArgumentException(String.format("Invalid configuration: bad using of special character '*' in allowed-list for key '%s'. If used, the '*' is the only value allowed for a given key", + productId)); + } + }); + } + } + + + /** + * If the allowed-list is present and the provided {@code productId} and {@code institutionExternalId} are not in that list, an execption is thrown. + * Otherwise, if the allowed-is is not present, then no validation is applied. + * + * @param productId the product id + * @param institutionExternalId the institution external id + */ + @Override + public boolean validate(String productId, String institutionExternalId) { + log.trace("validate start"); + log.debug("validate productId = {}, institutionExternalId = {}", productId, institutionExternalId); + final boolean valid = institutionProductsAllowedMap.isEmpty() || + Optional.ofNullable(institutionProductsAllowedMap.get().get(productId)) + .map(institutionExternalIds -> institutionExternalIds.contains("*") + || institutionExternalIds.contains(institutionExternalId)) + .orElse(false); + log.debug("validate result = {}", valid); + log.trace("validate end"); + return valid; + } + +} diff --git a/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/service/strategy/OnboardingValidationStrategy.java b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/service/strategy/OnboardingValidationStrategy.java new file mode 100644 index 000000000..bcae9265b --- /dev/null +++ b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/service/strategy/OnboardingValidationStrategy.java @@ -0,0 +1,7 @@ +package it.pagopa.selfcare.onboarding.service.strategy; + +public interface OnboardingValidationStrategy { + + boolean validate(String productId, String institutionExternalId); + +} diff --git a/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/util/GenericError.java b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/util/GenericError.java new file mode 100644 index 000000000..8819a034e --- /dev/null +++ b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/util/GenericError.java @@ -0,0 +1,83 @@ +package it.pagopa.selfcare.onboarding.util; + +public enum GenericError { + + GET_USER_INSTITUTION_RELATIONSHIP_ERROR("0023", "Error while retrieving user relationships"), + GET_INSTITUTION_BY_ID_ERROR("0040", "Error while retrieving institution having id %s"), + GET_INSTITUTION_BY_EXTERNAL_ID_ERROR("0041", "Error while retrieving institution having externalId %s"), + INSTITUTION_MANAGER_ERROR("0042", "Error while retrieving institution having externalId %s"), + INSTITUTION_BILLING_ERROR("0044", "Error while retrieving institution having externalId %s"), + CREATE_INSTITUTION_ERROR("0037", "Error while creating requested institution"), + INSTITUTION_INFOCAMERE_NOTFOUND("0039", "Institution %s not found on INFOCAMERE"), + ONBOARDING_OPERATION_ERROR("0017", "Error while performing onboarding operation"), + CREATE_DELEGATION_ERROR("0027", "Error while creating requested delegation"), + ONBOARDING_VERIFICATION_ERROR("0015", "Error while verifying onboarding"), + GETTING_ONBOARDING_INFO_ERROR("0016", "Error while getting onboarding info"), + GET_PRODUCTS_ERROR("0031", "Error while getting products"), + CONTRACT_PATH_ERROR("0100", "Contract Path is required"), + MANAGER_EMAIL_NOT_FOUND("0101", "Manager email not found"), + VERIFY_TOKEN_FAILED("0041", "Something went wrong trying to verify token"), + + SIGNATURE_NOT_FOUND("002-1007", "No signature found"), + SIGNATURE_VALIDATION_ERROR("002-1004", "The tax code related to signature does not match anyone contained in the relationships"), + ORIGINAL_DOCUMENT_NOT_FOUND("002-1008", "Original document information not found"), + + INSTITUTION_NOT_ONBOARDED("002-1009", "Institution having externalId %s has already onboarded for product %s"), + DOCUMENT_VALIDATION_FAIL("002-1000", "Error trying to validate document, due: %s"), + INVALID_SIGNATURE_FORMS("002-1003", "Only CAdES signature form is admitted. Invalid signatures forms detected: %s"), + INVALIDATE_ONBOARDING_ERROR("0022", "Error while invalidating onboarding"), + CONFIRM_ONBOARDING_ERROR("0021", "Error while confirming onboarding"), + INVALID_DOCUMENT_SIGNATURE("002-1002", "Document signature is invalid"), + INVALID_CONTRACT_DIGEST("002-1001", "Invalid file digest"), + + INVALIDE_SIGNATURE_TAX_CODE_FORMAT("002-1005", "Invalid tax code format found in digital signature"), + TAX_CODE_NOT_FOUND_IN_SIGNATURE("002-1006", "No tax code has been found in digital signature"), + INVALID_SIGNATURE_TAX_CODE("002-1004", "The tax code related to signature does not match anyone contained in the relationships"), + UNABLE_TO_DOWNLOAD_FILE("1102", "Unable to download template %s"), + INVALID_SIGNATURE("002-1005", "Signature not valid: "), + ERROR_DURING_SEND_MAIL("0000", "Error during send mail"), + ERROR_DURING_UPLOAD_FILE("0000", "Error during upload file %s"), + + ERROR_DURING_DELETED_FILE("0000", "Error during deleted file %s"), + ERROR_DURING_DOWNLOAD_FILE("0000", "Error during download file %s"), + ERROR_DURING_COMPRESS_FILE("0000", "Error compressing the file %s"), + RETRIEVING_USER_RELATIONSHIP_ERROR("0023", "Error while retrieving user relationships"), + ACTIVATE_RELATIONSHIP_ERROR("0024", "Error while activating relationship"), + SUSPEND_RELATIONSHIP_ERROR("0025", "Error while suspending relationship"), + PUT_INSTITUTION_ERROR("0051", "Error while updating institution"), + ONBOARDING_SUBDELEGATES_ERROR("0019", "Error while onboarding subdelegates"), + ONBOARDING_OPERATORS_ERROR("0020", "Error while onboarding operators"), + ONBOARDING_LEGALS_ERROR("0018", "Error while onboarding legals"), + RETRIEVE_GEO_TAXONOMIES_ERROR("0050", "Error while retrieving institution geographic taxonomy"), + GET_RELATIONSHIP_ERROR("0028", "Error while getting relationship"), + CREATE_PERSON_ERROR("0009", "Error while creating person"), + GET_INSTITUTION_ATTRIBUTES_ERROR("0022", "Error while getting party attributes"), + + ONBOARDING_EXPIRED("0040", "Onboarding with id %s not found or it is expired!"), + GET_INSTITUTION_BY_GEOTAXONOMY_ERROR("0053", "Error while searching institutions related to given geoTaxonomies"), + GET_INSTITUTION_BY_PRODUCTID_ERROR("0053", "Error while searching institutions related to given productId"), + GET_INSTITUTIONS_REQUEST_ERROR("0054", "Invalid request parameters sent. Allowed filters combinations taxCode and subunit or origin and originId"), + + VERIFY_USER_ERROR("0000", "Error while searching institutions related to given productId"), + GET_USER_ERROR("0000", "Error while searching user given UserID"), + GENERIC_ERROR("0000", "Generic Error"); + + + private final String code; + private final String detail; + + + GenericError(String code, String detail) { + this.code = code; + this.detail = detail; + } + + public String getCode() { + return code; + } + + public String getMessage() { + return detail; + } + +} diff --git a/onboarding-ms/src/main/java/it/pagopa/selfcare/util/InstitutionPaSubunitType.java b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/util/InstitutionPaSubunitType.java similarity index 55% rename from onboarding-ms/src/main/java/it/pagopa/selfcare/util/InstitutionPaSubunitType.java rename to apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/util/InstitutionPaSubunitType.java index 472cfd61c..e3af5786f 100644 --- a/onboarding-ms/src/main/java/it/pagopa/selfcare/util/InstitutionPaSubunitType.java +++ b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/util/InstitutionPaSubunitType.java @@ -1,4 +1,4 @@ -package it.pagopa.selfcare.util; +package it.pagopa.selfcare.onboarding.util; public enum InstitutionPaSubunitType { AOO, UO diff --git a/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/util/QueryUtils.java b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/util/QueryUtils.java new file mode 100644 index 000000000..2c5a15e4d --- /dev/null +++ b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/util/QueryUtils.java @@ -0,0 +1,79 @@ +package it.pagopa.selfcare.onboarding.util; + +import com.mongodb.MongoClientSettings; +import com.mongodb.client.model.Filters; +import com.mongodb.client.model.Sorts; +import it.pagopa.selfcare.onboarding.entity.Onboarding; +import lombok.AccessLevel; +import lombok.RequiredArgsConstructor; +import org.apache.commons.lang3.StringUtils; +import org.bson.BsonDocument; +import org.bson.BsonDocumentReader; +import org.bson.Document; +import org.bson.codecs.DecoderContext; +import org.bson.codecs.DocumentCodec; +import org.bson.conversions.Bson; + +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +@RequiredArgsConstructor(access = AccessLevel.NONE) +public class QueryUtils { + + public static Document buildQuery(Map parameters) { + if (!parameters.isEmpty()) { + return bsonToDocument(Filters.and(constructBsonFilter(parameters))); + } else { + return new Document(); + } + } + + /** + * The constructBsonFilter function takes a Map of parameters and returns a List of Bson objects. + * The function iterates over the entries in the parameter map, and for each entry it creates + * either an equality filter or a range filter depending on whether the key is "from" or "to". + */ + private static List constructBsonFilter(Map parameters) { + return parameters.entrySet().stream() + .map(entry -> { + if (StringUtils.equalsIgnoreCase(entry.getKey(), "from")) { + return Filters.gte(Onboarding.Fields.createdAt.name(), LocalDate.parse(entry.getValue(), DateTimeFormatter.ISO_LOCAL_DATE)); + } else if (StringUtils.equalsIgnoreCase(entry.getKey(), "to")) { + return Filters.lt(Onboarding.Fields.createdAt.name(), LocalDate.parse(entry.getValue(), DateTimeFormatter.ISO_LOCAL_DATE).plusDays(1)); + } + return Filters.eq(entry.getKey(), entry.getValue()); + }).toList(); + } + + private static Document bsonToDocument(Bson bson) { + BsonDocument bsonDocument = bson.toBsonDocument(BsonDocument.class, MongoClientSettings.getDefaultCodecRegistry()); + DocumentCodec codec = new DocumentCodec(); + DecoderContext decoderContext = DecoderContext.builder().build(); + return codec.decode(new BsonDocumentReader(bsonDocument), decoderContext); + } + + /** + * The createMapForOnboardingQueryParameter function creates a map of query parameters for the Onboarding Collection. + */ + public static Map createMapForOnboardingQueryParameter(String productId, String taxCode, String status, String from, String to) { + Map queryParameterMap = new HashMap<>(); + Optional.ofNullable(productId).ifPresent(value -> queryParameterMap.put("productId", value)); + Optional.ofNullable(taxCode).ifPresent(value -> queryParameterMap.put("institution.taxCode", value)); + Optional.ofNullable(status).ifPresent(value -> queryParameterMap.put("status", value)); + Optional.ofNullable(from).ifPresent(value -> queryParameterMap.put("from", value)); + Optional.ofNullable(to).ifPresent(value -> queryParameterMap.put("to", value)); + return queryParameterMap; + } + + public static Document buildSortDocument(String field, SortEnum order) { + if(SortEnum.ASC == order) { + return bsonToDocument(Sorts.ascending(field)); + }else{ + return bsonToDocument(Sorts.descending(field)); + } + } +} diff --git a/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/util/SortEnum.java b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/util/SortEnum.java new file mode 100644 index 000000000..0a6484547 --- /dev/null +++ b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/util/SortEnum.java @@ -0,0 +1,6 @@ +package it.pagopa.selfcare.onboarding.util; + +public enum SortEnum { + ASC, + DESC +} diff --git a/apps/onboarding-ms/src/main/openapi/core.json b/apps/onboarding-ms/src/main/openapi/core.json new file mode 100644 index 000000000..7898a76aa --- /dev/null +++ b/apps/onboarding-ms/src/main/openapi/core.json @@ -0,0 +1,7454 @@ +{ + "openapi" : "3.0.3", + "info" : { + "title" : "selc-ms-core", + "version" : "1.0-SNAPSHOT" + }, + "servers" : [ { + "url" : "{url}:{port}{basePath}", + "variables" : { + "url" : { + "default" : "http://localhost" + }, + "port" : { + "default" : "80" + }, + "basePath" : { + "default" : "" + } + } + } ], + "tags" : [ { + "name" : "Delegation", + "description" : "Delegation Controller" + }, { + "name" : "External", + "description" : "External Controller" + }, { + "name" : "Institution", + "description" : "Institution Controller" + }, { + "name" : "Management", + "description" : "Management Controller" + }, { + "name" : "Migration", + "description" : "Crud Controller" + }, { + "name" : "Onboarding", + "description" : "Onboarding Controller" + }, { + "name" : "Persons", + "description" : "User Controller" + }, { + "name" : "Token", + "description" : "Token Controller" + } ], + "paths" : { + "/migration/institution" : { + "post" : { + "tags" : [ "Migration" ], + "summary" : "${swagger.mscore.migration.save.institution}", + "description" : "${swagger.mscore.migration.save.institution}", + "operationId" : "createInstitutionUsingPOST", + "requestBody" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/MigrationInstitution" + } + } + } + }, + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/Institution" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "409" : { + "description" : "Conflict", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/migration/institution/{id}" : { + "get" : { + "tags" : [ "Migration" ], + "summary" : "${swagger.mscore.migration.findbyid.institution}", + "description" : "${swagger.mscore.migration.findbyid.institution}", + "operationId" : "findInstitutionByIdUsingGET", + "parameters" : [ { + "name" : "id", + "in" : "path", + "description" : "id", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/Institution" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + }, + "delete" : { + "tags" : [ "Migration" ], + "summary" : "${swagger.mscore.migration.delete.institution}", + "description" : "${swagger.mscore.migration.delete.institution}", + "operationId" : "deleteInstitutionUsingDELETE", + "parameters" : [ { + "name" : "id", + "in" : "path", + "description" : "id", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "204" : { + "description" : "No Content", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/Institution" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "409" : { + "description" : "Conflict", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/migration/institutions" : { + "get" : { + "tags" : [ "Migration" ], + "summary" : "${swagger.mscore.migration.find.institution}", + "description" : "${swagger.mscore.migration.find.institution}", + "operationId" : "findInstitutionsUsingGET", + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "application/json" : { + "schema" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/Institution" + } + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/migration/token" : { + "post" : { + "tags" : [ "Migration" ], + "summary" : "${swagger.mscore.migration.save.token}", + "description" : "${swagger.mscore.migration.save.token}", + "operationId" : "createTokenUsingPOST", + "requestBody" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/MigrationToken" + } + } + } + }, + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/Token" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "409" : { + "description" : "Conflict", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/migration/token/{id}" : { + "get" : { + "tags" : [ "Migration" ], + "summary" : "${swagger.mscore.migration.findbyid.token}", + "description" : "${swagger.mscore.migration.findbyid.token}", + "operationId" : "findTokenByIdUsingGET", + "parameters" : [ { + "name" : "id", + "in" : "path", + "description" : "id", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/Token" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + }, + "delete" : { + "tags" : [ "Migration" ], + "summary" : "${swagger.mscore.migration.delete.token}", + "description" : "${swagger.mscore.migration.delete.token}", + "operationId" : "deleteTokenUsingDELETE", + "parameters" : [ { + "name" : "id", + "in" : "path", + "description" : "id", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "204" : { + "description" : "No Content", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/Token" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "409" : { + "description" : "Conflict", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/migration/tokens" : { + "get" : { + "tags" : [ "Migration" ], + "summary" : "${swagger.mscore.migration.find.token}", + "description" : "${swagger.mscore.migration.find.token}", + "operationId" : "findTokensUsingGET", + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "application/json" : { + "schema" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/Token" + } + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/migration/user" : { + "post" : { + "tags" : [ "Migration" ], + "summary" : "${swagger.mscore.migration.save.user}", + "description" : "${swagger.mscore.migration.save.user}", + "operationId" : "createUserUsingPOST", + "requestBody" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/MigrationOnboardedUser" + } + } + } + }, + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/OnboardedUser" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "409" : { + "description" : "Conflict", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/migration/user/{id}" : { + "get" : { + "tags" : [ "Migration" ], + "summary" : "${swagger.mscore.migration.findbyid.user}", + "description" : "${swagger.mscore.migration.findbyid.user}", + "operationId" : "findUserByIdUsingGET", + "parameters" : [ { + "name" : "id", + "in" : "path", + "description" : "id", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/OnboardedUser" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + }, + "delete" : { + "tags" : [ "Migration" ], + "summary" : "${swagger.mscore.migration.delete.user}", + "description" : "${swagger.mscore.migration.delete.user}", + "operationId" : "deleteUserUsingDELETE", + "parameters" : [ { + "name" : "id", + "in" : "path", + "description" : "id", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "204" : { + "description" : "No Content", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/OnboardedUser" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "409" : { + "description" : "Conflict", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/migration/users" : { + "get" : { + "tags" : [ "Migration" ], + "summary" : "${swagger.mscore.migration.find.token}", + "description" : "${swagger.mscore.migration.find.token}", + "operationId" : "findUsersUsingGET", + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "application/json" : { + "schema" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/OnboardedUser" + } + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/delegations" : { + "get" : { + "tags" : [ "Delegation" ], + "summary" : "Retrieve institution's delegations", + "description" : "Retrieve institution's delegations", + "operationId" : "getDelegationsUsingGET", + "parameters" : [ { + "name" : "institutionId", + "in" : "query", + "description" : "The internal identifier of the institution", + "required" : false, + "style" : "form", + "schema" : { + "type" : "string" + } + }, { + "name" : "brokerId", + "in" : "query", + "description" : "The internal identifier of the institution", + "required" : false, + "style" : "form", + "schema" : { + "type" : "string" + } + }, { + "name" : "productId", + "in" : "query", + "description" : "Product's unique identifier", + "required" : false, + "style" : "form", + "schema" : { + "type" : "string" + } + }, { + "name" : "mode", + "in" : "query", + "description" : "Mode (full or normal) to retreieve institution's delegations", + "required" : false, + "style" : "form", + "schema" : { + "type" : "string", + "enum" : [ "FULL", "NORMAL" ] + } + } ], + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "application/json" : { + "schema" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/DelegationResponse" + } + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + }, + "post" : { + "tags" : [ "Delegation" ], + "summary" : "Create an association between institution id and technical partner", + "description" : "Create an association between institution id and technical partner", + "operationId" : "createDelegationUsingPOST", + "requestBody" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/DelegationRequest" + } + } + } + }, + "responses" : { + "201" : { + "description" : "Created", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/DelegationResponse" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "409" : { + "description" : "Conflict", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/external/institutions" : { + "get" : { + "tags" : [ "External" ], + "summary" : "Gets the corresponding institution using internal institution id", + "description" : "Gets the corresponding institution using internal institution id", + "operationId" : "retrieveInstitutionByIdsUsingGET", + "parameters" : [ { + "name" : "ids", + "in" : "query", + "description" : "List of Institution to onboard", + "required" : true, + "style" : "form", + "explode" : true, + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "application/json" : { + "schema" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/InstitutionResponse" + } + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/external/institutions/pn-pg" : { + "post" : { + "tags" : [ "External" ], + "summary" : "create an institution (PG) using external institution id fetching data from info-camere", + "description" : "create an institution (PG) using external institution id fetching data from info-camere", + "operationId" : "createPnPgInstitutionUsingPOST", + "requestBody" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/CreatePnPgInstitutionRequest" + } + } + } + }, + "responses" : { + "201" : { + "description" : "Created", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/InstitutionPnPgResponse" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "409" : { + "description" : "Conflict", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/external/institutions/{externalId}" : { + "get" : { + "tags" : [ "External" ], + "summary" : "Gets institution using external institution id", + "description" : "Gets institution using external institution id", + "operationId" : "getByExternalIdUsingGET", + "parameters" : [ { + "name" : "externalId", + "in" : "path", + "description" : "Institution's unique external identifier", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/InstitutionResponse" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/external/institutions/{externalId}/geotaxonomies" : { + "get" : { + "tags" : [ "External" ], + "summary" : "retrieves the geographic taxonomies related to Institution.", + "description" : "retrieves the geographic taxonomies related to Institution.", + "operationId" : "retrieveInstitutionGeoTaxonomiesByExternalIdUsingGET", + "parameters" : [ { + "name" : "externalId", + "in" : "path", + "description" : "Institution's unique external identifier", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "application/json" : { + "schema" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/GeographicTaxonomies" + } + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/external/institutions/{externalId}/products" : { + "get" : { + "tags" : [ "External" ], + "summary" : "retrieves the products related to Institution", + "description" : "retrieves the products related to Institution", + "operationId" : "retrieveInstitutionProductsByExternalIdUsingGET", + "parameters" : [ { + "name" : "externalId", + "in" : "path", + "description" : "Institution's unique external identifier", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + }, { + "name" : "states", + "in" : "query", + "description" : "states", + "required" : false, + "style" : "form", + "explode" : true, + "schema" : { + "type" : "string", + "enum" : [ "ACTIVE", "DELETED", "PENDING", "REJECTED", "SUSPENDED", "TOBEVALIDATED" ] + } + } ], + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/OnboardedProducts" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/external/institutions/{externalId}/products/{productId}/billing" : { + "get" : { + "tags" : [ "External" ], + "summary" : "retrieves the billing data related to the institution even if the current user is not related to the institution/product", + "description" : "retrieves the billing data related to the institution even if the current user is not related to the institution/product", + "operationId" : "getBillingInstitutionByExternalIdUsingGET", + "parameters" : [ { + "name" : "externalId", + "in" : "path", + "description" : "Institution's unique external identifier", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + }, { + "name" : "productId", + "in" : "path", + "description" : "Product's unique identifier", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/InstitutionBillingResponse" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/external/institutions/{externalId}/products/{productId}/manager" : { + "get" : { + "tags" : [ "External" ], + "summary" : "retrieves the manager related to the institution even if the current user is not related to the institution/product", + "description" : "retrieves the manager related to the institution even if the current user is not related to the institution/product", + "operationId" : "getManagerInstitutionByExternalIdUsingGET", + "parameters" : [ { + "name" : "externalId", + "in" : "path", + "description" : "Institution's unique external identifier", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + }, { + "name" : "productId", + "in" : "path", + "description" : "Product's unique identifier", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/InstitutionManagerResponse" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/external/institutions/{externalId}/relationships" : { + "get" : { + "tags" : [ "External" ], + "summary" : "returns the relationships related to the institution", + "description" : "returns the relationships related to the institution", + "operationId" : "getUserInstitutionRelationshipsByExternalIdUsingGET", + "parameters" : [ { + "name" : "externalId", + "in" : "path", + "description" : "Institution's unique external identifier", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + }, { + "name" : "personId", + "in" : "query", + "description" : "personId", + "required" : false, + "style" : "form", + "schema" : { + "type" : "string" + } + }, { + "name" : "roles", + "in" : "query", + "description" : "roles", + "required" : false, + "style" : "form", + "explode" : true, + "schema" : { + "type" : "string", + "enum" : [ "DELEGATE", "MANAGER", "OPERATOR", "SUB_DELEGATE" ] + } + }, { + "name" : "states", + "in" : "query", + "description" : "states", + "required" : false, + "style" : "form", + "explode" : true, + "schema" : { + "type" : "string", + "enum" : [ "ACTIVE", "DELETED", "PENDING", "REJECTED", "SUSPENDED", "TOBEVALIDATED" ] + } + }, { + "name" : "products", + "in" : "query", + "description" : "products", + "required" : false, + "style" : "form", + "explode" : true, + "schema" : { + "type" : "string" + } + }, { + "name" : "productRoles", + "in" : "query", + "description" : "productRoles", + "required" : false, + "style" : "form", + "explode" : true, + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "application/json" : { + "schema" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/RelationshipResult" + } + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/institutions/" : { + "get" : { + "tags" : [ "Institution" ], + "summary" : "Gets institutions filtering by taxCode and/or subunitCode", + "description" : "Gets institutions filtering by taxCode and/or subunitCode", + "operationId" : "getInstitutionsUsingGET", + "parameters" : [ { + "name" : "taxCode", + "in" : "query", + "description" : "Institution's tax code", + "required" : false, + "style" : "form", + "schema" : { + "type" : "string" + } + }, { + "name" : "subunitCode", + "in" : "query", + "description" : "Institution's subunit code", + "required" : false, + "style" : "form", + "schema" : { + "type" : "string" + } + }, { + "name" : "origin", + "in" : "query", + "description" : "origin", + "required" : false, + "style" : "form", + "schema" : { + "type" : "string" + } + }, { + "name" : "originId", + "in" : "query", + "description" : "originId", + "required" : false, + "style" : "form", + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/InstitutionsResponse" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + }, + "post" : { + "tags" : [ "Institution" ], + "summary" : "create an institution using external institution id without fetching data from party-registry or info-camere", + "description" : "create an institution using external institution id without fetching data from party-registry or info-camere", + "operationId" : "createInstitutionUsingPOST_1", + "requestBody" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/InstitutionRequest" + } + } + } + }, + "responses" : { + "201" : { + "description" : "Created", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/InstitutionResponse" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "409" : { + "description" : "Conflict", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/institutions/from-anac/" : { + "post" : { + "tags" : [ "Institution" ], + "summary" : "${swagger.mscore.institution.create.from-anac}", + "description" : "${swagger.mscore.institution.create.from-anac}", + "operationId" : "createInstitutionFromAnacUsingPOST", + "requestBody" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/InstitutionRequest" + } + } + } + }, + "responses" : { + "201" : { + "description" : "Created", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/InstitutionResponse" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "409" : { + "description" : "Conflict", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/institutions/from-ipa/" : { + "post" : { + "tags" : [ "Institution" ], + "summary" : "create an institution from ipa registry", + "description" : "create an institution from ipa registry", + "operationId" : "createInstitutionFromIpaUsingPOST", + "requestBody" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/InstitutionFromIpaPost" + } + } + } + }, + "responses" : { + "201" : { + "description" : "Created", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/InstitutionResponse" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "409" : { + "description" : "Conflict", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/institutions/insert/{externalId}" : { + "post" : { + "tags" : [ "Institution" ], + "summary" : "create an institution using external institution id without fetching data from party-registry or info-camere", + "description" : "create an institution using external institution id without fetching data from party-registry or info-camere", + "operationId" : "createInstitutionRawUsingPOST", + "parameters" : [ { + "name" : "externalId", + "in" : "path", + "description" : "Institution's unique external identifier", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + } ], + "requestBody" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/InstitutionRequest" + } + } + } + }, + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/InstitutionResponse" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "409" : { + "description" : "Conflict", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "deprecated" : true, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/institutions/onboarded/{productId}" : { + "post" : { + "tags" : [ "Institution" ], + "summary" : "Retrieve list of institution which logged user can onboard", + "description" : "Retrieve list of institution which logged user can onboard", + "operationId" : "getValidInstitutionToOnboardUsingPOST", + "parameters" : [ { + "name" : "productId", + "in" : "path", + "description" : "productId", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + } ], + "requestBody" : { + "content" : { + "application/json" : { + "schema" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/InstitutionToOnboard" + } + } + } + } + }, + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "application/json" : { + "schema" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/InstitutionToOnboard" + } + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "409" : { + "description" : "Conflict", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/institutions/pg" : { + "post" : { + "tags" : [ "Institution" ], + "summary" : "create an institution (PG) using external institution id fetching data from info-camere", + "description" : "create an institution (PG) using external institution id fetching data from info-camere", + "operationId" : "createPgInstitutionUsingPOST", + "requestBody" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/CreatePgInstitutionRequest" + } + } + } + }, + "responses" : { + "201" : { + "description" : "Created", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/InstitutionResponse" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "409" : { + "description" : "Conflict", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/institutions/products/{productId}" : { + "get" : { + "tags" : [ "Institution" ], + "summary" : "Gets institutions filtering onboardings by product id", + "description" : "Gets institutions filtering onboardings by product id", + "operationId" : "findFromProductUsingGET", + "parameters" : [ { + "name" : "productId", + "in" : "path", + "description" : "Product's unique identifier", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + }, { + "name" : "page", + "in" : "query", + "description" : "${swagger.mscore.page.number}", + "required" : false, + "style" : "form", + "schema" : { + "type" : "integer", + "format" : "int32" + } + }, { + "name" : "size", + "in" : "query", + "description" : "${swagger.mscore.page.size}", + "required" : false, + "style" : "form", + "schema" : { + "type" : "integer", + "format" : "int32" + } + } ], + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/InstitutionOnboardingListResponse" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/institutions/{externalId}" : { + "post" : { + "tags" : [ "Institution" ], + "summary" : "create an institution (PA) using external institution id fetching data from party-registry", + "description" : "create an institution (PA) using external institution id fetching data from party-registry", + "operationId" : "createInstitutionByExternalIdUsingPOST", + "parameters" : [ { + "name" : "externalId", + "in" : "path", + "description" : "Institution's unique external identifier", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "201" : { + "description" : "Created", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/InstitutionResponse" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "409" : { + "description" : "Conflict", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "deprecated" : true, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/institutions/{id}" : { + "get" : { + "tags" : [ "Institution" ], + "summary" : "Gets the corresponding institution using internal institution id", + "description" : "Gets the corresponding institution using internal institution id", + "operationId" : "retrieveInstitutionByIdUsingGET", + "parameters" : [ { + "name" : "id", + "in" : "path", + "description" : "The internal identifier of the institution", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/InstitutionResponse" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + }, + "put" : { + "tags" : [ "Institution" ], + "summary" : "update institution data of given institution", + "description" : "update institution data of given institution", + "operationId" : "updateInstitutionUsingPUT", + "parameters" : [ { + "name" : "id", + "in" : "path", + "description" : "The internal identifier of the institution", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + } ], + "requestBody" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/InstitutionPut" + } + } + } + }, + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/InstitutionResponse" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "403" : { + "description" : "Forbidden", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + }, + "head" : { + "tags" : [ "Management" ], + "summary" : "verify if Institution exists for a given ID", + "description" : "verify if Institution exists for a given ID", + "operationId" : "verifyInstitutionUsingHEAD", + "parameters" : [ { + "name" : "id", + "in" : "path", + "description" : "The internal identifier of the institution", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "204" : { + "description" : "No Content" + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "deprecated" : true, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/institutions/{id}/geotaxonomies" : { + "get" : { + "tags" : [ "Institution" ], + "summary" : "retrieves the geographic taxonomies this institution is related to", + "description" : "retrieves the geographic taxonomies this institution is related to", + "operationId" : "retrieveInstitutionGeoTaxonomiesUsingGET", + "parameters" : [ { + "name" : "id", + "in" : "path", + "description" : "The internal identifier of the institution", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "application/json" : { + "schema" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/GeographicTaxonomies" + } + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/institutions/{id}/products" : { + "get" : { + "tags" : [ "Institution" ], + "summary" : "retrieves the insistitution's related products.", + "description" : "retrieves the insistitution's related products.", + "operationId" : "retrieveInstitutionProductsUsingGET", + "parameters" : [ { + "name" : "id", + "in" : "path", + "description" : "The internal identifier of the institution", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + }, { + "name" : "states", + "in" : "query", + "description" : "List of Relationship state for filter products", + "required" : false, + "style" : "form", + "explode" : true, + "schema" : { + "type" : "string", + "enum" : [ "ACTIVE", "DELETED", "PENDING", "REJECTED", "SUSPENDED", "TOBEVALIDATED" ] + } + } ], + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/OnboardedProducts" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/institutions/{id}/relationships" : { + "get" : { + "tags" : [ "Institution" ], + "summary" : "returns the relationships related to the institution", + "description" : "returns the relationships related to the institution", + "operationId" : "getUserInstitutionRelationshipsUsingGET", + "parameters" : [ { + "name" : "id", + "in" : "path", + "description" : "The internal identifier of the institution", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + }, { + "name" : "personId", + "in" : "query", + "description" : "personId", + "required" : false, + "style" : "form", + "schema" : { + "type" : "string" + } + }, { + "name" : "roles", + "in" : "query", + "description" : "roles", + "required" : false, + "style" : "form", + "explode" : true, + "schema" : { + "type" : "string", + "enum" : [ "DELEGATE", "MANAGER", "OPERATOR", "SUB_DELEGATE" ] + } + }, { + "name" : "states", + "in" : "query", + "description" : "states", + "required" : false, + "style" : "form", + "explode" : true, + "schema" : { + "type" : "string", + "enum" : [ "ACTIVE", "DELETED", "PENDING", "REJECTED", "SUSPENDED", "TOBEVALIDATED" ] + } + }, { + "name" : "products", + "in" : "query", + "description" : "products", + "required" : false, + "style" : "form", + "explode" : true, + "schema" : { + "type" : "string" + } + }, { + "name" : "productRoles", + "in" : "query", + "description" : "productRoles", + "required" : false, + "style" : "form", + "explode" : true, + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "application/json" : { + "schema" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/RelationshipResult" + } + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/institutions/{institutionId}/onboardings" : { + "get" : { + "tags" : [ "Institution" ], + "summary" : "${swagger.mscore.institution.info}", + "description" : "${swagger.mscore.institution.info}", + "operationId" : "getOnboardingsInstitutionUsingGET", + "parameters" : [ { + "name" : "institutionId", + "in" : "path", + "description" : "The internal identifier of the institution", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + }, { + "name" : "productId", + "in" : "query", + "description" : "productId", + "required" : false, + "style" : "form", + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/OnboardingsResponse" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/institutions/{institutionId}/products/{productId}/createdAt" : { + "put" : { + "tags" : [ "Institution" ], + "summary" : "The service updates the createdAt field for the institution-product pair", + "description" : "The service updates the createdAt field for the institution-product pair", + "operationId" : "updateCreatedAtUsingPUT", + "parameters" : [ { + "name" : "institutionId", + "in" : "path", + "description" : "The internal identifier of the institution", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + }, { + "name" : "productId", + "in" : "path", + "description" : "Product's unique identifier", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + }, { + "name" : "createdAt", + "in" : "query", + "description" : "The createdAt date", + "required" : true, + "style" : "form", + "schema" : { + "type" : "string", + "format" : "date-time" + } + } ], + "responses" : { + "200" : { + "description" : "OK" + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "403" : { + "description" : "Forbidden", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/institutions/{institutionId}/users" : { + "get" : { + "tags" : [ "Institution" ], + "summary" : "getInstitutionUsers", + "description" : "Retrieve institution's users", + "operationId" : "getInstitutionUsersUsingGET", + "parameters" : [ { + "name" : "institutionId", + "in" : "path", + "description" : "Institution's unique identifier", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "application/json" : { + "schema" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/UserInfoResponse" + } + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/institutions/{productId}/brokers/{institutionType}" : { + "get" : { + "tags" : [ "Institution" ], + "summary" : "Retrieve institution brokers", + "description" : "${swagger.mscore.institutions.getInstitutionBrokers}", + "operationId" : "getInstitutionBrokersUsingGET", + "parameters" : [ { + "name" : "productId", + "in" : "path", + "description" : "Product's unique identifier", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + }, { + "name" : "institutionType", + "in" : "path", + "description" : "Institution's type", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string", + "enum" : [ "GSP", "PA", "PG", "PSP", "PT", "SA", "SCP" ] + } + } ], + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "application/json" : { + "schema" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/BrokerResponse" + } + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/bulk/institutions" : { + "post" : { + "tags" : [ "Management" ], + "summary" : "Gets the corresponding institution using internal institution id", + "description" : "Gets the corresponding institution using internal institution id", + "operationId" : "retrieveInstitutionByIdsUsingPOST", + "requestBody" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/BulkPartiesSeed" + } + } + } + }, + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "*/*" : { + "schema" : { + "$ref" : "#/components/schemas/BulkInstitutions" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "409" : { + "description" : "Conflict", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/external/institutions/product/{productId}" : { + "get" : { + "tags" : [ "Management" ], + "summary" : "Retrieves Institutions by product ID", + "description" : "Retrieves Institutions by product ID", + "operationId" : "getInstitutionByProductIdUsingGET", + "parameters" : [ { + "name" : "productId", + "in" : "path", + "description" : "Product's unique identifier", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "204" : { + "description" : "No Content", + "content" : { + "*/*" : { + "schema" : { + "$ref" : "#/components/schemas/InstitutionListResponse" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "deprecated" : true, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/institutions/bygeotaxonomies" : { + "get" : { + "tags" : [ "Management" ], + "summary" : "Retrieves a collection of institutions having one or more geographic taxonomies", + "description" : "Retrieves a collection of institutions having one or more geographic taxonomies", + "operationId" : "getInstitutionByGeotaxonomiesUsingGET", + "parameters" : [ { + "name" : "geoTaxonomies", + "in" : "query", + "description" : "Comma separated list of the geographic taxonomies to search", + "required" : true, + "style" : "form", + "schema" : { + "type" : "string" + } + }, { + "name" : "searchMode", + "in" : "query", + "description" : "The search mode to perform, as default 'any'", + "required" : false, + "style" : "form", + "schema" : { + "type" : "string", + "enum" : [ "ALL", "ANY", "EXACT" ] + } + } ], + "responses" : { + "204" : { + "description" : "No Content", + "content" : { + "*/*" : { + "schema" : { + "$ref" : "#/components/schemas/InstitutionListResponse" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "deprecated" : true, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/institutions/{id}/attributes" : { + "get" : { + "tags" : [ "Management" ], + "summary" : "returns the attributes of the identified institution, if any.", + "description" : "returns the attributes of the identified institution, if any.", + "operationId" : "getInstitutionAttributesUsingGET", + "parameters" : [ { + "name" : "id", + "in" : "path", + "description" : "The internal identifier of the institution", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "204" : { + "description" : "No Content", + "content" : { + "*/*" : { + "schema" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/AttributesResponse" + } + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "deprecated" : true, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/management/external/institutions/{externalId}" : { + "get" : { + "tags" : [ "Management" ], + "summary" : "Gets institution using external institution id", + "description" : "Gets institution using external institution id", + "operationId" : "getInstitutionByExternalIdUsingGET", + "parameters" : [ { + "name" : "externalId", + "in" : "path", + "description" : "Institution's unique external identifier", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "204" : { + "description" : "No Content", + "content" : { + "*/*" : { + "schema" : { + "$ref" : "#/components/schemas/InstitutionManagementResponse" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "deprecated" : true, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/management/institutions/{id}" : { + "get" : { + "tags" : [ "Management" ], + "summary" : "Gets the corresponding institution using internal institution id", + "description" : "Gets the corresponding institution using internal institution id", + "operationId" : "getInstitutionByInternalIdUsingGET", + "parameters" : [ { + "name" : "id", + "in" : "path", + "description" : "The internal identifier of the institution", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "204" : { + "description" : "No Content", + "content" : { + "*/*" : { + "schema" : { + "$ref" : "#/components/schemas/InstitutionManagementResponse" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "deprecated" : true, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/persons/{id}" : { + "get" : { + "tags" : [ "Management" ], + "summary" : "Retrieves Person by ID", + "description" : "Retrieves Person by ID", + "operationId" : "getUserUsingGET", + "parameters" : [ { + "name" : "id", + "in" : "path", + "description" : "User's unique identifier (uuid)", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "*/*" : { + "schema" : { + "$ref" : "#/components/schemas/PersonId" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "deprecated" : true, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + }, + "head" : { + "tags" : [ "Management" ], + "summary" : "verify if a Person exists for a given ID", + "description" : "verify if a Person exists for a given ID", + "operationId" : "verifyUserUsingHEAD", + "parameters" : [ { + "name" : "id", + "in" : "path", + "description" : "User's unique identifier (uuid)", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "200" : { + "description" : "OK" + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "deprecated" : true, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/relationships" : { + "get" : { + "tags" : [ "Management" ], + "summary" : "Return a list of relationships", + "description" : "Return a list of relationships", + "operationId" : "getInstitutionRelationshipsUsingGET", + "parameters" : [ { + "name" : "from", + "in" : "query", + "description" : "from", + "required" : false, + "style" : "form", + "schema" : { + "type" : "string" + } + }, { + "name" : "to", + "in" : "query", + "description" : "to", + "required" : false, + "style" : "form", + "schema" : { + "type" : "string" + } + }, { + "name" : "roles", + "in" : "query", + "description" : "roles", + "required" : false, + "style" : "form", + "explode" : true, + "schema" : { + "type" : "string", + "enum" : [ "DELEGATE", "MANAGER", "OPERATOR", "SUB_DELEGATE" ] + } + }, { + "name" : "states", + "in" : "query", + "description" : "states", + "required" : false, + "style" : "form", + "explode" : true, + "schema" : { + "type" : "string", + "enum" : [ "ACTIVE", "DELETED", "PENDING", "REJECTED", "SUSPENDED", "TOBEVALIDATED" ] + } + }, { + "name" : "products", + "in" : "query", + "description" : "products", + "required" : false, + "style" : "form", + "explode" : true, + "schema" : { + "type" : "string" + } + }, { + "name" : "productRoles", + "in" : "query", + "description" : "productRoles", + "required" : false, + "style" : "form", + "explode" : true, + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "204" : { + "description" : "No Content", + "content" : { + "*/*" : { + "schema" : { + "$ref" : "#/components/schemas/RelationshipsManagement" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "deprecated" : true, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/tokens/{tokenId}" : { + "get" : { + "tags" : [ "Management" ], + "summary" : "retrieve a token relationship", + "description" : "retrieve a token relationship", + "operationId" : "getTokenUsingGET", + "parameters" : [ { + "name" : "tokenId", + "in" : "path", + "description" : "contract's unique identifier", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "*/*" : { + "schema" : { + "$ref" : "#/components/schemas/TokenResponse" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "deprecated" : true, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/onboarding/" : { + "head" : { + "tags" : [ "Onboarding" ], + "summary" : "verify if onboardedProduct is already onboarded for institution", + "description" : "verify if onboardedProduct is already onboarded for institution", + "operationId" : "verifyOnboardingInfoUsingHEAD", + "parameters" : [ { + "name" : "taxCode", + "in" : "query", + "description" : "Institution's tax code", + "required" : true, + "style" : "form", + "schema" : { + "type" : "string" + } + }, { + "name" : "subunitCode", + "in" : "query", + "description" : "Institution's subunit code", + "required" : false, + "style" : "form", + "schema" : { + "type" : "string" + } + }, { + "name" : "productId", + "in" : "query", + "description" : "Product's unique identifier", + "required" : true, + "style" : "form", + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "204" : { + "description" : "No Content" + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/onboarding/approve/{tokenId}" : { + "post" : { + "tags" : [ "Onboarding" ], + "summary" : "approve an onboarding reuqest by an operator review", + "description" : "approve an onboarding reuqest by an operator review", + "operationId" : "approveOnboardingUsingPOST", + "parameters" : [ { + "name" : "tokenId", + "in" : "path", + "description" : "contract's unique identifier", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "204" : { + "description" : "No Content" + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "409" : { + "description" : "Conflict", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/onboarding/complete/{tokenId}" : { + "post" : { + "tags" : [ "Onboarding" ], + "summary" : "complete an onboarding request", + "description" : "complete an onboarding request", + "operationId" : "completeOnboardingUsingPOST", + "parameters" : [ { + "name" : "tokenId", + "in" : "path", + "description" : "contract's unique identifier", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + } ], + "requestBody" : { + "content" : { + "multipart/form-data" : { + "schema" : { + "required" : [ "contract" ], + "type" : "object", + "properties" : { + "contract" : { + "type" : "string", + "description" : "contract", + "format" : "binary" + } + } + } + } + } + }, + "responses" : { + "204" : { + "description" : "No Content" + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "409" : { + "description" : "Conflict", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + }, + "delete" : { + "tags" : [ "Onboarding" ], + "summary" : "invalidate an onboarding request", + "description" : "invalidate an onboarding request", + "operationId" : "invalidateOnboardingUsingDELETE", + "parameters" : [ { + "name" : "tokenId", + "in" : "path", + "description" : "contract's unique identifier", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "204" : { + "description" : "No Content" + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "409" : { + "description" : "Conflict", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/onboarding/info" : { + "get" : { + "tags" : [ "Onboarding" ], + "summary" : "returns onboarding info", + "description" : "returns onboarding info", + "operationId" : "onboardingInfoUsingGET", + "parameters" : [ { + "name" : "institutionId", + "in" : "query", + "description" : "The internal identifier of the institution", + "required" : false, + "style" : "form", + "schema" : { + "type" : "string" + } + }, { + "name" : "institutionExternalId", + "in" : "query", + "description" : "Institution's unique external identifier", + "required" : false, + "style" : "form", + "schema" : { + "type" : "string" + } + }, { + "name" : "states", + "in" : "query", + "description" : "List of Relationship state for filter products", + "required" : false, + "style" : "form", + "explode" : true, + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "*/*" : { + "schema" : { + "$ref" : "#/components/schemas/OnboardingInfoResponse" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/onboarding/institution" : { + "post" : { + "tags" : [ "Onboarding" ], + "summary" : "create a new Token (contract), and update institution and users data", + "description" : "create a new Token (contract), and update institution and users data", + "operationId" : "onboardingInstitutionUsingPOST", + "requestBody" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/OnboardingInstitutionRequest" + } + } + } + }, + "responses" : { + "204" : { + "description" : "No Content" + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "409" : { + "description" : "Conflict", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/onboarding/institution/complete" : { + "post" : { + "tags" : [ "Onboarding" ], + "summary" : "update institution and users data without adding a new token", + "description" : "update institution and users data without adding a new token", + "operationId" : "onboardingInstitutionCompleteUsingPOST", + "requestBody" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/OnboardingInstitutionRequest" + } + } + } + }, + "responses" : { + "204" : { + "description" : "No Content" + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "409" : { + "description" : "Conflict", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/onboarding/institution/{externalId}/products/{productId}" : { + "head" : { + "tags" : [ "Onboarding" ], + "summary" : "verify if onboardedProduct is already onboarded for institution", + "description" : "verify if onboardedProduct is already onboarded for institution", + "operationId" : "verifyOnboardingInfoUsingHEAD_1", + "parameters" : [ { + "name" : "externalId", + "in" : "path", + "description" : "Institution's unique external identifier", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + }, { + "name" : "productId", + "in" : "path", + "description" : "Product's unique identifier", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "204" : { + "description" : "No Content" + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/onboarding/legals" : { + "post" : { + "tags" : [ "Onboarding" ], + "summary" : "performs legals onboarding on an already existing institution", + "description" : "performs legals onboarding on an already existing institution", + "operationId" : "onboardingInstitutionLegalsUsingPOST", + "requestBody" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/OnboardingInstitutionLegalsRequest" + } + } + } + }, + "responses" : { + "204" : { + "description" : "No Content" + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "409" : { + "description" : "Conflict", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/onboarding/operators" : { + "post" : { + "tags" : [ "Onboarding" ], + "summary" : "performs operators onboarding on an already existing institution", + "description" : "performs operators onboarding on an already existing institution", + "operationId" : "onboardingInstitutionOperatorsUsingPOST", + "requestBody" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/OnboardingInstitutionOperatorsRequest" + } + } + } + }, + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "*/*" : { + "schema" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/RelationshipResult" + } + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "409" : { + "description" : "Conflict", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/onboarding/reject/{tokenId}" : { + "delete" : { + "tags" : [ "Onboarding" ], + "summary" : "invalidate an onboarding request by an operator review", + "description" : "invalidate an onboarding request by an operator review", + "operationId" : "onboardingRejectUsingDELETE", + "parameters" : [ { + "name" : "tokenId", + "in" : "path", + "description" : "contract's unique identifier", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "204" : { + "description" : "No Content" + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "409" : { + "description" : "Conflict", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/onboarding/relationship/{relationshipId}/document" : { + "get" : { + "tags" : [ "Onboarding" ], + "summary" : "retrieve the contractDocument related to a relationship", + "description" : "retrieve the contractDocument related to a relationship", + "operationId" : "getOnboardingDocumentUsingGET", + "parameters" : [ { + "name" : "relationshipId", + "in" : "path", + "description" : "UserBinding's unique identifier", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "*/*" : { + "schema" : { + "type" : "string", + "format" : "byte" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/onboarding/subdelegates" : { + "post" : { + "tags" : [ "Onboarding" ], + "summary" : "performs subdelegates onboarding on an already existing institution", + "description" : "performs subdelegates onboarding on an already existing institution", + "operationId" : "onboardingInstitutionSubDelegateUsingPOST", + "requestBody" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/OnboardingInstitutionOperatorsRequest" + } + } + } + }, + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "*/*" : { + "schema" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/RelationshipResult" + } + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "409" : { + "description" : "Conflict", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/onboarding/{tokenId}/consume" : { + "post" : { + "tags" : [ "Onboarding" ], + "summary" : "Consume token onboarding request without digest verification ", + "description" : "Consume token onboarding request without digest verification ", + "operationId" : "consumeTokenUsingPOST", + "parameters" : [ { + "name" : "tokenId", + "in" : "path", + "description" : "contract's unique identifier", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + } ], + "requestBody" : { + "content" : { + "multipart/form-data" : { + "schema" : { + "required" : [ "contract" ], + "type" : "object", + "properties" : { + "contract" : { + "type" : "string", + "description" : "contract", + "format" : "binary" + } + } + } + } + } + }, + "responses" : { + "204" : { + "description" : "No Content" + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "409" : { + "description" : "Conflict", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/tokens/products/{productId}" : { + "get" : { + "tags" : [ "Token" ], + "summary" : "${swagger.mscore.tokens.findFromProduct}", + "description" : "${swagger.mscore.tokens.findFromProduct}", + "operationId" : "findFromProductUsingGET_1", + "parameters" : [ { + "name" : "productId", + "in" : "path", + "description" : "Product's unique identifier", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + }, { + "name" : "page", + "in" : "query", + "description" : "${swagger.mscore.page.number}", + "required" : false, + "style" : "form", + "schema" : { + "type" : "integer", + "format" : "int32" + } + }, { + "name" : "size", + "in" : "query", + "description" : "${swagger.mscore.page.size}", + "required" : false, + "style" : "form", + "schema" : { + "type" : "integer", + "format" : "int32" + } + } ], + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "*/*" : { + "schema" : { + "$ref" : "#/components/schemas/TokenListResponse" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/tokens/token" : { + "get" : { + "tags" : [ "Token" ], + "summary" : "Retrieve token given the institution's and product ids", + "operationId" : "getTokenUsingGET_1", + "parameters" : [ { + "name" : "institutionId", + "in" : "query", + "description" : "Institution's unique internal identifier", + "required" : true, + "style" : "form", + "schema" : { + "type" : "string" + } + }, { + "name" : "productId", + "in" : "query", + "description" : "Product's unique identifier", + "required" : true, + "style" : "form", + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "*/*" : { + "schema" : { + "$ref" : "#/components/schemas/TokenResource" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/tokens/{tokenId}/verify" : { + "post" : { + "tags" : [ "Token" ], + "summary" : "Verify if the token is already consumed", + "description" : "Verify if the token is already consumed", + "operationId" : "verifyTokenUsingPOST", + "parameters" : [ { + "name" : "tokenId", + "in" : "path", + "description" : "contract's unique identifier", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "*/*" : { + "schema" : { + "$ref" : "#/components/schemas/TokenResponse" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "409" : { + "description" : "Conflict", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/relationships/{relationshipId}" : { + "get" : { + "tags" : [ "Persons" ], + "summary" : "Gets the corresponding relationship", + "description" : "Gets the corresponding relationship", + "operationId" : "getRelationshipUsingGET", + "parameters" : [ { + "name" : "relationshipId", + "in" : "path", + "description" : "UserBinding's unique identifier", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "*/*" : { + "schema" : { + "$ref" : "#/components/schemas/RelationshipResult" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + }, + "delete" : { + "tags" : [ "Persons" ], + "summary" : "Given a relationship identifier, it deletes the corresponding relationship", + "description" : "Given a relationship identifier, it deletes the corresponding relationship", + "operationId" : "deleteRelationshipUsingDELETE", + "parameters" : [ { + "name" : "relationshipId", + "in" : "path", + "description" : "UserBinding's unique identifier", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "204" : { + "description" : "No Content" + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "409" : { + "description" : "Conflict", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/relationships/{relationshipId}/activate" : { + "post" : { + "tags" : [ "Persons" ], + "summary" : "Activate the relationship", + "description" : "Activate the relationship", + "operationId" : "activateRelationshipUsingPOST", + "parameters" : [ { + "name" : "relationshipId", + "in" : "path", + "description" : "UserBinding's unique identifier", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "204" : { + "description" : "No Content" + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "409" : { + "description" : "Conflict", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/relationships/{relationshipId}/suspend" : { + "post" : { + "tags" : [ "Persons" ], + "summary" : "Suspend the relationship", + "description" : "Suspend the relationship", + "operationId" : "suspendRelationshipUsingPOST", + "parameters" : [ { + "name" : "relationshipId", + "in" : "path", + "description" : "UserBinding's unique identifier", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "204" : { + "description" : "No Content" + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "409" : { + "description" : "Conflict", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/users/{id}" : { + "get" : { + "tags" : [ "Persons" ], + "summary" : "Retrieves user given userId and optional ProductId", + "description" : "Retrieves user given userId and optional ProductId", + "operationId" : "getUserInfoUsingGET", + "parameters" : [ { + "name" : "id", + "in" : "path", + "description" : "User's unique identifier", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + }, { + "name" : "productId", + "in" : "query", + "description" : "Product's unique identifier", + "required" : false, + "style" : "form", + "schema" : { + "type" : "string" + } + }, { + "name" : "institutionId", + "in" : "query", + "description" : "The internal identifier of the institution", + "required" : false, + "style" : "form", + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "*/*" : { + "schema" : { + "$ref" : "#/components/schemas/UserResponse" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/users/{id}/update" : { + "post" : { + "tags" : [ "Persons" ], + "summary" : "Service to send notification when user data get's updated", + "description" : "Service to send notification when user data get's updated", + "operationId" : "updateUserUsingPOST", + "parameters" : [ { + "name" : "id", + "in" : "path", + "description" : "User's unique identifier", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + }, { + "name" : "institutionId", + "in" : "query", + "description" : "The internal identifier of the institution", + "required" : true, + "style" : "form", + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "204" : { + "description" : "No Content" + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "409" : { + "description" : "Conflict", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/users/{userId}/institution-products" : { + "get" : { + "tags" : [ "Persons" ], + "summary" : "returns onboarding info", + "description" : "returns onboarding info", + "operationId" : "getInstitutionProductsInfoUsingGET", + "parameters" : [ { + "name" : "userId", + "in" : "path", + "description" : "UserBinding's unique identifier", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + }, { + "name" : "institutionId", + "in" : "query", + "description" : "The internal identifier of the institution", + "required" : false, + "style" : "form", + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "*/*" : { + "schema" : { + "$ref" : "#/components/schemas/OnboardingInfoResponse" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/users/{userId}/institutions/{institutionId}/products/{productId}" : { + "delete" : { + "tags" : [ "Persons" ], + "summary" : "Delete logically the association institution and product", + "description" : "Delete logically the association institution and product", + "operationId" : "deleteProductsUsingDELETE", + "parameters" : [ { + "name" : "userId", + "in" : "path", + "description" : "UserBinding's unique identifier", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + }, { + "name" : "institutionId", + "in" : "path", + "description" : "The internal identifier of the institution", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + }, { + "name" : "productId", + "in" : "path", + "description" : "Product's unique identifier", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "200" : { + "description" : "OK" + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "409" : { + "description" : "Conflict", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/users/{userId}/products" : { + "get" : { + "tags" : [ "Persons" ], + "summary" : "Retrieves products info and role which the user is enabled", + "description" : "Retrieves products info and role which the user is enabled", + "operationId" : "getUserProductsInfoUsingGET", + "parameters" : [ { + "name" : "userId", + "in" : "path", + "description" : "UserBinding's unique identifier", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + }, { + "name" : "institutionId", + "in" : "query", + "description" : "The internal identifier of the institution", + "required" : false, + "style" : "form", + "schema" : { + "type" : "string" + } + }, { + "name" : "states", + "in" : "query", + "description" : "List of Relationship state for filter products", + "required" : false, + "style" : "form", + "explode" : true, + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "*/*" : { + "schema" : { + "$ref" : "#/components/schemas/UserProductsResponse" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + } + }, + "components" : { + "schemas" : { + "Attributes" : { + "title" : "Attributes", + "type" : "object", + "properties" : { + "code" : { + "type" : "string" + }, + "description" : { + "type" : "string" + }, + "origin" : { + "type" : "string" + } + } + }, + "AttributesRequest" : { + "title" : "AttributesRequest", + "type" : "object", + "properties" : { + "code" : { + "type" : "string" + }, + "description" : { + "type" : "string" + }, + "origin" : { + "type" : "string" + } + } + }, + "AttributesResponse" : { + "title" : "AttributesResponse", + "type" : "object", + "properties" : { + "code" : { + "type" : "string" + }, + "description" : { + "type" : "string" + }, + "origin" : { + "type" : "string" + } + } + }, + "Billing" : { + "title" : "Billing", + "type" : "object", + "properties" : { + "publicServices" : { + "type" : "boolean" + }, + "recipientCode" : { + "type" : "string" + }, + "vatNumber" : { + "type" : "string" + } + } + }, + "BillingRequest" : { + "title" : "BillingRequest", + "type" : "object", + "properties" : { + "publicServices" : { + "type" : "boolean" + }, + "recipientCode" : { + "type" : "string" + }, + "vatNumber" : { + "type" : "string" + } + } + }, + "BillingResponse" : { + "title" : "BillingResponse", + "type" : "object", + "properties" : { + "publicServices" : { + "type" : "boolean" + }, + "recipientCode" : { + "type" : "string" + }, + "vatNumber" : { + "type" : "string" + } + } + }, + "BrokerResponse" : { + "title" : "BrokerResponse", + "type" : "object", + "properties" : { + "description" : { + "type" : "string" + }, + "id" : { + "type" : "string" + }, + "numberOfDelegations" : { + "type" : "integer", + "format" : "int32" + } + } + }, + "BulkInstitution" : { + "title" : "BulkInstitution", + "type" : "object", + "properties" : { + "address" : { + "type" : "string" + }, + "attributes" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/AttributesResponse" + } + }, + "description" : { + "type" : "string" + }, + "digitalAddress" : { + "type" : "string" + }, + "externalId" : { + "type" : "string" + }, + "id" : { + "type" : "string" + }, + "institutionType" : { + "type" : "string", + "enum" : [ "GSP", "PA", "PG", "PSP", "PT", "SA", "SCP" ] + }, + "origin" : { + "type" : "string" + }, + "originId" : { + "type" : "string" + }, + "products" : { + "type" : "object", + "additionalProperties" : { + "$ref" : "#/components/schemas/BulkProduct" + } + }, + "taxCode" : { + "type" : "string" + }, + "zipCode" : { + "type" : "string" + } + } + }, + "BulkInstitutions" : { + "title" : "BulkInstitutions", + "type" : "object", + "properties" : { + "found" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/BulkInstitution" + } + }, + "notFound" : { + "type" : "array", + "items" : { + "type" : "string" + } + } + } + }, + "BulkPartiesSeed" : { + "title" : "BulkPartiesSeed", + "type" : "object", + "properties" : { + "partyIdentifiers" : { + "type" : "array", + "items" : { + "type" : "string" + } + } + } + }, + "BulkProduct" : { + "title" : "BulkProduct", + "type" : "object", + "properties" : { + "billing" : { + "$ref" : "#/components/schemas/BillingResponse" + }, + "pricingPlan" : { + "type" : "string" + }, + "product" : { + "type" : "string" + }, + "status" : { + "type" : "string", + "enum" : [ "ACTIVE", "DELETED", "PENDING", "REJECTED", "SUSPENDED", "TOBEVALIDATED" ] + } + } + }, + "BusinessData" : { + "title" : "BusinessData", + "type" : "object", + "properties" : { + "businessRegisterPlace" : { + "type" : "string" + }, + "rea" : { + "type" : "string" + }, + "shareCapital" : { + "type" : "string" + } + } + }, + "Contract" : { + "title" : "Contract", + "type" : "object", + "properties" : { + "path" : { + "type" : "string" + }, + "version" : { + "type" : "string" + } + } + }, + "ContractRequest" : { + "title" : "ContractRequest", + "type" : "object", + "properties" : { + "path" : { + "type" : "string" + }, + "version" : { + "type" : "string" + } + } + }, + "CreatePgInstitutionRequest" : { + "title" : "CreatePgInstitutionRequest", + "type" : "object", + "properties" : { + "description" : { + "type" : "string" + }, + "existsInRegistry" : { + "type" : "boolean" + }, + "taxId" : { + "type" : "string" + } + } + }, + "CreatePnPgInstitutionRequest" : { + "title" : "CreatePnPgInstitutionRequest", + "type" : "object", + "properties" : { + "description" : { + "type" : "string" + }, + "taxId" : { + "type" : "string" + } + } + }, + "DataProtectionOfficer" : { + "title" : "DataProtectionOfficer", + "type" : "object", + "properties" : { + "address" : { + "type" : "string" + }, + "email" : { + "type" : "string" + }, + "pec" : { + "type" : "string" + } + } + }, + "DataProtectionOfficerRequest" : { + "title" : "DataProtectionOfficerRequest", + "type" : "object", + "properties" : { + "address" : { + "type" : "string" + }, + "email" : { + "type" : "string" + }, + "pec" : { + "type" : "string" + } + } + }, + "DataProtectionOfficerResponse" : { + "title" : "DataProtectionOfficerResponse", + "type" : "object", + "properties" : { + "address" : { + "type" : "string" + }, + "email" : { + "type" : "string" + }, + "pec" : { + "type" : "string" + } + } + }, + "DelegationRequest" : { + "title" : "DelegationRequest", + "type" : "object", + "properties" : { + "from" : { + "type" : "string" + }, + "institutionFromName" : { + "type" : "string" + }, + "institutionToName" : { + "type" : "string" + }, + "productId" : { + "type" : "string" + }, + "to" : { + "type" : "string" + }, + "type" : { + "type" : "string", + "enum" : [ "AOO", "PT" ] + } + } + }, + "DelegationResponse" : { + "title" : "DelegationResponse", + "type" : "object", + "properties" : { + "brokerId" : { + "type" : "string" + }, + "brokerName" : { + "type" : "string" + }, + "brokerTaxCode" : { + "type" : "string" + }, + "brokerType" : { + "type" : "string" + }, + "id" : { + "type" : "string" + }, + "institutionId" : { + "type" : "string" + }, + "institutionName" : { + "type" : "string" + }, + "institutionRootName" : { + "type" : "string" + }, + "institutionType" : { + "type" : "string", + "enum" : [ "GSP", "PA", "PG", "PSP", "PT", "SA", "SCP" ] + }, + "productId" : { + "type" : "string" + }, + "taxCode" : { + "type" : "string" + }, + "type" : { + "type" : "string", + "enum" : [ "AOO", "PT" ] + } + } + }, + "GeoTaxonomies" : { + "title" : "GeoTaxonomies", + "type" : "object", + "properties" : { + "code" : { + "type" : "string" + }, + "desc" : { + "type" : "string" + } + } + }, + "GeographicTaxonomies" : { + "title" : "GeographicTaxonomies", + "type" : "object", + "properties" : { + "code" : { + "type" : "string" + }, + "country" : { + "type" : "string" + }, + "country_abbreviation" : { + "type" : "string" + }, + "desc" : { + "type" : "string" + }, + "enabled" : { + "type" : "boolean" + }, + "istat_code" : { + "type" : "string" + }, + "province_abbreviation" : { + "type" : "string" + }, + "province_id" : { + "type" : "string" + }, + "region_id" : { + "type" : "string" + } + } + }, + "Institution" : { + "title" : "Institution", + "type" : "object", + "properties" : { + "address" : { + "type" : "string" + }, + "attributes" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/Attributes" + } + }, + "billing" : { + "$ref" : "#/components/schemas/Billing" + }, + "businessRegisterPlace" : { + "type" : "string" + }, + "createdAt" : { + "type" : "string", + "format" : "date-time" + }, + "dataProtectionOfficer" : { + "$ref" : "#/components/schemas/DataProtectionOfficer" + }, + "description" : { + "type" : "string" + }, + "digitalAddress" : { + "type" : "string" + }, + "externalId" : { + "type" : "string" + }, + "geographicTaxonomies" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/InstitutionGeographicTaxonomies" + } + }, + "id" : { + "type" : "string" + }, + "imported" : { + "type" : "boolean" + }, + "institutionType" : { + "type" : "string", + "enum" : [ "GSP", "PA", "PG", "PSP", "PT", "SA", "SCP" ] + }, + "onboarding" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/Onboarding" + } + }, + "origin" : { + "type" : "string" + }, + "originId" : { + "type" : "string" + }, + "paAttributes" : { + "$ref" : "#/components/schemas/PaAttributes" + }, + "parentDescription" : { + "type" : "string" + }, + "paymentServiceProvider" : { + "$ref" : "#/components/schemas/PaymentServiceProvider" + }, + "rea" : { + "type" : "string" + }, + "rootParentId" : { + "type" : "string" + }, + "shareCapital" : { + "type" : "string" + }, + "subunitCode" : { + "type" : "string" + }, + "subunitType" : { + "type" : "string" + }, + "supportEmail" : { + "type" : "string" + }, + "supportPhone" : { + "type" : "string" + }, + "taxCode" : { + "type" : "string" + }, + "updatedAt" : { + "type" : "string", + "format" : "date-time" + }, + "zipCode" : { + "type" : "string" + } + } + }, + "InstitutionBillingResponse" : { + "title" : "InstitutionBillingResponse", + "type" : "object", + "properties" : { + "address" : { + "type" : "string" + }, + "aooParentCode" : { + "type" : "string" + }, + "billing" : { + "$ref" : "#/components/schemas/BillingResponse" + }, + "description" : { + "type" : "string" + }, + "digitalAddress" : { + "type" : "string" + }, + "externalId" : { + "type" : "string" + }, + "institutionId" : { + "type" : "string" + }, + "institutionType" : { + "type" : "string", + "enum" : [ "GSP", "PA", "PG", "PSP", "PT", "SA", "SCP" ] + }, + "origin" : { + "type" : "string", + "enum" : [ "ADE", "ANAC", "INFOCAMERE", "IPA", "MOCK", "SELC", "UNKNOWN" ] + }, + "originId" : { + "type" : "string" + }, + "pricingPlan" : { + "type" : "string" + }, + "subunitCode" : { + "type" : "string" + }, + "subunitType" : { + "type" : "string" + }, + "taxCode" : { + "type" : "string" + }, + "zipCode" : { + "type" : "string" + } + } + }, + "InstitutionFromIpaPost" : { + "title" : "InstitutionFromIpaPost", + "type" : "object", + "properties" : { + "subunitCode" : { + "type" : "string" + }, + "subunitType" : { + "type" : "string", + "enum" : [ "AOO", "UO" ] + }, + "taxCode" : { + "type" : "string" + } + } + }, + "InstitutionGeographicTaxonomies" : { + "title" : "InstitutionGeographicTaxonomies", + "type" : "object", + "properties" : { + "code" : { + "type" : "string" + }, + "desc" : { + "type" : "string" + } + } + }, + "InstitutionListResponse" : { + "title" : "InstitutionListResponse", + "type" : "object", + "properties" : { + "items" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/InstitutionManagementResponse" + } + } + } + }, + "InstitutionManagementResponse" : { + "title" : "InstitutionManagementResponse", + "type" : "object", + "properties" : { + "address" : { + "type" : "string" + }, + "aooParentCode" : { + "type" : "string" + }, + "attributes" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/AttributesResponse" + } + }, + "businessRegisterPlace" : { + "type" : "string" + }, + "createdAt" : { + "type" : "string", + "format" : "date-time" + }, + "dataProtectionOfficer" : { + "$ref" : "#/components/schemas/DataProtectionOfficerResponse" + }, + "description" : { + "type" : "string" + }, + "digitalAddress" : { + "type" : "string" + }, + "externalId" : { + "type" : "string" + }, + "geographicTaxonomies" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/GeoTaxonomies" + } + }, + "id" : { + "type" : "string" + }, + "imported" : { + "type" : "boolean" + }, + "institutionType" : { + "type" : "string", + "enum" : [ "GSP", "PA", "PG", "PSP", "PT", "SA", "SCP" ] + }, + "origin" : { + "type" : "string" + }, + "originId" : { + "type" : "string" + }, + "paymentServiceProvider" : { + "$ref" : "#/components/schemas/PaymentServiceProviderResponse" + }, + "products" : { + "type" : "object", + "additionalProperties" : { + "$ref" : "#/components/schemas/ProductsManagement" + } + }, + "rea" : { + "type" : "string" + }, + "shareCapital" : { + "type" : "string" + }, + "subunitCode" : { + "type" : "string" + }, + "subunitType" : { + "type" : "string" + }, + "supportEmail" : { + "type" : "string" + }, + "supportPhone" : { + "type" : "string" + }, + "taxCode" : { + "type" : "string" + }, + "updatedAt" : { + "type" : "string", + "format" : "date-time" + }, + "zipCode" : { + "type" : "string" + } + } + }, + "InstitutionManagerResponse" : { + "title" : "InstitutionManagerResponse", + "type" : "object", + "properties" : { + "billing" : { + "$ref" : "#/components/schemas/BillingResponse" + }, + "createdAt" : { + "type" : "string", + "format" : "date-time" + }, + "from" : { + "type" : "string" + }, + "id" : { + "type" : "string" + }, + "institutionUpdate" : { + "$ref" : "#/components/schemas/InstitutionUpdateResponse" + }, + "pricingPlan" : { + "type" : "string" + }, + "product" : { + "$ref" : "#/components/schemas/ProductInfo" + }, + "role" : { + "type" : "string" + }, + "state" : { + "type" : "string", + "enum" : [ "ACTIVE", "DELETED", "PENDING", "REJECTED", "SUSPENDED", "TOBEVALIDATED" ] + }, + "to" : { + "type" : "string" + }, + "updatedAt" : { + "type" : "string", + "format" : "date-time" + } + } + }, + "InstitutionOnboardingListResponse" : { + "title" : "InstitutionOnboardingListResponse", + "type" : "object", + "properties" : { + "items" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/InstitutionOnboardingResponse" + } + } + } + }, + "InstitutionOnboardingResponse" : { + "title" : "InstitutionOnboardingResponse", + "type" : "object", + "properties" : { + "address" : { + "type" : "string" + }, + "aooParentCode" : { + "type" : "string" + }, + "attributes" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/AttributesResponse" + } + }, + "businessRegisterPlace" : { + "type" : "string" + }, + "createdAt" : { + "type" : "string", + "format" : "date-time" + }, + "dataProtectionOfficer" : { + "$ref" : "#/components/schemas/DataProtectionOfficerResponse" + }, + "description" : { + "type" : "string" + }, + "digitalAddress" : { + "type" : "string" + }, + "externalId" : { + "type" : "string" + }, + "geographicTaxonomies" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/GeoTaxonomies" + } + }, + "id" : { + "type" : "string" + }, + "imported" : { + "type" : "boolean" + }, + "institutionType" : { + "type" : "string", + "enum" : [ "GSP", "PA", "PG", "PSP", "PT", "SA", "SCP" ] + }, + "onboardings" : { + "type" : "object", + "additionalProperties" : { + "$ref" : "#/components/schemas/OnboardingResponse" + } + }, + "origin" : { + "type" : "string" + }, + "originId" : { + "type" : "string" + }, + "paymentServiceProvider" : { + "$ref" : "#/components/schemas/PaymentServiceProviderResponse" + }, + "rea" : { + "type" : "string" + }, + "shareCapital" : { + "type" : "string" + }, + "subunitCode" : { + "type" : "string" + }, + "subunitType" : { + "type" : "string" + }, + "supportEmail" : { + "type" : "string" + }, + "supportPhone" : { + "type" : "string" + }, + "taxCode" : { + "type" : "string" + }, + "updatedAt" : { + "type" : "string", + "format" : "date-time" + }, + "zipCode" : { + "type" : "string" + } + } + }, + "InstitutionPnPgResponse" : { + "title" : "InstitutionPnPgResponse", + "type" : "object", + "properties" : { + "id" : { + "type" : "string" + } + } + }, + "InstitutionProduct" : { + "title" : "InstitutionProduct", + "type" : "object", + "properties" : { + "id" : { + "type" : "string" + }, + "state" : { + "type" : "string", + "enum" : [ "ACTIVE", "DELETED", "PENDING", "REJECTED", "SUSPENDED", "TOBEVALIDATED" ] + } + } + }, + "InstitutionProducts" : { + "title" : "InstitutionProducts", + "type" : "object", + "properties" : { + "institutionId" : { + "type" : "string" + }, + "institutionName" : { + "type" : "string" + }, + "institutionRootName" : { + "type" : "string" + }, + "products" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/Product" + } + } + } + }, + "InstitutionPut" : { + "title" : "InstitutionPut", + "type" : "object", + "properties" : { + "description" : { + "type" : "string" + }, + "digitalAddress" : { + "type" : "string" + }, + "geographicTaxonomyCodes" : { + "type" : "array", + "items" : { + "type" : "string" + } + } + } + }, + "InstitutionRequest" : { + "title" : "InstitutionRequest", + "type" : "object", + "properties" : { + "address" : { + "type" : "string" + }, + "attributes" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/AttributesRequest" + } + }, + "billing" : { + "$ref" : "#/components/schemas/BillingRequest" + }, + "businessRegisterPlace" : { + "type" : "string" + }, + "createdAt" : { + "type" : "string", + "format" : "date-time" + }, + "dataProtectionOfficer" : { + "$ref" : "#/components/schemas/DataProtectionOfficerRequest" + }, + "description" : { + "type" : "string" + }, + "digitalAddress" : { + "type" : "string" + }, + "externalId" : { + "type" : "string" + }, + "geographicTaxonomies" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/GeoTaxonomies" + } + }, + "id" : { + "type" : "string" + }, + "imported" : { + "type" : "boolean" + }, + "institutionType" : { + "type" : "string", + "enum" : [ "GSP", "PA", "PG", "PSP", "PT", "SA", "SCP" ] + }, + "onboarding" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/OnboardingRequest" + } + }, + "origin" : { + "type" : "string" + }, + "originId" : { + "type" : "string" + }, + "paymentServiceProvider" : { + "$ref" : "#/components/schemas/PaymentServiceProviderRequest" + }, + "rea" : { + "type" : "string" + }, + "shareCapital" : { + "type" : "string" + }, + "supportEmail" : { + "type" : "string" + }, + "supportPhone" : { + "type" : "string" + }, + "taxCode" : { + "type" : "string" + }, + "updatedAt" : { + "type" : "string", + "format" : "date-time" + }, + "zipCode" : { + "type" : "string" + } + } + }, + "InstitutionResponse" : { + "title" : "InstitutionResponse", + "type" : "object", + "properties" : { + "address" : { + "type" : "string" + }, + "aooParentCode" : { + "type" : "string" + }, + "attributes" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/AttributesResponse" + } + }, + "businessRegisterPlace" : { + "type" : "string" + }, + "createdAt" : { + "type" : "string", + "format" : "date-time" + }, + "dataProtectionOfficer" : { + "$ref" : "#/components/schemas/DataProtectionOfficerResponse" + }, + "description" : { + "type" : "string" + }, + "digitalAddress" : { + "type" : "string" + }, + "externalId" : { + "type" : "string" + }, + "geographicTaxonomies" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/GeoTaxonomies" + } + }, + "id" : { + "type" : "string" + }, + "imported" : { + "type" : "boolean" + }, + "institutionType" : { + "type" : "string", + "enum" : [ "GSP", "PA", "PG", "PSP", "PT", "SA", "SCP" ] + }, + "onboarding" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/OnboardedProductResponse" + } + }, + "origin" : { + "type" : "string" + }, + "originId" : { + "type" : "string" + }, + "paymentServiceProvider" : { + "$ref" : "#/components/schemas/PaymentServiceProviderResponse" + }, + "rea" : { + "type" : "string" + }, + "rootParent" : { + "$ref" : "#/components/schemas/RootParentResponse" + }, + "shareCapital" : { + "type" : "string" + }, + "subunitCode" : { + "type" : "string" + }, + "subunitType" : { + "type" : "string" + }, + "supportEmail" : { + "type" : "string" + }, + "supportPhone" : { + "type" : "string" + }, + "taxCode" : { + "type" : "string" + }, + "updatedAt" : { + "type" : "string", + "format" : "date-time" + }, + "zipCode" : { + "type" : "string" + } + } + }, + "InstitutionToOnboard" : { + "title" : "InstitutionToOnboard", + "type" : "object", + "properties" : { + "cfImpresa" : { + "type" : "string" + }, + "denominazione" : { + "type" : "string" + } + } + }, + "InstitutionUpdate" : { + "title" : "InstitutionUpdate", + "type" : "object", + "properties" : { + "address" : { + "type" : "string" + }, + "businessRegisterPlace" : { + "type" : "string" + }, + "dataProtectionOfficer" : { + "$ref" : "#/components/schemas/DataProtectionOfficer" + }, + "description" : { + "type" : "string" + }, + "digitalAddress" : { + "type" : "string" + }, + "geographicTaxonomies" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/InstitutionGeographicTaxonomies" + } + }, + "imported" : { + "type" : "boolean" + }, + "institutionType" : { + "type" : "string", + "enum" : [ "GSP", "PA", "PG", "PSP", "PT", "SA", "SCP" ] + }, + "paymentServiceProvider" : { + "$ref" : "#/components/schemas/PaymentServiceProvider" + }, + "rea" : { + "type" : "string" + }, + "shareCapital" : { + "type" : "string" + }, + "supportEmail" : { + "type" : "string" + }, + "supportPhone" : { + "type" : "string" + }, + "taxCode" : { + "type" : "string" + }, + "zipCode" : { + "type" : "string" + } + } + }, + "InstitutionUpdateRequest" : { + "title" : "InstitutionUpdateRequest", + "type" : "object", + "properties" : { + "address" : { + "type" : "string" + }, + "businessRegisterPlace" : { + "type" : "string" + }, + "dataProtectionOfficer" : { + "$ref" : "#/components/schemas/DataProtectionOfficerRequest" + }, + "description" : { + "type" : "string" + }, + "digitalAddress" : { + "type" : "string" + }, + "geographicTaxonomyCodes" : { + "type" : "array", + "items" : { + "type" : "string" + } + }, + "imported" : { + "type" : "boolean" + }, + "institutionType" : { + "type" : "string", + "enum" : [ "GSP", "PA", "PG", "PSP", "PT", "SA", "SCP" ] + }, + "paymentServiceProvider" : { + "$ref" : "#/components/schemas/PaymentServiceProviderRequest" + }, + "rea" : { + "type" : "string" + }, + "shareCapital" : { + "type" : "string" + }, + "supportEmail" : { + "type" : "string" + }, + "supportPhone" : { + "type" : "string" + }, + "taxCode" : { + "type" : "string" + }, + "zipCode" : { + "type" : "string" + } + } + }, + "InstitutionUpdateResponse" : { + "title" : "InstitutionUpdateResponse", + "type" : "object", + "properties" : { + "address" : { + "type" : "string" + }, + "aooParentCode" : { + "type" : "string" + }, + "businessRegisterPlace" : { + "type" : "string" + }, + "dataProtectionOfficer" : { + "$ref" : "#/components/schemas/DataProtectionOfficerResponse" + }, + "description" : { + "type" : "string" + }, + "digitalAddress" : { + "type" : "string" + }, + "geographicTaxonomyCodes" : { + "type" : "array", + "items" : { + "type" : "string" + } + }, + "imported" : { + "type" : "boolean" + }, + "institutionType" : { + "type" : "string", + "enum" : [ "GSP", "PA", "PG", "PSP", "PT", "SA", "SCP" ] + }, + "paymentServiceProvider" : { + "$ref" : "#/components/schemas/PaymentServiceProviderResponse" + }, + "rea" : { + "type" : "string" + }, + "shareCapital" : { + "type" : "string" + }, + "subunitCode" : { + "type" : "string" + }, + "subunitType" : { + "type" : "string" + }, + "supportEmail" : { + "type" : "string" + }, + "supportPhone" : { + "type" : "string" + }, + "taxCode" : { + "type" : "string" + }, + "zipCode" : { + "type" : "string" + } + } + }, + "InstitutionsResponse" : { + "title" : "InstitutionsResponse", + "type" : "object", + "properties" : { + "institutions" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/InstitutionResponse" + } + } + } + }, + "LegalsResponse" : { + "title" : "LegalsResponse", + "type" : "object", + "properties" : { + "env" : { + "type" : "string", + "enum" : [ "COLL", "DEV", "PROD", "ROOT" ] + }, + "partyId" : { + "type" : "string" + }, + "relationshipId" : { + "type" : "string" + }, + "role" : { + "type" : "string", + "enum" : [ "DELEGATE", "MANAGER", "OPERATOR", "SUB_DELEGATE" ] + } + } + }, + "MigrationInstitution" : { + "title" : "MigrationInstitution", + "type" : "object", + "properties" : { + "address" : { + "type" : "string" + }, + "attributes" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/Attributes" + } + }, + "billing" : { + "$ref" : "#/components/schemas/Billing" + }, + "businessRegisterPlace" : { + "type" : "string" + }, + "createdAt" : { + "type" : "string", + "format" : "date-time" + }, + "dataProtectionOfficer" : { + "$ref" : "#/components/schemas/DataProtectionOfficer" + }, + "description" : { + "type" : "string" + }, + "digitalAddress" : { + "type" : "string" + }, + "externalId" : { + "type" : "string" + }, + "geographicTaxonomies" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/InstitutionGeographicTaxonomies" + } + }, + "id" : { + "type" : "string" + }, + "imported" : { + "type" : "boolean" + }, + "institutionType" : { + "type" : "string", + "enum" : [ "GSP", "PA", "PG", "PSP", "PT", "SA", "SCP" ] + }, + "onboarding" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/Onboarding" + } + }, + "origin" : { + "type" : "string" + }, + "originId" : { + "type" : "string" + }, + "paymentServiceProvider" : { + "$ref" : "#/components/schemas/PaymentServiceProvider" + }, + "rea" : { + "type" : "string" + }, + "shareCapital" : { + "type" : "string" + }, + "supportEmail" : { + "type" : "string" + }, + "supportPhone" : { + "type" : "string" + }, + "taxCode" : { + "type" : "string" + }, + "updatedAt" : { + "type" : "string", + "format" : "date-time" + }, + "zipCode" : { + "type" : "string" + } + } + }, + "MigrationOnboardedUser" : { + "title" : "MigrationOnboardedUser", + "type" : "object", + "properties" : { + "bindings" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/UserBinding" + } + }, + "createdAt" : { + "type" : "string", + "format" : "date-time" + }, + "id" : { + "type" : "string" + } + } + }, + "MigrationToken" : { + "title" : "MigrationToken", + "type" : "object", + "properties" : { + "checksum" : { + "type" : "string" + }, + "closedAt" : { + "type" : "string", + "format" : "date-time" + }, + "contractSigned" : { + "type" : "string" + }, + "contractTemplate" : { + "type" : "string" + }, + "contractVersion" : { + "type" : "string" + }, + "createdAt" : { + "type" : "string", + "format" : "date-time" + }, + "expiringDate" : { + "type" : "string", + "format" : "date-time" + }, + "id" : { + "type" : "string" + }, + "institutionId" : { + "type" : "string" + }, + "institutionUpdate" : { + "$ref" : "#/components/schemas/InstitutionUpdate" + }, + "productId" : { + "type" : "string" + }, + "status" : { + "type" : "string", + "enum" : [ "ACTIVE", "DELETED", "PENDING", "REJECTED", "SUSPENDED", "TOBEVALIDATED" ] + }, + "type" : { + "type" : "string", + "enum" : [ "INSTITUTION", "LEGALS" ] + }, + "updatedAt" : { + "type" : "string", + "format" : "date-time" + }, + "users" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/TokenUser" + } + } + } + }, + "OnboardedInstitutionResponse" : { + "title" : "OnboardedInstitutionResponse", + "type" : "object", + "properties" : { + "address" : { + "type" : "string" + }, + "aooParentCode" : { + "type" : "string" + }, + "attributes" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/AttributesResponse" + } + }, + "billing" : { + "$ref" : "#/components/schemas/Billing" + }, + "businessData" : { + "$ref" : "#/components/schemas/BusinessData" + }, + "dataProtectionOfficer" : { + "$ref" : "#/components/schemas/DataProtectionOfficerResponse" + }, + "description" : { + "type" : "string" + }, + "digitalAddress" : { + "type" : "string" + }, + "externalId" : { + "type" : "string" + }, + "geographicTaxonomies" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/GeoTaxonomies" + } + }, + "id" : { + "type" : "string" + }, + "institutionType" : { + "type" : "string", + "enum" : [ "GSP", "PA", "PG", "PSP", "PT", "SA", "SCP" ] + }, + "origin" : { + "type" : "string" + }, + "originId" : { + "type" : "string" + }, + "parentDescription" : { + "type" : "string" + }, + "paymentServiceProvider" : { + "$ref" : "#/components/schemas/PaymentServiceProviderResponse" + }, + "pricingPlan" : { + "type" : "string" + }, + "productInfo" : { + "$ref" : "#/components/schemas/ProductInfo" + }, + "role" : { + "type" : "string", + "enum" : [ "DELEGATE", "MANAGER", "OPERATOR", "SUB_DELEGATE" ] + }, + "rootParentId" : { + "type" : "string" + }, + "state" : { + "type" : "string" + }, + "subunitCode" : { + "type" : "string" + }, + "subunitType" : { + "type" : "string" + }, + "supportContact" : { + "$ref" : "#/components/schemas/SupportContact" + }, + "taxCode" : { + "type" : "string" + }, + "zipCode" : { + "type" : "string" + } + } + }, + "OnboardedProduct" : { + "title" : "OnboardedProduct", + "type" : "object", + "properties" : { + "contract" : { + "type" : "string" + }, + "createdAt" : { + "type" : "string", + "format" : "date-time" + }, + "env" : { + "type" : "string", + "enum" : [ "COLL", "DEV", "PROD", "ROOT" ] + }, + "productId" : { + "type" : "string" + }, + "productRole" : { + "type" : "string" + }, + "relationshipId" : { + "type" : "string" + }, + "role" : { + "type" : "string", + "enum" : [ "DELEGATE", "MANAGER", "OPERATOR", "SUB_DELEGATE" ] + }, + "status" : { + "type" : "string", + "enum" : [ "ACTIVE", "DELETED", "PENDING", "REJECTED", "SUSPENDED", "TOBEVALIDATED" ] + }, + "tokenId" : { + "type" : "string" + }, + "updatedAt" : { + "type" : "string", + "format" : "date-time" + } + } + }, + "OnboardedProductResponse" : { + "title" : "OnboardedProductResponse", + "type" : "object", + "properties" : { + "billing" : { + "$ref" : "#/components/schemas/BillingResponse" + }, + "createdAt" : { + "type" : "string", + "format" : "date-time" + }, + "productId" : { + "type" : "string" + }, + "status" : { + "type" : "string", + "enum" : [ "ACTIVE", "DELETED", "PENDING", "REJECTED", "SUSPENDED", "TOBEVALIDATED" ] + }, + "updatedAt" : { + "type" : "string", + "format" : "date-time" + } + } + }, + "OnboardedProducts" : { + "title" : "OnboardedProducts", + "type" : "object", + "properties" : { + "products" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/InstitutionProduct" + } + } + } + }, + "OnboardedUser" : { + "title" : "OnboardedUser", + "type" : "object", + "properties" : { + "bindings" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/UserBinding" + } + }, + "createdAt" : { + "type" : "string", + "format" : "date-time" + }, + "id" : { + "type" : "string" + } + } + }, + "Onboarding" : { + "title" : "Onboarding", + "type" : "object", + "properties" : { + "billing" : { + "$ref" : "#/components/schemas/Billing" + }, + "closedAt" : { + "type" : "string", + "format" : "date-time" + }, + "contract" : { + "type" : "string" + }, + "createdAt" : { + "type" : "string", + "format" : "date-time" + }, + "pricingPlan" : { + "type" : "string" + }, + "productId" : { + "type" : "string" + }, + "status" : { + "type" : "string", + "enum" : [ "ACTIVE", "DELETED", "PENDING", "REJECTED", "SUSPENDED", "TOBEVALIDATED" ] + }, + "tokenId" : { + "type" : "string" + }, + "updatedAt" : { + "type" : "string", + "format" : "date-time" + } + } + }, + "OnboardingImportContract" : { + "title" : "OnboardingImportContract", + "type" : "object", + "properties" : { + "contractType" : { + "type" : "string" + }, + "createdAt" : { + "type" : "string", + "format" : "date-time" + }, + "fileName" : { + "type" : "string" + }, + "filePath" : { + "type" : "string" + } + } + }, + "OnboardingInfoResponse" : { + "title" : "OnboardingInfoResponse", + "type" : "object", + "properties" : { + "institutions" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/OnboardedInstitutionResponse" + } + }, + "userId" : { + "type" : "string" + } + } + }, + "OnboardingInstitutionLegalsRequest" : { + "title" : "OnboardingInstitutionLegalsRequest", + "type" : "object", + "properties" : { + "contract" : { + "$ref" : "#/components/schemas/ContractRequest" + }, + "institutionExternalId" : { + "type" : "string" + }, + "institutionId" : { + "type" : "string" + }, + "productId" : { + "type" : "string" + }, + "productName" : { + "type" : "string" + }, + "signContract" : { + "type" : "boolean" + }, + "users" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/Person" + } + } + } + }, + "OnboardingInstitutionOperatorsRequest" : { + "title" : "OnboardingInstitutionOperatorsRequest", + "type" : "object", + "properties" : { + "institutionId" : { + "type" : "string" + }, + "productId" : { + "type" : "string" + }, + "productTitle" : { + "type" : "string" + }, + "users" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/Person" + } + } + } + }, + "OnboardingInstitutionRequest" : { + "title" : "OnboardingInstitutionRequest", + "type" : "object", + "properties" : { + "billing" : { + "$ref" : "#/components/schemas/BillingRequest" + }, + "contract" : { + "$ref" : "#/components/schemas/ContractRequest" + }, + "contractImported" : { + "$ref" : "#/components/schemas/OnboardingImportContract" + }, + "institutionExternalId" : { + "type" : "string" + }, + "institutionUpdate" : { + "$ref" : "#/components/schemas/InstitutionUpdateRequest" + }, + "pricingPlan" : { + "type" : "string" + }, + "productId" : { + "type" : "string" + }, + "productName" : { + "type" : "string" + }, + "signContract" : { + "type" : "boolean" + }, + "users" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/Person" + } + } + } + }, + "OnboardingRequest" : { + "title" : "OnboardingRequest", + "type" : "object", + "properties" : { + "billingRequest" : { + "$ref" : "#/components/schemas/Billing" + }, + "contract" : { + "$ref" : "#/components/schemas/Contract" + }, + "contractCreatedAt" : { + "type" : "string", + "format" : "date-time" + }, + "contractFilePath" : { + "type" : "string" + }, + "institutionExternalId" : { + "type" : "string" + }, + "institutionUpdate" : { + "$ref" : "#/components/schemas/InstitutionUpdate" + }, + "pricingPlan" : { + "type" : "string" + }, + "productId" : { + "type" : "string" + }, + "productName" : { + "type" : "string" + }, + "signContract" : { + "type" : "boolean" + }, + "tokenType" : { + "type" : "string", + "enum" : [ "INSTITUTION", "LEGALS" ] + }, + "users" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/UserToOnboard" + } + } + } + }, + "OnboardingResponse" : { + "title" : "OnboardingResponse", + "type" : "object", + "properties" : { + "billing" : { + "$ref" : "#/components/schemas/BillingResponse" + }, + "closedAt" : { + "type" : "string", + "format" : "date-time" + }, + "contract" : { + "type" : "string" + }, + "createdAt" : { + "type" : "string", + "format" : "date-time" + }, + "pricingPlan" : { + "type" : "string" + }, + "productId" : { + "type" : "string" + }, + "status" : { + "type" : "string", + "enum" : [ "ACTIVE", "DELETED", "PENDING", "REJECTED", "SUSPENDED", "TOBEVALIDATED" ] + }, + "tokenId" : { + "type" : "string" + }, + "updatedAt" : { + "type" : "string", + "format" : "date-time" + } + } + }, + "OnboardingsResponse" : { + "title" : "OnboardingsResponse", + "type" : "object", + "properties" : { + "onboardings" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/OnboardingResponse" + } + } + } + }, + "PaAttributes" : { + "title" : "PaAttributes", + "type" : "object", + "properties" : { + "aooParentCode" : { + "type" : "string" + } + } + }, + "PaymentServiceProvider" : { + "title" : "PaymentServiceProvider", + "type" : "object", + "properties" : { + "abiCode" : { + "type" : "string" + }, + "businessRegisterNumber" : { + "type" : "string" + }, + "legalRegisterName" : { + "type" : "string" + }, + "legalRegisterNumber" : { + "type" : "string" + }, + "vatNumberGroup" : { + "type" : "boolean" + } + } + }, + "PaymentServiceProviderRequest" : { + "title" : "PaymentServiceProviderRequest", + "type" : "object", + "properties" : { + "abiCode" : { + "type" : "string" + }, + "businessRegisterNumber" : { + "type" : "string" + }, + "legalRegisterName" : { + "type" : "string" + }, + "legalRegisterNumber" : { + "type" : "string" + }, + "vatNumberGroup" : { + "type" : "boolean" + } + } + }, + "PaymentServiceProviderResponse" : { + "title" : "PaymentServiceProviderResponse", + "type" : "object", + "properties" : { + "abiCode" : { + "type" : "string" + }, + "businessRegisterNumber" : { + "type" : "string" + }, + "legalRegisterName" : { + "type" : "string" + }, + "legalRegisterNumber" : { + "type" : "string" + }, + "vatNumberGroup" : { + "type" : "boolean" + } + } + }, + "Person" : { + "title" : "Person", + "type" : "object", + "properties" : { + "email" : { + "type" : "string" + }, + "env" : { + "type" : "string", + "enum" : [ "COLL", "DEV", "PROD", "ROOT" ] + }, + "id" : { + "type" : "string" + }, + "name" : { + "type" : "string" + }, + "productRole" : { + "type" : "string" + }, + "role" : { + "type" : "string", + "enum" : [ "DELEGATE", "MANAGER", "OPERATOR", "SUB_DELEGATE" ] + }, + "roleLabel" : { + "type" : "string" + }, + "surname" : { + "type" : "string" + }, + "taxCode" : { + "type" : "string" + } + } + }, + "PersonId" : { + "title" : "PersonId", + "type" : "object", + "properties" : { + "id" : { + "type" : "string" + } + } + }, + "Problem" : { + "title" : "Problem", + "type" : "object", + "properties" : { + "errors" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/ProblemError" + } + }, + "status" : { + "type" : "integer", + "format" : "int32" + } + } + }, + "ProblemError" : { + "title" : "ProblemError", + "type" : "object" + }, + "Product" : { + "title" : "Product", + "type" : "object", + "properties" : { + "contract" : { + "type" : "string" + }, + "createdAt" : { + "type" : "string", + "format" : "date-time" + }, + "env" : { + "type" : "string", + "enum" : [ "COLL", "DEV", "PROD", "ROOT" ] + }, + "productId" : { + "type" : "string" + }, + "productRole" : { + "type" : "string" + }, + "role" : { + "type" : "string", + "enum" : [ "DELEGATE", "MANAGER", "OPERATOR", "SUB_DELEGATE" ] + }, + "status" : { + "type" : "string", + "enum" : [ "ACTIVE", "DELETED", "PENDING", "REJECTED", "SUSPENDED", "TOBEVALIDATED" ] + }, + "tokenId" : { + "type" : "string" + }, + "updatedAt" : { + "type" : "string", + "format" : "date-time" + } + } + }, + "ProductInfo" : { + "title" : "ProductInfo", + "type" : "object", + "properties" : { + "createdAt" : { + "type" : "string", + "format" : "date-time" + }, + "id" : { + "type" : "string" + }, + "role" : { + "type" : "string" + } + } + }, + "ProductsManagement" : { + "title" : "ProductsManagement", + "type" : "object", + "properties" : { + "billing" : { + "$ref" : "#/components/schemas/BillingResponse" + }, + "pricingPlan" : { + "type" : "string" + }, + "product" : { + "type" : "string" + } + } + }, + "RelationshipResult" : { + "title" : "RelationshipResult", + "type" : "object", + "properties" : { + "billing" : { + "$ref" : "#/components/schemas/BillingResponse" + }, + "createdAt" : { + "type" : "string", + "format" : "date-time" + }, + "from" : { + "type" : "string" + }, + "id" : { + "type" : "string" + }, + "institutionUpdate" : { + "$ref" : "#/components/schemas/InstitutionUpdateResponse" + }, + "pricingPlan" : { + "type" : "string" + }, + "product" : { + "$ref" : "#/components/schemas/ProductInfo" + }, + "role" : { + "type" : "string", + "enum" : [ "DELEGATE", "MANAGER", "OPERATOR", "SUB_DELEGATE" ] + }, + "state" : { + "type" : "string", + "enum" : [ "ACTIVE", "DELETED", "PENDING", "REJECTED", "SUSPENDED", "TOBEVALIDATED" ] + }, + "to" : { + "type" : "string" + }, + "tokenId" : { + "type" : "string" + }, + "updatedAt" : { + "type" : "string", + "format" : "date-time" + } + } + }, + "RelationshipsManagement" : { + "title" : "RelationshipsManagement", + "type" : "object", + "properties" : { + "items" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/RelationshipResult" + } + } + } + }, + "RootParentResponse" : { + "title" : "RootParentResponse", + "type" : "object", + "properties" : { + "description" : { + "type" : "string" + }, + "id" : { + "type" : "string" + } + } + }, + "SupportContact" : { + "title" : "SupportContact", + "type" : "object", + "properties" : { + "supportEmail" : { + "type" : "string" + }, + "supportPhone" : { + "type" : "string" + } + } + }, + "Token" : { + "title" : "Token", + "type" : "object", + "properties" : { + "activatedAt" : { + "type" : "string", + "format" : "date-time" + }, + "checksum" : { + "type" : "string" + }, + "contentType" : { + "type" : "string" + }, + "contractSigned" : { + "type" : "string" + }, + "contractTemplate" : { + "type" : "string" + }, + "contractVersion" : { + "type" : "string" + }, + "createdAt" : { + "type" : "string", + "format" : "date-time" + }, + "deletedAt" : { + "type" : "string", + "format" : "date-time" + }, + "expiringDate" : { + "type" : "string", + "format" : "date-time" + }, + "id" : { + "type" : "string" + }, + "institutionId" : { + "type" : "string" + }, + "institutionUpdate" : { + "$ref" : "#/components/schemas/InstitutionUpdate" + }, + "productId" : { + "type" : "string" + }, + "status" : { + "type" : "string", + "enum" : [ "ACTIVE", "DELETED", "PENDING", "REJECTED", "SUSPENDED", "TOBEVALIDATED" ] + }, + "type" : { + "type" : "string", + "enum" : [ "INSTITUTION", "LEGALS" ] + }, + "updatedAt" : { + "type" : "string", + "format" : "date-time" + }, + "users" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/TokenUser" + } + } + } + }, + "TokenListResponse" : { + "title" : "TokenListResponse", + "type" : "object", + "properties" : { + "items" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/TokenResponse" + } + } + } + }, + "TokenResource" : { + "title" : "TokenResource", + "type" : "object", + "properties" : { + "checksum" : { + "type" : "string" + }, + "closedAt" : { + "type" : "string", + "format" : "date-time" + }, + "contractSigned" : { + "type" : "string" + }, + "contractTemplate" : { + "type" : "string" + }, + "contractVersion" : { + "type" : "string" + }, + "createdAt" : { + "type" : "string", + "format" : "date-time" + }, + "expiringDate" : { + "type" : "string", + "format" : "date-time" + }, + "id" : { + "type" : "string" + }, + "institutionId" : { + "type" : "string" + }, + "institutionUpdate" : { + "$ref" : "#/components/schemas/InstitutionUpdate" + }, + "productId" : { + "type" : "string" + }, + "status" : { + "type" : "string", + "enum" : [ "ACTIVE", "DELETED", "PENDING", "REJECTED", "SUSPENDED", "TOBEVALIDATED" ] + }, + "type" : { + "type" : "string", + "enum" : [ "INSTITUTION", "LEGALS" ] + }, + "updatedAt" : { + "type" : "string", + "format" : "date-time" + }, + "users" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/TokenUser" + } + } + } + }, + "TokenResponse" : { + "title" : "TokenResponse", + "type" : "object", + "properties" : { + "checksum" : { + "type" : "string" + }, + "closedAt" : { + "type" : "string", + "format" : "date-time" + }, + "contentType" : { + "type" : "string" + }, + "contractSigned" : { + "type" : "string" + }, + "contractTemplate" : { + "type" : "string" + }, + "contractVersion" : { + "type" : "string" + }, + "createdAt" : { + "type" : "string", + "format" : "date-time" + }, + "expiringDate" : { + "type" : "string", + "format" : "date-time" + }, + "id" : { + "type" : "string" + }, + "institutionId" : { + "type" : "string" + }, + "institutionUpdate" : { + "$ref" : "#/components/schemas/InstitutionUpdate" + }, + "legals" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/LegalsResponse" + } + }, + "productId" : { + "type" : "string" + }, + "status" : { + "type" : "string", + "enum" : [ "ACTIVE", "DELETED", "PENDING", "REJECTED", "SUSPENDED", "TOBEVALIDATED" ] + }, + "updatedAt" : { + "type" : "string", + "format" : "date-time" + }, + "users" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/TokenUser" + } + } + } + }, + "TokenUser" : { + "title" : "TokenUser", + "type" : "object", + "properties" : { + "role" : { + "type" : "string", + "enum" : [ "DELEGATE", "MANAGER", "OPERATOR", "SUB_DELEGATE" ] + }, + "userId" : { + "type" : "string" + } + } + }, + "UserBinding" : { + "title" : "UserBinding", + "type" : "object", + "properties" : { + "institutionId" : { + "type" : "string" + }, + "institutionName" : { + "type" : "string" + }, + "institutionRootName" : { + "type" : "string" + }, + "products" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/OnboardedProduct" + } + } + } + }, + "UserInfoResponse" : { + "title" : "UserInfoResponse", + "type" : "object", + "properties" : { + "email" : { + "type" : "string" + }, + "id" : { + "type" : "string" + }, + "name" : { + "type" : "string" + }, + "products" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/OnboardedProduct" + } + }, + "surname" : { + "type" : "string" + }, + "taxCode" : { + "type" : "string" + } + } + }, + "UserProductsResponse" : { + "title" : "UserProductsResponse", + "type" : "object", + "properties" : { + "bindings" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/InstitutionProducts" + } + }, + "id" : { + "type" : "string" + } + } + }, + "UserResponse" : { + "title" : "UserResponse", + "type" : "object", + "properties" : { + "email" : { + "type" : "string" + }, + "id" : { + "type" : "string" + }, + "name" : { + "type" : "string" + }, + "surname" : { + "type" : "string" + }, + "taxCode" : { + "type" : "string" + } + } + }, + "UserToOnboard" : { + "title" : "UserToOnboard", + "type" : "object", + "properties" : { + "email" : { + "type" : "string" + }, + "env" : { + "type" : "string", + "enum" : [ "COLL", "DEV", "PROD", "ROOT" ] + }, + "id" : { + "type" : "string" + }, + "name" : { + "type" : "string" + }, + "productRole" : { + "type" : "string" + }, + "role" : { + "type" : "string", + "enum" : [ "DELEGATE", "MANAGER", "OPERATOR", "SUB_DELEGATE" ] + }, + "roleLabel" : { + "type" : "string" + }, + "surname" : { + "type" : "string" + }, + "taxCode" : { + "type" : "string" + } + } + } + }, + "securitySchemes" : { + "bearerAuth" : { + "type" : "http", + "description" : "A bearer token in the format of a JWS and conformed to the specifications included in [RFC8725](https://tools.ietf.org/html/RFC8725)", + "scheme" : "bearer", + "bearerFormat" : "JWT" + } + } + } +} \ No newline at end of file diff --git a/apps/onboarding-ms/src/main/openapi/onboarding_functions.json b/apps/onboarding-ms/src/main/openapi/onboarding_functions.json new file mode 100644 index 000000000..8e1592e29 --- /dev/null +++ b/apps/onboarding-ms/src/main/openapi/onboarding_functions.json @@ -0,0 +1,165 @@ +{ + "openapi": "3.0.3", + "info": { + "title": "selc-party-registry-proxy", + "description": "Party Registry Proxy API documentation", + "version": "0.0.1-SNAPSHOT" + }, + "servers": [ + { + "url": "{url}:{port}{basePath}", + "variables": { + "url": { + "default": "http://localhost" + }, + "port": { + "default": "80" + }, + "basePath": { + "default": "" + } + } + } + ], + "tags": [ + { + "name": "Orchestration", + "description": "Orchestration Trigger" + } + ], + "paths": { + "/api/StartOnboardingOrchestration": { + "get": { + "tags": [ + "Orchestration" + ], + "summary": "", + "description": "", + "parameters": [ + { + "name": "onboardingId", + "in": "query", + "description": "Onboarding id about item to process", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "202": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OrchestrationResponse" + } + } + } + } + }, + "security": [ + { + "api_key": [] + } + ] + } + }, + "/api/StartOnboardingCompletionOrchestration": { + "get": { + "tags": [ + "Orchestration" + ], + "summary": "", + "description": "", + "parameters": [ + { + "name": "onboardingId", + "in": "query", + "description": "Onboarding id about item to process", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "202": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OrchestrationResponse" + } + } + } + } + }, + "security": [ + { + "api_key_complete": [] + } + ] + } + } + }, + "components": { + "schemas": { + "OrchestrationResponse": { + "title": "OrchestrationResponse", + "type": "object", + "properties": { + "schema": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "" + }, + "purgeHistoryDeleteUri": { + "type": "string", + "description": "" + }, + "restartPostUri": { + "type": "string", + "description": "" + }, + "sendEventPostUri": { + "type": "string", + "description": "" + }, + "statusQueryGetUri": { + "type": "string", + "description": "" + }, + "terminatePostUri": { + "type": "string", + "description": "" + }, + "resumePostUri": { + "type": "string", + "description": "" + }, + "suspendPostUri": { + "type": "string", + "description": "" + } + } + } + } + } + }, + "securitySchemes": { + "api_key": { + "type": "apiKey", + "name": "x-functions-key", + "in": "header" + }, + "api_key_complete": { + "type": "apiKey", + "name": "x-functions-key", + "in": "header" + } + } + } +} \ No newline at end of file diff --git a/apps/onboarding-ms/src/main/openapi/party_registry_proxy.json b/apps/onboarding-ms/src/main/openapi/party_registry_proxy.json new file mode 100644 index 000000000..fb8510db8 --- /dev/null +++ b/apps/onboarding-ms/src/main/openapi/party_registry_proxy.json @@ -0,0 +1,2126 @@ +{ + "openapi" : "3.0.3", + "info" : { + "title" : "selc-party-registry-proxy", + "description" : "Party Registry Proxy API documentation", + "version" : "0.0.1-SNAPSHOT" + }, + "servers" : [ { + "url" : "{url}:{port}{basePath}", + "variables" : { + "url" : { + "default" : "http://localhost" + }, + "port" : { + "default" : "80" + }, + "basePath" : { + "default" : "" + } + } + } ], + "tags" : [ { + "name" : "GeographicTaxonomies", + "description" : "Geographic Taxonomies Controller" + }, { + "name" : "aoo", + "description" : "AOO Controller" + }, { + "name" : "category", + "description" : "Category operations" + }, { + "name" : "infocamere", + "description" : "Info Camere Controller" + }, { + "name" : "institution", + "description" : "Institution operations" + }, { + "name" : "insurance-companies", + "description" : "Ivass Controller" + }, { + "name" : "nationalRegistries", + "description" : "National Registries Controller" + }, { + "name" : "stations", + "description" : "Station Controller" + }, { + "name" : "uo", + "description" : "UO Controller" + } ], + "paths" : { + "/aoo" : { + "get" : { + "tags" : [ "aoo" ], + "summary" : "Retrieve all AOO from IPA", + "description" : "Returns the AOO list", + "operationId" : "findAllUsingGET", + "parameters" : [ { + "name" : "page", + "in" : "query", + "description" : "Desired page number for result pagination. It is optional, and the default value is 1 when not specified", + "required" : false, + "style" : "form", + "schema" : { + "type" : "integer", + "format" : "int32" + } + }, { + "name" : "limit", + "in" : "query", + "description" : "Maximum number of items per page. It is optional, and the default value is 10 when not specified", + "required" : false, + "style" : "form", + "schema" : { + "type" : "integer", + "format" : "int32" + } + } ], + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/AOOsResource" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "401" : { + "description" : "Unauthorized", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "500" : { + "description" : "Internal Server Error", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/aoo/{codiceUniAoo}" : { + "get" : { + "tags" : [ "aoo" ], + "summary" : "Retrieve an AOO given its code", + "description" : "Returns an AOO", + "operationId" : "findByUnicodeUsingGET", + "parameters" : [ { + "name" : "codiceUniAoo", + "in" : "path", + "description" : "AOO unique identifier, the same of Id", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + }, { + "name" : "categories", + "in" : "query", + "description" : "Filter from origin category", + "required" : false, + "style" : "form", + "explode" : true, + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/AOOResource" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "401" : { + "description" : "Unauthorized", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "500" : { + "description" : "Internal Server Error", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/categories" : { + "get" : { + "tags" : [ "category" ], + "summary" : "Get all categories", + "description" : "Returns the categories list", + "operationId" : "findCategoriesUsingGET", + "parameters" : [ { + "name" : "origin", + "in" : "query", + "description" : "Describes which is the source of data", + "required" : false, + "style" : "form", + "schema" : { + "type" : "string", + "enum" : [ "ANAC", "INFOCAMERE", "IPA", "IVASS", "static" ] + } + }, { + "name" : "page", + "in" : "query", + "description" : "Desired page number for result pagination. It is optional, and the default value is 1 when not specified", + "required" : false, + "style" : "form", + "schema" : { + "type" : "integer", + "format" : "int32" + } + }, { + "name" : "limit", + "in" : "query", + "description" : "Maximum number of items per page. It is optional, and the default value is 10 when not specified", + "required" : false, + "style" : "form", + "schema" : { + "type" : "integer", + "format" : "int32" + } + } ], + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/CategoriesResource" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "401" : { + "description" : "Unauthorized", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "500" : { + "description" : "Internal Server Error", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/origins/{origin}/categories/{code}" : { + "get" : { + "tags" : [ "category" ], + "summary" : "Get a category", + "description" : "Returns a category", + "operationId" : "findCategoryUsingGET", + "parameters" : [ { + "name" : "origin", + "in" : "path", + "description" : "Describes which is the source of data", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string", + "enum" : [ "ANAC", "INFOCAMERE", "IPA", "IVASS", "static" ] + } + }, { + "name" : "code", + "in" : "path", + "description" : "code", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/CategoryResource" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "401" : { + "description" : "Unauthorized", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "500" : { + "description" : "Internal Server Error", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/geotaxonomies" : { + "get" : { + "tags" : [ "GeographicTaxonomies" ], + "summary" : "retrieves the geographic taxonomies by description", + "description" : "retrieves the geographic taxonomies by description", + "operationId" : "retrieveGeoTaxonomiesByDescriptionUsingGET", + "parameters" : [ { + "name" : "description", + "in" : "query", + "description" : "geographic taxonomy description", + "required" : true, + "style" : "form", + "schema" : { + "type" : "string" + } + }, { + "name" : "offset", + "in" : "query", + "description" : "identifies the page 0-based index, default to 0", + "required" : false, + "style" : "form", + "schema" : { + "type" : "integer", + "format" : "int32" + } + }, { + "name" : "limit", + "in" : "query", + "description" : "identifies the number of entries in a page, default to 10", + "required" : false, + "style" : "form", + "schema" : { + "type" : "integer", + "format" : "int32" + } + } ], + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "application/json" : { + "schema" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/GeographicTaxonomyResource" + } + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "401" : { + "description" : "Unauthorized", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "500" : { + "description" : "Internal Server Error", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/geotaxonomies/{geotaxId}" : { + "get" : { + "tags" : [ "GeographicTaxonomies" ], + "summary" : "retrieves the geographic taxonomy by code", + "description" : "retrieves the geographic taxonomy by code", + "operationId" : "retrieveGeoTaxonomiesByCodeUsingGET", + "parameters" : [ { + "name" : "geotaxId", + "in" : "path", + "description" : "Geographic taxonomy unique identifier ", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/GeographicTaxonomyResource" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "401" : { + "description" : "Unauthorized", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "500" : { + "description" : "Internal Server Error", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/info-camere/institutions" : { + "post" : { + "tags" : [ "infocamere" ], + "summary" : "Get institutions by legal tax id", + "description" : "Get the list of companies represented by the tax code of the person (physical or juridical) passed as a parameter", + "operationId" : "institutionsByLegalTaxIdUsingPOST", + "requestBody" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/GetInstitutionsByLegalDto" + } + } + } + }, + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/BusinessesResource" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "401" : { + "description" : "Unauthorized", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "500" : { + "description" : "Internal Server Error", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/institutions" : { + "get" : { + "tags" : [ "institution" ], + "summary" : "Search institutions", + "description" : "Returns a list of Institutions.", + "operationId" : "searchUsingGET", + "parameters" : [ { + "name" : "search", + "in" : "query", + "description" : "if passed, the result is filtered based on the contained value.", + "required" : false, + "style" : "form", + "schema" : { + "type" : "string" + } + }, { + "name" : "page", + "in" : "query", + "description" : "Desired page number for result pagination. It is optional, and the default value is 1 when not specified", + "required" : false, + "style" : "form", + "schema" : { + "type" : "integer", + "format" : "int32" + } + }, { + "name" : "limit", + "in" : "query", + "description" : "Maximum number of items per page. It is optional, and the default value is 10 when not specified", + "required" : false, + "style" : "form", + "schema" : { + "type" : "integer", + "format" : "int32" + } + }, { + "name" : "categories", + "in" : "query", + "description" : "Filter from origin category", + "required" : false, + "style" : "form", + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/InstitutionsResource" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "401" : { + "description" : "Unauthorized", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "500" : { + "description" : "Internal Server Error", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/institutions/{id}" : { + "get" : { + "tags" : [ "institution" ], + "summary" : "Find institution by ID", + "description" : "Returns a single institution. If 'origin' param is filled, the ID to find is treated as 'originId' ($ref: '#/components/schemas/Institution'); otherwise is treated as 'id' ($ref: '#/components/schemas/Institution') ", + "operationId" : "findInstitutionUsingGET", + "parameters" : [ { + "name" : "id", + "in" : "path", + "description" : "The institution ID. It change semantic based on the origin param value (see notes)", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + }, { + "name" : "origin", + "in" : "query", + "description" : "Describes which is the source of data", + "required" : false, + "style" : "form", + "schema" : { + "type" : "string", + "enum" : [ "ANAC", "INFOCAMERE", "IPA", "IVASS", "static" ] + } + }, { + "name" : "categories", + "in" : "query", + "description" : "Filter from origin category", + "required" : false, + "style" : "form", + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/InstitutionResource" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "401" : { + "description" : "Unauthorized", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "500" : { + "description" : "Internal Server Error", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/insurance-companies" : { + "get" : { + "tags" : [ "insurance-companies" ], + "summary" : "Search insurance company", + "description" : "Returns a list of insurance companies", + "operationId" : "searchUsingGET_1", + "parameters" : [ { + "name" : "search", + "in" : "query", + "description" : "Optional search field. Users can provide a search string to filter results", + "required" : false, + "style" : "form", + "schema" : { + "type" : "string" + } + }, { + "name" : "page", + "in" : "query", + "description" : "Desired page number for result pagination. It is optional, and the default value is 1 when not specified", + "required" : false, + "style" : "form", + "schema" : { + "type" : "integer", + "format" : "int32" + } + }, { + "name" : "limit", + "in" : "query", + "description" : "Maximum number of items per page. It is optional, and the default value is 10 when not specified", + "required" : false, + "style" : "form", + "schema" : { + "type" : "integer", + "format" : "int32" + } + } ], + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/InsuranceCompaniesResource" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "401" : { + "description" : "Unauthorized", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "500" : { + "description" : "Internal Server Error", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/insurance-companies/{taxId}" : { + "get" : { + "tags" : [ "insurance-companies" ], + "summary" : "Search insurance company by its taxCode", + "description" : "Returns only one insurance company.", + "operationId" : "searchByTaxCodeUsingGET", + "parameters" : [ { + "name" : "taxId", + "in" : "path", + "description" : "taxCode of insurance company", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/InsuranceCompanyResource" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "401" : { + "description" : "Unauthorized", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "500" : { + "description" : "Internal Server Error", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/national-registries/legal-address" : { + "get" : { + "tags" : [ "nationalRegistries" ], + "summary" : "Retrieve data from AdE and InfoCamere", + "description" : "Get the legal address of the business", + "operationId" : "legalAddressUsingGET", + "parameters" : [ { + "name" : "taxId", + "in" : "query", + "description" : "taxId", + "required" : true, + "style" : "form", + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/LegalAddressResponse" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "401" : { + "description" : "Unauthorized", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "500" : { + "description" : "Internal Server Error", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/national-registries/verify-legal" : { + "get" : { + "tags" : [ "nationalRegistries" ], + "summary" : "Retrieve data from AdE and InfoCamere", + "description" : "verify if given taxId is legal of given institution identified with vatNumber", + "operationId" : "verifyLegalUsingGET", + "parameters" : [ { + "name" : "taxId", + "in" : "query", + "description" : "taxId", + "required" : true, + "style" : "form", + "schema" : { + "type" : "string" + } + }, { + "name" : "vatNumber", + "in" : "query", + "description" : "vatNumber", + "required" : true, + "style" : "form", + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/LegalVerificationResult" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "401" : { + "description" : "Unauthorized", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "500" : { + "description" : "Internal Server Error", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/stations" : { + "get" : { + "tags" : [ "stations" ], + "summary" : "Search station", + "description" : "Returns a list of station.", + "operationId" : "searchUsingGET_2", + "parameters" : [ { + "name" : "search", + "in" : "query", + "description" : "Optional search field. Users can provide a search string to filter results", + "required" : false, + "style" : "form", + "schema" : { + "type" : "string" + } + }, { + "name" : "page", + "in" : "query", + "description" : "Desired page number for result pagination. It is optional, and the default value is 1 when not specified", + "required" : false, + "style" : "form", + "schema" : { + "type" : "integer", + "format" : "int32" + } + }, { + "name" : "limit", + "in" : "query", + "description" : "Maximum number of items per page. It is optional, and the default value is 10 when not specified", + "required" : false, + "style" : "form", + "schema" : { + "type" : "integer", + "format" : "int32" + } + } ], + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/StationsResource" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "401" : { + "description" : "Unauthorized", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "500" : { + "description" : "Internal Server Error", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/stations/{taxId}" : { + "get" : { + "tags" : [ "stations" ], + "summary" : "Search station by its taxCode", + "description" : "Returns only one station.", + "operationId" : "searchByTaxCodeUsingGET_1", + "parameters" : [ { + "name" : "taxId", + "in" : "path", + "description" : "taxCode of station", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/StationResource" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "401" : { + "description" : "Unauthorized", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "500" : { + "description" : "Internal Server Error", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/uo" : { + "get" : { + "tags" : [ "uo" ], + "summary" : "Retrieve all UO from IPA", + "description" : "Returns the UO list", + "operationId" : "findAllUsingGET_1", + "parameters" : [ { + "name" : "page", + "in" : "query", + "description" : "Desired page number for result pagination. It is optional, and the default value is 1 when not specified", + "required" : false, + "style" : "form", + "schema" : { + "type" : "integer", + "format" : "int32" + } + }, { + "name" : "limit", + "in" : "query", + "description" : "Maximum number of items per page. It is optional, and the default value is 10 when not specified", + "required" : false, + "style" : "form", + "schema" : { + "type" : "integer", + "format" : "int32" + } + } ], + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/UOsResource" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "401" : { + "description" : "Unauthorized", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "500" : { + "description" : "Internal Server Error", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + }, + "/uo/{codiceUniAoo}" : { + "get" : { + "tags" : [ "uo" ], + "summary" : "Retrieve a UO given its code", + "description" : "Returns a UO", + "operationId" : "findByUnicodeUsingGET_1", + "parameters" : [ { + "name" : "codiceUniAoo", + "in" : "path", + "description" : "UO unique identifier, the same of Id", + "required" : true, + "style" : "simple", + "schema" : { + "type" : "string" + } + }, { + "name" : "categories", + "in" : "query", + "description" : "Filter from origin category", + "required" : false, + "style" : "form", + "explode" : true, + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/UOResource" + } + } + } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "401" : { + "description" : "Unauthorized", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "500" : { + "description" : "Internal Server Error", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "bearerAuth" : [ "global" ] + } ] + } + } + }, + "components" : { + "schemas" : { + "AOOResource" : { + "title" : "AOOResource", + "type" : "object", + "properties" : { + "cap" : { + "type" : "string" + }, + "codAoo" : { + "type" : "string", + "description" : "AOO code" + }, + "codiceCatastaleComune" : { + "type" : "string", + "description" : "AOO land registry code" + }, + "codiceComuneISTAT" : { + "type" : "string", + "description" : "AOO istat code" + }, + "codiceFiscaleEnte" : { + "type" : "string", + "description" : "AOO fiscal code" + }, + "codiceIpa" : { + "type" : "string", + "description" : "AOO ipa code" + }, + "codiceUniAoo" : { + "type" : "string", + "description" : "AOO unique identifier, the same of Id" + }, + "cognomeResponsabile" : { + "type" : "string", + "description" : "AOO manager lastname" + }, + "dataAggiornamento" : { + "type" : "string", + "description" : "Identifies date of last update on the specific AOO" + }, + "dataIstituzione" : { + "type" : "string", + "description" : "Identifies date of first creation for AOO" + }, + "denominazioneAoo" : { + "type" : "string", + "description" : "AOO description" + }, + "denominazioneEnte" : { + "type" : "string", + "description" : "AOO parent description" + }, + "fax" : { + "type" : "string", + "description" : "AOO fax" + }, + "id" : { + "type" : "string" + }, + "indirizzo" : { + "type" : "string", + "description" : "AOO address" + }, + "mail1" : { + "type" : "string" + }, + "mailResponsabile" : { + "type" : "string", + "description" : "AOO manager email" + }, + "nomeResponsabile" : { + "type" : "string", + "description" : "AOO manager firstname" + }, + "origin" : { + "type" : "string", + "description" : "{swagger.model.*.origin}", + "enum" : [ "ANAC", "INFOCAMERE", "IPA", "IVASS", "static" ] + }, + "protocolloInformatico" : { + "type" : "string", + "description" : "AOO IT protocol" + }, + "telefono" : { + "type" : "string", + "description" : "AOO phone number" + }, + "telefonoResponsabile" : { + "type" : "string", + "description" : "AOO manager phone number" + }, + "tipoMail1" : { + "type" : "string" + }, + "uriprotocolloInformatico" : { + "type" : "string" + } + } + }, + "AOOsResource" : { + "title" : "AOOsResource", + "required" : [ "count", "items" ], + "type" : "object", + "properties" : { + "count" : { + "type" : "integer", + "description" : "Total count of items", + "format" : "int64" + }, + "items" : { + "type" : "array", + "description" : "List of AOO resource", + "items" : { + "$ref" : "#/components/schemas/AOOResource" + } + } + } + }, + "BusinessResource" : { + "title" : "BusinessResource", + "type" : "object", + "properties" : { + "businessName" : { + "type" : "string" + }, + "businessTaxId" : { + "type" : "string" + } + } + }, + "BusinessesResource" : { + "title" : "BusinessesResource", + "type" : "object", + "properties" : { + "businesses" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/BusinessResource" + } + }, + "legalTaxId" : { + "type" : "string" + }, + "requestDateTime" : { + "type" : "string" + } + } + }, + "CategoriesResource" : { + "title" : "CategoriesResource", + "required" : [ "items" ], + "type" : "object", + "properties" : { + "items" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/CategoryResource" + } + } + } + }, + "CategoryResource" : { + "title" : "CategoryResource", + "type" : "object", + "properties" : { + "code" : { + "type" : "string" + }, + "id" : { + "type" : "string" + }, + "kind" : { + "type" : "string" + }, + "name" : { + "type" : "string" + }, + "origin" : { + "type" : "string", + "description" : "Describes which is the source of data", + "enum" : [ "ANAC", "INFOCAMERE", "IPA", "IVASS", "static" ] + } + } + }, + "GeographicTaxonomyResource" : { + "title" : "GeographicTaxonomyResource", + "type" : "object", + "properties" : { + "code" : { + "type" : "string", + "description" : "Geographic taxonomy unique identifier " + }, + "country" : { + "type" : "string", + "description" : "Geographic taxonomy country" + }, + "country_abbreviation" : { + "type" : "string", + "description" : "Geographic taxonomy country abbreviation" + }, + "desc" : { + "type" : "string", + "description" : "Geographic taxonomy description" + }, + "enabled" : { + "type" : "boolean", + "description" : "Geographic taxonomy enabled", + "example" : false + }, + "istat_code" : { + "type" : "string", + "description" : "Geographic taxonomy istat code" + }, + "province_abbreviation" : { + "type" : "string", + "description" : "Geographic taxonomy province abbreviation" + }, + "province_id" : { + "type" : "string", + "description" : "Geographic taxonomy province unique identifier" + }, + "region_id" : { + "type" : "string", + "description" : "Geographic taxonomy region unique identifier" + } + } + }, + "GetInstitutionsByLegalDto" : { + "title" : "GetInstitutionsByLegalDto", + "type" : "object", + "properties" : { + "filter" : { + "$ref" : "#/components/schemas/GetInstitutionsByLegalFilterDto" + } + } + }, + "GetInstitutionsByLegalFilterDto" : { + "title" : "GetInstitutionsByLegalFilterDto", + "type" : "object", + "properties" : { + "legalTaxId" : { + "type" : "string" + } + } + }, + "InstitutionResource" : { + "title" : "InstitutionResource", + "type" : "object", + "properties" : { + "address" : { + "type" : "string", + "description" : "Institution address" + }, + "aoo" : { + "type" : "string", + "description" : "Area organizzativa omogenea" + }, + "category" : { + "type" : "string", + "description" : "Institution category" + }, + "description" : { + "type" : "string", + "description" : "Institution description" + }, + "digitalAddress" : { + "type" : "string", + "description" : "Institution digital address" + }, + "id" : { + "type" : "string", + "description" : "Semantic id to recognize a party between origins (or externalId)" + }, + "istatCode" : { + "type" : "string", + "description" : "Institution istat Code" + }, + "o" : { + "type" : "string", + "description" : "o" + }, + "origin" : { + "type" : "string", + "description" : "Describes which is the source of data", + "enum" : [ "ANAC", "INFOCAMERE", "IPA", "IVASS", "static" ] + }, + "originId" : { + "type" : "string", + "description" : "Id of the institution from its origin" + }, + "ou" : { + "type" : "string", + "description" : "ou" + }, + "taxCode" : { + "type" : "string", + "description" : "Institution fiscal code" + }, + "zipCode" : { + "type" : "string", + "description" : "Institution zipCode" + } + } + }, + "InstitutionsResource" : { + "title" : "InstitutionsResource", + "required" : [ "count", "items" ], + "type" : "object", + "properties" : { + "count" : { + "type" : "integer", + "format" : "int64" + }, + "items" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/InstitutionResource" + } + } + } + }, + "InsuranceCompaniesResource" : { + "title" : "InsuranceCompaniesResource", + "required" : [ "count", "items" ], + "type" : "object", + "properties" : { + "count" : { + "type" : "integer", + "description" : "list of companies resource size", + "format" : "int64" + }, + "items" : { + "type" : "array", + "description" : "list of insurance companies resource", + "items" : { + "$ref" : "#/components/schemas/InsuranceCompanyResource" + } + } + } + }, + "InsuranceCompanyResource" : { + "title" : "InsuranceCompanyResource", + "type" : "object", + "properties" : { + "address" : { + "type" : "string", + "description" : "Identifies legal address of insurance company" + }, + "description" : { + "type" : "string", + "description" : "insurance company's name" + }, + "digitalAddress" : { + "type" : "string", + "description" : "insurance company's mail address" + }, + "id" : { + "type" : "string", + "description" : "insurance company's unique identifier" + }, + "origin" : { + "type" : "string", + "description" : "Describes which is the source of data", + "enum" : [ "ANAC", "INFOCAMERE", "IPA", "IVASS", "static" ] + }, + "originId" : { + "type" : "string", + "description" : "insurance company's IVASS unique identifier" + }, + "registerType" : { + "type" : "string", + "description" : "Identifies register type for company" + }, + "taxCode" : { + "type" : "string", + "description" : "taxCode of insurance company" + }, + "workType" : { + "type" : "string", + "description" : "Identifies work type for company" + } + } + }, + "InvalidParam" : { + "title" : "InvalidParam", + "required" : [ "name", "reason" ], + "type" : "object", + "properties" : { + "name" : { + "type" : "string", + "description" : "Invalid parameter name." + }, + "reason" : { + "type" : "string", + "description" : "Invalid parameter reason." + } + } + }, + "LegalAddressResponse" : { + "title" : "LegalAddressResponse", + "type" : "object", + "properties" : { + "address" : { + "type" : "string" + }, + "zipCode" : { + "type" : "string" + } + } + }, + "LegalVerificationResult" : { + "title" : "LegalVerificationResult", + "type" : "object", + "properties" : { + "resultCode" : { + "type" : "string" + }, + "resultDetail" : { + "type" : "string" + }, + "verificationResult" : { + "type" : "boolean" + } + } + }, + "Problem" : { + "title" : "Problem", + "required" : [ "status", "title" ], + "type" : "object", + "properties" : { + "detail" : { + "type" : "string", + "description" : "Human-readable description of this specific problem." + }, + "instance" : { + "type" : "string", + "description" : "A URI that describes where the problem occurred." + }, + "invalidParams" : { + "type" : "array", + "description" : "A list of invalid parameters details.", + "items" : { + "$ref" : "#/components/schemas/InvalidParam" + } + }, + "status" : { + "type" : "integer", + "description" : "The HTTP status code.", + "format" : "int32", + "example" : 500 + }, + "title" : { + "type" : "string", + "description" : "Short human-readable summary of the problem." + }, + "type" : { + "type" : "string", + "description" : "A URL to a page with more details regarding the problem." + } + }, + "description" : "A \"problem detail\" as a way to carry machine-readable details of errors (https://datatracker.ietf.org/doc/html/rfc7807)" + }, + "StationResource" : { + "title" : "StationResource", + "type" : "object", + "properties" : { + "anacEnabled" : { + "type" : "boolean", + "description" : "Identifies if ANAC station is enabled", + "example" : false + }, + "anacEngaged" : { + "type" : "boolean", + "description" : "Identifies if ANAC station is engaged", + "example" : false + }, + "description" : { + "type" : "string", + "description" : "station's name" + }, + "digitalAddress" : { + "type" : "string", + "description" : "station's mail address" + }, + "id" : { + "type" : "string", + "description" : "station's unique identifier" + }, + "origin" : { + "type" : "string", + "description" : "Describes which is the source of data", + "enum" : [ "ANAC", "INFOCAMERE", "IPA", "IVASS", "static" ] + }, + "originId" : { + "type" : "string", + "description" : "station's anac unique identifier" + }, + "taxCode" : { + "type" : "string", + "description" : "taxCode of station" + } + } + }, + "StationsResource" : { + "title" : "StationsResource", + "required" : [ "count", "items" ], + "type" : "object", + "properties" : { + "count" : { + "type" : "integer", + "description" : "list of station resource size", + "format" : "int64" + }, + "items" : { + "type" : "array", + "description" : "list of station resource", + "items" : { + "$ref" : "#/components/schemas/StationResource" + } + } + } + }, + "UOResource" : { + "title" : "UOResource", + "type" : "object", + "properties" : { + "cap" : { + "type" : "string" + }, + "codiceCatastaleComune" : { + "type" : "string", + "description" : "UO land registry code" + }, + "codiceComuneISTAT" : { + "type" : "string", + "description" : "UO istat code" + }, + "codiceFiscaleEnte" : { + "type" : "string", + "description" : "UO fiscal code" + }, + "codiceIpa" : { + "type" : "string", + "description" : "UO ipa code" + }, + "codiceUniAoo" : { + "type" : "string", + "description" : "AOO unique identifier, the same of Id" + }, + "codiceUniUo" : { + "type" : "string", + "description" : "UO unique identifier, the same of Id" + }, + "codiceUniUoPadre" : { + "type" : "string", + "description" : "UO parent code" + }, + "cognomeResponsabile" : { + "type" : "string", + "description" : "UO manager lastname" + }, + "dataAggiornamento" : { + "type" : "string", + "description" : "Identifies date of last update on the specific UO" + }, + "dataIstituzione" : { + "type" : "string", + "description" : "Identifies date of first creation for UO" + }, + "denominazioneEnte" : { + "type" : "string", + "description" : "UO parent description" + }, + "descrizioneUo" : { + "type" : "string", + "description" : "UO description" + }, + "fax" : { + "type" : "string", + "description" : "UO fax" + }, + "id" : { + "type" : "string" + }, + "indirizzo" : { + "type" : "string", + "description" : "UO address" + }, + "mail1" : { + "type" : "string" + }, + "mailResponsabile" : { + "type" : "string", + "description" : "UO manager email" + }, + "nomeResponsabile" : { + "type" : "string", + "description" : "UO manager firstname" + }, + "origin" : { + "type" : "string", + "description" : "Describes which is the source of data", + "enum" : [ "ANAC", "INFOCAMERE", "IPA", "IVASS", "static" ] + }, + "telefono" : { + "type" : "string", + "description" : "UO phone number" + }, + "telefonoResponsabile" : { + "type" : "string", + "description" : "UO manager phone number" + }, + "tipoMail1" : { + "type" : "string" + }, + "url" : { + "type" : "string", + "description" : "UO url" + } + } + }, + "UOsResource" : { + "title" : "UOsResource", + "required" : [ "count", "items" ], + "type" : "object", + "properties" : { + "count" : { + "type" : "integer", + "description" : "Total count of items", + "format" : "int64" + }, + "items" : { + "type" : "array", + "description" : "List of UO resource", + "items" : { + "$ref" : "#/components/schemas/UOResource" + } + } + } + } + }, + "securitySchemes" : { + "bearerAuth" : { + "type" : "http", + "description" : "A bearer token in the format of a JWS and conformed to the specifications included in [RFC8725](https://tools.ietf.org/html/RFC8725)", + "scheme" : "bearer", + "bearerFormat" : "JWT" + } + } + } +} \ No newline at end of file diff --git a/apps/onboarding-ms/src/main/openapi/user_registry.json b/apps/onboarding-ms/src/main/openapi/user_registry.json new file mode 100644 index 000000000..c6ac022d9 --- /dev/null +++ b/apps/onboarding-ms/src/main/openapi/user_registry.json @@ -0,0 +1,596 @@ +{ + "openapi" : "3.0.1", + "info" : { + "title" : "pdv-u-user-registry-api", + "description" : "User Registry API documentation", + "version" : "1.0-SNAPSHOT" + }, + "servers" : [ { + "url" : "https://api.uat.pdv.pagopa.it/{basePath}", + "variables" : { + "basePath" : { + "default" : "user-registry/v1" + } + } + } ], + "tags" : [ { + "name" : "user", + "description" : "User operations" + } ], + "paths" : { + "/users" : { + "patch" : { + "tags" : [ "user" ], + "summary" : "Upsert user", + "description" : "Update the given subset fields of an existing user by external id, if not present create a new one", + "operationId" : "saveUsingPATCH", + "requestBody" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/SaveUserDto" + } + } + }, + "required" : true + }, + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/UserId" + } + } + } + }, + "429" : { + "description" : "Too Many Requests", + "content" : { } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "500" : { + "description" : "Internal Server Error", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "409" : { + "description" : "Conflict", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "403" : { + "description" : "Forbidden", + "content" : { } + } + }, + "security" : [ { + "api_key" : [ ] + } ] + } + }, + "/users/{id}" : { + "get" : { + "tags" : [ "user" ], + "summary" : "Find user", + "description" : "Retrieve the user by its internal id", + "operationId" : "findByIdUsingGET", + "parameters" : [ { + "name" : "fl", + "in" : "query", + "description" : "Field list. Subset of fields to be retrieved for the requested resource", + "required" : true, + "schema" : { + "type" : "string" + } + }, { + "name" : "id", + "in" : "path", + "description" : "User internal id", + "required" : true, + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "200" : { + "description" : "OK", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/UserResource" + } + } + } + }, + "429" : { + "description" : "Too Many Requests", + "content" : { } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "500" : { + "description" : "Internal Server Error", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "403" : { + "description" : "Forbidden", + "content" : { } + } + }, + "security" : [ { + "api_key" : [ ] + } ] + }, + "delete" : { + "tags" : [ "user" ], + "summary" : "Delete user", + "description" : "Delete the user by its internal id", + "operationId" : "deleteByIdUsingDELETE", + "parameters" : [ { + "name" : "id", + "in" : "path", + "description" : "User internal id", + "required" : true, + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "429" : { + "description" : "Too Many Requests", + "content" : { } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "500" : { + "description" : "Internal Server Error", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "204" : { + "description" : "No Content", + "content" : { } + }, + "403" : { + "description" : "Forbidden", + "content" : { } + } + }, + "security" : [ { + "api_key" : [ ] + } ] + }, + "patch" : { + "tags" : [ "user" ], + "summary" : "Update user", + "description" : "Update the given subset fields of an existing user by its internal id, if not present an error is returned", + "operationId" : "updateUsingPATCH", + "parameters" : [ { + "name" : "id", + "in" : "path", + "description" : "User internal id", + "required" : true, + "schema" : { + "type" : "string" + } + } ], + "requestBody" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/MutableUserFieldsDto" + } + } + }, + "required" : true + }, + "responses" : { + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "500" : { + "description" : "Internal Server Error", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "204" : { + "description" : "No Content", + "content" : { } + }, + "403" : { + "description" : "Forbidden", + "content" : { } + }, + "404" : { + "description" : "Not Found", + "content" : { } + }, + "429" : { + "description" : "Too Many Requests", + "content" : { } + }, + "409" : { + "description" : "Conflict", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + } + }, + "security" : [ { + "api_key" : [ ] + } ] + } + }, + "/users/search" : { + "post" : { + "tags" : [ "user" ], + "summary" : "Search user", + "description" : "Search a user given its fiscal code", + "operationId" : "searchUsingPOST", + "parameters" : [ { + "name" : "fl", + "in" : "query", + "description" : "Field list. Subset of fields to be retrieved for the requested resource", + "required" : true, + "schema" : { + "type" : "string" + } + } ], + "requestBody" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/UserSearchDto" + } + } + }, + "required" : true + }, + "responses" : { + "404" : { + "description" : "Not Found", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "200" : { + "description" : "OK", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/UserResource" + } + } + } + }, + "429" : { + "description" : "Too Many Requests", + "content" : { } + }, + "400" : { + "description" : "Bad Request", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "500" : { + "description" : "Internal Server Error", + "content" : { + "application/problem+json" : { + "schema" : { + "$ref" : "#/components/schemas/Problem" + } + } + } + }, + "403" : { + "description" : "Forbidden", + "content" : { } + } + }, + "security" : [ { + "api_key" : [ ] + } ] + } + } + }, + "components" : { + "schemas" : { + "UserSearchDto" : { + "title" : "UserSearchDto", + "required" : [ "fiscalCode" ], + "type" : "object", + "properties" : { + "fiscalCode" : { + "type" : "string", + "description" : "User fiscal code" + } + } + }, + "WorkContactResource" : { + "title" : "WorkContactResource", + "type" : "object", + "properties" : { + "email" : { + "$ref" : "#/components/schemas/CertifiableFieldResourceOfstring" + } + } + }, + "CertifiableFieldResourceOfstring" : { + "title" : "CertifiableFieldResourceOfstring", + "required" : [ "certification", "value" ], + "type" : "object", + "properties" : { + "certification" : { + "type" : "string", + "description" : "Certified source of information", + "enum" : [ "NONE", "SPID" ] + }, + "value" : { + "type" : "string", + "description" : "Field value" + } + } + }, + "UserId" : { + "title" : "UserId", + "required" : [ "id" ], + "type" : "object", + "properties" : { + "id" : { + "type" : "string", + "description" : "User internal id", + "format" : "uuid" + } + } + }, + "MutableUserFieldsDto" : { + "title" : "MutableUserFieldsDto", + "type" : "object", + "properties" : { + "birthDate" : { + "$ref" : "#/components/schemas/CertifiableFieldResourceOfLocalDate" + }, + "email" : { + "$ref" : "#/components/schemas/CertifiableFieldResourceOfstring" + }, + "familyName" : { + "$ref" : "#/components/schemas/CertifiableFieldResourceOfstring" + }, + "name" : { + "$ref" : "#/components/schemas/CertifiableFieldResourceOfstring" + }, + "workContacts" : { + "type" : "object", + "additionalProperties" : { + "$ref" : "#/components/schemas/WorkContactResource" + }, + "description" : "User work contacts" + } + } + }, + "CertifiableFieldResourceOfLocalDate" : { + "title" : "CertifiableFieldResourceOfLocalDate", + "required" : [ "certification", "value" ], + "type" : "object", + "properties" : { + "certification" : { + "type" : "string", + "description" : "Certified source of information", + "enum" : [ "NONE", "SPID" ] + }, + "value" : { + "type" : "string", + "description" : "Field value", + "format" : "date" + } + } + }, + "UserResource" : { + "title" : "UserResource", + "required" : [ "id" ], + "type" : "object", + "properties" : { + "birthDate" : { + "$ref" : "#/components/schemas/CertifiableFieldResourceOfLocalDate" + }, + "email" : { + "$ref" : "#/components/schemas/CertifiableFieldResourceOfstring" + }, + "familyName" : { + "$ref" : "#/components/schemas/CertifiableFieldResourceOfstring" + }, + "fiscalCode" : { + "type" : "string", + "description" : "User fiscal code" + }, + "id" : { + "type" : "string", + "description" : "User internal id", + "format" : "uuid" + }, + "name" : { + "$ref" : "#/components/schemas/CertifiableFieldResourceOfstring" + }, + "workContacts" : { + "type" : "object", + "additionalProperties" : { + "$ref" : "#/components/schemas/WorkContactResource" + }, + "description" : "User work contacts" + } + } + }, + "SaveUserDto" : { + "title" : "SaveUserDto", + "required" : [ "fiscalCode" ], + "type" : "object", + "properties" : { + "birthDate" : { + "$ref" : "#/components/schemas/CertifiableFieldResourceOfLocalDate" + }, + "email" : { + "$ref" : "#/components/schemas/CertifiableFieldResourceOfstring" + }, + "familyName" : { + "$ref" : "#/components/schemas/CertifiableFieldResourceOfstring" + }, + "fiscalCode" : { + "type" : "string", + "description" : "User fiscal code" + }, + "name" : { + "$ref" : "#/components/schemas/CertifiableFieldResourceOfstring" + }, + "workContacts" : { + "type" : "object", + "additionalProperties" : { + "$ref" : "#/components/schemas/WorkContactResource" + }, + "description" : "User work contacts" + } + } + }, + "Problem" : { + "title" : "Problem", + "required" : [ "status", "title" ], + "type" : "object", + "properties" : { + "detail" : { + "type" : "string", + "description" : "Human-readable description of this specific problem." + }, + "instance" : { + "type" : "string", + "description" : "A URI that describes where the problem occurred." + }, + "invalidParams" : { + "type" : "array", + "description" : "A list of invalid parameters details.", + "items" : { + "$ref" : "#/components/schemas/InvalidParam" + } + }, + "status" : { + "type" : "integer", + "description" : "The HTTP status code.", + "format" : "int32" + }, + "title" : { + "type" : "string", + "description" : "Short human-readable summary of the problem." + }, + "type" : { + "type" : "string", + "description" : "A URL to a page with more details regarding the problem." + } + }, + "description" : "A \"problem detail\" as a way to carry machine-readable details of errors (https://datatracker.ietf.org/doc/html/rfc7807)" + }, + "InvalidParam" : { + "title" : "InvalidParam", + "required" : [ "name", "reason" ], + "type" : "object", + "properties" : { + "name" : { + "type" : "string", + "description" : "Invalid parameter name." + }, + "reason" : { + "type" : "string", + "description" : "Invalid parameter reason." + } + } + } + }, + "securitySchemes" : { + "api_key" : { + "type" : "apiKey", + "name" : "x-api-key", + "in" : "header" + } + } + } +} \ No newline at end of file diff --git a/onboarding-ms/src/main/resources/META-INF/resources/index.html b/apps/onboarding-ms/src/main/resources/META-INF/resources/index.html similarity index 100% rename from onboarding-ms/src/main/resources/META-INF/resources/index.html rename to apps/onboarding-ms/src/main/resources/META-INF/resources/index.html diff --git a/apps/onboarding-ms/src/main/resources/application.properties b/apps/onboarding-ms/src/main/resources/application.properties new file mode 100644 index 000000000..c165b2c40 --- /dev/null +++ b/apps/onboarding-ms/src/main/resources/application.properties @@ -0,0 +1,84 @@ + +quarkus.http.port=8080 + +#quarkus.smallrye-jwt.blocking-authentication=true + +## JWT +quarkus.http.auth.proactive=false +mp.jwt.verify.publickey=${JWT-PUBLIC-KEY} +mp.jwt.verify.issuer=SPID +#smallrye.jwt.verify.key-format=JWK_BASE64URL + +smallrye.jwt.claims.groups=USER +smallrye.jwt.path.sub=name + +## OPEN API ## +uarkus.smallrye-openapi.info-title=Onboarding API +%dev.quarkus.smallrye-openapi.info-title=Onboarding API (development) +%uat.quarkus.smallrye-openapi.info-title=Onboarding API (test) +quarkus.smallrye-openapi.info-version=1.0.0 + + +quarkus.log.level=INFO +quarkus.http.limits.max-form-attribute-size=4096 + +quarkus.mongodb.connection-string = ${MONGODB-CONNECTION-STRING} +quarkus.mongodb.database = selcOnboarding + +onboarding.institutions-allowed-list=${ONBOARDING_ALLOWED_INSTITUTIONS_PRODUCTS} +onboarding.expiring-date = ${ONBOARDING_EXPIRING_DATE:60} +onboarding.orchestration.enabled = ${ONBOARDING_ORCHESTRATION_ENABLED:true} + +#quarkus.native.resources.includes=publicKey.pem + + +## SIGNATURE + +onboarding-ms.signature.verify-enabled=${SIGNATURE_VALIDATION_ENABLED:true} +onboarding-ms.signature.eu-list-of-trusted-lists-url=https://ec.europa.eu/tools/lotl/eu-lotl.xml +onboarding-ms.signature.eu-official-journal-url=https://eur-lex.europa.eu/legal-content/EN/TXT/?uri=uriserv:OJ.C_.2019.276.01.0001.01.ENG + + +## Rest Client +%local.quarkus.rest-client.logging.scope=request-response +%local.quarkus.rest-client.logging.body-limit=200 + +quarkus.log.category."org.jboss.resteasy.reactive.client.logging".level=DEBUG + +quarkus.openapi-generator.codegen.spec.onboarding_functions_json.mutiny=true +quarkus.openapi-generator.codegen.spec.onboarding_functions_json.additional-model-type-annotations=@lombok.Builder; @lombok.NoArgsConstructor; @lombok.AllArgsConstructor +quarkus.openapi-generator.onboarding_functions_json.auth.api_key.api-key = ${ONBOARDING-FUNCTIONS-API-KEY:example-api-key} +quarkus.openapi-generator.onboarding_functions_json.auth.api_key_complete.api-key = ${START-COMPLETION-FUNCTIONS-API-KEY:example-api-key} +quarkus.rest-client."org.openapi.quarkus.onboarding_functions_json.api.OrchestrationApi".url=${ONBOARDING_FUNCTIONS_URL:http://localhost:8080} + +quarkus.openapi-generator.codegen.spec.user_registry_json.mutiny=true +quarkus.openapi-generator.codegen.spec.user_registry_json.additional-model-type-annotations=@lombok.Builder; @lombok.NoArgsConstructor; @lombok.AllArgsConstructor +quarkus.openapi-generator.user_registry_json.auth.api_key.api-key = ${USER-REGISTRY-API-KEY:example-api-key} +quarkus.rest-client."org.openapi.quarkus.user_registry_json.api.UserApi".url=${USER_REGISTRY_URL:http://localhost:8080} + +quarkus.openapi-generator.codegen.spec.core_json.mutiny=true +quarkus.openapi-generator.codegen.spec.core_json.additional-model-type-annotations=@lombok.Builder; @lombok.NoArgsConstructor; @lombok.AllArgsConstructor +quarkus.openapi-generator.codegen.spec.core_json.enable-security-generation=false +quarkus.openapi-generator.codegen.spec.core_json.additional-api-type-annotations=@org.eclipse.microprofile.rest.client.annotation.RegisterClientHeaders(it.pagopa.selfcare.onboarding.client.auth.AuthenticationPropagationHeadersFactory.class) +quarkus.rest-client."org.openapi.quarkus.core_json.api.OnboardingApi".url=${MS_CORE_URL:http://localhost:8080} + +quarkus.openapi-generator.codegen.spec.party_registry_proxy_json.mutiny=true +quarkus.openapi-generator.codegen.spec.party_registry_proxy_json.additional-model-type-annotations=@lombok.Builder; @lombok.NoArgsConstructor; @lombok.AllArgsConstructor +quarkus.openapi-generator.codegen.spec.party_registry_proxy_json.enable-security-generation=false +quarkus.openapi-generator.codegen.spec.party_registry_proxy_json.additional-api-type-annotations=@org.eclipse.microprofile.rest.client.annotation.RegisterClientHeaders(it.pagopa.selfcare.onboarding.client.auth.AuthenticationPropagationHeadersFactory.class) +quarkus.rest-client."org.openapi.quarkus.party_registry_proxy_json.api.UoApi".url=${MS_PARTY_REGISTRY_URL:http://localhost:8080} +quarkus.rest-client."org.openapi.quarkus.party_registry_proxy_json.api.AooApi".url=${MS_PARTY_REGISTRY_URL:http://localhost:8080} + +## AZURE STORAGE ## + +onboarding-ms.blob-storage.container-product=${STORAGE_CONTAINER_PRODUCT:selc-d-product} +onboarding-ms.blob-storage.filepath-product = products.json +onboarding-ms.blob-storage.connection-string-product = ${BLOB-STORAGE-PRODUCT-CONNECTION-STRING:UseDevelopmentStorage=true;} + +onboarding-ms.blob-storage.path-contracts = parties/docs/ +onboarding-ms.blob-storage.container-contracts=${STORAGE_CONTAINER_CONTRACT:selc-d-contracts-blob} +onboarding-ms.blob-storage.connection-string-contracts = ${BLOB-STORAGE-CONTRACT-CONNECTION-STRING:UseDevelopmentStorage=true;} + +## Jacoco +quarkus.jacoco.includes=it/pagopa/selfcare/onboarding/controller/*,it/pagopa/selfcare/onboarding/service/**,it/pagopa/selfcare/onboarding/repository/** +quarkus.jacoco.data-file=target/jacoco.exec \ No newline at end of file diff --git a/apps/onboarding-ms/src/test/java/it/pagopa/selfcare/onboarding/controller/OnboardingControllerTest.java b/apps/onboarding-ms/src/test/java/it/pagopa/selfcare/onboarding/controller/OnboardingControllerTest.java new file mode 100644 index 000000000..42288e018 --- /dev/null +++ b/apps/onboarding-ms/src/test/java/it/pagopa/selfcare/onboarding/controller/OnboardingControllerTest.java @@ -0,0 +1,372 @@ +package it.pagopa.selfcare.onboarding.controller; + +import io.quarkus.test.InjectMock; +import io.quarkus.test.common.QuarkusTestResource; +import io.quarkus.test.common.http.TestHTTPEndpoint; +import io.quarkus.test.junit.QuarkusTest; +import io.quarkus.test.mongodb.MongoTestResource; +import io.quarkus.test.security.TestSecurity; +import io.restassured.http.ContentType; +import io.smallrye.mutiny.Uni; +import it.pagopa.selfcare.onboarding.common.InstitutionType; +import it.pagopa.selfcare.onboarding.controller.request.*; +import it.pagopa.selfcare.onboarding.controller.response.InstitutionResponse; +import it.pagopa.selfcare.onboarding.controller.response.OnboardingGet; +import it.pagopa.selfcare.onboarding.controller.response.OnboardingGetResponse; +import it.pagopa.selfcare.onboarding.controller.response.OnboardingResponse; +import it.pagopa.selfcare.onboarding.exception.InvalidRequestException; +import it.pagopa.selfcare.onboarding.service.OnboardingService; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import org.mockito.ArgumentCaptor; +import org.mockito.Mockito; + +import java.io.File; +import java.io.IOException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static io.restassured.RestAssured.given; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; + +@QuarkusTest +@TestHTTPEndpoint(OnboardingController.class) +@QuarkusTestResource(MongoTestResource.class) +class OnboardingControllerTest { + + final static OnboardingPspRequest onboardingPspValid; + final static UserRequest userDTO; + final static OnboardingPgRequest onboardingPgValid; + final static OnboardingDefaultRequest onboardingBaseValid; + + final static InstitutionBaseRequest institution; + final static InstitutionPspRequest institutionPsp; + + @InjectMock + OnboardingService onboardingService; + + static { + onboardingBaseValid = new OnboardingDefaultRequest(); + onboardingBaseValid.setProductId("productId"); + + userDTO = new UserRequest(); + userDTO.setTaxCode("taxCode"); + + BillingRequest billingRequest = new BillingRequest(); + billingRequest.setVatNumber("vatNumber"); + + onboardingBaseValid.setUsers(List.of(userDTO)); + onboardingBaseValid.setBilling(billingRequest); + + institution = new InstitutionBaseRequest(); + institution.setInstitutionType(InstitutionType.PT); + institution.setTaxCode("taxCode"); + institution.setDigitalAddress("example@example.it"); + onboardingBaseValid.setInstitution(institution); + + /* PSP */ + onboardingPspValid = new OnboardingPspRequest(); + onboardingPspValid.setProductId("productId"); + onboardingPspValid.setUsers(List.of(userDTO)); + + institutionPsp = new InstitutionPspRequest(); + institutionPsp.setInstitutionType(InstitutionType.PT); + institutionPsp.setTaxCode("taxCode"); + institutionPsp.setDigitalAddress("example@example.it"); + institutionPsp.setPaymentServiceProvider(new PaymentServiceProviderRequest()); + onboardingPspValid.setInstitution(institutionPsp); + + /* PG */ + + onboardingPgValid = new OnboardingPgRequest(); + onboardingPgValid.setTaxCode("code"); + onboardingPgValid.setProductId("productId"); + onboardingPgValid.setDigitalAddress("email@pagopa.it"); + onboardingPgValid.setUsers(List.of(userDTO)); + + } + + @Test + @TestSecurity(user = "userJwt") + void onboarding_shouldNotValidBody() { + + given() + .when() + .body(new OnboardingDefaultRequest()) + .contentType(ContentType.JSON) + .post() + .then() + .statusCode(400); + } + + @ParameterizedTest + @TestSecurity(user = "userJwt") + @ValueSource(strings = {"/psp","/pa"}) + void onboarding_shouldNotValidPspBody(String path) { + + given() + .when() + .body(new OnboardingDefaultRequest()) + .contentType(ContentType.JSON) + .post(path) + .then() + .statusCode(400); + } + + @Test + @TestSecurity(user = "userJwt") + void onboarding() { + + Mockito.when(onboardingService.onboarding(any())) + .thenReturn(Uni.createFrom().item(new OnboardingResponse())); + + given() + .when() + .body(onboardingBaseValid) + .contentType(ContentType.JSON) + .post() + .then() + .statusCode(200); + } + + @Test + @TestSecurity(user = "userJwt") + void onboardingPa() { + + /* PA */ + OnboardingPaRequest onboardingPaValid = new OnboardingPaRequest(); + onboardingPaValid.setProductId("productId"); + + + BillingPaRequest billingPaRequest = new BillingPaRequest(); + billingPaRequest.setRecipientCode("code"); + billingPaRequest.setVatNumber("vat"); + + onboardingPaValid.setUsers(List.of(userDTO)); + onboardingPaValid.setInstitution(institution); + onboardingPaValid.setBilling(billingPaRequest); + + Mockito.when(onboardingService.onboardingPa(any())) + .thenReturn(Uni.createFrom().item(new OnboardingResponse())); + + given() + .when() + .body(onboardingPaValid) + .contentType(ContentType.JSON) + .post("/pa") + .then() + .statusCode(200); + } + + @Test + @TestSecurity(user = "userJwt") + void onboardingPsp() { + + Mockito.when(onboardingService.onboardingPsp(any())) + .thenReturn(Uni.createFrom().item(new OnboardingResponse())); + + given() + .when() + .body(onboardingPspValid) + .contentType(ContentType.JSON) + .post("/psp") + .then() + .statusCode(200); + } + + //@Test + void onboardingPg() { + + given() + .when() + .body(onboardingPgValid) + .contentType(ContentType.JSON) + .post("/pg") + .then() + .statusCode(200); + } + + + @Test + void complete_unauthorized() { + + given() + .when() + .pathParam("tokenId", "actual-token-id") + .contentType(ContentType.MULTIPART) + .put("/{tokenId}/complete") + .then() + .statusCode(401); + } + + @Test + @TestSecurity(user = "userJwt") + void complete() throws IOException { + File testFile = new File("src/test/resources/application.properties"); + String onboardingId = "actual-onboarding-id"; + + when(onboardingService.complete(any(), any())) + .thenReturn(Uni.createFrom().nullItem()); + + given() + .when() + .pathParam("onboardingId", onboardingId) + .contentType(ContentType.MULTIPART) + .multiPart("contract", testFile) + .put("/{onboardingId}/complete") + .then() + .statusCode(204); + + ArgumentCaptor expectedId = ArgumentCaptor.forClass(String.class); + verify(onboardingService, times(1)) + .complete(expectedId.capture(), any()); + assertEquals(expectedId.getValue(), onboardingId); + } + + @Test + @TestSecurity(user = "userJwt") + void deleteOK(){ + String onboardingId = "actual-onboarding-id"; + + when(onboardingService.deleteOnboarding(onboardingId)) + .thenReturn(Uni.createFrom().item(1L)); + + given() + .when() + .pathParam("onboardingId", onboardingId) + .put("/{onboardingId}/delete") + .then() + .statusCode(204); + + ArgumentCaptor expectedId = ArgumentCaptor.forClass(String.class); + verify(onboardingService, times(1)) + .deleteOnboarding(expectedId.capture()); + assertEquals(expectedId.getValue(), onboardingId); + } + + @Test + @TestSecurity(user = "userJwt") + void deleteInvalidOnboardingIdOrOnboardingNotFound(){ + String onboardingId = "actual-onboarding-id"; + + when(onboardingService.deleteOnboarding(onboardingId)) + .thenThrow(InvalidRequestException.class); + + given() + .when() + .pathParam("onboardingId", onboardingId) + .put("/{onboardingId}/delete") + .then() + .statusCode(400); + + ArgumentCaptor expectedId = ArgumentCaptor.forClass(String.class); + verify(onboardingService, times(1)) + .deleteOnboarding(expectedId.capture()); + assertEquals(expectedId.getValue(), onboardingId); + } + + @Test + @TestSecurity(user = "userJwt") + void getOnboarding(){ + OnboardingGetResponse response = getOnboardingGetResponse(); + when(onboardingService.onboardingGet("prod-io", "taxCode", "ACTIVE", "2023-12-01", "2023-12-31", 0, 20)) + .thenReturn(Uni.createFrom().item(response)); + + Map queryParameterMap = getStringStringMap(); + + given() + .when() + .queryParams(queryParameterMap) + .get() + .then() + .statusCode(200); + + verify(onboardingService, times(1)) + .onboardingGet("prod-io", "taxCode", "ACTIVE", "2023-12-01", "2023-12-31", 0, 20); + } + + @Test + @TestSecurity(user = "userJwt") + void getOnboardingById(){ + OnboardingGet onboardingGet = dummyOnboardingGet(); + when(onboardingService.onboardingGet(onboardingGet.getId())) + .thenReturn(Uni.createFrom().item(onboardingGet)); + + given() + .when() + .get("/" + onboardingGet.getId()) + .then() + .statusCode(200); + + verify(onboardingService, times(1)) + .onboardingGet(onboardingGet.getId()); + } + + @Test + @TestSecurity(user = "userJwt") + void getOnboardingByIdWithUserInfo(){ + OnboardingGet onboardingGet = dummyOnboardingGet(); + when(onboardingService.onboardingGetWithUserInfo(onboardingGet.getId())) + .thenReturn(Uni.createFrom().item(onboardingGet)); + + given() + .when() + .get("/" + onboardingGet.getId() + "/withUserInfo") + .then() + .statusCode(200); + + verify(onboardingService, times(1)) + .onboardingGetWithUserInfo(onboardingGet.getId()); + } + + + @Test + @TestSecurity(user = "userJwt") + void getOnboardingPending(){ + OnboardingGet onboardingGet = dummyOnboardingGet(); + when(onboardingService.onboardingPending(onboardingGet.getId())) + .thenReturn(Uni.createFrom().item(onboardingGet)); + + given() + .when() + .get("/{onboardingId}/pending", onboardingGet.getId()) + .then() + .statusCode(200); + + verify(onboardingService, times(1)) + .onboardingPending(onboardingGet.getId()); + } + private static Map getStringStringMap() { + Map queryParameterMap = new HashMap<>(); + queryParameterMap.put("productId","prod-io"); + queryParameterMap.put("taxCode","taxCode"); + queryParameterMap.put("from","2023-12-01"); + queryParameterMap.put("to","2023-12-31"); + queryParameterMap.put("status","ACTIVE"); + return queryParameterMap; + } + + private static OnboardingGetResponse getOnboardingGetResponse() { + OnboardingGet onboarding = dummyOnboardingGet(); + OnboardingGetResponse response = new OnboardingGetResponse(); + response.setCount(1L); + response.setItems(List.of(onboarding)); + return response; + } + + private static OnboardingGet dummyOnboardingGet() { + OnboardingGet onboarding = new OnboardingGet(); + onboarding.setId("id"); + onboarding.setStatus("ACTIVE"); + onboarding.setProductId("prod-io"); + InstitutionResponse institutionResponse = new InstitutionResponse(); + institutionResponse.setTaxCode("taxCode"); + onboarding.setInstitution(institutionResponse); + return onboarding; + } + +} \ No newline at end of file diff --git a/apps/onboarding-ms/src/test/java/it/pagopa/selfcare/onboarding/service/OnboardingServiceDefaultTest.java b/apps/onboarding-ms/src/test/java/it/pagopa/selfcare/onboarding/service/OnboardingServiceDefaultTest.java new file mode 100644 index 000000000..7cae44fd1 --- /dev/null +++ b/apps/onboarding-ms/src/test/java/it/pagopa/selfcare/onboarding/service/OnboardingServiceDefaultTest.java @@ -0,0 +1,1135 @@ +package it.pagopa.selfcare.onboarding.service; + +import io.quarkus.mongodb.panache.common.reactive.ReactivePanacheUpdate; +import io.quarkus.mongodb.panache.reactive.ReactivePanacheQuery; +import io.quarkus.panache.mock.PanacheMock; +import io.quarkus.test.InjectMock; +import io.quarkus.test.common.QuarkusTestResource; +import io.quarkus.test.junit.QuarkusTest; +import io.quarkus.test.mongodb.MongoTestResource; +import io.quarkus.test.vertx.RunOnVertxContext; +import io.quarkus.test.vertx.UniAsserter; +import io.smallrye.mutiny.Uni; +import io.smallrye.mutiny.helpers.test.UniAssertSubscriber; +import it.pagopa.selfcare.azurestorage.AzureBlobClient; +import it.pagopa.selfcare.onboarding.common.InstitutionType; +import it.pagopa.selfcare.onboarding.common.OnboardingStatus; +import it.pagopa.selfcare.onboarding.common.PartyRole; +import it.pagopa.selfcare.onboarding.controller.request.*; +import it.pagopa.selfcare.onboarding.controller.response.InstitutionResponse; +import it.pagopa.selfcare.onboarding.controller.response.OnboardingGet; +import it.pagopa.selfcare.onboarding.controller.response.OnboardingGetResponse; +import it.pagopa.selfcare.onboarding.controller.response.UserResponse; +import it.pagopa.selfcare.onboarding.entity.Institution; +import it.pagopa.selfcare.onboarding.entity.Onboarding; +import it.pagopa.selfcare.onboarding.entity.Token; +import it.pagopa.selfcare.onboarding.entity.User; +import it.pagopa.selfcare.onboarding.exception.InvalidRequestException; +import it.pagopa.selfcare.onboarding.exception.OnboardingNotAllowedException; +import it.pagopa.selfcare.onboarding.exception.ResourceNotFoundException; +import it.pagopa.selfcare.onboarding.util.InstitutionPaSubunitType; +import it.pagopa.selfcare.product.entity.Product; +import it.pagopa.selfcare.product.entity.ProductRole; +import it.pagopa.selfcare.product.entity.ProductRoleInfo; +import it.pagopa.selfcare.product.exception.ProductNotFoundException; +import it.pagopa.selfcare.product.service.ProductService; +import jakarta.inject.Inject; +import jakarta.ws.rs.WebApplicationException; +import jakarta.ws.rs.core.Response; +import org.bson.Document; +import org.bson.types.ObjectId; +import org.eclipse.microprofile.rest.client.inject.RestClient; +import org.jboss.resteasy.reactive.ClientWebApplicationException; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.openapi.quarkus.core_json.api.OnboardingApi; +import org.openapi.quarkus.onboarding_functions_json.api.OrchestrationApi; +import org.openapi.quarkus.onboarding_functions_json.model.OrchestrationResponse; +import org.openapi.quarkus.party_registry_proxy_json.api.AooApi; +import org.openapi.quarkus.party_registry_proxy_json.api.UoApi; +import org.openapi.quarkus.party_registry_proxy_json.model.AOOResource; +import org.openapi.quarkus.party_registry_proxy_json.model.UOResource; +import org.openapi.quarkus.user_registry_json.api.UserApi; +import org.openapi.quarkus.user_registry_json.model.CertifiableFieldResourceOfstring; +import org.openapi.quarkus.user_registry_json.model.UserId; +import org.openapi.quarkus.user_registry_json.model.UserResource; + +import java.io.File; +import java.time.LocalDateTime; +import java.util.*; + +import static it.pagopa.selfcare.onboarding.common.ProductId.PROD_INTEROP; +import static it.pagopa.selfcare.onboarding.service.OnboardingServiceDefault.USERS_FIELD_TAXCODE; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.*; + + +@QuarkusTest +@QuarkusTestResource(MongoTestResource.class) +class OnboardingServiceDefaultTest { + + @Inject + OnboardingServiceDefault onboardingService; + + @InjectMock + @RestClient + UserApi userRegistryApi; + + @InjectMock + ProductService productService; + + @InjectMock + @RestClient + AooApi aooApi; + + @InjectMock + @RestClient + UoApi uoApi; + + + @InjectMock + AzureBlobClient azureBlobClient; + + @InjectMock + SignatureService signatureService; + + @InjectMock + @RestClient + OnboardingApi onboardingApi; + + @InjectMock + @RestClient + OrchestrationApi orchestrationApi; + + final static UserRequest manager = UserRequest.builder() + .name("name") + .surname("surname") + .taxCode("taxCode") + .role(PartyRole.MANAGER) + .build(); + + final static UserResource managerResource; + + final static File testFile = new File("src/test/resources/application.properties"); + + static { + managerResource = new UserResource(); + managerResource.setId(UUID.randomUUID()); + managerResource.setName(new CertifiableFieldResourceOfstring() + .value(manager.getName()) + .certification(CertifiableFieldResourceOfstring.CertificationEnum.NONE)); + managerResource.setFamilyName(new CertifiableFieldResourceOfstring() + .value(manager.getSurname()) + .certification(CertifiableFieldResourceOfstring.CertificationEnum.NONE)); + } + + void mockPersistOnboarding(UniAsserter asserter) { + asserter.execute(() -> PanacheMock.mock(Onboarding.class)); + asserter.execute(() -> when(Onboarding.persist(any(Onboarding.class), any())) + .thenAnswer(arg -> { + Onboarding onboarding = (Onboarding) arg.getArguments()[0]; + onboarding.setId(ObjectId.get()); + return Uni.createFrom().nullItem(); + })); + } + + @Test + @RunOnVertxContext + void onboarding_shouldThrowExceptionIfRoleNotValid(UniAsserter asserter) { + OnboardingDefaultRequest onboardingDefaultRequest = new OnboardingDefaultRequest(); + onboardingDefaultRequest.setInstitution(new InstitutionBaseRequest()); + onboardingDefaultRequest.setUsers(List.of(UserRequest.builder() + .taxCode("taxCode") + .role(PartyRole.OPERATOR) + .build())); + + mockPersistOnboarding(asserter); + + asserter.assertFailedWith(() -> onboardingService.onboarding(onboardingDefaultRequest), + InvalidRequestException.class); + } + + @Test + @RunOnVertxContext + void onboardingPa_throwExceptionIfUserFoundedAndProductThrowException(UniAsserter asserter) { + OnboardingPaRequest onboardingRequest = new OnboardingPaRequest(); + UserRequest manager = UserRequest.builder() + .name("currentName") + .surname("currentSurname") + .taxCode("currentTaxCode") + .role(PartyRole.MANAGER) + .build(); + + onboardingRequest.setUsers(List.of(manager)); + onboardingRequest.setProductId("productId"); + onboardingRequest.setInstitution(new InstitutionBaseRequest()); + + mockPersistOnboarding(asserter); + + asserter.execute(() -> when(userRegistryApi.searchUsingPOST(any(), any())) + .thenReturn(Uni.createFrom().item(managerResource))); + + asserter.execute(() -> when(productService.getProductIsValid(onboardingRequest.getProductId())) + .thenThrow(IllegalArgumentException.class)); + + asserter.assertFailedWith(() -> onboardingService.onboardingPa(onboardingRequest), OnboardingNotAllowedException.class); + } + + + @Test + @RunOnVertxContext + void onboarding_throwExceptionIfUserFoundedAndProductIsNotValid(UniAsserter asserter) { + OnboardingPaRequest onboardingRequest = new OnboardingPaRequest(); + onboardingRequest.setUsers(List.of(manager)); + onboardingRequest.setProductId("productId"); + onboardingRequest.setInstitution(new InstitutionBaseRequest()); + + mockPersistOnboarding(asserter); + + asserter.execute(() -> when(userRegistryApi.searchUsingPOST(any(),any())) + .thenReturn(Uni.createFrom().item(managerResource))); + + asserter.execute(() -> when(productService.getProductIsValid(onboardingRequest.getProductId())) + .thenThrow(ProductNotFoundException.class)); + + asserter.assertFailedWith(() -> onboardingService.onboardingPa(onboardingRequest), OnboardingNotAllowedException.class); + + //asserter.execute(() -> verify(userRegistryApi, times(1)) + //.searchUsingPOST(any(),any())); + //asserter.execute(() -> verify(productService, times(1)) + //.getProductIsValid(onboardingRequest.getProductId())); + //asserter.execute(() -> verifyNoMoreInteractions(userRegistryApi)); + } + + @Test + @RunOnVertxContext + void onboarding_throwExceptionIfUserFoundedAndProductIsNotDelegable(UniAsserter asserter) { + OnboardingPaRequest onboardingRequest = new OnboardingPaRequest(); + onboardingRequest.setUsers(List.of(manager)); + onboardingRequest.setProductId("productId"); + InstitutionBaseRequest institutionBaseRequest = new InstitutionBaseRequest(); + institutionBaseRequest.setInstitutionType(InstitutionType.PT); + onboardingRequest.setInstitution(institutionBaseRequest); + + mockPersistOnboarding(asserter); + + asserter.execute(() -> when(userRegistryApi.searchUsingPOST(any(),any())) + .thenReturn(Uni.createFrom().item(managerResource))); + + Product productResource = new Product(); + productResource.setDelegable(Boolean.FALSE); + asserter.execute(() -> when(productService.getProductIsValid(onboardingRequest.getProductId())) + .thenReturn(productResource)); + + asserter.assertFailedWith(() -> onboardingService.onboardingPa(onboardingRequest), OnboardingNotAllowedException.class); + + /*verify(userRegistryApi, times(1)) + .searchUsingPOST(any(),any()); + verify(productService, times(1)) + .getProductIsValid(onboardingRequest.getProductId()); + verifyNoMoreInteractions(userRegistryApi);*/ + } + + @Test + @RunOnVertxContext + void onboarding_throwExceptionIfUserFoundedAndProductRoleIsNotValid(UniAsserter asserter) { + OnboardingPaRequest onboardingRequest = new OnboardingPaRequest(); + onboardingRequest.setUsers(List.of(manager)); + onboardingRequest.setProductId("productId"); + InstitutionBaseRequest institutionBaseRequest = new InstitutionBaseRequest(); + institutionBaseRequest.setInstitutionType(InstitutionType.PG); + onboardingRequest.setInstitution(institutionBaseRequest); + + mockPersistOnboarding(asserter); + + asserter.execute(() -> when(userRegistryApi.searchUsingPOST(any(),any())) + .thenReturn(Uni.createFrom().item(managerResource))); + + Product productResource = new Product(); + productResource.setRoleMappings(new HashMap<>()); + asserter.execute(() -> when(productService.getProductIsValid(onboardingRequest.getProductId())) + .thenReturn(productResource)); + + asserter.assertFailedWith(() -> onboardingService.onboardingPa(onboardingRequest), OnboardingNotAllowedException.class); + + /*verify(userRegistryApi, times(1)) + .searchUsingPOST(any(),any()); + verify(productService, times(1)) + .getProductIsValid(onboardingRequest.getProductId()); + verifyNoMoreInteractions(userRegistryApi);*/ + } + + @Test + @RunOnVertxContext + void onboardingPa_throwExceptionIfUserFoundedAndProductParentRoleIsNotValid(UniAsserter asserter) { + OnboardingPaRequest onboardingRequest = new OnboardingPaRequest(); + onboardingRequest.setUsers(List.of(manager)); + onboardingRequest.setProductId("productId"); + onboardingRequest.setInstitution(new InstitutionBaseRequest()); + + mockPersistOnboarding(asserter); + + asserter.execute(() -> when(userRegistryApi.searchUsingPOST(any(),any())) + .thenReturn(Uni.createFrom().item(managerResource))); + + Product productResource = new Product(); + Product productParent = new Product(); + productParent.setRoleMappings(new HashMap<>()); + productResource.setParent(productParent); + asserter.execute(() -> when(productService.getProductIsValid(onboardingRequest.getProductId())) + .thenReturn(productResource)); + + asserter.assertFailedWith(() -> onboardingService.onboardingPa(onboardingRequest), OnboardingNotAllowedException.class); + + /*verify(userRegistryApi, times(1)) + .searchUsingPOST(any(),any()); + verify(productService, times(1)) + .getProductIsValid(onboardingRequest.getProductId()); + verifyNoMoreInteractions(userRegistryApi)*/; + } + + @Test + @RunOnVertxContext + void onboardingPa_throwExceptionIfProductAlreadyOnboarded(UniAsserter asserter) { + OnboardingPaRequest onboardingRequest = new OnboardingPaRequest(); + onboardingRequest.setUsers(List.of(manager)); + onboardingRequest.setProductId("productId"); + InstitutionBaseRequest institutionBaseRequest = new InstitutionBaseRequest(); + institutionBaseRequest.setInstitutionType(InstitutionType.PA); + institutionBaseRequest.setTaxCode("taxCode"); + onboardingRequest.setInstitution(institutionBaseRequest); + + mockPersistOnboarding(asserter); + + asserter.execute(() -> when(userRegistryApi.searchUsingPOST(any(),any())) + .thenReturn(Uni.createFrom().item(managerResource))); + + + Product productResource = createDummyProduct(onboardingRequest.getProductId(),false); + + asserter.execute(() -> when(productService.getProductIsValid(onboardingRequest.getProductId())) + .thenReturn(productResource)); + + asserter.execute(() -> when(onboardingApi.verifyOnboardingInfoUsingHEAD(institutionBaseRequest.getTaxCode(), onboardingRequest.getProductId(), institutionBaseRequest.getSubunitCode())) + .thenReturn(Uni.createFrom().item(Response.noContent().build()))); + + asserter.assertFailedWith(() -> onboardingService.onboardingPa(onboardingRequest), InvalidRequestException.class); + + /*verify(userRegistryApi, times(1)) + .searchUsingPOST(any(),any()); + verify(onboardingApi, times(1)) + .verifyOnboardingInfoUsingHEAD(institutionBaseRequest.getTaxCode(), onboardingRequest.getProductId(), institutionBaseRequest.getSubunitCode()); + verifyNoMoreInteractions(userRegistryApi);*/ + } + + @Test + @RunOnVertxContext + void onboarding_Onboarding_addParentDescritpionForAooOrUo_Aoo(UniAsserter asserter) { + UserRequest manager = UserRequest.builder() + .name("name") + .taxCode(managerResource.getFiscalCode()) + .role(PartyRole.MANAGER) + .build(); + + OnboardingDefaultRequest request = new OnboardingDefaultRequest(); + request.setUsers(List.of(manager)); + request.setProductId(PROD_INTEROP.getValue()); + InstitutionBaseRequest institutionBaseRequest = new InstitutionBaseRequest(); + institutionBaseRequest.setInstitutionType(InstitutionType.PA); + institutionBaseRequest.setTaxCode("taxCode"); + institutionBaseRequest.setSubunitType(InstitutionPaSubunitType.AOO); + institutionBaseRequest.setSubunitCode("SubunitCode"); + request.setInstitution(institutionBaseRequest); + + mockPersistOnboarding(asserter); + + asserter.execute(() -> when(userRegistryApi.updateUsingPATCH(any(),any())) + .thenReturn(Uni.createFrom().item(Response.noContent().build()))); + + mockSimpleSearchPOSTAndPersist(asserter); + mockSimpleProductValidAssert(request.getProductId(), false, asserter); + mockVerifyOnboardingNotFound(asserter); + + AOOResource aooResource = new AOOResource(); + aooResource.setDenominazioneEnte("TEST"); + asserter.execute(() -> when(aooApi.findByUnicodeUsingGET(institutionBaseRequest.getSubunitCode(), null)) + .thenReturn(Uni.createFrom().item(aooResource))); + + asserter.assertThat(() -> onboardingService.onboarding(request), Assertions::assertNotNull); + + asserter.execute(() -> { + PanacheMock.verify(Onboarding.class).persist(any(Onboarding.class), any()); + PanacheMock.verify(Onboarding.class).persistOrUpdate(any(List.class)); + PanacheMock.verifyNoMoreInteractions(Onboarding.class); + }); + } + + @Test + @RunOnVertxContext + void onboarding_Onboarding_addParentDescritpionForAooOrUo_AooNotFound(UniAsserter asserter) { + UserRequest manager = UserRequest.builder() + .name("name") + .taxCode(managerResource.getFiscalCode()) + .role(PartyRole.MANAGER) + .build(); + + OnboardingDefaultRequest request = new OnboardingDefaultRequest(); + request.setUsers(List.of(manager)); + request.setProductId(PROD_INTEROP.getValue()); + InstitutionBaseRequest institutionBaseRequest = new InstitutionBaseRequest(); + institutionBaseRequest.setInstitutionType(InstitutionType.PA); + institutionBaseRequest.setTaxCode("taxCode"); + institutionBaseRequest.setSubunitType(InstitutionPaSubunitType.AOO); + institutionBaseRequest.setSubunitCode("SubunitCode"); + request.setInstitution(institutionBaseRequest); + + mockPersistOnboarding(asserter); + + asserter.execute(() -> when(userRegistryApi.updateUsingPATCH(any(),any())) + .thenReturn(Uni.createFrom().item(Response.noContent().build()))); + + mockSimpleSearchPOSTAndPersist(asserter); + mockSimpleProductValidAssert(request.getProductId(), false, asserter); + mockVerifyOnboardingNotFound(asserter); + + AOOResource aooResource = new AOOResource(); + aooResource.setDenominazioneEnte("TEST"); + WebApplicationException exception = mock(WebApplicationException.class); + Response response = mock(Response.class); + when(response.getStatus()).thenReturn(404); + when(exception.getResponse()).thenReturn(response); + asserter.execute(() -> when(aooApi.findByUnicodeUsingGET(institutionBaseRequest.getSubunitCode(), null)) + .thenReturn(Uni.createFrom().failure(exception))); + + asserter.assertFailedWith(() -> onboardingService.onboarding(request), ResourceNotFoundException.class); + + asserter.execute(() -> { + PanacheMock.verify(Onboarding.class).persist(any(Onboarding.class), any()); + PanacheMock.verifyNoMoreInteractions(Onboarding.class); + }); + } + + @Test + @RunOnVertxContext + void onboarding_Onboarding_addParentDescritpionForAooOrUo_AooException(UniAsserter asserter) { + UserRequest manager = UserRequest.builder() + .name("name") + .taxCode(managerResource.getFiscalCode()) + .role(PartyRole.MANAGER) + .build(); + + OnboardingDefaultRequest request = new OnboardingDefaultRequest(); + request.setUsers(List.of(manager)); + request.setProductId(PROD_INTEROP.getValue()); + InstitutionBaseRequest institutionBaseRequest = new InstitutionBaseRequest(); + institutionBaseRequest.setInstitutionType(InstitutionType.PA); + institutionBaseRequest.setTaxCode("taxCode"); + institutionBaseRequest.setSubunitType(InstitutionPaSubunitType.AOO); + institutionBaseRequest.setSubunitCode("SubunitCode"); + request.setInstitution(institutionBaseRequest); + + mockPersistOnboarding(asserter); + + asserter.execute(() -> when(userRegistryApi.updateUsingPATCH(any(),any())) + .thenReturn(Uni.createFrom().item(Response.noContent().build()))); + + mockSimpleSearchPOSTAndPersist(asserter); + mockSimpleProductValidAssert(request.getProductId(), false, asserter); + mockVerifyOnboardingNotFound(asserter); + + AOOResource aooResource = new AOOResource(); + aooResource.setDenominazioneEnte("TEST"); + WebApplicationException exception = mock(WebApplicationException.class); + Response response = mock(Response.class); + when(response.getStatus()).thenReturn(500); + when(exception.getResponse()).thenReturn(response); + asserter.execute(() -> when(aooApi.findByUnicodeUsingGET(institutionBaseRequest.getSubunitCode(), null)) + .thenReturn(Uni.createFrom().failure(exception))); + + asserter.assertFailedWith(() -> onboardingService.onboarding(request), WebApplicationException.class); + + asserter.execute(() -> { + PanacheMock.verify(Onboarding.class).persist(any(Onboarding.class), any()); + PanacheMock.verifyNoMoreInteractions(Onboarding.class); + }); + } + + @Test + @RunOnVertxContext + void onboarding_Onboarding_addParentDescritpionForAooOrUo_Uo(UniAsserter asserter) { + UserRequest manager = UserRequest.builder() + .name("name") + .taxCode(managerResource.getFiscalCode()) + .role(PartyRole.MANAGER) + .build(); + + OnboardingDefaultRequest request = new OnboardingDefaultRequest(); + request.setUsers(List.of(manager)); + request.setProductId(PROD_INTEROP.getValue()); + InstitutionBaseRequest institutionBaseRequest = new InstitutionBaseRequest(); + institutionBaseRequest.setInstitutionType(InstitutionType.PA); + institutionBaseRequest.setTaxCode("taxCode"); + institutionBaseRequest.setSubunitType(InstitutionPaSubunitType.UO); + institutionBaseRequest.setSubunitCode("SubunitCode"); + request.setInstitution(institutionBaseRequest); + + mockPersistOnboarding(asserter); + + asserter.execute(() -> when(userRegistryApi.updateUsingPATCH(any(),any())) + .thenReturn(Uni.createFrom().item(Response.noContent().build()))); + + mockSimpleSearchPOSTAndPersist(asserter); + mockSimpleProductValidAssert(request.getProductId(), false, asserter); + mockVerifyOnboardingNotFound(asserter); + + UOResource uoResource = new UOResource(); + uoResource.setDenominazioneEnte("TEST"); + asserter.execute(() -> when(uoApi.findByUnicodeUsingGET1(institutionBaseRequest.getSubunitCode(), null)) + .thenReturn(Uni.createFrom().item(uoResource))); + + asserter.assertThat(() -> onboardingService.onboarding(request), Assertions::assertNotNull); + + asserter.execute(() -> { + PanacheMock.verify(Onboarding.class).persist(any(Onboarding.class), any()); + PanacheMock.verify(Onboarding.class).persistOrUpdate(any(List.class)); + PanacheMock.verifyNoMoreInteractions(Onboarding.class); + }); + } + + @Test + @RunOnVertxContext + void onboarding_Onboarding_addParentDescritpionForAooOrUo_UoNotFound(UniAsserter asserter) { + UserRequest manager = UserRequest.builder() + .name("name") + .taxCode(managerResource.getFiscalCode()) + .role(PartyRole.MANAGER) + .build(); + + OnboardingDefaultRequest request = new OnboardingDefaultRequest(); + request.setUsers(List.of(manager)); + request.setProductId(PROD_INTEROP.getValue()); + InstitutionBaseRequest institutionBaseRequest = new InstitutionBaseRequest(); + institutionBaseRequest.setInstitutionType(InstitutionType.PA); + institutionBaseRequest.setTaxCode("taxCode"); + institutionBaseRequest.setSubunitType(InstitutionPaSubunitType.UO); + institutionBaseRequest.setSubunitCode("SubunitCode"); + request.setInstitution(institutionBaseRequest); + + mockPersistOnboarding(asserter); + + asserter.execute(() -> when(userRegistryApi.updateUsingPATCH(any(),any())) + .thenReturn(Uni.createFrom().item(Response.noContent().build()))); + + mockSimpleSearchPOSTAndPersist(asserter); + mockSimpleProductValidAssert(request.getProductId(), false, asserter); + mockVerifyOnboardingNotFound(asserter); + + WebApplicationException exception = mock(WebApplicationException.class); + Response response = mock(Response.class); + when(response.getStatus()).thenReturn(404); + when(exception.getResponse()).thenReturn(response); + + UOResource uoResource = new UOResource(); + uoResource.setDenominazioneEnte("TEST"); + asserter.execute(() -> when(uoApi.findByUnicodeUsingGET1(institutionBaseRequest.getSubunitCode(), null)) + .thenReturn(Uni.createFrom().failure(exception))); + + asserter.assertFailedWith(() -> onboardingService.onboarding(request), ResourceNotFoundException.class); + + asserter.execute(() -> { + PanacheMock.verify(Onboarding.class).persist(any(Onboarding.class), any()); + PanacheMock.verifyNoMoreInteractions(Onboarding.class); + }); + } + + @Test + @RunOnVertxContext + void onboarding_Onboarding_addParentDescritpionForAooOrUo_UoException(UniAsserter asserter) { + UserRequest manager = UserRequest.builder() + .name("name") + .taxCode(managerResource.getFiscalCode()) + .role(PartyRole.MANAGER) + .build(); + + OnboardingDefaultRequest request = new OnboardingDefaultRequest(); + request.setUsers(List.of(manager)); + request.setProductId(PROD_INTEROP.getValue()); + InstitutionBaseRequest institutionBaseRequest = new InstitutionBaseRequest(); + institutionBaseRequest.setInstitutionType(InstitutionType.PA); + institutionBaseRequest.setTaxCode("taxCode"); + institutionBaseRequest.setSubunitType(InstitutionPaSubunitType.UO); + institutionBaseRequest.setSubunitCode("SubunitCode"); + request.setInstitution(institutionBaseRequest); + + mockPersistOnboarding(asserter); + + asserter.execute(() -> when(userRegistryApi.updateUsingPATCH(any(),any())) + .thenReturn(Uni.createFrom().item(Response.noContent().build()))); + + mockSimpleSearchPOSTAndPersist(asserter); + mockSimpleProductValidAssert(request.getProductId(), false, asserter); + mockVerifyOnboardingNotFound(asserter); + + WebApplicationException exception = mock(WebApplicationException.class); + Response response = mock(Response.class); + when(response.getStatus()).thenReturn(500); + when(exception.getResponse()).thenReturn(response); + + UOResource uoResource = new UOResource(); + uoResource.setDenominazioneEnte("TEST"); + asserter.execute(() -> when(uoApi.findByUnicodeUsingGET1(institutionBaseRequest.getSubunitCode(), null)) + .thenReturn(Uni.createFrom().failure(exception))); + + asserter.assertFailedWith(() -> onboardingService.onboarding(request), WebApplicationException.class); + + asserter.execute(() -> { + PanacheMock.verify(Onboarding.class).persist(any(Onboarding.class), any()); + PanacheMock.verifyNoMoreInteractions(Onboarding.class); + }); + } + + void mockSimpleSearchPOSTAndPersist(UniAsserter asserter){ + + asserter.execute(() -> PanacheMock.mock(Onboarding.class)); + + asserter.execute(() -> when(userRegistryApi.searchUsingPOST(any(),any())) + .thenReturn(Uni.createFrom().item(managerResource))); + + asserter.execute(() -> when(Onboarding.persistOrUpdate(any(List.class))) + .thenAnswer(arg -> { + List onboardings = (List) arg.getArguments()[0]; + onboardings.get(0).setId(ObjectId.get()); + return Uni.createFrom().nullItem(); + })); + + asserter.execute(() -> when(orchestrationApi.apiStartOnboardingOrchestrationGet(any())) + .thenReturn(Uni.createFrom().item(new OrchestrationResponse()))); + } + @Test + @RunOnVertxContext + void onboardingSa_whenUserFoundedAndWillNotUpdate(UniAsserter asserter) { + OnboardingSaRequest onboardingRequest = new OnboardingSaRequest(); + onboardingRequest.setUsers(List.of(manager)); + onboardingRequest.setProductId("productId"); + InstitutionBaseRequest institutionBaseRequest = new InstitutionBaseRequest(); + institutionBaseRequest.setInstitutionType(InstitutionType.SA); + onboardingRequest.setInstitution(institutionBaseRequest); + + mockPersistOnboarding(asserter); + mockSimpleSearchPOSTAndPersist(asserter); + mockSimpleProductValidAssert(onboardingRequest.getProductId(), false, asserter); + mockVerifyOnboardingNotFound(asserter); + + asserter.assertThat(() -> onboardingService.onboardingSa(onboardingRequest), Assertions::assertNotNull); + + asserter.execute(() -> { + PanacheMock.verify(Onboarding.class).persist(any(Onboarding.class), any()); + PanacheMock.verify(Onboarding.class).persistOrUpdate(any(List.class)); + PanacheMock.verifyNoMoreInteractions(Onboarding.class); + }); + } + + + void mockSimpleProductValidAssert(String productId, boolean hasParent, UniAsserter asserter) { + Product productResource = createDummyProduct(productId,hasParent); + + asserter.execute(() -> when(productService.getProductIsValid(productId)) + .thenReturn(productResource)); + } + + Product createDummyProduct(String productId, boolean hasParent) { + Product productResource = new Product(); + productResource.setId(productId); + Map roleMapping = new HashMap<>(); + ProductRole productRole = new ProductRole(); + productRole.setCode("admin"); + ProductRoleInfo productRoleInfo = new ProductRoleInfo(); + productRoleInfo.setRoles(List.of(productRole)); + roleMapping.put(manager.getRole(), productRoleInfo); + productResource.setRoleMappings(roleMapping); + + if(hasParent) { + Product parent = new Product(); + parent.setId("productParentId"); + Map roleParentMapping = new HashMap<>(); + roleParentMapping.put(manager.getRole(), productRoleInfo); + parent.setRoleMappings(roleParentMapping); + + productResource.setParent(parent); + } + + return productResource; + } + + + @Test + @RunOnVertxContext + void onboardingPsp_whenUserFoundedAndWillNotUpdate(UniAsserter asserter) { + OnboardingPspRequest onboardingRequest = new OnboardingPspRequest(); + onboardingRequest.setUsers(List.of(manager)); + onboardingRequest.setProductId("productId"); + InstitutionPspRequest institutionPspRequest = new InstitutionPspRequest(); + institutionPspRequest.setInstitutionType(InstitutionType.PSP); + onboardingRequest.setInstitution(institutionPspRequest); + + mockPersistOnboarding(asserter); + mockSimpleSearchPOSTAndPersist(asserter); + mockSimpleProductValidAssert(onboardingRequest.getProductId(), false, asserter); + mockVerifyOnboardingNotFound(asserter); + + asserter.assertThat(() -> onboardingService.onboardingPsp(onboardingRequest), Assertions::assertNotNull); + + asserter.execute(() -> { + PanacheMock.verify(Onboarding.class).persist(any(Onboarding.class), any()); + PanacheMock.verify(Onboarding.class).persistOrUpdate(any(List.class)); + PanacheMock.verifyNoMoreInteractions(Onboarding.class); + }); + } + + + @Test + @RunOnVertxContext + void onboardingPsp_whenUserFoundedAndWillNotUpdateAndProductHasParent(UniAsserter asserter) { + OnboardingPspRequest onboardingRequest = new OnboardingPspRequest(); + onboardingRequest.setUsers(List.of(manager)); + onboardingRequest.setProductId("productId"); + InstitutionPspRequest institutionPspRequest = new InstitutionPspRequest(); + institutionPspRequest.setInstitutionType(InstitutionType.PSP); + onboardingRequest.setInstitution(institutionPspRequest); + + mockPersistOnboarding(asserter); + mockSimpleSearchPOSTAndPersist(asserter); + mockSimpleProductValidAssert(onboardingRequest.getProductId(), true, asserter); + mockVerifyOnboardingNotFound(asserter); + + asserter.assertThat(() -> onboardingService.onboardingPsp(onboardingRequest), Assertions::assertNotNull); + + asserter.execute(() -> { + PanacheMock.verify(Onboarding.class).persist(any(Onboarding.class), any()); + PanacheMock.verify(Onboarding.class).persistOrUpdate(any(List.class)); + PanacheMock.verifyNoMoreInteractions(Onboarding.class); + }); + } + + + @Test + @RunOnVertxContext + void onboarding_whenUserFoundedAndWillNotUpdate(UniAsserter asserter) { + OnboardingDefaultRequest onboardingDefaultRequest = new OnboardingDefaultRequest(); + onboardingDefaultRequest.setUsers(List.of(manager)); + onboardingDefaultRequest.setProductId("productId"); + onboardingDefaultRequest.setInstitution(new InstitutionBaseRequest()); + + mockPersistOnboarding(asserter); + mockSimpleSearchPOSTAndPersist(asserter); + mockSimpleProductValidAssert(onboardingDefaultRequest.getProductId(), false, asserter); + mockVerifyOnboardingNotFound(asserter); + + asserter.assertThat(() -> onboardingService.onboarding(onboardingDefaultRequest), Assertions::assertNotNull); + + asserter.execute(() -> { + PanacheMock.verify(Onboarding.class).persist(any(Onboarding.class), any()); + PanacheMock.verify(Onboarding.class).persistOrUpdate(any(List.class)); + PanacheMock.verifyNoMoreInteractions(Onboarding.class); + }); + } + + @Test + @RunOnVertxContext + void onboarding_whenUserFoundedAndWillUpdate(UniAsserter asserter) { + UserRequest manager = UserRequest.builder() + .name("name") + .taxCode(managerResource.getFiscalCode()) + .role(PartyRole.MANAGER) + .build(); + + OnboardingDefaultRequest request = new OnboardingDefaultRequest(); + request.setUsers(List.of(manager)); + request.setProductId(PROD_INTEROP.getValue()); + InstitutionPspRequest institutionPspRequest = new InstitutionPspRequest(); + institutionPspRequest.setInstitutionType(InstitutionType.GSP); + request.setInstitution(institutionPspRequest); + + mockPersistOnboarding(asserter); + + asserter.execute(() -> when(userRegistryApi.updateUsingPATCH(any(),any())) + .thenReturn(Uni.createFrom().item(Response.noContent().build()))); + + mockSimpleSearchPOSTAndPersist(asserter); + mockSimpleProductValidAssert(request.getProductId(), false, asserter); + mockVerifyOnboardingNotFound(asserter); + + asserter.assertThat(() -> onboardingService.onboarding(request), Assertions::assertNotNull); + + asserter.execute(() -> { + PanacheMock.verify(Onboarding.class).persist(any(Onboarding.class), any()); + PanacheMock.verify(Onboarding.class).persistOrUpdate(any(List.class)); + PanacheMock.verifyNoMoreInteractions(Onboarding.class); + }); + } + + @Test + @RunOnVertxContext + void onboarding_whenUserNotFoundedAndWillSave(UniAsserter asserter) { + OnboardingDefaultRequest request = new OnboardingDefaultRequest(); + request.setUsers(List.of(manager)); + request.setProductId("productId"); + request.setInstitution(new InstitutionBaseRequest()); + final UUID createUserId = UUID.randomUUID(); + + mockPersistOnboarding(asserter); + + asserter.execute(() -> PanacheMock.mock(Onboarding.class)); + + asserter.execute(() -> when(userRegistryApi.searchUsingPOST(any(),any())) + .thenReturn(Uni.createFrom().failure(new WebApplicationException(404)))); + + asserter.execute(() -> when(userRegistryApi.saveUsingPATCH(any())) + .thenReturn(Uni.createFrom().item(UserId.builder().id(createUserId).build()))); + + mockSimpleProductValidAssert(request.getProductId(), false, asserter); + mockVerifyOnboardingNotFound(asserter); + + asserter.execute(() -> when(Onboarding.persistOrUpdate(any(List.class))) + .thenAnswer(arg -> { + List onboardings = (List) arg.getArguments()[0]; + onboardings.get(0).setId(ObjectId.get()); + return Uni.createFrom().nullItem(); + })); + + asserter.assertThat(() -> onboardingService.onboarding(request), Assertions::assertNotNull); + + asserter.execute(() -> { + PanacheMock.verify(Onboarding.class).persist(any(Onboarding.class), any()); + PanacheMock.verify(Onboarding.class).persistOrUpdate(any(List.class)); + PanacheMock.verifyNoMoreInteractions(Onboarding.class); + }); + } + + + @Test + @RunOnVertxContext + void onboarding_shouldThrowExceptionIfUserRegistryFails(UniAsserter asserter) { + OnboardingDefaultRequest onboardingDefaultRequest = new OnboardingDefaultRequest(); + onboardingDefaultRequest.setInstitution(new InstitutionBaseRequest()); + onboardingDefaultRequest.setUsers(List.of(manager)); + + mockPersistOnboarding(asserter); + + asserter.execute(() -> when(userRegistryApi.searchUsingPOST(any(),any())) + .thenReturn(Uni.createFrom().failure(new WebApplicationException()))); + + asserter.assertFailedWith(() -> onboardingService.onboarding(onboardingDefaultRequest), WebApplicationException.class); + + /*verify(userRegistryApi, times(1)) + .searchUsingPOST(any(),any()); + verifyNoMoreInteractions(userRegistryApi);*/ + } + + void mockVerifyOnboardingNotFound(UniAsserter asserter){ + asserter.execute(() -> when(onboardingApi.verifyOnboardingInfoUsingHEAD(any(), any(), any())) + .thenReturn(Uni.createFrom().failure(new ClientWebApplicationException(404)))); + } + + @Test + @RunOnVertxContext + void completeWithoutSignatureVerification_shouldThrowExceptionWhenExpired(UniAsserter asserter) { + Onboarding onboarding = createDummyOnboarding(); + onboarding.setExpiringDate(LocalDateTime.now().minusDays(1)); + asserter.execute(() -> PanacheMock.mock(Onboarding.class)); + asserter.execute(() -> when(Onboarding.findByIdOptional(any())) + .thenReturn(Uni.createFrom().item(Optional.of(onboarding)))); + + asserter.assertFailedWith(() -> onboardingService.completeWithoutSignatureVerification(onboarding.getId().toHexString(), null), + InvalidRequestException.class); + } + + @Test + @RunOnVertxContext + void completeWithoutSignatureVerification(UniAsserter asserter) { + Onboarding onboarding = createDummyOnboarding(); + asserter.execute(() -> PanacheMock.mock(Onboarding.class)); + asserter.execute(() -> when(Onboarding.findByIdOptional(any())) + .thenReturn(Uni.createFrom().item(Optional.of(onboarding)))); + + mockFindToken(asserter, onboarding.getId().toHexString()); + + mockSimpleProductValidAssert(onboarding.getProductId(), false, asserter); + mockVerifyOnboardingNotFound(asserter); + + final String filepath = "upload-file-path"; + when(azureBlobClient.uploadFile(any(),any(),any())).thenReturn(filepath); + mockUpdateToken(asserter, filepath); + + asserter.assertThat(() -> onboardingService.completeWithoutSignatureVerification(onboarding.getId().toHexString(), testFile), + Assertions::assertNotNull); + + } + + @Test + @RunOnVertxContext + void complete_shouldThrowExceptionWhenSignatureFail(UniAsserter asserter) { + Onboarding onboarding = createDummyOnboarding(); + asserter.execute(() -> PanacheMock.mock(Onboarding.class)); + asserter.execute(() -> when(Onboarding.findByIdOptional(any())) + .thenReturn(Uni.createFrom().item(Optional.of(onboarding)))); + + mockFindToken(asserter, onboarding.getId().toHexString()); + + //Mock find manager fiscal code + String actualUseUid = onboarding.getUsers().get(0).getId(); + UserResource actualUserResource = new UserResource(); + actualUserResource.setFiscalCode("ACTUAL-FISCAL-CODE"); + asserter.execute(() -> when(userRegistryApi.findByIdUsingGET(USERS_FIELD_TAXCODE, actualUseUid)) + .thenReturn(Uni.createFrom().item(actualUserResource))); + + //Mock contract signature fail + asserter.execute(() -> doThrow(InvalidRequestException.class) + .when(signatureService) + .verifySignature(any(),any(),any())); + + asserter.assertFailedWith(() -> onboardingService.complete(onboarding.getId().toHexString(), testFile), + InvalidRequestException.class); + } + + + @Test + @RunOnVertxContext + void complete(UniAsserter asserter) { + Onboarding onboarding = createDummyOnboarding(); + asserter.execute(() -> PanacheMock.mock(Onboarding.class)); + asserter.execute(() -> when(Onboarding.findByIdOptional(any())) + .thenReturn(Uni.createFrom().item(Optional.of(onboarding)))); + + mockFindToken(asserter, onboarding.getId().toHexString()); + + //Mock find manager fiscal code + String actualUseUid = onboarding.getUsers().get(0).getId(); + UserResource actualUserResource = new UserResource(); + actualUserResource.setFiscalCode("ACTUAL-FISCAL-CODE"); + asserter.execute(() -> when(userRegistryApi.findByIdUsingGET(USERS_FIELD_TAXCODE, actualUseUid)) + .thenReturn(Uni.createFrom().item(actualUserResource))); + + //Mock contract signature fail + asserter.execute(() -> doNothing() + .when(signatureService) + .verifySignature(any(),any(),any())); + + mockSimpleProductValidAssert(onboarding.getProductId(), false, asserter); + mockVerifyOnboardingNotFound(asserter); + + final String filepath = "upload-file-path"; + when(azureBlobClient.uploadFile(any(),any(),any())).thenReturn(filepath); + mockUpdateToken(asserter, filepath); + + asserter.assertThat(() -> onboardingService.complete(onboarding.getId().toHexString(), testFile), + Assertions::assertNotNull); + } + @Test + void testOnboardingGet() { + int page = 0, size = 3; + Onboarding onboarding = createDummyOnboarding(); + mockFindOnboarding(onboarding); + OnboardingGetResponse getResponse = getOnboardingGetResponse(onboarding.getId()); + UniAssertSubscriber subscriber = onboardingService + .onboardingGet("prod-io", null, null, "2023-11-10", "2021-12-10", page,size) + .subscribe() + .withSubscriber(UniAssertSubscriber.create()); + + subscriber.assertCompleted().assertItem(getResponse); + } + + private static OnboardingGetResponse getOnboardingGetResponse(ObjectId id) { + OnboardingGet onboarding = new OnboardingGet(); + onboarding.setId(id.toString()); + onboarding.setProductId("prod-id"); + UserResponse user = new UserResponse(); + user.setId("actual-user-id"); + user.setRole(PartyRole.MANAGER); + onboarding.setUsers(List.of(user)); + InstitutionResponse institutionResponse = new InstitutionResponse(); + onboarding.setInstitution(institutionResponse); + OnboardingGetResponse response = new OnboardingGetResponse(); + response.setCount(1L); + response.setItems(List.of(onboarding)); + return response; + } + + private void mockFindOnboarding(Onboarding onboarding) { + ReactivePanacheQuery query = mock(ReactivePanacheQuery.class); + ReactivePanacheQuery queryPage = mock(ReactivePanacheQuery.class); + PanacheMock.mock(Onboarding.class); + when(Onboarding.find(any(Document.class),any(Document.class))).thenReturn(query); + when(Onboarding.find(any(Document.class),eq(null))).thenReturn(query); + when(query.page(anyInt(),anyInt())).thenReturn(queryPage); + when(queryPage.list()).thenReturn(Uni.createFrom().item(List.of(onboarding))); + when(query.count()).thenReturn(Uni.createFrom().item(1L)); + } + + private void mockFindToken(UniAsserter asserter, String onboardingId) { + Token token = new Token(); + token.setChecksum("actual-checksum"); + asserter.execute(() -> PanacheMock.mock(Token.class)); + asserter.execute(() -> when(Token.list("onboardingId", onboardingId)) + .thenReturn(Uni.createFrom().item(List.of(token)))); + } + + private void mockUpdateToken(UniAsserter asserter, String filepath) { + + //Mock token updat + asserter.execute(() -> PanacheMock.mock(Token.class)); + ReactivePanacheUpdate panacheUpdate = mock(ReactivePanacheUpdate.class); + asserter.execute(() -> when(panacheUpdate.where("contractSigned", filepath)) + .thenReturn(Uni.createFrom().item(1L))); + asserter.execute(() -> when(Token.update(anyString(),any(Object[].class))) + .thenReturn(panacheUpdate)); + } + + private Onboarding createDummyOnboarding() { + Onboarding onboarding = new Onboarding(); + onboarding.setId(ObjectId.get()); + onboarding.setProductId("prod-id"); + + Institution institution = new Institution(); + onboarding.setInstitution(institution); + + User user = new User(); + user.setId("actual-user-id"); + user.setRole(PartyRole.MANAGER); + onboarding.setUsers(List.of(user)); + return onboarding; + } + + @Test + void testOnboardingUpdateStatusOK() { + String onboardingId = "655df045dc52ea5f37c80955"; + mockUpdateOnboarding(onboardingId, 1L); + UniAssertSubscriber subscriber = onboardingService + .deleteOnboarding(onboardingId) + .subscribe() + .withSubscriber(UniAssertSubscriber.create()); + + subscriber.assertCompleted().assertItem(1L); + } + + @Test + void testOnboardingUpdateStatusInvalidOnboardingId() { + String onboardingId = "123456"; + UniAssertSubscriber subscriber = onboardingService + .deleteOnboarding(onboardingId) + .subscribe() + .withSubscriber(UniAssertSubscriber.create()); + + subscriber.assertFailedWith(InvalidRequestException.class, "Given onboardingId [123456] has wrong format"); + } + + @Test + void testOnboardingDeleteOnboardingNotFoundOrAlreadyDeleted() { + String onboardingId = "655df045dc52ea5f37c80955"; + mockUpdateOnboarding(onboardingId, 0L); + UniAssertSubscriber subscriber = onboardingService + .deleteOnboarding(onboardingId) + .subscribe() + .withSubscriber(UniAssertSubscriber.create()); + + subscriber.assertFailedWith(InvalidRequestException.class, "Onboarding with id 655df045dc52ea5f37c80955 not found or already deleted"); + } + + private void mockUpdateOnboarding(String onboardingId, Long updatedItemCount) { + ReactivePanacheUpdate query = mock(ReactivePanacheUpdate.class); + PanacheMock.mock(Onboarding.class); + when(Onboarding.update(Onboarding.Fields.status.name(), OnboardingStatus.DELETED)).thenReturn(query); + when(query.where("_id", onboardingId)).thenReturn(Uni.createFrom().item(updatedItemCount)); + } + + @Test + void onboardingGet() { + Onboarding onboarding = createDummyOnboarding(); + PanacheMock.mock(Onboarding.class); + when(Onboarding.findByIdOptional(any())) + .thenReturn(Uni.createFrom().item(Optional.of(onboarding))); + + UniAssertSubscriber subscriber = onboardingService + .onboardingGet(onboarding.getId().toHexString()) + .subscribe() + .withSubscriber(UniAssertSubscriber.create()); + + OnboardingGet actual = subscriber.assertCompleted().awaitItem().getItem(); + Assertions.assertNotNull(actual); + Assertions.assertEquals(onboarding.getId().toHexString(), actual.getId()); + Assertions.assertEquals(onboarding.getProductId(), actual.getProductId()); + } + + @Test + void onboardingGet_shouldResourceNotFound() { + PanacheMock.mock(Onboarding.class); + when(Onboarding.findByIdOptional(any())) + .thenReturn(Uni.createFrom().item(Optional.empty())); + + UniAssertSubscriber subscriber = onboardingService + .onboardingGet(ObjectId.get().toHexString()) + .subscribe() + .withSubscriber(UniAssertSubscriber.create()) + .assertFailedWith(ResourceNotFoundException.class); + } + + @Test + void onboardingPending() { + Onboarding onboarding = createDummyOnboarding(); + onboarding.setStatus(OnboardingStatus.PENDING); + PanacheMock.mock(Onboarding.class); + when(Onboarding.findByIdOptional(any())) + .thenReturn(Uni.createFrom().item(Optional.of(onboarding))); + + UniAssertSubscriber subscriber = onboardingService + .onboardingPending(onboarding.getId().toHexString()) + .subscribe() + .withSubscriber(UniAssertSubscriber.create()); + + OnboardingGet actual = subscriber.assertCompleted().awaitItem().getItem(); + Assertions.assertNotNull(actual); + Assertions.assertEquals(onboarding.getId().toHexString(), actual.getId()); + Assertions.assertEquals(onboarding.getProductId(), actual.getProductId()); + } + + @Test + void onboardingPending_shouldResourceNotFound() { + Onboarding onboarding = createDummyOnboarding(); + PanacheMock.mock(Onboarding.class); + when(Onboarding.findByIdOptional(any())) + .thenReturn(Uni.createFrom().item(Optional.of(onboarding))); + + UniAssertSubscriber subscriber = onboardingService + .onboardingPending(ObjectId.get().toHexString()) + .subscribe() + .withSubscriber(UniAssertSubscriber.create()) + .assertFailedWith(ResourceNotFoundException.class); + } + + @Test + void onboardingGetWithUserInfo() { + Onboarding onboarding = createDummyOnboarding(); + PanacheMock.mock(Onboarding.class); + when(Onboarding.findByIdOptional(any())) + .thenReturn(Uni.createFrom().item(Optional.of(onboarding))); + + when(userRegistryApi.findByIdUsingGET(anyString(), anyString())) + .thenReturn(Uni.createFrom().item(managerResource)); + + UniAssertSubscriber subscriber = onboardingService + .onboardingGetWithUserInfo(onboarding.getId().toHexString()) + .subscribe() + .withSubscriber(UniAssertSubscriber.create()); + + OnboardingGet actual = subscriber.assertCompleted().awaitItem().getItem(); + Assertions.assertNotNull(actual); + Assertions.assertEquals(onboarding.getId().toHexString(), actual.getId()); + Assertions.assertEquals(onboarding.getProductId(), actual.getProductId()); + Assertions.assertEquals(onboarding.getUsers().size(), actual.getUsers().size()); + UserResponse actualUser = actual.getUsers().get(0); + Assertions.assertEquals(actualUser.getName(), managerResource.getName().getValue()); + Assertions.assertEquals(actualUser.getSurname(), managerResource.getFamilyName().getValue()); + } + +} diff --git a/apps/onboarding-ms/src/test/java/it/pagopa/selfcare/onboarding/service/SignatureServiceDefaultTest.java b/apps/onboarding-ms/src/test/java/it/pagopa/selfcare/onboarding/service/SignatureServiceDefaultTest.java new file mode 100644 index 000000000..4e02eb38f --- /dev/null +++ b/apps/onboarding-ms/src/test/java/it/pagopa/selfcare/onboarding/service/SignatureServiceDefaultTest.java @@ -0,0 +1,590 @@ +package it.pagopa.selfcare.onboarding.service; + +import eu.europa.esig.dss.detailedreport.jaxb.XmlDetailedReport; +import eu.europa.esig.dss.diagnostic.OrphanCertificateTokenWrapper; +import eu.europa.esig.dss.diagnostic.jaxb.*; +import eu.europa.esig.dss.enumerations.DigestAlgorithm; +import eu.europa.esig.dss.enumerations.EncryptionAlgorithm; +import eu.europa.esig.dss.enumerations.MaskGenerationFunction; +import eu.europa.esig.dss.model.DigestDocument; +import eu.europa.esig.dss.simplereport.jaxb.XmlSimpleReport; +import eu.europa.esig.dss.validation.AdvancedSignature; +import eu.europa.esig.dss.validation.SignedDocumentValidator; +import eu.europa.esig.dss.validation.TokenIdentifierProvider; +import eu.europa.esig.dss.validation.reports.Reports; +import eu.europa.esig.dss.validation.timestamp.DetachedTimestampValidator; +import eu.europa.esig.dss.xades.validation.XAdESSignature; +import eu.europa.esig.validationreport.jaxb.ValidationReportType; +import io.quarkus.test.common.QuarkusTestResource; +import io.quarkus.test.junit.QuarkusTest; +import io.quarkus.test.mongodb.MongoTestResource; +import it.pagopa.selfcare.onboarding.exception.InvalidRequestException; +import jakarta.inject.Inject; +import org.apache.batik.anim.dom.BindableElement; +import org.apache.batik.anim.dom.SVG12DOMImplementation; +import org.apache.batik.anim.dom.SVG12OMDocument; +import org.apache.batik.dom.GenericDocumentType; +import org.junit.jupiter.api.Test; + +import java.math.BigInteger; +import java.sql.Date; +import java.time.LocalDate; +import java.time.ZoneOffset; +import java.util.ArrayList; +import java.util.List; + +import static it.pagopa.selfcare.onboarding.util.GenericError.INVALID_DOCUMENT_SIGNATURE; +import static it.pagopa.selfcare.onboarding.util.GenericError.TAX_CODE_NOT_FOUND_IN_SIGNATURE; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; + + +@QuarkusTest +@QuarkusTestResource(MongoTestResource.class) +class SignatureServiceDefaultTest { + + + @Inject + SignatureServiceDefault signatureService; + + /** + * Method under test: {@link SignatureServiceDefault#isDocumentSigned(SignedDocumentValidator)} + */ + @Test + void isDocumentSigned_shouldThrowInvalidRequestException() { + assertThrows(InvalidRequestException.class, + () -> signatureService.isDocumentSigned(new DetachedTimestampValidator(new DigestDocument()))); + } + + /** + * Method under test: {@link SignatureServiceDefault#isDocumentSigned(SignedDocumentValidator)} + */ + @Test + void testIsDocumentSigned3() { + DetachedTimestampValidator detachedTimestampValidator = mock(DetachedTimestampValidator.class); + when(detachedTimestampValidator.getSignatures()).thenReturn(new ArrayList<>()); + assertThrows(InvalidRequestException.class, () -> signatureService.isDocumentSigned(detachedTimestampValidator)); + verify(detachedTimestampValidator).getSignatures(); + } + + /** + * Method under test: {@link SignatureServiceDefault#isDocumentSigned(SignedDocumentValidator)} + */ + @Test + void testIsDocumentSigned4() { + ArrayList advancedSignatureList = new ArrayList<>(); + GenericDocumentType dt = new GenericDocumentType("Qualified Name", "42", "42"); + + advancedSignatureList.add(new XAdESSignature( + new BindableElement("Prefix", new SVG12OMDocument(dt, new SVG12DOMImplementation()), "Ns", "Ln"))); + DetachedTimestampValidator detachedTimestampValidator = mock(DetachedTimestampValidator.class); + when(detachedTimestampValidator.getSignatures()).thenReturn(advancedSignatureList); + signatureService.isDocumentSigned(detachedTimestampValidator); + verify(detachedTimestampValidator).getSignatures(); + } + + @Test + void validateDocument_shouldThrowInvalidRequestException() { + SignedDocumentValidator signedDocumentValidator = mock(SignedDocumentValidator.class); + when(signedDocumentValidator.validateDocument()).thenThrow(new RuntimeException()); + assertThrows(InvalidRequestException.class, () -> signatureService.validateDocument(signedDocumentValidator)); + } + + + /** + * Method under test: {@link SignatureServiceDefault#verifySignatureForm(SignedDocumentValidator)} + */ + @Test + void testVerifySignatureForm() { + DetachedTimestampValidator detachedTimestampValidator = new DetachedTimestampValidator(new DigestDocument()); + assertDoesNotThrow(() -> signatureService.verifySignatureForm(detachedTimestampValidator)); + assertTrue(detachedTimestampValidator.getSignatures().isEmpty()); + } + + + /** + * Method under test: {@link SignatureServiceDefault#verifySignatureForm(SignedDocumentValidator)} + */ + @Test + void verifySignatureForm_withTokenIdentifierProvider() { + DetachedTimestampValidator detachedTimestampValidator = new DetachedTimestampValidator(new DigestDocument()); + detachedTimestampValidator.setTokenIdentifierProvider(mock(TokenIdentifierProvider.class)); + assertDoesNotThrow(() -> signatureService.verifySignatureForm(detachedTimestampValidator)); + assertTrue(detachedTimestampValidator.getSignatures().isEmpty()); + } + + /** + * Method under test: {@link SignatureServiceDefault#verifySignatureForm(SignedDocumentValidator)} + */ + @Test + void verifySignatureForm_shouldSignaturesNotEmpty() { + SignedDocumentValidator signedDocumentValidator = mock(SignedDocumentValidator.class); + when(signedDocumentValidator.getSignatures()).thenReturn(new ArrayList<>()); + assertDoesNotThrow(() -> signatureService.verifySignatureForm(signedDocumentValidator)); + verify(signedDocumentValidator).getSignatures(); + } + + /** + * Method under test: {@link SignatureServiceDefault#verifySignatureForm(SignedDocumentValidator)} + */ + @Test + void testVerifySignatureForm6() { + ArrayList advancedSignatureList = new ArrayList<>(); + GenericDocumentType dt = new GenericDocumentType("VALID", "42", "42"); + + advancedSignatureList.add(new XAdESSignature( + new BindableElement("VALID", new SVG12OMDocument(dt, new SVG12DOMImplementation()), "VALID", "VALID"))); + SignedDocumentValidator signedDocumentValidator = mock(SignedDocumentValidator.class); + when(signedDocumentValidator.getSignatures()).thenReturn(advancedSignatureList); + assertThrows(InvalidRequestException.class, () -> signatureService.verifySignatureForm(signedDocumentValidator), + "Only CAdES signature form is admitted. Invalid signatures forms detected: [XAdES]"); + verify(signedDocumentValidator).getSignatures(); + } + + /** + * Method under test: {@link SignatureServiceDefault#verifySignatureForm(SignedDocumentValidator)} + */ + @Test + void testVerifySignatureForm8() { + ArrayList advancedSignatureList = new ArrayList<>(); + GenericDocumentType dt = new GenericDocumentType("Qualified Name", "42", "42"); + + advancedSignatureList.add(new XAdESSignature( + new BindableElement("Prefix", new SVG12OMDocument(dt, new SVG12DOMImplementation()), "Ns", "Ln"))); + advancedSignatureList.addAll(new ArrayList<>()); + GenericDocumentType dt1 = new GenericDocumentType("VALID", "42", "42"); + + advancedSignatureList.add(new XAdESSignature( + new BindableElement("VALID", new SVG12OMDocument(dt1, new SVG12DOMImplementation()), "VALID", "VALID"))); + SignedDocumentValidator signedDocumentValidator = mock(SignedDocumentValidator.class); + when(signedDocumentValidator.getSignatures()).thenReturn(advancedSignatureList); + assertThrows(InvalidRequestException.class, () -> signatureService.verifySignatureForm(signedDocumentValidator), + "Only CAdES signature form is admitted. Invalid signatures forms detected: [XAdES, XAdES]"); + verify(signedDocumentValidator).getSignatures(); + } + + /** + * Method under test: {@link SignatureServiceDefault#verifySignature(Reports)} + */ + @Test + void testVerifySignature() { + XmlDiagnosticData diagnosticDataJaxb = new XmlDiagnosticData(); + XmlDetailedReport detailedReport = new XmlDetailedReport(); + XmlSimpleReport simpleReport = new XmlSimpleReport(); + Reports reports = new Reports(diagnosticDataJaxb, detailedReport, simpleReport, new ValidationReportType()); + + assertThrows(InvalidRequestException.class, () -> signatureService.verifySignature(reports), INVALID_DOCUMENT_SIGNATURE.getMessage()); + } + + /** + * Method under test: {@link SignatureServiceDefault#verifySignature(Reports)} + */ + @Test + void testVerifySignature2() { + XmlDiagnosticData diagnosticDataJaxb = new XmlDiagnosticData(); + XmlDetailedReport detailedReport = new XmlDetailedReport(); + assertThrows(InvalidRequestException.class, () -> signatureService + .verifySignature(new Reports(diagnosticDataJaxb, detailedReport, new XmlSimpleReport(), null)), INVALID_DOCUMENT_SIGNATURE.getMessage()); + } + + /** + * Method under test: {@link SignatureServiceDefault#verifySignature(Reports)} + */ + @Test + void testVerifySignature3() { + XmlDiagnosticData diagnosticDataJaxb = new XmlDiagnosticData(); + XmlDetailedReport detailedReport = new XmlDetailedReport(); + XmlSimpleReport simpleReport = new XmlSimpleReport(); + Reports reports = new Reports(diagnosticDataJaxb, detailedReport, simpleReport, new ValidationReportType()); + assertThrows(InvalidRequestException.class, () -> signatureService.verifySignature(reports), INVALID_DOCUMENT_SIGNATURE.getMessage()); + + List expectedSignatureValidationReport = reports.getDiagnosticData() + .getAllOrphanCertificateObjects(); + assertEquals(expectedSignatureValidationReport, + reports.getEtsiValidationReportJaxb().getSignatureValidationReport()); + } + + /** + * Method under test: {@link SignatureServiceDefault#verifySignature(Reports)} + */ + @Test + void testVerifySignature4() { + XmlDiagnosticData xmlDiagnosticData = new XmlDiagnosticData(); + xmlDiagnosticData.setValidationDate(mock(Date.class)); + XmlDetailedReport detailedReport = new XmlDetailedReport(); + XmlSimpleReport simpleReport = new XmlSimpleReport(); + Reports reports = new Reports(xmlDiagnosticData, detailedReport, simpleReport, new ValidationReportType()); + + assertThrows(InvalidRequestException.class, () -> signatureService.verifySignature(reports), INVALID_DOCUMENT_SIGNATURE.getMessage()); + } + + /** + * Method under test: {@link SignatureServiceDefault#verifySignature(Reports)} + */ + @Test + void testVerifySignature5() { + XmlDiagnosticData diagnosticDataJaxb = mock(XmlDiagnosticData.class); + XmlDetailedReport detailedReport = new XmlDetailedReport(); + XmlSimpleReport simpleReport = new XmlSimpleReport(); + Reports reports = new Reports(diagnosticDataJaxb, detailedReport, simpleReport, new ValidationReportType()); + + assertThrows(InvalidRequestException.class, () -> signatureService.verifySignature(reports), INVALID_DOCUMENT_SIGNATURE.getMessage()); + + List expectedSignatureValidationReport = reports.getDiagnosticData() + .getAllOrphanCertificateObjects(); + assertEquals(expectedSignatureValidationReport, + reports.getEtsiValidationReportJaxb().getSignatureValidationReport()); + } + + /** + * Method under test: {@link SignatureServiceDefault#verifyDigest(SignedDocumentValidator, String)} + */ + @Test + void testVerifyDigest() { + DetachedTimestampValidator detachedTimestampValidator = new DetachedTimestampValidator(new DigestDocument()); + assertDoesNotThrow(() -> signatureService.verifyDigest(detachedTimestampValidator, "Checksum")); + assertTrue(detachedTimestampValidator.getSignatures().isEmpty()); + } + + /** + * Method under test: {@link SignatureServiceDefault#verifyDigest(SignedDocumentValidator, String)} + */ + @Test + void testVerifyDigest2() { + DetachedTimestampValidator detachedTimestampValidator = new DetachedTimestampValidator( + mock(DigestDocument.class)); + assertDoesNotThrow(() -> signatureService.verifyDigest(detachedTimestampValidator, "Checksum")); + assertTrue(detachedTimestampValidator.getSignatures().isEmpty()); + } + + /** + * Method under test: {@link SignatureServiceDefault#verifyDigest(SignedDocumentValidator, String)} + */ + @Test + void testVerifyDigest3() { + DetachedTimestampValidator detachedTimestampValidator = new DetachedTimestampValidator(new DigestDocument()); + detachedTimestampValidator.setTokenIdentifierProvider(mock(TokenIdentifierProvider.class)); + assertDoesNotThrow(() -> signatureService.verifyDigest(detachedTimestampValidator, "Checksum")); + assertTrue(detachedTimestampValidator.getSignatures().isEmpty()); + } + + + /** + * Method under test: {@link SignatureServiceDefault#verifyDigest(SignedDocumentValidator, String)} + */ + @Test + void testVerifyDigest5() { + DetachedTimestampValidator detachedTimestampValidator = mock(DetachedTimestampValidator.class); + when(detachedTimestampValidator.getSignatures()).thenReturn(new ArrayList<>()); + assertDoesNotThrow(() -> signatureService.verifyDigest(detachedTimestampValidator, "Checksum")); + verify(detachedTimestampValidator).getSignatures(); + } + + /** + * Method under test: {@link SignatureServiceDefault#verifyDigest(SignedDocumentValidator, String)} + */ + @Test + void testVerifyDigest6() { + ArrayList advancedSignatureList = new ArrayList<>(); + GenericDocumentType dt = new GenericDocumentType("VALID", "42", "42"); + + advancedSignatureList.add(new XAdESSignature( + new BindableElement("VALID", new SVG12OMDocument(dt, new SVG12DOMImplementation()), "VALID", "VALID"))); + DetachedTimestampValidator detachedTimestampValidator = mock(DetachedTimestampValidator.class); + when(detachedTimestampValidator.getOriginalDocuments((String) any())).thenReturn(new ArrayList<>()); + when(detachedTimestampValidator.getSignatures()).thenReturn(advancedSignatureList); + assertThrows(InvalidRequestException.class, () -> signatureService.verifyDigest(detachedTimestampValidator, "Checksum"), "Invalid file digest"); + verify(detachedTimestampValidator).getSignatures(); + verify(detachedTimestampValidator).getOriginalDocuments((String) any()); + } + + /** + * Method under test: {@link SignatureServiceDefault#verifyDigest(SignedDocumentValidator, String)} + */ + @Test + void testVerifyDigest9() { + XAdESSignature xAdESSignature = mock(XAdESSignature.class); + when(xAdESSignature.getId()).thenReturn("42"); + + ArrayList advancedSignatureList = new ArrayList<>(); + advancedSignatureList.add(xAdESSignature); + DetachedTimestampValidator detachedTimestampValidator = mock(DetachedTimestampValidator.class); + when(detachedTimestampValidator.getOriginalDocuments((String) any())).thenReturn(new ArrayList<>()); + when(detachedTimestampValidator.getSignatures()).thenReturn(advancedSignatureList); + assertThrows(InvalidRequestException.class, () -> signatureService.verifyDigest(detachedTimestampValidator, "Checksum"), "Invalid file digest"); + verify(detachedTimestampValidator).getSignatures(); + verify(detachedTimestampValidator).getOriginalDocuments((String) any()); + verify(xAdESSignature).getId(); + } + + /** + * Method under test: {@link SignatureServiceDefault#verifyManagerTaxCode(Reports, List)} + */ + @Test + void testVerifyManagerTaxCode() { + XmlDetailedReport detailedReport = new XmlDetailedReport(); + XmlSimpleReport simpleReport = new XmlSimpleReport(); + Reports reports = new Reports(dummyXmlDiagnosticData(), detailedReport, simpleReport, new ValidationReportType()); + + assertThrows(InvalidRequestException.class, () -> signatureService.verifyManagerTaxCode(reports, new ArrayList<>()), + TAX_CODE_NOT_FOUND_IN_SIGNATURE.getMessage()); + } + + XmlDiagnosticData dummyXmlDiagnosticData() { + XmlDiagnosticData diagnosticDataJaxb = new XmlDiagnosticData(); + XmlCertificate xmlCertificate = new XmlCertificate(); + xmlCertificate.setSubjectSerialNumber("TINIT-EXAMPLE"); + diagnosticDataJaxb.setUsedCertificates(List.of(xmlCertificate)); + return diagnosticDataJaxb; + } + + /** + * Method under test: {@link SignatureServiceDefault#verifyManagerTaxCode(Reports, List)} + */ + @Test + void testVerifyManagerTaxCode2() { + XmlDiagnosticData diagnosticDataJaxb = new XmlDiagnosticData(); + XmlDetailedReport detailedReport = new XmlDetailedReport(); + XmlSimpleReport simpleReport = new XmlSimpleReport(); + Reports reports = new Reports(diagnosticDataJaxb, detailedReport, simpleReport, new ValidationReportType()); + ArrayList userList = new ArrayList<>(); + + assertThrows(InvalidRequestException.class, () -> signatureService.verifyManagerTaxCode(reports, userList), + TAX_CODE_NOT_FOUND_IN_SIGNATURE.getMessage()); + + assertEquals(userList, reports.getDiagnosticDataJaxb().getUsedCertificates()); + } + + /** + * Method under test: {@link SignatureServiceDefault#verifyManagerTaxCode(Reports, List)} + */ + @Test + void testVerifyManagerTaxCode4() { + XmlDiagnosticData xmlDiagnosticData = new XmlDiagnosticData(); + xmlDiagnosticData.setValidationDate(mock(Date.class)); + XmlDetailedReport detailedReport = new XmlDetailedReport(); + XmlSimpleReport simpleReport = new XmlSimpleReport(); + Reports reports = new Reports(xmlDiagnosticData, detailedReport, simpleReport, new ValidationReportType()); + + assertThrows(InvalidRequestException.class, () -> signatureService.verifyManagerTaxCode(reports, new ArrayList<>()), + TAX_CODE_NOT_FOUND_IN_SIGNATURE.getMessage()); + } + + /** + * Method under test: {@link SignatureServiceDefault#verifyManagerTaxCode(Reports, List)} + */ + @Test + void testVerifyManagerTaxCode5() { + XmlDiagnosticData xmlDiagnosticData = mock(XmlDiagnosticData.class); + when(xmlDiagnosticData.getUsedCertificates()).thenReturn(new ArrayList<>()); + XmlDetailedReport detailedReport = new XmlDetailedReport(); + XmlSimpleReport simpleReport = new XmlSimpleReport(); + Reports reports = new Reports(xmlDiagnosticData, detailedReport, simpleReport, new ValidationReportType()); + + assertThrows(InvalidRequestException.class, () -> signatureService.verifyManagerTaxCode(reports, new ArrayList<>()), + TAX_CODE_NOT_FOUND_IN_SIGNATURE.getMessage()); + + verify(xmlDiagnosticData).getUsedCertificates(); + } + + /** + * Method under test: {@link SignatureServiceDefault#verifyManagerTaxCode(Reports, List)} + */ + @Test + void testVerifyManagerTaxCode6() { + XmlBasicSignature xmlBasicSignature = new XmlBasicSignature(); + xmlBasicSignature.setDigestAlgoUsedToSignThisToken(DigestAlgorithm.SHA1); + xmlBasicSignature.setEncryptionAlgoUsedToSignThisToken(EncryptionAlgorithm.RSA); + xmlBasicSignature.setKeyLengthUsedToSignThisToken("42"); + xmlBasicSignature.setMaskGenerationFunctionUsedToSignThisToken(MaskGenerationFunction.MGF1); + xmlBasicSignature.setSignatureIntact(true); + xmlBasicSignature.setSignatureValid(true); + + XmlDigestAlgoAndValue xmlDigestAlgoAndValue = new XmlDigestAlgoAndValue(); + xmlDigestAlgoAndValue.setDigestMethod(DigestAlgorithm.SHA1); + xmlDigestAlgoAndValue.setDigestValue(new byte[]{'A', 1, 'A', 1, 'A', 1, 'A', 1}); + xmlDigestAlgoAndValue.setMatch(true); + + XmlOriginalThirdCountryQcStatementsMapping xmlOriginalThirdCountryQcStatementsMapping = new XmlOriginalThirdCountryQcStatementsMapping(); + xmlOriginalThirdCountryQcStatementsMapping.setOtherOIDs(new ArrayList<>()); + xmlOriginalThirdCountryQcStatementsMapping.setQcCClegislation(new ArrayList<>()); + xmlOriginalThirdCountryQcStatementsMapping.setQcCompliance(new XmlQcCompliance()); + xmlOriginalThirdCountryQcStatementsMapping.setQcSSCD(new XmlQcSSCD()); + xmlOriginalThirdCountryQcStatementsMapping.setQcTypes(new ArrayList<>()); + + + XmlTrustServiceEquivalenceInformation trustServiceEquivalenceInformation = new XmlTrustServiceEquivalenceInformation(); + trustServiceEquivalenceInformation.setTrustServiceLegalIdentifier("42"); + trustServiceEquivalenceInformation.setCertificateContentEquivalenceList(new ArrayList<>()); + + XmlMRACertificateMapping xmlMRACertificateMapping = new XmlMRACertificateMapping(); + xmlMRACertificateMapping.setTrustServiceEquivalenceInformation(trustServiceEquivalenceInformation); + xmlMRACertificateMapping.setOriginalThirdCountryMapping(xmlOriginalThirdCountryQcStatementsMapping); + + XmlPSD2QcInfo xmlPSD2QcInfo = new XmlPSD2QcInfo(); + xmlPSD2QcInfo.setNcaId("42"); + xmlPSD2QcInfo.setNcaName("42"); + xmlPSD2QcInfo.setRolesOfPSP(new ArrayList<>()); + + XmlQcCompliance xmlQcCompliance = new XmlQcCompliance(); + xmlQcCompliance.setPresent(true); + + XmlQcEuLimitValue xmlQcEuLimitValue = new XmlQcEuLimitValue(); + xmlQcEuLimitValue.setAmount(42); + xmlQcEuLimitValue.setCurrency("42"); + xmlQcEuLimitValue.setExponent(42); + + XmlQcSSCD xmlQcSSCD = new XmlQcSSCD(); + xmlQcSSCD.setPresent(true); + + XmlOID xmlOID = new XmlOID(); + xmlOID.setDescription("42"); + xmlOID.setValue("42"); + + XmlQcStatements xmlQcStatements = new XmlQcStatements(); + xmlQcStatements.setEnactedMRA(true); + xmlQcStatements.setMRACertificateMapping(xmlMRACertificateMapping); + xmlQcStatements.setOtherOIDs(new ArrayList<>()); + xmlQcStatements.setPSD2QcInfo(xmlPSD2QcInfo); + xmlQcStatements.setQcCClegislation(new ArrayList<>()); + xmlQcStatements.setQcCompliance(xmlQcCompliance); + xmlQcStatements.setQcEuLimitValue(xmlQcEuLimitValue); + xmlQcStatements.setQcEuPDS(new ArrayList<>()); + xmlQcStatements.setQcEuRetentionPeriod(42); + xmlQcStatements.setQcSSCD(xmlQcSSCD); + xmlQcStatements.setQcTypes(new ArrayList<>()); + xmlQcStatements.setSemanticsIdentifier(xmlOID); + + XmlBasicSignature xmlBasicSignature1 = new XmlBasicSignature(); + xmlBasicSignature1.setDigestAlgoUsedToSignThisToken(DigestAlgorithm.SHA1); + xmlBasicSignature1.setEncryptionAlgoUsedToSignThisToken(EncryptionAlgorithm.RSA); + xmlBasicSignature1.setKeyLengthUsedToSignThisToken("42"); + xmlBasicSignature1.setMaskGenerationFunctionUsedToSignThisToken(MaskGenerationFunction.MGF1); + xmlBasicSignature1.setSignatureIntact(true); + xmlBasicSignature1.setSignatureValid(true); + + XmlDigestAlgoAndValue xmlDigestAlgoAndValue1 = new XmlDigestAlgoAndValue(); + xmlDigestAlgoAndValue1.setDigestMethod(DigestAlgorithm.SHA1); + xmlDigestAlgoAndValue1.setDigestValue(new byte[]{'A', 1, 'A', 1, 'A', 1, 'A', 1}); + xmlDigestAlgoAndValue1.setMatch(true); + + XmlQcStatements xmlQcStatements1 = new XmlQcStatements(); + xmlQcStatements1.setEnactedMRA(true); + xmlQcStatements1.setMRACertificateMapping(new XmlMRACertificateMapping()); + xmlQcStatements1.setOtherOIDs(new ArrayList<>()); + xmlQcStatements1.setPSD2QcInfo(new XmlPSD2QcInfo()); + xmlQcStatements1.setQcCClegislation(new ArrayList<>()); + xmlQcStatements1.setQcCompliance(new XmlQcCompliance()); + xmlQcStatements1.setQcEuLimitValue(new XmlQcEuLimitValue()); + xmlQcStatements1.setQcEuPDS(new ArrayList<>()); + xmlQcStatements1.setQcEuRetentionPeriod(42); + xmlQcStatements1.setQcSSCD(new XmlQcSSCD()); + xmlQcStatements1.setQcTypes(new ArrayList<>()); + xmlQcStatements1.setSemanticsIdentifier(new XmlOID()); + + XmlSigningCertificate xmlSigningCertificate = new XmlSigningCertificate(); + xmlSigningCertificate.setCertificate(new XmlCertificate()); + xmlSigningCertificate.setPublicKey(new byte[]{'A', 1, 'A', 1, 'A', 1, 'A', 1}); + + XmlCertificate xmlCertificate = new XmlCertificate(); + xmlCertificate.setBase64Encoded(new byte[]{'A', 1, 'A', 1, 'A', 1, 'A', 1}); + xmlCertificate.setBasicSignature(xmlBasicSignature1); + xmlCertificate.setCertificateExtensions(new ArrayList<>()); + xmlCertificate.setCertificateChain(new ArrayList<>()); + xmlCertificate.setCommonName("42"); + xmlCertificate.setCountryName("42"); + xmlCertificate.setDigestAlgoAndValue(xmlDigestAlgoAndValue1); + xmlCertificate.setEmail("42"); + xmlCertificate.setEntityKey("42"); + xmlCertificate.setGivenName("42"); + xmlCertificate.setId("42"); + xmlCertificate.setLocality("42"); + xmlCertificate + .setNotAfter(java.util.Date.from(LocalDate.of(1970, 1, 1).atStartOfDay().atZone(ZoneOffset.UTC).toInstant())); + xmlCertificate.setNotBefore( + java.util.Date.from(LocalDate.of(1970, 1, 1).atStartOfDay().atZone(ZoneOffset.UTC).toInstant())); + xmlCertificate.setOrganizationIdentifier("42"); + xmlCertificate.setOrganizationName("42"); + xmlCertificate.setOrganizationalUnit("42"); + xmlCertificate.setPseudonym("42"); + xmlCertificate.setPublicKeyEncryptionAlgo(EncryptionAlgorithm.RSA); + xmlCertificate.setPublicKeySize(42); + xmlCertificate.setRevocations(new ArrayList<>()); + xmlCertificate.setSelfSigned(true); + xmlCertificate.setSerialNumber(BigInteger.valueOf(42L)); + xmlCertificate.setSigningCertificate(xmlSigningCertificate); + xmlCertificate.setSources(new ArrayList<>()); + xmlCertificate.setState("42"); + xmlCertificate.setSubjectSerialNumber("42"); + xmlCertificate.setSurname("42"); + xmlCertificate.setTitle("42"); + xmlCertificate.setTrusted(true); + xmlCertificate.setTrustedServiceProviders(new ArrayList<>()); + + XmlSigningCertificate xmlSigningCertificate1 = new XmlSigningCertificate(); + xmlSigningCertificate1.setCertificate(xmlCertificate); + xmlSigningCertificate1.setPublicKey(new byte[]{'A', 1, 'A', 1, 'A', 1, 'A', 1}); + + XmlCertificate xmlCertificate1 = new XmlCertificate(); + xmlCertificate1.setBase64Encoded(new byte[]{'A', 1, 'A', 1, 'A', 1, 'A', 1}); + xmlCertificate1.setBasicSignature(xmlBasicSignature); + xmlCertificate1.setCertificateChain(new ArrayList<>()); + xmlCertificate1.setCommonName("42"); + xmlCertificate1.setCountryName("42"); + xmlCertificate1.setDigestAlgoAndValue(xmlDigestAlgoAndValue); + xmlCertificate1.setEmail("42"); + xmlCertificate1.setEntityKey("42"); + xmlCertificate1.setGivenName("42"); + xmlCertificate1.setId("42"); + xmlCertificate1.setLocality("42"); + xmlCertificate1 + .setNotAfter(java.util.Date.from(LocalDate.of(1970, 1, 1).atStartOfDay().atZone(ZoneOffset.UTC).toInstant())); + xmlCertificate1.setNotBefore( + java.util.Date.from(LocalDate.of(1970, 1, 1).atStartOfDay().atZone(ZoneOffset.UTC).toInstant())); + xmlCertificate1.setOrganizationIdentifier("42"); + xmlCertificate1.setOrganizationName("42"); + xmlCertificate1.setOrganizationalUnit("42"); + xmlCertificate1.setPseudonym("42"); + xmlCertificate1.setPublicKeyEncryptionAlgo(EncryptionAlgorithm.RSA); + xmlCertificate1.setPublicKeySize(42); + xmlCertificate1.setRevocations(new ArrayList<>()); + xmlCertificate1.setSelfSigned(true); + xmlCertificate1.setSerialNumber(BigInteger.valueOf(42L)); + xmlCertificate1.setSigningCertificate(xmlSigningCertificate1); + xmlCertificate1.setSources(new ArrayList<>()); + xmlCertificate1.setState("42"); + xmlCertificate1.setSubjectSerialNumber("42"); + xmlCertificate1.setSurname("42"); + xmlCertificate1.setTitle("42"); + xmlCertificate1.setTrusted(true); + xmlCertificate1.setTrustedServiceProviders(new ArrayList<>()); + + ArrayList xmlCertificateList = new ArrayList<>(); + xmlCertificateList.add(xmlCertificate1); + XmlDiagnosticData xmlDiagnosticData = mock(XmlDiagnosticData.class); + when(xmlDiagnosticData.getUsedCertificates()).thenReturn(xmlCertificateList); + XmlDetailedReport detailedReport = new XmlDetailedReport(); + XmlSimpleReport simpleReport = new XmlSimpleReport(); + Reports reports = new Reports(xmlDiagnosticData, detailedReport, simpleReport, new ValidationReportType()); + + assertThrows(InvalidRequestException.class, () -> signatureService.verifyManagerTaxCode(reports, new ArrayList<>()), + TAX_CODE_NOT_FOUND_IN_SIGNATURE.getMessage()); + + verify(xmlDiagnosticData).getUsedCertificates(); + } + + /** + * Method under test: {@link SignatureServiceDefault#verifyManagerTaxCode(Reports, List)} + */ + @Test + void verifyManagerTaxCode() { + Reports reports = mock(Reports.class); + when(reports.getDiagnosticData()).thenReturn(null); + + assertThrows(InvalidRequestException.class, () -> signatureService.verifyManagerTaxCode(reports, new ArrayList<>()), + TAX_CODE_NOT_FOUND_IN_SIGNATURE.getMessage()); + + verify(reports).getDiagnosticData(); + } +} + diff --git a/apps/onboarding-ms/src/test/java/it/pagopa/selfcare/onboarding/service/strategy/ConfigMapAllowedListOnboardingValidationStrategyTest.java b/apps/onboarding-ms/src/test/java/it/pagopa/selfcare/onboarding/service/strategy/ConfigMapAllowedListOnboardingValidationStrategyTest.java new file mode 100644 index 000000000..5c3a59aca --- /dev/null +++ b/apps/onboarding-ms/src/test/java/it/pagopa/selfcare/onboarding/service/strategy/ConfigMapAllowedListOnboardingValidationStrategyTest.java @@ -0,0 +1,111 @@ +package it.pagopa.selfcare.onboarding.service.strategy; + +import com.fasterxml.jackson.core.JsonProcessingException; +import io.quarkus.test.junit.QuarkusTest; +import it.pagopa.selfcare.onboarding.service.strategy.ConfigMapAllowedListOnboardingValidationStrategy; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.function.Executable; + +import java.util.Optional; + +import static org.junit.jupiter.api.Assertions.*; + +@QuarkusTest +class ConfigMapAllowedListOnboardingValidationStrategyTest { + + @Test + void validate_allowedListNotConfigured() throws JsonProcessingException { + // given + + final String productId = "prod-io"; + final String institutionExternalId = "inst-1"; + final ConfigMapAllowedListOnboardingValidationStrategy validationStrategy = + new ConfigMapAllowedListOnboardingValidationStrategy(Optional.empty()); + // when + final Executable executable = () -> validationStrategy.validate(productId, institutionExternalId); + // then + assertDoesNotThrow(executable); + } + + + @Test + void validate_productNotInConfig() throws JsonProcessingException { + // given + final String productId = "prod-io"; + final String institutionExternalId = "inst-1"; + final ConfigMapAllowedListOnboardingValidationStrategy validationStrategy = + new ConfigMapAllowedListOnboardingValidationStrategy(Optional.of("{}")); + // when + final boolean validate = validationStrategy.validate(productId, institutionExternalId); + // then + assertFalse(validate); + } + + + @Test + void validate_invalidConfig_invalidUsageOfSpecialCharacter() { + // given + // when + final Executable executable = () -> new ConfigMapAllowedListOnboardingValidationStrategy(Optional.of("{'prod-io':['inst-1','*']}")); + // then + final IllegalArgumentException e = assertThrows(IllegalArgumentException.class, executable); + assertEquals("Invalid configuration: bad using of special character '*' in allowed-list for key 'prod-io'. If used, the '*' is the only value allowed for a given key", e.getMessage()); + } + + @Test + void validate_allowedListSizeGreaterThanOne() throws JsonProcessingException { + // given + final String productId = "prod-io"; + final String institutionExternalId = "inst-2"; + final ConfigMapAllowedListOnboardingValidationStrategy validationStrategy = + new ConfigMapAllowedListOnboardingValidationStrategy(Optional.of("{'prod-io':['inst-1','inst-2','inst-3']}")); + // when + final boolean validate = validationStrategy.validate(productId, institutionExternalId); + // then + assertTrue(validate); + } + + + @Test + void validate_institutionExplicitlyInAllowed() throws JsonProcessingException { + // given + final String productId = "prod-io"; + final String institutionExternalId = "inst-1"; + final ConfigMapAllowedListOnboardingValidationStrategy validationStrategy = + new ConfigMapAllowedListOnboardingValidationStrategy(Optional.of("{'prod-io':['inst-1']}")); + // when + final boolean validate = validationStrategy.validate(productId, institutionExternalId); + // then + assertTrue(validate); + } + + + @Test + void validate_institutionImplicitlyInAllowedList() throws JsonProcessingException { + // given + final String productId = "prod-io"; + final String institutionExternalId = "inst-1"; + final ConfigMapAllowedListOnboardingValidationStrategy validationStrategy = + new ConfigMapAllowedListOnboardingValidationStrategy(Optional.empty()); + // when + final boolean validate = validationStrategy.validate(productId, institutionExternalId); + // then + assertTrue(validate); + } + + + @Test + void validate_institutionNotInAllowedList() throws JsonProcessingException { + // given + + final String productId = "prod-io"; + final String institutionExternalId = "inst-2"; + final ConfigMapAllowedListOnboardingValidationStrategy validationStrategy = + new ConfigMapAllowedListOnboardingValidationStrategy(Optional.of("{'prod-io':['inst-1']}")); + // when + final boolean validate = validationStrategy.validate(productId, institutionExternalId); + // then + assertFalse(validate); + } + +} \ No newline at end of file diff --git a/apps/onboarding-ms/src/test/resources/application.properties b/apps/onboarding-ms/src/test/resources/application.properties new file mode 100644 index 000000000..82222cd75 --- /dev/null +++ b/apps/onboarding-ms/src/test/resources/application.properties @@ -0,0 +1,2 @@ +mp.jwt.verify.publickey="" +mp.jwt.verify.issuer=SPID diff --git a/apps/pom.xml b/apps/pom.xml new file mode 100644 index 000000000..752ee07cb --- /dev/null +++ b/apps/pom.xml @@ -0,0 +1,40 @@ + + + 4.0.0 + + + it.pagopa.selfcare + onboarding-root + 0.0.1 + + + onboarding-apps + pom + + + + onboarding-ms + + + onboarding-ms/pom.xml + + + + onboarding-ms + + + + onboarding-functions + + + onboarding-functions/pom.xml + + + + onboarding-functions + + + + + diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 000000000..8ce778c54 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,15 @@ +version: '3.8' + +services: + + onboarding-ms: + image: onboarding-ms:latest + container_name: onboarding-ms + restart: on-failure + build: + context: . + dockerfile: ./apps/onboarding-ms/Dockerfile + ports: + - "8080:8080" + environment: + - JWT_TOKEN_PUBLIC_KEY=asdf diff --git a/libs/onboarding-sdk-azure-storage/.gitignore b/libs/onboarding-sdk-azure-storage/.gitignore new file mode 100644 index 000000000..5ff6309b7 --- /dev/null +++ b/libs/onboarding-sdk-azure-storage/.gitignore @@ -0,0 +1,38 @@ +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### IntelliJ IDEA ### +.idea/modules.xml +.idea/jarRepositories.xml +.idea/compiler.xml +.idea/libraries/ +*.iws +*.iml +*.ipr + +### Eclipse ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ + +### Mac OS ### +.DS_Store \ No newline at end of file diff --git a/libs/onboarding-sdk-azure-storage/README.md b/libs/onboarding-sdk-azure-storage/README.md new file mode 100644 index 000000000..7c2292fe4 --- /dev/null +++ b/libs/onboarding-sdk-azure-storage/README.md @@ -0,0 +1,42 @@ +# Onboarding SDK Azure Storage + +This library has been developed to provide a set of Java utility classes to simplify the work of interact with azure storage. It includes features that helping for upload or download file from an azure storage container. + +## Installation + +To use this library in your projects, you can add the dependency to your pom.xml if you're using Maven: + +```shell script + + it.pagopa.selfcare + onboarding-sdk-azure-storage + 0.0.1 + +``` + +If you are using Gradle, you can add the dependency to your build.gradle file: + +```shell script +dependencies { + implementation 'it.pagopa.selfcare:onboarding-sdk-azure-storage:0.0.1' +} +``` + +## Usage + +Here's an example of how to use AzureBlobClient: + +```java script + +public class Main { + public static void main(String[] args) { + final String azureStorageConnectionString = ... ; // set the azure storage connectionString, for ex. AccountName=asd;AccountKey=asd;DefaultEndpointsProtocol=http;BlobEndpoint=http://127.0.0.1:10000/account; + final String azureStorageContainerName = ... ; // set the azure storage container name + final AzureBlobClient azureBlobClient = new AzureBlobClientDefault(azureStorageConnectionString, azureStorageContainerName); + + //Getting file as text + final String filepath = ... ; + final String jsonString = azureBlobClient.getFileAsText(filepath); + } +} +``` \ No newline at end of file diff --git a/libs/onboarding-sdk-azure-storage/pom.xml b/libs/onboarding-sdk-azure-storage/pom.xml new file mode 100644 index 000000000..1b53e3dac --- /dev/null +++ b/libs/onboarding-sdk-azure-storage/pom.xml @@ -0,0 +1,28 @@ + + + 4.0.0 + + it.pagopa.selfcare + onboarding-sdk-pom + 0.1.3 + ../onboarding-sdk-pom + + + onboarding-sdk-azure-storage + + + UTF-8 + 12.24.0 + + + + + com.azure + azure-storage-blob + ${azure-storage-blob-version} + + + + \ No newline at end of file diff --git a/libs/onboarding-sdk-azure-storage/src/main/java/it/pagopa/selfcare/azurestorage/AzureBlobClient.java b/libs/onboarding-sdk-azure-storage/src/main/java/it/pagopa/selfcare/azurestorage/AzureBlobClient.java new file mode 100644 index 000000000..84f9b4ded --- /dev/null +++ b/libs/onboarding-sdk-azure-storage/src/main/java/it/pagopa/selfcare/azurestorage/AzureBlobClient.java @@ -0,0 +1,20 @@ +package it.pagopa.selfcare.azurestorage; + +import com.azure.storage.blob.models.BlobProperties; + +import java.io.File; + +public interface AzureBlobClient { + + byte[] getFile(String filePath); + + String getFileAsText(String filePath); + + File getFileAsPdf(String contractTemplate); + + String uploadFile(String path, String filename, byte[] data); + + void removeFile(String fileName); + + BlobProperties getProperties(String filePath); +} diff --git a/libs/onboarding-sdk-azure-storage/src/main/java/it/pagopa/selfcare/azurestorage/AzureBlobClientDefault.java b/libs/onboarding-sdk-azure-storage/src/main/java/it/pagopa/selfcare/azurestorage/AzureBlobClientDefault.java new file mode 100644 index 000000000..0e4478092 --- /dev/null +++ b/libs/onboarding-sdk-azure-storage/src/main/java/it/pagopa/selfcare/azurestorage/AzureBlobClientDefault.java @@ -0,0 +1,154 @@ +package it.pagopa.selfcare.azurestorage; + +import com.azure.core.util.BinaryData; +import com.azure.storage.blob.BlobClient; +import com.azure.storage.blob.BlobContainerClient; +import com.azure.storage.blob.BlobServiceClient; +import com.azure.storage.blob.BlobServiceClientBuilder; +import com.azure.storage.blob.models.BlobProperties; +import com.azure.storage.blob.models.BlobStorageException; +import it.pagopa.selfcare.azurestorage.error.SelfcareAzureStorageError; +import it.pagopa.selfcare.azurestorage.error.SelfcareAzureStorageException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; +import java.nio.file.Paths; + + +public class AzureBlobClientDefault implements AzureBlobClient { + + private static final Logger log = LoggerFactory.getLogger(AzureBlobClientDefault.class); + + private final BlobServiceClient blobClient; + private final String containerName; + + public AzureBlobClientDefault(String connectionString, String containerName) { + log.trace("it.pagopa.selfcare.azurestorage.AzureBlobClient.it.pagopa.selfcare.azurestorage.AzureBlobClient"); + this.containerName = containerName; + this.blobClient = new BlobServiceClientBuilder() + .connectionString(connectionString) + .buildClient(); + } + + @Override + public byte[] getFile(String filePath) { + log.info("START - getFile for path: {}", filePath); + try { + final BlobContainerClient blobContainer = blobClient.getBlobContainerClient(containerName); + final BlobClient blob = blobContainer.getBlobClient(filePath); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + //BlobProperties properties = blob.getProperties(); + blob.downloadStream(outputStream); + log.info("END - getFile - path {}", filePath); + //response.setData(outputStream.toByteArray()); + //response.setFileName(blob.getName()); + //response.setMimetype(properties.getContentType()); + + return outputStream.toByteArray(); + } catch (BlobStorageException e) { + if (e.getStatusCode() == 404) { + throw new SelfcareAzureStorageException(String.format(SelfcareAzureStorageError.ERROR_DURING_DOWNLOAD_FILE.getMessage(), filePath), + SelfcareAzureStorageError.ERROR_DURING_DOWNLOAD_FILE.getCode()); + } + throw new SelfcareAzureStorageException(String.format(SelfcareAzureStorageError.ERROR_DURING_DOWNLOAD_FILE.getMessage(), filePath), + SelfcareAzureStorageError.ERROR_DURING_DOWNLOAD_FILE.getCode()); + } + } + + @Override + public String getFileAsText(String filePath) { + log.info("START - getTemplateFile for template: {}", filePath); + try { + + final BlobContainerClient blobContainer = blobClient.getBlobContainerClient(containerName); + final BlobClient blob = blobContainer.getBlobClient(filePath); + + BinaryData content = blob.downloadContent(); + log.info("END - getTemplateFile - Downloaded {}", filePath); + return content.toString(); + } catch (BlobStorageException e) { + log.error(String.format(SelfcareAzureStorageError.ERROR_DURING_DOWNLOAD_FILE.getMessage(), filePath), e); + throw new SelfcareAzureStorageException(String.format(SelfcareAzureStorageError.ERROR_DURING_DOWNLOAD_FILE.getMessage(), filePath), + SelfcareAzureStorageError.ERROR_DURING_DOWNLOAD_FILE.getCode()); + } + } + + @Override + public File getFileAsPdf(String contractTemplate){ + log.info("START - getFileAsPdf for template: {}", contractTemplate); + + final BlobContainerClient blobContainer; + final BlobClient blob; + final File downloadedFile; + + try { + blobContainer = blobClient.getBlobContainerClient(containerName); + blob = blobContainer.getBlobClient(contractTemplate); + String fileName = Paths.get(contractTemplate).getFileName().toString(); + downloadedFile = File.createTempFile(fileName, ".pdf"); + blob.downloadToFile(downloadedFile.getAbsolutePath(), true); + } catch (BlobStorageException | IOException e) { + log.error(String.format(SelfcareAzureStorageError.ERROR_DURING_DOWNLOAD_FILE.getMessage(), contractTemplate), e); + throw new SelfcareAzureStorageException(String.format(SelfcareAzureStorageError.ERROR_DURING_DOWNLOAD_FILE.getMessage(), contractTemplate), + SelfcareAzureStorageError.ERROR_DURING_DOWNLOAD_FILE.getCode()); + } + + log.info("END - getFileAsPdf"); + return downloadedFile; + } + + @Override + public String uploadFile(String path, String filename, byte[] data) { + log.debug("START - uploadFile for path: {}, filename: {}", path, filename); + String filepath = Paths.get(path, filename).toString(); + log.debug("uploadContract fileName = {}", filepath); + try { + final BlobContainerClient blobContainer = blobClient.getBlobContainerClient(containerName); + final BlobClient blob = blobContainer.getBlobClient(filepath); + blob.upload(BinaryData.fromBytes(data), true); + log.info("Uploaded {}", filepath); + return filepath; + } catch (BlobStorageException e) { + log.error(String.format(SelfcareAzureStorageError.ERROR_DURING_UPLOAD_FILE.getMessage(), filepath), e); + throw new SelfcareAzureStorageException(String.format(SelfcareAzureStorageError.ERROR_DURING_UPLOAD_FILE.getMessage(), filepath), + SelfcareAzureStorageError.ERROR_DURING_UPLOAD_FILE.getCode()); + } + } + + @Override + public void removeFile(String fileName) { + log.debug("START - delete file for fileName: {}", fileName); + + try { + final BlobContainerClient blobContainer = blobClient.getBlobContainerClient(containerName); + final BlobClient blob = blobContainer.getBlobClient(fileName); + blob.deleteIfExists(); + log.debug("Deleted {}", fileName); + } catch (BlobStorageException e) { + log.error(String.format(SelfcareAzureStorageError.ERROR_DURING_DELETED_FILE.getMessage(), fileName), e); + throw new SelfcareAzureStorageException(String.format(SelfcareAzureStorageError.ERROR_DURING_DELETED_FILE.getMessage(), fileName), + SelfcareAzureStorageError.ERROR_DURING_DELETED_FILE.getCode()); + } + } + + @Override + public BlobProperties getProperties(String filePath) { + try { + final BlobContainerClient blobContainer = blobClient.getBlobContainerClient(containerName); + final BlobClient blob = blobContainer.getBlobClient(filePath); + + return blob.getProperties(); + } catch (BlobStorageException e) { + if (e.getStatusCode() == 404) { + throw new SelfcareAzureStorageException(String.format(SelfcareAzureStorageError.ERROR_DURING_DOWNLOAD_FILE.getMessage(), filePath), + SelfcareAzureStorageError.ERROR_DURING_DOWNLOAD_FILE.getCode()); + } + throw new SelfcareAzureStorageException(String.format(SelfcareAzureStorageError.ERROR_DURING_DOWNLOAD_FILE.getMessage(), filePath), + SelfcareAzureStorageError.ERROR_DURING_DOWNLOAD_FILE.getCode()); + } + } + +} diff --git a/libs/onboarding-sdk-azure-storage/src/main/java/it/pagopa/selfcare/azurestorage/error/SelfcareAzureStorageError.java b/libs/onboarding-sdk-azure-storage/src/main/java/it/pagopa/selfcare/azurestorage/error/SelfcareAzureStorageError.java new file mode 100644 index 000000000..c8d284ebe --- /dev/null +++ b/libs/onboarding-sdk-azure-storage/src/main/java/it/pagopa/selfcare/azurestorage/error/SelfcareAzureStorageError.java @@ -0,0 +1,26 @@ +package it.pagopa.selfcare.azurestorage.error; + +public enum SelfcareAzureStorageError { + + ERROR_DURING_UPLOAD_FILE("0000", "Error during upload file %s"), + + ERROR_DURING_DELETED_FILE("0000", "Error during deleted file %s"), + ERROR_DURING_DOWNLOAD_FILE("0000", "Error during download file %s"); + + private final String code; + private final String detail; + + + SelfcareAzureStorageError(String code, String detail) { + this.code = code; + this.detail = detail; + } + + public String getCode() { + return code; + } + + public String getMessage() { + return detail; + } +} diff --git a/libs/onboarding-sdk-azure-storage/src/main/java/it/pagopa/selfcare/azurestorage/error/SelfcareAzureStorageException.java b/libs/onboarding-sdk-azure-storage/src/main/java/it/pagopa/selfcare/azurestorage/error/SelfcareAzureStorageException.java new file mode 100644 index 000000000..6f6182e73 --- /dev/null +++ b/libs/onboarding-sdk-azure-storage/src/main/java/it/pagopa/selfcare/azurestorage/error/SelfcareAzureStorageException.java @@ -0,0 +1,15 @@ +package it.pagopa.selfcare.azurestorage.error; + +public class SelfcareAzureStorageException extends RuntimeException { + + private final String code; + + public SelfcareAzureStorageException(String message, String code) { + super(message); + this.code = code; + } + + public String getCode() { + return code; + } +} diff --git a/libs/onboarding-sdk-common/.gitignore b/libs/onboarding-sdk-common/.gitignore new file mode 100644 index 000000000..5ff6309b7 --- /dev/null +++ b/libs/onboarding-sdk-common/.gitignore @@ -0,0 +1,38 @@ +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### IntelliJ IDEA ### +.idea/modules.xml +.idea/jarRepositories.xml +.idea/compiler.xml +.idea/libraries/ +*.iws +*.iml +*.ipr + +### Eclipse ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ + +### Mac OS ### +.DS_Store \ No newline at end of file diff --git a/libs/onboarding-sdk-common/README.md b/libs/onboarding-sdk-common/README.md new file mode 100644 index 000000000..31068846b --- /dev/null +++ b/libs/onboarding-sdk-common/README.md @@ -0,0 +1,23 @@ +# Onboarding SDK Common + +This library has been developed to provide a set of Java utility classes to simplify the work of onboarding service. It includes constants that helping for some aspects of onboarding activity. + +## Installation + +To use this library in your projects, you can add the dependency to your pom.xml if you're using Maven: + +```shell script + + it.pagopa.selfcare + onboarding-sdk-common + 0.0.1 + +``` + +If you are using Gradle, you can add the dependency to your build.gradle file: + +```shell script +dependencies { + implementation 'it.pagopa.selfcare:onboarding-sdk-common:0.0.1' +} +``` diff --git a/libs/onboarding-sdk-common/pom.xml b/libs/onboarding-sdk-common/pom.xml new file mode 100644 index 000000000..6ee56a33f --- /dev/null +++ b/libs/onboarding-sdk-common/pom.xml @@ -0,0 +1,13 @@ + + 4.0.0 + + it.pagopa.selfcare + onboarding-sdk-pom + 0.1.3 + ../onboarding-sdk-pom + + onboarding-sdk-common + onboarding-sdk-common + http://maven.apache.org + diff --git a/libs/onboarding-sdk-common/src/main/java/it/pagopa/selfcare/onboarding/common/Env.java b/libs/onboarding-sdk-common/src/main/java/it/pagopa/selfcare/onboarding/common/Env.java new file mode 100644 index 000000000..ed222b200 --- /dev/null +++ b/libs/onboarding-sdk-common/src/main/java/it/pagopa/selfcare/onboarding/common/Env.java @@ -0,0 +1,8 @@ +package it.pagopa.selfcare.onboarding.common; + +public enum Env { + ROOT, + DEV, + COLL, + PROD +} diff --git a/libs/onboarding-sdk-common/src/main/java/it/pagopa/selfcare/onboarding/common/InstitutionPaSubunitType.java b/libs/onboarding-sdk-common/src/main/java/it/pagopa/selfcare/onboarding/common/InstitutionPaSubunitType.java new file mode 100644 index 000000000..f3a7c350d --- /dev/null +++ b/libs/onboarding-sdk-common/src/main/java/it/pagopa/selfcare/onboarding/common/InstitutionPaSubunitType.java @@ -0,0 +1,5 @@ +package it.pagopa.selfcare.onboarding.common; + +public enum InstitutionPaSubunitType { + AOO, UO +} diff --git a/onboarding-ms/src/main/java/it/pagopa/selfcare/util/InstitutionType.java b/libs/onboarding-sdk-common/src/main/java/it/pagopa/selfcare/onboarding/common/InstitutionType.java similarity index 51% rename from onboarding-ms/src/main/java/it/pagopa/selfcare/util/InstitutionType.java rename to libs/onboarding-sdk-common/src/main/java/it/pagopa/selfcare/onboarding/common/InstitutionType.java index 0056348f6..6d730c36a 100644 --- a/onboarding-ms/src/main/java/it/pagopa/selfcare/util/InstitutionType.java +++ b/libs/onboarding-sdk-common/src/main/java/it/pagopa/selfcare/onboarding/common/InstitutionType.java @@ -1,10 +1,12 @@ -package it.pagopa.selfcare.util; +package it.pagopa.selfcare.onboarding.common; public enum InstitutionType { PA, PG, GSP, + SA, PT, SCP, - PSP + PSP, + AS } diff --git a/libs/onboarding-sdk-common/src/main/java/it/pagopa/selfcare/onboarding/common/OnboardingStatus.java b/libs/onboarding-sdk-common/src/main/java/it/pagopa/selfcare/onboarding/common/OnboardingStatus.java new file mode 100644 index 000000000..1991c9f94 --- /dev/null +++ b/libs/onboarding-sdk-common/src/main/java/it/pagopa/selfcare/onboarding/common/OnboardingStatus.java @@ -0,0 +1,10 @@ +package it.pagopa.selfcare.onboarding.common; +public enum OnboardingStatus { + REQUEST, + TO_BE_VALIDATED, + PENDING, + COMPLETED, + FAILED, + REJECTED, + DELETED +} diff --git a/libs/onboarding-sdk-common/src/main/java/it/pagopa/selfcare/onboarding/common/Origin.java b/libs/onboarding-sdk-common/src/main/java/it/pagopa/selfcare/onboarding/common/Origin.java new file mode 100644 index 000000000..ef4e9b713 --- /dev/null +++ b/libs/onboarding-sdk-common/src/main/java/it/pagopa/selfcare/onboarding/common/Origin.java @@ -0,0 +1,43 @@ +package it.pagopa.selfcare.onboarding.common; + +import java.util.Arrays; +import java.util.Objects; + +public enum Origin { + MOCK("MOCK"), + IPA("IPA"), + SELC("SELC"), + ANAC("ANAC"), + UNKNOWN("UNKNOWN"), + ADE("ADE"), + INFOCAMERE("INFOCAMERE"), + IVASS("IVASS"); + + private final String value; + + Origin(String value) { + this.value = value; + } + + public String getValue() { + return value; + } + + @Override + public String toString() { + return value; + } + + + public static Origin fromValue(String value) { + if(Objects.nonNull(value)) { + return Arrays.stream(values()) + .filter(origin -> origin.toString().equals(value)) + .findAny() + .orElseThrow(() -> new IllegalArgumentException("Valid value for Origin are: IPA, INFOCAMERE, SELC or static")); + }else{ + return Origin.UNKNOWN; + } + } + +} \ No newline at end of file diff --git a/libs/onboarding-sdk-common/src/main/java/it/pagopa/selfcare/onboarding/common/PartyRole.java b/libs/onboarding-sdk-common/src/main/java/it/pagopa/selfcare/onboarding/common/PartyRole.java new file mode 100644 index 000000000..be30ad4dc --- /dev/null +++ b/libs/onboarding-sdk-common/src/main/java/it/pagopa/selfcare/onboarding/common/PartyRole.java @@ -0,0 +1,9 @@ +package it.pagopa.selfcare.onboarding.common; + +public enum PartyRole { + MANAGER, + DELEGATE, + SUB_DELEGATE, + OPERATOR; + +} diff --git a/libs/onboarding-sdk-common/src/main/java/it/pagopa/selfcare/onboarding/common/PricingPlan.java b/libs/onboarding-sdk-common/src/main/java/it/pagopa/selfcare/onboarding/common/PricingPlan.java new file mode 100644 index 000000000..88140408b --- /dev/null +++ b/libs/onboarding-sdk-common/src/main/java/it/pagopa/selfcare/onboarding/common/PricingPlan.java @@ -0,0 +1,18 @@ +package it.pagopa.selfcare.onboarding.common; + +public enum PricingPlan { + + FA("FAST"), + BASE("BASE"), + PREMIUM("PREMIUM"); + + private final String value; + + PricingPlan(String value) { + this.value = value; + } + + public String getValue() { + return value; + } +} diff --git a/libs/onboarding-sdk-common/src/main/java/it/pagopa/selfcare/onboarding/common/ProductId.java b/libs/onboarding-sdk-common/src/main/java/it/pagopa/selfcare/onboarding/common/ProductId.java new file mode 100644 index 000000000..d4a6ca319 --- /dev/null +++ b/libs/onboarding-sdk-common/src/main/java/it/pagopa/selfcare/onboarding/common/ProductId.java @@ -0,0 +1,29 @@ +package it.pagopa.selfcare.onboarding.common; + +public enum ProductId { + + PROD_INTEROP("prod-interop"), + PROD_PN("prod-pn"), + PROD_FD("prod-fd"), + PROD_FD_GARANTITO("prod-fd-garantito"), + PROD_IO("prod-io"), + PROD_INTEROP_COLL("prod-interop-coll"), + PROD_IO_SIGN("prod-io-sign"), + PROD_PAGOPA("prod-pagopa"), + PROD_IO_PREMIUM("prod-io-premium"); + + private final String value; + + ProductId(String value) { + this.value = value; + } + + public String getValue() { + return value; + } + + @Override + public String toString() { + return value; + } +} diff --git a/libs/onboarding-sdk-common/src/main/java/it/pagopa/selfcare/onboarding/common/TokenType.java b/libs/onboarding-sdk-common/src/main/java/it/pagopa/selfcare/onboarding/common/TokenType.java new file mode 100644 index 000000000..a2f9adedf --- /dev/null +++ b/libs/onboarding-sdk-common/src/main/java/it/pagopa/selfcare/onboarding/common/TokenType.java @@ -0,0 +1,6 @@ +package it.pagopa.selfcare.onboarding.common; + +public enum TokenType { + INSTITUTION, + LEGALS +} diff --git a/libs/onboarding-sdk-common/src/main/java/it/pagopa/selfcare/onboarding/common/WorkflowType.java b/libs/onboarding-sdk-common/src/main/java/it/pagopa/selfcare/onboarding/common/WorkflowType.java new file mode 100644 index 000000000..5fc90e96d --- /dev/null +++ b/libs/onboarding-sdk-common/src/main/java/it/pagopa/selfcare/onboarding/common/WorkflowType.java @@ -0,0 +1,9 @@ +package it.pagopa.selfcare.onboarding.common; + +public enum WorkflowType { + + CONTRACT_REGISTRATION, + FOR_APPROVE, + FOR_APPROVE_PT, + CONFIRMATION +} diff --git a/libs/onboarding-sdk-crypto/.gitignore b/libs/onboarding-sdk-crypto/.gitignore new file mode 100644 index 000000000..5ff6309b7 --- /dev/null +++ b/libs/onboarding-sdk-crypto/.gitignore @@ -0,0 +1,38 @@ +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### IntelliJ IDEA ### +.idea/modules.xml +.idea/jarRepositories.xml +.idea/compiler.xml +.idea/libraries/ +*.iws +*.iml +*.ipr + +### Eclipse ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ + +### Mac OS ### +.DS_Store \ No newline at end of file diff --git a/libs/onboarding-sdk-crypto/README.md b/libs/onboarding-sdk-crypto/README.md new file mode 100644 index 000000000..3a97e0512 --- /dev/null +++ b/libs/onboarding-sdk-crypto/README.md @@ -0,0 +1,101 @@ +# Onboarding SDK Crypto + +This module contains utilities to perform cryptographic operation, such digital signatures. See [Confluence page](https://pagopa.atlassian.net/wiki/spaces/SCP/pages/616857618/Firma+digitale+per+mezzo+dei+servizi+di+Aruba) +for integration and documentation details + + +### Hash signature sources + +It is possible to configure different hash signature sources. + +The sources available inside this repository are: + +* Pkcs7HashSignService +* ArubaPkcs7HashSignService + + +### Pkcs7HashSignService + +It will use the provided private key and certificate, you must set these env variables. + +| Properties | Description | Default | +|--------------------|---------------------------------------------------------------------------------|---------| +| CRYPTO_PRIVATE_KEY | The private key (PEM) used when the pkcs7 hash signature source is local | | +| CRYPTO_CERT | The certificate (PEM) used when the pkcs7 hash signature source is local | | + + + +### ArubaPkcs7HashSignService: Aruba integration + +It integrates the ARSS (Aruba Remote Sign Service) Soap service in order to build the automatic digital +signature of the hash of a single file through the certificates stored inside Aruba. + +See [Confluence page](https://pagopa.atlassian.net/wiki/spaces/SCP/pages/616857618/Firma+digitale+per+mezzo+dei+servizi+di+Aruba) +for integration and documentation details + + +The integration towards Aruba is configurable through the following environment variables: + +| ENV | Description | Default | +|------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------| +| ARUBA_SIGN_SERVICE_BASE_URL | The URL of the webService | https://arss.demo.firma-automatica.it:443/ArubaSignService/ArubaSignService | +| ARUBA_SIGN_SERVICE_CONNECT_TIMEOUT_MS | The timeout configured to establish the connection. If 0, no timeout will be configured | 0 | +| ARUBA_SIGN_SERVICE_REQUEST_TIMEOUT_MS | The timeout configured for the request. If 0, no timeout will be configured | 0 | +| ARUBA_SIGN_SERVICE_IDENTITY_TYPE_OTP_AUTH | The string identifying the automatic signature domain indicated when ARSS is installed | typeOtpAuth | +| ARUBA_SIGN_SERVICE_IDENTITY_OTP_PWD | The string identifying the automatic signature transactions defined when the ARSS server is installed (it is normally known by the administrator of the IT infrastructure network on which users are working) | otpPwd | +| ARUBA_SIGN_SERVICE_IDENTITY_USER | The string containing the signature user's username | user | +| ARUBA_SIGN_SERVICE_IDENTITY_DELEGATED_USER | The string containing the username for the delegated user | delegatedUser | +| ARUBA_SIGN_SERVICE_IDENTITY_DELEGATED_PASSWORD | The String containing the delegated user's password | delegatedPassword | +| ARUBA_SIGN_SERVICE_IDENTITY_DELEGATED_DOMAIN | The delegated user's domain | delegatedDomain | + + +## Installation + +To use this library in your projects, you can add the dependency to your pom.xml if you're using Maven: + +```shell script + + it.pagopa.selfcare + onboarding-sdk-crypto + 0.1.0 + +``` +If you are using Gradle, you can add the dependency to your build.gradle file: + +```shell script +dependencies { + implementation 'it.pagopa.selfcare:onboarding-sdk-crypto:0.1.0' +} +``` + +## Usage + +You can inject the service in the context of Quarkus or Spring (replace @ApplicationScoped with @Bean). + +### Pkcs7HashSignService + +```java script + @ApplicationScoped + public Pkcs7HashSignService pkcs7HashSignService(){ + return new Pkcs7HashSignServiceImpl(); + } + + @ApplicationScoped + public PadesSignService padesSignService(Pkcs7HashSignService pkcs7HashSignService){ + return new PadesSignServiceImpl(pkcs7HashSignService); + } + ``` + +### ArubaPkcs7HashSignService + +```java script + @ApplicationScoped + public Pkcs7HashSignService pkcs7HashSignService(){ + return new ArubaPkcs7HashSignServiceImpl(new ArubaSignServiceImpl()); + } + + @ApplicationScoped + public PadesSignService padesSignService(Pkcs7HashSignService pkcs7HashSignService){ + return new PadesSignServiceImpl(pkcs7HashSignService); + } + ``` \ No newline at end of file diff --git a/libs/onboarding-sdk-crypto/pom.xml b/libs/onboarding-sdk-crypto/pom.xml new file mode 100644 index 000000000..55eedfc2f --- /dev/null +++ b/libs/onboarding-sdk-crypto/pom.xml @@ -0,0 +1,101 @@ + + 4.0.0 + + it.pagopa.selfcare + onboarding-sdk-pom + 0.1.3 + ../onboarding-sdk-pom + + onboarding-sdk-crypto + onboarding-sdk-crypto + http://maven.apache.org + + + + + jakarta.xml.soap + jakarta.xml.soap-api + 3.0.1 + + + jakarta.xml.ws + jakarta.xml.ws-api + 4.0.1 + + + com.sun.xml.ws + jaxws-rt + 4.0.2 + + + jakarta.activation + jakarta.activation-api + + + jakarta.xml.bind + jakarta.xml.bind-api + + + com.sun.xml.bind + jaxb-impl + 4.0.1 + + + com.sun.xml.messaging.saaj + saaj-impl + 3.0.0 + + + org.slf4j + slf4j-api + + + + org.apache.pdfbox + pdfbox + 2.0.27 + + + org.bouncycastle + bcprov-jdk18on + + + org.bouncycastle + bcpkix-jdk18on + + + org.apache.commons + commons-lang3 + + + + uk.org.webcompere + system-stubs-core + 2.1.3 + test + + + + + + + com.sun.xml.ws + jaxws-maven-plugin + 4.0.0 + + + + wsimport + + + + + src/main/resources/docs/aruba/ + it.pagopa.selfcare.onboarding.crypto.soap.aruba.sign.generated.client + ${project.build.directory}/generated-sources/wsimport/ + + + + + diff --git a/libs/onboarding-sdk-crypto/src/main/java/it/pagopa/selfcare/onboarding/crypto/ArubaPkcs7HashSignServiceImpl.java b/libs/onboarding-sdk-crypto/src/main/java/it/pagopa/selfcare/onboarding/crypto/ArubaPkcs7HashSignServiceImpl.java new file mode 100644 index 000000000..2ef91123c --- /dev/null +++ b/libs/onboarding-sdk-crypto/src/main/java/it/pagopa/selfcare/onboarding/crypto/ArubaPkcs7HashSignServiceImpl.java @@ -0,0 +1,18 @@ +package it.pagopa.selfcare.onboarding.crypto; + +import java.io.IOException; +import java.io.InputStream; + +public class ArubaPkcs7HashSignServiceImpl implements Pkcs7HashSignService { + + private final ArubaSignService arubaSignService; + + public ArubaPkcs7HashSignServiceImpl(ArubaSignService arubaSignService) { + this.arubaSignService = arubaSignService; + } + + @Override + public byte[] sign(InputStream is) throws IOException { + return arubaSignService.pkcs7Signhash(is); + } +} diff --git a/libs/onboarding-sdk-crypto/src/main/java/it/pagopa/selfcare/onboarding/crypto/ArubaSignService.java b/libs/onboarding-sdk-crypto/src/main/java/it/pagopa/selfcare/onboarding/crypto/ArubaSignService.java new file mode 100644 index 000000000..e6f228cfa --- /dev/null +++ b/libs/onboarding-sdk-crypto/src/main/java/it/pagopa/selfcare/onboarding/crypto/ArubaSignService.java @@ -0,0 +1,9 @@ +package it.pagopa.selfcare.onboarding.crypto; + +import java.io.InputStream; + +/** It allows to perform signature requests towards Aruba. */ +public interface ArubaSignService { + byte[] hashSign(InputStream is); + byte[] pkcs7Signhash(InputStream is); +} diff --git a/libs/onboarding-sdk-crypto/src/main/java/it/pagopa/selfcare/onboarding/crypto/ArubaSignServiceImpl.java b/libs/onboarding-sdk-crypto/src/main/java/it/pagopa/selfcare/onboarding/crypto/ArubaSignServiceImpl.java new file mode 100644 index 000000000..d6e50cd2a --- /dev/null +++ b/libs/onboarding-sdk-crypto/src/main/java/it/pagopa/selfcare/onboarding/crypto/ArubaSignServiceImpl.java @@ -0,0 +1,116 @@ +package it.pagopa.selfcare.onboarding.crypto; + + + +import com.sun.xml.ws.developer.JAXWSProperties; +import it.pagopa.selfcare.onboarding.crypto.config.ArubaInitializer; +import it.pagopa.selfcare.onboarding.crypto.config.ArubaSignConfig; +import it.pagopa.selfcare.onboarding.crypto.soap.aruba.sign.generated.client.*; +import it.pagopa.selfcare.onboarding.crypto.utils.CryptoUtils; +import it.pagopa.selfcare.onboarding.crypto.utils.SoapLoggingHandler; +import jakarta.xml.ws.BindingProvider; +import jakarta.xml.ws.handler.Handler; + +import java.io.InputStream; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.List; + +public class ArubaSignServiceImpl implements ArubaSignService { + + private static final DateTimeFormatter df = DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm:ss"); + + private final ArubaSignConfig config; + private final SoapLoggingHandler soapLoggingHandler; + + private final ArubaSignServiceService arubaSignServiceService; + + public ArubaSignServiceImpl() { + this.config = ArubaInitializer.initializeConfig(); + this.soapLoggingHandler = new SoapLoggingHandler(); + + this.arubaSignServiceService = new ArubaSignServiceService(getClass().getClassLoader().getResource("docs/aruba/ArubaSignService.wsdl")); + } + + private it.pagopa.selfcare.onboarding.crypto.soap.aruba.sign.generated.client.ArubaSignService getClient() { + it.pagopa.selfcare.onboarding.crypto.soap.aruba.sign.generated.client.ArubaSignService client = arubaSignServiceService.getArubaSignServicePort(); + ((BindingProvider) client).getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, config.getBaseUrl()); + + if (config.getConnectTimeoutMs() > 0) { + ((BindingProvider) client).getRequestContext().put(JAXWSProperties.CONNECT_TIMEOUT, config.getConnectTimeoutMs()); + } + if (config.getRequestTimeoutMs() > 0) { + ((BindingProvider) client).getRequestContext().put(JAXWSProperties.REQUEST_TIMEOUT, config.getRequestTimeoutMs()); + } + + @SuppressWarnings("rawtypes") + List handlerChain = ((BindingProvider) client).getBinding().getHandlerChain(); + handlerChain.add(soapLoggingHandler); + ((BindingProvider) client).getBinding().setHandlerChain(handlerChain); + + return client; + } + +//region hashSign request + @Override + public byte[] hashSign(InputStream is) { + it.pagopa.selfcare.onboarding.crypto.soap.aruba.sign.generated.client.ArubaSignService client = getClient(); + SignHashRequest request = buildSignHashRequest(is); + SignHashReturn result = client.signhash(request); + if ("OK".equals(result.getStatus())) { + return result.getSignature(); + } else { + throw new IllegalStateException(String.format("Something gone wrong while signing input file: returnCode: %s; description:%s", result.getReturnCode(), result.getDescription())); + } + } + + private SignHashRequest buildSignHashRequest(InputStream is) { + SignHashRequest request = new SignHashRequest(); + + request.setCertID("AS0"); + request.setIdentity(config.getAuth()); + + request.setHash(CryptoUtils.getDigest(is)); + request.setHashtype("SHA256"); + + request.setRequirecert(false); + + return request; + } +//endregion + +//region pkcs7Signhash request + @Override + public byte[] pkcs7Signhash(InputStream is) { + it.pagopa.selfcare.onboarding.crypto.soap.aruba.sign.generated.client.ArubaSignService client = getClient(); + SignRequestV2 request = buildSignRequest(is); + try { + SignReturnV2 result = client.pkcs7Signhash(request, false, false); + if ("OK".equals(result.getStatus())) { + return result.getBinaryoutput(); + } else { + throw new IllegalStateException(String.format("Something gone wrong while performing pkcs7 hash sign request: returnCode: %s; description:%s", result.getReturnCode(), result.getDescription())); + } + } catch (TypeOfTransportNotImplemented_Exception e) { + throw new IllegalStateException("Something gone wrong when invoking Aruba in order to calculate pkcs7 hash sign request", e); + } + } + + private SignRequestV2 buildSignRequest(InputStream is) { + SignRequestV2 request = new SignRequestV2(); + + request.setCertID("AS0"); + request.setProfile("NULL"); + request.setIdentity(config.getAuth()); + + request.setTransport(TypeTransport.BYNARYNET); + request.setBinaryinput(CryptoUtils.getDigest(is)); + + request.setRequiredmark(false); + request.setSigningTime(df.format(LocalDateTime.now())); + + return request; + } +//endregion + +} diff --git a/libs/onboarding-sdk-crypto/src/main/java/it/pagopa/selfcare/onboarding/crypto/PadesSignService.java b/libs/onboarding-sdk-crypto/src/main/java/it/pagopa/selfcare/onboarding/crypto/PadesSignService.java new file mode 100644 index 000000000..5ebeb709c --- /dev/null +++ b/libs/onboarding-sdk-crypto/src/main/java/it/pagopa/selfcare/onboarding/crypto/PadesSignService.java @@ -0,0 +1,10 @@ +package it.pagopa.selfcare.onboarding.crypto; + + +import it.pagopa.selfcare.onboarding.crypto.entity.SignatureInformation; + +import java.io.File; + +public interface PadesSignService { + void padesSign(File pdfFile, File signedPdfFile, SignatureInformation signInfo); +} diff --git a/libs/onboarding-sdk-crypto/src/main/java/it/pagopa/selfcare/onboarding/crypto/PadesSignServiceImpl.java b/libs/onboarding-sdk-crypto/src/main/java/it/pagopa/selfcare/onboarding/crypto/PadesSignServiceImpl.java new file mode 100644 index 000000000..a08acc7fc --- /dev/null +++ b/libs/onboarding-sdk-crypto/src/main/java/it/pagopa/selfcare/onboarding/crypto/PadesSignServiceImpl.java @@ -0,0 +1,43 @@ +package it.pagopa.selfcare.onboarding.crypto; + +import it.pagopa.selfcare.onboarding.crypto.entity.SignatureInformation; +import it.pagopa.selfcare.onboarding.crypto.utils.CryptoUtils; +import org.apache.pdfbox.pdmodel.PDDocument; +import org.apache.pdfbox.pdmodel.interactive.digitalsignature.PDSignature; +import org.apache.pdfbox.pdmodel.interactive.digitalsignature.SignatureOptions; + +import java.io.File; +import java.io.FileOutputStream; +import java.util.Calendar; + +public class PadesSignServiceImpl implements PadesSignService { + private final Pkcs7HashSignService pkcs7Signature; + + public PadesSignServiceImpl(Pkcs7HashSignService pkcs7Signature) { + this.pkcs7Signature = pkcs7Signature; + } + + public void padesSign(File pdfFile, File signedPdfFile, SignatureInformation signInfo) { + CryptoUtils.createParentDirectoryIfNotExists(signedPdfFile); + + try (FileOutputStream fos = new FileOutputStream(signedPdfFile); + PDDocument doc = PDDocument.load(pdfFile)){ + + PDSignature signature = new PDSignature(); + signature.setFilter(PDSignature.FILTER_ADOBE_PPKLITE); + signature.setSubFilter(PDSignature.SUBFILTER_ADBE_PKCS7_DETACHED); + signature.setName(signInfo.getName()); + signature.setLocation(signInfo.getLocation()); + signature.setReason(signInfo.getReason()); + signature.setSignDate(Calendar.getInstance()); + SignatureOptions signatureOptions = new SignatureOptions(); + signatureOptions.setPreferredSignatureSize(35944); + doc.addSignature(signature, this.pkcs7Signature, signatureOptions); + doc.saveIncremental(fos); + + } catch (Exception var12) { + throw new IllegalStateException(String.format("Something gone wrong while signing input pdf %s and storing it into %s", pdfFile.getAbsolutePath(), signedPdfFile.getAbsolutePath()), var12); + } + } +} + diff --git a/libs/onboarding-sdk-crypto/src/main/java/it/pagopa/selfcare/onboarding/crypto/Pkcs7HashSignService.java b/libs/onboarding-sdk-crypto/src/main/java/it/pagopa/selfcare/onboarding/crypto/Pkcs7HashSignService.java new file mode 100644 index 000000000..f15152ac6 --- /dev/null +++ b/libs/onboarding-sdk-crypto/src/main/java/it/pagopa/selfcare/onboarding/crypto/Pkcs7HashSignService.java @@ -0,0 +1,6 @@ +package it.pagopa.selfcare.onboarding.crypto; + +import org.apache.pdfbox.pdmodel.interactive.digitalsignature.SignatureInterface; + +public interface Pkcs7HashSignService extends SignatureInterface { +} diff --git a/libs/onboarding-sdk-crypto/src/main/java/it/pagopa/selfcare/onboarding/crypto/Pkcs7HashSignServiceImpl.java b/libs/onboarding-sdk-crypto/src/main/java/it/pagopa/selfcare/onboarding/crypto/Pkcs7HashSignServiceImpl.java new file mode 100644 index 000000000..45f093e12 --- /dev/null +++ b/libs/onboarding-sdk-crypto/src/main/java/it/pagopa/selfcare/onboarding/crypto/Pkcs7HashSignServiceImpl.java @@ -0,0 +1,57 @@ +package it.pagopa.selfcare.onboarding.crypto; + + +import it.pagopa.selfcare.onboarding.crypto.config.LocalCryptoConfig; +import it.pagopa.selfcare.onboarding.crypto.config.LocalCryptoInitializer; +import it.pagopa.selfcare.onboarding.crypto.utils.CMSTypedDataInputStream; +import org.bouncycastle.cert.X509CertificateHolder; +import org.bouncycastle.cert.jcajce.JcaCertStore; +import org.bouncycastle.cms.*; +import org.bouncycastle.cms.jcajce.JcaSignerInfoGeneratorBuilder; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.operator.ContentSigner; +import org.bouncycastle.operator.OperatorCreationException; +import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder; +import org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder; +import org.bouncycastle.util.Store; + +import java.io.*; +import java.security.cert.CertificateEncodingException; +import java.util.Collections; + +/** + * Implementation of {@link Pkcs7HashSignService} which will use provided private and public keys to perform sign operations + */ +public class Pkcs7HashSignServiceImpl implements Pkcs7HashSignService { + + private final CMSSignedDataGenerator cmsSignGenerator; + + public Pkcs7HashSignServiceImpl() { + try { + LocalCryptoConfig localCryptoConfig = LocalCryptoInitializer.initializeConfig(); + BouncyCastleProvider bc = new BouncyCastleProvider(); + Store certStore = new JcaCertStore(Collections.singletonList(localCryptoConfig.getCertificate())); + + cmsSignGenerator = new CMSSignedDataGenerator(); + ContentSigner sha512Signer = new JcaContentSignerBuilder("SHA256WithRSA").setProvider(bc).build(localCryptoConfig.getPrivateKey()); + + cmsSignGenerator.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder( + new JcaDigestCalculatorProviderBuilder().setProvider(bc).build()).build(sha512Signer, new X509CertificateHolder(localCryptoConfig.getCertificate().getEncoded()) + )); + cmsSignGenerator.addCertificates(certStore); + } catch (CertificateEncodingException | OperatorCreationException | CMSException | IOException e) { + throw new IllegalStateException("Something gone wrong while initializing CertStore using provided private and public key", e); + } + } + + public byte[] sign(InputStream is) throws IOException { + try { + CMSTypedDataInputStream msg = new CMSTypedDataInputStream(is); + CMSSignedData signedData = cmsSignGenerator.generate(msg, false); + return signedData.getEncoded(); + } catch (CMSException e) { + throw new IllegalArgumentException("Something gone wrong while performing pkcs7 hash sign", e); + } + } + +} diff --git a/libs/onboarding-sdk-crypto/src/main/java/it/pagopa/selfcare/onboarding/crypto/config/ArubaInitializer.java b/libs/onboarding-sdk-crypto/src/main/java/it/pagopa/selfcare/onboarding/crypto/config/ArubaInitializer.java new file mode 100644 index 000000000..7575056ce --- /dev/null +++ b/libs/onboarding-sdk-crypto/src/main/java/it/pagopa/selfcare/onboarding/crypto/config/ArubaInitializer.java @@ -0,0 +1,33 @@ +package it.pagopa.selfcare.onboarding.crypto.config; + +import it.pagopa.selfcare.onboarding.crypto.soap.aruba.sign.generated.client.Auth; + +import java.util.Optional; + +public class ArubaInitializer { + + private ArubaInitializer() {} + + public static ArubaSignConfig initializeConfig() { + + ArubaSignConfig config = new ArubaSignConfig(); + config.setConnectTimeoutMs(Optional.ofNullable(System.getenv("ARUBA_SIGN_SERVICE_CONNECT_TIMEOUT_MS")) + .map(Integer::parseInt).orElse(0)); + config.setRequestTimeoutMs(Optional.ofNullable(System.getenv("ARUBA_SIGN_SERVICE_REQUEST_TIMEOUT_MS")) + .map(Integer::parseInt).orElse(0)); + config.setBaseUrl(Optional.ofNullable(System.getenv("ARUBA_SIGN_SERVICE_BASE_URL")) + .orElse("https://arss.demo.firma-automatica.it:443/ArubaSignService/ArubaSignService")); + + Auth auth = new Auth(); + auth.setTypeOtpAuth(System.getenv("ARUBA_SIGN_SERVICE_IDENTITY_TYPE_OTP_AUTH")); + auth.setOtpPwd(System.getenv("ARUBA_SIGN_SERVICE_IDENTITY_OTP_PWD")); + auth.setUser(System.getenv("ARUBA_SIGN_SERVICE_IDENTITY_USER")); + auth.setDelegatedUser(System.getenv("ARUBA_SIGN_SERVICE_IDENTITY_DELEGATED_USER")); + auth.setDelegatedPassword(System.getenv("ARUBA_SIGN_SERVICE_IDENTITY_DELEGATED_PASSWORD")); + auth.setDelegatedDomain(System.getenv("ARUBA_SIGN_SERVICE_IDENTITY_DELEGATED_DOMAIN")); + auth.setTypeHSM("COSIGN"); + config.setAuth(auth); + + return config; + } +} diff --git a/libs/onboarding-sdk-crypto/src/main/java/it/pagopa/selfcare/onboarding/crypto/config/ArubaSignConfig.java b/libs/onboarding-sdk-crypto/src/main/java/it/pagopa/selfcare/onboarding/crypto/config/ArubaSignConfig.java new file mode 100644 index 000000000..8ebf9e9c1 --- /dev/null +++ b/libs/onboarding-sdk-crypto/src/main/java/it/pagopa/selfcare/onboarding/crypto/config/ArubaSignConfig.java @@ -0,0 +1,42 @@ +package it.pagopa.selfcare.onboarding.crypto.config; + +import it.pagopa.selfcare.onboarding.crypto.soap.aruba.sign.generated.client.Auth; + +public class ArubaSignConfig { + private String baseUrl; + private Integer connectTimeoutMs; + private Integer requestTimeoutMs; + private Auth auth; + + public String getBaseUrl() { + return baseUrl; + } + + public void setBaseUrl(String baseUrl) { + this.baseUrl = baseUrl; + } + + public Integer getConnectTimeoutMs() { + return connectTimeoutMs; + } + + public void setConnectTimeoutMs(Integer connectTimeoutMs) { + this.connectTimeoutMs = connectTimeoutMs; + } + + public Integer getRequestTimeoutMs() { + return requestTimeoutMs; + } + + public void setRequestTimeoutMs(Integer requestTimeoutMs) { + this.requestTimeoutMs = requestTimeoutMs; + } + + public Auth getAuth() { + return auth; + } + + public void setAuth(Auth auth) { + this.auth = auth; + } +} diff --git a/libs/onboarding-sdk-crypto/src/main/java/it/pagopa/selfcare/onboarding/crypto/config/LocalCryptoConfig.java b/libs/onboarding-sdk-crypto/src/main/java/it/pagopa/selfcare/onboarding/crypto/config/LocalCryptoConfig.java new file mode 100644 index 000000000..049e43e9a --- /dev/null +++ b/libs/onboarding-sdk-crypto/src/main/java/it/pagopa/selfcare/onboarding/crypto/config/LocalCryptoConfig.java @@ -0,0 +1,26 @@ +package it.pagopa.selfcare.onboarding.crypto.config; + +import java.security.PrivateKey; +import java.security.cert.Certificate; + +public class LocalCryptoConfig { + + private Certificate certificate; + private PrivateKey privateKey; + + public Certificate getCertificate() { + return certificate; + } + + public void setCertificate(Certificate certificate) { + this.certificate = certificate; + } + + public PrivateKey getPrivateKey() { + return privateKey; + } + + public void setPrivateKey(PrivateKey privateKey) { + this.privateKey = privateKey; + } +} diff --git a/libs/onboarding-sdk-crypto/src/main/java/it/pagopa/selfcare/onboarding/crypto/config/LocalCryptoInitializer.java b/libs/onboarding-sdk-crypto/src/main/java/it/pagopa/selfcare/onboarding/crypto/config/LocalCryptoInitializer.java new file mode 100644 index 000000000..4d352f5ee --- /dev/null +++ b/libs/onboarding-sdk-crypto/src/main/java/it/pagopa/selfcare/onboarding/crypto/config/LocalCryptoInitializer.java @@ -0,0 +1,34 @@ +package it.pagopa.selfcare.onboarding.crypto.config; + +import it.pagopa.selfcare.onboarding.crypto.utils.CryptoUtils; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +public class LocalCryptoInitializer { + + private final static Logger log = LoggerFactory.getLogger(LocalCryptoInitializer.class); + + private LocalCryptoInitializer(){} + + public static LocalCryptoConfig initializeConfig() { + LocalCryptoConfig config = new LocalCryptoConfig(); + String cert = System.getenv("CRYPTO_CERT"); + String pKey = System.getenv("CRYPTO_PRIVATE_KEY"); + + try { + if (StringUtils.isBlank(cert) || StringUtils.isBlank(pKey)) { + log.error("Define private and cert values in order to perform locally sign operations"); + } else { + + config.setCertificate(CryptoUtils.getCertificate(cert)); + config.setPrivateKey(CryptoUtils.getPrivateKey(pKey)); + } + } catch (Exception e) { + log.error("Something gone wrong while loading crypto private and public keys", e); + } + + return config; + } +} diff --git a/libs/onboarding-sdk-crypto/src/main/java/it/pagopa/selfcare/onboarding/crypto/entity/SignatureInformation.java b/libs/onboarding-sdk-crypto/src/main/java/it/pagopa/selfcare/onboarding/crypto/entity/SignatureInformation.java new file mode 100644 index 000000000..d12a5f6ce --- /dev/null +++ b/libs/onboarding-sdk-crypto/src/main/java/it/pagopa/selfcare/onboarding/crypto/entity/SignatureInformation.java @@ -0,0 +1,37 @@ +package it.pagopa.selfcare.onboarding.crypto.entity; + +public class SignatureInformation { + private String name; + private String location; + private String reason; + + public SignatureInformation(String name, String location, String reason) { + this.name = name; + this.location = location; + this.reason = reason; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getLocation() { + return location; + } + + public void setLocation(String location) { + this.location = location; + } + + public String getReason() { + return reason; + } + + public void setReason(String reason) { + this.reason = reason; + } +} diff --git a/libs/onboarding-sdk-crypto/src/main/java/it/pagopa/selfcare/onboarding/crypto/utils/CMSTypedDataInputStream.java b/libs/onboarding-sdk-crypto/src/main/java/it/pagopa/selfcare/onboarding/crypto/utils/CMSTypedDataInputStream.java new file mode 100644 index 000000000..01de4d265 --- /dev/null +++ b/libs/onboarding-sdk-crypto/src/main/java/it/pagopa/selfcare/onboarding/crypto/utils/CMSTypedDataInputStream.java @@ -0,0 +1,37 @@ +package it.pagopa.selfcare.onboarding.crypto.utils; + +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; +import org.bouncycastle.cms.CMSTypedData; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +public class CMSTypedDataInputStream implements CMSTypedData { + InputStream in; + + public CMSTypedDataInputStream(InputStream is) { + in = is; + } + + @Override + public ASN1ObjectIdentifier getContentType() { + return PKCSObjectIdentifiers.data; + } + + @Override + public Object getContent() { + return in; + } + + @Override + public void write(OutputStream out) throws IOException { + byte[] buffer = new byte[8 * 1024]; + int read; + while ((read = in.read(buffer)) != -1) { + out.write(buffer, 0, read); + } + in.close(); + } +} \ No newline at end of file diff --git a/libs/onboarding-sdk-crypto/src/main/java/it/pagopa/selfcare/onboarding/crypto/utils/CryptoUtils.java b/libs/onboarding-sdk-crypto/src/main/java/it/pagopa/selfcare/onboarding/crypto/utils/CryptoUtils.java new file mode 100644 index 000000000..1984fdde7 --- /dev/null +++ b/libs/onboarding-sdk-crypto/src/main/java/it/pagopa/selfcare/onboarding/crypto/utils/CryptoUtils.java @@ -0,0 +1,76 @@ +package it.pagopa.selfcare.onboarding.crypto.utils; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.security.KeyFactory; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.security.interfaces.RSAPrivateKey; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.PKCS8EncodedKeySpec; +import java.util.Base64; + +public class CryptoUtils { + + private CryptoUtils() {} + + public static void createParentDirectoryIfNotExists(File destFile) { + Path destDir = destFile.toPath().getParent(); + if (!Files.exists(destDir)) { + try { + Files.createDirectories(destDir); + } catch (IOException var3) { + throw new IllegalArgumentException(String.format("Something gone wrong while creating destination folder: %s", destDir), var3); + } + } + + } + + + + public static byte[] getDigest(InputStream is) { + try { + MessageDigest digest = MessageDigest.getInstance("SHA-256"); + return digest.digest(is.readAllBytes()); + } catch (NoSuchAlgorithmException e) { + throw new IllegalStateException("Something gone wrong selecting digest algorithm", e); + } catch (IOException e) { + throw new IllegalArgumentException("Something gone wrong while reading inputStream", e); + } + } + + public static X509Certificate getCertificate(String cert) throws IOException, CertificateException { + try( + InputStream is = new ByteArrayInputStream(cert.getBytes(StandardCharsets.UTF_8)) + ) { + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + return (X509Certificate) cf.generateCertificate(is); + } + } + + public static RSAPrivateKey getPrivateKey(String privateKey) throws InvalidKeySpecException, NoSuchAlgorithmException, IOException { + String keyStringFormat = pemToString(privateKey); + try( + InputStream is = new ByteArrayInputStream(Base64.getDecoder().decode(keyStringFormat)) + ) { + PKCS8EncodedKeySpec encodedKeySpec = new PKCS8EncodedKeySpec(is.readAllBytes()); + KeyFactory kf = KeyFactory.getInstance("RSA"); + return (RSAPrivateKey) kf.generatePrivate(encodedKeySpec); + } + } + + public static String pemToString(String target) { + return target + .replaceAll("^-----BEGIN[A-Z|\\s]+-----", "") + .replaceAll("\\n+", "") + .replaceAll("-----END[A-Z|\\s]+-----$", ""); + } +} diff --git a/libs/onboarding-sdk-crypto/src/main/java/it/pagopa/selfcare/onboarding/crypto/utils/SoapLoggingHandler.java b/libs/onboarding-sdk-crypto/src/main/java/it/pagopa/selfcare/onboarding/crypto/utils/SoapLoggingHandler.java new file mode 100644 index 000000000..30300b30f --- /dev/null +++ b/libs/onboarding-sdk-crypto/src/main/java/it/pagopa/selfcare/onboarding/crypto/utils/SoapLoggingHandler.java @@ -0,0 +1,63 @@ +package it.pagopa.selfcare.onboarding.crypto.utils; + +import jakarta.xml.soap.SOAPException; +import jakarta.xml.soap.SOAPMessage; +import jakarta.xml.ws.handler.MessageContext; +import jakarta.xml.ws.handler.soap.SOAPHandler; +import jakarta.xml.ws.handler.soap.SOAPMessageContext; +import org.slf4j.Logger; + +import javax.xml.namespace.QName; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.Collections; +import java.util.Set; + + +public class SoapLoggingHandler implements SOAPHandler { + + private static final Logger log = org.slf4j.LoggerFactory.getLogger(SoapLoggingHandler.class); + + @Override + public void close(MessageContext msg) { + // Do Nothing + } + + @Override + public boolean handleFault(SOAPMessageContext msg) { + SOAPMessage message = msg.getMessage(); + try { + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + message.writeTo(outputStream); + log.info("Obtained a fault message: {}", outputStream); + } catch (SOAPException | IOException e) { + log.error("Something gone wrong while tracing soap fault message"); + } + return true; + } + + @Override + public boolean handleMessage(SOAPMessageContext msg) { + if(log.isDebugEnabled()) { + SOAPMessage message = msg.getMessage(); + boolean isOutboundMessage = (Boolean) msg.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); + String msgType = isOutboundMessage + ? "OUTBOUND MESSAGE" + : "INBOUND MESSAGE"; + try { + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + message.writeTo(outputStream); + log.debug("Obtained a {} message: {}", msgType, outputStream); + } catch (SOAPException | IOException e) { + log.error(String.format("Something gone wrong while tracing soap %s", msgType)); + } + } + return true; + } + + @Override + public Set getHeaders() { + return Collections.emptySet(); + } + +} \ No newline at end of file diff --git a/libs/onboarding-sdk-crypto/src/main/resources/docs/aruba/ArubaSignService.wsdl b/libs/onboarding-sdk-crypto/src/main/resources/docs/aruba/ArubaSignService.wsdl new file mode 100644 index 000000000..445981a21 --- /dev/null +++ b/libs/onboarding-sdk-crypto/src/main/resources/docs/aruba/ArubaSignService.wsdl @@ -0,0 +1,772 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/libs/onboarding-sdk-crypto/src/main/resources/docs/aruba/ArubaSignService.xsd b/libs/onboarding-sdk-crypto/src/main/resources/docs/aruba/ArubaSignService.xsd new file mode 100644 index 000000000..538df5ba2 --- /dev/null +++ b/libs/onboarding-sdk-crypto/src/main/resources/docs/aruba/ArubaSignService.xsd @@ -0,0 +1,1114 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/libs/onboarding-sdk-crypto/src/main/resources/docs/aruba/oasis-200401-wss-wssecurity-utility-1.0.xsd b/libs/onboarding-sdk-crypto/src/main/resources/docs/aruba/oasis-200401-wss-wssecurity-utility-1.0.xsd new file mode 100644 index 000000000..f8d74e9c6 --- /dev/null +++ b/libs/onboarding-sdk-crypto/src/main/resources/docs/aruba/oasis-200401-wss-wssecurity-utility-1.0.xsd @@ -0,0 +1,108 @@ + + + + + + + +This type defines the fault code value for Timestamp message expiration. + + + + + + + + + + +This global attribute supports annotating arbitrary elements with an ID. + + + + + + +Convenience attribute group used to simplify this schema. + + + + + + + + + +This type is for elements whose [children] is a psuedo-dateTime and can have arbitrary attributes. + + + + + + + + + + + +This type is for elements whose [children] is an anyURI and can have arbitrary attributes. + + + + + + + + + + + + +This complex type ties together the timestamp related elements into a composite type. + + + + + + + + + + + + + + +This element allows Timestamps to be applied anywhere element wildcards are present, +including as a SOAP header. + + + + + + + +This element allows an expiration time to be applied anywhere element wildcards are present. + + + + + + +This element allows a creation time to be applied anywhere element wildcards are present. + + + + diff --git a/libs/onboarding-sdk-crypto/src/main/resources/docs/aruba/xmlmime.xml b/libs/onboarding-sdk-crypto/src/main/resources/docs/aruba/xmlmime.xml new file mode 100644 index 000000000..766a07bd9 --- /dev/null +++ b/libs/onboarding-sdk-crypto/src/main/resources/docs/aruba/xmlmime.xml @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/libs/onboarding-sdk-crypto/src/test/java/it/pagopa/selfcare/onboarding/crypto/PadesSignServiceTest.java b/libs/onboarding-sdk-crypto/src/test/java/it/pagopa/selfcare/onboarding/crypto/PadesSignServiceTest.java new file mode 100644 index 000000000..2dd64efe6 --- /dev/null +++ b/libs/onboarding-sdk-crypto/src/test/java/it/pagopa/selfcare/onboarding/crypto/PadesSignServiceTest.java @@ -0,0 +1,140 @@ +package it.pagopa.selfcare.onboarding.crypto; + + +import it.pagopa.selfcare.onboarding.crypto.config.LocalCryptoConfig; +import it.pagopa.selfcare.onboarding.crypto.entity.SignatureInformation; +import org.apache.pdfbox.cos.COSName; +import org.apache.pdfbox.io.IOUtils; +import org.apache.pdfbox.pdmodel.PDDocument; +import org.apache.pdfbox.pdmodel.PDPage; +import org.apache.pdfbox.pdmodel.PDPageTree; +import org.apache.pdfbox.pdmodel.interactive.digitalsignature.PDSignature; +import org.bouncycastle.cert.X509CertificateHolder; +import org.bouncycastle.cms.CMSException; +import org.bouncycastle.cms.CMSProcessableByteArray; +import org.bouncycastle.cms.CMSSignedData; +import org.bouncycastle.cms.SignerInformation; +import org.bouncycastle.cms.jcajce.JcaSimpleSignerInfoVerifierBuilder; +import org.bouncycastle.operator.OperatorCreationException; +import org.bouncycastle.util.Store; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.security.GeneralSecurityException; +import java.security.cert.CertificateEncodingException; +import java.security.cert.CertificateException; +import java.util.Collection; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + + +public class PadesSignServiceTest { + + private PadesSignService service; + + // mocked data will not be aligned with timestamp alway updated, thus base test could not successfully sign + protected boolean verifySignerInformation = true; + protected Path inputFilePath = Path.of("src/test/resources/signTest.pdf"); + + private Pkcs7HashSignService pkcs7HashSignService; + + @BeforeEach + void setup() throws IOException { + pkcs7HashSignService = mock(Pkcs7HashSignService.class); + service = new PadesSignServiceImpl(pkcs7HashSignService); + } + + @Test + protected void testPadesSign() throws IOException, GeneralSecurityException, OperatorCreationException, CMSException { + File inputFile = inputFilePath.toFile(); + File outputFile = getOutputPadesFile(); + if (outputFile.exists()) { + Assertions.assertTrue(outputFile.delete()); + } + + when(pkcs7HashSignService.sign(any())).thenReturn(Files.readAllBytes(inputFilePath)); + + service.padesSign(inputFile, outputFile, new SignatureInformation("PagoPA S.P.A", "Rome", "onboarding contract")); + Assertions.assertTrue(outputFile.exists()); + + checkPadesSignature(inputFile, outputFile); + } + + protected File getOutputPadesFile() { + return Path.of("target/tmp/signedSignTest-selfSigned.pdf").toFile(); + } + + @SuppressWarnings("unchecked") + private void checkPadesSignature(File origFile, File signedFile) + throws IOException, CMSException, OperatorCreationException, GeneralSecurityException + { + PDDocument document = PDDocument.load(origFile); + // get string representation of pages COSObject + String origPageKey = document.getDocumentCatalog().getCOSObject().getItem(COSName.PAGES).toString(); + document.close(); + + document = PDDocument.load(signedFile); + + // early detection of problems in the page structure + int p = 0; + PDPageTree pageTree = document.getPages(); + for (PDPage page : document.getPages()) + { + Assertions.assertEquals(p, pageTree.indexOf(page)); + ++p; + } + + Assertions.assertEquals(origPageKey, document.getDocumentCatalog().getCOSObject().getItem(COSName.PAGES).toString()); + + List signatureDictionaries = document.getSignatureDictionaries(); + if (signatureDictionaries.isEmpty()) + { + Assertions.fail("no signature found"); + } + for (PDSignature sig : document.getSignatureDictionaries()) + { + byte[] contents = sig.getContents(); + + byte[] buf = sig.getSignedContent(new FileInputStream(signedFile)); + + // verify that getSignedContent() brings the same content + // regardless whether from an InputStream or from a byte array + FileInputStream fis2 = new FileInputStream(signedFile); + byte[] buf2 = sig.getSignedContent(IOUtils.toByteArray(fis2)); + Assertions.assertArrayEquals(buf, buf2); + fis2.close(); + + // verify that all getContents() methods returns the same content + FileInputStream fis3 = new FileInputStream(signedFile); + byte[] contents2 = sig.getContents(IOUtils.toByteArray(fis3)); + Assertions.assertArrayEquals(contents, contents2); + fis3.close(); + byte[] contents3 = sig.getContents(new FileInputStream(signedFile)); + Assertions.assertArrayEquals(contents, contents3); + } + document.close(); + } + + @Test + void testHandleException() throws IOException { + File inputFile = inputFilePath.toFile(); + File outputFile = getOutputPadesFile(); + if (outputFile.exists()) { + Assertions.assertTrue(outputFile.delete()); + } + + + when(pkcs7HashSignService.sign(any())).thenThrow(new RuntimeException()); + assertThrows(IllegalStateException.class, () -> service.padesSign(inputFile, outputFile, new SignatureInformation("PagoPA S.P.A", "Rome", "onboarding contract"))); + } +} \ No newline at end of file diff --git a/libs/onboarding-sdk-crypto/src/test/java/it/pagopa/selfcare/onboarding/crypto/Pkcs7HashSignServiceTest.java b/libs/onboarding-sdk-crypto/src/test/java/it/pagopa/selfcare/onboarding/crypto/Pkcs7HashSignServiceTest.java new file mode 100644 index 000000000..490b284ff --- /dev/null +++ b/libs/onboarding-sdk-crypto/src/test/java/it/pagopa/selfcare/onboarding/crypto/Pkcs7HashSignServiceTest.java @@ -0,0 +1,100 @@ +package it.pagopa.selfcare.onboarding.crypto; + +import org.junit.jupiter.api.*; +import uk.org.webcompere.systemstubs.environment.EnvironmentVariables; + +import java.io.FileInputStream; +import java.io.IOException; +import java.nio.file.Path; +import java.util.Base64; + +import static uk.org.webcompere.systemstubs.SystemStubs.withEnvironmentVariables; + +class Pkcs7HashSignServiceTest { + + private static final String testCert = "-----BEGIN CERTIFICATE-----\n" + + "MIIDnzCCAoegAwIBAgIUJ8/0z+sR6Llr9FcIGoc5nvZQydgwDQYJKoZIhvcNAQEL\n" + + "BQAwXzELMAkGA1UEBhMCSVQxDTALBgNVBAgMBFJPTUUxDTALBgNVBAcMBFJPTUUx\n" + + "DjAMBgNVBAoMBUlEUEFZMQ4wDAYDVQQLDAVJRFBBWTESMBAGA1UEAwwJbG9jYWxo\n" + + "b3N0MB4XDTIyMTEwOTE1MTI0NFoXDTMyMDkxNzE1MTI0NFowXzELMAkGA1UEBhMC\n" + + "SVQxDTALBgNVBAgMBFJPTUUxDTALBgNVBAcMBFJPTUUxDjAMBgNVBAoMBUlEUEFZ\n" + + "MQ4wDAYDVQQLDAVJRFBBWTESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG\n" + + "9w0BAQEFAAOCAQ8AMIIBCgKCAQEArDOJKswwCaKdYJbaHZz3bgEIl7z1ArZpNI54\n" + + "ZGaXcRitiwjr/W9fenW69mG7IAlITuPtaIu4iggXTcSRuaulres2EvuP7KjL0tfo\n" + + "x/PstqaMZzLF8wOYfJE4iJ8ffcQL67LJ3/Wwn2FhYVV+4D2AYW8QPdRm406HJG7b\n" + + "NKLmdM9AFUQp6zoTvNegyWQyAfH40i72UopltDubcAykD6YgkRctCtKd8h/BRpIR\n" + + "tMn0AGLM/o5qwYu+eCAy8/7Ppj3HzCwHkDOJad/g2pRj4soJdvn5rP6TM4OVtZ7V\n" + + "ehxionkaccBPcyDGSrIo5837XYaGv3r7Rn0rCplfxnU4Gtmd5wIDAQABo1MwUTAd\n" + + "BgNVHQ4EFgQUPYfJeHRHwSLmcueB8jUQSHUReVIwHwYDVR0jBBgwFoAUPYfJeHRH\n" + + "wSLmcueB8jUQSHUReVIwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOC\n" + + "AQEAK34LEHSVM44Wwbs9nKDKeQTRGosdd+gQSrqGf3nI0vkhckuaoYPnuFKi+eo2\n" + + "r+J6xXgqhQfrvhXnYxNEJr9U+9ELBc3IjG6bTUS6HyWhu2PJCeckxQJqonVntl99\n" + + "jmEr4G7QJeDc9oJmC0NJqBmQS/D0tMxChNWpYe1AoGXwqc4S6NTd3x2Z8THzv8du\n" + + "MMn7+1f/VOWe7/Iuuvx5DHN2JFi0lvhMqwglIweGn/qLGB0+r9GM+QlfGuZvUey2\n" + + "x3C0DLQnNIkNKktGjaNjCmpZcd9SIVi6TOPpR+AxlIddYvUXu4GYVXyfDPgzPeha\n" + + "JDiI4WMkIMmYSzhMc/lfuDMGow==\n" + + "-----END CERTIFICATE-----"; + + private static final String testPrivateKey = "-----BEGIN PRIVATE KEY-----\n" + + "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCsM4kqzDAJop1g\n" + + "ltodnPduAQiXvPUCtmk0jnhkZpdxGK2LCOv9b196dbr2YbsgCUhO4+1oi7iKCBdN\n" + + "xJG5q6Wt6zYS+4/sqMvS1+jH8+y2poxnMsXzA5h8kTiInx99xAvrssnf9bCfYWFh\n" + + "VX7gPYBhbxA91GbjTockbts0ouZ0z0AVRCnrOhO816DJZDIB8fjSLvZSimW0O5tw\n" + + "DKQPpiCRFy0K0p3yH8FGkhG0yfQAYsz+jmrBi754IDLz/s+mPcfMLAeQM4lp3+Da\n" + + "lGPiygl2+fms/pMzg5W1ntV6HGKieRpxwE9zIMZKsijnzftdhoa/evtGfSsKmV/G\n" + + "dTga2Z3nAgMBAAECggEAEC6FmMJ4Tyd7T3zNgVPjQnCRbKTihz858qjislibqZKO\n" + + "mE6d0oJ5P+o5R/bWHUQSCevMPvNGQ55QBkxO/1ocZxP/0FfYZf5UrPsCEmwfFejf\n" + + "r8DrLhNr7GS/IcOGM4zNK/hwlP2i+88sVfexRQQygLVtmsnPY1PZSjiqm68lJdu+\n" + + "aP8TYM10y1aeiYnfuUYvnvXJFXeTEockhaUJTmeIQNbbUy+pyJ0mAPASPtXRLr8h\n" + + "UflutICnWcx4v/qkCn1jmHw+NMA4q7hOH7UuOAqj53FqGMN+IWfjMmmYoQ7MVURx\n" + + "8CrnEtlCOua+C8EEIFL2ylvV7X0cv/DqCJLVQoegsQKBgQDLzMaAjNgD8xSXp+Gj\n" + + "beeUsSGptEaGMuA89AzyTnCyvU9a1HGwDAghoQPae+pVk7R5uokojWkBVzP/kKxv\n" + + "ZldGwPOegUUdBLS4yJML+OkqtoCgf3Mbcozm5dVYtx7bYdhh3PswzRmn/h/YjEAz\n" + + "+/mxi6dJir0k0Nd4YNtQbzBctwKBgQDYTtSmJvVQdOHnzqA/LRmMF1l+HaqLuDfu\n" + + "B4rDlxCdDfOAvHqz+3YapP3B4MQuz29TSDqwAnzoN2XZX5B6g/jKauWpAwZkFXuO\n" + + "fqcfNG/+MewTcHIYNm+EtgXtIsnCXDfAeXdQapzNsOX+XSF/aWcgGHg18xOBPt0R\n" + + "7Aoa/h34UQKBgQCsCzGjwcJ2CxXeNPYxfg1ao/HUDoDet0I/kpL/VqKi8Vd1SRS0\n" + + "VmPi58eWALfBCJD5ljRFjKMRY6lc3KgE3vNconTG4UAUEC30NDaWi8liqnCJjS4C\n" + + "BMDYBzwEyYn+D2qYqvFOsEYxYEFIEJX+jH+sl0VguwOTec38LF/YVhUQnwKBgG5u\n" + + "2Kw3SZkZA1ioqjF24gsexKbZmH+avps8qICw+F9mhwIbt/15jVOPFqrMCPzpFKoN\n" + + "P0ErFAAugEYZPxb9l6AoMTY3gCTKvvkB+mq5B9BcRm2qQ+XOrOKxV5c44o7jK+eN\n" + + "W/fnZkSxYsqZW4fEFU1SkNTiU/vxT0ZeHs6nHD/xAoGAOIqaqQnJfGj/wLo3Z9o5\n" + + "/Oxu1zTPGZC6SqpdygCjlQ0kQ8Bp0LV7nL06/VCHAHI2lF12xApRnFk7GY3xyqK8\n" + + "nYxeRASCj3GGmLupGshtfCtDBeysE2h7kj3Bo0d6g1Ye+j8BUZuZaZm6WNlo7cgE\n" + + "NLHn1k0IpmXFOiFa1Y1D6Bc=\n" + + "-----END PRIVATE KEY-----"; + + private Pkcs7HashSignService service; + + private static EnvironmentVariables environmentVariables = new EnvironmentVariables(); + + @BeforeAll + static void setup() throws Exception { + environmentVariables.set("CRYPTO_CERT", testCert); + environmentVariables.set("CRYPTO_PRIVATE_KEY", testPrivateKey); + environmentVariables.setup(); + } + + @AfterAll + static void afterAll() throws Exception { + environmentVariables.teardown(); + } + @Test + void shouldAssertEncoding() throws IOException { + + service = new Pkcs7HashSignServiceImpl(); + try (FileInputStream fis = new FileInputStream(Path.of("src/test/resources/signTest.pdf").toFile())) { + byte[] result = service.sign(fis); + Assertions.assertNotNull(result); + checkPkcs7HashSign(Base64.getEncoder().encodeToString(result)); + } + } + + protected void checkPkcs7HashSign(String result) { + String expectedPrefix = "MIAGCSqGSIb3DQEHAqCAMIACAQExDTALBglghkgBZQMEAgEwCwYJKoZIhvcNAQcBoIAwggOfMIICh6ADAgECAhQnz"; + Assertions.assertTrue( + result.startsWith(expectedPrefix), + String.format("Prefix unexpected:\n%s\n%s", result, expectedPrefix) + ); + } +} diff --git a/libs/onboarding-sdk-crypto/src/test/java/it/pagopa/selfcare/onboarding/crypto/utils/SoapLoggingHandlerTest.java b/libs/onboarding-sdk-crypto/src/test/java/it/pagopa/selfcare/onboarding/crypto/utils/SoapLoggingHandlerTest.java new file mode 100644 index 000000000..b67ca6deb --- /dev/null +++ b/libs/onboarding-sdk-crypto/src/test/java/it/pagopa/selfcare/onboarding/crypto/utils/SoapLoggingHandlerTest.java @@ -0,0 +1,52 @@ +package it.pagopa.selfcare.onboarding.crypto.utils; + +import jakarta.xml.soap.SOAPMessage; +import jakarta.xml.ws.handler.MessageContext; +import jakarta.xml.ws.handler.soap.SOAPMessageContext; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +import java.util.Collections; + +class SoapLoggingHandlerTest { + + private final SoapLoggingHandler soapLoggingHandler = new SoapLoggingHandler(); + + @Test + void testInbound(){ + SOAPMessageContext messageMock = getSoapMessageMock(false); + + Assertions.assertTrue(soapLoggingHandler.handleMessage(messageMock)); + } + + @Test + void testOutbound(){ + SOAPMessageContext messageMock = getSoapMessageMock(true); + + Assertions.assertTrue(soapLoggingHandler.handleMessage(messageMock)); + } + + private SOAPMessageContext getSoapMessageMock(boolean t) { + SOAPMessageContext messageMock = Mockito.mock(SOAPMessageContext.class); + Mockito.when(messageMock.getMessage()).thenReturn(Mockito.mock(SOAPMessage.class)); + Mockito.when(messageMock.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY)).thenReturn(t); + return messageMock; + } + + @Test + void testFault(){ + SOAPMessageContext messageMock = Mockito.mock(SOAPMessageContext.class); + Mockito.when(messageMock.getMessage()).thenReturn(Mockito.mock(SOAPMessage.class)); + + Assertions.assertTrue(soapLoggingHandler.handleFault(messageMock)); + } + + @Test + void testGetHeaders(){ + Assertions.assertEquals( + Collections.emptySet(), + soapLoggingHandler.getHeaders() + ); + } +} diff --git a/libs/onboarding-sdk-crypto/src/test/resources/signTest.pdf b/libs/onboarding-sdk-crypto/src/test/resources/signTest.pdf new file mode 100644 index 000000000..19d5aefec Binary files /dev/null and b/libs/onboarding-sdk-crypto/src/test/resources/signTest.pdf differ diff --git a/libs/onboarding-sdk-pom/.gitignore b/libs/onboarding-sdk-pom/.gitignore new file mode 100644 index 000000000..5ff6309b7 --- /dev/null +++ b/libs/onboarding-sdk-pom/.gitignore @@ -0,0 +1,38 @@ +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### IntelliJ IDEA ### +.idea/modules.xml +.idea/jarRepositories.xml +.idea/compiler.xml +.idea/libraries/ +*.iws +*.iml +*.ipr + +### Eclipse ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ + +### Mac OS ### +.DS_Store \ No newline at end of file diff --git a/libs/onboarding-sdk-pom/pom.xml b/libs/onboarding-sdk-pom/pom.xml new file mode 100644 index 000000000..d9aba6b95 --- /dev/null +++ b/libs/onboarding-sdk-pom/pom.xml @@ -0,0 +1,111 @@ + + 4.0.0 + + + it.pagopa.selfcare + onboarding-sdk-pom + pom + onboarding-sdk-pom + 0.1.3 + + + 17 + 17 + 5.7.2 + 5.7.0 + true + + + + + selfcare-github + Selfcare Onboarding SDK + https://maven.pkg.github.com/pagopa/selfcare-onboarding + + + + + + + io.quarkus.platform + quarkus-bom + 3.4.2 + pom + import + + + + + + + org.junit.jupiter + junit-jupiter-api + ${junit-jupiter.version} + test + + + org.junit.jupiter + junit-jupiter-engine + ${junit-jupiter.version} + test + + + org.mockito + mockito-core + ${mockito.version} + test + + + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.1 + + + org.sonarsource.scanner.maven + sonar-maven-plugin + 3.10.0.2594 + + + org.jacoco + jacoco-maven-plugin + 0.8.11 + + + + + + + org.jacoco + jacoco-maven-plugin + + + default-prepare-agent + + prepare-agent + + + true + + + + + report + test + + report + + + + + + + + + diff --git a/libs/onboarding-sdk-product/.gitignore b/libs/onboarding-sdk-product/.gitignore new file mode 100644 index 000000000..5ff6309b7 --- /dev/null +++ b/libs/onboarding-sdk-product/.gitignore @@ -0,0 +1,38 @@ +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### IntelliJ IDEA ### +.idea/modules.xml +.idea/jarRepositories.xml +.idea/compiler.xml +.idea/libraries/ +*.iws +*.iml +*.ipr + +### Eclipse ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ + +### Mac OS ### +.DS_Store \ No newline at end of file diff --git a/libs/onboarding-sdk-product/README.md b/libs/onboarding-sdk-product/README.md new file mode 100644 index 000000000..ddc7de713 --- /dev/null +++ b/libs/onboarding-sdk-product/README.md @@ -0,0 +1,104 @@ +# Onboarding SDK Product + +This library has been developed to provide a set of Java utility classes to simplify the work of handle **Selfcare Product** as string. + +Selfcare Products is a collection of PagoPA products available for use by institutions. Each product contains specific information, such as its status, admitted role, or a filepath template for building contract necessary for selfcare business logic. + +The Onboarding SDK Product offers a set of classes designed for managing this collection of records using a file. + +## Installation + +To use this library in your projects, you can add the dependency to your pom.xml if you're using Maven: + +```shell script + + it.pagopa.selfcare + onboarding-sdk-product + 0.0.1 + +``` + +If you are using Gradle, you can add the dependency to your build.gradle file: + +```shell script +dependencies { + implementation 'it.pagopa.selfcare:onboarding-sdk-product:0.0.1' +} +``` +## Product JSON Schema + +Product string which are used by ProductService must follow a specific schema, look at src/main/schema folder. + +## Usage + +Here's an example of how to use ProductService for retrieving product: + +```java script + +public class Main { + public static void main(String[] args) { + final String productJsonString = ... ; // set a json string compliant to a List of Product Pojo + final ProductService productService = new ProductServiceDefault(productJsonString); + + //Get product if it is valid + final String productId = "prod-pagopa"; + final Product product = productService.getProductIsValid(productId); + } +} +``` + +Generally, you load product json string from an azure storage container, this example use onboading-sdk-azure-storage, and inject the product service in the context of Quarkus or Spring (replace @ApplicationScoped with @Bean). + +```java script + @ApplicationScoped + public ProductService productService(AzureStorageConfig azureStorageConfig){ + AzureBlobClient azureBlobClient = new AzureBlobClientDefault(azureStorageConfig.connectionStringProduct(), azureStorageConfig.containerProduct()); + String productJsonString = azureBlobClient.getFileAsText(azureStorageConfig.productFilepath()); + try { + return new ProductServiceDefault(productJsonString, objectMapper()); + } catch (JsonProcessingException e) { + throw new IllegalArgumentException("Found an issue when trying to serialize product json string!!"); + } + } + ``` + +## CacheableProductService + +This product has been primarly designed to maintain the last updated version of the product.json information in memory and refresh it based on the azure BlobProperties "LastModified" property. + +When a new ProductServiceCacheable gets instantiated a new ProductServiceDefault gets created reading the current product.json from azure, and its current LastModified date gets saved as productLastModifiedDate. + +Every time a method call is made, the refreshProduct() is called and the saved lastModifiedDate is compared to the current LastModified date read from the BlobProperties, if the lastModifiedDate is older than the current date from azure, a new ProductServiceDefault will be created with the updated product.json taken from azure storage. + + +```java script + public ProductServiceCacheable(AzureBlobClient azureBlobClient,String filePath){ + this.azureBlobClient=azureBlobClient; + this.filePath=filePath; + refreshProduct(); + } + public void refreshProduct(){ + LocalDateTime currentLastModifiedDate=azureBlobClient.getProperties(filePath).getLastModified().toLocalDateTime(); + if(productLastModifiedDate==null||currentLastModifiedDate.isAfter(productLastModifiedDate)){ + String productJsonString=azureBlobClient.getFileAsText(filePath); + try{ + this.productService=new ProductServiceDefault(productJsonString); + }catch(JsonProcessingException e){ + throw new IllegalArgumentException(e.getMessage()); + } + this.productLastModifiedDate=currentLastModifiedDate; + } + } +``` +Here's an example on how to retrieve the ProductService using ProductServiceCacheable. +```java script + @ApplicationScoped + public ProductService productService(AzureStorageConfig azureStorageConfig){ + AzureBlobClient azureBlobClient = new AzureBlobClientDefault(azureStorageConfig.connectionStringProduct(), azureStorageConfig.containerProduct()); + try{ + return new ProductServiceCacheable(azureBlobClient, azureStorageConfig.getFilePath()); + } catch(IllegalArgumentException e){ + throw new IllegalArgumentException("Found an issue when trying to serialize product json string!!"); + } + } +``` \ No newline at end of file diff --git a/libs/onboarding-sdk-product/pom.xml b/libs/onboarding-sdk-product/pom.xml new file mode 100644 index 000000000..00cc2fe69 --- /dev/null +++ b/libs/onboarding-sdk-product/pom.xml @@ -0,0 +1,55 @@ + + 4.0.0 + + it.pagopa.selfcare + onboarding-sdk-pom + 0.1.3 + ../onboarding-sdk-pom + + onboarding-sdk-product + onboarding-sdk-product + + + 2.15.2 + + + + + + com.fasterxml.jackson.core + jackson-databind + ${jackson.version} + + + it.pagopa.selfcare + onboarding-sdk-azure-storage + ${project.version} + + + + it.pagopa.selfcare + onboarding-sdk-common + ${project.version} + + + org.mockito + mockito-inline + 2.13.0 + test + + + io.quarkus + quarkus-junit5-mockito + test + + + com.microsoft.azure + azure-storage + 8.6.6 + test + + + + + diff --git a/libs/onboarding-sdk-product/src/main/java/it/pagopa/selfcare/product/entity/BackOfficeConfigurations.java b/libs/onboarding-sdk-product/src/main/java/it/pagopa/selfcare/product/entity/BackOfficeConfigurations.java new file mode 100644 index 000000000..e9284a3ae --- /dev/null +++ b/libs/onboarding-sdk-product/src/main/java/it/pagopa/selfcare/product/entity/BackOfficeConfigurations.java @@ -0,0 +1,23 @@ +package it.pagopa.selfcare.product.entity; + +public class BackOfficeConfigurations { + + private String url; + private String identityTokenAudience; + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + public String getIdentityTokenAudience() { + return identityTokenAudience; + } + + public void setIdentityTokenAudience(String identityTokenAudience) { + this.identityTokenAudience = identityTokenAudience; + } +} diff --git a/libs/onboarding-sdk-product/src/main/java/it/pagopa/selfcare/product/entity/ContractStorage.java b/libs/onboarding-sdk-product/src/main/java/it/pagopa/selfcare/product/entity/ContractStorage.java new file mode 100644 index 000000000..3818d4df0 --- /dev/null +++ b/libs/onboarding-sdk-product/src/main/java/it/pagopa/selfcare/product/entity/ContractStorage.java @@ -0,0 +1,34 @@ +package it.pagopa.selfcare.product.entity; + +import java.time.Instant; + +public class ContractStorage { + + private Instant contractTemplateUpdatedAt; + private String contractTemplatePath; + private String contractTemplateVersion; + + public Instant getContractTemplateUpdatedAt() { + return contractTemplateUpdatedAt; + } + + public void setContractTemplateUpdatedAt(Instant contractTemplateUpdatedAt) { + this.contractTemplateUpdatedAt = contractTemplateUpdatedAt; + } + + public String getContractTemplatePath() { + return contractTemplatePath; + } + + public void setContractTemplatePath(String contractTemplatePath) { + this.contractTemplatePath = contractTemplatePath; + } + + public String getContractTemplateVersion() { + return contractTemplateVersion; + } + + public void setContractTemplateVersion(String contractTemplateVersion) { + this.contractTemplateVersion = contractTemplateVersion; + } +} diff --git a/libs/onboarding-sdk-product/src/main/java/it/pagopa/selfcare/product/entity/Product.java b/libs/onboarding-sdk-product/src/main/java/it/pagopa/selfcare/product/entity/Product.java new file mode 100644 index 000000000..d2c098dc3 --- /dev/null +++ b/libs/onboarding-sdk-product/src/main/java/it/pagopa/selfcare/product/entity/Product.java @@ -0,0 +1,236 @@ +package it.pagopa.selfcare.product.entity; + +import it.pagopa.selfcare.onboarding.common.InstitutionType; +import it.pagopa.selfcare.onboarding.common.PartyRole; + +import java.time.Instant; +import java.util.Map; + +public class Product { + + private String id; + private String logo; + private String depictImageUrl; + private String title; + private String logoBgColor; + private String description; + private String urlPublic; + private String urlBO; + private Instant createdAt; + private String createdBy; + private Instant modifiedAt; + private String modifiedBy; + private Map roleMappings; + private String roleManagementURL; + private Instant contractTemplateUpdatedAt; + private String contractTemplatePath; + private String contractTemplateVersion; + private Map institutionContractMappings; + private boolean enabled = true; + private boolean delegable; + private ProductStatus status; + private String parentId; + private String identityTokenAudience; + private Map backOfficeEnvironmentConfigurations; + private Product parent; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getLogo() { + return logo; + } + + public void setLogo(String logo) { + this.logo = logo; + } + + public String getDepictImageUrl() { + return depictImageUrl; + } + + public void setDepictImageUrl(String depictImageUrl) { + this.depictImageUrl = depictImageUrl; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getLogoBgColor() { + return logoBgColor; + } + + public void setLogoBgColor(String logoBgColor) { + this.logoBgColor = logoBgColor; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getUrlPublic() { + return urlPublic; + } + + public void setUrlPublic(String urlPublic) { + this.urlPublic = urlPublic; + } + + public String getUrlBO() { + return urlBO; + } + + public void setUrlBO(String urlBO) { + this.urlBO = urlBO; + } + + public Instant getCreatedAt() { + return createdAt; + } + + public void setCreatedAt(Instant createdAt) { + this.createdAt = createdAt; + } + + public String getCreatedBy() { + return createdBy; + } + + public void setCreatedBy(String createdBy) { + this.createdBy = createdBy; + } + + public Instant getModifiedAt() { + return modifiedAt; + } + + public void setModifiedAt(Instant modifiedAt) { + this.modifiedAt = modifiedAt; + } + + public String getModifiedBy() { + return modifiedBy; + } + + public void setModifiedBy(String modifiedBy) { + this.modifiedBy = modifiedBy; + } + + public Map getRoleMappings() { + return roleMappings; + } + + public void setRoleMappings(Map roleMappings) { + this.roleMappings = roleMappings; + } + + public String getRoleManagementURL() { + return roleManagementURL; + } + + public void setRoleManagementURL(String roleManagementURL) { + this.roleManagementURL = roleManagementURL; + } + + public Instant getContractTemplateUpdatedAt() { + return contractTemplateUpdatedAt; + } + + public void setContractTemplateUpdatedAt(Instant contractTemplateUpdatedAt) { + this.contractTemplateUpdatedAt = contractTemplateUpdatedAt; + } + + public String getContractTemplatePath() { + return contractTemplatePath; + } + + public void setContractTemplatePath(String contractTemplatePath) { + this.contractTemplatePath = contractTemplatePath; + } + + public String getContractTemplateVersion() { + return contractTemplateVersion; + } + + public void setContractTemplateVersion(String contractTemplateVersion) { + this.contractTemplateVersion = contractTemplateVersion; + } + + public Map getInstitutionContractMappings() { + return institutionContractMappings; + } + + public void setInstitutionContractMappings(Map institutionContractMappings) { + this.institutionContractMappings = institutionContractMappings; + } + + public boolean isEnabled() { + return enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + public boolean isDelegable() { + return delegable; + } + + public void setDelegable(boolean delegable) { + this.delegable = delegable; + } + + public ProductStatus getStatus() { + return status; + } + + public void setStatus(ProductStatus status) { + this.status = status; + } + + public String getParentId() { + return parentId; + } + + public void setParentId(String parentId) { + this.parentId = parentId; + } + + public String getIdentityTokenAudience() { + return identityTokenAudience; + } + + public void setIdentityTokenAudience(String identityTokenAudience) { + this.identityTokenAudience = identityTokenAudience; + } + + public Map getBackOfficeEnvironmentConfigurations() { + return backOfficeEnvironmentConfigurations; + } + + public void setBackOfficeEnvironmentConfigurations(Map backOfficeEnvironmentConfigurations) { + this.backOfficeEnvironmentConfigurations = backOfficeEnvironmentConfigurations; + } + + public Product getParent() { + return parent; + } + + public void setParent(Product parent) { + this.parent = parent; + } +} diff --git a/libs/onboarding-sdk-product/src/main/java/it/pagopa/selfcare/product/entity/ProductRole.java b/libs/onboarding-sdk-product/src/main/java/it/pagopa/selfcare/product/entity/ProductRole.java new file mode 100644 index 000000000..6d5793f1b --- /dev/null +++ b/libs/onboarding-sdk-product/src/main/java/it/pagopa/selfcare/product/entity/ProductRole.java @@ -0,0 +1,32 @@ +package it.pagopa.selfcare.product.entity; + +public class ProductRole { + + private String code; + private String label; + private String description; + + public String getCode() { + return code; + } + + public void setCode(String code) { + this.code = code; + } + + public String getLabel() { + return label; + } + + public void setLabel(String label) { + this.label = label; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } +} diff --git a/libs/onboarding-sdk-product/src/main/java/it/pagopa/selfcare/product/entity/ProductRoleInfo.java b/libs/onboarding-sdk-product/src/main/java/it/pagopa/selfcare/product/entity/ProductRoleInfo.java new file mode 100644 index 000000000..05f4da849 --- /dev/null +++ b/libs/onboarding-sdk-product/src/main/java/it/pagopa/selfcare/product/entity/ProductRoleInfo.java @@ -0,0 +1,25 @@ +package it.pagopa.selfcare.product.entity; + +import java.util.List; + +public class ProductRoleInfo { + + private boolean multiroleAllowed; + private List roles; + + public boolean isMultiroleAllowed() { + return multiroleAllowed; + } + + public void setMultiroleAllowed(boolean multiroleAllowed) { + this.multiroleAllowed = multiroleAllowed; + } + + public List getRoles() { + return roles; + } + + public void setRoles(List roles) { + this.roles = roles; + } +} diff --git a/libs/onboarding-sdk-product/src/main/java/it/pagopa/selfcare/product/entity/ProductStatus.java b/libs/onboarding-sdk-product/src/main/java/it/pagopa/selfcare/product/entity/ProductStatus.java new file mode 100644 index 000000000..db06c073a --- /dev/null +++ b/libs/onboarding-sdk-product/src/main/java/it/pagopa/selfcare/product/entity/ProductStatus.java @@ -0,0 +1,6 @@ +package it.pagopa.selfcare.product.entity; + +public enum ProductStatus { + + ACTIVE, TESTING, PHASE_OUT, INACTIVE +} diff --git a/libs/onboarding-sdk-product/src/main/java/it/pagopa/selfcare/product/exception/InvalidRoleMappingException.java b/libs/onboarding-sdk-product/src/main/java/it/pagopa/selfcare/product/exception/InvalidRoleMappingException.java new file mode 100644 index 000000000..47137a730 --- /dev/null +++ b/libs/onboarding-sdk-product/src/main/java/it/pagopa/selfcare/product/exception/InvalidRoleMappingException.java @@ -0,0 +1,8 @@ +package it.pagopa.selfcare.product.exception; + +public class InvalidRoleMappingException extends RuntimeException { + + public InvalidRoleMappingException(String message){ + super(message); + } +} diff --git a/libs/onboarding-sdk-product/src/main/java/it/pagopa/selfcare/product/exception/ProductNotFoundException.java b/libs/onboarding-sdk-product/src/main/java/it/pagopa/selfcare/product/exception/ProductNotFoundException.java new file mode 100644 index 000000000..b325f6f67 --- /dev/null +++ b/libs/onboarding-sdk-product/src/main/java/it/pagopa/selfcare/product/exception/ProductNotFoundException.java @@ -0,0 +1,11 @@ +package it.pagopa.selfcare.product.exception; + +public class ProductNotFoundException extends RuntimeException { + + public ProductNotFoundException(){ + super(); + } + public ProductNotFoundException(String message){ + super(message); + } +} diff --git a/libs/onboarding-sdk-product/src/main/java/it/pagopa/selfcare/product/service/ProductService.java b/libs/onboarding-sdk-product/src/main/java/it/pagopa/selfcare/product/service/ProductService.java new file mode 100644 index 000000000..56ead812b --- /dev/null +++ b/libs/onboarding-sdk-product/src/main/java/it/pagopa/selfcare/product/service/ProductService.java @@ -0,0 +1,22 @@ +package it.pagopa.selfcare.product.service; + + +import it.pagopa.selfcare.onboarding.common.InstitutionType; +import it.pagopa.selfcare.onboarding.common.PartyRole; +import it.pagopa.selfcare.product.entity.Product; +import it.pagopa.selfcare.product.entity.ProductRoleInfo; + +import java.util.List; +import java.util.Map; + +public interface ProductService { + public List getProducts(boolean rootOnly, boolean valid) ; + + void validateRoleMappings(Map roleMappings); + + Product getProduct(String productId); + + void fillContractTemplatePathAndVersion(Product product, InstitutionType institutionType); + + Product getProductIsValid(String productId); +} diff --git a/libs/onboarding-sdk-product/src/main/java/it/pagopa/selfcare/product/service/ProductServiceCacheable.java b/libs/onboarding-sdk-product/src/main/java/it/pagopa/selfcare/product/service/ProductServiceCacheable.java new file mode 100644 index 000000000..11a3043b3 --- /dev/null +++ b/libs/onboarding-sdk-product/src/main/java/it/pagopa/selfcare/product/service/ProductServiceCacheable.java @@ -0,0 +1,76 @@ +package it.pagopa.selfcare.product.service; + +import com.fasterxml.jackson.core.JsonProcessingException; +import it.pagopa.selfcare.azurestorage.AzureBlobClient; +import it.pagopa.selfcare.azurestorage.AzureBlobClientDefault; +import it.pagopa.selfcare.onboarding.common.InstitutionType; +import it.pagopa.selfcare.onboarding.common.PartyRole; +import it.pagopa.selfcare.product.entity.Product; +import it.pagopa.selfcare.product.entity.ProductRoleInfo; + +import java.time.LocalDateTime; +import java.util.List; +import java.util.Map; + +public class ProductServiceCacheable implements ProductService{ + LocalDateTime productLastModifiedDate; + private final AzureBlobClient azureBlobClient; + private ProductServiceDefault productService; + final String filePath; + + + public ProductServiceCacheable(String connectionString, String containerName, String filePath ){ + this.azureBlobClient = new AzureBlobClientDefault(connectionString, containerName); + this.filePath = filePath; + refreshProduct(); + } + + public ProductServiceCacheable(AzureBlobClient azureBlobClient, String filePath) { + this.azureBlobClient = azureBlobClient; + this.filePath = filePath; + refreshProduct(); + } + + public void refreshProduct(){ + LocalDateTime currentLastModifiedDate = azureBlobClient.getProperties(filePath).getLastModified().toLocalDateTime(); + if(productLastModifiedDate == null || currentLastModifiedDate.isAfter(productLastModifiedDate)){ + String productJsonString = azureBlobClient.getFileAsText(filePath); + try{ + this.productService = new ProductServiceDefault(productJsonString); + }catch(JsonProcessingException e){ + throw new IllegalArgumentException(e.getMessage()); + } + this.productLastModifiedDate = currentLastModifiedDate; + } + } + + @Override + public List getProducts(boolean rootOnly, boolean valid) { + refreshProduct(); + return productService.getProducts(rootOnly, valid); + } + + @Override + public void validateRoleMappings(Map roleMappings) { + refreshProduct(); + productService.validateRoleMappings(roleMappings); + } + + @Override + public Product getProduct(String productId) { + refreshProduct(); + return productService.getProduct(productId); + } + + @Override + public void fillContractTemplatePathAndVersion(Product product, InstitutionType institutionType) { + refreshProduct(); + productService.fillContractTemplatePathAndVersion(product, institutionType); + } + + @Override + public Product getProductIsValid(String productId) { + refreshProduct(); + return productService.getProductIsValid(productId); + } +} diff --git a/libs/onboarding-sdk-product/src/main/java/it/pagopa/selfcare/product/service/ProductServiceDefault.java b/libs/onboarding-sdk-product/src/main/java/it/pagopa/selfcare/product/service/ProductServiceDefault.java new file mode 100644 index 000000000..add7cd8b3 --- /dev/null +++ b/libs/onboarding-sdk-product/src/main/java/it/pagopa/selfcare/product/service/ProductServiceDefault.java @@ -0,0 +1,162 @@ +package it.pagopa.selfcare.product.service; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import it.pagopa.selfcare.onboarding.common.InstitutionType; +import it.pagopa.selfcare.onboarding.common.PartyRole; +import it.pagopa.selfcare.product.entity.Product; +import it.pagopa.selfcare.product.entity.ProductRoleInfo; +import it.pagopa.selfcare.product.entity.ProductStatus; +import it.pagopa.selfcare.product.exception.InvalidRoleMappingException; +import it.pagopa.selfcare.product.exception.ProductNotFoundException; + +import java.util.*; +import java.util.function.Function; +import java.util.stream.Collectors; + +public class ProductServiceDefault implements ProductService { + + protected static final String REQUIRED_PRODUCT_ID_MESSAGE = "A product id is required"; + + final Map productsMap; + + public ProductServiceDefault(String productString) throws JsonProcessingException { + /* define object mapper */ + ObjectMapper mapper = new ObjectMapper(); + mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); + mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); + + this.productsMap = constructProductsMap(productString, mapper); + } + + public ProductServiceDefault(String productString, ObjectMapper mapper) throws JsonProcessingException { + this.productsMap = constructProductsMap(productString, mapper); + } + + private Map constructProductsMap(String productString, ObjectMapper mapper) throws JsonProcessingException { + List productList = mapper.readValue(productString, new TypeReference>(){}); + if(Objects.isNull(productList) || productList.isEmpty()) throw new ProductNotFoundException("json string is empty!"); + return productList.stream() + .collect(Collectors.toMap(Product::getId, Function.identity())); + } + + /** + * Returns the list of PagoPA products tree which are not INACTIVE + * @param rootOnly if true only product that has parent is null are returned + * @return List of PagoPA products + */ + @Override + public List getProducts(boolean rootOnly, boolean valid) { + + return rootOnly + ? productsMap.values().stream() + .filter(product -> Objects.isNull(product.getParentId())) + .filter(product -> !valid || !statusIsNotValid(product.getStatus())) + .collect(Collectors.toList()) + : productsMap.values().stream() + .filter(product -> !valid || !statusIsNotValid(product.getStatus())) + .collect(Collectors.toList()); + } + + /** + * Utility method for validating role mappings that contains associations between Selfcare role and Product role. + * Each Selfcare role must be only one Product role except OPERATOR. + * @param roleMappings + * @throws IllegalArgumentException roleMappings is null or empty + * @throws InvalidRoleMappingException Selfcare role have more than one Product role + */ + @Override + public void validateRoleMappings(Map roleMappings) { + + if(Objects.isNull(roleMappings) || roleMappings.isEmpty()) + throw new IllegalArgumentException("A product role mappings is required"); + roleMappings.forEach((partyRole, productRoleInfo) -> { + if(Objects.isNull(productRoleInfo)) + throw new IllegalArgumentException("A product role info is required"); + if(Objects.isNull(productRoleInfo.getRoles()) || productRoleInfo.getRoles().isEmpty()) + throw new IllegalArgumentException("At least one Product role are required"); + if (productRoleInfo.getRoles().size() > 1 && !PartyRole.OPERATOR.equals(partyRole)) { + throw new InvalidRoleMappingException(String.format("Only '%s' Party-role can have more than one Product-role, %s", + PartyRole.OPERATOR.name(), + String.format("partyRole = %s => productRoleInfo = %s", partyRole, productRoleInfo))); + } + }); + } + + /** + * Return a product by productId without any filter + * retrieving data from institutionContractMappings map + * @param productId + * @return Product + * @throws IllegalArgumentException if @param id is null + * @throws ProductNotFoundException if product is not found + * + */ + @Override + public Product getProduct(String productId) { + return getProduct(productId, false); + } + + private Product getProduct(String productId, boolean filterValid) { + + if(Objects.isNull(productId)) { + throw new IllegalArgumentException(REQUIRED_PRODUCT_ID_MESSAGE); + } + Product product = Optional.ofNullable(productsMap.get(productId)) + .orElseThrow(ProductNotFoundException::new); + if (filterValid && statusIsNotValid(product.getStatus())) { + throw new ProductNotFoundException(); + } + + if (product.getParentId() != null) { + Product parent = Optional.ofNullable(productsMap.get(product.getParentId())) + .orElseThrow(ProductNotFoundException::new); + if (filterValid && statusIsNotValid(parent.getStatus())) { + throw new ProductNotFoundException(); + } + + product.setParent(parent); + } + + return product; + } + + /** + * Fills contractTemplatePath and ContractTemplateVersion based on @param institutionType. + * If institutionContractMappings contains institutionType, it take value from that setting inside + * contractTemplatePath and contractTemplateVersion of product + * @param product Product + * @param institutionType InstitutionType + */ + @Override + public void fillContractTemplatePathAndVersion(Product product, InstitutionType institutionType) { + if (institutionType != null && product.getInstitutionContractMappings() != null && product.getInstitutionContractMappings().containsKey(institutionType)) { + product.setContractTemplatePath(product.getInstitutionContractMappings().get(institutionType).getContractTemplatePath()); + product.setContractTemplateVersion(product.getInstitutionContractMappings().get(institutionType).getContractTemplateVersion()); + } + } + + + /** + * Returns the information for a single product if it has not PHASE_OUT,INACTIVE status and its parent has not PHASE_OUT,INACTIVE status + * @param productId + * @return Product if it is valid or null if it has PHASE_OUT,INACTIVE status + * @throws IllegalArgumentException product id is null + * @throws ProductNotFoundException product id or its parent does not exist or have PHASE_OUT,INACTIVE status + */ + @Override + public Product getProductIsValid(String productId) { + return getProduct(productId, true); + } + + private static boolean statusIsNotValid(ProductStatus status) { + return List.of(ProductStatus.INACTIVE, ProductStatus.PHASE_OUT).contains(status); + } + + +} diff --git a/libs/onboarding-sdk-product/src/main/schema/Product_v1.avsc b/libs/onboarding-sdk-product/src/main/schema/Product_v1.avsc new file mode 100644 index 000000000..8975cbc5b --- /dev/null +++ b/libs/onboarding-sdk-product/src/main/schema/Product_v1.avsc @@ -0,0 +1,107 @@ +{ + "type" : "record", + "name" : "Product", + "namespace" : "it.pagopa.selfcare.product.entity", + "fields" : [ { + "name" : "id", + "type" : [ "string" ] + }, { + "name" : "logo", + "type" : [ "string" ] + }, { + "name" : "depictImageUrl", + "type" : [ "string" ] + }, { + "name" : "title", + "type" : [ "string" ] + }, { + "name" : "logoBgColor", + "type" : [ "string" ] + }, { + "name" : "description", + "type" : [ "string" ] + }, { + "name" : "urlPublic", + "type" : [ "string" ] + }, { + "name" : "urlBO", + "type" : [ "string" ] + }, { + "name" : "createdAt", + "type" : [ "string" ] + }, { + "name" : "createdBy", + "type" : [ "string" ] + }, { + "name" : "modifiedAt", + "type" : [ "string" ] + }, { + "name" : "modifiedBy", + "type" : [ "string" ] + }, { + "name" : "roleManagementURL", + "type" : [ "null", "string" ] + }, { + "name" : "contractTemplateUpdatedAt", + "type" : [ "string" ] + }, { + "name" : "contractTemplatePath", + "type" : [ "string" ] + }, { + "name" : "contractTemplateVersion", + "type" : [ "string" ] + }, { + "name" : "institutionContractMappings", + "type" : [ "null", { + "type" : "map", + "values" : { + "type" : "record", + "name" : "ContractStorage", + "fields" : [ { + "name" : "contractTemplateUpdatedAt", + "type" : [ "null", "string" ] + }, { + "name" : "contractTemplatePath", + "type" : [ "null", "string" ] + }, { + "name" : "contractTemplateVersion", + "type" : [ "null", "string" ] + } ] + } + } ] + }, { + "name" : "enabled", + "type" : "boolean" + }, { + "name" : "delegable", + "type" : ["null","boolean"] + }, { + "name" : "status", + "type" : [ "string" ] + }, { + "name" : "parentId", + "type" : [ "null", "string" ] + }, { + "name" : "identityTokenAudience", + "type" : [ "string" ] + }, { + "name" : "backOfficeEnvironmentConfigurations", + "type" : [ "null", { + "type" : "map", + "values" : { + "type" : "record", + "name" : "BackOfficeConfigurations", + "fields" : [ { + "name" : "url", + "type" : [ "null", "string" ] + }, { + "name" : "identityTokenAudience", + "type" : [ "null", "string" ] + } ] + } + } ] + }, { + "name" : "parent", + "type" : [ "null", "Product" ] + } ] +} \ No newline at end of file diff --git a/libs/onboarding-sdk-product/src/test/java/ProductServiceDefaultTest.java b/libs/onboarding-sdk-product/src/test/java/ProductServiceDefaultTest.java new file mode 100644 index 000000000..84438221a --- /dev/null +++ b/libs/onboarding-sdk-product/src/test/java/ProductServiceDefaultTest.java @@ -0,0 +1,116 @@ +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import it.pagopa.selfcare.onboarding.common.PartyRole; +import it.pagopa.selfcare.product.entity.ProductRole; +import it.pagopa.selfcare.product.entity.ProductRoleInfo; +import it.pagopa.selfcare.product.exception.InvalidRoleMappingException; +import it.pagopa.selfcare.product.exception.ProductNotFoundException; +import it.pagopa.selfcare.product.service.ProductServiceDefault; +import org.junit.jupiter.api.Test; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.*; + +public class ProductServiceDefaultTest { + + final private String PRODUCT_JSON_STRING_EMPTY = "[]"; + final private String PRODUCT_JSON_STRING = "[{\"id\":\"prod-test-parent\",\"status\":\"ACTIVE\"}," + + "{\"id\":\"prod-test\", \"parentId\":\"prod-test-parent\",\"status\":\"ACTIVE\"}," + + "{\"id\":\"prod-inactive\",\"status\":\"INACTIVE\"}]"; + + @Test + void productServiceDefault_shouldThrowProductNotFoundExceptionIfJsonIsEmpty() { + assertThrows(ProductNotFoundException.class, () -> new ProductServiceDefault(PRODUCT_JSON_STRING_EMPTY)); + } + @Test + void productServiceDefault_shouldNotThrowProductNotFoundExceptionIfJsonIsValid() { + assertDoesNotThrow(() -> new ProductServiceDefault(PRODUCT_JSON_STRING)); + } + @Test + void productServiceDefault_shouldThrowProductNotFoundExceptionIfJsonIsEmptyAndMapper() { + assertThrows(ProductNotFoundException.class, () -> new ProductServiceDefault(PRODUCT_JSON_STRING_EMPTY, new ObjectMapper())); + } + + @Test + void getProducts_shouldReturnProductsRootOnly() throws JsonProcessingException { + ProductServiceDefault productService = new ProductServiceDefault(PRODUCT_JSON_STRING); + assertEquals( 2, productService.getProducts(true, false).size()); + } + + @Test + void getProducts_shouldReturnProductsAll() throws JsonProcessingException { + ProductServiceDefault productService = new ProductServiceDefault(PRODUCT_JSON_STRING); + assertEquals(3, productService.getProducts(false, false).size()); + } + + @Test + void getProducts_shouldReturnProductsRootOnlyAndValid() throws JsonProcessingException { + ProductServiceDefault productService = new ProductServiceDefault(PRODUCT_JSON_STRING); + assertEquals( 1, productService.getProducts(true, true).size()); + } + + @Test + void getProducts_shouldReturnProductsAllAndValid() throws JsonProcessingException { + ProductServiceDefault productService = new ProductServiceDefault(PRODUCT_JSON_STRING); + assertEquals(2, productService.getProducts(false, true).size()); + } + + @Test + void validateRoleMappings_shouldThrowIllegalExceptionIfRoleMappingIsNull() throws JsonProcessingException { + ProductServiceDefault productService = new ProductServiceDefault(PRODUCT_JSON_STRING); + assertThrows(IllegalArgumentException.class, () -> productService.validateRoleMappings(new HashMap<>())); + } + + @Test + void validateRoleMappings_shouldThrowIllegalExceptionIfProductRoleInfoIsNull() throws JsonProcessingException { + ProductServiceDefault productService = new ProductServiceDefault(PRODUCT_JSON_STRING); + Map roleMappings = new HashMap<>(); + roleMappings.put(PartyRole.MANAGER, null); + assertThrows(IllegalArgumentException.class, () -> productService.validateRoleMappings(roleMappings)); + } + + @Test + void validateRoleMappings_shouldThrowIllegalExceptionIfProductRoleInfoIsRolesEmpty() throws JsonProcessingException { + ProductServiceDefault productService = new ProductServiceDefault(PRODUCT_JSON_STRING); + Map roleMappings = new HashMap<>(); + roleMappings.put(PartyRole.MANAGER, new ProductRoleInfo()); + assertThrows(IllegalArgumentException.class, () -> productService.validateRoleMappings(roleMappings)); + } + + @Test + void validateRoleMappings_shouldThrowInvalidRoleMappingExceptionIfProductRoleInfoIsRolesEmpty() throws JsonProcessingException { + ProductServiceDefault productService = new ProductServiceDefault(PRODUCT_JSON_STRING); + Map roleMappings = new HashMap<>(); + ProductRoleInfo productRoleInfo1 = new ProductRoleInfo(); + productRoleInfo1.setRoles(List.of(new ProductRole(), new ProductRole())); + roleMappings.put(PartyRole.MANAGER, productRoleInfo1); + assertThrows(InvalidRoleMappingException.class, () -> productService.validateRoleMappings(roleMappings)); + } + + @Test + void getProduct_shouldThrowIllegalExceptionIfIdNull() throws JsonProcessingException { + ProductServiceDefault productService = new ProductServiceDefault(PRODUCT_JSON_STRING); + assertThrows(IllegalArgumentException.class, () -> productService.getProduct(null)); + } + + @Test + void getProduct_shouldThrowProductNotFoundExceptionIfIdNotFound() throws JsonProcessingException { + ProductServiceDefault productService = new ProductServiceDefault(PRODUCT_JSON_STRING); + assertThrows(ProductNotFoundException.class, () -> productService.getProduct("prod-not-found")); + } + + @Test + void getProduct_shouldGetProduct() throws JsonProcessingException { + ProductServiceDefault productService = new ProductServiceDefault(PRODUCT_JSON_STRING); + assertNotNull(productService.getProduct("prod-test")); + } + + @Test + void getProductValid_shouldThrowProductNotFoundExceptionIfProductInactive() throws JsonProcessingException { + ProductServiceDefault productService = new ProductServiceDefault(PRODUCT_JSON_STRING); + assertThrows(ProductNotFoundException.class, () -> productService.getProductIsValid("prod-inactive")); + } +} diff --git a/libs/onboarding-sdk-product/src/test/java/it/pagopa/selfcare/product/service/ProductServiceCacheableTest.java b/libs/onboarding-sdk-product/src/test/java/it/pagopa/selfcare/product/service/ProductServiceCacheableTest.java new file mode 100644 index 000000000..68509b120 --- /dev/null +++ b/libs/onboarding-sdk-product/src/test/java/it/pagopa/selfcare/product/service/ProductServiceCacheableTest.java @@ -0,0 +1,189 @@ +package it.pagopa.selfcare.product.service; + +import com.azure.storage.blob.models.BlobProperties; +import it.pagopa.selfcare.azurestorage.AzureBlobClient; +import it.pagopa.selfcare.onboarding.common.PartyRole; +import it.pagopa.selfcare.product.entity.Product; +import it.pagopa.selfcare.product.entity.ProductRole; +import it.pagopa.selfcare.product.entity.ProductRoleInfo; +import it.pagopa.selfcare.product.exception.InvalidRoleMappingException; +import it.pagopa.selfcare.product.exception.ProductNotFoundException; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.function.Executable; + +import java.time.OffsetDateTime; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +class ProductServiceCacheableTest { + final private String PRODUCT_JSON_STRING = "[{\"id\":\"prod-test-parent\",\"status\":\"ACTIVE\"}," + + "{\"id\":\"prod-test\", \"parentId\":\"prod-test-parent\",\"status\":\"ACTIVE\"}," + + "{\"id\":\"prod-inactive\",\"status\":\"INACTIVE\"}]"; + + final private String PRODUCT_JSON_STRING_EMPTY = "[]"; + + @Test + void constructProduct() { + //given + final String filePath = "filePath"; + ProductServiceCacheable productServiceCacheable = mockProductService(PRODUCT_JSON_STRING, filePath); + //then + assertNotNull(productServiceCacheable.productLastModifiedDate); + } + + @Test + void createProduct_notFound() { + //given + final String filePath = "filePath"; + assertThrows(ProductNotFoundException.class, () -> mockProductService(PRODUCT_JSON_STRING_EMPTY, filePath)); + } + + @Test + void getProducts_rootOnly() { + //given + final String filePath = "filePath"; + ProductServiceCacheable productServiceCacheable = mockProductService(PRODUCT_JSON_STRING, filePath); + //then + assertEquals(2, productServiceCacheable.getProducts(true, false).size()); + + } + + @Test + void getProducts_getAll() { + //given + final String filePath = "filePath"; + ProductServiceCacheable productServiceCacheable = mockProductService(PRODUCT_JSON_STRING, filePath); + //then + assertEquals(3, productServiceCacheable.getProducts(false, false).size()); + } + + @Test + void getProducts_rootAndValidOnly() { + //given + final String filePath = "filePath"; + ProductServiceCacheable productServiceCacheable = mockProductService(PRODUCT_JSON_STRING, filePath); + //then + assertEquals(1, productServiceCacheable.getProducts(true, true).size()); + + } + + @Test + void getProduct_allValid() { + //given + final String filePath = "filePath"; + ProductServiceCacheable productServiceCacheable = mockProductService(PRODUCT_JSON_STRING, filePath); + //then + assertEquals(2, productServiceCacheable.getProducts(false, true).size()); + } + + @Test + void validateRoleMappings_exceptionNullroleMapping() { + //given + final String filePath = "filePath"; + ProductServiceCacheable productServiceCacheable = mockProductService(PRODUCT_JSON_STRING, filePath); + //when + Executable executable = () -> productServiceCacheable.validateRoleMappings(new HashMap<>()); + //then + assertThrows(IllegalArgumentException.class, executable); + } + + @Test + void validateRoleMappings_exceptionNullRoleInfo() { + //given + final String filePath = "filePath"; + ProductServiceCacheable productServiceCacheable = mockProductService(PRODUCT_JSON_STRING, filePath); + Map roleMappings = new HashMap<>(); + roleMappings.put(PartyRole.MANAGER, null); + //when + Executable executable = () -> productServiceCacheable.validateRoleMappings(roleMappings); + //then + assertThrows(IllegalArgumentException.class, executable); + } + + @Test + void validateRoleMappings_exceptionEmptyRoleInfo() { + //given + final String filePath = "filePath"; + ProductServiceCacheable productServiceCacheable = mockProductService(PRODUCT_JSON_STRING, filePath); + Map roleMappings = new HashMap<>(); + roleMappings.put(PartyRole.MANAGER, new ProductRoleInfo()); + //when + Executable executable = () -> productServiceCacheable.validateRoleMappings(roleMappings); + //then + assertThrows(IllegalArgumentException.class, executable); + } + + @Test + void validateRoleMappings_exceptionEmptyRoleInfoList() { + //given + final String filePath = "filePath"; + ProductServiceCacheable productServiceCacheable = mockProductService(PRODUCT_JSON_STRING, filePath); + Map roleMappings = new HashMap<>(); + ProductRoleInfo productRoleInfo1 = new ProductRoleInfo(); + productRoleInfo1.setRoles(List.of(new ProductRole(), new ProductRole())); + roleMappings.put(PartyRole.MANAGER, productRoleInfo1); + //when + Executable executable = () -> productServiceCacheable.validateRoleMappings(roleMappings); + //then + assertThrows(InvalidRoleMappingException.class, executable); + } + + @Test + void getProduct_nullId() { + final String filePath = "filePath"; + ProductServiceCacheable productServiceCacheable = mockProductService(PRODUCT_JSON_STRING, filePath); + //when + Executable executable = () -> productServiceCacheable.getProduct(null); + //then + assertThrows(IllegalArgumentException.class, executable); + } + + @Test + void getProduct_notFound() { + final String filePath = "filePath"; + ProductServiceCacheable productServiceCacheable = mockProductService(PRODUCT_JSON_STRING, filePath); + //when + Executable executable = () -> productServiceCacheable.getProduct("notFound"); + //then + assertThrows(ProductNotFoundException.class, executable); + } + + @Test + void getProduct() { + final String filePath = "filePath"; + ProductServiceCacheable productServiceCacheable = mockProductService(PRODUCT_JSON_STRING, filePath); + //when + Product product = productServiceCacheable.getProduct("prod-test"); + //then + assertNotNull(product); + } + + @Test + void getProduct_notFoundInactive() { + + + final String filePath = "filePath"; + ProductServiceCacheable productServiceCacheable = mockProductService(PRODUCT_JSON_STRING, filePath); + //when + Executable executable = () -> productServiceCacheable.getProductIsValid("prod-inactive"); + //then + assertThrows(ProductNotFoundException.class, executable); + } + + private ProductServiceCacheable mockProductService(String productJson, String filePath) { + AzureBlobClient azureBlobClient = mock(AzureBlobClient.class); + BlobProperties blobPropertiesMock = mock(BlobProperties.class); + + when(azureBlobClient.getProperties(any())).thenReturn(blobPropertiesMock); + when(blobPropertiesMock.getLastModified()).thenReturn(OffsetDateTime.now()); + when(azureBlobClient.getFileAsText(any())).thenReturn(productJson); + return new ProductServiceCacheable(azureBlobClient, filePath); + } + +} \ No newline at end of file diff --git a/libs/onboarding-sdk-product/src/test/resources/mockito-extensions.properties b/libs/onboarding-sdk-product/src/test/resources/mockito-extensions.properties new file mode 100644 index 000000000..131dd6161 --- /dev/null +++ b/libs/onboarding-sdk-product/src/test/resources/mockito-extensions.properties @@ -0,0 +1 @@ +org.mockito.plugins.MockMaker=mock-maker-inline \ No newline at end of file diff --git a/libs/pom.xml b/libs/pom.xml new file mode 100644 index 000000000..75fbd06f5 --- /dev/null +++ b/libs/pom.xml @@ -0,0 +1,28 @@ + + + 4.0.0 + + + it.pagopa.selfcare + onboarding-root + 0.0.1 + + + onboarding-libs + pom + + + true + + + + onboarding-sdk-azure-storage + onboarding-sdk-common + onboarding-sdk-product + onboarding-sdk-crypto + onboarding-sdk-pom + + + + diff --git a/onboarding-functions/.dockerignore b/onboarding-functions/.dockerignore deleted file mode 100644 index 94810d006..000000000 --- a/onboarding-functions/.dockerignore +++ /dev/null @@ -1,5 +0,0 @@ -* -!target/*-runner -!target/*-runner.jar -!target/lib/* -!target/quarkus-app/* \ No newline at end of file diff --git a/onboarding-functions/README.md b/onboarding-functions/README.md deleted file mode 100644 index 6a4242b69..000000000 --- a/onboarding-functions/README.md +++ /dev/null @@ -1,17 +0,0 @@ -# onboarding-functions - -Repository that contains onboarding functions. - -## Packaging and running the application - -The application can be packaged using: -```shell script -./mvnw package -``` -It produces the `onboarding-functions-1.0.0-SNAPSHOT.jar` file in the `target/` directory. - -## Related Guides - -- Azure Functions ([guide](https://quarkus.io/guides/azure-functions)): Write Microsoft Azure functions - -## Provided Code diff --git a/onboarding-functions/pom.xml b/onboarding-functions/pom.xml deleted file mode 100644 index c7d5b3607..000000000 --- a/onboarding-functions/pom.xml +++ /dev/null @@ -1,106 +0,0 @@ - - - 4.0.0 - onboarding-functions - 1.0.0-SNAPSHOT - - - - - it.pagopa.selfcare - onboarding - 0.0.1 - - - - 3.11.0 - 11 - UTF-8 - UTF-8 - quarkus-bom - io.quarkus.platform - 3.3.2 - true - 3.1.2 - - - - - - ${quarkus.platform.group-id} - ${quarkus.platform.artifact-id} - ${quarkus.platform.version} - pom - import - - - - - - io.quarkus - quarkus-azure-functions - - - io.quarkus - quarkus-arc - - - com.microsoft.azure.functions - azure-functions-java-library - - - io.quarkus - quarkus-junit5 - test - - - io.rest-assured - rest-assured - test - - - org.mockito - mockito-core - test - - - - - - ${quarkus.platform.group-id} - quarkus-maven-plugin - ${quarkus.platform.version} - true - - - - build - generate-code - generate-code-tests - - - - - - maven-compiler-plugin - ${compiler-plugin.version} - - - -parameters - - - - - maven-surefire-plugin - ${surefire-plugin.version} - - - org.jboss.logmanager.LogManager - ${maven.home} - - - - - - diff --git a/onboarding-functions/src/main/java/it/pagopa/selfcare/GreetingService.java b/onboarding-functions/src/main/java/it/pagopa/selfcare/GreetingService.java deleted file mode 100644 index 7c3c00b91..000000000 --- a/onboarding-functions/src/main/java/it/pagopa/selfcare/GreetingService.java +++ /dev/null @@ -1,10 +0,0 @@ -package it.pagopa.selfcare; - -import jakarta.enterprise.context.ApplicationScoped; - -@ApplicationScoped -public class GreetingService { - public String greeting(String name) { - return "Guten Tag " + name; - } -} diff --git a/onboarding-functions/src/main/java/it/pagopa/selfcare/OnboardingFunctions.java b/onboarding-functions/src/main/java/it/pagopa/selfcare/OnboardingFunctions.java deleted file mode 100644 index efa6d502b..000000000 --- a/onboarding-functions/src/main/java/it/pagopa/selfcare/OnboardingFunctions.java +++ /dev/null @@ -1,48 +0,0 @@ -package it.pagopa.selfcare; - -import com.microsoft.azure.functions.ExecutionContext; -import com.microsoft.azure.functions.HttpMethod; -import com.microsoft.azure.functions.HttpRequestMessage; -import com.microsoft.azure.functions.HttpResponseMessage; -import com.microsoft.azure.functions.HttpStatus; -import com.microsoft.azure.functions.annotation.AuthorizationLevel; -import com.microsoft.azure.functions.annotation.FunctionName; -import com.microsoft.azure.functions.annotation.HttpTrigger; - -import jakarta.inject.Inject; - -import java.util.Optional; - -/** - * Azure Functions with HTTP Trigger integrated with Quarkus - */ -public class OnboardingFunctions { - @Inject - GreetingService service; - - /** - * This function listens at endpoint "/api/HttpExample". Two ways to invoke it using "curl" command in bash: - * 1. curl -d "HTTP Body" {your host}/api/HttpExample - * 2. curl "{your host}/api/HttpExample?name=HTTP%20Query" - */ - @FunctionName("HttpExample") - public HttpResponseMessage run( - @HttpTrigger( - name = "req", - methods = {HttpMethod.GET, HttpMethod.POST}, - authLevel = AuthorizationLevel.ANONYMOUS) - HttpRequestMessage> request, - final ExecutionContext context) { - context.getLogger().info("Java HTTP trigger processed a request."); - - // Parse query parameter - final String query = request.getQueryParameters().get("name"); - final String name = request.getBody().orElse(query); - - if (name == null) { - return request.createResponseBuilder(HttpStatus.BAD_REQUEST).body("Please pass a name on the query string or in the request body").build(); - } else { - return request.createResponseBuilder(HttpStatus.OK).body(service.greeting(name)).build(); - } - } -} diff --git a/onboarding-functions/src/main/resources/application.properties b/onboarding-functions/src/main/resources/application.properties deleted file mode 100644 index e945db684..000000000 --- a/onboarding-functions/src/main/resources/application.properties +++ /dev/null @@ -1,5 +0,0 @@ -quarkus.azure-functions.app-name=onboarding-functions-1694099464026 -quarkus.azure-functions.subscription-id=${AZURE_SUBSCRIPTION_ID:""} -quarkus.azure-functions.resource-group=${AZURE_RESOURCE_GROUP:""} -quarkus.azure-functions.region=${AZURE_APP_REGION:""} -quarkus.azure-functions.app-insights-key=${AZURE_APP_INSIGHTS_KEY:""} diff --git a/onboarding-functions/src/test/java/org/acme/OnboardingFunctionsTest.java b/onboarding-functions/src/test/java/org/acme/OnboardingFunctionsTest.java deleted file mode 100644 index f67919806..000000000 --- a/onboarding-functions/src/test/java/org/acme/OnboardingFunctionsTest.java +++ /dev/null @@ -1,69 +0,0 @@ -package org.acme; - -import com.microsoft.azure.functions.ExecutionContext; -import com.microsoft.azure.functions.HttpRequestMessage; -import com.microsoft.azure.functions.HttpResponseMessage; -import com.microsoft.azure.functions.HttpStatus; -import io.quarkus.test.junit.QuarkusTest; -import it.pagopa.selfcare.OnboardingFunctions; -import org.junit.jupiter.api.Test; -import org.mockito.invocation.InvocationOnMock; -import org.mockito.stubbing.Answer; - -import jakarta.inject.Inject; -import java.util.HashMap; -import java.util.Map; -import java.util.Optional; -import java.util.logging.Logger; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; - - - -/** - * Unit test for Function class. - */ -@QuarkusTest -public class OnboardingFunctionsTest { - - @Inject - OnboardingFunctions function; - - /** - * Unit test for HttpTriggerJava method. - */ - @Test - public void testHttpTriggerJava() throws Exception { - // Setup - @SuppressWarnings("unchecked") - final HttpRequestMessage> req = mock(HttpRequestMessage.class); - - final Map queryParams = new HashMap<>(); - queryParams.put("name", "Azure"); - doReturn(queryParams).when(req).getQueryParameters(); - - final Optional queryBody = Optional.empty(); - doReturn(queryBody).when(req).getBody(); - - doAnswer(new Answer() { - @Override - public HttpResponseMessage.Builder answer(InvocationOnMock invocation) { - HttpStatus status = (HttpStatus) invocation.getArguments()[0]; - return new HttpResponseMessageMock.HttpResponseMessageBuilderMock().status(status); - } - }).when(req).createResponseBuilder(any(HttpStatus.class)); - - final ExecutionContext context = mock(ExecutionContext.class); - doReturn(Logger.getGlobal()).when(context).getLogger(); - - // Invoke - final HttpResponseMessage ret = function.run(req, context); - - // Verify - assertEquals(ret.getStatus(), HttpStatus.OK); - } -} diff --git a/onboarding-ms/.dockerignore b/onboarding-ms/.dockerignore deleted file mode 100644 index 94810d006..000000000 --- a/onboarding-ms/.dockerignore +++ /dev/null @@ -1,5 +0,0 @@ -* -!target/*-runner -!target/*-runner.jar -!target/lib/* -!target/quarkus-app/* \ No newline at end of file diff --git a/onboarding-ms/README.md b/onboarding-ms/README.md deleted file mode 100644 index 23cfc18af..000000000 --- a/onboarding-ms/README.md +++ /dev/null @@ -1,67 +0,0 @@ -# Microservice Onboarding - -Repository that contains backend services synch for selfcare onboarding. - -## Configuration Properties - - -| **Property** | **Enviroment Variable** | **Default** | **Required** | -|--------------------------------------------|-------------------------|-------------|:--------------:| -| quarkus.mongodb.connection-string
    | MONGODB_CONNECTION_URI | | yes | -| mp.jwt.verify.publickey
    | JWT_TOKEN_PUBLIC_KEY | | yes | - - -## Running the application in dev mode - -You can run your application in dev mode that enables live coding using: -```shell script -./mvnw compile quarkus:dev -``` - -> **_NOTE:_** Quarkus now ships with a Dev UI, which is available in dev mode only at http://localhost:8080/q/dev/. - -## Packaging and running the application - -The application can be packaged using: -```shell script -./mvnw package -``` -It produces the `quarkus-run.jar` file in the `target/quarkus-app/` directory. -Be aware that it’s not an _über-jar_ as the dependencies are copied into the `target/quarkus-app/lib/` directory. - -The application is now runnable using `java -jar target/quarkus-app/quarkus-run.jar`. - -If you want to build an _über-jar_, execute the following command: -```shell script -./mvnw package -Dquarkus.package.type=uber-jar -``` - -The application, packaged as an _über-jar_, is now runnable using `java -jar target/*-runner.jar`. - -## Creating a native executable - -You can create a native executable using: -```shell script -./mvnw package -Pnative -``` - -Or, if you don't have GraalVM installed, you can run the native executable build in a container using: -```shell script -./mvnw package -Pnative -Dquarkus.native.container-build=true -``` - -You can then execute your native executable with: `./target/onboarding-ms-1.0.0-SNAPSHOT-runner` - -If you want to learn more about building native executables, please consult https://quarkus.io/guides/maven-tooling. - -## Related Guides - -- RESTEasy Reactive ([guide](https://quarkus.io/guides/resteasy-reactive)): A Jakarta REST implementation utilizing build time processing and Vert.x. This extension is not compatible with the quarkus-resteasy extension, or any of the extensions that depend on it. - -## Provided Code - -### RESTEasy Reactive - -Easily start your Reactive RESTful Web Services - -[Related guide section...](https://quarkus.io/guides/getting-started-reactive#reactive-jax-rs-resources) diff --git a/onboarding-ms/deploy-image-container-app.yaml b/onboarding-ms/deploy-image-container-app.yaml deleted file mode 100644 index af427269c..000000000 --- a/onboarding-ms/deploy-image-container-app.yaml +++ /dev/null @@ -1,25 +0,0 @@ -properties: - managedEnvironmentId: /subscriptions/$SUBSCRIPTION_ID$/resourceGroups/$RESOURCE_GROUP$/providers/Microsoft.App/managedEnvironments/$CONTAINER_APP_ENV$ - configuration: - secrets: - - name: jwt-public-key - value: $JWT_PUBLIC_KEY$ - - name: mongo-connection-uri - value: $MONGODB_CONNECTION_URI$ - ingress: - external: true - allowInsecure: false - targetPort: 8080 - template: - containers: - - image: ghcr.io/pagopa/selfcare-onboarding-ms:latest - name: selfcare-onboarding-ms - env: - - name: JWT_TOKEN_PUBLIC_KEY - secretRef: jwt-public-key - - name: MONGODB_CONNECTION_URI - secretRef: mongo-connection-uri - - scale: - minReplicas: 1 - maxReplicas: 5 \ No newline at end of file diff --git a/onboarding-ms/src/main/docker/Dockerfile.jvm b/onboarding-ms/src/main/docker/Dockerfile.jvm deleted file mode 100644 index c5712f39a..000000000 --- a/onboarding-ms/src/main/docker/Dockerfile.jvm +++ /dev/null @@ -1,95 +0,0 @@ -#### -# This Dockerfile is used in order to build a container that runs the Quarkus application in JVM mode -# -# Before building the container image run: -# -# ./mvnw package -# -# Then, build the image with: -# -# docker build -f src/main/docker/Dockerfile.jvm -t quarkus/onboarding-ms-jvm . -# -# Then run the container using: -# -# docker run -i --rm -p 8080:8080 quarkus/onboarding-ms-jvm -# -# If you want to include the debug port into your docker image -# you will have to expose the debug port (default 5005 being the default) like this : EXPOSE 8080 5005. -# Additionally you will have to set -e JAVA_DEBUG=true and -e JAVA_DEBUG_PORT=*:5005 -# when running the container -# -# Then run the container using : -# -# docker run -i --rm -p 8080:8080 quarkus/onboarding-ms-jvm -# -# This image uses the `run-java.sh` script to run the application. -# This scripts computes the command line to execute your Java application, and -# includes memory/GC tuning. -# You can configure the behavior using the following environment properties: -# - JAVA_OPTS: JVM options passed to the `java` command (example: "-verbose:class") -# - JAVA_OPTS_APPEND: User specified Java options to be appended to generated options -# in JAVA_OPTS (example: "-Dsome.property=foo") -# - JAVA_MAX_MEM_RATIO: Is used when no `-Xmx` option is given in JAVA_OPTS. This is -# used to calculate a default maximal heap memory based on a containers restriction. -# If used in a container without any memory constraints for the container then this -# option has no effect. If there is a memory constraint then `-Xmx` is set to a ratio -# of the container available memory as set here. The default is `50` which means 50% -# of the available memory is used as an upper boundary. You can skip this mechanism by -# setting this value to `0` in which case no `-Xmx` option is added. -# - JAVA_INITIAL_MEM_RATIO: Is used when no `-Xms` option is given in JAVA_OPTS. This -# is used to calculate a default initial heap memory based on the maximum heap memory. -# If used in a container without any memory constraints for the container then this -# option has no effect. If there is a memory constraint then `-Xms` is set to a ratio -# of the `-Xmx` memory as set here. The default is `25` which means 25% of the `-Xmx` -# is used as the initial heap size. You can skip this mechanism by setting this value -# to `0` in which case no `-Xms` option is added (example: "25") -# - JAVA_MAX_INITIAL_MEM: Is used when no `-Xms` option is given in JAVA_OPTS. -# This is used to calculate the maximum value of the initial heap memory. If used in -# a container without any memory constraints for the container then this option has -# no effect. If there is a memory constraint then `-Xms` is limited to the value set -# here. The default is 4096MB which means the calculated value of `-Xms` never will -# be greater than 4096MB. The value of this variable is expressed in MB (example: "4096") -# - JAVA_DIAGNOSTICS: Set this to get some diagnostics information to standard output -# when things are happening. This option, if set to true, will set -# `-XX:+UnlockDiagnosticVMOptions`. Disabled by default (example: "true"). -# - JAVA_DEBUG: If set remote debugging will be switched on. Disabled by default (example: -# true"). -# - JAVA_DEBUG_PORT: Port used for remote debugging. Defaults to 5005 (example: "8787"). -# - CONTAINER_CORE_LIMIT: A calculated core limit as described in -# https://www.kernel.org/doc/Documentation/scheduler/sched-bwc.txt. (example: "2") -# - CONTAINER_MAX_MEMORY: Memory limit given to the container (example: "1024"). -# - GC_MIN_HEAP_FREE_RATIO: Minimum percentage of heap free after GC to avoid expansion. -# (example: "20") -# - GC_MAX_HEAP_FREE_RATIO: Maximum percentage of heap free after GC to avoid shrinking. -# (example: "40") -# - GC_TIME_RATIO: Specifies the ratio of the time spent outside the garbage collection. -# (example: "4") -# - GC_ADAPTIVE_SIZE_POLICY_WEIGHT: The weighting given to the current GC time versus -# previous GC times. (example: "90") -# - GC_METASPACE_SIZE: The initial metaspace size. (example: "20") -# - GC_MAX_METASPACE_SIZE: The maximum metaspace size. (example: "100") -# - GC_CONTAINER_OPTIONS: Specify Java GC to use. The value of this variable should -# contain the necessary JRE command-line options to specify the required GC, which -# will override the default of `-XX:+UseParallelGC` (example: -XX:+UseG1GC). -# - HTTPS_PROXY: The location of the https proxy. (example: "myuser@127.0.0.1:8080") -# - HTTP_PROXY: The location of the http proxy. (example: "myuser@127.0.0.1:8080") -# - NO_PROXY: A comma separated lists of hosts, IP addresses or domains that can be -# accessed directly. (example: "foo.example.com,bar.example.com") -# -### -FROM registry.access.redhat.com/ubi8/openjdk-17:1.15 - -ENV LANGUAGE='en_US:en' - - -# We make four distinct layers so if there are application changes the library layers can be re-used -COPY target/quarkus-app/lib/ /deployments/lib/ -COPY target/quarkus-app/*.jar /deployments/ -COPY target/quarkus-app/app/ /deployments/app/ -COPY target/quarkus-app/quarkus/ /deployments/quarkus/ - -EXPOSE 8080 -USER 185 -ENV JAVA_OPTS="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager" -ENV JAVA_APP_JAR="/deployments/quarkus-run.jar" - diff --git a/onboarding-ms/src/main/docker/Dockerfile.legacy-jar b/onboarding-ms/src/main/docker/Dockerfile.legacy-jar deleted file mode 100644 index 054e0d45d..000000000 --- a/onboarding-ms/src/main/docker/Dockerfile.legacy-jar +++ /dev/null @@ -1,91 +0,0 @@ -#### -# This Dockerfile is used in order to build a container that runs the Quarkus application in JVM mode -# -# Before building the container image run: -# -# ./mvnw package -Dquarkus.package.type=legacy-jar -# -# Then, build the image with: -# -# docker build -f src/main/docker/Dockerfile.legacy-jar -t quarkus/onboarding-ms-legacy-jar . -# -# Then run the container using: -# -# docker run -i --rm -p 8080:8080 quarkus/onboarding-ms-legacy-jar -# -# If you want to include the debug port into your docker image -# you will have to expose the debug port (default 5005 being the default) like this : EXPOSE 8080 5005. -# Additionally you will have to set -e JAVA_DEBUG=true and -e JAVA_DEBUG_PORT=*:5005 -# when running the container -# -# Then run the container using : -# -# docker run -i --rm -p 8080:8080 quarkus/onboarding-ms-legacy-jar -# -# This image uses the `run-java.sh` script to run the application. -# This scripts computes the command line to execute your Java application, and -# includes memory/GC tuning. -# You can configure the behavior using the following environment properties: -# - JAVA_OPTS: JVM options passed to the `java` command (example: "-verbose:class") -# - JAVA_OPTS_APPEND: User specified Java options to be appended to generated options -# in JAVA_OPTS (example: "-Dsome.property=foo") -# - JAVA_MAX_MEM_RATIO: Is used when no `-Xmx` option is given in JAVA_OPTS. This is -# used to calculate a default maximal heap memory based on a containers restriction. -# If used in a container without any memory constraints for the container then this -# option has no effect. If there is a memory constraint then `-Xmx` is set to a ratio -# of the container available memory as set here. The default is `50` which means 50% -# of the available memory is used as an upper boundary. You can skip this mechanism by -# setting this value to `0` in which case no `-Xmx` option is added. -# - JAVA_INITIAL_MEM_RATIO: Is used when no `-Xms` option is given in JAVA_OPTS. This -# is used to calculate a default initial heap memory based on the maximum heap memory. -# If used in a container without any memory constraints for the container then this -# option has no effect. If there is a memory constraint then `-Xms` is set to a ratio -# of the `-Xmx` memory as set here. The default is `25` which means 25% of the `-Xmx` -# is used as the initial heap size. You can skip this mechanism by setting this value -# to `0` in which case no `-Xms` option is added (example: "25") -# - JAVA_MAX_INITIAL_MEM: Is used when no `-Xms` option is given in JAVA_OPTS. -# This is used to calculate the maximum value of the initial heap memory. If used in -# a container without any memory constraints for the container then this option has -# no effect. If there is a memory constraint then `-Xms` is limited to the value set -# here. The default is 4096MB which means the calculated value of `-Xms` never will -# be greater than 4096MB. The value of this variable is expressed in MB (example: "4096") -# - JAVA_DIAGNOSTICS: Set this to get some diagnostics information to standard output -# when things are happening. This option, if set to true, will set -# `-XX:+UnlockDiagnosticVMOptions`. Disabled by default (example: "true"). -# - JAVA_DEBUG: If set remote debugging will be switched on. Disabled by default (example: -# true"). -# - JAVA_DEBUG_PORT: Port used for remote debugging. Defaults to 5005 (example: "8787"). -# - CONTAINER_CORE_LIMIT: A calculated core limit as described in -# https://www.kernel.org/doc/Documentation/scheduler/sched-bwc.txt. (example: "2") -# - CONTAINER_MAX_MEMORY: Memory limit given to the container (example: "1024"). -# - GC_MIN_HEAP_FREE_RATIO: Minimum percentage of heap free after GC to avoid expansion. -# (example: "20") -# - GC_MAX_HEAP_FREE_RATIO: Maximum percentage of heap free after GC to avoid shrinking. -# (example: "40") -# - GC_TIME_RATIO: Specifies the ratio of the time spent outside the garbage collection. -# (example: "4") -# - GC_ADAPTIVE_SIZE_POLICY_WEIGHT: The weighting given to the current GC time versus -# previous GC times. (example: "90") -# - GC_METASPACE_SIZE: The initial metaspace size. (example: "20") -# - GC_MAX_METASPACE_SIZE: The maximum metaspace size. (example: "100") -# - GC_CONTAINER_OPTIONS: Specify Java GC to use. The value of this variable should -# contain the necessary JRE command-line options to specify the required GC, which -# will override the default of `-XX:+UseParallelGC` (example: -XX:+UseG1GC). -# - HTTPS_PROXY: The location of the https proxy. (example: "myuser@127.0.0.1:8080") -# - HTTP_PROXY: The location of the http proxy. (example: "myuser@127.0.0.1:8080") -# - NO_PROXY: A comma separated lists of hosts, IP addresses or domains that can be -# accessed directly. (example: "foo.example.com,bar.example.com") -# -### -FROM registry.access.redhat.com/ubi8/openjdk-17:1.15 - -ENV LANGUAGE='en_US:en' - - -COPY target/lib/* /deployments/lib/ -COPY target/*-runner.jar /deployments/quarkus-run.jar - -EXPOSE 8080 -USER 185 -ENV JAVA_OPTS="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager" -ENV JAVA_APP_JAR="/deployments/quarkus-run.jar" diff --git a/onboarding-ms/src/main/docker/Dockerfile.native b/onboarding-ms/src/main/docker/Dockerfile.native deleted file mode 100644 index 475a1aa2a..000000000 --- a/onboarding-ms/src/main/docker/Dockerfile.native +++ /dev/null @@ -1,27 +0,0 @@ -#### -# This Dockerfile is used in order to build a container that runs the Quarkus application in native (no JVM) mode. -# -# Before building the container image run: -# -# ./mvnw package -Pnative -# -# Then, build the image with: -# -# docker build -f src/main/docker/Dockerfile.native -t quarkus/onboarding-ms . -# -# Then run the container using: -# -# docker run -i --rm -p 8080:8080 quarkus/onboarding-ms -# -### -FROM registry.access.redhat.com/ubi8/ubi-minimal:8.6 -WORKDIR /work/ -#RUN chown 1001 /work \ -# && chmod "g+rwX" /work \ -# && chown 1001:root /work -COPY target/*-runner /work/application - -EXPOSE 8080 -USER 1001 - -CMD ["./application", "-Dquarkus.http.host=0.0.0.0"] diff --git a/onboarding-ms/src/main/docker/Dockerfile.native-micro b/onboarding-ms/src/main/docker/Dockerfile.native-micro deleted file mode 100644 index 5d24ba24b..000000000 --- a/onboarding-ms/src/main/docker/Dockerfile.native-micro +++ /dev/null @@ -1,30 +0,0 @@ -#### -# This Dockerfile is used in order to build a container that runs the Quarkus application in native (no JVM) mode. -# It uses a micro base image, tuned for Quarkus native executables. -# It reduces the size of the resulting container image. -# Check https://quarkus.io/guides/quarkus-runtime-base-image for further information about this image. -# -# Before building the container image run: -# -# ./mvnw package -Pnative -# -# Then, build the image with: -# -# docker build -f src/main/docker/Dockerfile.native-micro -t quarkus/onboarding-ms . -# -# Then run the container using: -# -# docker run -i --rm -p 8080:8080 quarkus/onboarding-ms -# -### -FROM quay.io/quarkus/quarkus-micro-image:2.0 -WORKDIR /work/ -#RUN chown 1001 /work \ -# && chmod "g+rwX" /work \ -# && chown 1001:root /work -COPY target/*-runner /work/application - -EXPOSE 8080 -USER 1001 - -CMD ["./application", "-Dquarkus.http.host=0.0.0.0"] diff --git a/onboarding-ms/src/main/java/it/pagopa/selfcare/controller/OnboardingController.java b/onboarding-ms/src/main/java/it/pagopa/selfcare/controller/OnboardingController.java deleted file mode 100644 index 53f356635..000000000 --- a/onboarding-ms/src/main/java/it/pagopa/selfcare/controller/OnboardingController.java +++ /dev/null @@ -1,56 +0,0 @@ -package it.pagopa.selfcare.controller; - -import io.smallrye.mutiny.Uni; -import it.pagopa.selfcare.controller.request.*; -import it.pagopa.selfcare.controller.response.OnboardingResponse; -import it.pagopa.selfcare.mapper.OnboardingMapper; -import it.pagopa.selfcare.service.OnboardingService; -import jakarta.annotation.security.RolesAllowed; -import jakarta.validation.Valid; -import jakarta.ws.rs.*; -import jakarta.ws.rs.core.MediaType; -import lombok.AllArgsConstructor; - -@RolesAllowed("USER") -@Path("/onboarding") -@AllArgsConstructor -public class OnboardingController { - - final private OnboardingService onboardingService; - - @POST - @Consumes(MediaType.APPLICATION_JSON) - @Produces(MediaType.APPLICATION_JSON) - public Uni onboarding(@Valid OnboardingDefaultRequest onboardingRequest) { - return onboardingService.onboarding(onboardingRequest); - } - - @POST - @Path("/pa") - @Consumes(MediaType.APPLICATION_JSON) - @Produces(MediaType.APPLICATION_JSON) - public Uni onboardingPa(@Valid OnboardingPaRequest onboardingRequest) { - return onboardingService.onboardingPa(onboardingRequest); - } - - @POST - @Path("/psp") - @Consumes(MediaType.APPLICATION_JSON) - @Produces(MediaType.APPLICATION_JSON) - public Uni onboardingPsp(@Valid OnboardingPspRequest onboardingRequest) { - return onboardingService.onboardingPsp(onboardingRequest); - } - - /** - * Onboarding pg may be excluded from the async onboarding flow - * Institutions may be saved without passing from onboarding - * - @POST - @Path("/pg") - @Consumes(MediaType.APPLICATION_JSON) - @Produces(MediaType.APPLICATION_JSON) - public Uni onboardingPg(@Valid OnboardingPgRequest onboardingRequest) { - return onboardingService.onboarding(onboardingMapper.toEntity(onboardingRequest)) - .map(onboardingMapper::toResponse); - }*/ -} diff --git a/onboarding-ms/src/main/java/it/pagopa/selfcare/entity/Onboarding.java b/onboarding-ms/src/main/java/it/pagopa/selfcare/entity/Onboarding.java deleted file mode 100644 index 33e51460b..000000000 --- a/onboarding-ms/src/main/java/it/pagopa/selfcare/entity/Onboarding.java +++ /dev/null @@ -1,23 +0,0 @@ -package it.pagopa.selfcare.entity; - -import it.pagopa.selfcare.controller.request.ContractRequest; -import it.pagopa.selfcare.controller.request.OnboardingImportContract; -import lombok.Data; -import org.bson.types.ObjectId; - -import java.util.List; - -@Data -public class Onboarding { - - public ObjectId id; - - private String productId; - private Institution institution; - private List users; - private String pricingPlan; - private Billing billing; - private ContractRequest contract; - private OnboardingImportContract contractImported; - private Boolean signContract; -} diff --git a/onboarding-ms/src/main/java/it/pagopa/selfcare/mapper/OnboardingMapper.java b/onboarding-ms/src/main/java/it/pagopa/selfcare/mapper/OnboardingMapper.java deleted file mode 100644 index 2a533b2b6..000000000 --- a/onboarding-ms/src/main/java/it/pagopa/selfcare/mapper/OnboardingMapper.java +++ /dev/null @@ -1,22 +0,0 @@ -package it.pagopa.selfcare.mapper; - -import it.pagopa.selfcare.controller.request.*; -import it.pagopa.selfcare.controller.response.OnboardingResponse; -import it.pagopa.selfcare.entity.Onboarding; -import org.mapstruct.Mapper; -import org.mapstruct.Mapping; - -@Mapper(componentModel = "cdi") -public interface OnboardingMapper { - - Onboarding toEntity(OnboardingPaRequest request); - Onboarding toEntity(OnboardingPspRequest request); - Onboarding toEntity(OnboardingDefaultRequest request); - - @Mapping(source = "taxCode", target = "institution.taxCode") - @Mapping(source = "businessName", target = "institution.description") - @Mapping(source = "digitalAddress", target = "institution.digitalAddress") - Onboarding toEntity(OnboardingPgRequest request); - - OnboardingResponse toResponse(Onboarding onboarding); -} diff --git a/onboarding-ms/src/main/java/it/pagopa/selfcare/repository/OnboardingRepository.java b/onboarding-ms/src/main/java/it/pagopa/selfcare/repository/OnboardingRepository.java deleted file mode 100644 index e9998ab6b..000000000 --- a/onboarding-ms/src/main/java/it/pagopa/selfcare/repository/OnboardingRepository.java +++ /dev/null @@ -1,45 +0,0 @@ -package it.pagopa.selfcare.repository; - -import com.mongodb.client.model.Filters; -import io.quarkus.mongodb.reactive.ReactiveMongoClient; -import io.quarkus.mongodb.reactive.ReactiveMongoCollection; -import io.smallrye.mutiny.Uni; -import it.pagopa.selfcare.entity.Onboarding; -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.inject.Inject; -import org.bson.BsonObjectId; -import org.eclipse.microprofile.config.inject.ConfigProperty; - -import java.util.Objects; -import java.util.Optional; - -@ApplicationScoped -public class OnboardingRepository { - - public static final String COLLECTION_NAME = "onboardings"; - @ConfigProperty(name = "quarkus.mongodb.database") - String mongodbDatabase; - - @Inject - ReactiveMongoClient mongoClient; - - - public Uni persistOrUpdate(Onboarding model) { - return Objects.nonNull(model.getId()) - ? getCollection().findOneAndReplace(Filters.eq("_id", model.getId()), model) - : getCollection().insertOne(model) - .onItem().transform(insertOneResult -> { - model.setId(Optional.ofNullable(insertOneResult.getInsertedId()) - .map(id -> id.asObjectId().getValue()) - .orElse(null)); - return model; - }); - } - - - private ReactiveMongoCollection getCollection(){ - return mongoClient - .getDatabase(mongodbDatabase) - .getCollection(COLLECTION_NAME, Onboarding.class); - } -} diff --git a/onboarding-ms/src/main/java/it/pagopa/selfcare/service/OnboardingService.java b/onboarding-ms/src/main/java/it/pagopa/selfcare/service/OnboardingService.java deleted file mode 100644 index 57f6d00b0..000000000 --- a/onboarding-ms/src/main/java/it/pagopa/selfcare/service/OnboardingService.java +++ /dev/null @@ -1,16 +0,0 @@ -package it.pagopa.selfcare.service; - -import io.smallrye.mutiny.Uni; -import it.pagopa.selfcare.controller.request.OnboardingDefaultRequest; -import it.pagopa.selfcare.controller.request.OnboardingPaRequest; -import it.pagopa.selfcare.controller.request.OnboardingPspRequest; -import it.pagopa.selfcare.controller.response.OnboardingResponse; -import it.pagopa.selfcare.entity.Onboarding; - -public interface OnboardingService { - - Uni onboarding(OnboardingDefaultRequest onboardingRequest); - - Uni onboardingPsp(OnboardingPspRequest onboardingRequest); - Uni onboardingPa(OnboardingPaRequest onboardingRequest); -} diff --git a/onboarding-ms/src/main/java/it/pagopa/selfcare/service/OnboardingServiceDefault.java b/onboarding-ms/src/main/java/it/pagopa/selfcare/service/OnboardingServiceDefault.java deleted file mode 100644 index 4a6556d6d..000000000 --- a/onboarding-ms/src/main/java/it/pagopa/selfcare/service/OnboardingServiceDefault.java +++ /dev/null @@ -1,160 +0,0 @@ -package it.pagopa.selfcare.service; - -import io.smallrye.mutiny.Multi; -import io.smallrye.mutiny.Uni; -import it.pagopa.selfcare.commons.base.security.PartyRole; -import it.pagopa.selfcare.constants.CustomError; -import it.pagopa.selfcare.controller.request.OnboardingDefaultRequest; -import it.pagopa.selfcare.controller.request.OnboardingPaRequest; -import it.pagopa.selfcare.controller.request.OnboardingPspRequest; -import it.pagopa.selfcare.controller.request.UserRequest; -import it.pagopa.selfcare.controller.response.OnboardingResponse; -import it.pagopa.selfcare.entity.Onboarding; -import it.pagopa.selfcare.entity.User; -import it.pagopa.selfcare.exception.InvalidRequestException; -import it.pagopa.selfcare.exception.UpdateNotAllowedException; -import it.pagopa.selfcare.mapper.OnboardingMapper; -import it.pagopa.selfcare.repository.OnboardingRepository; -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.inject.Inject; -import jakarta.ws.rs.WebApplicationException; -import org.eclipse.microprofile.rest.client.inject.RestClient; -import org.openapi.quarkus.user_registry_json.api.UserApi; -import org.openapi.quarkus.user_registry_json.model.*; - -import java.util.*; -import java.util.stream.Collectors; - -@ApplicationScoped -public class OnboardingServiceDefault implements OnboardingService { - - public static final String USERS_FIELD_LIST = "fiscalCode,name,workContacts"; - @RestClient - @Inject - UserApi userRegistryApi; - - @Inject - OnboardingRepository onboardingRepository; - - @Inject - OnboardingMapper onboardingMapper; - - @Override - public Uni onboarding(OnboardingDefaultRequest onboardingRequest) { - return fillUsersAndOnboarding(onboardingMapper.toEntity(onboardingRequest), onboardingRequest.getUsers()); - } - - @Override - public Uni onboardingPsp(OnboardingPspRequest onboardingRequest) { - return fillUsersAndOnboarding(onboardingMapper.toEntity(onboardingRequest), onboardingRequest.getUsers()); - } - - @Override - public Uni onboardingPa(OnboardingPaRequest onboardingRequest) { - return fillUsersAndOnboarding(onboardingMapper.toEntity(onboardingRequest), onboardingRequest.getUsers()); - } - - public Uni fillUsersAndOnboarding(Onboarding onboarding, List userRequests) { - - /** Check if Product is Valid and retrieve */ - /* PT is delegable ? - if(InstitutionType.PT == onboardingData.getInstitutionType() && !delegable) { - throw new OnboardingNotAllowedException(String.format(ONBOARDING_NOT_ALLOWED_ERROR_MESSAGE_TEMPLATE, - onboardingData.getTaxCode(), - onboardingData.getProductId())); - }*/ - - /* Check validation on onboarding maps */ - /* Check if role user is valid using Product, - /* Verify already onboarding for product and product parent */ - - return checkRoleAndRetrieveUsers(userRequests, List.of(PartyRole.MANAGER, PartyRole.DELEGATE)) - .onItem().invoke(onboarding::setUsers).replaceWith(onboarding) - .onItem().transformToUni(onboardingRepository::persistOrUpdate) - .onItem().transform(onboardingMapper::toResponse); - } - - public Uni> checkRoleAndRetrieveUsers(List users, List validRoles) { - - List usersNotValidRole = users.stream() - .filter(user -> !validRoles.contains(user.getRole())) - .toList(); - if (!usersNotValidRole.isEmpty()) { - String usersNotValidRoleString = usersNotValidRole.stream() - .map(user -> user.getRole().toString()) - .collect(Collectors.joining(",")); - return Uni.createFrom().failure( new InvalidRequestException(String.format(CustomError.ROLES_NOT_ADMITTED_ERROR.getMessage(), usersNotValidRoleString), - CustomError.ROLES_NOT_ADMITTED_ERROR.getCode())); - } - - return Multi.createFrom().iterable(users) - .onItem().transformToUni(user -> userRegistryApi - .searchUsingPOST(USERS_FIELD_LIST, new UserSearchDto().fiscalCode(user.getTaxCode())) - - /* retrieve userId, if found will eventually update some fields */ - .onItem().transformToUni(userResource -> createUpdateUserRequest(user, userResource) - .map(userUpdateRequest -> userRegistryApi.updateUsingPATCH(userResource.getId().toString(), userUpdateRequest) - .replaceWith(userResource.getId())) - .orElse(Uni.createFrom().item(userResource.getId()))) - /* if not found 404, will create new user */ - .onFailure(WebApplicationException.class).recoverWithUni(ex -> ((WebApplicationException)ex).getResponse().getStatus() == 404 - ? userRegistryApi.saveUsingPATCH(createSaveUserDto(user)).onItem().transform(UserId::getId) - : Uni.createFrom().failure(ex)) - .onItem().transform(userResourceId -> User.builder() - .id(userResourceId.toString()) - .role(user.getRole()) - .build()) - ) - .concatenate().collect().asList(); - } - - private SaveUserDto createSaveUserDto(UserRequest model) { - SaveUserDto resource = new SaveUserDto(); - resource.setFiscalCode(model.getTaxCode()); - resource.setName(new CertifiableFieldResourceOfstring() - .value(model.getName()) - .certification(CertifiableFieldResourceOfstring.CertificationEnum.NONE)); - resource.setFamilyName(new CertifiableFieldResourceOfstring() - .value(model.getSurname()) - .certification(CertifiableFieldResourceOfstring.CertificationEnum.NONE)); - return resource; - } - - protected static Optional createUpdateUserRequest(UserRequest user, UserResource foundUser) { - Optional mutableUserFieldsDto = Optional.empty(); - if (isFieldToUpdate(foundUser.getName(), user.getName())) { - MutableUserFieldsDto dto = new MutableUserFieldsDto(); - dto.setName(new CertifiableFieldResourceOfstring() - .value(user.getName()) - .certification(CertifiableFieldResourceOfstring.CertificationEnum.NONE)); - mutableUserFieldsDto = Optional.of(dto); - } - if (isFieldToUpdate(foundUser.getFamilyName(), user.getSurname())) { - MutableUserFieldsDto dto = mutableUserFieldsDto.orElseGet(MutableUserFieldsDto::new); - dto.setFamilyName(new CertifiableFieldResourceOfstring() - .value(user.getSurname()) - .certification(CertifiableFieldResourceOfstring.CertificationEnum.NONE)); - mutableUserFieldsDto = Optional.of(dto); - } - return mutableUserFieldsDto; - } - - private static boolean isFieldToUpdate(CertifiableFieldResourceOfstring certifiedField, String value) { - boolean isToUpdate = true; - if (certifiedField != null) { - if (CertifiableFieldResourceOfstring.CertificationEnum.NONE.equals(certifiedField.getCertification())) { - if (certifiedField.getValue().equals(value)) { - isToUpdate = false; - } - } else { - if (certifiedField.getValue().equalsIgnoreCase(value)) { - isToUpdate = false; - } else { - throw new UpdateNotAllowedException(String.format("Update user request not allowed because of value %s", value)); - } - } - } - return isToUpdate; - } - -} diff --git a/onboarding-ms/src/main/openapi/core.json b/onboarding-ms/src/main/openapi/core.json deleted file mode 100644 index 22831f10d..000000000 --- a/onboarding-ms/src/main/openapi/core.json +++ /dev/null @@ -1 +0,0 @@ -{"openapi":"3.0.3","info":{"title":"selc-ms-core","version":"1.0-SNAPSHOT"},"servers":[{"url":"{url}:{port}{basePath}","variables":{"url":{"default":"http://10.1.1.250"},"port":{"default":"80"},"basePath":{"default":""}}}],"tags":[{"name":"External","description":"External Controller"},{"name":"Institution","description":"Institution Controller"},{"name":"Management","description":"Management Controller"},{"name":"Migration","description":"Crud Controller"},{"name":"Onboarding","description":"Onboarding Controller"},{"name":"Persons","description":"User Controller"},{"name":"Token","description":"Token Controller"}],"paths":{"/migration/institution":{"post":{"tags":["Migration"],"summary":"${swagger.mscore.migration.save.institution}","description":"${swagger.mscore.migration.save.institution}","operationId":"createInstitutionUsingPOST","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MigrationInstitution"}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Institution"}}}},"400":{"description":"Bad Request","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not Found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"Conflict","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}},"security":[{"bearerAuth":["global"]}]}},"/migration/institution/{id}":{"get":{"tags":["Migration"],"summary":"${swagger.mscore.migration.findbyid.institution}","description":"${swagger.mscore.migration.findbyid.institution}","operationId":"findInstitutionByIdUsingGET","parameters":[{"name":"id","in":"path","description":"id","required":true,"style":"simple","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Institution"}}}},"400":{"description":"Bad Request","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not Found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}},"security":[{"bearerAuth":["global"]}]},"delete":{"tags":["Migration"],"summary":"${swagger.mscore.migration.delete.institution}","description":"${swagger.mscore.migration.delete.institution}","operationId":"deleteInstitutionUsingDELETE","parameters":[{"name":"id","in":"path","description":"id","required":true,"style":"simple","schema":{"type":"string"}}],"responses":{"204":{"description":"No Content","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Institution"}}}},"400":{"description":"Bad Request","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not Found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"Conflict","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}},"security":[{"bearerAuth":["global"]}]}},"/migration/institutions":{"get":{"tags":["Migration"],"summary":"${swagger.mscore.migration.find.institution}","description":"${swagger.mscore.migration.find.institution}","operationId":"findInstitutionsUsingGET","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Institution"}}}}},"400":{"description":"Bad Request","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not Found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}},"security":[{"bearerAuth":["global"]}]}},"/migration/token":{"post":{"tags":["Migration"],"summary":"${swagger.mscore.migration.save.token}","description":"${swagger.mscore.migration.save.token}","operationId":"createTokenUsingPOST","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MigrationToken"}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Token"}}}},"400":{"description":"Bad Request","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not Found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"Conflict","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}},"security":[{"bearerAuth":["global"]}]}},"/migration/token/{id}":{"get":{"tags":["Migration"],"summary":"${swagger.mscore.migration.findbyid.token}","description":"${swagger.mscore.migration.findbyid.token}","operationId":"findTokenByIdUsingGET","parameters":[{"name":"id","in":"path","description":"id","required":true,"style":"simple","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Token"}}}},"400":{"description":"Bad Request","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not Found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}},"security":[{"bearerAuth":["global"]}]},"delete":{"tags":["Migration"],"summary":"${swagger.mscore.migration.delete.token}","description":"${swagger.mscore.migration.delete.token}","operationId":"deleteTokenUsingDELETE","parameters":[{"name":"id","in":"path","description":"id","required":true,"style":"simple","schema":{"type":"string"}}],"responses":{"204":{"description":"No Content","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Token"}}}},"400":{"description":"Bad Request","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not Found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"Conflict","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}},"security":[{"bearerAuth":["global"]}]}},"/migration/tokens":{"get":{"tags":["Migration"],"summary":"${swagger.mscore.migration.find.token}","description":"${swagger.mscore.migration.find.token}","operationId":"findTokensUsingGET","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Token"}}}}},"400":{"description":"Bad Request","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not Found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}},"security":[{"bearerAuth":["global"]}]}},"/migration/user":{"post":{"tags":["Migration"],"summary":"${swagger.mscore.migration.save.user}","description":"${swagger.mscore.migration.save.user}","operationId":"createUserUsingPOST","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MigrationOnboardedUser"}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardedUser"}}}},"400":{"description":"Bad Request","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not Found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"Conflict","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}},"security":[{"bearerAuth":["global"]}]}},"/migration/user/{id}":{"get":{"tags":["Migration"],"summary":"${swagger.mscore.migration.findbyid.user}","description":"${swagger.mscore.migration.findbyid.user}","operationId":"findUserByIdUsingGET","parameters":[{"name":"id","in":"path","description":"id","required":true,"style":"simple","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardedUser"}}}},"400":{"description":"Bad Request","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not Found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}},"security":[{"bearerAuth":["global"]}]},"delete":{"tags":["Migration"],"summary":"${swagger.mscore.migration.delete.user}","description":"${swagger.mscore.migration.delete.user}","operationId":"deleteUserUsingDELETE","parameters":[{"name":"id","in":"path","description":"id","required":true,"style":"simple","schema":{"type":"string"}}],"responses":{"204":{"description":"No Content","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardedUser"}}}},"400":{"description":"Bad Request","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not Found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"Conflict","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}},"security":[{"bearerAuth":["global"]}]}},"/migration/users":{"get":{"tags":["Migration"],"summary":"${swagger.mscore.migration.find.token}","description":"${swagger.mscore.migration.find.token}","operationId":"findUsersUsingGET","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/OnboardedUser"}}}}},"400":{"description":"Bad Request","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not Found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}},"security":[{"bearerAuth":["global"]}]}},"/external/institutions":{"get":{"tags":["External"],"summary":"Gets the corresponding institution using internal institution id","description":"Gets the corresponding institution using internal institution id","operationId":"retrieveInstitutionByIdsUsingGET","parameters":[{"name":"ids","in":"query","description":"List of Institution to onboard","required":true,"style":"form","explode":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/InstitutionResponse"}}}}},"400":{"description":"Bad Request","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not Found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}},"security":[{"bearerAuth":["global"]}]}},"/external/institutions/pn-pg":{"post":{"tags":["External"],"summary":"create an institution (PG) using external institution id fetching data from info-camere","description":"create an institution (PG) using external institution id fetching data from info-camere","operationId":"createPnPgInstitutionUsingPOST","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatePnPgInstitutionRequest"}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InstitutionPnPgResponse"}}}},"400":{"description":"Bad Request","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not Found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"Conflict","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}},"security":[{"bearerAuth":["global"]}]}},"/external/institutions/{externalId}":{"get":{"tags":["External"],"summary":"Gets institution using external institution id","description":"Gets institution using external institution id","operationId":"getByExternalIdUsingGET","parameters":[{"name":"externalId","in":"path","description":"Institution's unique external identifier","required":true,"style":"simple","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InstitutionResponse"}}}},"400":{"description":"Bad Request","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not Found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}},"security":[{"bearerAuth":["global"]}]}},"/external/institutions/{externalId}/geotaxonomies":{"get":{"tags":["External"],"summary":"retrieves the geographic taxonomies related to Institution.","description":"retrieves the geographic taxonomies related to Institution.","operationId":"retrieveInstitutionGeoTaxonomiesByExternalIdUsingGET","parameters":[{"name":"externalId","in":"path","description":"Institution's unique external identifier","required":true,"style":"simple","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/GeographicTaxonomies"}}}}},"400":{"description":"Bad Request","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not Found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}},"security":[{"bearerAuth":["global"]}]}},"/external/institutions/{externalId}/products":{"get":{"tags":["External"],"summary":"retrieves the products related to Institution","description":"retrieves the products related to Institution","operationId":"retrieveInstitutionProductsByExternalIdUsingGET","parameters":[{"name":"externalId","in":"path","description":"Institution's unique external identifier","required":true,"style":"simple","schema":{"type":"string"}},{"name":"states","in":"query","description":"states","required":false,"style":"form","explode":true,"schema":{"type":"string","enum":["ACTIVE","DELETED","PENDING","REJECTED","SUSPENDED","TOBEVALIDATED"]}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardedProducts"}}}},"400":{"description":"Bad Request","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not Found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}},"security":[{"bearerAuth":["global"]}]}},"/external/institutions/{externalId}/products/{productId}/billing":{"get":{"tags":["External"],"summary":"retrieves the billing data related to the institution even if the current user is not related to the institution/product","description":"retrieves the billing data related to the institution even if the current user is not related to the institution/product","operationId":"getBillingInstitutionByExternalIdUsingGET","parameters":[{"name":"externalId","in":"path","description":"Institution's unique external identifier","required":true,"style":"simple","schema":{"type":"string"}},{"name":"productId","in":"path","description":"Product's unique identifier","required":true,"style":"simple","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InstitutionBillingResponse"}}}},"400":{"description":"Bad Request","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not Found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}},"security":[{"bearerAuth":["global"]}]}},"/external/institutions/{externalId}/products/{productId}/manager":{"get":{"tags":["External"],"summary":"retrieves the manager related to the institution even if the current user is not related to the institution/product","description":"retrieves the manager related to the institution even if the current user is not related to the institution/product","operationId":"getManagerInstitutionByExternalIdUsingGET","parameters":[{"name":"externalId","in":"path","description":"Institution's unique external identifier","required":true,"style":"simple","schema":{"type":"string"}},{"name":"productId","in":"path","description":"Product's unique identifier","required":true,"style":"simple","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InstitutionManagerResponse"}}}},"400":{"description":"Bad Request","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not Found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}},"security":[{"bearerAuth":["global"]}]}},"/external/institutions/{externalId}/relationships":{"get":{"tags":["External"],"summary":"returns the relationships related to the institution","description":"returns the relationships related to the institution","operationId":"getUserInstitutionRelationshipsByExternalIdUsingGET","parameters":[{"name":"externalId","in":"path","description":"Institution's unique external identifier","required":true,"style":"simple","schema":{"type":"string"}},{"name":"personId","in":"query","description":"personId","required":false,"style":"form","schema":{"type":"string"}},{"name":"roles","in":"query","description":"roles","required":false,"style":"form","explode":true,"schema":{"type":"string","enum":["DELEGATE","MANAGER","OPERATOR","SUB_DELEGATE"]}},{"name":"states","in":"query","description":"states","required":false,"style":"form","explode":true,"schema":{"type":"string","enum":["ACTIVE","DELETED","PENDING","REJECTED","SUSPENDED","TOBEVALIDATED"]}},{"name":"products","in":"query","description":"products","required":false,"style":"form","explode":true,"schema":{"type":"string"}},{"name":"productRoles","in":"query","description":"productRoles","required":false,"style":"form","explode":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/RelationshipResult"}}}}},"400":{"description":"Bad Request","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not Found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}},"security":[{"bearerAuth":["global"]}]}},"/institutions/":{"get":{"tags":["Institution"],"summary":"Gets institutions filtering by taxCode and/or subunitCode","description":"Gets institutions filtering by taxCode and/or subunitCode","operationId":"getInstitutionsUsingGET","parameters":[{"name":"taxCode","in":"query","description":"${swagger.mscore.institutions.model.taxCode}","required":true,"style":"form","schema":{"type":"string"}},{"name":"subunitCode","in":"query","description":"${swagger.mscore.institutions.model.subunitCode}","required":false,"style":"form","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InstitutionsResponse"}}}},"400":{"description":"Bad Request","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not Found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}},"security":[{"bearerAuth":["global"]}]},"post":{"tags":["Institution"],"summary":"create an institution using external institution id without fetching data from party-registry or info-camere","description":"create an institution using external institution id without fetching data from party-registry or info-camere","operationId":"createInstitutionUsingPOST_1","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InstitutionRequest"}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InstitutionResponse"}}}},"400":{"description":"Bad Request","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not Found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"Conflict","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}},"security":[{"bearerAuth":["global"]}]}},"/institutions/from-ipa/":{"post":{"tags":["Institution"],"summary":"${swagger.mscore.institution.create.from-ipa}","description":"${swagger.mscore.institution.create.from-ipa}","operationId":"createInstitutionFromIpaUsingPOST","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InstitutionFromIpaPost"}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InstitutionResponse"}}}},"400":{"description":"Bad Request","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not Found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"Conflict","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}},"security":[{"bearerAuth":["global"]}]}},"/institutions/insert/{externalId}":{"post":{"tags":["Institution"],"summary":"create an institution using external institution id without fetching data from party-registry or info-camere","description":"create an institution using external institution id without fetching data from party-registry or info-camere","operationId":"createInstitutionRawUsingPOST","parameters":[{"name":"externalId","in":"path","description":"Institution's unique external identifier","required":true,"style":"simple","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InstitutionRequest"}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InstitutionResponse"}}}},"400":{"description":"Bad Request","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not Found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"Conflict","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}},"deprecated":true,"security":[{"bearerAuth":["global"]}]}},"/institutions/onboarded/{productId}":{"post":{"tags":["Institution"],"summary":"Retrieve list of institution which logged user can onboard","description":"Retrieve list of institution which logged user can onboard","operationId":"getValidInstitutionToOnboardUsingPOST","parameters":[{"name":"productId","in":"path","description":"productId","required":true,"style":"simple","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/InstitutionToOnboard"}}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/InstitutionToOnboard"}}}}},"400":{"description":"Bad Request","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not Found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"Conflict","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}},"security":[{"bearerAuth":["global"]}]}},"/institutions/pg":{"post":{"tags":["Institution"],"summary":"create an institution (PG) using external institution id fetching data from info-camere","description":"create an institution (PG) using external institution id fetching data from info-camere","operationId":"createPgInstitutionUsingPOST","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatePgInstitutionRequest"}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InstitutionResponse"}}}},"400":{"description":"Bad Request","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not Found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"Conflict","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}},"security":[{"bearerAuth":["global"]}]}},"/institutions/{externalId}":{"post":{"tags":["Institution"],"summary":"create an institution (PA) using external institution id fetching data from party-registry","description":"create an institution (PA) using external institution id fetching data from party-registry","operationId":"createInstitutionByExternalIdUsingPOST","parameters":[{"name":"externalId","in":"path","description":"Institution's unique external identifier","required":true,"style":"simple","schema":{"type":"string"}}],"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InstitutionResponse"}}}},"400":{"description":"Bad Request","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not Found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"Conflict","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}},"deprecated":true,"security":[{"bearerAuth":["global"]}]}},"/institutions/{id}":{"get":{"tags":["Institution"],"summary":"Gets the corresponding institution using internal institution id","description":"Gets the corresponding institution using internal institution id","operationId":"retrieveInstitutionByIdUsingGET","parameters":[{"name":"id","in":"path","description":"The internal identifier of the institution","required":true,"style":"simple","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InstitutionResponse"}}}},"400":{"description":"Bad Request","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not Found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}},"security":[{"bearerAuth":["global"]}]},"put":{"tags":["Institution"],"summary":"update institution data of given institution","description":"update institution data of given institution","operationId":"updateInstitutionUsingPUT","parameters":[{"name":"id","in":"path","description":"The internal identifier of the institution","required":true,"style":"simple","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InstitutionPut"}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InstitutionResponse"}}}},"400":{"description":"Bad Request","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"Forbidden","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not Found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}},"security":[{"bearerAuth":["global"]}]},"head":{"tags":["Management"],"summary":"verify if Institution exists for a given ID","description":"verify if Institution exists for a given ID","operationId":"verifyInstitutionUsingHEAD","parameters":[{"name":"id","in":"path","description":"The internal identifier of the institution","required":true,"style":"simple","schema":{"type":"string"}}],"responses":{"204":{"description":"No Content"},"400":{"description":"Bad Request","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not Found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}},"deprecated":true,"security":[{"bearerAuth":["global"]}]}},"/institutions/{id}/geotaxonomies":{"get":{"tags":["Institution"],"summary":"retrieves the geographic taxonomies this institution is related to","description":"retrieves the geographic taxonomies this institution is related to","operationId":"retrieveInstitutionGeoTaxonomiesUsingGET","parameters":[{"name":"id","in":"path","description":"The internal identifier of the institution","required":true,"style":"simple","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/GeographicTaxonomies"}}}}},"400":{"description":"Bad Request","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not Found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}},"security":[{"bearerAuth":["global"]}]}},"/institutions/{id}/products":{"get":{"tags":["Institution"],"summary":"retrieves the insistitution's related products.","description":"retrieves the insistitution's related products.","operationId":"retrieveInstitutionProductsUsingGET","parameters":[{"name":"id","in":"path","description":"The internal identifier of the institution","required":true,"style":"simple","schema":{"type":"string"}},{"name":"states","in":"query","description":"List of Relationship state for filter products","required":false,"style":"form","explode":true,"schema":{"type":"string","enum":["ACTIVE","DELETED","PENDING","REJECTED","SUSPENDED","TOBEVALIDATED"]}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardedProducts"}}}},"400":{"description":"Bad Request","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not Found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}},"security":[{"bearerAuth":["global"]}]}},"/institutions/{id}/relationships":{"get":{"tags":["Institution"],"summary":"returns the relationships related to the institution","description":"returns the relationships related to the institution","operationId":"getUserInstitutionRelationshipsUsingGET","parameters":[{"name":"id","in":"path","description":"The internal identifier of the institution","required":true,"style":"simple","schema":{"type":"string"}},{"name":"personId","in":"query","description":"personId","required":false,"style":"form","schema":{"type":"string"}},{"name":"roles","in":"query","description":"roles","required":false,"style":"form","explode":true,"schema":{"type":"string","enum":["DELEGATE","MANAGER","OPERATOR","SUB_DELEGATE"]}},{"name":"states","in":"query","description":"states","required":false,"style":"form","explode":true,"schema":{"type":"string","enum":["ACTIVE","DELETED","PENDING","REJECTED","SUSPENDED","TOBEVALIDATED"]}},{"name":"products","in":"query","description":"products","required":false,"style":"form","explode":true,"schema":{"type":"string"}},{"name":"productRoles","in":"query","description":"productRoles","required":false,"style":"form","explode":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/RelationshipResult"}}}}},"400":{"description":"Bad Request","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not Found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}},"security":[{"bearerAuth":["global"]}]}},"/institutions/{institutionId}/onboardings":{"get":{"tags":["Institution"],"summary":"${swagger.mscore.institution.info}","description":"${swagger.mscore.institution.info}","operationId":"getOnboardingsInstitutionUsingGET","parameters":[{"name":"institutionId","in":"path","description":"The internal identifier of the institution","required":true,"style":"simple","schema":{"type":"string"}},{"name":"productId","in":"query","description":"productId","required":false,"style":"form","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardingsResponse"}}}},"400":{"description":"Bad Request","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not Found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}},"security":[{"bearerAuth":["global"]}]}},"/institutions/{institutionId}/products/{productId}/createdAt":{"put":{"tags":["Institution"],"summary":"The service updates the createdAt field for the institution-product pair","description":"The service updates the createdAt field for the institution-product pair","operationId":"updateCreatedAtUsingPUT","parameters":[{"name":"institutionId","in":"path","description":"The internal identifier of the institution","required":true,"style":"simple","schema":{"type":"string"}},{"name":"productId","in":"path","description":"Product's unique identifier","required":true,"style":"simple","schema":{"type":"string"}},{"name":"createdAt","in":"query","description":"The createdAt date","required":true,"style":"form","schema":{"type":"string","format":"date-time"}}],"responses":{"200":{"description":"OK"},"400":{"description":"Bad Request","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"Forbidden","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not Found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}},"security":[{"bearerAuth":["global"]}]}},"/bulk/institutions":{"post":{"tags":["Management"],"summary":"Gets the corresponding institution using internal institution id","description":"Gets the corresponding institution using internal institution id","operationId":"retrieveInstitutionByIdsUsingPOST","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkPartiesSeed"}}}},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/BulkInstitutions"}}}},"400":{"description":"Bad Request","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not Found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"Conflict","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}},"security":[{"bearerAuth":["global"]}]}},"/external/institutions/product/{productId}":{"get":{"tags":["Management"],"summary":"Retrieves Institutions by product ID","description":"Retrieves Institutions by product ID","operationId":"getInstitutionByProductIdUsingGET","parameters":[{"name":"productId","in":"path","description":"Product's unique identifier","required":true,"style":"simple","schema":{"type":"string"}}],"responses":{"204":{"description":"No Content","content":{"*/*":{"schema":{"$ref":"#/components/schemas/InstitutionListResponse"}}}},"400":{"description":"Bad Request","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not Found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}},"deprecated":true,"security":[{"bearerAuth":["global"]}]}},"/institutions/bygeotaxonomies":{"get":{"tags":["Management"],"summary":"Retrieves a collection of institutions having one or more geographic taxonomies","description":"Retrieves a collection of institutions having one or more geographic taxonomies","operationId":"getInstitutionByGeotaxonomiesUsingGET","parameters":[{"name":"geoTaxonomies","in":"query","description":"Comma separated list of the geographic taxonomies to search","required":true,"style":"form","schema":{"type":"string"}},{"name":"searchMode","in":"query","description":"The search mode to perform, as default 'any'","required":false,"style":"form","schema":{"type":"string","enum":["ALL","ANY","EXACT"]}}],"responses":{"204":{"description":"No Content","content":{"*/*":{"schema":{"$ref":"#/components/schemas/InstitutionListResponse"}}}},"400":{"description":"Bad Request","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not Found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}},"deprecated":true,"security":[{"bearerAuth":["global"]}]}},"/institutions/{id}/attributes":{"get":{"tags":["Management"],"summary":"returns the attributes of the identified institution, if any.","description":"returns the attributes of the identified institution, if any.","operationId":"getInstitutionAttributesUsingGET","parameters":[{"name":"id","in":"path","description":"The internal identifier of the institution","required":true,"style":"simple","schema":{"type":"string"}}],"responses":{"204":{"description":"No Content","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/AttributesResponse"}}}}},"400":{"description":"Bad Request","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not Found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}},"deprecated":true,"security":[{"bearerAuth":["global"]}]}},"/management/external/institutions/{externalId}":{"get":{"tags":["Management"],"summary":"Gets institution using external institution id","description":"Gets institution using external institution id","operationId":"getInstitutionByExternalIdUsingGET","parameters":[{"name":"externalId","in":"path","description":"Institution's unique external identifier","required":true,"style":"simple","schema":{"type":"string"}}],"responses":{"204":{"description":"No Content","content":{"*/*":{"schema":{"$ref":"#/components/schemas/InstitutionManagementResponse"}}}},"400":{"description":"Bad Request","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not Found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}},"deprecated":true,"security":[{"bearerAuth":["global"]}]}},"/management/institutions/{id}":{"get":{"tags":["Management"],"summary":"Gets the corresponding institution using internal institution id","description":"Gets the corresponding institution using internal institution id","operationId":"getInstitutionByInternalIdUsingGET","parameters":[{"name":"id","in":"path","description":"The internal identifier of the institution","required":true,"style":"simple","schema":{"type":"string"}}],"responses":{"204":{"description":"No Content","content":{"*/*":{"schema":{"$ref":"#/components/schemas/InstitutionManagementResponse"}}}},"400":{"description":"Bad Request","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not Found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}},"deprecated":true,"security":[{"bearerAuth":["global"]}]}},"/persons/{id}":{"get":{"tags":["Management"],"summary":"Retrieves Person by ID","description":"Retrieves Person by ID","operationId":"getUserUsingGET","parameters":[{"name":"id","in":"path","description":"User's unique identifier (uuid)","required":true,"style":"simple","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/PersonId"}}}},"400":{"description":"Bad Request","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not Found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}},"deprecated":true,"security":[{"bearerAuth":["global"]}]},"head":{"tags":["Management"],"summary":"verify if a Person exists for a given ID","description":"verify if a Person exists for a given ID","operationId":"verifyUserUsingHEAD","parameters":[{"name":"id","in":"path","description":"User's unique identifier (uuid)","required":true,"style":"simple","schema":{"type":"string"}}],"responses":{"200":{"description":"OK"},"400":{"description":"Bad Request","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not Found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}},"deprecated":true,"security":[{"bearerAuth":["global"]}]}},"/relationships":{"get":{"tags":["Management"],"summary":"Return a list of relationships","description":"Return a list of relationships","operationId":"getInstitutionRelationshipsUsingGET","parameters":[{"name":"from","in":"query","description":"from","required":false,"style":"form","schema":{"type":"string"}},{"name":"to","in":"query","description":"to","required":false,"style":"form","schema":{"type":"string"}},{"name":"roles","in":"query","description":"roles","required":false,"style":"form","explode":true,"schema":{"type":"string","enum":["DELEGATE","MANAGER","OPERATOR","SUB_DELEGATE"]}},{"name":"states","in":"query","description":"states","required":false,"style":"form","explode":true,"schema":{"type":"string","enum":["ACTIVE","DELETED","PENDING","REJECTED","SUSPENDED","TOBEVALIDATED"]}},{"name":"products","in":"query","description":"products","required":false,"style":"form","explode":true,"schema":{"type":"string"}},{"name":"productRoles","in":"query","description":"productRoles","required":false,"style":"form","explode":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"No Content","content":{"*/*":{"schema":{"$ref":"#/components/schemas/RelationshipsManagement"}}}},"400":{"description":"Bad Request","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not Found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}},"deprecated":true,"security":[{"bearerAuth":["global"]}]}},"/tokens/{tokenId}":{"get":{"tags":["Management"],"summary":"retrieve a token relationship","description":"retrieve a token relationship","operationId":"getTokenUsingGET","parameters":[{"name":"tokenId","in":"path","description":"contract's unique identifier","required":true,"style":"simple","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/TokenResponse"}}}},"400":{"description":"Bad Request","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not Found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}},"deprecated":true,"security":[{"bearerAuth":["global"]}]}},"/onboarding/":{"head":{"tags":["Onboarding"],"summary":"verify if onboardedProduct is already onboarded for institution","description":"verify if onboardedProduct is already onboarded for institution","operationId":"verifyOnboardingInfoUsingHEAD","parameters":[{"name":"taxCode","in":"query","description":"${swagger.mscore.institutions.model.taxCode}","required":true,"style":"form","schema":{"type":"string"}},{"name":"subunitCode","in":"query","description":"${swagger.mscore.institutions.model.subunitCode}","required":false,"style":"form","schema":{"type":"string"}},{"name":"productId","in":"query","description":"Product's unique identifier","required":true,"style":"form","schema":{"type":"string"}}],"responses":{"204":{"description":"No Content"},"400":{"description":"Bad Request","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not Found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}},"security":[{"bearerAuth":["global"]}]}},"/onboarding/approve/{tokenId}":{"post":{"tags":["Onboarding"],"summary":"approve an onboarding reuqest by an operator review","description":"approve an onboarding reuqest by an operator review","operationId":"approveOnboardingUsingPOST","parameters":[{"name":"tokenId","in":"path","description":"contract's unique identifier","required":true,"style":"simple","schema":{"type":"string"}}],"responses":{"204":{"description":"No Content"},"400":{"description":"Bad Request","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not Found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"Conflict","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}},"security":[{"bearerAuth":["global"]}]}},"/onboarding/complete/{tokenId}":{"post":{"tags":["Onboarding"],"summary":"complete an onboarding request","description":"complete an onboarding request","operationId":"completeOnboardingUsingPOST","parameters":[{"name":"tokenId","in":"path","description":"contract's unique identifier","required":true,"style":"simple","schema":{"type":"string"}}],"requestBody":{"content":{"multipart/form-data":{"schema":{"required":["contract"],"type":"object","properties":{"contract":{"type":"string","description":"contract","format":"binary"}}}}}},"responses":{"204":{"description":"No Content"},"400":{"description":"Bad Request","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not Found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"Conflict","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}},"security":[{"bearerAuth":["global"]}]},"delete":{"tags":["Onboarding"],"summary":"invalidate an onboarding request","description":"invalidate an onboarding request","operationId":"invalidateOnboardingUsingDELETE","parameters":[{"name":"tokenId","in":"path","description":"contract's unique identifier","required":true,"style":"simple","schema":{"type":"string"}}],"responses":{"204":{"description":"No Content"},"400":{"description":"Bad Request","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not Found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"Conflict","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}},"security":[{"bearerAuth":["global"]}]}},"/onboarding/info":{"get":{"tags":["Onboarding"],"summary":"returns onboarding info","description":"returns onboarding info","operationId":"onboardingInfoUsingGET","parameters":[{"name":"institutionId","in":"query","description":"The internal identifier of the institution","required":false,"style":"form","schema":{"type":"string"}},{"name":"institutionExternalId","in":"query","description":"Institution's unique external identifier","required":false,"style":"form","schema":{"type":"string"}},{"name":"states","in":"query","description":"List of Relationship state for filter products","required":false,"style":"form","explode":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/OnboardingInfoResponse"}}}},"400":{"description":"Bad Request","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not Found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}},"security":[{"bearerAuth":["global"]}]}},"/onboarding/institution":{"post":{"tags":["Onboarding"],"summary":"create a new Token (contract), and update institution and users data","description":"create a new Token (contract), and update institution and users data","operationId":"onboardingInstitutionUsingPOST","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardingInstitutionRequest"}}}},"responses":{"204":{"description":"No Content"},"400":{"description":"Bad Request","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not Found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"Conflict","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}},"security":[{"bearerAuth":["global"]}]}},"/onboarding/institution/complete":{"post":{"tags":["Onboarding"],"summary":"update institution and users data without adding a new token","description":"update institution and users data without adding a new token","operationId":"onboardingInstitutionCompleteUsingPOST","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardingInstitutionRequest"}}}},"responses":{"204":{"description":"No Content"},"400":{"description":"Bad Request","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not Found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"Conflict","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}},"security":[{"bearerAuth":["global"]}]}},"/onboarding/institution/{externalId}/products/{productId}":{"head":{"tags":["Onboarding"],"summary":"verify if onboardedProduct is already onboarded for institution","description":"verify if onboardedProduct is already onboarded for institution","operationId":"verifyOnboardingInfoUsingHEAD_1","parameters":[{"name":"externalId","in":"path","description":"Institution's unique external identifier","required":true,"style":"simple","schema":{"type":"string"}},{"name":"productId","in":"path","description":"Product's unique identifier","required":true,"style":"simple","schema":{"type":"string"}}],"responses":{"204":{"description":"No Content"},"400":{"description":"Bad Request","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not Found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}},"security":[{"bearerAuth":["global"]}]}},"/onboarding/legals":{"post":{"tags":["Onboarding"],"summary":"performs legals onboarding on an already existing institution","description":"performs legals onboarding on an already existing institution","operationId":"onboardingInstitutionLegalsUsingPOST","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardingInstitutionLegalsRequest"}}}},"responses":{"204":{"description":"No Content"},"400":{"description":"Bad Request","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not Found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"Conflict","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}},"security":[{"bearerAuth":["global"]}]}},"/onboarding/operators":{"post":{"tags":["Onboarding"],"summary":"performs operators onboarding on an already existing institution","description":"performs operators onboarding on an already existing institution","operationId":"onboardingInstitutionOperatorsUsingPOST","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardingInstitutionOperatorsRequest"}}}},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/RelationshipResult"}}}}},"400":{"description":"Bad Request","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not Found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"Conflict","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}},"security":[{"bearerAuth":["global"]}]}},"/onboarding/reject/{tokenId}":{"delete":{"tags":["Onboarding"],"summary":"invalidate an onboarding request by an operator review","description":"invalidate an onboarding request by an operator review","operationId":"onboardingRejectUsingDELETE","parameters":[{"name":"tokenId","in":"path","description":"contract's unique identifier","required":true,"style":"simple","schema":{"type":"string"}}],"responses":{"204":{"description":"No Content"},"400":{"description":"Bad Request","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not Found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"Conflict","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}},"security":[{"bearerAuth":["global"]}]}},"/onboarding/relationship/{relationshipId}/document":{"get":{"tags":["Onboarding"],"summary":"retrieve the contractDocument related to a relationship","description":"retrieve the contractDocument related to a relationship","operationId":"getOnboardingDocumentUsingGET","parameters":[{"name":"relationshipId","in":"path","description":"UserBinding's unique identifier","required":true,"style":"simple","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"string","format":"byte"}}}},"400":{"description":"Bad Request","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not Found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}},"security":[{"bearerAuth":["global"]}]}},"/onboarding/subdelegates":{"post":{"tags":["Onboarding"],"summary":"performs subdelegates onboarding on an already existing institution","description":"performs subdelegates onboarding on an already existing institution","operationId":"onboardingInstitutionSubDelegateUsingPOST","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardingInstitutionOperatorsRequest"}}}},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/RelationshipResult"}}}}},"400":{"description":"Bad Request","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not Found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"Conflict","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}},"security":[{"bearerAuth":["global"]}]}},"/onboarding/{tokenId}/consume":{"post":{"tags":["Onboarding"],"summary":"Consume token onboarding request without digest verification ","description":"Consume token onboarding request without digest verification ","operationId":"consumeTokenUsingPOST","parameters":[{"name":"tokenId","in":"path","description":"contract's unique identifier","required":true,"style":"simple","schema":{"type":"string"}}],"requestBody":{"content":{"multipart/form-data":{"schema":{"required":["contract"],"type":"object","properties":{"contract":{"type":"string","description":"contract","format":"binary"}}}}}},"responses":{"204":{"description":"No Content"},"400":{"description":"Bad Request","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not Found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"Conflict","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}},"security":[{"bearerAuth":["global"]}]}},"/tokens/token":{"get":{"tags":["Token"],"summary":"Retrieve token given the institution's and product ids","operationId":"getTokenUsingGET_1","parameters":[{"name":"institutionId","in":"query","description":"Institution's unique internal identifier","required":true,"style":"form","schema":{"type":"string"}},{"name":"productId","in":"query","description":"Product's unique identifier","required":true,"style":"form","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/TokenResource"}}}},"400":{"description":"Bad Request","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not Found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}},"security":[{"bearerAuth":["global"]}]}},"/tokens/{tokenId}/verify":{"post":{"tags":["Token"],"summary":"Verify if the token is already consumed","description":"Verify if the token is already consumed","operationId":"verifyTokenUsingPOST","parameters":[{"name":"tokenId","in":"path","description":"contract's unique identifier","required":true,"style":"simple","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/TokenResponse"}}}},"400":{"description":"Bad Request","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not Found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"Conflict","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}},"security":[{"bearerAuth":["global"]}]}},"/relationships/{relationshipId}":{"get":{"tags":["Persons"],"summary":"Gets the corresponding relationship","description":"Gets the corresponding relationship","operationId":"getRelationshipUsingGET","parameters":[{"name":"relationshipId","in":"path","description":"UserBinding's unique identifier","required":true,"style":"simple","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/RelationshipResult"}}}},"400":{"description":"Bad Request","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not Found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}},"security":[{"bearerAuth":["global"]}]},"delete":{"tags":["Persons"],"summary":"Given a relationship identifier, it deletes the corresponding relationship","description":"Given a relationship identifier, it deletes the corresponding relationship","operationId":"deleteRelationshipUsingDELETE","parameters":[{"name":"relationshipId","in":"path","description":"UserBinding's unique identifier","required":true,"style":"simple","schema":{"type":"string"}}],"responses":{"204":{"description":"No Content"},"400":{"description":"Bad Request","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not Found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"Conflict","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}},"security":[{"bearerAuth":["global"]}]}},"/relationships/{relationshipId}/activate":{"post":{"tags":["Persons"],"summary":"Activate the relationship","description":"Activate the relationship","operationId":"activateRelationshipUsingPOST","parameters":[{"name":"relationshipId","in":"path","description":"UserBinding's unique identifier","required":true,"style":"simple","schema":{"type":"string"}}],"responses":{"204":{"description":"No Content"},"400":{"description":"Bad Request","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not Found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"Conflict","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}},"security":[{"bearerAuth":["global"]}]}},"/relationships/{relationshipId}/suspend":{"post":{"tags":["Persons"],"summary":"Suspend the relationship","description":"Suspend the relationship","operationId":"suspendRelationshipUsingPOST","parameters":[{"name":"relationshipId","in":"path","description":"UserBinding's unique identifier","required":true,"style":"simple","schema":{"type":"string"}}],"responses":{"204":{"description":"No Content"},"400":{"description":"Bad Request","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not Found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"Conflict","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}},"security":[{"bearerAuth":["global"]}]}}},"components":{"schemas":{"Attributes":{"title":"Attributes","type":"object","properties":{"code":{"type":"string"},"description":{"type":"string"},"origin":{"type":"string"}}},"AttributesRequest":{"title":"AttributesRequest","type":"object","properties":{"code":{"type":"string"},"description":{"type":"string"},"origin":{"type":"string"}}},"AttributesResponse":{"title":"AttributesResponse","type":"object","properties":{"code":{"type":"string"},"description":{"type":"string"},"origin":{"type":"string"}}},"Billing":{"title":"Billing","type":"object","properties":{"publicServices":{"type":"boolean"},"recipientCode":{"type":"string"},"vatNumber":{"type":"string"}}},"BillingRequest":{"title":"BillingRequest","type":"object","properties":{"publicServices":{"type":"boolean"},"recipientCode":{"type":"string"},"vatNumber":{"type":"string"}}},"BillingResponse":{"title":"BillingResponse","type":"object","properties":{"publicServices":{"type":"boolean"},"recipientCode":{"type":"string"},"vatNumber":{"type":"string"}}},"BulkInstitution":{"title":"BulkInstitution","required":["address","description","digitalAddress","externalId","id","origin","originId","products","taxCode","zipCode"],"type":"object","properties":{"address":{"type":"string"},"attributes":{"type":"array","items":{"$ref":"#/components/schemas/AttributesResponse"}},"description":{"type":"string"},"digitalAddress":{"type":"string"},"externalId":{"type":"string"},"id":{"type":"string"},"institutionType":{"type":"string","enum":["GSP","PA","PG","PSP","PT","SCP"]},"origin":{"type":"string"},"originId":{"type":"string"},"products":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/BulkProduct"}},"taxCode":{"type":"string"},"zipCode":{"type":"string"}}},"BulkInstitutions":{"title":"BulkInstitutions","type":"object","properties":{"found":{"type":"array","items":{"$ref":"#/components/schemas/BulkInstitution"}},"notFound":{"type":"array","items":{"type":"string"}}}},"BulkPartiesSeed":{"title":"BulkPartiesSeed","required":["partyIdentifiers"],"type":"object","properties":{"partyIdentifiers":{"type":"array","items":{"type":"string"}}}},"BulkProduct":{"title":"BulkProduct","required":["billing","product"],"type":"object","properties":{"billing":{"$ref":"#/components/schemas/BillingResponse"},"pricingPlan":{"type":"string"},"product":{"type":"string"},"status":{"type":"string","enum":["ACTIVE","DELETED","PENDING","REJECTED","SUSPENDED","TOBEVALIDATED"]}}},"BusinessData":{"title":"BusinessData","type":"object","properties":{"businessRegisterPlace":{"type":"string"},"rea":{"type":"string"},"shareCapital":{"type":"string"}}},"Contract":{"title":"Contract","type":"object","properties":{"path":{"type":"string"},"version":{"type":"string"}}},"ContractRequest":{"title":"ContractRequest","type":"object","properties":{"path":{"type":"string"},"version":{"type":"string"}}},"CreatePgInstitutionRequest":{"title":"CreatePgInstitutionRequest","required":["existsInRegistry"],"type":"object","properties":{"description":{"type":"string"},"existsInRegistry":{"type":"boolean"},"taxId":{"type":"string"}}},"CreatePnPgInstitutionRequest":{"title":"CreatePnPgInstitutionRequest","type":"object","properties":{"description":{"type":"string"},"taxId":{"type":"string"}}},"DataProtectionOfficer":{"title":"DataProtectionOfficer","type":"object","properties":{"address":{"type":"string"},"email":{"type":"string"},"pec":{"type":"string"}}},"DataProtectionOfficerRequest":{"title":"DataProtectionOfficerRequest","type":"object","properties":{"address":{"type":"string"},"email":{"type":"string"},"pec":{"type":"string"}}},"DataProtectionOfficerResponse":{"title":"DataProtectionOfficerResponse","type":"object","properties":{"address":{"type":"string"},"email":{"type":"string"},"pec":{"type":"string"}}},"GeoTaxonomies":{"title":"GeoTaxonomies","type":"object","properties":{"code":{"type":"string"},"desc":{"type":"string"}}},"GeographicTaxonomies":{"title":"GeographicTaxonomies","type":"object","properties":{"code":{"type":"string"},"country":{"type":"string"},"country_abbreviation":{"type":"string"},"desc":{"type":"string"},"enabled":{"type":"boolean"},"istat_code":{"type":"string"},"province_abbreviation":{"type":"string"},"province_id":{"type":"string"},"region_id":{"type":"string"}}},"Institution":{"title":"Institution","type":"object","properties":{"address":{"type":"string"},"attributes":{"type":"array","items":{"$ref":"#/components/schemas/Attributes"}},"billing":{"$ref":"#/components/schemas/Billing"},"businessRegisterPlace":{"type":"string"},"createdAt":{"type":"string","format":"date-time"},"dataProtectionOfficer":{"$ref":"#/components/schemas/DataProtectionOfficer"},"description":{"type":"string"},"digitalAddress":{"type":"string"},"externalId":{"type":"string"},"geographicTaxonomies":{"type":"array","items":{"$ref":"#/components/schemas/InstitutionGeographicTaxonomies"}},"id":{"type":"string"},"imported":{"type":"boolean"},"institutionType":{"type":"string","enum":["GSP","PA","PG","PSP","PT","SCP"]},"onboarding":{"type":"array","items":{"$ref":"#/components/schemas/Onboarding"}},"origin":{"type":"string"},"originId":{"type":"string"},"paAttributes":{"$ref":"#/components/schemas/PaAttributes"},"paymentServiceProvider":{"$ref":"#/components/schemas/PaymentServiceProvider"},"rea":{"type":"string"},"shareCapital":{"type":"string"},"subunitCode":{"type":"string"},"subunitType":{"type":"string"},"supportEmail":{"type":"string"},"supportPhone":{"type":"string"},"taxCode":{"type":"string"},"updatedAt":{"type":"string","format":"date-time"},"zipCode":{"type":"string"}}},"InstitutionBillingResponse":{"title":"InstitutionBillingResponse","type":"object","properties":{"address":{"type":"string"},"aooParentCode":{"type":"string"},"billing":{"$ref":"#/components/schemas/BillingResponse"},"description":{"type":"string"},"digitalAddress":{"type":"string"},"externalId":{"type":"string"},"institutionId":{"type":"string"},"institutionType":{"type":"string","enum":["GSP","PA","PG","PSP","PT","SCP"]},"origin":{"type":"string","enum":["ADE","INFOCAMERE","IPA","MOCK","SELC","UNKNOWN"]},"originId":{"type":"string"},"pricingPlan":{"type":"string"},"subunitCode":{"type":"string"},"subunitType":{"type":"string"},"taxCode":{"type":"string"},"zipCode":{"type":"string"}}},"InstitutionFromIpaPost":{"title":"InstitutionFromIpaPost","required":["taxCode"],"type":"object","properties":{"subunitCode":{"type":"string"},"subunitType":{"type":"string","enum":["AOO","EC","UO"]},"taxCode":{"type":"string"}}},"InstitutionGeographicTaxonomies":{"title":"InstitutionGeographicTaxonomies","type":"object","properties":{"code":{"type":"string"},"desc":{"type":"string"}}},"InstitutionListResponse":{"title":"InstitutionListResponse","type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/InstitutionManagementResponse"}}}},"InstitutionManagementResponse":{"title":"InstitutionManagementResponse","type":"object","properties":{"address":{"type":"string"},"aooParentCode":{"type":"string"},"attributes":{"type":"array","items":{"$ref":"#/components/schemas/AttributesResponse"}},"businessRegisterPlace":{"type":"string"},"createdAt":{"type":"string","format":"date-time"},"dataProtectionOfficer":{"$ref":"#/components/schemas/DataProtectionOfficerResponse"},"description":{"type":"string"},"digitalAddress":{"type":"string"},"externalId":{"type":"string"},"geographicTaxonomies":{"type":"array","items":{"$ref":"#/components/schemas/GeoTaxonomies"}},"id":{"type":"string"},"imported":{"type":"boolean"},"institutionType":{"type":"string","enum":["GSP","PA","PG","PSP","PT","SCP"]},"origin":{"type":"string"},"originId":{"type":"string"},"paymentServiceProvider":{"$ref":"#/components/schemas/PaymentServiceProviderResponse"},"products":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/ProductsManagement"}},"rea":{"type":"string"},"shareCapital":{"type":"string"},"subunitCode":{"type":"string"},"subunitType":{"type":"string"},"supportEmail":{"type":"string"},"supportPhone":{"type":"string"},"taxCode":{"type":"string"},"updatedAt":{"type":"string","format":"date-time"},"zipCode":{"type":"string"}}},"InstitutionManagerResponse":{"title":"InstitutionManagerResponse","type":"object","properties":{"billing":{"$ref":"#/components/schemas/BillingResponse"},"createdAt":{"type":"string","format":"date-time"},"from":{"type":"string"},"id":{"type":"string"},"institutionUpdate":{"$ref":"#/components/schemas/InstitutionUpdateResponse"},"pricingPlan":{"type":"string"},"product":{"$ref":"#/components/schemas/ProductInfo"},"role":{"type":"string"},"state":{"type":"string","enum":["ACTIVE","DELETED","PENDING","REJECTED","SUSPENDED","TOBEVALIDATED"]},"to":{"type":"string"},"updatedAt":{"type":"string","format":"date-time"}}},"InstitutionPnPgResponse":{"title":"InstitutionPnPgResponse","type":"object","properties":{"id":{"type":"string"}}},"InstitutionProduct":{"title":"InstitutionProduct","type":"object","properties":{"id":{"type":"string"},"state":{"type":"string","enum":["ACTIVE","DELETED","PENDING","REJECTED","SUSPENDED","TOBEVALIDATED"]}}},"InstitutionPut":{"title":"InstitutionPut","type":"object","properties":{"description":{"type":"string"},"digitalAddress":{"type":"string"},"geographicTaxonomyCodes":{"type":"array","items":{"type":"string"}}}},"InstitutionRequest":{"title":"InstitutionRequest","type":"object","properties":{"address":{"type":"string"},"attributes":{"type":"array","items":{"$ref":"#/components/schemas/AttributesRequest"}},"billing":{"$ref":"#/components/schemas/BillingRequest"},"businessRegisterPlace":{"type":"string"},"createdAt":{"type":"string","format":"date-time"},"dataProtectionOfficer":{"$ref":"#/components/schemas/DataProtectionOfficerRequest"},"description":{"type":"string"},"digitalAddress":{"type":"string"},"externalId":{"type":"string"},"geographicTaxonomies":{"type":"array","items":{"$ref":"#/components/schemas/GeoTaxonomies"}},"id":{"type":"string"},"imported":{"type":"boolean"},"institutionType":{"type":"string","enum":["GSP","PA","PG","PSP","PT","SCP"]},"onboarding":{"type":"array","items":{"$ref":"#/components/schemas/OnboardingRequest"}},"origin":{"type":"string"},"originId":{"type":"string"},"paymentServiceProvider":{"$ref":"#/components/schemas/PaymentServiceProviderRequest"},"rea":{"type":"string"},"shareCapital":{"type":"string"},"supportEmail":{"type":"string"},"supportPhone":{"type":"string"},"taxCode":{"type":"string"},"updatedAt":{"type":"string","format":"date-time"},"zipCode":{"type":"string"}}},"InstitutionResponse":{"title":"InstitutionResponse","type":"object","properties":{"address":{"type":"string"},"aooParentCode":{"type":"string"},"attributes":{"type":"array","items":{"$ref":"#/components/schemas/AttributesResponse"}},"businessRegisterPlace":{"type":"string"},"dataProtectionOfficer":{"$ref":"#/components/schemas/DataProtectionOfficerResponse"},"description":{"type":"string"},"digitalAddress":{"type":"string"},"externalId":{"type":"string"},"geographicTaxonomies":{"type":"array","items":{"$ref":"#/components/schemas/GeoTaxonomies"}},"id":{"type":"string"},"imported":{"type":"boolean"},"institutionType":{"type":"string","enum":["GSP","PA","PG","PSP","PT","SCP"]},"origin":{"type":"string"},"originId":{"type":"string"},"paymentServiceProvider":{"$ref":"#/components/schemas/PaymentServiceProviderResponse"},"rea":{"type":"string"},"shareCapital":{"type":"string"},"subunitCode":{"type":"string"},"subunitType":{"type":"string"},"supportEmail":{"type":"string"},"supportPhone":{"type":"string"},"taxCode":{"type":"string"},"zipCode":{"type":"string"}}},"InstitutionToOnboard":{"title":"InstitutionToOnboard","type":"object","properties":{"cfImpresa":{"type":"string"},"denominazione":{"type":"string"}}},"InstitutionUpdate":{"title":"InstitutionUpdate","type":"object","properties":{"address":{"type":"string"},"businessRegisterPlace":{"type":"string"},"dataProtectionOfficer":{"$ref":"#/components/schemas/DataProtectionOfficer"},"description":{"type":"string"},"digitalAddress":{"type":"string"},"geographicTaxonomies":{"type":"array","items":{"$ref":"#/components/schemas/InstitutionGeographicTaxonomies"}},"imported":{"type":"boolean"},"institutionType":{"type":"string","enum":["GSP","PA","PG","PSP","PT","SCP"]},"paymentServiceProvider":{"$ref":"#/components/schemas/PaymentServiceProvider"},"rea":{"type":"string"},"shareCapital":{"type":"string"},"supportEmail":{"type":"string"},"supportPhone":{"type":"string"},"taxCode":{"type":"string"},"zipCode":{"type":"string"}}},"InstitutionUpdateRequest":{"title":"InstitutionUpdateRequest","required":["institutionType"],"type":"object","properties":{"address":{"type":"string"},"businessRegisterPlace":{"type":"string"},"dataProtectionOfficer":{"$ref":"#/components/schemas/DataProtectionOfficerRequest"},"description":{"type":"string"},"digitalAddress":{"type":"string"},"geographicTaxonomyCodes":{"type":"array","items":{"type":"string"}},"imported":{"type":"boolean"},"institutionType":{"type":"string","enum":["GSP","PA","PG","PSP","PT","SCP"]},"paymentServiceProvider":{"$ref":"#/components/schemas/PaymentServiceProviderRequest"},"rea":{"type":"string"},"shareCapital":{"type":"string"},"supportEmail":{"type":"string"},"supportPhone":{"type":"string"},"taxCode":{"type":"string"},"zipCode":{"type":"string"}}},"InstitutionUpdateResponse":{"title":"InstitutionUpdateResponse","type":"object","properties":{"address":{"type":"string"},"aooParentCode":{"type":"string"},"businessRegisterPlace":{"type":"string"},"dataProtectionOfficer":{"$ref":"#/components/schemas/DataProtectionOfficerResponse"},"description":{"type":"string"},"digitalAddress":{"type":"string"},"geographicTaxonomyCodes":{"type":"array","items":{"type":"string"}},"imported":{"type":"boolean"},"institutionType":{"type":"string","enum":["GSP","PA","PG","PSP","PT","SCP"]},"paymentServiceProvider":{"$ref":"#/components/schemas/PaymentServiceProviderResponse"},"rea":{"type":"string"},"shareCapital":{"type":"string"},"subunitCode":{"type":"string"},"subunitType":{"type":"string"},"supportEmail":{"type":"string"},"supportPhone":{"type":"string"},"taxCode":{"type":"string"},"zipCode":{"type":"string"}}},"InstitutionsResponse":{"title":"InstitutionsResponse","type":"object","properties":{"institutions":{"type":"array","items":{"$ref":"#/components/schemas/InstitutionResponse"}}}},"LegalsResponse":{"title":"LegalsResponse","type":"object","properties":{"env":{"type":"string","enum":["COLL","DEV","PROD","ROOT"]},"partyId":{"type":"string"},"relationshipId":{"type":"string"},"role":{"type":"string","enum":["DELEGATE","MANAGER","OPERATOR","SUB_DELEGATE"]}}},"MigrationInstitution":{"title":"MigrationInstitution","required":["institutionType","origin"],"type":"object","properties":{"address":{"type":"string"},"attributes":{"type":"array","items":{"$ref":"#/components/schemas/Attributes"}},"billing":{"$ref":"#/components/schemas/Billing"},"businessRegisterPlace":{"type":"string"},"createdAt":{"type":"string","format":"date-time"},"dataProtectionOfficer":{"$ref":"#/components/schemas/DataProtectionOfficer"},"description":{"type":"string"},"digitalAddress":{"type":"string"},"externalId":{"type":"string"},"geographicTaxonomies":{"type":"array","items":{"$ref":"#/components/schemas/InstitutionGeographicTaxonomies"}},"id":{"type":"string"},"imported":{"type":"boolean"},"institutionType":{"type":"string","enum":["GSP","PA","PG","PSP","PT","SCP"]},"onboarding":{"type":"array","items":{"$ref":"#/components/schemas/Onboarding"}},"origin":{"type":"string"},"originId":{"type":"string"},"paymentServiceProvider":{"$ref":"#/components/schemas/PaymentServiceProvider"},"rea":{"type":"string"},"shareCapital":{"type":"string"},"supportEmail":{"type":"string"},"supportPhone":{"type":"string"},"taxCode":{"type":"string"},"updatedAt":{"type":"string","format":"date-time"},"zipCode":{"type":"string"}}},"MigrationOnboardedUser":{"title":"MigrationOnboardedUser","type":"object","properties":{"bindings":{"type":"array","items":{"$ref":"#/components/schemas/UserBinding"}},"createdAt":{"type":"string","format":"date-time"},"id":{"type":"string"}}},"MigrationToken":{"title":"MigrationToken","required":["status","type"],"type":"object","properties":{"checksum":{"type":"string"},"closedAt":{"type":"string","format":"date-time"},"contractSigned":{"type":"string"},"contractTemplate":{"type":"string"},"contractVersion":{"type":"string"},"createdAt":{"type":"string","format":"date-time"},"expiringDate":{"type":"string","format":"date-time"},"id":{"type":"string"},"institutionId":{"type":"string"},"institutionUpdate":{"$ref":"#/components/schemas/InstitutionUpdate"},"productId":{"type":"string"},"status":{"type":"string","enum":["ACTIVE","DELETED","PENDING","REJECTED","SUSPENDED","TOBEVALIDATED"]},"type":{"type":"string","enum":["INSTITUTION","LEGALS"]},"updatedAt":{"type":"string","format":"date-time"},"users":{"type":"array","items":{"$ref":"#/components/schemas/TokenUser"}}}},"OnboardedInstitutionResponse":{"title":"OnboardedInstitutionResponse","type":"object","properties":{"address":{"type":"string"},"aooParentCode":{"type":"string"},"attributes":{"type":"array","items":{"$ref":"#/components/schemas/AttributesResponse"}},"billing":{"$ref":"#/components/schemas/Billing"},"businessData":{"$ref":"#/components/schemas/BusinessData"},"dataProtectionOfficer":{"$ref":"#/components/schemas/DataProtectionOfficerResponse"},"description":{"type":"string"},"digitalAddress":{"type":"string"},"externalId":{"type":"string"},"geographicTaxonomies":{"type":"array","items":{"$ref":"#/components/schemas/GeoTaxonomies"}},"id":{"type":"string"},"institutionType":{"type":"string","enum":["GSP","PA","PG","PSP","PT","SCP"]},"origin":{"type":"string"},"originId":{"type":"string"},"paymentServiceProvider":{"$ref":"#/components/schemas/PaymentServiceProviderResponse"},"pricingPlan":{"type":"string"},"productInfo":{"$ref":"#/components/schemas/ProductInfo"},"role":{"type":"string","enum":["DELEGATE","MANAGER","OPERATOR","SUB_DELEGATE"]},"state":{"type":"string"},"subunitCode":{"type":"string"},"subunitType":{"type":"string"},"supportContact":{"$ref":"#/components/schemas/SupportContact"},"taxCode":{"type":"string"},"zipCode":{"type":"string"}}},"OnboardedProduct":{"title":"OnboardedProduct","type":"object","properties":{"contract":{"type":"string"},"createdAt":{"type":"string","format":"date-time"},"env":{"type":"string","enum":["COLL","DEV","PROD","ROOT"]},"productId":{"type":"string"},"productRole":{"type":"string"},"relationshipId":{"type":"string"},"role":{"type":"string","enum":["DELEGATE","MANAGER","OPERATOR","SUB_DELEGATE"]},"status":{"type":"string","enum":["ACTIVE","DELETED","PENDING","REJECTED","SUSPENDED","TOBEVALIDATED"]},"tokenId":{"type":"string"},"updatedAt":{"type":"string","format":"date-time"}}},"OnboardedProducts":{"title":"OnboardedProducts","type":"object","properties":{"products":{"type":"array","items":{"$ref":"#/components/schemas/InstitutionProduct"}}}},"OnboardedUser":{"title":"OnboardedUser","type":"object","properties":{"bindings":{"type":"array","items":{"$ref":"#/components/schemas/UserBinding"}},"createdAt":{"type":"string","format":"date-time"},"id":{"type":"string"}}},"Onboarding":{"title":"Onboarding","type":"object","properties":{"billing":{"$ref":"#/components/schemas/Billing"},"closedAt":{"type":"string","format":"date-time"},"contract":{"type":"string"},"createdAt":{"type":"string","format":"date-time"},"pricingPlan":{"type":"string"},"productId":{"type":"string"},"status":{"type":"string","enum":["ACTIVE","DELETED","PENDING","REJECTED","SUSPENDED","TOBEVALIDATED"]},"tokenId":{"type":"string"},"updatedAt":{"type":"string","format":"date-time"}}},"OnboardingImportContract":{"title":"OnboardingImportContract","type":"object","properties":{"contractType":{"type":"string"},"createdAt":{"type":"string","format":"date-time"},"fileName":{"type":"string"},"filePath":{"type":"string"}}},"OnboardingInfoResponse":{"title":"OnboardingInfoResponse","type":"object","properties":{"institutions":{"type":"array","items":{"$ref":"#/components/schemas/OnboardedInstitutionResponse"}},"userId":{"type":"string"}}},"OnboardingInstitutionLegalsRequest":{"title":"OnboardingInstitutionLegalsRequest","required":["contract"],"type":"object","properties":{"contract":{"$ref":"#/components/schemas/ContractRequest"},"institutionExternalId":{"type":"string"},"institutionId":{"type":"string"},"productId":{"type":"string"},"productName":{"type":"string"},"signContract":{"type":"boolean"},"users":{"type":"array","items":{"$ref":"#/components/schemas/Person"}}}},"OnboardingInstitutionOperatorsRequest":{"title":"OnboardingInstitutionOperatorsRequest","type":"object","properties":{"institutionId":{"type":"string"},"productId":{"type":"string"},"users":{"type":"array","items":{"$ref":"#/components/schemas/Person"}}}},"OnboardingInstitutionRequest":{"title":"OnboardingInstitutionRequest","required":["institutionUpdate"],"type":"object","properties":{"billing":{"$ref":"#/components/schemas/BillingRequest"},"contract":{"$ref":"#/components/schemas/ContractRequest"},"contractImported":{"$ref":"#/components/schemas/OnboardingImportContract"},"institutionExternalId":{"type":"string"},"institutionUpdate":{"$ref":"#/components/schemas/InstitutionUpdateRequest"},"pricingPlan":{"type":"string"},"productId":{"type":"string"},"productName":{"type":"string"},"signContract":{"type":"boolean"},"users":{"type":"array","items":{"$ref":"#/components/schemas/Person"}}}},"OnboardingRequest":{"title":"OnboardingRequest","type":"object","properties":{"billingRequest":{"$ref":"#/components/schemas/Billing"},"contract":{"$ref":"#/components/schemas/Contract"},"contractCreatedAt":{"type":"string","format":"date-time"},"contractFilePath":{"type":"string"},"institutionExternalId":{"type":"string"},"institutionUpdate":{"$ref":"#/components/schemas/InstitutionUpdate"},"pricingPlan":{"type":"string"},"productId":{"type":"string"},"productName":{"type":"string"},"signContract":{"type":"boolean"},"tokenType":{"type":"string","enum":["INSTITUTION","LEGALS"]},"users":{"type":"array","items":{"$ref":"#/components/schemas/UserToOnboard"}}}},"OnboardingResponse":{"title":"OnboardingResponse","type":"object","properties":{"billing":{"$ref":"#/components/schemas/BillingResponse"},"closedAt":{"type":"string","format":"date-time"},"contract":{"type":"string"},"createdAt":{"type":"string","format":"date-time"},"pricingPlan":{"type":"string"},"productId":{"type":"string"},"status":{"$ref":"#/components/schemas/RelationshipResponse"},"tokenId":{"type":"string"},"updatedAt":{"type":"string","format":"date-time"}}},"OnboardingsResponse":{"title":"OnboardingsResponse","type":"object","properties":{"onboardings":{"type":"array","items":{"$ref":"#/components/schemas/OnboardingResponse"}}}},"PaAttributes":{"title":"PaAttributes","type":"object","properties":{"aooParentCode":{"type":"string"}}},"PaymentServiceProvider":{"title":"PaymentServiceProvider","type":"object","properties":{"abiCode":{"type":"string"},"businessRegisterNumber":{"type":"string"},"legalRegisterName":{"type":"string"},"legalRegisterNumber":{"type":"string"},"vatNumberGroup":{"type":"boolean"}}},"PaymentServiceProviderRequest":{"title":"PaymentServiceProviderRequest","type":"object","properties":{"abiCode":{"type":"string"},"businessRegisterNumber":{"type":"string"},"legalRegisterName":{"type":"string"},"legalRegisterNumber":{"type":"string"},"vatNumberGroup":{"type":"boolean"}}},"PaymentServiceProviderResponse":{"title":"PaymentServiceProviderResponse","type":"object","properties":{"abiCode":{"type":"string"},"businessRegisterNumber":{"type":"string"},"legalRegisterName":{"type":"string"},"legalRegisterNumber":{"type":"string"},"vatNumberGroup":{"type":"boolean"}}},"Person":{"title":"Person","type":"object","properties":{"email":{"type":"string"},"env":{"type":"string","enum":["COLL","DEV","PROD","ROOT"]},"id":{"type":"string"},"name":{"type":"string"},"productRole":{"type":"string"},"role":{"type":"string","enum":["DELEGATE","MANAGER","OPERATOR","SUB_DELEGATE"]},"surname":{"type":"string"},"taxCode":{"type":"string"}}},"PersonId":{"title":"PersonId","type":"object","properties":{"id":{"type":"string"}}},"Problem":{"title":"Problem","type":"object","properties":{"errors":{"type":"array","items":{"$ref":"#/components/schemas/ProblemError"}},"status":{"type":"integer","format":"int32"}}},"ProblemError":{"title":"ProblemError","type":"object","properties":{"code":{"type":"string"},"detail":{"type":"string"}}},"ProductInfo":{"title":"ProductInfo","type":"object","properties":{"createdAt":{"type":"string","format":"date-time"},"id":{"type":"string"},"role":{"type":"string"}}},"ProductsManagement":{"title":"ProductsManagement","type":"object","properties":{"billing":{"$ref":"#/components/schemas/BillingResponse"},"pricingPlan":{"type":"string"},"product":{"type":"string"}}},"RelationshipResponse":{"title":"RelationshipResponse","type":"object","properties":{"billingResponse":{"$ref":"#/components/schemas/BillingResponse"},"createdAt":{"type":"string","format":"date-time"},"from":{"type":"array","items":{"type":"string"}},"id":{"type":"string"},"institutionUpdate":{"$ref":"#/components/schemas/InstitutionUpdateResponse"},"pricingPlan":{"type":"string"},"product":{"type":"string"},"role":{"type":"string"},"state":{"type":"string","enum":["ACTIVE","DELETED","PENDING","REJECTED","SUSPENDED","TOBEVALIDATED"]},"to":{"type":"string"},"updatedAt":{"type":"string","format":"date-time"}}},"RelationshipResult":{"title":"RelationshipResult","type":"object","properties":{"billing":{"$ref":"#/components/schemas/BillingResponse"},"createdAt":{"type":"string","format":"date-time"},"from":{"type":"string"},"id":{"type":"string"},"institutionUpdate":{"$ref":"#/components/schemas/InstitutionUpdateResponse"},"pricingPlan":{"type":"string"},"product":{"$ref":"#/components/schemas/ProductInfo"},"role":{"type":"string","enum":["DELEGATE","MANAGER","OPERATOR","SUB_DELEGATE"]},"state":{"type":"string","enum":["ACTIVE","DELETED","PENDING","REJECTED","SUSPENDED","TOBEVALIDATED"]},"to":{"type":"string"},"tokenId":{"type":"string"},"updatedAt":{"type":"string","format":"date-time"}}},"RelationshipsManagement":{"title":"RelationshipsManagement","type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/RelationshipResult"}}}},"SupportContact":{"title":"SupportContact","type":"object","properties":{"supportEmail":{"type":"string"},"supportPhone":{"type":"string"}}},"Token":{"title":"Token","type":"object","properties":{"checksum":{"type":"string"},"closedAt":{"type":"string","format":"date-time"},"contentType":{"type":"string"},"contractSigned":{"type":"string"},"contractTemplate":{"type":"string"},"contractVersion":{"type":"string"},"createdAt":{"type":"string","format":"date-time"},"expiringDate":{"type":"string","format":"date-time"},"id":{"type":"string"},"institutionId":{"type":"string"},"institutionUpdate":{"$ref":"#/components/schemas/InstitutionUpdate"},"productId":{"type":"string"},"status":{"type":"string","enum":["ACTIVE","DELETED","PENDING","REJECTED","SUSPENDED","TOBEVALIDATED"]},"type":{"type":"string","enum":["INSTITUTION","LEGALS"]},"updatedAt":{"type":"string","format":"date-time"},"users":{"type":"array","items":{"$ref":"#/components/schemas/TokenUser"}}}},"TokenResource":{"title":"TokenResource","type":"object","properties":{"checksum":{"type":"string"},"closedAt":{"type":"string","format":"date-time"},"contractSigned":{"type":"string"},"contractTemplate":{"type":"string"},"contractVersion":{"type":"string"},"createdAt":{"type":"string","format":"date-time"},"expiringDate":{"type":"string","format":"date-time"},"id":{"type":"string"},"institutionId":{"type":"string"},"institutionUpdate":{"$ref":"#/components/schemas/InstitutionUpdate"},"productId":{"type":"string"},"status":{"type":"string","enum":["ACTIVE","DELETED","PENDING","REJECTED","SUSPENDED","TOBEVALIDATED"]},"type":{"type":"string","enum":["INSTITUTION","LEGALS"]},"updatedAt":{"type":"string","format":"date-time"},"users":{"type":"array","items":{"$ref":"#/components/schemas/TokenUser"}}}},"TokenResponse":{"title":"TokenResponse","type":"object","properties":{"checksum":{"type":"string"},"id":{"type":"string"},"legals":{"type":"array","items":{"$ref":"#/components/schemas/LegalsResponse"}}}},"TokenUser":{"title":"TokenUser","type":"object","properties":{"role":{"type":"string","enum":["DELEGATE","MANAGER","OPERATOR","SUB_DELEGATE"]},"userId":{"type":"string"}}},"UserBinding":{"title":"UserBinding","type":"object","properties":{"institutionId":{"type":"string"},"products":{"type":"array","items":{"$ref":"#/components/schemas/OnboardedProduct"}}}},"UserToOnboard":{"title":"UserToOnboard","type":"object","properties":{"email":{"type":"string"},"env":{"type":"string","enum":["COLL","DEV","PROD","ROOT"]},"id":{"type":"string"},"name":{"type":"string"},"productRole":{"type":"string"},"role":{"type":"string","enum":["DELEGATE","MANAGER","OPERATOR","SUB_DELEGATE"]},"surname":{"type":"string"},"taxCode":{"type":"string"}}}},"securitySchemes":{"bearerAuth":{"type":"http","description":"A bearer token in the format of a JWS and conformed to the specifications included in [RFC8725](https://tools.ietf.org/html/RFC8725)","scheme":"bearer","bearerFormat":"JWT"}}}} \ No newline at end of file diff --git a/onboarding-ms/src/main/resources/application.properties b/onboarding-ms/src/main/resources/application.properties deleted file mode 100644 index 91e0f5ead..000000000 --- a/onboarding-ms/src/main/resources/application.properties +++ /dev/null @@ -1,28 +0,0 @@ -quarkus.smallrye-jwt.blocking-authentication=true - -mp.jwt.verify.publickey=${JWT_TOKEN_PUBLIC_KEY} -mp.jwt.verify.issuer=SPID - -smallrye.jwt.claims.groups=USER -smallrye.jwt.path.sub=name - -quarkus.log.level=INFO - -quarkus.mongodb.connection-string = ${MONGODB_CONNECTION_URI} -quarkus.mongodb.database = selcOnboarding - -#quarkus.native.resources.includes=publicKey.pem - -## Rest Client -quarkus.rest-client.logging.scope=request-response -#quarkus.rest-client.logging.body-limit=50 - -quarkus.log.category."org.jboss.resteasy.reactive.client.logging".level=DEBUG -quarkus.openapi-generator.codegen.spec.user_registry_json.mutiny=true -quarkus.openapi-generator.codegen.spec.user_registry_json.additional-model-type-annotations=@lombok.Builder; @lombok.NoArgsConstructor; @lombok.AllArgsConstructor -quarkus.openapi-generator.user_registry_json.auth.api_key.api-key = ${USER_REGISTRY_API_KEY} -quarkus.rest-client."org.openapi.quarkus.user_registry_json.api.UserApi".url=${USER_REGISTRY_URL} - -## Jacoco - -quarkus.jacoco.includes=it/pagopa/selfcare/controller/*,it/pagopa/selfcare/service/**,it/pagopa/selfcare/repository/** \ No newline at end of file diff --git a/onboarding-ms/src/test/java/it/pagopa/selfcare/OnboardingControllerIT.java b/onboarding-ms/src/test/java/it/pagopa/selfcare/OnboardingControllerIT.java deleted file mode 100644 index bfa149587..000000000 --- a/onboarding-ms/src/test/java/it/pagopa/selfcare/OnboardingControllerIT.java +++ /dev/null @@ -1,9 +0,0 @@ -package it.pagopa.selfcare; - -import io.quarkus.test.junit.QuarkusIntegrationTest; -import it.pagopa.selfcare.controller.OnboardingControllerTest; - -@QuarkusIntegrationTest -public class OnboardingControllerIT extends OnboardingControllerTest { - // Execute the same tests but in packaged mode. -} diff --git a/onboarding-ms/src/test/java/it/pagopa/selfcare/controller/OnboardingControllerTest.java b/onboarding-ms/src/test/java/it/pagopa/selfcare/controller/OnboardingControllerTest.java deleted file mode 100644 index ba7a90b50..000000000 --- a/onboarding-ms/src/test/java/it/pagopa/selfcare/controller/OnboardingControllerTest.java +++ /dev/null @@ -1,170 +0,0 @@ -package it.pagopa.selfcare.controller; - -import io.quarkus.test.InjectMock; -import io.quarkus.test.common.QuarkusTestResource; -import io.quarkus.test.common.http.TestHTTPEndpoint; -import io.quarkus.test.junit.QuarkusTest; -import io.quarkus.test.mongodb.MongoTestResource; -import io.quarkus.test.security.TestSecurity; -import io.restassured.http.ContentType; -import io.smallrye.mutiny.Uni; -import it.pagopa.selfcare.controller.request.*; -import it.pagopa.selfcare.controller.response.OnboardingResponse; -import it.pagopa.selfcare.service.OnboardingService; -import it.pagopa.selfcare.util.InstitutionType; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.ValueSource; -import org.mockito.Mockito; - -import java.util.List; - -import static io.restassured.RestAssured.given; -import static org.mockito.ArgumentMatchers.any; - -@QuarkusTest -@TestHTTPEndpoint(OnboardingController.class) -@QuarkusTestResource(MongoTestResource.class) -@TestSecurity(authorizationEnabled = false) -public class OnboardingControllerTest { - - final static OnboardingPspRequest onboardingPspValid; - final static OnboardingPaRequest onboardingPaValid; - final static OnboardingPgRequest onboardingPgValid; - final static OnboardingDefaultRequest onboardingBaseValid; - - final static InstitutionBaseRequest institution; - final static InstitutionPspRequest institutionPsp; - - @InjectMock - OnboardingService onboardingService; - - static { - onboardingBaseValid = new OnboardingDefaultRequest(); - onboardingBaseValid.setProductId("productId"); - - UserRequest userDTO = new UserRequest(); - userDTO.setId("is"); - onboardingBaseValid.setUsers(List.of(userDTO)); - - institution = new InstitutionBaseRequest(); - institution.setInstitutionType(InstitutionType.PT); - institution.setTaxCode("taxCode"); - onboardingBaseValid.setInstitution(institution); - - /* PA */ - onboardingPaValid = new OnboardingPaRequest(); - onboardingPaValid.setProductId("productId"); - - onboardingPaValid.setUsers(List.of(userDTO)); - onboardingPaValid.setInstitution(institution); - BillingRequest billingRequest = new BillingRequest(); - billingRequest.setRecipientCode("code"); - billingRequest.setVatNumber("vat"); - onboardingPaValid.setBilling(billingRequest); - - /* PSP */ - onboardingPspValid = new OnboardingPspRequest(); - onboardingPspValid.setProductId("productId"); - onboardingPspValid.setUsers(List.of(userDTO)); - - institutionPsp = new InstitutionPspRequest(); - institutionPsp.setInstitutionType(InstitutionType.PT); - institutionPsp.setTaxCode("taxCode"); - institutionPsp.setPaymentServiceProvider(new PaymentServiceProviderRequest()); - onboardingPspValid.setInstitution(institutionPsp); - - /* PG */ - - onboardingPgValid = new OnboardingPgRequest(); - onboardingPgValid.setTaxCode("code"); - onboardingPgValid.setProductId("productId"); - onboardingPgValid.setDigitalAddress("email@pagopa.it"); - onboardingPgValid.setUsers(List.of(userDTO)); - } - - @Test - public void onboarding_shouldNotValidBody() { - - given() - .when() - .body(new OnboardingDefaultRequest()) - .contentType(ContentType.JSON) - .post() - .then() - .statusCode(400); - } - - @ParameterizedTest - @ValueSource(strings = {"/psp","/pa"}) - public void onboarding_shouldNotValidPspBody(String path) { - - given() - .when() - .body(onboardingBaseValid) - .contentType(ContentType.JSON) - .post(path) - .then() - .statusCode(400); - } - - @Test - public void onboarding() { - - Mockito.when(onboardingService.onboarding(any())) - .thenReturn(Uni.createFrom().item(new OnboardingResponse())); - - given() - .when() - .body(onboardingBaseValid) - .contentType(ContentType.JSON) - .post() - .then() - .statusCode(200); - } - - @Test - public void onboardingPa() { - - Mockito.when(onboardingService.onboardingPa(any())) - .thenReturn(Uni.createFrom().item(new OnboardingResponse())); - - given() - .when() - .body(onboardingPaValid) - .contentType(ContentType.JSON) - .post("/pa") - .then() - .statusCode(200); - } - - @Test - public void onboardingPsp() { - - Mockito.when(onboardingService.onboardingPsp(any())) - .thenReturn(Uni.createFrom().item(new OnboardingResponse())); - - given() - .when() - .body(onboardingPspValid) - .contentType(ContentType.JSON) - .post("/psp") - .then() - .statusCode(200); - } - - - - //@Test - public void onboardingPg() { - - given() - .when() - .body(onboardingPgValid) - .contentType(ContentType.JSON) - .post("/pg") - .then() - .statusCode(200); - } - -} \ No newline at end of file diff --git a/onboarding-ms/src/test/java/it/pagopa/selfcare/repository/OnboardingRepositoryTest.java b/onboarding-ms/src/test/java/it/pagopa/selfcare/repository/OnboardingRepositoryTest.java deleted file mode 100644 index 4ce7e5864..000000000 --- a/onboarding-ms/src/test/java/it/pagopa/selfcare/repository/OnboardingRepositoryTest.java +++ /dev/null @@ -1,97 +0,0 @@ -package it.pagopa.selfcare.repository; - -import com.mongodb.client.result.InsertOneResult; -import io.quarkus.mongodb.reactive.ReactiveMongoClient; -import io.quarkus.mongodb.reactive.ReactiveMongoCollection; -import io.quarkus.mongodb.reactive.ReactiveMongoDatabase; -import io.quarkus.test.InjectMock; -import io.quarkus.test.Mock; -import io.quarkus.test.junit.QuarkusTest; -import io.smallrye.mutiny.Uni; -import io.smallrye.mutiny.helpers.test.UniAssertSubscriber; -import it.pagopa.selfcare.entity.Onboarding; -import jakarta.inject.Inject; -import org.bson.BsonObjectId; -import org.bson.BsonValue; -import org.bson.conversions.Bson; -import org.bson.types.ObjectId; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.mockito.Mockito; - - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.mockito.ArgumentMatchers.any; - -@QuarkusTest -public class OnboardingRepositoryTest { - - - @Inject - OnboardingRepository repository; - - @InjectMock - ReactiveMongoClient mongoClient; - - - ReactiveMongoCollection reactiveMongoCollection; - - Onboarding onboarding; - - @BeforeEach - public void before() { - ReactiveMongoDatabase reactiveMongoDatabase = Mockito.mock(ReactiveMongoDatabase.class); - reactiveMongoCollection = Mockito.mock(ReactiveMongoCollection.class); - Mockito.when(reactiveMongoDatabase.getCollection(any(), any())).thenReturn(reactiveMongoCollection); - - Mockito.when(mongoClient.getDatabase(any())).thenReturn(reactiveMongoDatabase); - - - onboarding = new Onboarding(); - } - - - @Test - public void shouldUpdteIfContractHasObjectId() { - Onboarding onboarding = new Onboarding(); - onboarding.setId(ObjectId.get()); - onboarding.setProductId("setProductId"); - - Mockito.when(reactiveMongoCollection.findOneAndReplace(any(Bson.class), any())) - .thenAnswer(I -> Uni.createFrom().item((Onboarding) I.getArguments()[1])); - - UniAssertSubscriber subscriber = repository.persistOrUpdate(onboarding) - .subscribe().withSubscriber(UniAssertSubscriber.create()).awaitItem(); - - Onboarding result = subscriber.assertCompleted().getItem(); - assertNotNull(result); - assertEquals(result.getProductId(), onboarding.getProductId()); - } - - @Test - public void shouldPersitIfContractNotHasObjectId() { - Onboarding newContract = new Onboarding(); - ObjectId id = ObjectId.get(); - - Mockito.when(reactiveMongoCollection.insertOne(any(Onboarding.class))) - .thenAnswer(I -> Uni.createFrom().item(new InsertOneResult() { - @Override - public boolean wasAcknowledged() { - return false; - } - - @Override - public BsonValue getInsertedId() { - return new BsonObjectId(id); - } - })); - - UniAssertSubscriber subscriber = repository.persistOrUpdate(newContract) - .subscribe().withSubscriber(UniAssertSubscriber.create()).awaitItem(); - - Onboarding result = subscriber.assertCompleted().getItem(); - assertNotNull(result); - assertEquals(result.getId(), id); - } -} diff --git a/onboarding-ms/src/test/java/it/pagopa/selfcare/service/OnboardingServiceDefaultTest.java b/onboarding-ms/src/test/java/it/pagopa/selfcare/service/OnboardingServiceDefaultTest.java deleted file mode 100644 index ca43c3bce..000000000 --- a/onboarding-ms/src/test/java/it/pagopa/selfcare/service/OnboardingServiceDefaultTest.java +++ /dev/null @@ -1,216 +0,0 @@ -package it.pagopa.selfcare.service; - -import io.quarkus.test.InjectMock; -import io.quarkus.test.junit.QuarkusTest; -import io.smallrye.mutiny.Uni; -import io.smallrye.mutiny.helpers.test.UniAssertSubscriber; -import it.pagopa.selfcare.commons.base.security.PartyRole; -import it.pagopa.selfcare.controller.request.OnboardingDefaultRequest; -import it.pagopa.selfcare.controller.request.OnboardingPaRequest; -import it.pagopa.selfcare.controller.request.OnboardingPspRequest; -import it.pagopa.selfcare.controller.request.UserRequest; -import it.pagopa.selfcare.controller.response.OnboardingResponse; -import it.pagopa.selfcare.repository.OnboardingRepository; -import jakarta.inject.Inject; -import jakarta.ws.rs.WebApplicationException; -import jakarta.ws.rs.core.Response; -import org.eclipse.microprofile.rest.client.inject.RestClient; -import org.junit.jupiter.api.Test; -import org.mockito.Mockito; -import org.openapi.quarkus.user_registry_json.api.UserApi; -import org.openapi.quarkus.user_registry_json.model.CertifiableFieldResourceOfstring; -import org.openapi.quarkus.user_registry_json.model.UserId; -import org.openapi.quarkus.user_registry_json.model.UserResource; - -import java.util.List; -import java.util.UUID; - -import static io.smallrye.common.constraint.Assert.assertNotNull; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.*; - - -@QuarkusTest -public class OnboardingServiceDefaultTest { - - @Inject - OnboardingServiceDefault onboardingService; - - @InjectMock - OnboardingRepository onboardingRepository; - - @InjectMock - @RestClient - UserApi userRegistryApi; - - final static UserRequest manager = UserRequest.builder() - .id(UUID.randomUUID().toString()) - .name("name") - .surname("surname") - .taxCode("taxCode") - .role(PartyRole.MANAGER) - .build(); - - final static UserResource managerResource; - - static { - managerResource = new UserResource(); - managerResource.setId(UUID.fromString(manager.getId())); - managerResource.setName(new CertifiableFieldResourceOfstring() - .value(manager.getName()) - .certification(CertifiableFieldResourceOfstring.CertificationEnum.NONE)); - managerResource.setFamilyName(new CertifiableFieldResourceOfstring() - .value(manager.getSurname()) - .certification(CertifiableFieldResourceOfstring.CertificationEnum.NONE)); - } - - @Test - void onboarding_shouldThrowExceptionIfRoleNotValid() { - OnboardingDefaultRequest onboardingDefaultRequest = new OnboardingDefaultRequest(); - onboardingDefaultRequest.setUsers(List.of(UserRequest.builder() - .taxCode("taxCode") - .role(PartyRole.OPERATOR) - .build())); - - onboardingService.onboarding(onboardingDefaultRequest) - .subscribe().withSubscriber(UniAssertSubscriber.create()).assertFailed(); - } - - void mockSimpleSearchPOSTAndPersist(){ - - Mockito.when(userRegistryApi.searchUsingPOST(any(),any())) - .thenReturn(Uni.createFrom().item(managerResource)); - - Mockito.when(onboardingRepository.persistOrUpdate(any())) - .thenAnswer(arg -> Uni.createFrom().item(arg.getArguments()[0])); - } - @Test - void onboardingPa_whenUserFoundedAndWillNotUpdate() { - OnboardingPaRequest onboardingRequest = new OnboardingPaRequest(); - onboardingRequest.setUsers(List.of(manager)); - - mockSimpleSearchPOSTAndPersist(); - - UniAssertSubscriber subscriber = onboardingService.onboardingPa(onboardingRequest) - .subscribe().withSubscriber(UniAssertSubscriber.create()).awaitItem(); - - OnboardingResponse actual = subscriber.assertCompleted().getItem(); - assertNotNull(actual); - - verify(userRegistryApi, times(1)) - .searchUsingPOST(any(),any()); - verifyNoMoreInteractions(userRegistryApi); - } - - - @Test - void onboardingPsp_whenUserFoundedAndWillNotUpdate() { - OnboardingPspRequest onboardingRequest = new OnboardingPspRequest(); - onboardingRequest.setUsers(List.of(manager)); - - mockSimpleSearchPOSTAndPersist(); - - UniAssertSubscriber subscriber = onboardingService.onboardingPsp(onboardingRequest) - .subscribe().withSubscriber(UniAssertSubscriber.create()).awaitItem(); - - OnboardingResponse actual = subscriber.assertCompleted().getItem(); - assertNotNull(actual); - - verify(userRegistryApi, times(1)) - .searchUsingPOST(any(),any()); - verifyNoMoreInteractions(userRegistryApi); - } - - - @Test - void onboarding_whenUserFoundedAndWillNotUpdate() { - OnboardingDefaultRequest onboardingDefaultRequest = new OnboardingDefaultRequest(); - onboardingDefaultRequest.setUsers(List.of(manager)); - - mockSimpleSearchPOSTAndPersist(); - - UniAssertSubscriber subscriber = onboardingService.onboarding(onboardingDefaultRequest) - .subscribe().withSubscriber(UniAssertSubscriber.create()).awaitItem(); - - OnboardingResponse actual = subscriber.assertCompleted().getItem(); - assertNotNull(actual); - - verify(userRegistryApi, times(1)) - .searchUsingPOST(any(),any()); - verifyNoMoreInteractions(userRegistryApi); - } - - @Test - void onboarding_whenUserFoundedAndWillUpdate() { - UserRequest manager = UserRequest.builder() - .id(managerResource.getId().toString()) - .name("name") - .taxCode("taxCode") - .role(PartyRole.MANAGER) - .build(); - - OnboardingDefaultRequest onboardingDefaultRequest = new OnboardingDefaultRequest(); - onboardingDefaultRequest.setUsers(List.of(manager)); - - Mockito.when(userRegistryApi.updateUsingPATCH(any(),any())) - .thenReturn(Uni.createFrom().item(Response.noContent().build())); - - mockSimpleSearchPOSTAndPersist(); - - UniAssertSubscriber subscriber = onboardingService.onboarding(onboardingDefaultRequest) - .subscribe().withSubscriber(UniAssertSubscriber.create()).awaitItem(); - - OnboardingResponse actual = subscriber.assertCompleted().getItem(); - assertNotNull(actual); - - verify(userRegistryApi, times(1)) - .searchUsingPOST(any(),any()); - verify(userRegistryApi, times(1)) - .updateUsingPATCH(any(),any()); - verifyNoMoreInteractions(userRegistryApi); - } - - @Test - void onboarding_whenUserNotFoundedAndWillSave() { - OnboardingDefaultRequest onboardingDefaultRequest = new OnboardingDefaultRequest(); - onboardingDefaultRequest.setUsers(List.of(manager)); - - Mockito.when(userRegistryApi.searchUsingPOST(any(),any())) - .thenReturn(Uni.createFrom().failure(new WebApplicationException(404))); - - Mockito.when(userRegistryApi.saveUsingPATCH(any())) - .thenReturn(Uni.createFrom().item(UserId.builder().id(UUID.fromString(manager.getId())).build())); - - Mockito.when(onboardingRepository.persistOrUpdate(any())) - .thenAnswer(arg -> Uni.createFrom().item(arg.getArguments()[0])); - - UniAssertSubscriber subscriber = onboardingService.onboarding(onboardingDefaultRequest) - .subscribe().withSubscriber(UniAssertSubscriber.create()).awaitItem(); - - OnboardingResponse actual = subscriber.assertCompleted().getItem(); - assertNotNull(actual); - - verify(userRegistryApi, times(1)) - .searchUsingPOST(any(),any()); - verify(userRegistryApi, times(1)) - .saveUsingPATCH(any()); - verifyNoMoreInteractions(userRegistryApi); - } - - - @Test - void onboarding_shouldThrowExceptionIfUserRegistryFails() { - OnboardingDefaultRequest onboardingDefaultRequest = new OnboardingDefaultRequest(); - onboardingDefaultRequest.setUsers(List.of(manager)); - - Mockito.when(userRegistryApi.searchUsingPOST(any(),any())) - .thenReturn(Uni.createFrom().failure(new WebApplicationException())); - - onboardingService.onboarding(onboardingDefaultRequest) - .subscribe().withSubscriber(UniAssertSubscriber.create()).awaitFailure(); - - verify(userRegistryApi, times(1)) - .searchUsingPOST(any(),any()); - verifyNoMoreInteractions(userRegistryApi); - } -} diff --git a/onboarding-ms/src/test/resources/application.properties b/onboarding-ms/src/test/resources/application.properties deleted file mode 100644 index ead902600..000000000 --- a/onboarding-ms/src/test/resources/application.properties +++ /dev/null @@ -1,4 +0,0 @@ -mp.jwt.verify.publickey="" -mp.jwt.verify.issuer=SPID - -quarkus.openapi-generator.user_registry_json.auth.api_key.api-key = "example" diff --git a/pom.xml b/pom.xml index 651e8c740..c6d0a990f 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ 4.0.0 it.pagopa.selfcare - onboarding + onboarding-root 0.0.1 pom @@ -12,24 +12,11 @@ - onboarding-functions - onboarding-ms + apps + libs + test-coverage - - 2.4.6 - - - - - it.pagopa.selfcare - selc-commons-base - ${selc-commons.version} - - - - - selfcare-platform diff --git a/test-coverage/.gitignore b/test-coverage/.gitignore new file mode 100644 index 000000000..5ff6309b7 --- /dev/null +++ b/test-coverage/.gitignore @@ -0,0 +1,38 @@ +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### IntelliJ IDEA ### +.idea/modules.xml +.idea/jarRepositories.xml +.idea/compiler.xml +.idea/libraries/ +*.iws +*.iml +*.ipr + +### Eclipse ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ + +### Mac OS ### +.DS_Store \ No newline at end of file diff --git a/test-coverage/README.md b/test-coverage/README.md new file mode 100644 index 000000000..3a3070567 --- /dev/null +++ b/test-coverage/README.md @@ -0,0 +1,24 @@ +# Test Coverage + +It is a submodule designed to assess the test coverage of the entire project. It contains various configurations to evaluate the coverage of individual modules. Specifically, it leverages the Maven plugin, Jacoco, using the 'report-aggregate' goal to aggregate reports from the individual modules and provide them to Sonarqube for test coverage and code quality verification. It's essential for each module to have the same plugin or library that generates the jacoco.xml file, summarizing the test coverage for that specific module. + +## Usage + +To run coverage on a specific module, dedicated profiles have been configured. For example, to execute it on the `apps/onboarding-ms module`, you can use the following command: + +```shell script +mvn --projects :test-coverage --also-make verify -Ponboarding-ms,report +``` + +* **report** is used for generating reports. +* **onboarding-ms** is used to perform the scan on onboarding-ms module. + +Make sure you have the necessary configurations and dependencies in place for accurate test coverage analysis. + +## Sonarcloud + +To enable performing the scan on Sonarcloud you can add profile `coverage` and some other information: + +```shell script +mvn --projects :test-coverage --also-make verify -Ponboarding-ms,report,coverage -Dsonar.organization=xxx -Dsonar.projectKey=yyy -Dsonar.token=zzzz -Dsonar.pullrequest.key=123 +``` diff --git a/test-coverage/pom.xml b/test-coverage/pom.xml new file mode 100644 index 000000000..6d39eb116 --- /dev/null +++ b/test-coverage/pom.xml @@ -0,0 +1,160 @@ + + + 4.0.0 + + + it.pagopa.selfcare + onboarding-root + 0.0.1 + + test-coverage + pom + test-coverage + + + ${project.basedir}/target/site/jacoco-aggregate/jacoco.xml + **/exception/**, **/response/**, **/request/**, **/entity/**, **/common/**, **/utils/**, **/*Constant*, **/*Config.java, **/error/**, org/** + https://sonarcloud.io + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.1 + + + org.sonarsource.scanner.maven + sonar-maven-plugin + 3.10.0.2594 + + + org.jacoco + jacoco-maven-plugin + 0.8.11 + + + + + + + + + onboarding-ms + + false + + + + it.pagopa.selfcare + onboarding-ms + 1.0.0-SNAPSHOT + + + + + onboarding-functions + + false + + + + it.pagopa.selfcare + onboarding-functions + 1.0.0-SNAPSHOT + + + + + onboarding-sdk + + false + + + + it.pagopa.selfcare + onboarding-sdk-product + 0.1.3 + + + it.pagopa.selfcare + onboarding-sdk-common + 0.1.3 + + + it.pagopa.selfcare + onboarding-sdk-azure-storage + 0.1.3 + + + it.pagopa.selfcare + onboarding-sdk-crypto + 0.1.3 + + + + + + report + + + + org.jacoco + jacoco-maven-plugin + + + report + + report-aggregate + + verify + + + + + + + **/config/* + **/exception/** + **/response/** + **/request/** + **/entity/** + **/common/** + **/utils/** + **/error/** + **/*Constant* + org/** + + + + + + + + coverage + + + + org.sonarsource.scanner.maven + sonar-maven-plugin + + + sonar + + sonar + + verify + + + + + + + + + + +